Repository: open-mmlab/mmagic Branch: main Commit: 0a560bba9b79 Files: 1687 Total size: 18.8 MB Directory structure: gitextract_ofufjmnn/ ├── .circleci/ │ ├── config.yml │ ├── docker/ │ │ └── Dockerfile │ └── test.yml ├── .dele.yml ├── .dev_scripts/ │ ├── README.md │ ├── create_ceph_configs.py │ ├── doc_link_checker.py │ ├── download_models.py │ ├── inference_benchmark.sh │ ├── job_watcher.py │ ├── metric_mapping.py │ ├── task_mapping.py │ ├── test_benchmark.py │ ├── test_benchmark.yml │ ├── train_benchmark.py │ ├── train_benchmark.yml │ ├── update_config_readme.py │ ├── update_model_index.py │ ├── update_ut.py │ └── utils/ │ ├── __init__.py │ ├── job_util.py │ └── modelindex.py ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── 1-bug-report.yml │ │ ├── 2-feature-request.yml │ │ ├── 3-new-model.yml │ │ ├── 4-documentation.yml │ │ └── config.yml │ ├── pull_request_template.md │ └── workflows/ │ ├── lint.yml │ ├── merge_stage_test.yml │ ├── pr_stage_test.yml │ ├── publish-to-pypi.yml │ └── test_mim.yml ├── .gitignore ├── .owners.yml ├── .pre-commit-config.yaml ├── .pylintrc ├── .readthedocs.yml ├── CITATION.cff ├── LICENSE ├── MANIFEST.in ├── README.md ├── README_zh-CN.md ├── configs/ │ ├── _base_/ │ │ ├── datasets/ │ │ │ ├── basicvsr_test_config.py │ │ │ ├── celeba.py │ │ │ ├── cifar10_noaug.py │ │ │ ├── cifar10_nopad.py │ │ │ ├── comp1k.py │ │ │ ├── deblurring-defocus_test_config.py │ │ │ ├── deblurring-motion_test_config.py │ │ │ ├── decompression_test_config.py │ │ │ ├── denoising-gaussian_color_test_config.py │ │ │ ├── denoising-gaussian_gray_test_config.py │ │ │ ├── denoising-real_test_config.py │ │ │ ├── deraining_test_config.py │ │ │ ├── ffhq_flip.py │ │ │ ├── grow_scale_imgs_ffhq_styleganv1.py │ │ │ ├── imagenet_128.py │ │ │ ├── imagenet_256.py │ │ │ ├── imagenet_512.py │ │ │ ├── imagenet_64.py │ │ │ ├── imagenet_noaug_128.py │ │ │ ├── liif_test_config.py │ │ │ ├── lsun_stylegan.py │ │ │ ├── paired_imgs_256x256_crop.py │ │ │ ├── places.py │ │ │ ├── sisr_x2_test_config.py │ │ │ ├── sisr_x3_test_config.py │ │ │ ├── sisr_x4_test_config.py │ │ │ ├── tdan_test_config.py │ │ │ ├── unconditional_imgs_128x128.py │ │ │ ├── unconditional_imgs_64x64.py │ │ │ ├── unconditional_imgs_flip_512x512.py │ │ │ ├── unconditional_imgs_flip_lanczos_resize_256x256.py │ │ │ └── unpaired_imgs_256x256.py │ │ ├── default_runtime.py │ │ ├── gen_default_runtime.py │ │ ├── inpaint_default_runtime.py │ │ ├── matting_default_runtime.py │ │ ├── models/ │ │ │ ├── base_cyclegan.py │ │ │ ├── base_deepfillv1.py │ │ │ ├── base_deepfillv2.py │ │ │ ├── base_edvr.py │ │ │ ├── base_gl.py │ │ │ ├── base_glean.py │ │ │ ├── base_liif.py │ │ │ ├── base_pconv.py │ │ │ ├── base_pix2pix.py │ │ │ ├── base_styleganv1.py │ │ │ ├── base_styleganv2.py │ │ │ ├── base_styleganv3.py │ │ │ ├── base_tof.py │ │ │ ├── biggan/ │ │ │ │ └── base_biggan_128x128.py │ │ │ ├── dcgan/ │ │ │ │ ├── base_dcgan_128x128.py │ │ │ │ └── base_dcgan_64x64.py │ │ │ ├── sagan/ │ │ │ │ ├── base_sagan_128x128.py │ │ │ │ └── base_sagan_32x32.py │ │ │ └── sngan_proj/ │ │ │ ├── base_sngan_proj_128x128.py │ │ │ └── base_sngan_proj_32x32.py │ │ └── schedules/ │ │ └── .gitkeep │ ├── animatediff/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── animatediff_Lyriel.py │ │ ├── animatediff_MajicMix.py │ │ ├── animatediff_RcnzCartoon.py │ │ ├── animatediff_RealisticVision.py │ │ ├── animatediff_RealisticVision_v2.py │ │ ├── animatediff_ToonYou.py │ │ └── metafile.yml │ ├── aot_gan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── aot-gan_smpgan_4xb4_places-512x512.py │ │ └── metafile.yml │ ├── basicvsr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── basicvsr_2xb4_reds4.py │ │ ├── basicvsr_2xb4_vimeo90k-bd.py │ │ ├── basicvsr_2xb4_vimeo90k-bi.py │ │ └── metafile.yml │ ├── basicvsr_pp/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── basicvsr-pp_c128n25_600k_ntire-decompress-track1.py │ │ ├── basicvsr-pp_c128n25_600k_ntire-decompress-track2.py │ │ ├── basicvsr-pp_c128n25_600k_ntire-decompress-track3.py │ │ ├── basicvsr-pp_c128n25_600k_ntire-vsr.py │ │ ├── basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py │ │ ├── basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py │ │ ├── basicvsr-pp_c64n7_8xb1-600k_reds4.py │ │ └── metafile.yml │ ├── biggan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py │ │ ├── biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py │ │ ├── biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py │ │ ├── biggan_2xb25-500kiters_cifar10-32x32.py │ │ ├── biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py │ │ ├── biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py │ │ └── metafile.yml │ ├── cain/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── cain_g1b32_1xb5_vimeo90k-triplet.py │ │ └── metafile.yml │ ├── controlnet/ │ │ ├── README.md │ │ ├── controlnet-1xb1-fill50k.py │ │ ├── controlnet-canny.py │ │ ├── controlnet-pose.py │ │ ├── controlnet-seg.py │ │ └── metafile.yml │ ├── controlnet_animation/ │ │ ├── README.md │ │ ├── anythingv3_config.py │ │ └── metafile.yml │ ├── cyclegan/ │ │ ├── README.md │ │ ├── cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py │ │ ├── cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra.py │ │ ├── cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py │ │ ├── cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter.py │ │ ├── cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra.py │ │ ├── cyclegan_lsgan-resnet-in_1xb1-80kiters_facades.py │ │ └── metafile.yml │ ├── dcgan/ │ │ ├── README.md │ │ ├── dcgan_1xb128-300kiters_celeba-cropped-64.py │ │ ├── dcgan_1xb128-5epoches_lsun-bedroom-64x64.py │ │ ├── dcgan_Glr4e-4_Dlr1e-4_1xb128-5kiters_mnist-64x64.py │ │ └── metafile.yml │ ├── deblurganv2/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── deblurganv2_fpn-inception_1xb1_gopro.py │ │ ├── deblurganv2_fpn-mobilenet_1xb1_gopro.py │ │ └── metafile.yml │ ├── deepfillv1/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── deepfillv1_4xb4_celeba-256x256.py │ │ ├── deepfillv1_8xb2_places-256x256.py │ │ └── metafile.yml │ ├── deepfillv2/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── deepfillv2_8xb2_celeba-256x256.py │ │ ├── deepfillv2_8xb2_places-256x256.py │ │ └── metafile.yml │ ├── dic/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── dic_gan-x8c48b6_4xb2-500k_celeba-hq.py │ │ ├── dic_x8c48b6_4xb2-150k_celeba-hq.py │ │ └── metafile.yml │ ├── diffusers_pipeline/ │ │ ├── README.md │ │ ├── metafile.yml │ │ └── sd_xl_pipeline.py │ ├── dim/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── dim_stage1-v16_1xb1-1000k_comp1k.py │ │ ├── dim_stage1-v16_1xb1-1000k_comp1k_online-merge.py │ │ ├── dim_stage2-v16-pln_1xb1-1000k_comp1k.py │ │ ├── dim_stage3-v16-pln_1xb1-1000k_comp1k.py │ │ └── metafile.yml │ ├── disco_diffusion/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── disco-diffusion_adm-u-finetuned_imagenet-256x256.py │ │ ├── disco-diffusion_adm-u-finetuned_imagenet-512x512.py │ │ ├── disco-diffusion_portrait-generator-v001.py │ │ ├── metafile.yml │ │ └── tutorials.ipynb │ ├── draggan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── stylegan2_1024x1024.py │ │ ├── stylegan2_256x256.py │ │ └── stylegan2_512x512.py │ ├── dreambooth/ │ │ ├── README.md │ │ ├── dreambooth-finetune_text_encoder.py │ │ ├── dreambooth-lora-prior_pre.py │ │ ├── dreambooth-lora.py │ │ ├── dreambooth-prior_pre.py │ │ ├── dreambooth.py │ │ └── metafile.yml │ ├── edsr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── edsr_x2c64b16_1xb16-300k_div2k.py │ │ ├── edsr_x3c64b16_1xb16-300k_div2k.py │ │ ├── edsr_x4c64b16_1xb16-300k_div2k.py │ │ └── metafile.yml │ ├── edvr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── edvrl_c128b40_8xb8-lr2e-4-600k_reds4.py │ │ ├── edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4.py │ │ ├── edvrm_8xb4-600k_reds.py │ │ ├── edvrm_wotsa_8xb4-600k_reds.py │ │ └── metafile.yml │ ├── eg3d/ │ │ ├── README.md │ │ ├── eg3d_cvt-official-rgb_afhq-512x512.py │ │ ├── eg3d_cvt-official-rgb_ffhq-512x512.py │ │ ├── eg3d_cvt-official-rgb_shapenet-128x128.py │ │ └── metafile.yml │ ├── esrgan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py │ │ ├── esrgan_x4c64b23g32_1xb16-400k_div2k.py │ │ └── metafile.yml │ ├── fastcomposer/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── fastcomposer_8xb16_FFHQ.py │ │ └── metafile.yml │ ├── flavr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── flavr_in4out1_8xb4_vimeo90k-septuplet.py │ │ └── metafile.yml │ ├── gca/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── baseline_r34_4xb10-200k_comp1k.py │ │ ├── baseline_r34_4xb10-dimaug-200k_comp1k.py │ │ ├── gca_r34_4xb10-200k_comp1k.py │ │ ├── gca_r34_4xb10-dimaug-200k_comp1k.py │ │ └── metafile.yml │ ├── ggan/ │ │ ├── README.md │ │ ├── ggan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py │ │ ├── ggan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py │ │ ├── ggan_lsgan-archi_lr1e-4-1xb128-20Mimgs_lsun-bedroom-64x64.py │ │ └── metafile.yml │ ├── glean/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq.py │ │ ├── glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py │ │ ├── glean_x16-fp16_2xb8_ffhq.py │ │ ├── glean_x16_2xb8_cat.py │ │ ├── glean_x16_2xb8_ffhq.py │ │ ├── glean_x8-fp16_2xb8_cat.py │ │ ├── glean_x8_2xb8_cat.py │ │ └── metafile.yml │ ├── global_local/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── gl_8xb12_celeba-256x256.py │ │ ├── gl_8xb12_places-256x256.py │ │ └── metafile.yml │ ├── guided_diffusion/ │ │ ├── README.md │ │ ├── adm-g_ddim25_8xb32_imagenet-256x256.py │ │ ├── adm-g_ddim25_8xb32_imagenet-512x512.py │ │ ├── adm-g_ddim25_8xb32_imagenet-64x64.py │ │ ├── adm_ddim250_8xb32_imagenet-256x256.py │ │ ├── adm_ddim250_8xb32_imagenet-512x512.py │ │ ├── adm_ddim250_8xb32_imagenet-64x64.py │ │ └── metafile.yml │ ├── iconvsr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── iconvsr_2xb4_reds4.py │ │ ├── iconvsr_2xb4_vimeo90k-bd.py │ │ ├── iconvsr_2xb4_vimeo90k-bi.py │ │ └── metafile.yml │ ├── indexnet/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── indexnet_mobv2-dimaug_1xb16-78k_comp1k.py │ │ ├── indexnet_mobv2_1xb16-78k_comp1k.py │ │ └── metafile.yml │ ├── inst_colorization/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── inst-colorizatioon_full_official_cocostuff-256x256.py │ │ └── metafile.yml │ ├── liif/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── liif-edsr-norm_c64b16_1xb16-1000k_div2k.py │ │ ├── liif-rdn-norm_c64b16_1xb16-1000k_div2k.py │ │ └── metafile.yml │ ├── lsgan/ │ │ ├── README.md │ │ ├── lsgan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py │ │ ├── lsgan_dcgan-archi_lr1e-4-1xb128-12Mimgs_lsun-bedroom-64x64.py │ │ ├── lsgan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py │ │ ├── lsgan_lsgan-archi_lr1e-4-1xb64-10Mimgs_lsun-bedroom-128x128.py │ │ └── metafile.yml │ ├── nafnet/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py │ │ └── nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py │ ├── partial_conv/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── pconv_stage1_8xb12_places-256x256.py │ │ ├── pconv_stage1_8xb1_celeba-256x256.py │ │ ├── pconv_stage2_4xb2_celeba-256x256.py │ │ └── pconv_stage2_4xb2_places-256x256.py │ ├── pggan/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── pggan_8xb4-12Mimg_celeba-hq-1024x1024.py │ │ ├── pggan_8xb4-12Mimgs_celeba-cropped-128x128.py │ │ └── pggan_8xb4-12Mimgs_lsun-bedroom-128x128.py │ ├── pix2pix/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── pix2pix_vanilla-unet-bn_1xb1-220kiters_aerial2maps.py │ │ ├── pix2pix_vanilla-unet-bn_1xb1-220kiters_maps2aerial.py │ │ ├── pix2pix_vanilla-unet-bn_1xb1-80kiters_facades.py │ │ └── pix2pix_vanilla-unet-bn_wo-jitter-flip-1xb4-190kiters_edges2shoes.py │ ├── positional_encoding_in_gans/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024.py │ │ ├── mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896.py │ │ ├── mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512.py │ │ ├── singan-csg_bohemian.py │ │ ├── singan-csg_fish.py │ │ ├── singan_interp-pad_balloons.py │ │ ├── singan_interp-pad_disc-nobn_balloons.py │ │ ├── singan_interp-pad_disc-nobn_fish.py │ │ ├── singan_spe-dim4_bohemian.py │ │ ├── singan_spe-dim4_fish.py │ │ ├── singan_spe-dim8_bohemian.py │ │ ├── stylegan2_c2_8xb3-1100kiters_ffhq-256x256.py │ │ └── stylegan2_c2_8xb3-1100kiters_ffhq-512x512.py │ ├── rdn/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── rdn_x2c64b16_1xb16-1000k_div2k.py │ │ ├── rdn_x3c64b16_1xb16-1000k_div2k.py │ │ └── rdn_x4c64b16_1xb16-1000k_div2k.py │ ├── real_basicvsr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py │ │ └── realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py │ ├── real_esrgan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py │ │ └── realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py │ ├── restormer/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── restormer_official_dfwb-color-sigma15.py │ │ ├── restormer_official_dfwb-color-sigma25.py │ │ ├── restormer_official_dfwb-color-sigma50.py │ │ ├── restormer_official_dfwb-gray-sigma15.py │ │ ├── restormer_official_dfwb-gray-sigma25.py │ │ ├── restormer_official_dfwb-gray-sigma50.py │ │ ├── restormer_official_dpdd-dual.py │ │ ├── restormer_official_dpdd-single.py │ │ ├── restormer_official_gopro.py │ │ ├── restormer_official_rain13k.py │ │ └── restormer_official_sidd.py │ ├── sagan/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── sagan_128_cvt_studioGAN.py │ │ ├── sagan_cvt-studioGAN_cifar10-32x32.py │ │ ├── sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py │ │ ├── sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128.py │ │ ├── sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128.py │ │ └── sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py │ ├── singan/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── singan_balloons.py │ │ ├── singan_bohemian.py │ │ └── singan_fish.py │ ├── sngan_proj/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── sngan-proj-cvt-studioGAN_cifar10-32x32.py │ │ ├── sngan-proj-cvt-studioGAN_imagenet1k-128x128.py │ │ ├── sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py │ │ ├── sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py │ │ ├── sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py │ │ └── sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py │ ├── srcnn/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ └── srcnn_x4k915_1xb16-1000k_div2k.py │ ├── srgan_resnet/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── msrresnet_x4c64b16_1xb16-1000k_div2k.py │ │ └── srgan_x4c64b16_1xb16-1000k_div2k.py │ ├── stable_diffusion/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── stable-diffusion_ddim_denoisingunet-inpaint.py │ │ ├── stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py │ │ └── stable-diffusion_ddim_denoisingunet.py │ ├── stable_diffusion_xl/ │ │ ├── README.md │ │ ├── metafile.yml │ │ └── stable-diffusion_xl_ddim_denoisingunet.py │ ├── styleganv1/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── styleganv1_ffhq-1024x1024_8xb4-25Mimgs.py │ │ └── styleganv1_ffhq-256x256_8xb4-25Mimgs.py │ ├── styleganv2/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256.py │ │ ├── stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256.py │ │ ├── stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py │ │ ├── stylegan2_c2_8xb4-800kiters_ffhq-256x256.py │ │ ├── stylegan2_c2_8xb4-800kiters_lsun-cat-256x256.py │ │ ├── stylegan2_c2_8xb4-800kiters_lsun-church-256x256.py │ │ ├── stylegan2_c2_8xb4-800kiters_lsun-horse-256x256.py │ │ ├── stylegan2_c2_8xb4_ffhq-1024x1024.py │ │ └── stylegan2_c2_8xb4_lsun-car-384x512.py │ ├── styleganv3/ │ │ ├── README.md │ │ ├── metafile.yml │ │ ├── stylegan3-r_ada-gamma3.3_8xb4-fp16_metfaces-1024x1024.py │ │ ├── stylegan3-r_cvt-official-rgb_8xb4_ffhq-1024x1024.py │ │ ├── stylegan3-r_cvt-official-rgb_8xb4_ffhqu-256x256.py │ │ ├── stylegan3-r_cvt-official-rgb_8xb4x8_afhqv2-512x512.py │ │ ├── stylegan3-t_ada-gamma6.6_8xb4-fp16_metfaces-1024x1024.py │ │ ├── stylegan3-t_cvt-official-rgb_8xb4_afhqv2-512x512.py │ │ ├── stylegan3-t_cvt-official-rgb_8xb4_ffhq-1024x1024.py │ │ ├── stylegan3-t_cvt-official-rgb_8xb4_ffhqu-256x256.py │ │ ├── stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py │ │ └── stylegan3-t_gamma32.8_8xb4-fp16-noaug_ffhq-1024x1024.py │ ├── swinir/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py │ │ ├── swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py │ │ ├── swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py │ │ ├── swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py │ │ ├── swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py │ │ ├── swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py │ │ ├── swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py │ │ ├── swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py │ │ ├── swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py │ │ ├── swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py │ │ ├── swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py │ │ └── swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py │ ├── tdan/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py │ │ ├── tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py │ │ ├── tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py │ │ └── tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py │ ├── textual_inversion/ │ │ ├── README.md │ │ ├── metafile.yml │ │ └── textual_inversion.py │ ├── tof/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py │ │ ├── tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py │ │ ├── tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py │ │ ├── tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py │ │ ├── tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py │ │ └── tof_x4_official_vimeo90k.py │ ├── ttsr/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ ├── ttsr-gan_x4c64b16_1xb9-500k_CUFED.py │ │ └── ttsr-rec_x4c64b16_1xb9-200k_CUFED.py │ ├── vico/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── metafile.yml │ │ └── vico.py │ └── wgan-gp/ │ ├── README.md │ ├── metafile.yml │ ├── wgangp_GN-GP-50_1xb64-160kiters_lsun-bedroom-128x128.py │ └── wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py ├── demo/ │ ├── README.md │ ├── download_inference_resources.py │ ├── gradio_animatediff.py │ ├── gradio_controlnet_animation.py │ ├── gradio_draggan.py │ ├── gradio_fastcomposer.py │ ├── gradio_inpainting.py │ ├── gradio_vico.py │ ├── mmagic_inference_demo.py │ ├── mmagic_inference_tutorial.ipynb │ ├── singan_demo.py │ └── utils/ │ ├── gradio_utils.py │ └── renderer.py ├── docker/ │ ├── Dockerfile │ └── README.md ├── docs/ │ ├── en/ │ │ ├── .dev_scripts/ │ │ │ ├── update_dataset_zoo.py │ │ │ └── update_model_zoo.py │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── _static/ │ │ │ └── css/ │ │ │ └── readthedocs.css │ │ ├── _templates/ │ │ │ ├── 404.html │ │ │ └── python/ │ │ │ ├── attribute.rst │ │ │ ├── class.rst │ │ │ ├── data.rst │ │ │ ├── exception.rst │ │ │ ├── function.rst │ │ │ ├── method.rst │ │ │ ├── module.rst │ │ │ ├── package.rst │ │ │ └── property.rst │ │ ├── advanced_guides/ │ │ │ ├── data_flow.md │ │ │ ├── data_preprocessor.md │ │ │ ├── evaluator.md │ │ │ └── structures.md │ │ ├── changelog.md │ │ ├── community/ │ │ │ ├── contributing.md │ │ │ └── projects.md │ │ ├── conf.py │ │ ├── device/ │ │ │ └── npu.md │ │ ├── docutils.conf │ │ ├── faq.md │ │ ├── get_started/ │ │ │ ├── install.md │ │ │ ├── overview.md │ │ │ └── quick_run.md │ │ ├── howto/ │ │ │ ├── dataset.md │ │ │ ├── losses.md │ │ │ ├── models.md │ │ │ └── transforms.md │ │ ├── index.rst │ │ ├── make.bat │ │ ├── migration/ │ │ │ ├── amp.md │ │ │ ├── data.md │ │ │ ├── distributed_train.md │ │ │ ├── eval_test.md │ │ │ ├── models.md │ │ │ ├── optimizers.md │ │ │ ├── overview.md │ │ │ ├── runtime.md │ │ │ ├── schedule.md │ │ │ └── visualization.md │ │ ├── switch_language.md │ │ └── user_guides/ │ │ ├── config.md │ │ ├── dataset_prepare.md │ │ ├── deploy.md │ │ ├── inference.md │ │ ├── metrics.md │ │ ├── train_test.md │ │ ├── useful_tools.md │ │ └── visualization.md │ └── zh_cn/ │ ├── .dev_scripts/ │ │ ├── update_dataset_zoo.py │ │ └── update_model_zoo.py │ ├── .gitignore │ ├── Makefile │ ├── _static/ │ │ └── css/ │ │ └── readthedocs.css │ ├── _templates/ │ │ └── 404.html │ ├── advanced_guides/ │ │ ├── data_flow.md │ │ ├── data_preprocessor.md │ │ ├── evaluator.md │ │ └── structures.md │ ├── changelog.md │ ├── community/ │ │ ├── contributing.md │ │ └── projects.md │ ├── conf.py │ ├── device/ │ │ └── npu_zh.md │ ├── faq.md │ ├── get_started/ │ │ ├── install.md │ │ ├── overview.md │ │ └── quick_run.md │ ├── howto/ │ │ ├── dataset.md │ │ ├── losses.md │ │ ├── models.md │ │ └── transforms.md │ ├── index.rst │ ├── make.bat │ ├── migration/ │ │ ├── amp.md │ │ ├── data.md │ │ ├── distributed_train.md │ │ ├── eval_test.md │ │ ├── models.md │ │ ├── optimizers.md │ │ ├── overview.md │ │ ├── runtime.md │ │ ├── schedule.md │ │ └── visualization.md │ ├── stat.py │ ├── switch_language.md │ └── user_guides/ │ ├── config.md │ ├── dataset_prepare.md │ ├── deploy.md │ ├── index.rst │ ├── inference.md │ ├── metrics.md │ ├── train_test.md │ ├── useful_tools.md │ └── visualization.md ├── mmagic/ │ ├── __init__.py │ ├── apis/ │ │ ├── __init__.py │ │ ├── inferencers/ │ │ │ ├── __init__.py │ │ │ ├── base_mmagic_inferencer.py │ │ │ ├── colorization_inferencer.py │ │ │ ├── conditional_inferencer.py │ │ │ ├── controlnet_animation_inferencer.py │ │ │ ├── diffusers_pipeline_inferencer.py │ │ │ ├── eg3d_inferencer.py │ │ │ ├── image_super_resolution_inferencer.py │ │ │ ├── inference_functions.py │ │ │ ├── inpainting_inferencer.py │ │ │ ├── matting_inferencer.py │ │ │ ├── text2image_inferencer.py │ │ │ ├── translation_inferencer.py │ │ │ ├── unconditional_inferencer.py │ │ │ ├── video_interpolation_inferencer.py │ │ │ └── video_restoration_inferencer.py │ │ └── mmagic_inferencer.py │ ├── configs/ │ │ ├── _base_/ │ │ │ ├── datasets/ │ │ │ │ ├── basicvsr_test_config.py │ │ │ │ ├── celeba.py │ │ │ │ ├── cifar10_noaug.py │ │ │ │ ├── cifar10_nopad.py │ │ │ │ ├── comp1k.py │ │ │ │ ├── deblurring-defocus_test_config.py │ │ │ │ ├── deblurring-motion_test_config.py │ │ │ │ ├── decompression_test_config.py │ │ │ │ ├── denoising-gaussian_color_test_config.py │ │ │ │ ├── denoising-gaussian_gray_test_config.py │ │ │ │ ├── denoising-real_test_config.py │ │ │ │ ├── deraining_test_config.py │ │ │ │ ├── ffhq_flip.py │ │ │ │ ├── grow_scale_imgs_ffhq_styleganv1.py │ │ │ │ ├── imagenet_128.py │ │ │ │ ├── imagenet_256.py │ │ │ │ ├── imagenet_512.py │ │ │ │ ├── imagenet_64.py │ │ │ │ ├── imagenet_noaug_128.py │ │ │ │ ├── liif_test_config.py │ │ │ │ ├── lsun_stylegan.py │ │ │ │ ├── paired_imgs_256x256_crop.py │ │ │ │ ├── places.py │ │ │ │ ├── sisr_x2_test_config.py │ │ │ │ ├── sisr_x3_test_config.py │ │ │ │ ├── sisr_x4_test_config.py │ │ │ │ ├── tdan_test_config.py │ │ │ │ ├── unconditional_imgs_128x128.py │ │ │ │ ├── unconditional_imgs_64x64.py │ │ │ │ ├── unconditional_imgs_flip_512x512.py │ │ │ │ ├── unconditional_imgs_flip_lanczos_resize_256x256.py │ │ │ │ └── unpaired_imgs_256x256.py │ │ │ ├── default_runtime.py │ │ │ ├── gen_default_runtime.py │ │ │ ├── inpaint_default_runtime.py │ │ │ ├── matting_default_runtime.py │ │ │ ├── models/ │ │ │ │ ├── base_cyclegan.py │ │ │ │ ├── base_deepfillv1.py │ │ │ │ ├── base_deepfillv2.py │ │ │ │ ├── base_edvr.py │ │ │ │ ├── base_gl.py │ │ │ │ ├── base_glean.py │ │ │ │ ├── base_liif.py │ │ │ │ ├── base_pconv.py │ │ │ │ ├── base_pix2pix.py │ │ │ │ ├── base_styleganv1.py │ │ │ │ ├── base_styleganv2.py │ │ │ │ ├── base_styleganv3.py │ │ │ │ ├── base_tof.py │ │ │ │ ├── biggan/ │ │ │ │ │ └── base_biggan_128x128.py │ │ │ │ ├── dcgan/ │ │ │ │ │ ├── base_dcgan_128x128.py │ │ │ │ │ └── base_dcgan_64x64.py │ │ │ │ ├── sagan/ │ │ │ │ │ ├── base_sagan_128x128.py │ │ │ │ │ └── base_sagan_32x32.py │ │ │ │ └── sngan_proj/ │ │ │ │ ├── base_sngan_proj_128x128.py │ │ │ │ └── base_sngan_proj_32x32.py │ │ │ └── schedules/ │ │ │ └── .gitkeep │ │ ├── biggan/ │ │ │ ├── biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py │ │ │ ├── biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py │ │ │ ├── biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py │ │ │ ├── biggan_2xb25-500kiters_cifar10-32x32.py │ │ │ ├── biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py │ │ │ └── biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py │ │ ├── dreambooth/ │ │ │ ├── dreambooth-finetune_text_encoder.py │ │ │ ├── dreambooth-prior_pre.py │ │ │ ├── dreambooth.py │ │ │ ├── dreambooth_lora-prior_pre.py │ │ │ └── dreambooth_lora.py │ │ ├── eg3d/ │ │ │ ├── eg3d_cvt-official-rgb_afhq-512x512.py │ │ │ ├── eg3d_cvt-official-rgb_ffhq-512x512.py │ │ │ └── eg3d_cvt-official-rgb_shapenet-128x128.py │ │ ├── guided_diffusion/ │ │ │ ├── adm-g_ddim25_8xb32_imagenet_256x256.py │ │ │ ├── adm-g_ddim25_8xb32_imagenet_512x512.py │ │ │ ├── adm-g_ddim25_8xb32_imagenet_64x64.py │ │ │ ├── adm_ddim250_8xb32_imagenet_256x256.py │ │ │ ├── adm_ddim250_8xb32_imagenet_512x512.py │ │ │ └── adm_ddim250_8xb32_imagenet_64x64.py │ │ ├── inst_colorization/ │ │ │ └── inst-colorizatioon_full_official_cocostuff-256x256.py │ │ ├── real_basicvsr/ │ │ │ ├── realbasicvsr_c64b20_1x30x8_8xb1_lr5e_5_150k_reds.py │ │ │ └── realbasicvsr_wogan_c64b20_2x30x8_8xb2_lr1e_4_300k_reds.py │ │ ├── styleganv2/ │ │ │ ├── stylegan2_c2_8xb4_800kiters_ffhq_256x256.py │ │ │ ├── stylegan2_c2_8xb4_800kiters_lsun_cat_256x256.py │ │ │ ├── stylegan2_c2_8xb4_800kiters_lsun_church_256x256.py │ │ │ ├── stylegan2_c2_8xb4_800kiters_lsun_horse_256x256.py │ │ │ ├── stylegan2_c2_8xb4_ffhq_1024x1024.py │ │ │ ├── stylegan2_c2_8xb4_lsun_car_384x512.py │ │ │ ├── stylegan2_c2_PL_8xb4_fp16_partial_GD_no_scaler_800kiters_ffhq_256x256.py │ │ │ ├── stylegan2_c2_PL_R1_8xb4_apex_fp16_no_scaler_800kiters_ffhq_256x256.py │ │ │ └── stylegan2_c2_PL_R1_8xb4_fp16_globalG_partialD_no_scaler_800kiters_ffhq_256x256.py │ │ └── styleganv3/ │ │ ├── stylegan3_r_ada_gamma33_8xb4_fp16_metfaces_1024x1024.py │ │ ├── stylegan3_r_cvt_official_rgb_8xb4_ffhq_1024x1024.py │ │ ├── stylegan3_r_cvt_official_rgb_8xb4_ffhqu_256x256.py │ │ ├── stylegan3_r_cvt_official_rgb_8xb4x8_afhqv2_512x512.py │ │ ├── stylegan3_t_ada_gamma66_8xb4_fp16_metfaces_1024x1024.py │ │ ├── stylegan3_t_cvt_official_rgb_8xb4_afhqv2_512x512.py │ │ ├── stylegan3_t_cvt_official_rgb_8xb4_ffhq_1024x1024.py │ │ ├── stylegan3_t_cvt_official_rgb_8xb4_ffhqu_256x256.py │ │ ├── stylegan3_t_gamma20_8xb4_fp16_noaug_ffhq_256x256.py │ │ └── stylegan3_t_gamma328_8xb4_fp16_noaug_ffhq_1024x1024.py │ ├── datasets/ │ │ ├── __init__.py │ │ ├── basic_conditional_dataset.py │ │ ├── basic_frames_dataset.py │ │ ├── basic_image_dataset.py │ │ ├── categories.py │ │ ├── cifar10_dataset.py │ │ ├── comp1k_dataset.py │ │ ├── controlnet_dataset.py │ │ ├── data_utils.py │ │ ├── dreambooth_dataset.py │ │ ├── grow_scale_image_dataset.py │ │ ├── imagenet_dataset.py │ │ ├── mscoco_dataset.py │ │ ├── paired_image_dataset.py │ │ ├── singan_dataset.py │ │ ├── textual_inversion_dataset.py │ │ ├── transforms/ │ │ │ ├── __init__.py │ │ │ ├── albu_function.py │ │ │ ├── albumentations.py │ │ │ ├── alpha.py │ │ │ ├── aug_frames.py │ │ │ ├── aug_pixel.py │ │ │ ├── aug_shape.py │ │ │ ├── blur_kernels.py │ │ │ ├── crop.py │ │ │ ├── fgbg.py │ │ │ ├── formatting.py │ │ │ ├── generate_assistant.py │ │ │ ├── generate_frame_indices.py │ │ │ ├── get_masked_image.py │ │ │ ├── loading.py │ │ │ ├── matlab_like_resize.py │ │ │ ├── normalization.py │ │ │ ├── random_degradations.py │ │ │ ├── random_down_sampling.py │ │ │ ├── trimap.py │ │ │ └── values.py │ │ └── unpaired_image_dataset.py │ ├── engine/ │ │ ├── __init__.py │ │ ├── hooks/ │ │ │ ├── __init__.py │ │ │ ├── ema.py │ │ │ ├── iter_time_hook.py │ │ │ ├── pggan_fetch_data_hook.py │ │ │ ├── pickle_data_hook.py │ │ │ ├── reduce_lr_scheduler_hook.py │ │ │ └── visualization_hook.py │ │ ├── optimizers/ │ │ │ ├── __init__.py │ │ │ ├── multi_optimizer_constructor.py │ │ │ ├── pggan_optimizer_constructor.py │ │ │ └── singan_optimizer_constructor.py │ │ ├── runner/ │ │ │ ├── __init__.py │ │ │ ├── log_processor.py │ │ │ ├── loop_utils.py │ │ │ └── multi_loops.py │ │ └── schedulers/ │ │ ├── __init__.py │ │ ├── linear_lr_scheduler_with_interval.py │ │ └── reduce_lr_scheduler.py │ ├── evaluation/ │ │ ├── __init__.py │ │ ├── evaluator.py │ │ ├── functional/ │ │ │ ├── __init__.py │ │ │ ├── fid_inception.py │ │ │ ├── gaussian_funcs.py │ │ │ └── inception_utils.py │ │ └── metrics/ │ │ ├── __init__.py │ │ ├── base_gen_metric.py │ │ ├── base_sample_wise_metric.py │ │ ├── connectivity_error.py │ │ ├── equivariance.py │ │ ├── fid.py │ │ ├── gradient_error.py │ │ ├── inception_score.py │ │ ├── mae.py │ │ ├── matting_mse.py │ │ ├── metrics_utils.py │ │ ├── ms_ssim.py │ │ ├── mse.py │ │ ├── niqe.py │ │ ├── niqe_pris_params.npz │ │ ├── ppl.py │ │ ├── precision_and_recall.py │ │ ├── psnr.py │ │ ├── sad.py │ │ ├── snr.py │ │ ├── ssim.py │ │ └── swd.py │ ├── models/ │ │ ├── __init__.py │ │ ├── archs/ │ │ │ ├── __init__.py │ │ │ ├── all_gather_layer.py │ │ │ ├── aspp.py │ │ │ ├── attention_injection.py │ │ │ ├── conv.py │ │ │ ├── downsample.py │ │ │ ├── ensemble.py │ │ │ ├── gated_conv_module.py │ │ │ ├── img_normalize.py │ │ │ ├── linear_module.py │ │ │ ├── lora.py │ │ │ ├── multi_layer_disc.py │ │ │ ├── patch_disc.py │ │ │ ├── resnet.py │ │ │ ├── separable_conv_module.py │ │ │ ├── simple_encoder_decoder.py │ │ │ ├── smpatch_disc.py │ │ │ ├── sr_backbone.py │ │ │ ├── tokenizer.py │ │ │ ├── upsample.py │ │ │ ├── vgg.py │ │ │ └── wrapper.py │ │ ├── base_models/ │ │ │ ├── __init__.py │ │ │ ├── average_model.py │ │ │ ├── base_conditional_gan.py │ │ │ ├── base_edit_model.py │ │ │ ├── base_gan.py │ │ │ ├── base_mattor.py │ │ │ ├── base_translation_model.py │ │ │ ├── basic_interpolator.py │ │ │ ├── one_stage.py │ │ │ └── two_stage.py │ │ ├── data_preprocessors/ │ │ │ ├── __init__.py │ │ │ ├── data_preprocessor.py │ │ │ └── mattor_preprocessor.py │ │ ├── diffusion_schedulers/ │ │ │ ├── __init__.py │ │ │ ├── ddim_scheduler.py │ │ │ └── ddpm_scheduler.py │ │ ├── editors/ │ │ │ ├── __init__.py │ │ │ ├── animatediff/ │ │ │ │ ├── __init__.py │ │ │ │ ├── animatediff.py │ │ │ │ ├── animatediff_utils.py │ │ │ │ ├── attention_3d.py │ │ │ │ ├── motion_module.py │ │ │ │ ├── resnet_3d.py │ │ │ │ ├── unet_3d.py │ │ │ │ └── unet_block.py │ │ │ ├── aotgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── aot_decoder.py │ │ │ │ ├── aot_encoder.py │ │ │ │ ├── aot_encoder_decoder.py │ │ │ │ ├── aot_inpaintor.py │ │ │ │ └── aot_neck.py │ │ │ ├── arcface/ │ │ │ │ ├── __init__.py │ │ │ │ ├── arcface_modules.py │ │ │ │ ├── id_loss.py │ │ │ │ └── model_irse.py │ │ │ ├── basicvsr/ │ │ │ │ ├── __init__.py │ │ │ │ ├── basicvsr.py │ │ │ │ └── basicvsr_net.py │ │ │ ├── basicvsr_plusplus_net/ │ │ │ │ ├── __init__.py │ │ │ │ └── basicvsr_plusplus_net.py │ │ │ ├── biggan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── biggan.py │ │ │ │ ├── biggan_deep_discriminator.py │ │ │ │ ├── biggan_deep_generator.py │ │ │ │ ├── biggan_discriminator.py │ │ │ │ ├── biggan_generator.py │ │ │ │ ├── biggan_modules.py │ │ │ │ └── biggan_snmodule.py │ │ │ ├── cain/ │ │ │ │ ├── __init__.py │ │ │ │ ├── cain.py │ │ │ │ └── cain_net.py │ │ │ ├── controlnet/ │ │ │ │ ├── __init__.py │ │ │ │ ├── controlnet.py │ │ │ │ └── controlnet_utils.py │ │ │ ├── cyclegan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── cyclegan.py │ │ │ │ ├── cyclegan_generator.py │ │ │ │ └── cyclegan_modules.py │ │ │ ├── dcgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── dcgan.py │ │ │ │ ├── dcgan_discriminator.py │ │ │ │ └── dcgan_generator.py │ │ │ ├── ddpm/ │ │ │ │ ├── __init__.py │ │ │ │ ├── attention.py │ │ │ │ ├── denoising_unet.py │ │ │ │ ├── embeddings.py │ │ │ │ ├── res_blocks.py │ │ │ │ └── unet_blocks.py │ │ │ ├── deblurganv2/ │ │ │ │ ├── __init__.py │ │ │ │ ├── deblurganv2.py │ │ │ │ ├── deblurganv2_discriminator.py │ │ │ │ ├── deblurganv2_generator.py │ │ │ │ └── deblurganv2_util.py │ │ │ ├── deepfillv1/ │ │ │ │ ├── __init__.py │ │ │ │ ├── contextual_attention.py │ │ │ │ ├── contextual_attention_neck.py │ │ │ │ ├── deepfill_decoder.py │ │ │ │ ├── deepfill_disc.py │ │ │ │ ├── deepfill_encoder.py │ │ │ │ ├── deepfill_refiner.py │ │ │ │ └── deepfillv1.py │ │ │ ├── deepfillv2/ │ │ │ │ ├── __init__.py │ │ │ │ └── two_stage_encoder_decoder.py │ │ │ ├── dic/ │ │ │ │ ├── __init__.py │ │ │ │ ├── dic.py │ │ │ │ ├── dic_net.py │ │ │ │ ├── feedback_hour_glass.py │ │ │ │ └── light_cnn.py │ │ │ ├── dim/ │ │ │ │ ├── __init__.py │ │ │ │ └── dim.py │ │ │ ├── disco_diffusion/ │ │ │ │ ├── __init__.py │ │ │ │ ├── clip_wrapper.py │ │ │ │ ├── disco.py │ │ │ │ ├── guider.py │ │ │ │ └── secondary_model.py │ │ │ ├── dreambooth/ │ │ │ │ ├── __init__.py │ │ │ │ └── dreambooth.py │ │ │ ├── duf/ │ │ │ │ ├── __init__.py │ │ │ │ └── duf.py │ │ │ ├── edsr/ │ │ │ │ ├── __init__.py │ │ │ │ └── edsr_net.py │ │ │ ├── edvr/ │ │ │ │ ├── __init__.py │ │ │ │ ├── edvr.py │ │ │ │ └── edvr_net.py │ │ │ ├── eg3d/ │ │ │ │ ├── __init__.py │ │ │ │ ├── camera.py │ │ │ │ ├── dual_discriminator.py │ │ │ │ ├── eg3d.py │ │ │ │ ├── eg3d_generator.py │ │ │ │ ├── eg3d_modules.py │ │ │ │ ├── eg3d_utils.py │ │ │ │ ├── ray_sampler.py │ │ │ │ └── renderer.py │ │ │ ├── esrgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── esrgan.py │ │ │ │ └── rrdb_net.py │ │ │ ├── fastcomposer/ │ │ │ │ ├── __init__.py │ │ │ │ ├── fastcomposer.py │ │ │ │ └── fastcomposer_util.py │ │ │ ├── fba/ │ │ │ │ ├── __init__.py │ │ │ │ ├── fba_decoder.py │ │ │ │ └── fba_encoder.py │ │ │ ├── flavr/ │ │ │ │ ├── __init__.py │ │ │ │ ├── flavr.py │ │ │ │ └── flavr_net.py │ │ │ ├── gca/ │ │ │ │ ├── __init__.py │ │ │ │ ├── gca.py │ │ │ │ ├── gca_module.py │ │ │ │ ├── resgca_dec.py │ │ │ │ └── resgca_enc.py │ │ │ ├── ggan/ │ │ │ │ ├── __init__.py │ │ │ │ └── ggan.py │ │ │ ├── glean/ │ │ │ │ ├── __init__.py │ │ │ │ └── glean_styleganv2.py │ │ │ ├── global_local/ │ │ │ │ ├── __init__.py │ │ │ │ ├── gl_decoder.py │ │ │ │ ├── gl_dilation.py │ │ │ │ ├── gl_disc.py │ │ │ │ ├── gl_encoder.py │ │ │ │ ├── gl_encoder_decoder.py │ │ │ │ └── gl_inpaintor.py │ │ │ ├── guided_diffusion/ │ │ │ │ ├── __init__.py │ │ │ │ ├── adm.py │ │ │ │ └── classifier.py │ │ │ ├── iconvsr/ │ │ │ │ ├── __init__.py │ │ │ │ └── iconvsr_net.py │ │ │ ├── indexnet/ │ │ │ │ ├── __init__.py │ │ │ │ ├── indexnet.py │ │ │ │ ├── indexnet_decoder.py │ │ │ │ └── indexnet_encoder.py │ │ │ ├── inst_colorization/ │ │ │ │ ├── __init__.py │ │ │ │ ├── color_utils.py │ │ │ │ ├── colorization_net.py │ │ │ │ ├── fusion_net.py │ │ │ │ ├── inst_colorization.py │ │ │ │ └── weight_layer.py │ │ │ ├── liif/ │ │ │ │ ├── __init__.py │ │ │ │ ├── liif.py │ │ │ │ ├── liif_net.py │ │ │ │ └── mlp_refiner.py │ │ │ ├── lsgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── lsgan.py │ │ │ │ ├── lsgan_discriminator.py │ │ │ │ └── lsgan_generator.py │ │ │ ├── mspie/ │ │ │ │ ├── __init__.py │ │ │ │ ├── mspie_stylegan2.py │ │ │ │ ├── mspie_stylegan2_discriminator.py │ │ │ │ ├── mspie_stylegan2_generator.py │ │ │ │ ├── mspie_stylegan2_modules.py │ │ │ │ ├── pe_singan.py │ │ │ │ ├── pe_singan_generator.py │ │ │ │ └── positional_encoding.py │ │ │ ├── nafnet/ │ │ │ │ ├── __init__.py │ │ │ │ ├── naf_avgpool2d.py │ │ │ │ ├── naf_layerNorm2d.py │ │ │ │ ├── nafbaseline_net.py │ │ │ │ └── nafnet_net.py │ │ │ ├── pconv/ │ │ │ │ ├── __init__.py │ │ │ │ ├── mask_conv_module.py │ │ │ │ ├── partial_conv.py │ │ │ │ ├── pconv_decoder.py │ │ │ │ ├── pconv_encoder.py │ │ │ │ ├── pconv_encoder_decoder.py │ │ │ │ └── pconv_inpaintor.py │ │ │ ├── pggan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── pggan.py │ │ │ │ ├── pggan_discriminator.py │ │ │ │ ├── pggan_generator.py │ │ │ │ └── pggan_modules.py │ │ │ ├── pix2pix/ │ │ │ │ ├── __init__.py │ │ │ │ ├── pix2pix.py │ │ │ │ ├── pix2pix_generator.py │ │ │ │ └── pix2pix_modules.py │ │ │ ├── plain/ │ │ │ │ ├── __init__.py │ │ │ │ ├── plain_decoder.py │ │ │ │ └── plain_refiner.py │ │ │ ├── rdn/ │ │ │ │ ├── __init__.py │ │ │ │ └── rdn_net.py │ │ │ ├── real_basicvsr/ │ │ │ │ ├── __init__.py │ │ │ │ ├── real_basicvsr.py │ │ │ │ └── real_basicvsr_net.py │ │ │ ├── real_esrgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── real_esrgan.py │ │ │ │ └── unet_disc.py │ │ │ ├── restormer/ │ │ │ │ ├── __init__.py │ │ │ │ └── restormer_net.py │ │ │ ├── sagan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── sagan.py │ │ │ │ ├── sagan_discriminator.py │ │ │ │ ├── sagan_generator.py │ │ │ │ └── sagan_modules.py │ │ │ ├── singan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── singan.py │ │ │ │ ├── singan_discriminator.py │ │ │ │ ├── singan_generator.py │ │ │ │ └── singan_modules.py │ │ │ ├── srcnn/ │ │ │ │ ├── __init__.py │ │ │ │ └── srcnn_net.py │ │ │ ├── srgan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── modified_vgg.py │ │ │ │ ├── sr_resnet.py │ │ │ │ └── srgan.py │ │ │ ├── stable_diffusion/ │ │ │ │ ├── __init__.py │ │ │ │ ├── clip_wrapper.py │ │ │ │ ├── stable_diffusion.py │ │ │ │ ├── stable_diffusion_inpaint.py │ │ │ │ └── vae.py │ │ │ ├── stable_diffusion_xl/ │ │ │ │ ├── __init__.py │ │ │ │ └── stable_diffusion_xl.py │ │ │ ├── stylegan1/ │ │ │ │ ├── __init__.py │ │ │ │ ├── stylegan1.py │ │ │ │ ├── stylegan1_discriminator.py │ │ │ │ ├── stylegan1_generator.py │ │ │ │ ├── stylegan1_modules.py │ │ │ │ └── stylegan_utils.py │ │ │ ├── stylegan2/ │ │ │ │ ├── __init__.py │ │ │ │ ├── ada/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── augment.py │ │ │ │ │ ├── grid_sample_gradfix.py │ │ │ │ │ ├── misc.py │ │ │ │ │ └── upfirdn2d.py │ │ │ │ ├── stylegan2.py │ │ │ │ ├── stylegan2_discriminator.py │ │ │ │ ├── stylegan2_generator.py │ │ │ │ └── stylegan2_modules.py │ │ │ ├── stylegan3/ │ │ │ │ ├── __init__.py │ │ │ │ ├── stylegan3.py │ │ │ │ ├── stylegan3_generator.py │ │ │ │ ├── stylegan3_modules.py │ │ │ │ └── stylegan3_utils.py │ │ │ ├── swinir/ │ │ │ │ ├── __init__.py │ │ │ │ ├── swinir_modules.py │ │ │ │ ├── swinir_net.py │ │ │ │ ├── swinir_rstb.py │ │ │ │ └── swinir_utils.py │ │ │ ├── tdan/ │ │ │ │ ├── __init__.py │ │ │ │ ├── tdan.py │ │ │ │ └── tdan_net.py │ │ │ ├── textual_inversion/ │ │ │ │ ├── __init__.py │ │ │ │ └── textual_inversion.py │ │ │ ├── tof/ │ │ │ │ ├── __init__.py │ │ │ │ ├── tof_vfi_net.py │ │ │ │ └── tof_vsr_net.py │ │ │ ├── ttsr/ │ │ │ │ ├── __init__.py │ │ │ │ ├── lte.py │ │ │ │ ├── search_transformer.py │ │ │ │ ├── ttsr.py │ │ │ │ ├── ttsr_disc.py │ │ │ │ └── ttsr_net.py │ │ │ ├── vico/ │ │ │ │ ├── __init__.py │ │ │ │ ├── vico.py │ │ │ │ └── vico_utils.py │ │ │ └── wgan_gp/ │ │ │ ├── __init__.py │ │ │ ├── wgan_discriminator.py │ │ │ ├── wgan_generator.py │ │ │ ├── wgan_gp.py │ │ │ └── wgan_gp_module.py │ │ ├── losses/ │ │ │ ├── __init__.py │ │ │ ├── adv_loss.py │ │ │ ├── clip_loss.py │ │ │ ├── composition_loss.py │ │ │ ├── face_id_loss.py │ │ │ ├── feature_loss.py │ │ │ ├── gan_loss.py │ │ │ ├── gradient_loss.py │ │ │ ├── loss_comps/ │ │ │ │ ├── __init__.py │ │ │ │ ├── clip_loss_comps.py │ │ │ │ ├── disc_auxiliary_loss_comps.py │ │ │ │ ├── face_id_loss_comps.py │ │ │ │ ├── gan_loss_comps.py │ │ │ │ └── gen_auxiliary_loss_comps.py │ │ │ ├── loss_wrapper.py │ │ │ ├── perceptual_loss.py │ │ │ └── pixelwise_loss.py │ │ └── utils/ │ │ ├── __init__.py │ │ ├── bbox_utils.py │ │ ├── diffusion_utils.py │ │ ├── flow_warp.py │ │ ├── model_utils.py │ │ ├── sampling_utils.py │ │ ├── tensor_utils.py │ │ └── tome_utils.py │ ├── registry.py │ ├── structures/ │ │ ├── __init__.py │ │ └── data_sample.py │ ├── utils/ │ │ ├── __init__.py │ │ ├── cli.py │ │ ├── collect_env.py │ │ ├── img_utils.py │ │ ├── io_utils.py │ │ ├── logger.py │ │ ├── sampler.py │ │ ├── setup_env.py │ │ ├── trans_utils.py │ │ └── typing.py │ ├── version.py │ └── visualization/ │ ├── __init__.py │ ├── concat_visualizer.py │ ├── vis_backend.py │ └── visualizer.py ├── model-index.yml ├── projects/ │ ├── README.md │ ├── animated_drawings/ │ │ ├── README.md │ │ ├── bvh/ │ │ │ └── zombie.bvh │ │ ├── characters/ │ │ │ └── slamdunk/ │ │ │ └── char_cfg.yaml │ │ ├── configs/ │ │ │ ├── motion/ │ │ │ │ └── zombie.yaml │ │ │ ├── mvc/ │ │ │ │ └── slamdunk.yaml │ │ │ └── retarget/ │ │ │ └── fair1_spf.yaml │ │ └── tools/ │ │ ├── generate_character.py │ │ └── generate_video.py │ ├── example_project/ │ │ ├── README.md │ │ ├── configs/ │ │ │ └── examplenet_8xb32_in1k.py │ │ └── models/ │ │ ├── __init__.py │ │ └── example_net.py │ ├── flow_style_vton/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── configs/ │ │ │ └── flow_style_vton_PFAFN_epoch_101.py │ │ ├── inference.py │ │ ├── models/ │ │ │ ├── __init__.py │ │ │ ├── afwm.py │ │ │ ├── flow_style_vton_model.py │ │ │ └── generator.py │ │ ├── test_pairs.txt │ │ └── vton_dataset.py │ ├── glide/ │ │ ├── configs/ │ │ │ ├── README.md │ │ │ ├── glide_ddim-classifier-free_laion-64-256.py │ │ │ └── glide_ddim-classifier-free_laion-64x64.py │ │ └── models/ │ │ ├── __init__.py │ │ ├── glide.py │ │ ├── glide_modules.py │ │ ├── glide_tokenizer/ │ │ │ ├── __init__.py │ │ │ ├── bpe.py │ │ │ └── simple_tokenizer.py │ │ └── text2im_unet.py │ ├── magicmaker/ │ │ └── index.html │ ├── powerpaint/ │ │ ├── README.md │ │ ├── gradio_PowerPaint.py │ │ ├── pipeline/ │ │ │ ├── pipeline_PowerPaint.py │ │ │ └── pipeline_PowerPaint_ControlNet.py │ │ ├── requirements.txt │ │ └── utils/ │ │ └── utils.py │ └── prompt_to_prompt/ │ ├── README.md │ ├── inversions/ │ │ ├── __init__.py │ │ ├── ddim_inversion.py │ │ └── null_text_inversion.py │ ├── models/ │ │ ├── ptp.py │ │ ├── ptp_utils.py │ │ └── seq_aligner.py │ └── visualize.ipynb ├── requirements/ │ ├── docs.txt │ ├── mminstall.txt │ ├── optional.txt │ ├── readthedocs.txt │ ├── runtime.txt │ └── tests.txt ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests/ │ ├── configs/ │ │ ├── aot_test.py │ │ ├── deepfillv1_test.py │ │ ├── diffuser_wrapper_cfg/ │ │ │ └── config.json │ │ ├── gl_test.py │ │ ├── one_stage_gl.py │ │ ├── pconv_test.py │ │ └── two_stage_test.py │ ├── data/ │ │ ├── coco/ │ │ │ └── annotations/ │ │ │ ├── captions_train2014.json │ │ │ └── captions_val2014.json │ │ ├── controlnet/ │ │ │ └── prompt.json │ │ ├── dataset/ │ │ │ ├── anno.json │ │ │ ├── anno.txt │ │ │ ├── c/ │ │ │ │ └── c.not_support_type │ │ │ ├── classes.txt │ │ │ └── wrong.yml │ │ ├── frames/ │ │ │ ├── ann1.txt │ │ │ ├── ann2.txt │ │ │ └── ann3.txt │ │ ├── image/ │ │ │ └── train.txt │ │ ├── inpainting/ │ │ │ ├── mask_list.txt │ │ │ └── mask_list_single_ch.txt │ │ ├── lq.lmdb/ │ │ │ ├── data.mdb │ │ │ ├── lock.mdb │ │ │ └── meta_info.txt │ │ ├── matting_dataset/ │ │ │ ├── ann.json │ │ │ └── ann_old.json │ │ └── textual_inversion/ │ │ └── imagenet_templates_small.txt │ ├── test_apis/ │ │ ├── test_inferencers/ │ │ │ ├── test_base_mmagic_inferencer.py │ │ │ ├── test_colorization_inferencer.py │ │ │ ├── test_conditional_inferencer.py │ │ │ ├── test_diffusers_pipeline_inferencer.py │ │ │ ├── test_eg3d_inferencer.py │ │ │ ├── test_image_super_resolution_inferencer.py │ │ │ ├── test_inference_functions.py │ │ │ ├── test_inpainting_inferencer.py │ │ │ ├── test_matting_inferencer.py │ │ │ ├── test_mmedit_inferencer.py │ │ │ ├── test_text2image_inferencers.py │ │ │ ├── test_translation_inferencer.py │ │ │ ├── test_unconditional_inferencer.py │ │ │ ├── test_video_interpolation_inferencer.py │ │ │ └── test_video_restoration_inferencer.py │ │ └── test_mmagic_inferencer.py │ ├── test_datasets/ │ │ ├── test_basic_conditional_dataset.py │ │ ├── test_basic_frames_dataset.py │ │ ├── test_basic_image_dataset.py │ │ ├── test_categories.py │ │ ├── test_cifar10_dataset.py │ │ ├── test_comp1k_dataset.py │ │ ├── test_controlnet_dataset.py │ │ ├── test_data_utils.py │ │ ├── test_dreambooth_dataset.py │ │ ├── test_grow_scale_image_dataset.py │ │ ├── test_imagenet_dataset.py │ │ ├── test_mscoco_dataset.py │ │ ├── test_paired_image_dataset.py │ │ ├── test_singan_dataset.py │ │ ├── test_textual_inversion_dataset.py │ │ ├── test_transforms/ │ │ │ ├── test_albumentations.py │ │ │ ├── test_alpha.py │ │ │ ├── test_aug_frames.py │ │ │ ├── test_aug_pixel.py │ │ │ ├── test_aug_shape.py │ │ │ ├── test_blur_kernels.py │ │ │ ├── test_crop.py │ │ │ ├── test_fgbg.py │ │ │ ├── test_formatting.py │ │ │ ├── test_generate_assistant.py │ │ │ ├── test_generate_frame_indices.py │ │ │ ├── test_get_masked_image.py │ │ │ ├── test_loading.py │ │ │ ├── test_matlab_like_resize.py │ │ │ ├── test_normalization.py │ │ │ ├── test_random_degradations.py │ │ │ ├── test_random_down_sampling.py │ │ │ ├── test_trimap.py │ │ │ └── test_values.py │ │ └── test_unpaired_image_dataset.py │ ├── test_engine/ │ │ ├── test_hooks/ │ │ │ ├── test_ema.py │ │ │ ├── test_iter_time_hook.py │ │ │ ├── test_pggan_fetch_data_hook.py │ │ │ ├── test_pickle_data_hook.py │ │ │ ├── test_reduce_lr_scheduler_hook.py │ │ │ └── test_visualization_hook.py │ │ ├── test_optimizers/ │ │ │ ├── test_multi_optimizer_constructor.py │ │ │ ├── test_pggan_optimizer_constructor.py │ │ │ └── test_singan_optimizer_constructor.py │ │ ├── test_runner/ │ │ │ ├── test_log_processor.py │ │ │ ├── test_loop_utils.py │ │ │ └── test_multi_loops.py │ │ └── test_schedulers/ │ │ ├── test_linear_lr_scheduler_with_interval.py │ │ └── test_reduce_lr_scheduler.py │ ├── test_evaluation/ │ │ ├── test_evaluator.py │ │ ├── test_functional/ │ │ │ ├── test_fid_inception.py │ │ │ ├── test_gaussian_funcs.py │ │ │ └── test_inception_utils.py │ │ └── test_metrics/ │ │ ├── test_base_gen_metric.py │ │ ├── test_base_sample_wise_metric.py │ │ ├── test_connectivity_error.py │ │ ├── test_equivariance.py │ │ ├── test_fid.py │ │ ├── test_gradient_error.py │ │ ├── test_inception_score.py │ │ ├── test_mae.py │ │ ├── test_matting_mse.py │ │ ├── test_metrics_utils.py │ │ ├── test_ms_ssim.py │ │ ├── test_mse.py │ │ ├── test_niqe.py │ │ ├── test_ppl.py │ │ ├── test_precision_and_recall.py │ │ ├── test_psnr.py │ │ ├── test_sad.py │ │ ├── test_snr.py │ │ ├── test_ssim.py │ │ └── test_swd.py │ ├── test_models/ │ │ ├── test_archs/ │ │ │ ├── test_aspp.py │ │ │ ├── test_conv.py │ │ │ ├── test_downsample.py │ │ │ ├── test_ensemble.py │ │ │ ├── test_gated_conv_module.py │ │ │ ├── test_img_normalize.py │ │ │ ├── test_linear_module.py │ │ │ ├── test_lora.py │ │ │ ├── test_multi_layer_disc.py │ │ │ ├── test_patch_disc.py │ │ │ ├── test_resnet.py │ │ │ ├── test_separable_conv_module.py │ │ │ ├── test_simple_encoder_decoder.py │ │ │ ├── test_smpatch_disc.py │ │ │ ├── test_sr_backbone.py │ │ │ ├── test_tokenizer.py │ │ │ ├── test_upsample.py │ │ │ ├── test_vgg.py │ │ │ └── test_wrapper.py │ │ ├── test_base_models/ │ │ │ ├── test_average_model.py │ │ │ ├── test_base_conditional_gan.py │ │ │ ├── test_base_edit_model.py │ │ │ ├── test_base_gan.py │ │ │ ├── test_base_mattor.py │ │ │ ├── test_base_translation_model.py │ │ │ ├── test_basic_interpolator.py │ │ │ ├── test_one_stage.py │ │ │ └── test_two_stage.py │ │ ├── test_data_preprocessors/ │ │ │ ├── test_data_preprocessor.py │ │ │ └── test_mattor_preprocessor.py │ │ ├── test_diffusion_schedulers/ │ │ │ ├── test_ddim_scheduler.py │ │ │ └── test_init.py │ │ ├── test_editors/ │ │ │ ├── test_animatediff/ │ │ │ │ ├── test_animatediff.py │ │ │ │ ├── test_attention3d.py │ │ │ │ ├── test_motion_module.py │ │ │ │ ├── test_res_blocks3d.py │ │ │ │ ├── test_unet3d.py │ │ │ │ └── test_unet_blocks3d.py │ │ │ ├── test_aotgan/ │ │ │ │ ├── test_aot_decoder.py │ │ │ │ ├── test_aot_encoder.py │ │ │ │ ├── test_aot_encoder_decoder.py │ │ │ │ ├── test_aot_inpaintor.py │ │ │ │ └── test_aot_neck.py │ │ │ ├── test_arcface/ │ │ │ │ ├── test_arcface_modules.py │ │ │ │ ├── test_id_loss.py │ │ │ │ └── test_model_irse.py │ │ │ ├── test_basicvsr/ │ │ │ │ ├── test_basicvsr.py │ │ │ │ └── test_basicvsr_net.py │ │ │ ├── test_basicvsr_plusplus_net/ │ │ │ │ └── test_basicvsr_plusplus_net.py │ │ │ ├── test_biggan/ │ │ │ │ ├── test_biggan.py │ │ │ │ ├── test_biggan_deep_discriminator.py │ │ │ │ ├── test_biggan_deep_generator.py │ │ │ │ ├── test_biggan_discriminator.py │ │ │ │ ├── test_biggan_generator.py │ │ │ │ ├── test_biggan_modules.py │ │ │ │ └── test_biggan_snmodule.py │ │ │ ├── test_cain/ │ │ │ │ ├── test_cain.py │ │ │ │ └── test_cain_net.py │ │ │ ├── test_controlnet/ │ │ │ │ ├── test_controlnet.py │ │ │ │ └── test_controlnet_utils.py │ │ │ ├── test_cyclegan/ │ │ │ │ ├── test_cyclegan.py │ │ │ │ ├── test_cyclegan_generator.py │ │ │ │ └── test_cyclegan_modules.py │ │ │ ├── test_dcgan/ │ │ │ │ ├── test_dcgan.py │ │ │ │ ├── test_dcgan_discriminator.py │ │ │ │ └── test_dcgan_generator.py │ │ │ ├── test_ddpm/ │ │ │ │ ├── test_attention.py │ │ │ │ ├── test_ddpm_scheduler.py │ │ │ │ ├── test_denoising_unet.py │ │ │ │ ├── test_embeddings.py │ │ │ │ ├── test_res_blocks.py │ │ │ │ └── test_unet_blocks.py │ │ │ ├── test_deblurganv2/ │ │ │ │ ├── test_deblurganv2.py │ │ │ │ ├── test_deblurganv2_discriminator.py │ │ │ │ └── test_deblurganv2_generator.py │ │ │ ├── test_deepfillv1/ │ │ │ │ ├── test_contextual_attention.py │ │ │ │ ├── test_contextual_attention_neck.py │ │ │ │ ├── test_deepfill_decoder.py │ │ │ │ ├── test_deepfill_disc.py │ │ │ │ ├── test_deepfill_encoder.py │ │ │ │ ├── test_deepfill_refiner.py │ │ │ │ └── test_deepfillv1.py │ │ │ ├── test_deepfillv2/ │ │ │ │ └── test_two_stage_encoder_decoder.py │ │ │ ├── test_dic/ │ │ │ │ ├── test_dic.py │ │ │ │ ├── test_dic_net.py │ │ │ │ ├── test_feedback_hour_glass.py │ │ │ │ └── test_light_cnn.py │ │ │ ├── test_dim/ │ │ │ │ └── test_dim.py │ │ │ ├── test_disco_diffusion/ │ │ │ │ ├── test_disco_diffusion.py │ │ │ │ └── test_disco_diffusion_clip_wrapper.py │ │ │ ├── test_dreambooth/ │ │ │ │ └── test_dreambooth.py │ │ │ ├── test_duf/ │ │ │ │ └── test_duf.py │ │ │ ├── test_edsr/ │ │ │ │ └── test_edsr_net.py │ │ │ ├── test_edvr/ │ │ │ │ ├── test_edvr.py │ │ │ │ └── test_edvr_net.py │ │ │ ├── test_eg3d/ │ │ │ │ ├── test_camera.py │ │ │ │ ├── test_dual_discriminator.py │ │ │ │ ├── test_eg3d.py │ │ │ │ ├── test_eg3d_generator.py │ │ │ │ ├── test_eg3d_modules.py │ │ │ │ ├── test_eg3d_utils.py │ │ │ │ ├── test_ray_sampler.py │ │ │ │ └── test_renderer.py │ │ │ ├── test_esrgan/ │ │ │ │ ├── test_esrgan.py │ │ │ │ └── test_rrdb_net.py │ │ │ ├── test_fastcomposer/ │ │ │ │ └── test_fastcomposer.py │ │ │ ├── test_fba/ │ │ │ │ ├── test_fba_decoder.py │ │ │ │ └── test_fba_encoder.py │ │ │ ├── test_flavr/ │ │ │ │ ├── test_flavr.py │ │ │ │ └── test_flavr_net.py │ │ │ ├── test_gca/ │ │ │ │ ├── test_gca.py │ │ │ │ ├── test_gca_module.py │ │ │ │ ├── test_resgca_dec.py │ │ │ │ └── test_resgca_enc.py │ │ │ ├── test_ggan/ │ │ │ │ └── test_ggan.py │ │ │ ├── test_glean/ │ │ │ │ └── test_glean_styleganv2.py │ │ │ ├── test_glide/ │ │ │ │ └── test_glide.py │ │ │ ├── test_global_local/ │ │ │ │ ├── test_gl_decoder.py │ │ │ │ ├── test_gl_dilation.py │ │ │ │ ├── test_gl_disc.py │ │ │ │ ├── test_gl_encoder.py │ │ │ │ ├── test_gl_encoder_decoder.py │ │ │ │ └── test_gl_inpaintor.py │ │ │ ├── test_guided_diffusion/ │ │ │ │ └── test_adm.py │ │ │ ├── test_iconvsr/ │ │ │ │ └── test_iconvsr_net.py │ │ │ ├── test_indexnet/ │ │ │ │ ├── test_indexnet.py │ │ │ │ ├── test_indexnet_decoder.py │ │ │ │ └── test_indexnet_encoder.py │ │ │ ├── test_inst_colorization/ │ │ │ │ ├── test_color_utils.py │ │ │ │ ├── test_colorization_net.py │ │ │ │ ├── test_fusion_net.py │ │ │ │ ├── test_inst_colorization.py │ │ │ │ └── test_weight_layer.py │ │ │ ├── test_liif/ │ │ │ │ ├── test_liif.py │ │ │ │ ├── test_liif_net.py │ │ │ │ └── test_mlp_refiner.py │ │ │ ├── test_lsgan/ │ │ │ │ ├── test_lsgan.py │ │ │ │ ├── test_lsgan_discriminator.py │ │ │ │ └── test_lsgan_generator.py │ │ │ ├── test_mspie/ │ │ │ │ ├── test_mspie_stylegan2.py │ │ │ │ ├── test_mspie_stylegan2_discriminator.py │ │ │ │ ├── test_mspie_stylegan2_generator.py │ │ │ │ ├── test_mspie_stylegan2_modules.py │ │ │ │ ├── test_pe_singan.py │ │ │ │ ├── test_pe_singan_generator.py │ │ │ │ └── test_positional_encoding.py │ │ │ ├── test_nafnet/ │ │ │ │ ├── test_naf_avgpool2d.py │ │ │ │ ├── test_naf_layernorm2d.py │ │ │ │ ├── test_nafbaseline.py │ │ │ │ └── test_nafnet.py │ │ │ ├── test_pconv/ │ │ │ │ ├── test_mask_conv_module.py │ │ │ │ ├── test_partial_conv.py │ │ │ │ ├── test_pconv_decoder.py │ │ │ │ ├── test_pconv_encoder.py │ │ │ │ ├── test_pconv_encoder_decoder.py │ │ │ │ └── test_pconv_inpaintor.py │ │ │ ├── test_pggan/ │ │ │ │ ├── test_pggan.py │ │ │ │ ├── test_pggan_discriminator.py │ │ │ │ ├── test_pggan_generator.py │ │ │ │ └── test_pggan_modules.py │ │ │ ├── test_pix2pix/ │ │ │ │ ├── test_pix2pix.py │ │ │ │ ├── test_pix2pix_generator.py │ │ │ │ └── test_pix2pix_modules.py │ │ │ ├── test_plain/ │ │ │ │ ├── test_plain_decoder.py │ │ │ │ └── test_plain_refiner.py │ │ │ ├── test_rdn/ │ │ │ │ └── test_rdn_net.py │ │ │ ├── test_real_basicvsr/ │ │ │ │ ├── test_real_basicvsr.py │ │ │ │ └── test_real_basicvsr_net.py │ │ │ ├── test_real_esrgan/ │ │ │ │ ├── test_real_esrgan.py │ │ │ │ └── test_unet_disc.py │ │ │ ├── test_restormer/ │ │ │ │ └── test_restormer_net.py │ │ │ ├── test_sagan/ │ │ │ │ ├── test_sagan.py │ │ │ │ ├── test_sagan_discriminator.py │ │ │ │ ├── test_sagan_generator.py │ │ │ │ └── test_sagan_modules.py │ │ │ ├── test_singan/ │ │ │ │ ├── test_singan.py │ │ │ │ ├── test_singan_discriminator.py │ │ │ │ ├── test_singan_generator.py │ │ │ │ └── test_singan_modules.py │ │ │ ├── test_srcnn/ │ │ │ │ └── test_srcnn_net.py │ │ │ ├── test_srgan/ │ │ │ │ ├── test_modified_vgg.py │ │ │ │ ├── test_sr_resnet.py │ │ │ │ └── test_srgan.py │ │ │ ├── test_stable_diffusion/ │ │ │ │ ├── test_clip_wrapper.py │ │ │ │ ├── test_stable_diffusion.py │ │ │ │ ├── test_stable_diffusion_inpaint.py │ │ │ │ ├── test_stable_diffusion_tomesd.py │ │ │ │ └── test_vae.py │ │ │ ├── test_stable_diffusion_xl/ │ │ │ │ └── test_stable_diffusion_xl.py │ │ │ ├── test_stylegan1/ │ │ │ │ ├── test_stylegan1.py │ │ │ │ ├── test_stylegan1_discriminator.py │ │ │ │ ├── test_stylegan1_generator.py │ │ │ │ ├── test_stylegan1_modules.py │ │ │ │ └── test_stylegan_utils.py │ │ │ ├── test_stylegan2/ │ │ │ │ ├── test_ada/ │ │ │ │ │ └── test_augment.py │ │ │ │ ├── test_stylegan2.py │ │ │ │ ├── test_stylegan2_discriminator.py │ │ │ │ ├── test_stylegan2_generator.py │ │ │ │ └── test_stylegan2_modules.py │ │ │ ├── test_stylegan3/ │ │ │ │ ├── test_stylegan3.py │ │ │ │ ├── test_stylegan3_generator.py │ │ │ │ ├── test_stylegan3_modules.py │ │ │ │ └── test_stylegan3_utils.py │ │ │ ├── test_swinir/ │ │ │ │ ├── test_swinir_modules.py │ │ │ │ ├── test_swinir_net.py │ │ │ │ ├── test_swinir_rstb.py │ │ │ │ └── test_swinir_utils.py │ │ │ ├── test_tdan/ │ │ │ │ ├── test_tdan.py │ │ │ │ └── test_tdan_net.py │ │ │ ├── test_tof/ │ │ │ │ ├── test_tof_vfi_net.py │ │ │ │ └── test_tof_vsr_net.py │ │ │ ├── test_ttsr/ │ │ │ │ ├── test_lte.py │ │ │ │ ├── test_search_transformer.py │ │ │ │ ├── test_ttsr.py │ │ │ │ ├── test_ttsr_disc.py │ │ │ │ └── test_ttsr_net.py │ │ │ ├── test_vico/ │ │ │ │ ├── test_vico.py │ │ │ │ └── test_vico_utils.py │ │ │ └── test_wgan_gp/ │ │ │ ├── test_wgan_discriminator.py │ │ │ ├── test_wgan_generator.py │ │ │ ├── test_wgan_gp.py │ │ │ └── test_wgan_gp_module.py │ │ ├── test_losses/ │ │ │ ├── test_clip_loss.py │ │ │ ├── test_composition_loss.py │ │ │ ├── test_face_id_loss.py │ │ │ ├── test_feature_loss.py │ │ │ ├── test_gan_loss.py │ │ │ ├── test_gradient_loss.py │ │ │ ├── test_loss_comps/ │ │ │ │ ├── test_clip_loss_comps.py │ │ │ │ ├── test_disc_auxiliary_loss_comps.py │ │ │ │ ├── test_face_id_loss_comps.py │ │ │ │ ├── test_gan_loss_comps.py │ │ │ │ └── test_gen_auxiliary_loss_comps.py │ │ │ ├── test_loss_wrapper.py │ │ │ ├── test_perceptual_loss.py │ │ │ └── test_pixelwise_loss.py │ │ └── test_utils/ │ │ ├── test_bbox_utils.py │ │ ├── test_flow_warp.py │ │ ├── test_model_utils.py │ │ ├── test_sampling_utils.py │ │ └── test_tensor_utils.py │ ├── test_structures/ │ │ └── test_data_sample.py │ ├── test_utils/ │ │ ├── test_cli.py │ │ ├── test_img_utils.py │ │ ├── test_io_utils.py │ │ ├── test_logger.py │ │ ├── test_sampler.py │ │ ├── test_setup_env.py │ │ └── test_trans_utils.py │ └── test_visualization/ │ ├── test_concat_visualizer.py │ ├── test_vis_backend.py │ └── test_visualizer.py └── tools/ ├── analysis_tools/ │ ├── get_flops.py │ └── print_config.py ├── cpu_train.sh ├── dataset_converters/ │ ├── bgm/ │ │ └── preprocess_bgm_dataset.py │ ├── celeba-hq/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── classic5/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── comp1k/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── check_extended_fg.py │ │ ├── evaluate_comp1k.py │ │ ├── extend_fg.py │ │ ├── filter_comp1k_anno.py │ │ └── preprocess_comp1k_dataset.py │ ├── denoising/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── deraining/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── df2k_ost/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ └── preprocess_df2k_ost_dataset.py │ ├── div2k/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ └── preprocess_div2k_dataset.py │ ├── dpdd/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── glean/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── preprocess_cat_test_dataset.py │ │ ├── preprocess_cat_train_dataset.py │ │ └── preprocess_ffhq_celebahq_dataset.py │ ├── gopro/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── hide/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── live1/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── ntire21_decompression/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── paired-pix2pix/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── paris-street-view/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── places365/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── realblur/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── realsrset/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── reds/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ ├── crop_sub_images.py │ │ └── preprocess_reds_dataset.py │ ├── sidd/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ └── preprocess_sidd_test_dataset.py │ ├── spmcs/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── udm10/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── unconditional_gans/ │ │ └── README.md │ ├── unpaired-cyclegan/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── vid4/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ └── preprocess_vid4_dataset.py │ ├── videolq/ │ │ ├── README.md │ │ └── README_zh-CN.md │ ├── vimeo90k/ │ │ ├── README.md │ │ ├── README_zh-CN.md │ │ └── preprocess_vimeo90k_dataset.py │ └── vimeo90k-triplet/ │ ├── README.md │ └── README_zh-CN.md ├── dist_test.sh ├── dist_train.sh ├── gui/ │ ├── README.md │ ├── component.py │ ├── gui.py │ ├── page_general.py │ ├── page_sr.py │ └── utils.py ├── model_converters/ │ └── publish_model.py ├── slurm_test.sh ├── slurm_train.sh ├── test.py └── train.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .circleci/config.yml ================================================ version: 2.1 # this allows you to use CircleCI's dynamic configuration feature setup: true # the path-filtering orb is required to continue a pipeline based on # the path of an updated fileset orbs: path-filtering: circleci/path-filtering@0.1.2 workflows: # the always-run workflow is always triggered, regardless of the pipeline parameters. always-run: jobs: # the path-filtering/filter job determines which pipeline # parameters to update. - path-filtering/filter: name: check-updated-files # 3-column, whitespace-delimited mapping. One mapping per # line: # mapping: | configs/.* lint_only true docs/.* lint_only true .dev_scripts/.* lint_only true .github/.* lint_only true demo/.* lint_only true projects/.* lint_only true mmagic/.* lint_only false requirements/.* lint_only false tests/.* lint_only false .circleci/.* lint_only false tools/.* lint_only true base-revision: main # this is the path of the configuration we should trigger once # path filtering and pipeline parameter value updates are # complete. In this case, we are using the parent dynamic # configuration itself. config-path: .circleci/test.yml ================================================ FILE: .circleci/docker/Dockerfile ================================================ ARG PYTORCH="1.8.1" ARG CUDA="10.2" ARG CUDNN="7" FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel # To fix GPG key error when running apt-get update RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub RUN apt-get update && apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx git ================================================ FILE: .circleci/test.yml ================================================ version: 2.1 # the default pipeline parameters, which will be updated according to # the results of the path-filtering orb parameters: lint_only: type: boolean default: true jobs: lint: docker: - image: cimg/python:3.7.4 steps: - checkout - run: name: Install pre-commit hook command: | pip install pre-commit pre-commit install - run: name: Linting command: pre-commit run --all-files - run: name: Check docstring coverage command: | pip install interrogate interrogate -v --ignore-init-method --ignore-module --ignore-nested-functions --ignore-magic --ignore-regex "__repr__" --fail-under 90 mmagic build_cpu: parameters: # The python version must match available image tags in # https://circleci.com/developer/images/image/cimg/python python: type: string torch: type: string torchvision: type: string docker: - image: cimg/python:<< parameters.python >> resource_class: large steps: - checkout - run: name: Install Libraries command: | sudo apt-get update sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 - run: name: Configure Python & pip command: | pip install --upgrade pip pip install wheel - run: name: Install PyTorch command: | python -V pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html - run: name: Install mmagic dependencies command: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - run: name: Build and install command: | pip install -e . - run: name: Run unittests command: | coverage run --branch --source mmagic -m pytest tests/ coverage xml coverage report -m build_cuda: parameters: torch: type: string cuda: type: enum enum: ["10.1", "10.2", "11.1"] cudnn: type: integer default: 7 machine: image: ubuntu-2004-cuda-11.4:202110-01 # docker_layer_caching: true resource_class: gpu.nvidia.small steps: - checkout - run: # Cloning repos in VM since Docker doesn't have access to the private key name: Clone Repos command: | git clone -b main --depth 1 https://github.com/open-mmlab/mmengine.git /home/circleci/mmengine - run: name: Build Docker image command: | docker build .circleci/docker -t mmagic:gpu --build-arg PYTORCH=<< parameters.torch >> --build-arg CUDA=<< parameters.cuda >> --build-arg CUDNN=<< parameters.cudnn >> docker run --gpus all -t -d -v /home/circleci/project:/mmagic -v /home/circleci/mmengine:/mmengine -v /home/circleci/mmdetection:/mmdetection -w /mmagic --name mmagic mmagic:gpu - run: name: Install mmagic dependencies command: | docker exec mmagic pip install -e /mmengine docker exec mmagic pip install -U openmim docker exec mmagic mim install 'mmcv >= 2.0.0' docker exec mmagic pip install -r requirements/tests.txt - run: name: Build and install command: | docker exec mmagic pip install -e . - run: name: Run unittests command: | docker exec mmagic pytest tests/ workflows: pr_stage_lint: when: << pipeline.parameters.lint_only >> jobs: - lint: name: lint filters: branches: ignore: - dev-1.x - main pr_stage_test: when: not: << pipeline.parameters.lint_only >> jobs: - lint: name: lint filters: branches: ignore: - dev-1.x - main - build_cpu: name: minimum_version_cpu torch: 1.10.0 torchvision: 0.11.0 python: 3.8.15 requires: - lint - build_cpu: name: maximum_version_cpu torch: 1.13.0 torchvision: 0.14.0 python: 3.8.15 requires: - minimum_version_cpu # - hold: # type: approval # requires: # - maximum_version_cpu # - build_cuda: # name: mainstream_version_gpu # torch: 1.8.1 # # Use double quotation mark to explicitly specify its type # # as string instead of number # cuda: "10.2" # requires: # - hold merge_stage_test: when: not: << pipeline.parameters.lint_only >> jobs: - build_cuda: name: minimum_version_gpu torch: 1.8.1 # Use double quotation mark to explicitly specify its type # as string instead of number cuda: "10.2" filters: branches: only: - dev-1.x ================================================ FILE: .dele.yml ================================================ dele_rules: issue: create: - name: "english needs" conditions: - "issue.title ~= ANSI" actions: - comment: message: "@{{ issue.author.name }}, english-please." - name: "add assignee" conditions: - "issue.assignees.count == 0" actions: - assign_with_owners - name: "set stale" conditions: - "issue.status.inactive_time >= 30d" actions: - label: add: ["stale"] - comment: message: "This issue will be closed in 5 days because it has been open 30 days with no activity, comment it or remove stale label to avoid it." pull_request: create: - name: "add size label" conditions: - "pr.labels ~= size/*" actions: - label: add: ["size"] - name: "welcome new contributor" conditions: - "pr.author.login ~= first_pr" actions: - comment: message: "Welcome @{{ pr.author.login }}! Thanks for your contribution to {{ pr.org }}/{{ .pr.repo }} 🎉" ================================================ FILE: .dev_scripts/README.md ================================================ # Scripts for developing MMagic - [1. Check UT](#1-check-ut) - [2. Test all the models](#2-test-all-the-models) - [3. Train all the models](#3-train-all-the-models) - [3.1 Train for debugging](#31-train-for-debugging) - [3.2 Train for FP32](#32-train-for-fp32) - [3.3 Train for FP16](#33-train-for-fp16) - [4. Monitor your training](#4-monitor-your-training) - [5. Train with a list of models](#5-train-with-a-list-of-models) - [6. Train with skipping a list of models](#6-train-with-skipping-a-list-of-models) - [7. Train failed or canceled jobs](#7-train-failed-or-canceled-jobs) - [8. Deterministic training](#8-deterministic-training) - [9. Automatically check links](#9-automatically-check-links) - [10. Calculate flops](#10-calculate-flops) - [11. Update model idnex](#11-update-model-index) ## 1. Check UT Please check your UT by the following scripts: ```python cd mmagic/ python .dev_script/update_ut.py ``` Then, you will find some redundant UT, missing UT and blank UT. Please create UTs according to your package code implementation. ## 2. Test all the models Please follow these steps to test all the models in MMagic: First, you will need download all the pre-trained checkpoints by: ```shell python .dev_scripts/download_models.py ``` Then, you can start testing all the benchmarks by: ```shell python .dev_scripts/test_benchmark.py ``` ## 3. Train all the models ### 3.1 Train for debugging In order to test all the pipelines of training, visualization, etc., you may want to set the total iterations of all the models as less steps (e.g., 100 steps) for quick evaluation. You can use the following steps: First, since our datasets are stored in ceph, you need to create ceph configs. ```shell # create configs python .dev_scripts/create_ceph_configs.py \ --target-dir configs_ceph_debug \ --gpus-per-job 2 \ --iters 100 \ --save-dir-prefix work_dirs/benchmark_debug \ --work-dir-prefix work_dirs/benchmark_debug ``` If you only want to update a specific config file, you can specify it by `--test-file configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py`. Here, `--target-dir` denotes the path of new created configs, `--gpus-per-job` denotes the numbers of gpus used for each job, `--iters` denotes the total iterations of each model, `--save-dir-prefix` and `--work-dir-prefix` denote the working directory, where you can find the working logging. Then, you will need to submit all the jobs by running `train_benchmark.py`. ```shell python .dev_scripts/train_benchmark.py mm_lol \ --config-dir configs_ceph_debug \ --run \ --gpus-per-job 2 \ --job-name debug \ --work-dir work_dirs/benchmark_debug \ --resume \ --quotatype=auto ``` Here, you will specify the configs files used for training by `--config-dir`, submit all the jobs to run by set `--run`. You can set the prefix name of the submitted jobs by `--job-name`, specify the working directory by `--work-dir`. We suggest using `--resume` to enable auto resume during training and `--quotatype=auto` to fully exploit all the computing resources. ### 3.2 Train for FP32 If you want to train all the models with FP32 (i.e, regular settings as the same with `configs/`), you can follow these steps: ```shell # create configs for fp32 python .dev_scripts/create_ceph_configs.py \ --target-dir configs_ceph_fp32 \ --gpus-per-job 4 \ --save-dir-prefix work_dirs/benchmark_fp32 \ --work-dir-prefix work_dirs/benchmark_fp32 \ ``` Then, submit the jobs to run by slurm: ```shell python .dev_scripts/train_benchmark.py mm_lol \ --config-dir configs_ceph_fp32 \ --run \ --resume \ --gpus-per-job 4 \ --job-name fp32 \ --work-dir work_dirs/benchmark_fp32 \ --quotatype=auto ``` ### 3.3 Train for FP16 You will also need to train the models with AMP (i.e., FP16), you can use the following steps to achieve this: ```shell python .dev_scripts/create_ceph_configs.py \ --target-dir configs_ceph_amp \ --gpus-per-job 4 \ --save-dir-prefix work_dirs/benchmark_amp \ --work-dir-prefix work_dirs/benchmark_amp ``` Then, submit the jobs to run: ```shell python .dev_scripts/train_benchmark.py mm_lol \ --config-dir configs_ceph_amp \ --run \ --resume \ --gpus-per-job 4 \ --amp \ --job-name amp \ --work-dir work_dirs/benchmark_amp \ --quotatype=auto ``` ## 4. Monitor your training After you submitting jobs following [3-Train-all-the-models](#3-train-all-the-models), you will find a `xxx.log` file. This log file list all the job name of job id you have submitted. With this log file, you can monitor your training by running `.dev_scripts/job_watcher.py`. For example, you can run ```shell python .dev_scripts/job_watcher.py --work-dir work_dirs/benchmark_fp32/ --log 20220923-140317.log ``` Then, you will find `20220923-140317.csv`, which reports the status and recent log of each job. ## 5. Train with a list of models If you only need to run some of the models, you can list all the models' name in a file, and specify the models when using `train_benchmark.py`. For example, ```shell python .dev_scripts/train_benchmark.py mm_lol \ --config-dir configs_ceph_fp32 \ --run \ --resume \ --gpus-per-job 4 \ --job-name fp32 \ --work-dir work_dirs/benchmark_fp32 \ --quotatype=auto \ --rerun \ --rerun-list 20220923-140317.log \ ``` Specifically, you need to enable `--rerun`, and specify the list of models to rerun by `--rerun-list` ## 6. Train with skipping a list of models If you want to train all the models while skipping some models, you can also list all the models' name in a file, and specify the models when running `train_benchmark.py`. For example, ```shell python .dev_scripts/train_benchmark.py mm_lol \ --config-dir configs_ceph_fp32 \ --run \ --resume \ --gpus-per-job 4 \ --job-name fp32 \ --work-dir work_dirs/benchmark_fp32 \ --quotatype=auto \ --skip \ --skip-list 20220923-140317.log \ ``` Specifically, you need to enable `--skip`, and specify the list of models to skip by `--skip-list` ## 7. Train failed or canceled jobs If you want to rerun failed or canceled jobs in the last run, you can combine `--rerun` flag with `--rerun-failure` and `--rerun-cancel` flags. For example, the log file of the last run is `train-20221009-211904.log`, and now you want to rerun the failed jobs. You can use the following command: ```bash python .dev_scripts/train_benchmark.py mm_lol \ --job-name RERUN \ --rerun train-20221009-211904.log \ --rerun-fail \ --run ``` We can combine `--rerun-fail` and `--rerun-cancel` with flag `---models` to rerun a **subset** of failed or canceled model. ```bash python .dev_scripts/train_benchmark.py mm_lol \ --job-name RERUN \ --rerun train-20221009-211904.log \ --rerun-fail \ --models sagan \ # only rerun 'sagan' models in all failed tasks --run ``` Specifically, `--rerun-fail` and `--rerun-cancel` can be used together to rerun both failed and cancaled jobs. ## 8. `deterministic` training Set `torch.backends.cudnn.deterministic = True` and `torch.backends.cudnn.benchmark = False` can remove randomness operation in Pytorch training. You can add `--deterministic` flag when start your benchmark training to remove the influence of randomness operation. ```shell python .dev_scripts/train_benchmark.py mm_lol --job-name xzn --models pix2pix --cpus-per-job 16 --run --deterministic ``` ## 9. Automatically check links Use the following script to check whether the links in documentations are valid: ```shell python .dev_scripts/doc_link_checker.py --target docs/zh_cn python .dev_scripts/doc_link_checker.py --target README_zh-CN.md python .dev_scripts/doc_link_checker.py --target docs/en python .dev_scripts/doc_link_checker.py --target README.md ``` You can specify the `--target` by a file or a directory. **Notes:** DO NOT use it in CI, because requiring too many http requirements by CI will cause 503 and CI will propabaly fail. ## 10. Calculate flops To summarize the flops of different models, you can run the following commands: ```bash python .dev_scripts/benchmark_valid_flop.py --flops --flops-str ``` ## 11. Update model index To update model-index according to `README.md`, please run the following commands, ```bash python .dev_scripts/update_model_index.py ``` ================================================ FILE: .dev_scripts/create_ceph_configs.py ================================================ import glob import os.path as osp import shutil from argparse import ArgumentParser from copy import deepcopy from mmengine import Config from tqdm import tqdm def update_intervals(config, args): if args.iters is None: return config # 1. change max-iters and val-interval if 'train_cfg' in config and config['train_cfg']: config['train_cfg'] = dict( type='IterBasedTrainLoop', max_iters=args.iters, val_interval=args.iters // 5) # 2. change logging interval if 'default_hooks' in config and config['default_hooks']: config['default_hooks']['logger'] = dict( type='LoggerHook', interval=args.iters // 10) config['default_hooks']['checkpoint'] = dict( type='CheckpointHook', interval=args.iters // 15) return config def convert_data_config(data_cfg): ceph_dataroot_prefix_temp = 'openmmlab:s3://openmmlab/datasets/{}/' local_dataroot_prefix = ['data', './data'] # val_dataloader may None if data_cfg is None: return data_cfg_updated = deepcopy(data_cfg) dataset: dict = data_cfg['dataset'] dataset_type: str = dataset['type'] if dataset_type in ['ImageNet', 'CIFAR10']: repo_name = 'classification' else: repo_name = 'editing' ceph_dataroot_prefix = ceph_dataroot_prefix_temp.format(repo_name) if 'data_root' in dataset: data_root: str = dataset['data_root'] for dataroot_prefix in local_dataroot_prefix: if data_root.startswith(dataroot_prefix): # avoid cvt './data/imagenet' -> # openmmlab:s3://openmmlab/datasets/classification//imagenet if data_root.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' data_root = data_root.replace(dataroot_prefix, ceph_dataroot_prefix) # add '/' at the end if not data_root.endswith('/'): data_root = data_root + '/' dataset['data_root'] = data_root elif 'data_roots' in dataset: # specific for pggan dataset, which need a dict of data_roots data_roots: dict = dataset['data_roots'] for k, data_root in data_roots.items(): for dataroot_prefix in local_dataroot_prefix: if data_root.startswith(dataroot_prefix): # avoid cvt './data/imagenet' -> # openmmlab:s3://openmmlab/datasets/classification//imagenet if data_root.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' data_root = data_root.replace(dataroot_prefix, ceph_dataroot_prefix) # add '/' at the end if not data_root.endswith('/'): data_root = data_root + '/' data_roots[k] = data_root dataset['data_roots'] = data_roots else: raise KeyError if hasattr(dataset, 'pipeline'): pipelines = dataset['pipeline'] for pipeline in pipelines: type_ = pipeline['type'] # only change mmcv(mmcls)'s loading config if type_ == 'mmcls.LoadImageFromFile': pipeline['file_client_args'] = dict(backend='petrel') elif type_ == 'LoadMask': if 'mask_list_file' in pipeline['mask_config']: local_mask_path = pipeline['mask_config']['mask_list_file'] for dataroot_prefix in local_dataroot_prefix: if local_mask_path.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' local_mask_path = local_mask_path.replace( dataroot_prefix, ceph_dataroot_prefix) pipeline['mask_config']['mask_list_file'] = local_mask_path pipeline['mask_config']['prefix'] = osp.dirname( local_mask_path) pipeline['mask_config']['io_backend'] = 'petrel' pipeline['mask_config']['file_client_kwargs'] = dict( backend='petrel') elif type_ == 'RandomLoadResizeBg': bg_dir_path = pipeline['bg_dir'] for dataroot_prefix in local_dataroot_prefix: if bg_dir_path.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' bg_dir_path = bg_dir_path.replace(dataroot_prefix, ceph_dataroot_prefix) bg_dir_path = bg_dir_path.replace(repo_name, 'detection') pipeline['bg_dir'] = bg_dir_path elif type_ == 'CompositeFg': fg_dir_path = pipeline['fg_dirs'] for i, fg in enumerate(fg_dir_path): for dataroot_prefix in local_dataroot_prefix: if fg.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' fg = fg.replace(dataroot_prefix, ceph_dataroot_prefix) pipeline['fg_dirs'][i] = fg alpha_dir_path = pipeline['alpha_dirs'] for i, alpha_dir in enumerate(alpha_dir_path): for dataroot_prefix in local_dataroot_prefix: if alpha_dir.startswith(dataroot_prefix + '/'): dataroot_prefix = dataroot_prefix + '/' alpha_dir = alpha_dir.replace(dataroot_prefix, ceph_dataroot_prefix) pipeline['alpha_dirs'][i] = alpha_dir data_cfg_updated['dataset'] = dataset return data_cfg_updated def update_ceph_config(filename, args, dry_run=False): if filename.startswith(osp.join(args.target_dir, '_base_')): # Skip base configs return None if args.ceph_path is not None: if args.ceph_path.endswith('/'): args.ceph_path = args.ceph_path[:-1] work_dir = f'{args.ceph_path}/{args.work_dir_prefix}' save_dir = f'{args.ceph_path}/{args.save_dir_prefix}' if not work_dir.endswith('/'): work_dir = work_dir + '/' if not save_dir.endswith('/'): save_dir = save_dir + '/' else: # disable save local results to ceph work_dir = args.work_dir_prefix save_dir = args.save_dir_prefix try: config = Config.fromfile(filename) # 0. update intervals config = update_intervals(config, args) # 1. change dataloader dataloader_prefix = [ f'{p}_dataloader' for p in ['train', 'val', 'test'] ] for prefix in dataloader_prefix: if not hasattr(config, prefix): continue data_cfg = config[prefix] if not isinstance(data_cfg, list): data_cfg_list = [data_cfg] data_cfg_is_list = False else: data_cfg_list = data_cfg data_cfg_is_list = True data_cfg_updated_list = [ convert_data_config(cfg) for cfg in data_cfg_list ] if data_cfg_is_list: config[prefix] = data_cfg_updated_list else: config[prefix] = data_cfg_updated_list[0] # 2. change visualizer if hasattr(config, 'vis_backends'): # TODO: support upload to ceph # for vis_cfg in config['vis_backends']: # if vis_cfg['type'] == 'VisBackend': # vis_cfg['ceph_path'] = work_dir # add pavi config if args.add_pavi: _, project, name = filename.split('/') name = name[:-2] # check if pavi config is inheritance from _base_ find_inherit = False for vis_cfg in config['vis_backends']: if vis_cfg['type'] == 'PaviVisBackend': vis_cfg['exp_name'] = name vis_cfg['project'] = project find_inherit = True break if not find_inherit: pavi_cfg = dict( type='PaviVisBackend', exp_name=name, project=project) config['vis_backends'].append(pavi_cfg) # add wandb config if args.add_wandb: _, project, name = filename.split('/') name = name[:-2] # check if wandb config is inheritance from _base_ find_inherit = False for vis_cfg in config['vis_backends']: if vis_cfg['type'] == 'WandbVisBackend': vis_cfg['name'] = name # name of config vis_cfg['project'] = project # name of model find_inherit = True break if not find_inherit: pavi_cfg = dict( type='WandbVisBackend', init_kwargs=dict(name=name, project=project)) config['vis_backends'].append(pavi_cfg) # add tensorboard config if args.add_tensorboard: find_inherit = False for vis_cfg in config['vis_backends']: if vis_cfg['type'] == 'TensorboardVisBackend': find_inherit = True break if not find_inherit: tensorboard_cfg = dict(type='TensorboardVisBackend') config['vis_backends'].append(tensorboard_cfg) config['visualizer']['vis_backends'] = config['vis_backends'] # 3. change logger hook and checkpoint hook if hasattr(config, 'default_hooks'): # file_client_args = dict(backend='petrel') for name, hooks in config['default_hooks'].items(): if name == 'logger': hooks['out_dir'] = save_dir # hooks['file_client_args'] = file_client_args elif name == 'checkpoint': hooks['out_dir'] = save_dir # hooks['file_client_args'] = file_client_args # 4. save config.dump(config.filename) return True except Exception as e: # noqa print(e) return False if __name__ == '__main__': parser = ArgumentParser() parser.add_argument('--ceph-path', type=str, default=None) parser.add_argument('--gpus-per-job', type=int, default=None) parser.add_argument( '--save-dir-prefix', type=str, default='work_dirs', help='Default prefix of the work dirs in the bucket') parser.add_argument( '--work-dir-prefix', type=str, default='work_dirs', help='Default prefix of the work dirs in the bucket') parser.add_argument( '--target-dir', type=str, default='configs_ceph', help='configs path') parser.add_argument( '--iters', type=int, default=None, help='set intervals') parser.add_argument( '--test-file', type=str, default=None, help='Dry-run on a test file.') parser.add_argument( '--add-pavi', action='store_true', help='Add pavi config or not.') parser.add_argument( '--add-wandb', action='store_true', help='Add wandb config or not.') parser.add_argument( '--add-tensorboard', action='store_true', help='Add Tensorboard config or not.') args = parser.parse_args() if args.test_file is None: print('Copying config files to "config_ceph" ...') shutil.copytree('configs', args.target_dir, dirs_exist_ok=True) print('Updating ceph configuration ...') files = glob.glob( osp.join(args.target_dir, '**', '*.py'), recursive=True) pbars = tqdm(files) res = [] for f in pbars: pbars.set_description(f'Processing {f}') res.append(update_ceph_config(f, args)) count_skip = res.count(None) count_done = res.count(True) count_fail = res.count(False) fail_list = [fn for status, fn in zip(res, files) if status is False] skip_list = [fn for status, fn in zip(res, files) if status is None] print(f'Successfully update {count_done} configs.') print(f'Skip {count_skip} configs.') if count_skip > 0: print(skip_list) print(f'Fail {count_fail} configs.') if count_fail > 0: print(fail_list) else: shutil.copy(args.test_file, args.test_file.replace('configs', args.target_dir)) update_ceph_config( args.test_file.replace('configs', args.target_dir), args, dry_run=True) ================================================ FILE: .dev_scripts/doc_link_checker.py ================================================ # Copyright (c) MegFlow. All rights reserved. # Copyright (c) OpenMMLab. All rights reserved. # /bin/python3 import argparse import os import re import requests from tqdm import tqdm def make_parser(): parser = argparse.ArgumentParser('Doc link checker') parser.add_argument( '--target', default='./docs', type=str, help='the directory or file to check') parser.add_argument( '--ignore', type=str, nargs='+', default=[], help='input image size') return parser pattern = re.compile(r'\[.*?\]\(.*?\)') def analyze_doc(home, path): problem_list = [] code_block = 0 with open(path) as f: lines = f.readlines() for line in lines: line = line.strip() if line.startswith('```'): code_block = 1 - code_block if code_block > 0: continue if '[' in line and ']' in line and '(' in line and ')' in line: all = pattern.findall(line) for item in all: # skip ![]() if item.find('[') == item.find(']') - 1: continue # process the case [text()]() offset = item.find('](') if offset == -1: continue item = item[offset:] start = item.find('(') end = item.find(')') ref = item[start + 1:end] if ref.startswith('http'): if ref.startswith( 'https://download.openmmlab.com/' ) or ref.startswith('http://download.openmmlab.com/'): resp = requests.head(ref) if resp.status_code == 200: continue else: problem_list.append(ref) else: continue if ref.startswith('#'): continue if ref == '<>': continue if '.md#' in ref: ref = ref[:ref.find('#')] if ref.startswith('/'): fullpath = os.path.join( os.path.dirname(__file__), '../', ref[1:]) else: fullpath = os.path.join(home, ref) if not os.path.exists(fullpath): problem_list.append(ref) else: continue if len(problem_list) > 0: print(f'{path}:') for item in problem_list: print(f'\t {item}') print('\n') raise Exception('found link error') def traverse(args): target = args.target if os.path.isfile(target): analyze_doc(os.path.dirname(target), target) return target_files = list(os.walk(target)) target_files.sort() for home, dirs, files in tqdm(target_files): if home in args.ignore: continue for filename in files: if filename.endswith('.md'): path = os.path.join(home, filename) if os.path.islink(path) is False: analyze_doc(home, path) if __name__ == '__main__': args = make_parser().parse_args() traverse(args) ================================================ FILE: .dev_scripts/download_models.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import platform import posixpath as osp # Even on windows, use posixpath import re import subprocess from collections import OrderedDict from importlib.machinery import SourceFileLoader from pathlib import Path from modelindex import load MMagic_ROOT = Path(__file__).absolute().parent.parent DOWNLOAD_DIR = osp.join(MMagic_ROOT, 'work_dirs', 'download') IS_WINDOWS = (platform.system() == 'Windows') def additional_download(args): """Download additional weights file used in this repo, such as VGG.""" url_path = [ 'https://www.adrianbulat.com/downloads/python-fan/2DFAN4-cd938726ad.zip', # noqa 'https://www.adrianbulat.com/downloads/python-fan/s3fd-619a316812.pth', 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth' ] checkpoint_root = args.checkpoint_root if not checkpoint_root: checkpoint_root = DOWNLOAD_DIR for url in url_path: path = osp.join(checkpoint_root, 'hub', 'checkpoints', osp.basename(url)) print() print(f'download {path} from {url}') if IS_WINDOWS: if args.dry_run: print(f'Call \'wget.download({url}, {path})\'') else: import wget wget.download(url, path) else: if args.dry_run: print(f'wget --no-check-certificate -N {url} {path}') else: os.system(f'wget --no-check-certificate -N {url} {path}') def parse_args(): parser = argparse.ArgumentParser(description='Download the checkpoints') parser.add_argument('--checkpoint-root', help='Checkpoint file root path.') parser.add_argument( '--models', nargs='+', type=str, help='Specify model names to run.') parser.add_argument( '--force', action='store_true', help='Whether force re-download the checkpoints.') parser.add_argument( '--model-list', type=str, help='Path of algorithm list to download') parser.add_argument( '--dry-run', action='store_true', help='Only show download command but not run') args = parser.parse_args() return args def download(args): model_index_file = MMagic_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() models = OrderedDict({model.name: model for model in model_index.models}) http_prefix_short = 'https://download.openmmlab.com/mmediting/' # load model list if args.model_list: file_list_path = args.model_list file_list = SourceFileLoader('model_list', file_list_path).load_module().model_list else: file_list = None if args.models: patterns = [re.compile(pattern) for pattern in args.models] filter_models = {} for k, v in models.items(): if any([re.match(pattern, k) for pattern in patterns]): filter_models[k] = v if len(filter_models) == 0: print('No model found, please specify models in:') print('\n'.join(models.keys())) return models = filter_models checkpoint_root = args.checkpoint_root if not checkpoint_root: checkpoint_root = DOWNLOAD_DIR for model_info in models.values(): if file_list is not None and model_info.name not in file_list: continue model_weight_url = model_info.weights if model_weight_url.startswith(http_prefix_short): model_name = model_weight_url[len(http_prefix_short):] elif model_weight_url == '': print(f'{model_info.Name} weight is missing') return None else: raise ValueError(f'Unknown url prefix. \'{model_weight_url}\'') model_name_split = model_name.split('/') if len(model_name_split) == 3: # 'TASK/METHOD/MODEL.pth' # remove task name model_name = osp.join(*model_name_split[1:-1]) else: model_name = osp.join(*model_name_split[:-1]) ckpt_name = model_weight_url.split('/')[-1] download_path = osp.join(checkpoint_root, model_name, ckpt_name) download_root = osp.join(checkpoint_root, model_name) if osp.exists(download_path): print(f'Already exists {download_path}') # do not delete when dry-run is true if args.force and not args.dry_run: print(f'Delete {download_path} to force re-download.') os.system(f'rm -rf {download_path}') else: continue try: cmd_str_list = [ 'wget', '-q', '--show-progress', '-p', download_root, model_weight_url ] if args.dry_run: print(' '.join(cmd_str_list)) else: subprocess.run(cmd_str_list, check=True) except Exception: # for older version of wget cmd_str_list = ['wget', '-P', download_root, model_weight_url] if args.dry_run: print(' '.join(cmd_str_list)) else: subprocess.run(cmd_str_list, check=True) if __name__ == '__main__': args = parse_args() download(args) additional_download(args) ================================================ FILE: .dev_scripts/inference_benchmark.sh ================================================ python demo/download_inference_resources.py # Text-to-Image python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir demo_text2image_stable_diffusion_res.png python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 1 \ --text "Room with blue walls and a yellow ceiling." \ --control 'https://user-images.githubusercontent.com/28132635/230297033-4f5c32df-365c-4cf4-8e4f-1b76a4cbb0b7.png' \ --result-out-dir demo_text2image_controlnet_canny_res.png python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 2 \ --text "masterpiece, best quality, sky, black hair, skirt, sailor collar, looking at viewer, short hair, building, bangs, neckerchief, long sleeves, cloudy sky, power lines, shirt, cityscape, pleated skirt, scenery, blunt bangs, city, night, black sailor collar, closed mouth" \ --control 'https://user-images.githubusercontent.com/28132635/230380893-2eae68af-d610-4f7f-aa68-c2f22c2abf7e.png' \ --result-out-dir demo_text2image_controlnet_pose_res.png python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 3 \ --text "black house, blue sky" \ --control 'https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/243599897-553a4c46-c61d-46df-b820-59a49aaf6678.png' \ --result-out-dir demo_text2image_controlnet_seg_res.png # Conditional GANs python demo/mmagic_inference_demo.py \ --model-name biggan \ --model-setting 3 \ --label 1 \ --result-out-dir demo_conditional_biggan_res.jpg # Unconditional GANs python demo/mmagic_inference_demo.py \ --model-name styleganv1 \ --result-out-dir demo_unconditional_styleganv1_res.jpg # Image Translation python demo/mmagic_inference_demo.py \ --model-name pix2pix \ --img ./resources/input/translation/gt_mask_0.png \ --result-out-dir ./resources/output/translation/demo_translation_pix2pix_res.png # Inpainting python demo/mmagic_inference_demo.py \ --model-name deepfillv2 \ --img ./resources/input/inpainting/celeba_test.png \ --mask ./resources/input/inpainting/bbox_mask.png \ --result-out-dir ./resources/output/inpainting/demo_inpainting_deepfillv2_res. # Matting python demo/mmagic_inference_demo.py \ --model-name aot_gan \ --img ./resources/input/matting/GT05.jpg \ --trimap ./resources/input/matting/GT05_trimap.jpg \ --result-out-dir ./resources/output/matting/demo_matting_gca_res.png # Image Restoration python demo/mmagic_inference_demo.py \ --model-name nafnet \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_nafnet_res.png # Image Super-resolution python demo/mmagic_inference_demo.py \ --model-name esrgan \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_esrgan_res.png python demo/mmagic_inference_demo.py \ --model-name ttsr \ --img ./resources/input/restoration/000001.png \ --ref ./resources/input/restoration/000001.png \ --result-out-dir ./resources/output/restoration/demo_restoration_ttsr_res.png # Video Super-Resolution python demo/mmagic_inference_demo.py \ --model-name basicvsr \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_basicvsr_res.mp4 python demo/mmagic_inference_demo.py \ --model-name edvr \ --extra-parameters window_size=5 \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_edvr_res.mp4 python demo/mmagic_inference_demo.py \ --model-name tdan \ --model-setting 2 \ --extra-parameters window_size=5 \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_tdan_res.mp4 # Video interpolation python demo/mmagic_inference_demo.py \ --model-name flavr \ --video ./resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4 \ --result-out-dir ./resources/output/video_interpolation/demo_video_interpolation_flavr_res.mp4 # Image Colorization python demo/mmagic_inference_demo.py \ --model-name inst_colorization \ --img https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg \ --result-out-dir demo_colorization_res.png # 3D-aware Generation python demo/mmagic_inference_demo.py \ --model-name eg3d \ --result-out-dir ./resources/output/eg3d-output ================================================ FILE: .dev_scripts/job_watcher.py ================================================ import os import os.path as osp import time from argparse import ArgumentParser from functools import partial from prettytable import PrettyTable from pygments import formatters, highlight, lexers from pygments.util import ClassNotFound from simple_term_menu import TerminalMenu CACHE_DIR = osp.join(osp.abspath('~'), '.task_watcher') def show_job_out(name, root, job_name_list): if name == 'Show Status': return show_job_status(root, job_name_list) job_id, job_name = name.split(' @ ') job_out_path = osp.join(root, job_name, f'job.{job_id.strip()}.out') try: with open(job_out_path, 'r') as file: out_content = file.read() except Exception: out_content = f'{job_out_path} not find.' out_content = out_content.split('\n')[-20:] out_content = '\n'.join(out_content) try: lexer = lexers.get_lexer_for_filename( job_out_path, stripnl=False, stripall=False) except ClassNotFound: lexer = lexers.get_lexer_by_name('text', stripnl=False, stripall=False) formatter = formatters.TerminalFormatter(bg='dark') # dark or light highlighted_file_content = highlight(out_content, lexer, formatter) return highlighted_file_content def show_job_status(root, job_name_list, csv_path=None): """Show job status and dump to csv. Args: root (_type_): _description_ job_name_list (_type_): _description_ Returns: _type_: _description_ """ table = PrettyTable(title='Job Status') table.field_names = ['Name', 'ID', 'Status', 'Output'] swatch_tmp = 'swatch examine {}' if csv_path is None: csv_path = 'status.cvs' for info in job_name_list: id_, name = info.split(' @ ') name = name.split('\n')[0].strip() proc = os.popen(swatch_tmp.format(id_)) stdout = proc.read().strip().split('\n') job_info = [s for s in stdout[2].split(' ') if s] status = job_info[5] job_out_path = osp.join(root, name, f'job.{id_.strip()}.out') if osp.exists(job_out_path): with open(job_out_path, 'r') as file: out_content = file.read() out_content = out_content.split('\n') if len(out_content) > 10: out_content = out_content[-7:-1] out_content = '\n'.join(out_content) else: out_content = 'No output currently.' table.add_row([name, id_, status, out_content]) with open(csv_path, 'w') as file: file.write(table.get_csv_string()) print(f'save job status to {csv_path}') return table.get_string() def save_for_resume(root, job_name_list): """Save job name and job ID for resume. Args: root (_type_): _description_ job_name_list (_type_): _description_ """ timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())) os.makedirs(CACHE_DIR, exist_ok=True) with open(osp.join(CACHE_DIR, timestamp), 'w') as file: file.write(f'{root}\n') file.writelines([n + '\n' for n in job_name_list]) with open(osp.join(CACHE_DIR, 'latest'), 'w') as file: file.write(f'{root}\n') file.writelines([n + '\n' for n in job_name_list]) def resume_from_file(file_path): """Resume TUI from file. Args: file_path (_type_): _description_ """ with open((file_path), 'r') as file: resume_info = file.readlines() resume_info = [info.strip() for info in resume_info] root = resume_info[0] job_name_list = resume_info[1:] show_tui(root, job_name_list) def start_from_proc(root, proc): """Start TUI from proc. Args: root (_type_): _description_ proc (_type_): _description_ """ std_out = proc.read().strip() std_out_list = std_out.split('\n') num_tasks = len(std_out_list) // 3 job_name_list = [] for idx in range(num_tasks): config = std_out_list[3 * idx].strip(' ') job_name = config.split('/')[-1].split('.')[0].strip(' ') job_id = std_out_list[3 * idx + 2].split(' ')[-1] job_name_list.append(f'{job_id} @ {job_name}') return job_name_list # save_for_resume(root, job_name_list) # show_tui(root, job_name_list) def show_tui(root, job_name_list): """Start a interactivate task watcher. Args: root (str): root for benchmark job_name_list (list[str]): List of 'JOBID @ JOBNAME' """ show_func = partial(show_job_out, root=root, job_name_list=job_name_list) terminal_menu = TerminalMenu( job_name_list + ['Show Status'], preview_command=show_func, preview_size=0.75) terminal_menu.show() if __name__ == '__main__': parser = ArgumentParser() parser.add_argument('--list', type=str, default=None) parser.add_argument('--resume', default='latest') parser.add_argument( '--work-dir', type=str, default='work_dirs/benchmark_amp') parser.add_argument( '--type', type=str, default='failed', choices=['running', 'success', 'queue', 'failed', 'all'], ) args = parser.parse_args() if args.list is not None: f = open(args.list, 'r') job_name_list = f.readlines() csv_path = osp.basename(args.list).replace('.log', '.csv') plain_txt = show_job_status(args.work_dir, job_name_list, csv_path) with open('status.log', 'w') as f: f.write(plain_txt) print('save status to status.log') else: if args.resume.upper() == 'LATEST': resume_from_file(osp.join(CACHE_DIR, 'latest')) else: resume_from_file(args.resume) ================================================ FILE: .dev_scripts/metric_mapping.py ================================================ # key-in-metafile: key-in-results.pkl METRICS_MAPPING = { 'FID': { 'keys': ['FID-Full-50k/fid'], 'tolerance': 0.5, 'rule': 'less' }, 'PSNR': { 'keys': ['PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'SSIM': { 'keys': ['MattingSSIM', 'SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'l1 error': { 'keys': ['MAE'], 'tolerance': 0.1, 'rule': 'less' }, 'CONN': { 'keys': ['ConnectivityError'], 'tolerance': 0.1, 'rule': 'less' }, 'GRAD': { 'keys': ['GradientError'], 'tolerance': 0.1, 'rule': 'less' }, 'MSE': { 'keys': ['MSE', 'MattingMSE'], 'tolerance': 0.1, 'rule': 'less' }, 'SAD': { 'keys': ['SAD'], 'tolerance': 0.1, 'rule': 'less' }, 'NIQE (Y)': { 'keys': ['NIQE'], 'tolerance': 0.1, 'rule': 'less' }, # verbose metric mapping for VSR 'REDS4 (BIx4) PSNR (RGB)': { 'keys': ['REDS4-BIx4-RGB/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vimeo-90K-T (BIx4) PSNR (Y)': { 'keys': ['Vimeo-90K-T-BIx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vimeo-90K-T (BDx4) PSNR (Y)': { 'keys': ['Vimeo-90K-T-BDx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'UDM10 (BDx4) PSNR (Y)': { 'keys': ['UDM10-BDx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vid4 (BDx4) PSNR (Y)': { 'keys': ['VID4-BDx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vid4 (BIx4) PSNR (Y)': { 'keys': ['VID4-BIx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'SPMCS-30 (BDx4) PSNR (Y)': { 'keys': ['SPMCS-BDx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'SPMCS-30 (BIx4) PSNR (Y)': { 'keys': ['SPMCS-BIx4-Y/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'REDS4 (BIx4) SSIM (RGB)': { 'keys': ['REDS4-BIx4-RGB/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vimeo-90K-T (BIx4) SSIM (Y)': { 'keys': ['Vimeo-90K-T-BIx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vimeo-90K-T (BDx4) SSIM (Y)': { 'keys': ['Vimeo-90K-T-BDx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'UDM10 (BDx4) SSIM (Y)': { 'keys': ['UDM10-BDx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vid4 (BDx4) SSIM (Y)': { 'keys': ['VID4-BDx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Vid4 (BIx4) SSIM (Y)': { 'keys': ['VID4-BIx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'SPMCS-30 (BDx4) SSIM (Y)': { 'keys': ['SPMCS-BDx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'SPMCS-30 (BIx4) SSIM (Y)': { 'keys': ['SPMCS-BIx4-Y/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Set5 SSIM': { 'keys': ['Set5/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Set5 PSNR': { 'keys': ['Set5/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'Set14 SSIM': { 'keys': ['Set14/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'Set14 PSNR': { 'keys': ['Set14/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, 'DIV2K SSIM': { 'keys': ['DIV2K/SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'DIV2K PSNR': { 'keys': ['DIV2K/PSNR'], 'tolerance': 0.1, 'rule': 'larger' }, } # add LIIF metrics liif_metrics = {} for dataset in ['Set5', 'Set14', 'DIV2K']: for metric, tolerance in zip(['PSNR', 'SSIM'], [0.1, 0.1]): for scale in [2, 3, 4, 6, 18, 30]: liif_metrics[f'{dataset}x{scale} {metric}'] = { 'keys': [f'{dataset}x{scale}/{metric}'], 'tolerance': 0.1, 'rule': 'larger' } METRICS_MAPPING.update(liif_metrics) def filter_metric(metric_mapping, summary_data): used_metric = dict() for metric, metric_info in metric_mapping.items(): for data_dict in summary_data.values(): if metric in data_dict: used_metric[metric] = metric_info break return used_metric ================================================ FILE: .dev_scripts/task_mapping.py ================================================ TASK_MAPPING = { 'Inpainting': [ 'aot-gan', 'deepfillv1', 'deepfillv2', 'global_local', 'partial_conv', ], 'Matting': [ 'dim', 'gca', 'indexnet', ], 'Restoreration': [ 'srcnn', 'srresnet_srgan', 'edsr', 'esrgan', 'rdn', 'dic', 'ttsr', 'glean', ], 'LIIF': ['liif'], 'Video_restoration': [ 'edvr', 'tof', 'tdan', 'basicvsr', 'basicvsr_plusplus', 'iconvsr', 'real_basicvsr', ], 'Video_interpolation': [ 'cain', 'flavr', 'tof', ] } ================================================ FILE: .dev_scripts/test_benchmark.py ================================================ import argparse import os import os.path as osp import pickle import re from collections import OrderedDict, defaultdict from datetime import datetime from importlib.machinery import SourceFileLoader from pathlib import Path from job_watcher import start_from_proc from metric_mapping import METRICS_MAPPING, filter_metric from modelindex.load_model_index import load from rich.console import Console from rich.syntax import Syntax from rich.table import Table from task_mapping import TASK_MAPPING console = Console() MMagic_ROOT = Path(__file__).absolute().parents[1] def parse_args(): parser = argparse.ArgumentParser( description="Test all models' accuracy in model-index.yml") parser.add_argument( 'partition', type=str, help='Cluster partition to use.') parser.add_argument('checkpoint_root', help='Checkpoint file root path.') parser.add_argument( '--job-name', type=str, default=' ', help='Slurm job name prefix') parser.add_argument('--port', type=int, default=29666, help='dist port') parser.add_argument( '--use-ceph-config', action='store_true', default=False, help='Use ceph configs or not.') parser.add_argument( '--models', nargs='+', type=str, help='Specify model names to run.') parser.add_argument( '--work-dir', default='work_dirs/benchmark_test', help='the dir to save metric') parser.add_argument( '--run', action='store_true', help='run script directly') parser.add_argument( '--local', action='store_true', help='run at local instead of cluster.') parser.add_argument( '--mail', type=str, help='Mail address to watch test status.') parser.add_argument( '--mail-type', nargs='+', default=['BEGIN'], choices=['NONE', 'BEGIN', 'END', 'FAIL', 'REQUEUE', 'ALL'], help='Mail address to watch test status.') parser.add_argument( '--quotatype', default=None, choices=['reserved', 'auto', 'spot'], help='Quota type, only available for phoenix-slurm>=0.2') parser.add_argument( '--summary', action='store_true', help='Summarize benchmark test results.') parser.add_argument( '--by-task', action='store_true', help='Summairze benchmark results by task.') parser.add_argument('--save', action='store_true', help='Save the summary') group_parser = parser.add_mutually_exclusive_group() group_parser.add_argument( '--P0', action='store_true', help='Whether test model in P0 list') group_parser.add_argument( '--model-list', type=str, default='', help='Path of algorithm list to load') args = parser.parse_args() return args def create_test_job_batch(commands, model_info, args, port, script_name): config_http_prefix_blob = ('https://github.com/open-mmlab/mmagic/' 'blob/main/') config_http_prefix_tree = ('https://github.com/open-mmlab/mmagic/' 'tree/main/') fname = model_info.name config = model_info.config if config.startswith('http'): config = config.replace(config_http_prefix_blob, './') config = config.replace(config_http_prefix_tree, './') if args.use_ceph_config: config = config.replace('configs', 'configs_ceph') config = Path(config) assert config.exists(), f'{fname}: {config} not found.' http_prefix_short = 'https://download.openmmlab.com/mmediting/' model_weight_url = model_info.weights if model_weight_url.startswith(http_prefix_short): model_name = model_weight_url[len(http_prefix_short):] elif model_weight_url == '': print(f'{fname} weight is missing') return None else: raise ValueError(f'Unknown url prefix. \'{model_weight_url}\'') model_name_split = model_name.split('/') if len(model_name_split) == 3: # 'TASK/METHOD/MODEL.pth' # remove task name model_name = osp.join(*model_name_split[1:]) else: model_name = osp.join(*model_name_split) if 's3://' in args.checkpoint_root: from mmengine.fileio import FileClient from petrel_client.common.exception import AccessDeniedError file_client = FileClient.infer_client(uri=args.checkpoint_root) checkpoint = file_client.join_path(args.checkpoint_root, model_name) try: exists = file_client.exists(checkpoint) except AccessDeniedError: exists = False else: checkpoint_root = Path(args.checkpoint_root) checkpoint = checkpoint_root / model_name exists = checkpoint.exists() if not exists: print(f'WARNING: {fname}: {checkpoint} not found.') return None job_name = f'{args.job_name}_{fname}'.strip('_') work_dir = Path(args.work_dir) / fname work_dir.mkdir(parents=True, exist_ok=True) result_file = work_dir / 'result.pkl' if args.mail is not None and 'NONE' not in args.mail_type: mail_cfg = (f'#SBATCH --mail {args.mail}\n' f'#SBATCH --mail-type {args.mail_type}\n') else: mail_cfg = '' if args.quotatype is not None: quota_cfg = f'#SBATCH --quotatype {args.quotatype}\n' else: quota_cfg = '' launcher = 'none' if args.local else 'slurm' runner = 'python' if args.local else 'srun python' # NOTE: set gpus as 2 job_script = (f'#!/bin/bash\n' f'#SBATCH --output {work_dir}/job.%j.out\n' f'#SBATCH --partition={args.partition}\n' f'#SBATCH --job-name {job_name}\n' f'#SBATCH --gres=gpu:2\n' f'{mail_cfg}{quota_cfg}' f'#SBATCH --ntasks-per-node=2\n' f'#SBATCH --ntasks=2\n' f'#SBATCH --cpus-per-task=16\n\n' f'export MASTER_PORT={port}\n' f'export CUBLAS_WORKSPACE_CONFIG=:4096:8\n' f'{runner} -u {script_name} {config} {checkpoint} ' f'--work-dir={work_dir} ' f'--out={result_file} ' f'--launcher={launcher}\n') with open(work_dir / 'job.sh', 'w') as f: f.write(job_script) commands.append(f'echo "{config}"') commands.append(f'echo "{work_dir}"') if args.local: commands.append(f'bash {work_dir}/job.sh') else: commands.append(f'sbatch {work_dir}/job.sh') return work_dir / 'job.sh' def test(args): # parse model-index.yml model_index_file = MMagic_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() models = OrderedDict({model.name: model for model in model_index.models}) script_name = osp.join('tools', 'test.py') port = args.port commands = [] if args.models: patterns = [re.compile(pattern) for pattern in args.models] filter_models = {} for k, v in models.items(): if any([re.match(pattern, k) for pattern in patterns]): filter_models[k] = v if len(filter_models) == 0: print('No model found, please specify models in:') print('\n'.join(models.keys())) return models = filter_models # load model list if args.P0: file_list = osp.join(osp.dirname(__file__), 'p0_test_list.py') elif args.model_list: file_list = args.model_list else: file_list = None if file_list: test_list = SourceFileLoader('model_list', file_list).load_module().model_list else: test_list = None preview_script = '' for model_info in models.values(): if model_info.results is None: continue if test_list is not None and model_info.name not in test_list: continue script_path = create_test_job_batch(commands, model_info, args, port, script_name) preview_script = script_path or preview_script port += 1 command_str = '\n'.join(commands) preview = Table() preview.add_column(str(preview_script)) preview.add_column('Shell command preview') preview.add_row( Syntax.from_path( preview_script, background_color='default', line_numbers=True, word_wrap=True), Syntax( command_str, 'bash', background_color='default', line_numbers=True, word_wrap=True)) console.print(preview) if args.run: proc = os.popen(command_str) job_name_list = start_from_proc(args.work_dir, proc) history_log = datetime.now().strftime('test-%Y%m%d-%H%M%S') + '.log' with open(history_log, 'w') as fp: fp.write(args.work_dir + '\n') for job in job_name_list: fp.write(job + '\n') cache_path = osp.expanduser(osp.join('~', '.task_watcher')) # print(cache_path) os.makedirs(cache_path, exist_ok=True) with open(osp.join(cache_path, 'latest.log'), 'w') as fp: fp.write(args.work_dir + '\n') for job in job_name_list: fp.write(job + '\n') print(f'Have saved job submission history in {history_log}') else: console.print('Please set "--run" to start the job') def show_summary(summary_data, models_map, work_dir, name='test_benchmark_summary', save=False): # table = Table(title='Test Benchmark Regression Summary') table_title = name.replace('_', ' ') table_title = table_title.capitalize() table = Table(title=table_title) table.add_column('Model') md_header = ['Model'] used_metrics = filter_metric(METRICS_MAPPING, summary_data) for metric in used_metrics: table.add_column(f'{metric} (expect)') table.add_column(f'{metric}') md_header.append(f'{metric} (expect)') md_header.append(f'{metric}') table.add_column('Date') md_header.append('Config') def set_color(value, expect, tolerance, rule): if value > expect + tolerance: return 'green' if rule == 'larger' else 'red' elif value < expect - tolerance: return 'red' if rule == 'larger' else 'green' else: return 'white' md_rows = ['| ' + ' | '.join(md_header) + ' |\n'] md_rows.append('|:' + ':|:'.join(['---'] * len(md_header)) + ':|\n') for model_name, summary in summary_data.items(): row = [model_name] md_row = [model_name] for metric_key in used_metrics: if metric_key in summary: metric = summary[metric_key] expect = round(metric['expect'], 2) result = round(metric['result'], 2) tolerance = metric['tolerance'] rule = metric['rule'] color = set_color(result, expect, tolerance, rule) row.append(f'{expect:.2f}') row.append(f'[{color}]{result:.2f}[/{color}]') md_row.append(f'{expect:.4f}') md_row.append(f'{result:.4f}') else: row.extend([''] * 2) md_row.extend([''] * 2) if 'date' in summary: row.append(summary['date']) md_row.append(summary['date']) else: row.append('') md_row.append('') table.add_row(*row) # add config to row model_info = models_map[model_name] md_row.append(model_info.config) md_rows.append('| ' + ' | '.join(md_row) + ' |\n') console.print(table) if save: summary_path = work_dir / f'{name}.md' with open(summary_path, 'w') as file: file.write('# Test Benchmark Regression Summary\n') file.writelines(md_rows) def summary(args): model_index_file = MMagic_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() models = OrderedDict({model.name: model for model in model_index.models}) work_dir = Path(args.work_dir) if args.models: patterns = [re.compile(pattern) for pattern in args.models] filter_models = {} for k, v in models.items(): if any([re.match(pattern, k) for pattern in patterns]): filter_models[k] = v if len(filter_models) == 0: print('No model found, please specify models in:') print('\n'.join(models.keys())) return models = filter_models summary_data = {} task_summary_data = defaultdict(dict) for model_name, model_info in models.items(): if model_info.results is None: continue # Skip if not found result file. result_file = work_dir / model_name / 'result.pkl' if not result_file.exists(): summary_data[model_name] = {} continue with open(result_file, 'rb') as file: results = pickle.load(file) date = datetime.fromtimestamp(result_file.lstat().st_mtime) expect_metrics = model_info.results[0].metrics # extract metrics summary = {'date': date.strftime('%Y-%m-%d')} for key_yml, value_yml in METRICS_MAPPING.items(): key_results = value_yml['keys'] tolerance = value_yml['tolerance'] rule = value_yml['rule'] for key_result in key_results: if key_yml in expect_metrics and key_result in results: expect_result = float(expect_metrics[key_yml]) result = float(results[key_result]) summary[key_yml] = dict( expect=expect_result, result=result, tolerance=tolerance, rule=rule) summary_data[model_name] = summary in_collection = model_info.data['In Collection'] for task, collection_list in TASK_MAPPING.items(): if in_collection.upper() in [c.upper() for c in collection_list]: task_summary_data[task][model_name] = summary break if args.by_task: for task_name, data in task_summary_data.items(): show_summary( data, models, work_dir, f'{task_name}_summary', save=args.save) show_summary(summary_data, models, work_dir, save=args.save) def main(): args = parse_args() if args.summary: summary(args) else: test(args) if __name__ == '__main__': main() ================================================ FILE: .dev_scripts/test_benchmark.yml ================================================ cases: - name: controlnet-1xb1-fill50k params: config: configs/controlnet/controlnet-1xb1-fill50k.py cpus_per_node: 16 gpus: 1 gpus_per_node: 1 - name: dreambooth params: config: configs/dreambooth/dreambooth.py cpus_per_node: 16 gpus: 1 gpus_per_node: 1 - name: basicvsr-pp_c64n7_8xb1-600k_reds4 params: checkpoint: basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth config: configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py cpus_per_node: 16 gpus: 4 gpus_per_node: 4 results: dataset: REDS4(BIx4) eval: - PSNR - SSIM metrics: PSNR (RGB): 32.3855 SSIM (RGB): 0.9069 - name: realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds params: checkpoint: realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth config: configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: REDS eval: - NIQE metrics: NIQE (Y): 3.7662 - name: stylegan2_c2_8xb4-800kiters_ffhq-256x256 params: checkpoint: stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth checkpoint_url: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth config: configs/styleganv2/stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py cpus_per_node: 4 gpus: 8 gpus_per_node: 8 results: dataset: FFHQ256 metrics: FID-50k: 3.992 - name: deepfillv2_8xb2_celeba-256x256 params: checkpoint: deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth checkpoint_url: https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth config: configs/deepfillv2/deepfillv2_8xb2_celeba-256x256.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: CelebA-val metrics: PSNR: 25.721 SSIM: 0.871 l1 error: 5.411 - name: realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost params: checkpoint: realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth config: configs/real_esrgan/realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: df2k_ost metrics: PSNR: 28.0297 SSIM: 0.8236 cluster_num: '2' default_floating_range: 1.0 model_floating_ranges: {} partition: mm_lol repo: mmagic branch: test task_type: test third_part_libs: [] ================================================ FILE: .dev_scripts/train_benchmark.py ================================================ import argparse import os import os.path as osp import pickle import re from collections import OrderedDict from datetime import datetime from pathlib import Path from job_watcher import start_from_proc from modelindex.load_model_index import load from rich.console import Console from rich.syntax import Syntax from rich.table import Table from tqdm import tqdm from utils import filter_jobs, parse_job_list_from_file console = Console() MMAGIC_ROOT = Path(__file__).absolute().parents[1] # key-in-metafile: key-in-results.pkl METRICS_MAP = { 'SWD': { 'keys': ['SWD/avg'], 'tolerance': 0.1, 'rule': 'less' }, 'MS-SSIM': { 'keys': ['MS-SSIM'], 'tolerance': 0.1, 'rule': 'larger' }, 'FID': { 'keys': ['FID-Full-50k/fid'], 'tolerance': 0.1, 'rule': 'less' }, 'FID50k': { 'keys': ['FID-Full-50k/fid'], 'tolerance': 0.1, 'rule': 'less' }, 'IS': { 'keys': ['IS-50k/is'], 'tolerance': 0.1, 'rule': 'larger' }, 'IS50k': { 'keys': ['IS-50k/is'], 'tolerance': 0.1, 'rule': 'larger' }, 'Precision50k': { 'keys': ['PR-50K/precision'], 'tolerance': 0.1, 'rule': 'large' }, 'Recall50k': { 'keys': ['PR-50K/recall'], 'tolerance': 0.1, 'rule': 'large' }, 'Precision10k': { 'keys': ['PR-10K/precision'], 'tolerance': 0.1, 'rule': 'large' }, 'Recall10k': { 'keys': ['PR-10K/recall'], 'tolerance': 0.1, 'rule': 'large' }, # 'PPL': {}, # TODO: no ppl in metafiles? 'EQ-R': { 'keys': ['EQ/eqr'], 'tolerance': 0.1, 'rule': 'larger' }, 'EQ-T': { 'keys': ['EQ/eqt_int'], 'tolerance': 0.1, 'rule': 'larger' }, } def parse_args(): parser = argparse.ArgumentParser( description="Train models' accuracy in model-index.yml") parser.add_argument( 'partition', type=str, help='Cluster partition to use.') parser.add_argument('--skip', type=str, default=None) parser.add_argument('--skip-list', default=None) parser.add_argument('--rerun', type=str, default=None) parser.add_argument( '--rerun-fail', action='store_true', help='only rerun failed tasks') parser.add_argument( '--rerun-cancel', action='store_true', help='only rerun cancel tasks') parser.add_argument('--rerun-list', default=None) parser.add_argument('--gpus-per-job', type=int, default=None) parser.add_argument('--cpus-per-job', type=int, default=16) parser.add_argument( '--amp', action='store_true', help='Whether to use amp.') parser.add_argument( '--resume', action='store_true', help='Whether to resume checkpoint.') parser.add_argument( '--job-name', type=str, default=' ', help='Slurm job name prefix') parser.add_argument('--port', type=int, default=29666, help='dist port') parser.add_argument( '--config-dir', type=str, default='configs_ceph', help='Use ceph configs or not.') parser.add_argument( '--models', nargs='+', type=str, help='Specify model names to run.') parser.add_argument( '--work-dir', default='work_dirs/benchmark_train', help='the dir to save metric') parser.add_argument( '--deterministic', action='store_true', help='Whether set `deterministic` during training.') parser.add_argument( '--run', action='store_true', help='run script directly') parser.add_argument( '--local', action='store_true', help='run at local instead of cluster.') parser.add_argument( '--mail', type=str, help='Mail address to watch train status.') parser.add_argument( '--mail-type', nargs='+', default=['BEGIN'], choices=['NONE', 'BEGIN', 'END', 'FAIL', 'REQUEUE', 'ALL'], help='Mail address to watch train status.') parser.add_argument( '--quotatype', default=None, choices=['reserved', 'auto', 'spot'], help='Quota type, only available for phoenix-slurm>=0.2') parser.add_argument( '--summary', action='store_true', help='Summarize benchmark train results.') parser.add_argument('--save', action='store_true', help='Save the summary') args = parser.parse_args() if args.skip is not None: with open(args.skip, 'r') as fp: skip_list = fp.readlines() skip_list = [j.split('\n')[0] for j in skip_list] args.skip_list = skip_list print('skip_list: ', args.skip_list) elif args.rerun is not None: job_id_list_full, job_name_list_full = parse_job_list_from_file( args.rerun) filter_target = [] if args.rerun_fail: filter_target += ['FAILED'] if args.rerun_cancel: filter_target += ['CANCELLED'] _, job_name_list = filter_jobs( job_id_list_full, job_name_list_full, filter_target, show_table=True, table_name='Rerun List') args.rerun_list = job_name_list return args def create_train_job_batch(commands, model_info, args, port, script_name): config_http_prefix_blob = ('https://github.com/open-mmlab/mmagic/' 'blob/main/') config_http_prefix_tree = ('https://github.com/open-mmlab/mmagic/' 'tree/main/') fname = model_info.name config = model_info.config if config.startswith('http'): config = config.replace(config_http_prefix_blob, './') config = config.replace(config_http_prefix_tree, './') config = config.replace('configs', args.config_dir) config = Path(config) assert config.exists(), f'{fname}: {config} not found.' try: n_gpus = int(model_info.metadata.data['GPUs'].split()[0]) except Exception: if 'official' in model_info.config: return None else: pattern = r'\d+xb\d+' parse_res = re.search(pattern, config.name) if not parse_res: # defaults to use 1 gpu n_gpus = 1 else: n_gpus = int(parse_res.group().split('x')[0]) if args.gpus_per_job is not None: n_gpus = min(args.gpus_per_job, n_gpus) job_name = f'{args.job_name}_{fname}' if (args.skip_list is not None) and model_info.name in args.skip_list: return None if (args.rerun_list is not None) and (model_info.name not in args.rerun_list): return None work_dir = Path(args.work_dir) / fname work_dir.mkdir(parents=True, exist_ok=True) if args.mail is not None and 'NONE' not in args.mail_type: mail_cfg = (f'#SBATCH --mail {args.mail}\n' f'#SBATCH --mail-type {args.mail_type}\n') else: mail_cfg = '' if args.quotatype is not None: quota_cfg = f'#SBATCH --quotatype {args.quotatype}\n' else: quota_cfg = '' launcher = 'none' if args.local or n_gpus == 0 else 'slurm' runner = 'python' if args.local else 'srun python' job_script = (f'#!/bin/bash\n' f'#SBATCH --output {work_dir}/job.%j.out\n' f'#SBATCH --partition={args.partition}\n' f'#SBATCH --job-name {job_name}\n' f'{mail_cfg}{quota_cfg}') if n_gpus > 0: job_script += (f'#SBATCH --gres=gpu:{n_gpus}\n' f'#SBATCH --ntasks-per-node={min(n_gpus, 8)}\n' f'#SBATCH --ntasks={n_gpus}\n' f'#SBATCH --cpus-per-task={args.cpus_per_job}\n\n') else: job_script += '\n\n' + 'export CUDA_VISIBLE_DEVICES=-1\n' if args.deterministic: job_script += 'export CUBLAS_WORKSPACE_CONFIG=:4096:8\n' job_script += (f'export MASTER_PORT={port}\n' f'{runner} -u {script_name} {config} ' f'--work-dir={work_dir} ' f'--launcher={launcher}') if args.resume: job_script += ' --resume ' if args.amp: job_script += ' --amp ' if args.deterministic: job_script += ' --cfg-options randomness.deterministic=True' job_script += '\n' with open(work_dir / 'job.sh', 'w') as f: f.write(job_script) commands.append(f'echo "{config}"') commands.append(f'echo "{work_dir}"') if args.local: commands.append(f'bash {work_dir}/job.sh') else: commands.append(f'sbatch {work_dir}/job.sh') return work_dir / 'job.sh' def train(args): # parse model-index.yml model_index_file = MMAGIC_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() models = OrderedDict({model.name: model for model in model_index.models}) script_name = osp.join('tools', 'train.py') port = args.port commands = [] if args.models: patterns = [re.compile(pattern) for pattern in args.models] filter_models = {} for k, v in models.items(): if any([re.match(pattern, k) for pattern in patterns]): filter_models[k] = v if len(filter_models) == 0: print('No model found, please specify models in:') print('\n'.join(models.keys())) return models = filter_models preview_script = '' pbar = tqdm(models.values()) for model_info in pbar: if model_info.results is None: continue model_name = model_info.name pbar.set_description(model_name) if 'cvt' in model_name: print(f'Skip converted config: {model_name} ({model_info.config})') continue script_path = create_train_job_batch(commands, model_info, args, port, script_name) if script_path is not None: preview_script = script_path or preview_script port += 1 command_str = '\n'.join(commands) preview = Table() preview.add_column(str(preview_script)) preview.add_column('Shell command preview') preview.add_row( Syntax.from_path( preview_script, background_color='default', line_numbers=True, word_wrap=True), Syntax( command_str, 'bash', background_color='default', line_numbers=True, word_wrap=True)) console.print(preview) if args.run: proc = os.popen(command_str) job_name_list = start_from_proc(args.work_dir, proc) history_log = datetime.now().strftime('train-%Y%m%d-%H%M%S') + '.log' with open(history_log, 'w') as fp: for job in job_name_list: fp.write(job + '\n') fp.close() print(f'Have saved job submission history in {history_log}') else: console.print('Please set "--run" to start the job') def show_summary(summary_data, models_map, work_dir, save=False): table = Table(title='Train Benchmark Regression Summary') table.add_column('Model') md_header = ['Model'] for metric in METRICS_MAP: table.add_column(f'{metric} (expect)') table.add_column(f'{metric}') md_header.append(f'{metric} (expect)') md_header.append(f'{metric}') table.add_column('Date') md_header.append('Config') def set_color(value, expect, tolerance, rule): if value > expect + tolerance: return 'green' if rule == 'larger' else 'red' elif value < expect - tolerance: return 'red' if rule == 'larger' else 'green' else: return 'white' md_rows = ['| ' + ' | '.join(md_header) + ' |\n'] md_rows.append('|:' + ':|:'.join(['---'] * len(md_header)) + ':|\n') for model_name, summary in summary_data.items(): row = [model_name] md_row = [model_name] for metric_key in METRICS_MAP: if metric_key in summary: metric = summary[metric_key] expect = round(metric['expect'], 2) result = round(metric['result'], 2) tolerance = metric['tolerance'] rule = metric['rule'] color = set_color(result, expect, tolerance, rule) row.append(f'{expect:.2f}') row.append(f'[{color}]{result:.2f}[/{color}]') md_row.append(f'{expect:.2f}') md_row.append(f'{result:.2f}') else: row.extend([''] * 2) md_row.extend([''] * 2) if 'date' in summary: row.append(summary['date']) md_row.append(summary['date']) else: row.append('') md_row.append('') table.add_row(*row) # add config to row model_info = models_map[model_name] md_row.append(model_info.config) md_rows.append('| ' + ' | '.join(md_row) + ' |\n') console.print(table) if save: summary_path = work_dir / 'train_benchmark_summary.md' with open(summary_path, 'w') as file: file.write('# Train Benchmark Regression Summary\n') file.writelines(md_rows) def summary(args): model_index_file = MMAGIC_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() models = OrderedDict({model.name: model for model in model_index.models}) work_dir = Path(args.work_dir) if args.models: patterns = [re.compile(pattern) for pattern in args.models] filter_models = {} for k, v in models.items(): if any([re.match(pattern, k) for pattern in patterns]): filter_models[k] = v if len(filter_models) == 0: print('No model found, please specify models in:') print('\n'.join(models.keys())) return models = filter_models summary_data = {} for model_name, model_info in models.items(): if model_info.results is None: continue # Skip if not found result file. result_file = work_dir / model_name / 'result.pkl' if not result_file.exists(): summary_data[model_name] = {} continue with open(result_file, 'rb') as file: results = pickle.load(file) date = datetime.fromtimestamp(result_file.lstat().st_mtime) expect_metrics = model_info.results[0].metrics # extract metrics summary = {'date': date.strftime('%Y-%m-%d')} for key_yml, key_tolerance in METRICS_MAP.items(): key_results = key_tolerance['keys'] tolerance = key_tolerance['tolerance'] rule = key_tolerance['rule'] for key_result in key_results: if key_yml in expect_metrics and key_result in results: expect_result = float(expect_metrics[key_yml]) result = float(results[key_result]) summary[key_yml] = dict( expect=expect_result, result=result, tolerance=tolerance, rule=rule) summary_data[model_name] = summary show_summary(summary_data, models, work_dir, args.save) # if args.save: # save_summary(summary_data, models, work_dir) def main(): args = parse_args() if args.summary: summary(args) else: train(args) if __name__ == '__main__': main() ================================================ FILE: .dev_scripts/train_benchmark.yml ================================================ cases: - name: controlnet-1xb1-fill50k params: config: configs/controlnet/controlnet-1xb1-fill50k.py cpus_per_node: 16 gpus: 1 gpus_per_node: 1 - name: dreambooth params: config: configs/dreambooth/dreambooth.py cpus_per_node: 16 gpus: 1 gpus_per_node: 1 - name: basicvsr-pp_c64n7_8xb1-600k_reds4 params: checkpoint: basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth config: configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py cpus_per_node: 16 gpus: 4 gpus_per_node: 4 results: dataset: REDS4(BIx4) eval: - PSNR - SSIM metrics: PSNR (RGB): 32.3855 SSIM (RGB): 0.9069 - name: realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds params: checkpoint: realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth config: configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: REDS eval: - NIQE metrics: NIQE (Y): 3.7662 - name: stylegan2_c2_8xb4-800kiters_ffhq-256x256 params: checkpoint: stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth checkpoint_url: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth config: configs/styleganv2/stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py cpus_per_node: 4 gpus: 8 gpus_per_node: 8 results: dataset: FFHQ256 metrics: FID-50k: 3.992 - name: deepfillv2_8xb2_celeba-256x256 params: checkpoint: deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth checkpoint_url: https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth config: configs/deepfillv2/deepfillv2_8xb2_celeba-256x256.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: CelebA-val metrics: PSNR: 25.721 SSIM: 0.871 l1 error: 5.411 - name: realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost params: checkpoint: realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth checkpoint_url: https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth config: configs/real_esrgan/realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py cpus_per_node: 16 gpus: 8 gpus_per_node: 8 results: dataset: df2k_ost metrics: PSNR: 28.0297 SSIM: 0.8236 cluster_num: '2' default_floating_range: 1.0 model_floating_ranges: {} partition: mm_lol repo: mmagic branch: test task_type: train third_part_libs: [] ================================================ FILE: .dev_scripts/update_config_readme.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. # This tool is used to update README.md and README_zh-CN.md in configs import glob import os import posixpath as osp # Even on windows, use posixpath import re import sys MMagic_ROOT = osp.dirname(osp.dirname(osp.dirname(__file__))) def update_md(md_file): """Update README.md and README_zh-CN.md. Args: md_file (str): Path to .md file. Returns: Bool: If the target README.md file is different from the original. """ # See https://github.com/open-mmlab/mmagic/pull/798 for these comments # unique_dict = generate_unique_name(md_file) md_file = md_file.replace(os.sep, '/') config_dir, _ = osp.split(md_file) files = os.listdir(config_dir) config_files = [file for file in files if file.endswith('.py')] for readme in ['README.md', 'README_zh-CN.md']: readme = osp.join(config_dir, readme) changed = False with open(readme, 'r', encoding='utf-8') as f: data = f.read() for config in config_files: _, ext = osp.splitext(config) if ext != '.py': continue re_config = config.replace('.', '\\.') re_config = config.replace('-', '\\-') re_result = re.search(rf'\]\(/(.*?)/{re_config}', data) if re_result is None: print(f'Warning: No {config} in {readme}') continue old_dir = re_result.groups()[0] if old_dir != config_dir: data = data.replace(old_dir, config_dir) print(f'from {old_dir} to {config_dir}') changed = True if changed: with open(readme, 'w', encoding='utf-8') as f: f.write(data) return False if __name__ == '__main__': if len(sys.argv) <= 1: configs_root = osp.join(MMagic_ROOT, 'configs') file_list = glob.glob( osp.join(configs_root, '**', '*README.md'), recursive=True) file_list.sort() else: file_list = [ fn for fn in sys.argv[1:] if osp.basename(fn) == 'README.md' ] if not file_list: sys.exit(0) file_modified = False for fn in file_list: print(f'process {fn}') file_modified |= update_md(fn) sys.exit(1 if file_modified else 0) ================================================ FILE: .dev_scripts/update_model_index.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. """This tool is used to update model-index.yml which is required by MIM, and will be automatically called as a pre-commit hook. The updating will be triggered if any change of model information (.md files in configs/) has been detected before a commit. The design of the metafile follows /wikcnz2ksDIyZiFM8iAMUoTmNHg. It is forbidden to set value as `NULL`, `None` or empty list and str. `Collection`: indicates a algorithm (which may contains multiple configs), e.g. Mask R-CNN - `Name` (str): required - `README` (str): optional - `Paper` (dict): optional - `URL` (str): required - `Title` (str): required - `Task` (List[str]): optional - `Year` (int): optional - `Metadata` (dict): optional - `Architecture` (List[str]): optional - `Training Data` (Union[str, List[str]]): optional - `Epochs` (int): optional - `Batch Size` (int): optional - `Training Techniques` (List[str]): optional - `Training Resources` (str): optional - `FLOPs` (Union[int, float]): optional - `Parameters` (int): optional - `Training Time` (Union[int, float]): optional - `Train time (s/iter)` (Union[int, float]): optional - `Training Memory (GB)` (float): optional - `Weights` (Union[str, List[str]]): optional `Model`: indicates a specific config - `Name` (str): required, globally unique - `In Collection` (str): required - `Config` (str): required - `Results` (List[dict]): required - `Task` (str): required - `Dataset` (str): required - `Metrics` (dict): required - `Weights` (str): optional - `Metadata` (dict): optional - `Architecture` (List[str]): optional - `Training Resources` (str): optional - `Training Data` (Union[str, List[str]]): optional - `Epochs` (int): optional - `Batch Size` (int): optional - `Training Techniques` (List[str]): optional - `FLOPs` (Union[int, float]): optional - `Parameters` (int): optional - `Training Time` (Union[int, float]): optional - `Train time (s/iter)` (Union[int, float]): optional - `Training Memory (GB)` (float): optional - `inference time (ms/im)` (List[dict]): optional - `value` (float): required - `hardware` (str): required - `backend` (str): required - `batch size` (str): required - `mode` (str): required, e.g., FP32, FP16, INT8, etc. - `resolution` (Tuple(int, int)): required - `Training Log` (str): optional - `README` (str): optional - `Paper` (dict): optional - `URL` (str): required - `Title` (str): required - `Converted From` (dict): optional - `Weights` (str): required - `Code` (str): required - `Code` (dict): optional - `URL` (str): required - `Version` (str): required - `Image` (str): optional The README.md file in MMagic follows following convention, - `Model`: [name_in_the_paper](path_to_config) - `Download`: [model](url_to_pre_trained_weights) | [log](url_to_log) """ import glob import posixpath as osp # Even on windows, use posixpath import re import sys import tqdm from modelindex.models.Collection import Collection from modelindex.models.Metadata import Metadata from modelindex.models.Model import Model from modelindex.models.Result import Result from utils import (collate_metrics, dump_yaml_and_check_difference, found_table, modelindex_to_dict) MMagic_ROOT = osp.dirname(osp.dirname(__file__)) KEYWORDS = [ 'Model', 'Dataset', 'Download', ] def parse_md(md_file): """Parse .md file and convert it to a .yml file which can be used for MIM. Args: md_file (str): Path to .md file. Returns: Bool: If the target YAML file is different from the original. """ readme = osp.relpath(md_file, MMagic_ROOT) readme = readme.replace('\\', '/') # for windows collection = Collection() collection_meta = Metadata() # force utf-8 instead of system defined with open(md_file, 'r', encoding='utf-8') as md: lines = md.readlines() # parse information for collection name = lines[0][2:] name, year = name.split('(', 1) year = int(re.sub('[^0-9]', '', year)) collection_name = name.strip() task_line = lines[4] model_task = task_line.strip().split(':')[-1].strip() model_task_list = model_task.lower().split(', ') collection.name = collection_name collection.readme = readme collection.data['Year'] = year collection.data['Task'] = model_task_list collection_meta.architecture = [collection_name] i = 0 model_list = {} while i < len(lines): # parse reference if lines[i].startswith('> ['): title, url = re.match(r'> \[(.*)]\((.*)\)', lines[i]).groups() collection.paper = dict(URL=url, Title=title) i += 1 # parse table elif found_table(lines, i): cols = [col.strip() for col in lines[i].split('|')][1:-1] # check required field for Model try: model_idx = cols.index('Model') dataset_idx = cols.index('Dataset') download_idx = cols.index('Download') used_metrics = collate_metrics(cols) if 'Task' in cols: task_idx = cols.index('Task') else: task_idx = None except Exception: raise ValueError( f'required fields: Model, Dataset, Download ' f'are not included in line {i+1} of {md_file}') j = i + 2 # parse table for valid fields while j < len(lines) and lines[j][0] == '|': line = lines[j].split('|')[1:-1] # name, in_collection, config of Model assert line[model_idx].find( '](') >= 0, f'invalid {model_idx} in {line} for {md_file}.' left = line[model_idx].index('](') + 2 right = line[model_idx].index(')', left) config = line[model_idx][left:right].strip('./') model_name = osp.splitext(osp.basename(config))[0] if model_name in model_list: model = model_list[model_name] else: model = Model( name=model_name, in_collection=collection_name, config=osp.join( osp.dirname(md_file), model_name + '.py')) model_list[model_name] = model # find results in each row dataset = line[dataset_idx].replace(' ', '') metrics = {} for metric_name, idx in used_metrics.items(): value = line[idx] value = value.replace('*', '') if '/' not in value: try: value = value.split('(')[0] metrics[metric_name] = float(value) except ValueError: value = value.replace(' ', '') else: try: PSNR, SSIM = [float(d) for d in value.split('/')] metrics[metric_name] = dict(PSNR=PSNR, SSIM=SSIM) except ValueError: pass task = model_task if task_idx is None else line[ task_idx].strip() assert ',' not in task, ( f'Find "," in "task" field of "{md_file}" (line {j}). ' 'Please check your readme carefully.') assert task.lower() in model_task_list, ( f'Task "{task}" not in "{model_task_list}" in "{md_file}" ' f'(line {j}). Please check your readme carefully.') result = Result(task=task, dataset=dataset, metrics=metrics) if model.results is None: model.results = result else: model.results.data.append(result) # check weights if line[download_idx].find('](') >= 0: if line[download_idx].find('model](') >= 0: left = line[download_idx].index('model](') + 7 else: left = line[download_idx].index('ckpt](') + 6 right = line[download_idx].index(')', left) model.weights = line[download_idx][left:right] j += 1 i = j else: i += 1 collection = modelindex_to_dict(collection) models = [modelindex_to_dict(m) for n, m in model_list.items()] assert len(models) > 0, f"'no model is found in {md_file}'" result = {'Collections': [collection], 'Models': models} yml_file = md_file.replace('README.md', 'metafile.yml') is_different = dump_yaml_and_check_difference(result, yml_file) return is_different def update_model_index(): """Update model-index.yml according to model .md files. Returns: Bool: If the updated model-index.yml is different from the original. """ configs_dir = osp.join(MMagic_ROOT, 'configs') yml_files = glob.glob(osp.join(configs_dir, '**', '*.yml'), recursive=True) yml_files.sort() model_index = { 'Import': [ osp.relpath(yml_file, MMagic_ROOT).replace( '\\', '/') # force using / as path separators for yml_file in yml_files ] } model_index_file = osp.join(MMagic_ROOT, 'model-index.yml') is_different = dump_yaml_and_check_difference(model_index, model_index_file) return is_different if __name__ == '__main__': if len(sys.argv) <= 1: configs_root = osp.join(MMagic_ROOT, 'configs') file_list = glob.glob( osp.join(configs_root, '**', '*README.md'), recursive=True) file_list.sort() else: file_list = [ fn for fn in sys.argv[1:] if osp.basename(fn) == 'README.md' ] if not file_list: sys.exit(0) file_modified = False file_list = file_list pbar = tqdm.tqdm(range(len(file_list)), initial=0, dynamic_ncols=True) for fn in file_list: file_modified |= parse_md(fn) pbar.update(1) pbar.set_description(f'processing {fn}') file_modified |= update_model_index() sys.exit(1 if file_modified else 0) ================================================ FILE: .dev_scripts/update_ut.py ================================================ import os import os.path as osp from argparse import ArgumentParser from fnmatch import fnmatch from glob import glob from tqdm import tqdm parser = ArgumentParser() parser.add_argument('--src', type=str, default='mmagic') parser.add_argument('--dst', type=str, default='tests') parser.add_argument( '--exclude', nargs='+', default=[ 'mmagic/.mim', 'mmagic/registry.py', 'mmagic/version.py', '__pycache__', '__init__', '**/__init__.py', '**/stylegan3_ops/*', '**/conv2d_gradfix.py', '**/grid_sample_gradfix.py', '**/misc.py', '**/upfirdn2d.py', '**/all_gather_layer.py', '**/typing.py' ]) args = parser.parse_args() def check_exclude(fn): for pattern in args.exclude: if fnmatch(fn, pattern): return True return False def update_ut(): target_ut = [] missing_ut = [] blank_ut = [] file_list = glob('mmagic/**/*.py', recursive=True) for f in tqdm(file_list): if check_exclude(f): continue if osp.splitext(osp.basename(f))[0] != '__init__': dirname = osp.dirname(f) dirname = dirname.replace('__', '') dirname = dirname.replace('mmagic', 'tests') dirname = dirname.replace('/', '/test_') os.makedirs(dirname, exist_ok=True) basename = osp.basename(f) basename = 'test_' + basename dst_path = osp.join(dirname, basename) target_ut.append(dst_path) if not osp.exists(dst_path): missing_ut.append(dst_path) fp = open(dst_path, 'a') fp.close() else: text_lines = open(dst_path, 'r').readlines() if len(text_lines) <= 3: blank_ut.append(dst_path) existing_ut = glob('tests/test_*/**/*.py', recursive=True) additional_ut = list(set(existing_ut) - set(target_ut)) if len(additional_ut) > 0: print('Additional UT:') for f in additional_ut: print(f) if len(missing_ut) > 0: print('Missing UT:') for f in missing_ut: print(f) if len(blank_ut) > 0: print('Blank UT:') for f in blank_ut: print(f) if __name__ == '__main__': update_ut() ================================================ FILE: .dev_scripts/utils/__init__.py ================================================ from .job_util import (filter_jobs, get_info_from_id, parse_job_list, parse_job_list_from_file) from .modelindex import (collate_metrics, dump_yaml_and_check_difference, found_table, modelindex_to_dict) __all__ = [ 'modelindex_to_dict', 'found_table', 'dump_yaml_and_check_difference', 'collate_metrics', 'parse_job_list', 'parse_job_list_from_file', 'get_info_from_id', 'filter_jobs' ] ================================================ FILE: .dev_scripts/utils/job_util.py ================================================ import os import os.path as osp from typing import Tuple from rich import print as pprint from rich.table import Table def parse_job_list(job_list) -> Tuple[list, list]: """Parse task name and job id from list. All elements in `job_list` must. be formatted as `JOBID @ JOBNAME`. Args: job_list (list[str]): Job list. Returns: Tuple[list, list]: Job ID list and Job name list. """ assert all([ ' @ ' in job for job in job_list ]), ('Each line of job list must be formatted like \'JOBID @ JOBNAME\'.') job_id_list, job_name_list = [], [] for job_info in job_list: job_id, job_name = job_info.split(' @ ') job_id_list.append(job_id) job_name_list.append(job_name) return job_id_list, job_name_list def parse_job_list_from_file(job_list_file: str) -> Tuple[list, list]: """Parse job list from file and return a tuple contains list of job id and job name. Args: job_list_file (str): The path to the file list. Returns: Tuple[list, list]: A tuple contains list of job id and job name. """ if not osp.exists(job_list_file): return False with open(job_list_file, 'r') as file: job_list = [job.strip() for job in file.readlines()] return parse_job_list(job_list) def get_info_from_id(job_id: str) -> dict: """Get the basic information of a job id with `swatch examine` command. Args: job_id (str): The ID of the job. Returns: dict: A dict contains information of the corresponding job id. """ # NOTE: do not have exception handling here info_stream = os.popen(f'swatch examine {job_id}') info_str = [line.strip() for line in info_stream.readlines()] status_info = info_str[2].split() try: status_dict = { 'JobID': status_info[0], 'JobName': status_info[1], 'Partition': status_info[2], 'NNodes': status_info[3], 'AllocCPUS': status_info[4], 'State': status_info[5] } except Exception: print(job_id) print(info_str) return status_dict def filter_jobs(job_id_list: list, job_name_list: list, select: list = ['FAILED'], show_table: bool = False, table_name: str = 'Filter Results') -> Tuple[list, list]: """Filter the job which status not belong to :attr:`select`. Args: job_id_list (list): The list of job ids. job_name_list (list): The list of job names. select (list, optional): Which kind of jobs will be selected. Defaults to ['FAILED']. show_table (bool, optional): Whether display the filter result in a table. Defaults to False. table_name (str, optional): The name of the table. Defaults to 'Filter Results'. Returns: Tuple[list]: A tuple contains selected job ids and job names. """ # if ignore is not passed, return the original id list and name list if not select: return job_id_list, job_name_list filtered_id_list, filtered_name_list = [], [] job_info_list = [] for id_, name_ in zip(job_id_list, job_name_list): info = get_info_from_id(id_) job_info_list.append(info) if info['State'] in select: filtered_id_list.append(id_) filtered_name_list.append(name_) if show_table: filter_table = Table(title=table_name) for field in ['Name', 'ID', 'State', 'Is Selected']: filter_table.add_column(field) for id_, name_, info_ in zip(job_id_list, job_name_list, job_info_list): selected = '[green]True' \ if info_['State'] in select else '[red]False' filter_table.add_row(name_, id_, info_['State'], selected) pprint(filter_table) return filtered_id_list, filtered_name_list ================================================ FILE: .dev_scripts/utils/modelindex.py ================================================ import os.path as osp import mmengine from modelindex.models.Collection import Collection from modelindex.models.Model import Model def dump_yaml_and_check_difference(obj, file): """Dump object to a yaml file, and check if the file content is different from the original. Args: obj (any): The python object to be dumped. file (str): YAML filename to dump the object to. Returns: Bool: If the target YAML file is different from the original. """ str_dump = mmengine.dump( obj, None, file_format='yaml', sort_keys=True, line_break='\n') # force use LF if osp.isfile(file): file_exists = True # print(f' exist {file}') with open(file, 'r', encoding='utf-8') as f: str_orig = f.read() else: file_exists = False str_orig = None if file_exists and str_orig == str_dump: is_different = False else: is_different = True print(f' update {file}') with open(file, 'w', encoding='utf-8') as f: f.write(str_dump) return is_different def collate_metrics(keys): """Collect metrics from the first row of the table. Args: keys (List): Elements in the first row of the table. Returns: dict: A dict of metrics. """ used_metrics = dict() for idx, key in enumerate(keys): if key in ['Model', 'Dataset', 'Training Resources', 'Download']: continue used_metrics[key] = idx return used_metrics def found_table(lines, i): if i + 1 >= len(lines): return False if i - 2 < 0 or 'SKIP THIS TABLE' in lines[i - 2]: return False if lines[i][0] != '|': return False for c in ['| :', '|:', '|-']: if c in lines[i + 1]: return True return False def modelindex_to_dict(model): if isinstance(model, Collection): result = model.data if model.metadata is not None: result['Metadata'] = model.metadata.data elif isinstance(model, Model): result = model.data if model.metadata is not None: result['Metadata'] = model.metadata.data if model.results is not None: results_list = [] for r in model.results: results_list.append(r.data) result['Results'] = results_list return result ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at chenkaidev@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq [homepage]: https://www.contributor-covenant.org ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing to MMagic All kinds of contributions are welcome, including but not limited to the following. - Fix typo or bugs - Add documentation or translate the documentation into other languages - Add new features and components ## Workflow 1. fork and pull the latest MMagic repository (MMagic) 2. checkout a new branch (do not use master branch for PRs) 3. commit your changes 4. create a PR ```{note} If you plan to add some new features that involve large changes, it is encouraged to open an issue for discussion first. ``` ## Code style ### Python We adopt [PEP8](https://www.python.org/dev/peps/pep-0008/) as the preferred code style. We use the following tools for linting and formatting: - [flake8](https://github.com/PyCQA/flake8): A wrapper around some linter tools. - [isort](https://github.com/timothycrosley/isort): A Python utility to sort imports. - [yapf](https://github.com/google/yapf): A formatter for Python files. - [codespell](https://github.com/codespell-project/codespell): A Python utility to fix common misspellings in text files. - [mdformat](https://github.com/executablebooks/mdformat): Mdformat is an opinionated Markdown formatter that can be used to enforce a consistent style in Markdown files. - [docformatter](https://github.com/myint/docformatter): A formatter to format docstring. Style configurations can be found in [setup.cfg](/setup.cfg). We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. The config for a pre-commit hook is stored in [.pre-commit-config](/.pre-commit-config.yaml). After you clone the repository, you will need to install initialize pre-commit hook. ```shell pip install -U pre-commit ``` From the repository folder ```shell pre-commit install ``` After this on every commit check code linters and formatter will be enforced. ```{important} Before you create a PR, make sure that your code lints and is formatted by yapf. ``` ### C++ and CUDA We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). ================================================ FILE: .github/ISSUE_TEMPLATE/1-bug-report.yml ================================================ name: "🐞 Bug report" description: "Create a report to help us reproduce and fix the bug" labels: "kind/bug,status/unconfirmed" title: "[Bug] " body: - type: markdown attributes: value: | If you have already identified the reason, we strongly appreciate you creating a new PR to fix it [here](https://github.com/open-mmlab/mmagic/pulls)! If this issue is about installing MMCV, please file an issue at [MMCV](https://github.com/open-mmlab/mmcv/issues/new/choose). If you need our help, please fill in as much of the following form as you're able to. **The less clear the description, the longer it will take to solve it.** - type: checkboxes attributes: label: Prerequisite description: Please check the following items before creating a new issue. options: - label: I have searched [Issues](https://github.com/open-mmlab/mmagic/issues) and [Discussions](https://github.com/open-mmlab/mmagic/discussions) but cannot get the expected help. required: true - label: I have read the [FAQ documentation](https://mmagic.readthedocs.io/en/latest/faq.html) but cannot get the expected help. required: true - label: The bug has not been fixed in the [latest version (main)](https://github.com/open-mmlab/mmagic) or [latest version (0.x)](https://github.com/open-mmlab/mmagic/tree/0.x). required: true - type: dropdown id: task attributes: label: Task description: The problem arises when options: - I'm using the official example scripts/configs for the officially supported tasks/models/datasets. - I have modified the scripts/configs, or I'm working on my own tasks/models/datasets. validations: required: true - type: dropdown id: branch attributes: label: Branch description: The problem arises when I'm working on options: - main branch https://github.com/open-mmlab/mmagic - 0.x branch https://github.com/open-mmlab/mmagic/tree/0.x validations: required: true - type: textarea attributes: label: Environment description: | Please run `python mmagic/utils/collect_env.py` to collect necessary environment information and copy-paste it here. You may add additional information that may be helpful for locating the problem, such as - How you installed PyTorch \[e.g., pip, conda, source\] - Other environment variables that may be related (such as `$PATH`, `$LD_LIBRARY_PATH`, `$PYTHONPATH`, etc.) validations: required: true - type: textarea attributes: label: Reproduces the problem - code sample description: | Please provide a code sample that reproduces the problem you ran into. It can be a Colab link or just a code snippet. placeholder: | ```python # Sample code to reproduce the problem ``` validations: required: true - type: textarea attributes: label: Reproduces the problem - command or script description: | What command or script did you run? placeholder: | ```shell The command or script you run. ``` validations: required: true - type: textarea attributes: label: Reproduces the problem - error message description: | Please provide the error message or logs you got, with the full traceback. placeholder: | ``` The error message or logs you got, with the full traceback. ``` validations: required: true - type: textarea attributes: label: Additional information description: Tell us anything else you think we should know. placeholder: | 1. What's your expected result? 2. What dataset did you use? 3. What do you think might be the reason? ================================================ FILE: .github/ISSUE_TEMPLATE/2-feature-request.yml ================================================ name: 🚀 Feature request description: Suggest an idea for this project labels: "kind/enhancement,status/unconfirmed" title: "[Feature] " body: - type: markdown attributes: value: | We strongly appreciate you creating a PR to implement this feature [here](https://github.com/open-mmlab/mmagic/pulls)! If you need our help, please fill in as much of the following form as you're able to. **The less clear the description, the longer it will take to solve it.** - type: textarea attributes: label: What's the feature? description: | Tell us more about the feature and how this feature can help. placeholder: | E.g., It is inconvenient when \[....\]. This feature can \[....\]. validations: required: true - type: textarea attributes: label: Any other context? description: | Have you considered any alternative solutions or features? If so, what are they? Also, feel free to add any other context or screenshots about the feature request here. ================================================ FILE: .github/ISSUE_TEMPLATE/3-new-model.yml ================================================ name: "\U0001F31F New model/dataset/scheduler addition" description: Submit a proposal/request to implement a new model / dataset / scheduler labels: "kind/feature,status/unconfirmed" title: "[New Models] " body: - type: textarea id: description-request validations: required: true attributes: label: Model/Dataset/Scheduler description description: | Put any and all important information relative to the model/dataset/scheduler - type: checkboxes attributes: label: Open source status description: | Please provide the open-source status, which would be very helpful options: - label: "The model implementation is available" - label: "The model weights are available." - type: textarea id: additional-info attributes: label: Provide useful links for the implementation description: | Please provide information regarding the implementation, the weights, and the authors. Please mention the authors by @gh-username if you're aware of their usernames. ================================================ FILE: .github/ISSUE_TEMPLATE/4-documentation.yml ================================================ name: 📚 Documentation description: Report an issue related to the documentation. labels: "kind/doc,status/unconfirmed" title: "[Docs] " body: - type: dropdown id: branch attributes: label: Branch description: This issue is related to the options: - main branch https://mmagic.readthedocs.io/en/latest/ - 0.x branch https://mmagic.readthedocs.io/en/0.x/ validations: required: true - type: textarea attributes: label: 📚 The doc issue description: > A clear and concise description the issue. validations: required: true - type: textarea attributes: label: Suggest a potential alternative/fix description: > Tell us how we could improve the documentation in this regard. - type: markdown attributes: value: > Thanks for contributing 🎉! ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: 💬 Forum url: https://github.com/open-mmlab/mmagic/discussions about: Ask general usage questions and discuss with other MMagic community members - name: 🌐 Explore OpenMMLab url: https://openmmlab.com/ about: Get to know more about OpenMMLab ================================================ FILE: .github/pull_request_template.md ================================================ Thanks for your contribution and we appreciate it a lot. The following instructions would make your pull request more healthy and more easily get feedback. If you do not understand some items, don't worry, just make the pull request and seek help from maintainers. ## Motivation Please describe the motivation of this PR and the goal you want to achieve through this PR. ## Modification Please briefly describe what modification is made in this PR. ## BC-breaking (Optional) Does the modification introduce changes that break the backward-compatibility of the downstream repositories? If so, please describe how it breaks the compatibility and how the downstream projects should modify their code to keep compatibility with this PR. ## Use cases (Optional) If this PR introduces a new feature, it is better to list some use cases here, and update the documentation. ## Checklist Submitting this pull request means that, **Before PR**: - [x] I have read and followed the workflow indicated in the [CONTRIBUTING.md](https://github.com/open-mmlab/mmagic/blob/main/.github/CONTRIBUTING.md) to create this PR. - [x] Pre-commit or linting tools indicated in [CONTRIBUTING.md](https://github.com/open-mmlab/mmagic/blob/main/.github/CONTRIBUTING.md) are used to fix the potential lint issues. - [x] Bug fixes are covered by unit tests, the case that causes the bug should be added in the unit tests. - [x] New functionalities are covered by complete unit tests. If not, please add more unit test to ensure the correctness. - [x] The documentation has been modified accordingly, including docstring or example tutorials. **After PR**: - [x] If the modification has potential influence on downstream or other related projects, this PR should be tested with some of those projects. - [x] CLA has been signed and all committers have signed the CLA in this PR. ================================================ FILE: .github/workflows/lint.yml ================================================ name: lint on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python 3.7 uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install pre-commit hook run: | pip install pre-commit pre-commit install - name: Linting run: pre-commit run --all-files - name: Check docstring coverage run: | pip install interrogate interrogate -v --ignore-init-method --ignore-module --ignore-nested-functions --ignore-regex "__repr__" --fail-under 90 mmagic ================================================ FILE: .github/workflows/merge_stage_test.yml ================================================ name: merge_stage_test on: push: paths-ignore: - 'README.md' - 'README_zh-CN.md' - 'docs/**' - '.owners.yml' - '.github/ISSUE_TEMPLATE/**' - '.github/*.md' - '.dev_scripts/**' - '.circleci/**' - 'configs/**' - 'projects/**' branches: - dev-1.x - test-1.x - main - test-branch concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build_cpu_py: runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.8, 3.9] torch: [1.8.1] include: - torch: 1.8.1 torchvision: 0.9.1 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Install PyTorch run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html - name: Install MMEngine run: pip install git+https://github.com/open-mmlab/mmengine.git@main - name: Install MMCV run: | pip install -U openmim mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt - name: Build and install run: rm -rf .eggs && pip install -e . - name: Run unittests and generate coverage report run: | coverage run --branch --source mmagic -m pytest tests/ coverage xml coverage report -m build_cpu_pt: runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] torch: [1.8.1, 1.9.1, 1.10.1, 1.11.0, 1.12.1, 1.13.0] include: - torch: 1.8.1 torchvision: 0.9.1 - torch: 1.9.1 torchvision: 0.10.1 - torch: 1.10.1 torchvision: 0.11.2 - torch: 1.11.0 torchvision: 0.12.0 - torch: 1.12.1 torchvision: 0.13.1 - torch: 1.13.0 torchvision: 0.14.0 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Install PyTorch run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html - name: Install MMEngine run: pip install git+https://github.com/open-mmlab/mmengine.git@main - name: Install MMCV run: | pip install -U openmim mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt - name: Build and install run: rm -rf .eggs && pip install -e . - name: Run unittests and generate coverage report run: | coverage run --branch --source mmagic -m pytest tests/ coverage xml --omit="**/stylegan3_ops/*,**/conv2d_gradfix.py,**/grid_sample_gradfix.py,**/misc.py,**/upfirdn2d.py,**all_gather_layer.py" coverage report -m # Only upload coverage report for python3.7 && pytorch1.8.1 cpu - name: Upload coverage to Codecov if: ${{matrix.torch == '1.8.1' && matrix.python-version == '3.7'}} uses: codecov/codecov-action@v1.0.14 with: file: ./coverage.xml flags: unittests env_vars: OS,PYTHON name: codecov-umbrella fail_ci_if_error: false build_cu102: runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel strategy: matrix: python-version: [3.7] include: - torch: 1.8.1 cuda: 10.2 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Fetch GPG keys run: | apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 - name: Install PyTorch run: pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html - name: Install mmagic dependencies run: | pip install -U openmim mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | pip install -e . build_cu116: runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.13.0-cuda11.6-cudnn8-devel strategy: matrix: python-version: [3.7] include: - torch: 1.8.1 cuda: 10.2 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Fetch GPG keys run: | apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 - name: Install PyTorch run: pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu - name: Install mmagic dependencies run: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | pip install -e . - name: Run unittests and generate coverage report run: | coverage run --branch --source mmagic -m pytest tests/ coverage xml --omit="**/stylegan3_ops/*,**/conv2d_gradfix.py,**/grid_sample_gradfix.py,**/misc.py,**/upfirdn2d.py,**all_gather_layer.py" coverage report -m build_windows: runs-on: windows-2022 strategy: matrix: python: [3.7] platform: [cpu, cu111] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: python -m pip install pip --upgrade && pip install wheel - name: Install lmdb run: python -m pip install lmdb - name: Install PyTorch run: python -m pip install torch==1.8.1+${{matrix.platform}} torchvision==0.9.1+${{matrix.platform}} -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html - name: Install mmagic dependencies run: | python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim mim install 'mmcv >= 2.0.0' python -m pip install -r requirements/tests.txt - name: Build and install run: | python -m pip install -e . - name: Run unittests and generate coverage report run: | pytest tests/ ================================================ FILE: .github/workflows/pr_stage_test.yml ================================================ name: pr_stage_test on: pull_request: paths-ignore: - 'README.md' - 'README_zh-CN.md' - '.owners.yml' - '.github/ISSUE_TEMPLATE/**' - '.github/*.md' - 'docs/**' - 'projects/**' - '.dev_scripts/**' - '.circleci/**' - 'configs/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build_cpu: runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.8] include: - torch: 2.0.1 torchvision: 0.15.2 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Install PyTorch run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install MMEngine run: pip install git+https://github.com/open-mmlab/mmengine.git@main - name: Install MMCV run: | pip install -U openmim mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt - name: Build and install run: rm -rf .eggs && pip install -e . - name: Run unittests and generate coverage report run: | coverage run --branch --source mmagic -m pytest tests/ coverage xml --omit="**/stylegan3_ops/*,**/conv2d_gradfix.py,**/grid_sample_gradfix.py,**/misc.py,**/upfirdn2d.py,**all_gather_layer.py" coverage report -m # Upload coverage report for python3.7 && pytorch1.8.1 cpu - name: Upload coverage to Codecov uses: codecov/codecov-action@v1.0.14 with: file: ./coverage.xml flags: unittests env_vars: OS,PYTHON name: codecov-umbrella fail_ci_if_error: false # - name: Setup tmate session # if: ${{ failure() }} # uses: mxschmitt/action-tmate@v3 build_cu118: runs-on: ubuntu-22.04 container: image: pytorch/pytorch:2.1.0-cuda11.8-cudnn8-devel strategy: matrix: python-version: [3.8] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Fetch GPG keys run: | apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libxrender-dev - name: Install PyTorch run: pip install torch==2.0.1+cpu torchvision==0.15.2+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install mmagic dependencies run: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | pip install -e . # - name: Setup tmate session # if: ${{ failure() }} # uses: mxschmitt/action-tmate@v3 build_windows: runs-on: windows-2022 strategy: matrix: python-version: [3.8] platform: [cpu, cu118] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: python -m pip install pip --upgrade && pip install wheel - name: Install lmdb run: python -m pip install lmdb - name: Install PyTorch run: python -m pip install torch==2.0.1+${{matrix.platform}} torchvision==0.15.2+${{matrix.platform}} -f https://download.pytorch.org/whl/torch_stable.html - name: Install mmagic dependencies run: | python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim mim install 'mmcv >= 2.0.0' python -m pip install -r requirements/tests.txt - name: Build and install run: | python -m pip install -e . - name: Run unittests and generate coverage report run: | pytest tests/ # - name: Setup tmate session # if: ${{ failure() }} # uses: mxschmitt/action-tmate@v3 ================================================ FILE: .github/workflows/publish-to-pypi.yml ================================================ name: deploy on: push concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build-n-publish: runs-on: ubuntu-latest if: startsWith(github.event.ref, 'refs/tags') steps: - uses: actions/checkout@v2 - name: Set up Python 3.7 uses: actions/setup-python@v1 with: python-version: 3.7 - name: Build MMagic run: | pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/torch_stable.html pip install wheel python setup.py sdist bdist_wheel - name: Publish distribution to PyPI run: | pip install twine twine upload dist/* -u __token__ -p ${{ secrets.pypi_password }} ================================================ FILE: .github/workflows/test_mim.yml ================================================ name: test-mim on: push: paths: - 'model-index.yml' - 'configs/**' pull_request: paths: - 'model-index.yml' - 'configs/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build_cpu: runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] torch: [1.8.0] include: - torch: 1.8.0 torch_version: torch1.8 torchvision: 0.9.0 steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade && pip install wheel - name: Install PyTorch run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install openmim run: pip install openmim - name: Build and install run: rm -rf .eggs && mim install -e . - name: test commands of mim run: mim search mmagic ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class **/*.pyc # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ tests/data/out # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/en/_build/ docs/en/_tmp/ docs/zh_cn/_build/ docs/zh_cn/_tmp/ requirements/src/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # custom .vscode .idea *.pkl *.pkl.json *.log.json work_dirs/ work_dirs configs_ceph/ configs_ceph_*/ /data/ /data mmagic/.mim demo/*.png *.csv out/*.png tests/data/out resources/ # Pytorch *.pth # onnx and tensorrt *.onnx *.trt # local history .history/** # Pytorch Server *.mar # MacOS .DS_Store # Slurm batchscript-* *.out *.png *.jpg *.zip work_dir work_dir/ ================================================ FILE: .owners.yml ================================================ # assign issues to owners automatically assign: issues: enabled # or disabled pull_requests: enabled # or disabled # assign strategy, both issues and pull requests follow the same strategy strategy: # random # round-robin daily-shift-based scedule: '*/1 * * * *' # assignees assignees: - zengyh1900 - LeoXing1996 - liuwenran - LeoXing1996 - liuwenran - zengyh1900 - zengyh1900 ================================================ FILE: .pre-commit-config.yaml ================================================ exclude: ^tests/data/ repos: - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 - repo: https://github.com/zhouzaida/isort rev: 5.12.1 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-yapf rev: v0.30.0 hooks: - id: yapf - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: trailing-whitespace exclude: ^dicts/ - id: check-yaml exclude: ^projects/animated_drawings/configs/retarget/ - id: end-of-file-fixer exclude: ^dicts/ - id: requirements-txt-fixer - id: double-quote-string-fixer - id: check-merge-conflict - id: fix-encoding-pragma args: ["--remove"] - id: mixed-line-ending args: ["--fix=lf"] - repo: https://github.com/codespell-project/codespell rev: v2.1.0 hooks: - id: codespell args: ["--skip", "*.ipynb", "-L", "formating,theis,te,nd,thre,Gool,gool,lod,patten,confectionary"] - repo: https://github.com/executablebooks/mdformat rev: 0.7.9 hooks: - id: mdformat args: ["--number", "--table-width", "200"] # language_version: python3.7 additional_dependencies: - mdformat-openmmlab - mdformat_frontmatter - linkify-it-py - repo: local hooks: - id: update-model-index name: update-model-index description: Collect model information and update model-index.yml entry: .dev_scripts/update_model_index.py additional_dependencies: [mmengine, modelindex, tqdm, rich] language: python files: ^configs/.*\.md$ require_serial: true - repo: https://github.com/myint/docformatter rev: v1.3.1 hooks: - id: docformatter args: ["--in-place", "--wrap-descriptions", "79"] - repo: https://github.com/open-mmlab/pre-commit-hooks rev: v0.4.0 # Use the ref you want to point at hooks: - id: check-algo-readme - id: check-copyright args: ["demo", "mmagic", "tests", "tools"] - id: remove-improper-eol-in-cn-docs - repo: local hooks: - id: update-model-zoo name: update-model-zoo description: update model-zoo.yml entry: docs/en/.dev_scripts/update_model_zoo.py additional_dependencies: [mmengine, modelindex, tqdm, rich] language: python files: ^configs/.*\.md$ require_serial: true ================================================ FILE: .pylintrc ================================================ [MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-whitelist= # Specify a score threshold to be exceeded before program exits with error. fail-under=10.0 # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS,configs # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python module names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=print-statement, parameter-unpacking, unpacking-in-except, old-raise-syntax, backtick, long-suffix, old-ne-operator, old-octal-literal, import-star-module-level, non-ascii-bytes-literal, raw-checker-failed, bad-inline-option, locally-disabled, file-ignored, suppressed-message, useless-suppression, deprecated-pragma, use-symbolic-message-instead, apply-builtin, basestring-builtin, buffer-builtin, cmp-builtin, coerce-builtin, execfile-builtin, file-builtin, long-builtin, raw_input-builtin, reduce-builtin, standarderror-builtin, unicode-builtin, xrange-builtin, coerce-method, delslice-method, getslice-method, setslice-method, no-absolute-import, old-division, dict-iter-method, dict-view-method, next-method-called, metaclass-assignment, indexing-exception, raising-string, reload-builtin, oct-method, hex-method, nonzero-method, cmp-method, input-builtin, round-builtin, intern-builtin, unichr-builtin, map-builtin-not-iterating, zip-builtin-not-iterating, range-builtin-not-iterating, filter-builtin-not-iterating, using-cmp-argument, eq-without-hash, div-method, idiv-method, rdiv-method, exception-message-attribute, invalid-str-codec, sys-max-int, bad-python3-import, deprecated-string-function, deprecated-str-translate-call, deprecated-itertools-function, deprecated-types-field, next-method-defined, dict-items-not-iterating, dict-keys-not-iterating, dict-values-not-iterating, deprecated-operator-function, deprecated-urllib-function, xreadlines-attribute, deprecated-sys-function, exception-escape, comprehension-escape, no-member, invalid-name, too-many-branches, wrong-import-order, too-many-arguments, missing-function-docstring, missing-module-docstring, too-many-locals, too-few-public-methods, abstract-method, broad-except, too-many-nested-blocks, too-many-instance-attributes, missing-class-docstring, duplicate-code, not-callable, protected-access, dangerous-default-value, no-name-in-module, logging-fstring-interpolation, super-init-not-called, redefined-builtin, attribute-defined-outside-init, arguments-differ, cyclic-import, bad-super-call, too-many-statements # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a score less than or equal to 10. You # have access to the variables 'error', 'warning', 'refactor', and 'convention' # which contain the number of messages in each category, as well as 'statement' # which is the total number of statements analyzed. This score is used by the # global evaluation report (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=yes [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis). It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 # List of decorators that change the signature of a decorated function. signature-mutators= [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it work, # install the python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains the private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to the private dictionary (see the # --spelling-private-dict-file option) instead of raising a message. spelling-store-unknown-words=no [LOGGING] # The type of string formatting that logging methods do. `old` means using % # formatting, `new` is for `{}` formatting. logging-format-style=old # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid defining new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=100 # Maximum number of lines in a module. max-module-lines=1000 # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [STRING] # This flag controls whether inconsistent-quotes generates a warning when the # character used as a quote delimiter is used inconsistently within a module. check-quote-consistency=no # This flag controls whether the implicit-str-concat should generate a warning # on implicit string concatenation in sequences defined over several lines. check-str-concat-over-line-jumps=no [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO # Regular expression of note tags to take in consideration. #notes-rgx= [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Bad variable names regexes, separated by a comma. If names match any regex, # they will always be refused bad-names-rgxs= # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. #class-attribute-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, ex, Run, _, x, y, w, h, a, b # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted good-names-rgxs= # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. #variable-rgx= [DESIGN] # Maximum number of arguments for function / method. max-args=5 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=12 # Maximum number of locals for function / method body. max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of return / yield for function / method body. max-returns=6 # Maximum number of statements in function / method body. max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 [IMPORTS] # List of modules that can be imported at any level, not just the top level # one. allow-any-import-level= # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled). ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled). import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant # Couples of modules and preferred modules, separated by a comma. preferred-modules= [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp, __post_init__ # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "BaseException, Exception". overgeneral-exceptions=BaseException, Exception ================================================ FILE: .readthedocs.yml ================================================ version: 2 formats: [pdf, epub] build: os: ubuntu-22.04 tools: python: "3.7" python: install: - requirements: requirements/docs.txt - requirements: requirements/readthedocs.txt ================================================ FILE: CITATION.cff ================================================ cff-version: 1.2.0 message: "If you use this software, please cite it as below." authors: - family-names: MMagic given-names: Contributors title: "MMagic: OpenMMLab Multimodal Advanced, Generative, and Intelligent Creation Toolbox" version: 1.0.0 date-released: 2023-04-25 url: "https://github.com/open-mmlab/mmagic" license: Apache-2.0 ================================================ FILE: LICENSE ================================================ Copyright (c) OpenMMLab. All rights reserved. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2023 MMagic 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. Copyright 2020 MMEditing 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. ================================================ FILE: MANIFEST.in ================================================ include requirements/*.txt include mmagic/.mim/VERSION include mmagic/.mim/model-index.yml include mmagic/evaluation/metrics/niqe_pris_params.npz recursive-include mmagic/.mim/configs *.py *.yml recursive-include mmagic/.mim/tools *.sh *.py recursive-include mmagic/.mim/demo *.py ================================================ FILE: README.md ================================================
 
Multimodal Advanced, Generative, and Intelligent Creation (MMagic [em'mædʒɪk])
 
OpenMMLab website HOT      OpenMMLab platform TRY IT OUT
 
[![PyPI](https://badge.fury.io/py/mmagic.svg)](https://pypi.org/project/mmagic/) [![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmagic.readthedocs.io/en/latest/) [![badge](https://github.com/open-mmlab/mmagic/workflows/build/badge.svg)](https://github.com/open-mmlab/mmagic/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmagic/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmagic) [![license](https://img.shields.io/github/license/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/blob/main/LICENSE) [![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/issues) [![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/issues) [![Open in OpenXLab](https://cdn-static.openxlab.org.cn/app-center/openxlab_demo.svg)](https://openxlab.org.cn/apps/detail/%E6%94%BF%E6%9D%B0/OpenMMLab-Projects) [📘Documentation](https://mmagic.readthedocs.io/en/latest/) | [🛠️Installation](https://mmagic.readthedocs.io/en/latest/get_started/install.html) | [📊Model Zoo](https://mmagic.readthedocs.io/en/latest/model_zoo/overview.html) | [🆕Update News](https://mmagic.readthedocs.io/en/latest/changelog.html) | [🚀Ongoing Projects](https://github.com/open-mmlab/mmagic/projects) | [🤔Reporting Issues](https://github.com/open-mmlab/mmagic/issues) English | [简体中文](README_zh-CN.md)
## 🚀 What's New ### New release [**MMagic v1.2.0**](https://github.com/open-mmlab/mmagic/releases/tag/v1.2.0) \[18/12/2023\]: - An advanced and powerful inpainting algorithm named PowerPaint is released in our repository. [Click to View](https://github.com/open-mmlab/mmagic/tree/main/projects/powerpaint) We are excited to announce the release of MMagic v1.0.0 that inherits from [MMEditing](https://github.com/open-mmlab/mmediting) and [MMGeneration](https://github.com/open-mmlab/mmgeneration). After iterative updates with OpenMMLab 2.0 framework and merged with MMGeneration, MMEditing has become a powerful tool that supports low-level algorithms based on both GAN and CNN. Today, MMEditing embraces Generative AI and transforms into a more advanced and comprehensive AIGC toolkit: **MMagic** (**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation). MMagic will provide more agile and flexible experimental support for researchers and AIGC enthusiasts, and help you on your AIGC exploration journey. We highlight the following new features. **1. New Models** We support 11 new models in 4 new tasks. - Text2Image / Diffusion - ControlNet - DreamBooth - Stable Diffusion - Disco Diffusion - GLIDE - Guided Diffusion - 3D-aware Generation - EG3D - Image Restoration - NAFNet - Restormer - SwinIR - Image Colorization - InstColorization **2. Magic Diffusion Model** For the Diffusion Model, we provide the following "magic" : - Support image generation based on Stable Diffusion and Disco Diffusion. - Support Finetune methods such as Dreambooth and DreamBooth LoRA. - Support controllability in text-to-image generation using ControlNet. - Support acceleration and optimization strategies based on xFormers to improve training and inference efficiency. - Support video generation based on MultiFrame Render. - Support calling basic models and sampling strategies through DiffuserWrapper. **3. Upgraded Framework** By using MMEngine and MMCV of OpenMMLab 2.0 framework, MMagic has upgraded in the following new features: - Refactor DataSample to support the combination and splitting of batch dimensions. - Refactor DataPreprocessor and unify the data format for various tasks during training and inference. - Refactor MultiValLoop and MultiTestLoop, supporting the evaluation of both generation-type metrics (e.g. FID) and reconstruction-type metrics (e.g. SSIM), and supporting the evaluation of multiple datasets at once. - Support visualization on local files or using tensorboard and wandb. - Support for 33+ algorithms accelerated by Pytorch 2.0. **MMagic** has supported all the tasks, models, metrics, and losses in [MMEditing](https://github.com/open-mmlab/mmediting) and [MMGeneration](https://github.com/open-mmlab/mmgeneration) and unifies interfaces of all components based on [MMEngine](https://github.com/open-mmlab/mmengine) 😍. Please refer to [changelog.md](docs/en/changelog.md) for details and release history. Please refer to [migration documents](docs/en/migration/overview.md) to migrate from [old version](https://github.com/open-mmlab/mmagic/tree/0.x) MMEditing 0.x to new version MMagic 1.x .
## 📄 Table of Contents - [📖 Introduction](#-introduction) - [🙌 Contributing](#-contributing) - [🛠️ Installation](#️-installation) - [📊 Model Zoo](#-model-zoo) - [🤝 Acknowledgement](#-acknowledgement) - [🖊️ Citation](#️-citation) - [🎫 License](#-license) - [🏗️ ️OpenMMLab Family](#️-️openmmlab-family) ## 📖 Introduction MMagic (**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation) is an advanced and comprehensive AIGC toolkit that inherits from [MMEditing](https://github.com/open-mmlab/mmediting) and [MMGeneration](https://github.com/open-mmlab/mmgeneration). It is an open-source image and video editing&generating toolbox based on PyTorch. It is a part of the [OpenMMLab](https://openmmlab.com/) project. Currently, MMagic support multiple image and video generation/editing tasks. https://user-images.githubusercontent.com/49083766/233564593-7d3d48ed-e843-4432-b610-35e3d257765c.mp4 ### ✨ Major features - **State of the Art Models** MMagic provides state-of-the-art generative models to process, edit and synthesize images and videos. - **Powerful and Popular Applications** MMagic supports popular and contemporary image restoration, text-to-image, 3D-aware generation, inpainting, matting, super-resolution and generation applications. Specifically, MMagic supports fine-tuning for stable diffusion and many exciting diffusion's application such as ControlNet Animation with SAM. MMagic also supports GAN interpolation, GAN projection, GAN manipulations and many other popular GAN’s applications. It’s time to begin your AIGC exploration journey! - **Efficient Framework** By using MMEngine and MMCV of OpenMMLab 2.0 framework, MMagic decompose the editing framework into different modules and one can easily construct a customized editor framework by combining different modules. We can define the training process just like playing with Legos and provide rich components and strategies. In MMagic, you can complete controls on the training process with different levels of APIs. With the support of [MMSeparateDistributedDataParallel](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/wrappers/seperate_distributed.py), distributed training for dynamic architectures can be easily implemented. ### ✨ Best Practice - The best practice on our main branch works with **Python 3.9+** and **PyTorch 2.0+**.

🔝Back to Table of Contents

## 🙌 Contributing More and more community contributors are joining us to make our repo better. Some recent projects are contributed by the community including: - [SDXL](configs/stable_diffusion_xl/README.md) is contributed by @okotaku. - [AnimateDiff](configs/animatediff/README.md) is contributed by @ElliotQi. - [ViCo](configs/vico/README.md) is contributed by @FerryHuang. - [DragGan](configs/draggan/README.md) is contributed by @qsun1. - [FastComposer](configs/fastcomposer/README.md) is contributed by @xiaomile. [Projects](projects/README.md) is opened to make it easier for everyone to add projects to MMagic. We appreciate all contributions to improve MMagic. Please refer to [CONTRIBUTING.md](https://github.com/open-mmlab/mmcv/blob/main/CONTRIBUTING.md) in MMCV and [CONTRIBUTING.md](https://github.com/open-mmlab/mmengine/blob/main/CONTRIBUTING.md) in MMEngine for more details about the contributing guideline.

🔝Back to Table of Contents

## 🛠️ Installation MMagic depends on [PyTorch](https://pytorch.org/), [MMEngine](https://github.com/open-mmlab/mmengine) and [MMCV](https://github.com/open-mmlab/mmcv). Below are quick steps for installation. **Step 1.** Install PyTorch following [official instructions](https://pytorch.org/get-started/locally/). **Step 2.** Install MMCV, MMEngine and MMagic with [MIM](https://github.com/open-mmlab/mim). ```shell pip3 install openmim mim install mmcv>=2.0.0 mim install mmengine mim install mmagic ``` **Step 3.** Verify MMagic has been successfully installed. ```shell cd ~ python -c "import mmagic; print(mmagic.__version__)" # Example output: 1.0.0 ``` **Getting Started** After installing MMagic successfully, now you are able to play with MMagic! To generate an image from text, you only need several lines of codes by MMagic! ```python from mmagic.apis import MMagicInferencer sd_inferencer = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = 'output/sd_res.png' sd_inferencer.infer(text=text_prompts, result_out_dir=result_out_dir) ``` Please see [quick run](docs/en/get_started/quick_run.md) and [inference](docs/en/user_guides/inference.md) for the basic usage of MMagic. **Install MMagic from source** You can also experiment on the latest developed version rather than the stable release by installing MMagic from source with the following commands: ```shell git clone https://github.com/open-mmlab/mmagic.git cd mmagic pip3 install -e . ``` Please refer to [installation](docs/en/get_started/install.md) for more detailed instruction.

🔝Back to Table of Contents

## 📊 Model Zoo
Supported algorithms
Conditional GANs Unconditional GANs Image Restoration Image Super-Resolution
Video Super-Resolution Video Interpolation Image Colorization Image Translation
Inpainting Matting Text-to-Image(Video) 3D-aware Generation
Please refer to [model_zoo](https://mmagic.readthedocs.io/en/latest/model_zoo/overview.html) for more details.

🔝Back to Table of Contents

## 🤝 Acknowledgement MMagic is an open source project that is contributed by researchers and engineers from various colleges and companies. We wish that the toolbox and benchmark could serve the growing research community by providing a flexible toolkit to reimplement existing methods and develop their own new methods. We appreciate all the contributors who implement their methods or add new features, as well as users who give valuable feedbacks. Thank you all!

🔝Back to Table of Contents

## 🖊️ Citation If MMagic is helpful to your research, please cite it as below. ```bibtex @misc{mmagic2023, title = {{MMagic}: {OpenMMLab} Multimodal Advanced, Generative, and Intelligent Creation Toolbox}, author = {{MMagic Contributors}}, howpublished = {\url{https://github.com/open-mmlab/mmagic}}, year = {2023} } ``` ```bibtex @misc{mmediting2022, title = {{MMEditing}: {OpenMMLab} Image and Video Editing Toolbox}, author = {{MMEditing Contributors}}, howpublished = {\url{https://github.com/open-mmlab/mmediting}}, year = {2022} } ```

🔝Back to Table of Contents

## 🎫 License This project is released under the [Apache 2.0 license](LICENSE). Please refer to [LICENSES](LICENSE) for the careful check, if you are using our code for commercial matters.

🔝Back to Table of Contents

## 🏗️ ️OpenMMLab Family - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab foundational library for training deep learning models. - [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. - [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. - [MMPreTrain](https://github.com/open-mmlab/mmpretrain): OpenMMLab Pre-training Toolbox and Benchmark. - [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark. - [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection. - [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark. - [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark. - [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox. - [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark. - [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark. - [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark. - [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. - [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark. - [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark. - [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. - [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark. - [MMagic](https://github.com/open-mmlab/mmagic): OpenMMLab Multimodal Advanced, Generative, and Intelligent Creation Toolbox. - [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab model deployment framework.

🔝Back to Table of Contents

================================================ FILE: README_zh-CN.md ================================================
 
Multimodal Advanced, Generative, and Intelligent Creation (MMagic [em'mædʒɪk])
 
OpenMMLab 官网 HOT      OpenMMLab 开放平台 TRY IT OUT
 
[![PyPI](https://badge.fury.io/py/mmagic.svg)](https://pypi.org/project/mmagic/) [![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmagic.readthedocs.io/zh_CN/latest/) [![badge](https://github.com/open-mmlab/mmagic/workflows/build/badge.svg)](https://github.com/open-mmlab/mmagic/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmagic/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmagic) [![license](https://img.shields.io/github/license/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/blob/main/LICENSE) [![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/issues) [![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmagic.svg)](https://github.com/open-mmlab/mmagic/issues) [![Open in OpenXLab](https://cdn-static.openxlab.org.cn/app-center/openxlab_demo.svg)](https://openxlab.org.cn/apps/detail/%E6%94%BF%E6%9D%B0/OpenMMLab-Projects) [📘使用文档](https://mmagic.readthedocs.io/zh_CN/latest/) | [🛠️安装教程](https://mmagic.readthedocs.io/zh_CN/latest/get_started/install.html) | [📊模型库](https://mmagic.readthedocs.io/zh_CN/latest/model_zoo/overview.html) | [🆕更新记录](https://mmagic.readthedocs.io/zh_CN/latest/changelog.html) | [🚀进行中的项目](https://github.com/open-mmlab/mmagic/projects) | [🤔提出问题](https://github.com/open-mmlab/mmagic/issues) [English](README.md) | 简体中文
## 🚀 最新进展 ### 最新的 [**MMagic v1.2.0**](https://github.com/open-mmlab/mmagic/releases/tag/v1.2.0) 版本已经在 \[18/12/2023\] 发布: - 我们的代码仓库中发布了一个先进而强大的图像 inpainting 算法 PowerPaint。 [Click to View](https://github.com/open-mmlab/mmagic/tree/main/projects/powerpaint) 我们正式发布 MMagic v1.0.0 版本,源自 [MMEditing](https://github.com/open-mmlab/mmediting) 和 [MMGeneration](https://github.com/open-mmlab/mmgeneration)。 经过 OpenMMLab 2.0 框架的迭代更新以及与 MMGeneration 的合并,MMEditing 已经成为了一个支持基于 GAN 和 CNN 的底层视觉算法的强大工具。而今天,MMEditing 将更加拥抱生成式 AI(Generative AI),正式更名为 **MMagic**(**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation),致力于打造更先进、更全面的 AIGC 开源算法库。MMagic 将为广大研究者与 AIGC 爱好者们提供更加快捷灵活的实验支持,助力你的 AIGC 探索之旅。 以下是此次版本发布的重点新功能: **1. 新算法** 我们支持了4个新任务以及11个新算法。 - Text2Image / Diffusion - ControlNet - DreamBooth - Stable Diffusion - Disco Diffusion - GLIDE - Guided Diffusion - 3D-aware Generation - EG3D - Image Restoration - NAFNet - Restormer - SwinIR - Image Colorization - InstColorization **2. Magic Diffusion Model** 针对 Diffusion Model,我们提供了以下“魔法” - 支持基于 Stable Diffusion 与 Disco Diffusion 的图像生成. - 支持 Dreambooth 以及 DreamBooth LoRA 等 Finetune 方法. - 支持 ControlNet 进行可控性的文本到图像生成. - 支持 xFormers 加速和优化策略,提高训练与推理效率. - 支持基于 MultiFrame Render 的视频生成. - 支持通过 Wrapper 调用 Diffusers 的基础模型以及采样策略. **3. 框架升级** 通过 OpenMMLab 2.0 框架的 MMEngine 和 MMCV, MMagic 在以下几方面完成升级: - 重构 DataSample,支持 batch 维度的组合与拆分. - 重构 DataPreprocessor,并统一各种任务在训练与推理时的数据格式. - 重构 MultiValLoop 与 MultiTestLoop,同时支持生成类型指标(e.g. FID)与重建类型指标(e.g. SSIM) 的评测,同时支持一次性评测多个数据集 - 支持本地可视化以及使用 tensorboard 或 wandb的可视化. - 支持 33+ 算法 Pytorch 2.0 加速. **MMagic** 已经支持了[MMEditing](https://github.com/open-mmlab/mmediting)和[MMGeneration](https://github.com/open-mmlab/mmgeneration)中的全量任务、模型、优化函数和评价指标 ,并基于[MMEngine](https://github.com/open-mmlab/mmengine)统一了各组件接口 😍。 如果想了解更多版本更新细节和历史信息,请阅读[更新日志](docs/zh_cn/changelog.md)。如果想从[旧版本](https://github.com/open-mmlab/mmagic/tree/master) MMEditing 0.x 迁移到新版本 MMagic 1.x,请阅读[迁移文档](docs/zh_cn/migration/overview.md)。
## 📄 目录 - [📖 介绍](#-介绍) - [🙌 参与贡献](#-参与贡献) - [🛠️ 安装](#%EF%B8%8F-安装) - [📊 模型库](#-模型库) - [🤝 致谢](#-致谢) - [🖊️ 引用](#%EF%B8%8F-引用) - [🎫 许可证](#-许可证) - [🏗️ ️OpenMMLab 的其他项目](#%EF%B8%8F-️openmmlab-的其他项目) ## 📖 介绍 MMagic 是基于 PyTorch 的图像&视频编辑和生成开源工具箱。是 [OpenMMLab](https://openmmlab.com/) 项目的成员之一。 目前 MMagic 支持多种图像和视频的生成/编辑任务。 https://user-images.githubusercontent.com/49083766/233564593-7d3d48ed-e843-4432-b610-35e3d257765c.mp4 ### ✨ 主要特性 - **SOTA 算法** MMagic 提供了处理、编辑、生成图像和视频的 SOTA 算法。 - **强有力且流行的应用** MMagic 支持了流行的图像修复、图文生成、3D生成、图像修补、抠图、超分辨率和生成等任务的应用。特别是 MMagic 支持了 Stable Diffusion 的微调和许多激动人心的 diffusion 应用,例如 ControlNet 动画生成。MMagic 也支持了 GANs 的插值,投影,编辑和其他流行的应用。请立即开始你的 AIGC 探索之旅! - **高效的框架** 通过 OpenMMLab 2.0 框架的 MMEngine 和 MMCV, MMagic 将编辑框架分解为不同的组件,并且可以通过组合不同的模块轻松地构建自定义的编辑器模型。我们可以像搭建“乐高”一样定义训练流程,提供丰富的组件和策略。在 MMagic 中,你可以使用不同的 APIs 完全控制训练流程。得益于 [MMSeparateDistributedDataParallel](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/wrappers/seperate_distributed.py), 动态模型结构的分布式训练可以轻松实现。 ### ✨ 最佳实践 - 主分支代码的最佳实践基于 **Python 3.9+** 和 **PyTorch 2.0+** 。

🔝返回目录

## 🙌 参与贡献 越来越多社区贡献者的加入使我们的算法库日益发展。最近由社区贡献的项目包括: - [SDXL](configs/stable_diffusion_xl/README.md) 来自 @okotaku. - [AnimateDiff](configs/animatediff/README.md) 来自 @ElliotQi. - [ViCo](configs/vico/README.md) 来自 @FerryHuang. - [DragGan](configs/draggan/README.md) 来自 @qsun1. - [FastComposer](configs/fastcomposer/README.md) 来自 @xiaomile. 为使向 MMagic 中添加项目更加容易,我们开启了 [Projects](projects/README.md) 。 感谢您为改善 MMagic 所做的所有贡献。请参阅 MMCV 中的 [CONTRIBUTING.md](https://github.com/open-mmlab/mmcv/blob/main/CONTRIBUTING_zh-CN.md) 和 MMEngine 中的 [CONTRIBUTING.md](https://github.com/open-mmlab/mmengine/blob/main/CONTRIBUTING_zh-CN.md) 以获取贡献指南。

🔝返回目录

## 🛠️ 安装 MMagic 依赖 [PyTorch](https://pytorch.org/),[MMEngine](https://github.com/open-mmlab/mmengine) 和 [MMCV](https://github.com/open-mmlab/mmcv),以下是安装的简要步骤。 **步骤 1.** 依照[官方教程](https://pytorch.org/get-started/locally/)安装 PyTorch 。 **步骤 2.** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 MMCV,MMEngine 和 MMagic 。 ``` pip3 install openmim mim install 'mmcv>=2.0.0' mim install 'mmengine' mim install 'mmagic' ``` **步骤 3.** 验证 MMagic 安装成功。 ```shell cd ~ python -c "import mmagic; print(mmagic.__version__)" # Example output: 1.0.0 ``` **开始使用** 成功安装 MMagic 后,你可以很容易地上手使用 MMagic!仅需几行代码,你就可以使用 MMagic 完成文本生成图像! ```python from mmagic.apis import MMagicInferencer sd_inferencer = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = 'output/sd_res.png' sd_inferencer.infer(text=text_prompts, result_out_dir=result_out_dir) ``` 请参考[快速运行](docs/zh_cn/get_started/quick_run.md)和[推理演示](docs/zh_cn/user_guides/inference.md)获取 MMagic 的基本用法。 **从源码安装 MMagic** 使用以下命令从源码安装 MMagic,你可以选择不使用已发布的稳定版本,而在最新开发的版本上进行实验。 ``` git clone https://github.com/open-mmlab/mmagic.git cd mmagic pip3 install -e . ``` 更详细的安装指南请参考 [安装指南](docs/zh_cn/get_started/install.md) 。

🔝Back to top

## 📊 模型库
支持的算法
Conditional GANs Unconditional GANs Image Restoration Image Super-Resolution
Video Super-Resolution Video Interpolation Image Colorization Image Translation
Inpainting Matting Text-to-Image(Video) 3D-aware Generation
请参考[模型库](https://mmagic.readthedocs.io/zh_CN/latest/model_zoo/overview.html)了解详情。

🔝返回目录

## 🤝 致谢 MMagic 是一款由不同学校和公司共同贡献的开源项目。我们感谢所有为项目提供算法复现和新功能支持的贡献者,以及提供宝贵反馈的用户。我们希望该工具箱和基准测试可以为社区提供灵活的代码工具,供用户复现现有算法并开发自己的新模型,从而不断为开源社区提供贡献。

🔝返回目录

## 🖊️ 引用 如果 MMagic 对您的研究有所帮助,请按照如下 bibtex 引用它。 ```bibtex @misc{mmagic2023, title = {{MMagic}: {OpenMMLab} Multimodal Advanced, Generative, and Intelligent Creation Toolbox}, author = {{MMagic Contributors}}, howpublished = {\url{https://github.com/open-mmlab/mmagic}}, year = {2023} } ``` ```bibtex @misc{mmediting2022, title = {{MMEditing}: {OpenMMLab} Image and Video Editing Toolbox}, author = {{MMEditing Contributors}}, howpublished = {\url{https://github.com/open-mmlab/mmediting}}, year = {2022} } ```

🔝返回目录

## 🎫 许可证 本项目开源自 [Apache 2.0 license](LICENSE)。

🔝返回目录

## 🏗️ ️OpenMMLab 的其他项目 - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab MMEngine. - [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab 计算机视觉基础库 - [MIM](https://github.com/open-mmlab/mim): MIM 是 OpenMMlab 项目、算法、模型的统一入口 - [MMPreTrain](https://github.com/open-mmlab/mmpretrain): OpenMMLab 预训练工具箱 - [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab 目标检测工具箱 - [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab 新一代通用 3D 目标检测平台 - [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab 旋转框检测工具箱与测试基准 - [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab 语义分割工具箱 - [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab 全流程文字检测识别理解工具箱 - [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab 姿态估计工具箱 - [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 人体参数化模型工具箱与测试基准 - [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab 自监督学习工具箱与测试基准 - [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab 模型压缩工具箱与测试基准 - [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab 少样本学习工具箱与测试基准 - [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab 新一代视频理解工具箱 - [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab 一体化视频目标感知平台 - [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab 光流估计工具箱与测试基准 - [MMagic](https://github.com/open-mmlab/mmagic): OpenMMLab 新一代人工智能内容生成(AIGC)工具箱 - [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab 模型部署框架

🔝返回目录

## 欢迎加入 OpenMMLab 社区 扫描下方的二维码可关注 OpenMMLab 团队的 [知乎官方账号](https://www.zhihu.com/people/openmmlab),扫描下方微信二维码添加喵喵好友,进入 MMagic 微信交流社群。【加好友申请格式:研究方向+地区+学校/公司+姓名】
我们会在 OpenMMLab 社区为大家 - 📢 分享 AI 框架的前沿核心技术 - 💻 解读 PyTorch 常用模块源码 - 📰 发布 OpenMMLab 的相关新闻 - 🚀 介绍 OpenMMLab 开发的前沿算法 - 🏃 获取更高效的问题答疑和意见反馈 - 🔥 提供与各行各业开发者充分交流的平台 干货满满 📘,等你来撩 💗,OpenMMLab 社区期待您的加入 👬 ================================================ FILE: configs/_base_/datasets/basicvsr_test_config.py ================================================ # configs for REDS4 reds_data_root = 'data/REDS' reds_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] reds_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=reds_data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_val.txt', depth=1, num_input_frames=100, fixed_seq_len=100, pipeline=reds_pipeline)) reds_evaluator = [ dict(type='PSNR', prefix='REDS4-BIx4-RGB'), dict(type='SSIM', prefix='REDS4-BIx4-RGB') ] # configs for vimeo90k-bd and vimeo90k-bi vimeo_90k_data_root = 'data/vimeo90k' vimeo_90k_file_list = [ 'im1.png', 'im2.png', 'im3.png', 'im4.png', 'im5.png', 'im6.png', 'im7.png' ] vimeo_90k_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='MirrorSequence', keys=['img']), dict(type='PackInputs') ] vimeo_90k_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vimeo90k_seq', task_name='vsr'), data_root=vimeo_90k_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vimeo90K_test_GT.txt', depth=2, num_input_frames=7, fixed_seq_len=7, load_frames_list=dict(img=vimeo_90k_file_list, gt=['im4.png']), pipeline=vimeo_90k_pipeline)) vimeo_90k_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vimeo90k_seq', task_name='vsr'), data_root=vimeo_90k_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vimeo90K_test_GT.txt', depth=2, num_input_frames=7, fixed_seq_len=7, load_frames_list=dict(img=vimeo_90k_file_list, gt=['im4.png']), pipeline=vimeo_90k_pipeline)) vimeo_90k_bd_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Vimeo-90K-T-BDx4-Y'), dict(type='SSIM', convert_to='Y', prefix='Vimeo-90K-T-BDx4-Y'), ] vimeo_90k_bi_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Vimeo-90K-T-BIx4-Y'), dict(type='SSIM', convert_to='Y', prefix='Vimeo-90K-T-BIx4-Y'), ] # config for UDM10 (BDx4) udm10_data_root = 'data/UDM10' udm10_pipeline = [ dict( type='GenerateSegmentIndices', interval_list=[1], filename_tmpl='{:04d}.png'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] udm10_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='udm10', task_name='vsr'), data_root=udm10_data_root, data_prefix=dict(img='BDx4', gt='GT'), pipeline=udm10_pipeline)) udm10_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='UDM10-BDx4-Y'), dict(type='SSIM', convert_to='Y', prefix='UDM10-BDx4-Y') ] # config for vid4 vid4_data_root = 'data/Vid4' vid4_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] vid4_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=1, pipeline=vid4_pipeline)) vid4_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=1, pipeline=vid4_pipeline)) vid4_bd_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='VID4-BDx4-Y'), dict(type='SSIM', convert_to='Y', prefix='VID4-BDx4-Y'), ] vid4_bi_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='VID4-BIx4-Y'), dict(type='SSIM', convert_to='Y', prefix='VID4-BIx4-Y'), ] # config for test test_cfg = dict(type='MultiTestLoop') test_dataloader = [ reds_dataloader, vimeo_90k_bd_dataloader, vimeo_90k_bi_dataloader, udm10_dataloader, vid4_bd_dataloader, vid4_bi_dataloader, ] test_evaluator = [ reds_evaluator, vimeo_90k_bd_evaluator, vimeo_90k_bi_evaluator, udm10_evaluator, vid4_bd_evaluator, vid4_bi_evaluator, ] ================================================ FILE: configs/_base_/datasets/celeba.py ================================================ # Base config for CelebA-HQ dataset # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data/CelebA-HQ' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt=''), ann_file='train_celeba_img_list.txt', test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt=''), ann_file='val_celeba_img_list.txt', test_mode=True, )) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE', mask_key='mask', scaling=100), # By default, compute with pixel value from 0-1 # scale=2 to align with 1.0 # scale=100 seems to align with readme dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator ================================================ FILE: configs/_base_/datasets/cifar10_noaug.py ================================================ cifar_pipeline = [dict(type='PackInputs')] cifar_dataset = dict( type='CIFAR10', data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline) train_dataloader = dict( num_workers=2, dataset=cifar_dataset, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset, sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset, sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/cifar10_nopad.py ================================================ cifar_pipeline = [ dict(type='Flip', keys=['gt'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] cifar_dataset = dict( type='CIFAR10', data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline) # test dataset do not use flip cifar_pipeline_test = [dict(type='PackInputs')] cifar_dataset_test = dict( type='CIFAR10', data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline_test) train_dataloader = dict( num_workers=2, dataset=cifar_dataset, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset_test, sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset_test, sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/comp1k.py ================================================ # Base config for Composition-1K dataset # dataset settings dataset_type = 'AdobeComp1kDataset' data_root = 'data/adobe_composition-1k' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, ann_file='training_list.json', test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, ann_file='test_list.json', test_mode=True, )) test_dataloader = val_dataloader # TODO: matting val_evaluator = [ dict(type='SAD'), dict(type='MattingMSE'), dict(type='GradientError'), dict(type='ConnectivityError'), ] test_evaluator = val_evaluator ================================================ FILE: configs/_base_/datasets/deblurring-defocus_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='imgL', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='imgR', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] dpdd_data_root = 'data/DPDD' dpdd_indoor_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='DPDD-Indoor', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), ann_file='indoor_labels.txt', pipeline=test_pipeline)) dpdd_indoor_evaluator = [ dict(type='MAE', prefix='DPDD-Indoor'), dict(type='PSNR', prefix='DPDD-Indoor'), dict(type='SSIM', prefix='DPDD-Indoor'), ] dpdd_outdoor_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='DPDD-Outdoor', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), ann_file='outdoor_labels.txt', pipeline=test_pipeline)) dpdd_outdoor_evaluator = [ dict(type='MAE', prefix='DPDD-Outdoor'), dict(type='PSNR', prefix='DPDD-Outdoor'), dict(type='SSIM', prefix='DPDD-Outdoor'), ] dpdd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='DPDD-Combined', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), pipeline=test_pipeline)) dpdd_evaluator = [ dict(type='MAE', prefix='DPDD-Combined'), dict(type='PSNR', prefix='DPDD-Combined'), dict(type='SSIM', prefix='DPDD-Combined'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ dpdd_indoor_dataloader, dpdd_outdoor_dataloader, dpdd_dataloader, ] test_evaluator = [ dpdd_indoor_evaluator, dpdd_outdoor_evaluator, dpdd_evaluator, ] ================================================ FILE: configs/_base_/datasets/deblurring-motion_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] gopro_data_root = 'data/gopro/test' gopro_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='GoPro', task_name='deblurring'), data_root=gopro_data_root, data_prefix=dict(img='blur', gt='sharp'), pipeline=test_pipeline)) gopro_evaluator = [ dict(type='PSNR', prefix='GoPro'), dict(type='SSIM', prefix='GoPro'), ] hide_data_root = 'data/HIDE' hide_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='HIDE', task_name='deblurring'), data_root=hide_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) hide_evaluator = [ dict(type='PSNR', prefix='HIDE'), dict(type='SSIM', prefix='HIDE'), ] realblurj_data_root = 'data/RealBlur_J' realblurj_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='RealBlur_J', task_name='deblurring'), data_root=realblurj_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) realblurj_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='RealBlurJ'), dict(type='SSIM', convert_to='Y', prefix='RealBlurJ'), ] realblurr_data_root = 'data/RealBlur_R' realblurr_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='RealBlur_R', task_name='deblurring'), data_root=realblurr_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) realblurr_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='RealBlurR'), dict(type='SSIM', convert_to='Y', prefix='RealBlurR'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ gopro_dataloader, hide_dataloader, realblurj_dataloader, realblurr_dataloader, ] test_evaluator = [ gopro_evaluator, hide_evaluator, realblurj_evaluator, realblurr_evaluator, ] ================================================ FILE: configs/_base_/datasets/decompression_test_config.py ================================================ quality = 10 test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomJPEGCompression', params=dict(quality=[quality, quality]), bgr2rgb=True, keys=['img']), dict(type='PackInputs') ] classic5_data_root = 'data/Classic5' classic5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='classic5', task_name='CAR'), data_root=classic5_data_root, data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) classic5_evaluator = [ dict(type='PSNR', prefix='Classic5'), dict(type='SSIM', prefix='Classic5'), ] live1_data_root = 'data/LIVE1' live1_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='live1', task_name='CAR'), data_root=live1_data_root, data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) live1_evaluator = [ dict(type='PSNR', prefix='LIVE1'), dict(type='SSIM', prefix='LIVE1'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ classic5_dataloader, live1_dataloader, ] test_evaluator = [ classic5_evaluator, live1_evaluator, ] ================================================ FILE: configs/_base_/datasets/denoising-gaussian_color_test_config.py ================================================ sigma = 15 test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=0), keys=['img']), dict(type='PackInputs') ] data_root = 'data/denoising_gaussian_test' cbsd68_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='CBSD68', task_name='denoising'), data_root=data_root, data_prefix=dict(img='CBSD68', gt='CBSD68'), pipeline=test_pipeline)) cbsd68_evaluator = [ dict(type='PSNR', prefix='CBSD68'), dict(type='SSIM', prefix='CBSD68'), ] kodak24_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Kodak24', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Kodak24', gt='Kodak24'), pipeline=test_pipeline)) kodak24_evaluator = [ dict(type='PSNR', prefix='Kodak24'), dict(type='SSIM', prefix='Kodak24'), ] mcmaster_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='McMaster', task_name='denoising'), data_root=data_root, data_prefix=dict(img='McMaster', gt='McMaster'), pipeline=test_pipeline)) mcmaster_evaluator = [ dict(type='PSNR', prefix='McMaster'), dict(type='SSIM', prefix='McMaster'), ] urban100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Urban100', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Urban100', gt='Urban100'), pipeline=test_pipeline)) urban100_evaluator = [ dict(type='PSNR', prefix='Urban100'), dict(type='SSIM', prefix='Urban100'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ cbsd68_dataloader, kodak24_dataloader, mcmaster_dataloader, urban100_dataloader, ] test_evaluator = [ cbsd68_evaluator, kodak24_evaluator, mcmaster_evaluator, urban100_evaluator, ] ================================================ FILE: configs/_base_/datasets/denoising-gaussian_gray_test_config.py ================================================ sigma = 15 test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', to_y_channel=True, imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', to_y_channel=True, imdecode_backend='cv2'), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=1), keys=['img']), dict(type='PackInputs') ] data_root = 'data/denoising_gaussian_test' set12_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Set12', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Set12', gt='Set12'), pipeline=test_pipeline)) set12_evaluator = [ dict(type='PSNR', prefix='Set12'), dict(type='SSIM', prefix='Set12'), ] bsd68_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='BSD68', task_name='denoising'), data_root=data_root, data_prefix=dict(img='BSD68', gt='BSD68'), pipeline=test_pipeline)) bsd68_evaluator = [ dict(type='PSNR', prefix='BSD68'), dict(type='SSIM', prefix='BSD68'), ] urban100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Urban100', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Urban100', gt='Urban100'), pipeline=test_pipeline)) urban100_evaluator = [ dict(type='PSNR', prefix='Urban100'), dict(type='SSIM', prefix='Urban100'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ set12_dataloader, bsd68_dataloader, urban100_dataloader, ] test_evaluator = [ set12_evaluator, bsd68_evaluator, urban100_evaluator, ] ================================================ FILE: configs/_base_/datasets/denoising-real_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] sidd_data_root = 'data/SIDD/val/' sidd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='SIDD', task_name='denoising'), data_root=sidd_data_root, data_prefix=dict(img='noisy', gt='gt'), filename_tmpl=dict(gt='{}_GT', img='{}_NOISY'), pipeline=test_pipeline)) sidd_evaluator = [ dict(type='PSNR', prefix='SIDD'), dict(type='SSIM', prefix='SIDD'), ] dnd_data_root = 'data/DND' dnd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='DND', task_name='denoising'), data_root=dnd_data_root, data_prefix=dict(img='input', gt='groundtruth'), pipeline=test_pipeline)) dnd_evaluator = [ dict(type='PSNR', prefix='DND'), dict(type='SSIM', prefix='DND'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ sidd_dataloader, # dnd_dataloader, ] test_evaluator = [ sidd_evaluator, # dnd_dataloader, ] ================================================ FILE: configs/_base_/datasets/deraining_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] rain100h_data_root = 'data/Rain100H' rain100h_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Rain100H', task_name='deraining'), data_root=rain100h_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) rain100h_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Rain100H'), dict(type='SSIM', convert_to='Y', prefix='Rain100H'), ] rain100l_data_root = 'data/Rain100L' rain100l_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Rain100L', task_name='deraining'), data_root=rain100l_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) rain100l_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Rain100L'), dict(type='SSIM', convert_to='Y', prefix='Rain100L'), ] test100_data_root = 'data/Test100' test100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Test100', task_name='deraining'), data_root=test100_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test100_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Test100'), dict(type='SSIM', convert_to='Y', prefix='Test100'), ] test1200_data_root = 'data/Test1200' test1200_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Test1200', task_name='deraining'), data_root=test1200_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test1200_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Test1200'), dict(type='SSIM', convert_to='Y', prefix='Test1200'), ] test2800_data_root = 'data/Test2800' test2800_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='Test2800', task_name='deraining'), data_root=test2800_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test2800_evaluator = [ dict(type='PSNR', convert_to='Y', prefix='Test2800'), dict(type='SSIM', convert_to='Y', prefix='Test2800'), ] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ rain100h_dataloader, rain100l_dataloader, test100_dataloader, test1200_dataloader, test2800_dataloader, ] test_evaluator = [ rain100h_evaluator, rain100l_evaluator, test100_evaluator, test1200_evaluator, test2800_evaluator, ] ================================================ FILE: configs/_base_/datasets/ffhq_flip.py ================================================ dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Flip', keys=['gt'], direction='horizontal'), dict(type='PackInputs', keys='gt') ] val_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='PackInputs', keys=['gt']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/grow_scale_imgs_ffhq_styleganv1.py ================================================ dataset_type = 'GrowScaleImgDataset' pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Flip', keys='gt', direction='horizontal'), dict(type='PackInputs') ] train_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type='GrowScaleImgDataset', data_roots={ '1024': './data/ffhq/images', '256': './data/ffhq/ffhq_imgs/ffhq_256', }, gpu_samples_base=4, # note that this should be changed with total gpu number gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4, '128': 4, '256': 4, '512': 4, '1024': 4 }, len_per_stage=300000, pipeline=pipeline), sampler=dict(type='InfiniteSampler', shuffle=True)) test_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type='BasicImageDataset', data_prefix=dict(gt=''), pipeline=pipeline, data_root='./data/ffhq/images'), sampler=dict(type='DefaultSampler', shuffle=False)) val_dataloader = test_dataloader ================================================ FILE: configs/_base_/datasets/imagenet_128.py ================================================ # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='RandomCropLongEdge', keys='gt'), dict(type='Resize', scale=(128, 128), keys='gt', backend='pillow'), dict(type='Flip', keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='CenterCropLongEdge', keys='gt'), dict(type='Resize', scale=(128, 128), keys='gt', backend='pillow'), dict(type='PackInputs') ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: configs/_base_/datasets/imagenet_256.py ================================================ # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='RandomCropLongEdge', keys=['img']), dict(type='Resize', scale=(256, 256), keys=['img'], backend='pillow'), dict(type='Flip', keys=['img'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='CenterCropLongEdge', keys=['img']), dict(type='Resize', scale=(256, 256), backend='pillow'), dict(type='PackInputs') ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: configs/_base_/datasets/imagenet_512.py ================================================ # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='RandomCropLongEdge', keys='gt'), dict(type='Resize', scale=(512, 512), keys='gt', backend='pillow'), dict(type='Flip', keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='CenterCropLongEdge', keys='gt'), dict(type='Resize', scale=(512, 512), keys='gt', backend='pillow'), dict(type='PackInputs') ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: configs/_base_/datasets/imagenet_64.py ================================================ # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='RandomCropLongEdge', keys='gt'), dict(type='Resize', scale=(64, 64), keys='gt', backend='pillow'), dict(type='Flip', keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='CenterCropLongEdge', keys='gt'), dict(type='Resize', scale=(64, 64), keys='gt', backend='pillow'), dict(type='PackInputs') ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: configs/_base_/datasets/imagenet_noaug_128.py ================================================ # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # Remove `RandomFlip` augmentation and change `RandomCropLongEdge` to # `CenterCropLongEdge` to eliminate randomness. # dataset settings train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='CenterCropLongEdge'), dict(type='Resize', scale=(128, 128), backend='pillow'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='CenterCropLongEdge'), dict(type='Resize', scale=(128, 128), backend='pillow'), dict(type='PackInputs') ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='data/imagenet', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: configs/_base_/datasets/liif_test_config.py ================================================ scale_test_list = [2, 3, 4, 6, 18, 30] test_pipelines = [[ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomDownSampling', scale_min=scale_test, scale_max=scale_test), dict(type='GenerateCoordinateAndCell', scale=scale_test, reshape_gt=False), dict(type='PackInputs') ] for scale_test in scale_test_list] # test config for Set5 set5_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set5', task_name='sisr'), data_root='data/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] set5_evaluators = [[ dict(type='PSNR', crop_border=scale, prefix=f'Set5x{scale}'), dict(type='SSIM', crop_border=scale, prefix=f'Set5x{scale}'), ] for scale in scale_test_list] # test config for Set14 set14_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set14', task_name='sisr'), data_root='data/Set14', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] set14_evaluators = [[ dict(type='PSNR', crop_border=scale, prefix=f'Set14x{scale}'), dict(type='SSIM', crop_border=scale, prefix=f'Set14x{scale}'), ] for scale in scale_test_list] # test config for DIV2K div2k_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root='data/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] div2k_evaluators = [[ dict(type='PSNR', crop_border=scale, prefix=f'DIV2Kx{scale}'), dict(type='SSIM', crop_border=scale, prefix=f'DIV2Kx{scale}'), ] for scale in scale_test_list] # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ *set5_dataloaders, *set14_dataloaders, *div2k_dataloaders, ] test_evaluator = [ *set5_evaluators, *set14_evaluators, *div2k_evaluators, ] ================================================ FILE: configs/_base_/datasets/lsun_stylegan.py ================================================ dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/paired_imgs_256x256_crop.py ================================================ dataset_type = 'PairedImageDataset' # domain_a = None # set by user # domain_b = None # set by user train_pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='A', domain_b='B', color_type='color'), dict( type='Resize', keys=['img_A', 'img_B'], scale=(286, 286), interpolation='bicubic'), dict(type='FixedCrop', keys=['img_A', 'img_B'], crop_size=(256, 256)), dict(type='Flip', keys=['img_A', 'img_B'], direction='horizontal'), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type='PackInputs', # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] test_pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='A', domain_b='B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='Resize', scale=(256, 256), keys='img', interpolation='bicubic') ]), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type='PackInputs', # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/places.py ================================================ # Base config for places365 dataset # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data/Places' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt='data_large'), ann_file='meta/places365_train_challenge.txt', # Note that Places365-standard (1.8M images) and # Place365-challenge (8M images) use different image lists. test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt='val_large'), ann_file='meta/places365_val.txt', test_mode=True, )) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE', mask_key='mask', scaling=100), # By default, compute with pixel value from 0-1 # scale=2 to align with 1.0 # scale=100 seems to align with readme dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator ================================================ FILE: configs/_base_/datasets/sisr_x2_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=2, prefix='Set5'), dict(type='SSIM', crop_border=2, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=2, prefix='Set14'), dict(type='SSIM', crop_border=2, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', # ann_file='meta_info_DIV2K800sub_GT.txt', ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=2, prefix='DIV2K'), dict(type='SSIM', crop_border=2, prefix='DIV2K'), ]) # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: configs/_base_/datasets/sisr_x3_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=3, prefix='Set5'), dict(type='SSIM', crop_border=3, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=3, prefix='Set14'), dict(type='SSIM', crop_border=3, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X3_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=3, prefix='DIV2K'), dict(type='SSIM', crop_border=3, prefix='DIV2K'), ]) # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: configs/_base_/datasets/sisr_x4_test_config.py ================================================ test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=4, prefix='Set5'), dict(type='SSIM', crop_border=4, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=4, prefix='Set14'), dict(type='SSIM', crop_border=4, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=4, prefix='DIV2K'), dict(type='SSIM', crop_border=4, prefix='DIV2K'), ]) # test config test_cfg = dict(type='MultiTestLoop') test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: configs/_base_/datasets/tdan_test_config.py ================================================ # configs for SPMCS-30 SPMC_data_root = 'data/SPMCS' SPMC_pipeline = [ dict(type='GenerateFrameIndiceswithPadding', padding='reflection'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] SPMC_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='spmcs', task_name='vsr'), data_root=SPMC_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_SPMCS_GT.txt', depth=2, num_input_frames=5, pipeline=SPMC_pipeline)) SPMC_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='spmcs', task_name='vsr'), data_root=SPMC_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_SPMCS_GT.txt', depth=2, num_input_frames=5, pipeline=SPMC_pipeline)) SPMC_bd_evaluator = dict( type='Evaluator', metrics=[ dict( type='PSNR', crop_border=8, convert_to='Y', prefix='SPMCS-BDx4-Y'), dict( type='SSIM', crop_border=8, convert_to='Y', prefix='SPMCS-BDx4-Y'), ]) SPMC_bi_evaluator = dict( type='Evaluator', metrics=[ dict( type='PSNR', crop_border=8, convert_to='Y', prefix='SPMCS-BIx4-Y'), dict( type='SSIM', crop_border=8, convert_to='Y', prefix='SPMCS-BIx4-Y'), ]) # config for vid4 vid4_data_root = 'data/Vid4' vid4_pipeline = [ # dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='GenerateFrameIndiceswithPadding', padding='reflection'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] vid4_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=5, pipeline=vid4_pipeline)) vid4_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=5, pipeline=vid4_pipeline)) vid4_bd_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', convert_to='Y', prefix='VID4-BDx4-Y'), dict(type='SSIM', convert_to='Y', prefix='VID4-BDx4-Y'), ]) vid4_bi_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', convert_to='Y', prefix='VID4-BIx4-Y'), dict(type='SSIM', convert_to='Y', prefix='VID4-BIx4-Y'), ]) # config for test test_cfg = dict(type='MultiTestLoop') test_dataloader = [ SPMC_bd_dataloader, SPMC_bi_dataloader, vid4_bd_dataloader, vid4_bi_dataloader, ] test_evaluator = [ SPMC_bd_evaluator, SPMC_bi_evaluator, vid4_bd_evaluator, vid4_bi_evaluator, ] ================================================ FILE: configs/_base_/datasets/unconditional_imgs_128x128.py ================================================ # dataset_type = 'BasicImageDataset' dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(128, 128)), dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/unconditional_imgs_64x64.py ================================================ dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(64, 64)), dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/unconditional_imgs_flip_512x512.py ================================================ dataset_type = 'BasicImageDataset' # TODO: train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(512, 512)), dict(type='Flip', keys=['gt'], direction='horizontal'), # TODO: dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/unconditional_imgs_flip_lanczos_resize_256x256.py ================================================ dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='Resize', keys='gt', scale=(256, 256), interpolation='lanczos', backend='pillow'), dict(type='Flip', keys=['gt'], direction='horizontal'), dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/datasets/unpaired_imgs_256x256.py ================================================ dataset_type = 'UnpairedImageDataset' domain_a = None # set by user domain_b = None # set by user train_pipeline = [ dict(type='LoadImageFromFile', key='img_A', color_type='color'), dict(type='LoadImageFromFile', key='img_B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=[ dict(type='Resize', scale=(286, 286), interpolation='bicubic'), dict( type='Crop', keys=['img'], crop_size=(256, 256), random_crop=True), ]), dict(type='Flip', keys=['img_A'], direction='horizontal'), dict(type='Flip', keys=['img_B'], direction='horizontal'), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type='PackInputs', # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] test_pipeline = [ dict(type='LoadImageFromFile', key='img_A', color_type='color'), dict(type='LoadImageFromFile', key='img_B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=dict( type='Resize', scale=(256, 256), interpolation='bicubic'), ), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type='PackInputs', # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user test_mode=True, pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user test_mode=True, pipeline=test_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: configs/_base_/default_runtime.py ================================================ default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( type='CheckpointHook', interval=5000, out_dir=save_dir, by_epoch=False, max_keep_ckpts=10, save_best='PSNR', rule='greater', ), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) load_from = None resume = False vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ================================================ FILE: configs/_base_/gen_default_runtime.py ================================================ default_scope = 'mmagic' randomness = dict(seed=2022, diff_rank_seed=True) # env settings dist_params = dict(backend='nccl') # disable opencv multithreading to avoid system being overloaded opencv_num_threads = 0 # set multi-process start method as `fork` to speed up the training mp_start_method = 'fork' # configure for default hooks default_hooks = dict( # record time of every iteration. timer=dict(type='IterTimerHook'), # print log every 100 iterations. logger=dict(type='LoggerHook', interval=100, log_metric_by_epoch=False), # save checkpoint per 10000 iterations checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, max_keep_ckpts=20, less_keys=['FID-Full-50k/fid', 'FID-50k/fid', 'swd/avg'], greater_keys=['IS-50k/is', 'ms-ssim/avg'], save_optimizer=True)) # config for environment env_cfg = dict( # whether to enable cudnn benchmark. cudnn_benchmark=True, # set multi process parameters. mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), # set distributed parameters. dist_cfg=dict(backend='nccl')) # set log level log_level = 'INFO' log_processor = dict(type='LogProcessor', by_epoch=False) # load from which checkpoint load_from = None # whether to resume training from the loaded checkpoint resume = None # config for model wrapper model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=False) # set visualizer vis_backends = [dict(type='VisBackend')] visualizer = dict(type='Visualizer', vis_backends=vis_backends) # config for training train_cfg = dict(by_epoch=False, val_begin=1, val_interval=10000) # config for val val_cfg = dict(type='MultiValLoop') val_evaluator = dict(type='Evaluator') # config for test test_cfg = dict(type='MultiTestLoop') test_evaluator = dict(type='Evaluator') # config for optim_wrapper_constructor optim_wrapper = dict(constructor='MultiOptimWrapperConstructor') ================================================ FILE: configs/_base_/inpaint_default_runtime.py ================================================ default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] log_level = 'INFO' log_processor = dict(type='LogProcessor', by_epoch=False) load_from = None resume = False # TODO: support auto scaling lr ================================================ FILE: configs/_base_/matting_default_runtime.py ================================================ default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='trimap_path', img_keys=['pred_alpha', 'trimap', 'gt_merged', 'gt_alpha'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=2000)] log_level = 'INFO' log_processor = dict(type='LogProcessor', by_epoch=False) load_from = None resume = False # TODO: support auto scaling lr ================================================ FILE: configs/_base_/models/base_cyclegan.py ================================================ _domain_a = None # set by user _domain_b = None # set by user model = dict( type='CycleGAN', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='ResnetGenerator', in_channels=3, out_channels=3, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02)), default_domain=None, # set by user reachable_domains=None, # set by user related_domains=None # set by user ) ================================================ FILE: configs/_base_/models/base_deepfillv1.py ================================================ # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') model = dict( type='DeepFillv1Inpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='DeepFillEncoderDecoder', stage1=dict( type='GLEncoderDecoder', encoder=dict(type='DeepFillEncoder', padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', in_channels=128, padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=128, act_cfg=dict(type='ELU'), padding_mode='reflect')), stage2=dict( type='DeepFillRefiner', encoder_attention=dict( type='DeepFillEncoder', encoder_type='stage2_attention', padding_mode='reflect'), encoder_conv=dict( type='DeepFillEncoder', encoder_type='stage2_conv', padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=128, act_cfg=dict(type='ELU'), padding_mode='reflect'), contextual_attention=dict( type='ContextualAttentionNeck', in_channels=128, padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', in_channels=256, padding_mode='reflect'))), disc=dict( type='DeepFillv1Discriminators', global_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=256, fc_in_channels=256 * 16 * 16, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), local_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=512, fc_in_channels=512 * 8 * 8, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2))), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type='GANLoss', gan_type='wgan', loss_weight=0.0001, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, ), loss_l1_valid=dict( type='L1Loss', loss_weight=1.0, ), loss_gp=dict(type='GradientPenaltyLoss', loss_weight=10.), loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001)) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001)), disc=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001))) # learning policy # Fixed ================================================ FILE: configs/_base_/models/base_deepfillv2.py ================================================ # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') model = dict( type='TwoStageInpaintor', disc_input_with_mask=True, data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='DeepFillEncoderDecoder', stage1=dict( type='GLEncoderDecoder', encoder=dict( type='DeepFillEncoder', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', conv_type='gated_conv', in_channels=96, channel_factor=0.75, out_act_cfg=dict(type='Tanh'), padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect')), stage2=dict( type='DeepFillRefiner', encoder_attention=dict( type='DeepFillEncoder', encoder_type='stage2_attention', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), encoder_conv=dict( type='DeepFillEncoder', encoder_type='stage2_conv', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect'), contextual_attention=dict( type='ContextualAttentionNeck', in_channels=96, conv_type='gated_conv', padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', in_channels=192, conv_type='gated_conv', out_act_cfg=dict(type='Tanh'), padding_mode='reflect'))), disc=dict( type='MultiLayerDiscriminator', in_channels=4, max_channels=256, fc_in_channels=None, num_convs=6, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=True, ), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type='GANLoss', gan_type='hinge', loss_weight=0.1, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, ), loss_l1_valid=dict( type='L1Loss', loss_weight=1.0, ), ) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001)), disc=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001))) # learning policy # Fixed ================================================ FILE: configs/_base_/models/base_edvr.py ================================================ _base_ = '../default_runtime.py' scale = 4 train_pipeline = [ dict(type='GenerateFrameIndices', interval_list=[1], frames_per_clip=99), dict(type='TemporalReverse', keys='img_path', reverse_ratio=0), dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=256), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateFrameIndiceswithPadding', padding='reflection_circle'), dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data/REDS' save_dir = './work_dirs' train_dataloader = dict( num_workers=8, batch_size=8, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_train.txt', depth=2, num_input_frames=5, num_output_frames=1, pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_val.txt', depth=2, num_input_frames=5, num_output_frames=1, pipeline=val_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=600_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999)), ) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, out_dir=save_dir, by_epoch=False)) ================================================ FILE: configs/_base_/models/base_gl.py ================================================ # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') model = dict( type='GLInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='GLEncoderDecoder', encoder=dict(type='GLEncoder', norm_cfg=dict(type='SyncBN')), decoder=dict(type='GLDecoder', norm_cfg=dict(type='SyncBN')), dilation_neck=dict( type='GLDilationNeck', norm_cfg=dict(type='SyncBN'))), disc=dict( type='GLDiscs', global_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='SyncBN'), ), local_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=5, norm_cfg=dict(type='SyncBN'), ), ), loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, )) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004)), disc=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004))) # learning policy # Fixed ================================================ FILE: configs/_base_/models/base_glean.py ================================================ _base_ = '../default_runtime.py' # DistributedDataParallel model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', find_unused_parameters=True) save_dir = './work_dirs' val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=300_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), ) # learning policy param_scheduler = dict( type='CosineAnnealingLR', by_epoch=False, T_max=600_000, eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, save_best=['MAE', 'PSNR', 'SSIM'], rule=['less', 'greater', 'greater']), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/_base_/models/base_liif.py ================================================ _base_ = '../default_runtime.py' work_dir = './work_dirs/liif' save_dir = './work_dirs' scale_min, scale_max = 1, 4 scale_test = 4 train_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomDownSampling', scale_min=scale_min, scale_max=scale_max, patch_size=48), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='GenerateCoordinateAndCell', sample_quantity=2304), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='RandomDownSampling', scale_min=scale_max, scale_max=scale_max), dict(type='GenerateCoordinateAndCell', reshape_gt=False), dict(type='PackInputs') ] # test_pipeline = [ # dict( # type='LoadImageFromFile', # key='gt', # color_type='color', # channel_order='rgb', # imdecode_backend='cv2'), # dict( # type='LoadImageFromFile', # key='img', # color_type='color', # channel_order='rgb', # imdecode_backend='cv2'), # dict(type='GenerateCoordinateAndCell', scale=scale_test, # reshape_gt=False), # dict(type='PackInputs') # ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict(gt='DIV2K_train_HR_sub'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale_max), dict(type='SSIM', crop_border=scale_max), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=3000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4)) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200_000, 400_000, 600_000, 800_000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=3000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/_base_/models/base_pconv.py ================================================ # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') model = dict( type='PConvInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='SyncBN', requires_grad=False), norm_eval=True), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='SyncBN'))), disc=None, loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg16', layer_weights={ '4': 1., '9': 1., '16': 1., }, perceptual_weight=0.05, style_weight=120, pretrained=('torchvision://vgg16')), loss_out_percep=True, loss_l1_hole=dict( type='L1Loss', loss_weight=6., ), loss_l1_valid=dict( type='L1Loss', loss_weight=1., ), loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1, )) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00005)) # learning policy # Fixed ================================================ FILE: configs/_base_/models/base_pix2pix.py ================================================ source_domain = None # set by user target_domain = None # set by user # model settings model = dict( type='Pix2Pix', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='UnetGenerator', in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)), loss_config=dict(pixel_loss_weight=100.0), default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain]) ================================================ FILE: configs/_base_/models/base_styleganv1.py ================================================ model = dict( type='StyleGANv1', data_preprocessor=dict(type='DataPreprocessor'), style_channels=512, generator=dict( type='StyleGANv1Generator', out_size=None, style_channels=512), discriminator=dict(type='StyleGAN1Discriminator', in_size=None)) ================================================ FILE: configs/_base_/models/base_styleganv2.py ================================================ # define GAN model d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) loss_config = dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2) model = dict( type='StyleGAN2', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='StyleGANv2Generator', out_size=None, # Need to be set. style_channels=512, ), discriminator=dict( type='StyleGAN2Discriminator', in_size=None, # Need to be set. ), ema_config=dict(type='ExponentialMovingAverage'), loss_config=loss_config) ================================================ FILE: configs/_base_/models/base_styleganv3.py ================================================ # define GAN model d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) model = dict( type='StyleGAN3', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='StyleGANv3Generator', noise_size=512, style_channels=512, out_size=None, # Need to be set. img_channels=3, ), discriminator=dict( type='StyleGAN2Discriminator', in_size=None, # Need to be set. ), ema_config=dict(type='ExponentialMovingAverage'), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) ================================================ FILE: configs/_base_/models/base_tof.py ================================================ _base_ = '../default_runtime.py' train_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] demo_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] # dataset settings train_dataset_type = 'BasicFramesDataset' val_dataset_type = 'BasicFramesDataset' data_root = 'data/vimeo_triplet' save_dir = './work_dirs' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=train_dataset_type, ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=train_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=val_dataset_type, ann_file='tri_testlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=train_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator # 5000 iters == 1 epoch epoch_length = 5000 train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=epoch_length) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict( type='Adam', lr=5e-5, betas=(0.9, 0.99), weight_decay=1e-4, ), ) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, gamma=0.5, milestones=[200000, 400000, 600000, 800000]) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=epoch_length, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/_base_/models/biggan/base_biggan_128x128.py ================================================ model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho')), generator_steps=1, discriminator_steps=1) ================================================ FILE: configs/_base_/models/dcgan/base_dcgan_128x128.py ================================================ # define GAN model model = dict( type='DCGAN', noise_size=100, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='DCGANGenerator', output_scale=128, base_channels=1024), discriminator=dict( type='DCGANDiscriminator', input_scale=128, output_scale=4, out_channels=100)) ================================================ FILE: configs/_base_/models/dcgan/base_dcgan_64x64.py ================================================ # define GAN model model = dict( type='DCGAN', noise_size=100, data_preprocessor=dict(type='DataPreprocessor'), generator=dict(type='DCGANGenerator', output_scale=64, base_channels=1024), discriminator=dict( type='DCGANDiscriminator', input_scale=64, output_scale=4, out_channels=1)) ================================================ FILE: configs/_base_/models/sagan/base_sagan_128x128.py ================================================ model = dict( type='SAGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='SAGANGenerator', output_scale=128, base_channels=64, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=4, with_spectral_norm=True), discriminator=dict( type='ProjDiscriminator', input_scale=128, base_channels=64, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=1, with_spectral_norm=True), generator_steps=1, discriminator_steps=1) ================================================ FILE: configs/_base_/models/sagan/base_sagan_32x32.py ================================================ model = dict( type='SAGAN', data_preprocessor=dict(type='DataPreprocessor'), num_classes=10, generator=dict( type='SAGANGenerator', num_classes=10, output_scale=32, base_channels=256, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=2, with_spectral_norm=True), discriminator=dict( type='ProjDiscriminator', num_classes=10, input_scale=32, base_channels=128, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=1, with_spectral_norm=True), generator_steps=1, discriminator_steps=5) ================================================ FILE: configs/_base_/models/sngan_proj/base_sngan_proj_128x128.py ================================================ # define GAN model model = dict( type='SNGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict(type='SNGANGenerator', output_scale=128, base_channels=64), discriminator=dict( type='ProjDiscriminator', input_scale=128, base_channels=64), discriminator_steps=2) ================================================ FILE: configs/_base_/models/sngan_proj/base_sngan_proj_32x32.py ================================================ # define GAN model model = dict( type='SNGAN', num_classes=10, data_preprocessor=dict(type='DataPreprocessor'), generator=dict(type='SNGANGenerator', output_scale=32, base_channels=256), discriminator=dict( type='ProjDiscriminator', input_scale=32, base_channels=128), discriminator_steps=5) ================================================ FILE: configs/_base_/schedules/.gitkeep ================================================ ================================================ FILE: configs/animatediff/README.md ================================================ # AnimateDiff (2023) > [AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning](https://arxiv.org/abs/2307.04725) > **Task**: Text2Video ## Abstract With the advance of text-to-image models (e.g., Stable Diffusion) and corresponding personalization techniques such as DreamBooth and LoRA, everyone can manifest their imagination into high-quality images at an affordable cost. Subsequently, there is a great demand for image animation techniques to further combine generated static images with motion dynamics. In this report, we propose a practical framework to animate most of the existing personalized text-to-image models once and for all, saving efforts in model-specific tuning. At the core of the proposed framework is to insert a newly initialized motion modeling module into the frozen text-to-image model and train it on video clips to distill reasonable motion priors. Once trained, by simply injecting this motion modeling module, all personalized versions derived from the same base T2I readily become text-driven models that produce diverse and personalized animated images. We conduct our evaluation on several public representative personalized text-to-image models across anime pictures and realistic photographs, and demonstrate that our proposed framework helps these models generate temporally smooth animation clips while preserving the domain and diversity of their outputs. ![512](https://github.com/ElliotQi/mmagic/assets/46469021/54d92aca-dfa9-4eeb-ba38-3f6c981e5399) ## Pretrained models We use Stable Diffusion's weights provided by HuggingFace Diffusers. You do not have to download the weights manually. If you use Diffusers wrapper, the weights will be downloaded automatically. This model has several weights including vae, unet and clip. You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'pretrained_model_path' in config to the weights dir. | Model | Dataset | Download | | :------------------------------------------------------------: | :-----: | :-----------------------------------------------------------------------------------------------------------------: | | [ToonYou](./animatediff_ToonYou.py) | - | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/toonyou_beta3.safetensors) | | [Lyriel](./animatediff_Lyriel.py) | - | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/lyriel_v16.safetensors) | | [RcnzCartoon](./animatediff_RcnzCartoon.py) | - | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/rcnzCartoon3d_v10.safetensors) | | [MajicMix](./animatediff_MajicMix.py) | - | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/majicmixRealistic_v5Preview.safetensors) | | [RealisticVision](./animatediff_RealisticVision.py) | - | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/realisticVisionV51_v20Novae.safetensors) | | [MotionModel_v1-5_v2](./animatediff_RealisticVision_v2.py) | WebVid | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/mm_sd_v15_v2.ckpt) | | [MotionModel_v1-5_2Mval](./animatediff_RealisticVision_v1.py) | WebVid | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/mm_fromscratch_2.5Mval.ckpt) | | [MotionModel_v1-5_10Mval](./animatediff_RealisticVision_v1.py) | WebVid | [model](https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/mm_fromscratch_10Mval.ckpt) | Latest models could be looked up on [OpenXLab_AnimateDiff](https://openxlab.org.cn/models/detail/ElliotQi/AnimateDiff). ## Quick Start Running the following codes, you can get a text-generated image. ### Reccomendation It's highly recommended to install [xformers](https://github.com/facebookresearch/xformers). It would save about 20G memory for 512\*512 resolution generation. ### Steps 1. Download [ToonYou](https://civitai.com/api/download/models/78775) and MotionModule checkpoint ```bash #!/bin/bash mkdir models && cd models mkdir Motion_Module && mkdir DreamBooth_LoRA gdown 1RqkQuGPaCO5sGZ6V6KZ-jUWmsRu48Kdq -O Motion_Module/ gdown 1ql0g_Ys4UCz2RnokYlBjyOYPbttbIpbu -O models/Motion_Module/ wget https://civitai.com/api/download/models/78775 -P DreamBooth_LoRA/ --content-disposition --no-check-certificate ``` 2. Modify the config file in `configs/animatediff/animatediff_ToonYou.py` ```python models_path = {Your Checkpoints Path} motion_module_cfg=dict( path={Your MotionModule Path} ), dream_booth_lora_cfg=dict( type='ToonYou', path={Your Dreambooth_Lora Path}, steps=25, guidance_scale=7.5) ``` 3. Enjoy Text2Video world ```python from mmengine import Config from mmagic.registry import MODELS from mmagic.utils import register_all_modules import os import torch from pathlib import Path import datetime from mmagic.models.editors.animatediff import save_videos_grid register_all_modules() cfg = Config.fromfile('configs/animatediff/animatediff_ToonYou.py') animatediff = MODELS.build(cfg.model).cuda() prompts = [ "best quality, masterpiece, 1girl, looking at viewer, blurry background, upper body, contemporary, dress", "masterpiece, best quality, 1girl, solo, cherry blossoms, hanami, pink flower, white flower, spring season, wisteria, petals, flower, plum blossoms, outdoors, falling petals, white hair, black eyes,", "best quality, masterpiece, 1boy, formal, abstract, looking at viewer, masculine, marble pattern", "best quality, masterpiece, 1girl, cloudy sky, dandelion, contrapposto, alternate hairstyle," ] negative_prompts = [ "", "badhandv4,easynegative,ng_deepnegative_v1_75t,verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, teeth", "", "", ] sample_idx = 0 random_seeds = cfg.randomness['seed'] random_seeds = [random_seeds] if isinstance(random_seeds, int) else list(random_seeds) samples = [] time_str = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S") savedir = f"samples/{Path(cfg.model['dream_booth_lora_cfg']['type']).stem}-{time_str}" os.makedirs(savedir) for prompt_idx, (prompt, n_prompt, random_seed) in enumerate(zip(prompts, negative_prompts, random_seeds)): output_dict = animatediff.infer(prompt,negative_prompt=n_prompt, video_length=16, height=256, width=256, seed=random_seed,num_inference_steps=cfg.model['dream_booth_lora_cfg']['steps']) sample = output_dict['samples'] prompt = "-".join((prompt.replace("/", "").split(" ")[:10])) save_videos_grid(sample, f"{savedir}/sample/{sample_idx}-{prompt}.gif") print(f"save to {savedir}/sample/{prompt}.gif") samples.append(sample) sample_idx += 1 samples = torch.concat(samples) save_videos_grid(samples, f"{savedir}/sample.gif", n_rows=4) ``` ### Prompts for other config - Lyriel ```yaml prompt: - "dark shot, epic realistic, portrait of halo, sunglasses, blue eyes, tartan scarf, white hair by atey ghailan, by greg rutkowski, by greg tocchini, by james gilleard, by joe fenton, by kaethe butcher, gradient yellow, black, brown and magenta color scheme, grunge aesthetic!!! graffiti tag wall background, art by greg rutkowski and artgerm, soft cinematic light, adobe lightroom, photolab, hdr, intricate, highly detailed, depth of field, faded, neutral colors, hdr, muted colors, hyperdetailed, artstation, cinematic, warm lights, dramatic light, intricate details, complex background, rutkowski, teal and orange" - "A forbidden castle high up in the mountains, pixel art, intricate details2, hdr, intricate details, hyperdetailed5, natural skin texture, hyperrealism, soft light, sharp, game art, key visual, surreal" - "dark theme, medieval portrait of a man sharp features, grim, cold stare, dark colors, Volumetric lighting, baroque oil painting by Greg Rutkowski, Artgerm, WLOP, Alphonse Mucha dynamic lighting hyperdetailed intricately detailed, hdr, muted colors, complex background, hyperrealism, hyperdetailed, amandine van ray" - "As I have gone alone in there and with my treasures bold, I can keep my secret where and hint of riches new and old. Begin it where warm waters halt and take it in a canyon down, not far but too far to walk, put in below the home of brown." n_prompt: - "3d, cartoon, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, artist name, young, loli, elf, 3d, illustration" - "3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, girl, loli, young, large breasts, red eyes, muscular" - "dof, grayscale, black and white, bw, 3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, girl, loli, young, large breasts, red eyes, muscular,badhandsv5-neg, By bad artist -neg 1, monochrome" - "holding an item, cowboy, hat, cartoon, 3d, disfigured, bad art, deformed,extra limbs,close up,b&w, weird colors, blurry, duplicate, morbid, mutilated, [out of frame], extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, ugly, blurry, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, out of frame, ugly, extra limbs, bad anatomy, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, mutated hands, fused fingers, too many fingers, long neck, Photoshop, video game, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, mutation, mutated, extra limbs, extra legs, extra arms, disfigured, deformed, cross-eye, body out of frame, blurry, bad art, bad anatomy, 3d render" ``` - RcnzCartoon ```yaml prompt: - "Jane Eyre with headphones, natural skin texture,4mm,k textures, soft cinematic light, adobe lightroom, photolab, hdr, intricate, elegant, highly detailed, sharp focus, cinematic look, soothing tones, insane details, intricate details, hyperdetailed, low contrast, soft cinematic light, dim colors, exposure blend, hdr, faded" - "close up Portrait photo of muscular bearded guy in a worn mech suit, light bokeh, intricate, steel metal [rust], elegant, sharp focus, photo by greg rutkowski, soft lighting, vibrant colors, masterpiece, streets, detailed face" - "absurdres, photorealistic, masterpiece, a 30 year old man with gold framed, aviator reading glasses and a black hooded jacket and a beard, professional photo, a character portrait, altermodern, detailed eyes, detailed lips, detailed face, grey eyes" - "a golden labrador, warm vibrant colours, natural lighting, dappled lighting, diffused lighting, absurdres, highres,k, uhd, hdr, rtx, unreal, octane render, RAW photo, photorealistic, global illumination, subsurface scattering" n_prompt: - "deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, mutated hands and fingers, disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation" - "nude, cross eyed, tongue, open mouth, inside, 3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, red eyes, muscular" - "easynegative, cartoon, anime, sketches, necklace, earrings worst quality, low quality, normal quality, bad anatomy, bad hands, shiny skin, error, missing fingers, extra digit, fewer digits, jpeg artifacts, signature, watermark, username, blurry, chubby, anorectic, bad eyes, old, wrinkled skin, red skin, photograph By bad artist -neg, big eyes, muscular face," - "beard, EasyNegative, lowres, chromatic aberration, depth of field, motion blur, blurry, bokeh, bad quality, worst quality, multiple arms, badhand" ``` - MajicMix ```yaml prompt: - "1girl, offshoulder, light smile, shiny skin best quality, masterpiece, photorealistic" - "best quality, masterpiece, photorealistic, 1boy, 50 years old beard, dramatic lighting" - "best quality, masterpiece, photorealistic, 1girl, light smile, shirt with collars, waist up, dramatic lighting, from below" - "male, man, beard, bodybuilder, skinhead,cold face, tough guy, cowboyshot, tattoo, french windows, luxury hotel masterpiece, best quality, photorealistic" n_prompt: - "ng_deepnegative_v1_75t, badhandv4, worst quality, low quality, normal quality, lowres, bad anatomy, bad hands, watermark, moles" - "nsfw, ng_deepnegative_v1_75t,badhandv4, worst quality, low quality, normal quality, lowres,watermark, monochrome" - "nsfw, ng_deepnegative_v1_75t,badhandv4, worst quality, low quality, normal quality, lowres,watermark, monochrome" - "nude, nsfw, ng_deepnegative_v1_75t, badhandv4, worst quality, low quality, normal quality, lowres, bad anatomy, bad hands, monochrome, grayscale watermark, moles, people" ``` - Realistic & Realistic_v2 (same prompts with different random seed, find more details in their config files) ```yaml prompt: - "b&w photo of 42 y.o man in black clothes, bald, face, half body, body, high detailed skin, skin pores, coastline, overcast weather, wind, waves, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3" - "close up photo of a rabbit, forest, haze, halation, bloom, dramatic atmosphere, centred, rule of thirds, 200mm 1.4f macro shot" - "photo of coastline, rocks, storm weather, wind, waves, lightning, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3" - "night, b&w photo of old house, post apocalypse, forest, storm weather, wind, rocks, 8k uhd, dslr, soft lighting, high quality, film grain" n_prompt: - "semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, text, close up, cropped, out of frame, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck" - "semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, text, close up, cropped, out of frame, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck" - "blur, haze, deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, mutated hands and fingers, deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated, ugly, disgusting, amputation" - "blur, haze, deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, art, mutated hands and fingers, deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated, ugly, disgusting, amputation" ``` 4. Start training motion module with the following command: ```bash # 4 GPUS bash tools/dist_train.sh configs/animatediff/animatediff.py 4 # 1 GPU python tools/train.py configs/animatediff/animatediff.py ``` ## Citation ```bibtex @article{guo2023animatediff, title={AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning}, author={Guo, Yuwei and Yang, Ceyuan and Rao, Anyi and Wang, Yaohui and Qiao, Yu and Lin, Dahua and Dai, Bo}, journal={arXiv preprint arXiv:2307.04725}, year={2023} } ``` ================================================ FILE: configs/animatediff/README_zh-CN.md ================================================ # AnimateDiff (2023) > [AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning](https://arxiv.org/abs/2307.04725) > **任务**: 视频生成, 扩散模型 ## 摘要 年来,AIGC 宛如 AI 海洋中最不可或缺的波涛,逐渐凝成滔天的巨浪,突破壁垒、扑向海岸,并酝酿着下一波潮水高涨。以 Stable Diffusion 这股翻腾最为汹涌的波涛为代表的文生图模型飞速发展,使得更多非专业用户也能通过简单的文字提示生成高质量的图片内容。然而,文生图模型的训练成本往往十分高昂,为减轻微调模型的代价,相应的模型定制化方法如 DreamBooth, LoRA 应运而生,使得用户在开源权重的基础上,用少量数据和消费级显卡即可实现模型个性化和特定风格下的图像生成质量的提升。这极大推动了 HuggingFace, CivitAI 等开源模型社区的发展,众多艺术家和爱好者在其中贡献了许多高质量的微调模型。不觉间,平静的海洋洪水滔天,海滩上留下数不清的色彩斑斓的鹅卵石,便是爱好者们精心调制的 AI 画作。 与动画相比,静态图像的表达能力是有限的。随着越来越多效果惊艳的微调模型的出现和视频生成技术的发展,人们期待着能够赋予这些定制化模型生成动画的能力。在最新开源的 AnimateDiff 中,作者提出了一种将任何定制化文生图模型拓展用于动画生成的框架,可以在保持原有定制化模型画面质量的基础上,生成相应的动画片段。为色彩斑斓的鹅卵石,增添一些动态的光泽。 ![512](https://github.com/ElliotQi/mmagic/assets/46469021/54d92aca-dfa9-4eeb-ba38-3f6c981e5399) ## 模型与结果 我们使用HuggingFace提供的Stable Diffusion权重。如果您使用Diffusers wrapper,您不必手动下载权重,其将自动下载。 | 模型 | 下载 | | :------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | | [ToonYou](./animatediff_ToonYou.py) | [model](https://civitai.com/api/download/models/78775) | | [Lyriel](./animatediff_Lyriel.py) | [model](https://civitai.com/api/download/models/72396) | | [RcnzCartoon](./animatediff_RcnzCartoon.py) | [model](https://civitai.com/api/download/models/71009) | | [MajicMix](./animatediff_MajicMix.py) | [model](https://civitai.com/api/download/models/79068) | | [RealisticVision](./animatediff_RealisticVision.py) | [model](https://civitai.com/api/download/models/29460) | | [RealisticVision_v2](./animatediff_RealisticVision_v2.py) | [model](https://huggingface.co/guoyww/animatediff/resolve/main/mm_sd_v15_v2.ckpt) | | [MotionModel_v1-5_v2](./animatediff_RealisticVision_v2.py) | [model](https://download.openxlab.org.cn/models/ElliotQi/AnimateDiff/weight/mm_sd_v15_v2) | | [MotionModel_v1-5_2Mval](./animatediff_RealisticVision_v1.py) | [model](https://download.openxlab.org.cn/models/ElliotQi/AnimateDiff/weight/mm_fromscratch_2.5Mval) | | [MotionModel_v1-5_10Mval](./animatediff_RealisticVision_v1.py) | WebVid | 最新模型更新请在[浦源_AnimateDiff](https://openxlab.org.cn/models/detail/ElliotQi/AnimateDiff)中查看 ## 快速开始 运行以下代码,你可以使用AnimateDiff通过文本生成视频。 #### 小建议 强烈推荐安装 [xformers](https://github.com/facebookresearch/xformers),512\*512分辨率可以节省约20G显存。 1. 下载 [ToonYou](https://civitai.com/api/download/models/78775) 和 MotionModule 权重 ```bash #!/bin/bash mkdir models && cd models mkdir Motion_Module && mkdir DreamBooth_LoRA gdown 1RqkQuGPaCO5sGZ6V6KZ-jUWmsRu48Kdq -O Motion_Module/ gdown 1ql0g_Ys4UCz2RnokYlBjyOYPbttbIpbu -O models/Motion_Module/ wget https://civitai.com/api/download/models/78775 -P DreamBooth_LoRA/ --content-disposition --no-check-certificate ``` 2. 修改 `configs/animatediff/animatediff_ToonYou.py` 配置文件中的权重路径 ```python models_path = {Your Checkpoints Path} motion_module_cfg=dict( path={Your MotionModule Path} ), dream_booth_lora_cfg=dict( type='ToonYou', path={Your Dreambooth_Lora Path}, steps=25, guidance_scale=7.5) ``` 3. 享受AnimateDiff视频生成吧! ```python from mmengine import Config from mmagic.registry import MODELS from mmagic.utils import register_all_modules import os import torch from pathlib import Path import datetime from mmagic.models.editors.animatediff import save_videos_grid register_all_modules() cfg = Config.fromfile('configs/animatediff/animatediff_ToonYou.py') animatediff = MODELS.build(cfg.model).cuda() prompts = [ "best quality, masterpiece, 1girl, looking at viewer, blurry background, upper body, contemporary, dress", "masterpiece, best quality, 1girl, solo, cherry blossoms, hanami, pink flower, white flower, spring season, wisteria, petals, flower, plum blossoms, outdoors, falling petals, white hair, black eyes,", "best quality, masterpiece, 1boy, formal, abstract, looking at viewer, masculine, marble pattern", "best quality, masterpiece, 1girl, cloudy sky, dandelion, contrapposto, alternate hairstyle," ] negative_prompts = [ "", "badhandv4,easynegative,ng_deepnegative_v1_75t,verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, teeth", "", "", ] sample_idx = 0 random_seeds = cfg.randomness['seed'] random_seeds = [random_seeds] if isinstance(random_seeds, int) else list(random_seeds) samples = [] time_str = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S") savedir = f"samples/{Path(cfg.model['dream_booth_lora_cfg']['type']).stem}-{time_str}" os.makedirs(savedir) for prompt_idx, (prompt, n_prompt, random_seed) in enumerate(zip(prompts, negative_prompts, random_seeds)): output_dict = animatediff.infer(prompt,negative_prompt=n_prompt, video_length=16, height=256, width=256, seed=random_seed,num_inference_steps=cfg.model['dream_booth_lora_cfg']['steps']) sample = output_dict['samples'] prompt = "-".join((prompt.replace("/", "").split(" ")[:10])) save_videos_grid(sample, f"{savedir}/sample/{sample_idx}-{prompt}.gif") print(f"save to {savedir}/sample/{prompt}.gif") samples.append(sample) sample_idx += 1 samples = torch.concat(samples) save_videos_grid(samples, f"{savedir}/sample.gif", n_rows=4) ``` ### 其他配置文件的Prompts - Lyriel ```yaml prompt: - "dark shot, epic realistic, portrait of halo, sunglasses, blue eyes, tartan scarf, white hair by atey ghailan, by greg rutkowski, by greg tocchini, by james gilleard, by joe fenton, by kaethe butcher, gradient yellow, black, brown and magenta color scheme, grunge aesthetic!!! graffiti tag wall background, art by greg rutkowski and artgerm, soft cinematic light, adobe lightroom, photolab, hdr, intricate, highly detailed, depth of field, faded, neutral colors, hdr, muted colors, hyperdetailed, artstation, cinematic, warm lights, dramatic light, intricate details, complex background, rutkowski, teal and orange" - "A forbidden castle high up in the mountains, pixel art, intricate details2, hdr, intricate details, hyperdetailed5, natural skin texture, hyperrealism, soft light, sharp, game art, key visual, surreal" - "dark theme, medieval portrait of a man sharp features, grim, cold stare, dark colors, Volumetric lighting, baroque oil painting by Greg Rutkowski, Artgerm, WLOP, Alphonse Mucha dynamic lighting hyperdetailed intricately detailed, hdr, muted colors, complex background, hyperrealism, hyperdetailed, amandine van ray" - "As I have gone alone in there and with my treasures bold, I can keep my secret where and hint of riches new and old. Begin it where warm waters halt and take it in a canyon down, not far but too far to walk, put in below the home of brown." n_prompt: - "3d, cartoon, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, artist name, young, loli, elf, 3d, illustration" - "3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, girl, loli, young, large breasts, red eyes, muscular" - "dof, grayscale, black and white, bw, 3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, girl, loli, young, large breasts, red eyes, muscular,badhandsv5-neg, By bad artist -neg 1, monochrome" - "holding an item, cowboy, hat, cartoon, 3d, disfigured, bad art, deformed,extra limbs,close up,b&w, weird colors, blurry, duplicate, morbid, mutilated, [out of frame], extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, ugly, blurry, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, out of frame, ugly, extra limbs, bad anatomy, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, mutated hands, fused fingers, too many fingers, long neck, Photoshop, video game, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, mutation, mutated, extra limbs, extra legs, extra arms, disfigured, deformed, cross-eye, body out of frame, blurry, bad art, bad anatomy, 3d render" ``` - RcnzCartoon ```yaml prompt: - "Jane Eyre with headphones, natural skin texture,4mm,k textures, soft cinematic light, adobe lightroom, photolab, hdr, intricate, elegant, highly detailed, sharp focus, cinematic look, soothing tones, insane details, intricate details, hyperdetailed, low contrast, soft cinematic light, dim colors, exposure blend, hdr, faded" - "close up Portrait photo of muscular bearded guy in a worn mech suit, light bokeh, intricate, steel metal [rust], elegant, sharp focus, photo by greg rutkowski, soft lighting, vibrant colors, masterpiece, streets, detailed face" - "absurdres, photorealistic, masterpiece, a 30 year old man with gold framed, aviator reading glasses and a black hooded jacket and a beard, professional photo, a character portrait, altermodern, detailed eyes, detailed lips, detailed face, grey eyes" - "a golden labrador, warm vibrant colours, natural lighting, dappled lighting, diffused lighting, absurdres, highres,k, uhd, hdr, rtx, unreal, octane render, RAW photo, photorealistic, global illumination, subsurface scattering" n_prompt: - "deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, mutated hands and fingers, disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation" - "nude, cross eyed, tongue, open mouth, inside, 3d, cartoon, anime, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, bad anatomy, red eyes, muscular" - "easynegative, cartoon, anime, sketches, necklace, earrings worst quality, low quality, normal quality, bad anatomy, bad hands, shiny skin, error, missing fingers, extra digit, fewer digits, jpeg artifacts, signature, watermark, username, blurry, chubby, anorectic, bad eyes, old, wrinkled skin, red skin, photograph By bad artist -neg, big eyes, muscular face," - "beard, EasyNegative, lowres, chromatic aberration, depth of field, motion blur, blurry, bokeh, bad quality, worst quality, multiple arms, badhand" ``` - MajicMix ```yaml prompt: - "1girl, offshoulder, light smile, shiny skin best quality, masterpiece, photorealistic" - "best quality, masterpiece, photorealistic, 1boy, 50 years old beard, dramatic lighting" - "best quality, masterpiece, photorealistic, 1girl, light smile, shirt with collars, waist up, dramatic lighting, from below" - "male, man, beard, bodybuilder, skinhead,cold face, tough guy, cowboyshot, tattoo, french windows, luxury hotel masterpiece, best quality, photorealistic" n_prompt: - "ng_deepnegative_v1_75t, badhandv4, worst quality, low quality, normal quality, lowres, bad anatomy, bad hands, watermark, moles" - "nsfw, ng_deepnegative_v1_75t,badhandv4, worst quality, low quality, normal quality, lowres,watermark, monochrome" - "nsfw, ng_deepnegative_v1_75t,badhandv4, worst quality, low quality, normal quality, lowres,watermark, monochrome" - "nude, nsfw, ng_deepnegative_v1_75t, badhandv4, worst quality, low quality, normal quality, lowres, bad anatomy, bad hands, monochrome, grayscale watermark, moles, people" ``` - Realistic & Realistic_v2 (两者使用相同prompts和不同的随机种子) ```yaml prompt: - "b&w photo of 42 y.o man in black clothes, bald, face, half body, body, high detailed skin, skin pores, coastline, overcast weather, wind, waves, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3" - "close up photo of a rabbit, forest, haze, halation, bloom, dramatic atmosphere, centred, rule of thirds, 200mm 1.4f macro shot" - "photo of coastline, rocks, storm weather, wind, waves, lightning, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3" - "night, b&w photo of old house, post apocalypse, forest, storm weather, wind, rocks, 8k uhd, dslr, soft lighting, high quality, film grain" n_prompt: - "semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, text, close up, cropped, out of frame, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck" - "semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, text, close up, cropped, out of frame, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck" - "blur, haze, deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, mutated hands and fingers, deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated, ugly, disgusting, amputation" - "blur, haze, deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime, art, mutated hands and fingers, deformed, distorted, disfigured, poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, disconnected limbs, mutation, mutated, ugly, disgusting, amputation" ``` 4. 开始训练运动模块脚本: ```bash # 4 GPUS bash tools/dist_train.sh configs/animatediff/animatediff.py 4 # 1 GPU python tools/train.py configs/animatediff/animatediff.py ``` ## 引用 ```bibtex @article{guo2023animatediff, title={AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning}, author={Guo, Yuwei and Yang, Ceyuan and Rao, Anyi and Wang, Yaohui and Qiao, Yu and Lin, Dahua and Dai, Bo}, journal={arXiv preprint arXiv:2307.04725}, year={2023} } ``` ================================================ FILE: configs/animatediff/animatediff_Lyriel.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 10917152860782582783, 6399018107401806238, 15875751942533906793, 6653196880059936551 ], diff_rank_seed=True) diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v14.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/lyriel_v16.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/animatediff_MajicMix.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 1572448948722921032, 1099474677988590681, 6488833139725635347, 18339859844376517918 ], diff_rank_seed=True) diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v14.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/majicmixRealistic_v5Preview.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/animatediff_RcnzCartoon.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 16931037867122267877, 2094308009433392066, 4292543217695451092, 15572665120852309890 ], diff_rank_seed=True) diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v14.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/rcnzCartoon3d_v10.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/animatediff_RealisticVision.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 5658137986800322009, 12099779162349365895, 10499524853910852697, 16768009035333711932 ], diff_rank_seed=True) diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v14.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/realisticVisionV20_v20.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/animatediff_RealisticVision_v2.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 13100322578370451493, 14752961627088720670, 9329399085567825781, 16987697414827649302 ], diff_rank_seed=True) diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', use_inflated_groupnorm=True, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=True, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=32, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v15_v2.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/realisticVisionV20_v20.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/animatediff_ToonYou.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' models_path = '/home/AnimateDiff/models/' randomness = dict( seed=[ 10788741199826055526, 6520604954829636163, 6519455744612555650, 16372571278361863751 ], diff_rank_seed=True) val_prompts = [ 'best quality, masterpiece, 1girl, looking at viewer,\ blurry background, upper body, contemporary, dress', 'masterpiece, best quality, 1girl, solo, cherry blossoms,\ hanami, pink flower, white flower, spring season, wisteria,\ petals, flower, plum blossoms, outdoors, falling petals,\ white hair, black eyes,', 'best quality, masterpiece, 1boy, formal, abstract,\ looking at viewer, masculine, marble pattern', 'best quality, masterpiece, 1girl, cloudy sky,\ dandelion, contrapposto, alternate hairstyle,' ] val_neg_propmts = [ '', 'badhandv4,easynegative,ng_deepnegative_v1_75t,verybadimagenegative_v1.3,\ bad-artist, bad_prompt_version2-neg, teeth', '', '', ] diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg=dict(path=models_path + 'Motion_Module/mm_sd_v14.ckpt'), dream_booth_lora_cfg=dict( type='ToonYou', path=models_path + 'DreamBooth_LoRA/toonyou_beta3.safetensors', steps=25, guidance_scale=7.5)) ================================================ FILE: configs/animatediff/metafile.yml ================================================ Collections: - Name: AnimateDiff Paper: Title: 'AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning' URL: https://arxiv.org/abs/2307.04725 README: configs/animatediff/README.md Task: - text2video Year: 2023 Models: - Config: configs/animatediff/animatediff_ToonYou.py In Collection: AnimateDiff Name: animatediff_ToonYou Results: - Dataset: '-' Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/toonyou_beta3.safetensors - Config: configs/animatediff/animatediff_Lyriel.py In Collection: AnimateDiff Name: animatediff_Lyriel Results: - Dataset: '-' Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/lyriel_v16.safetensors - Config: configs/animatediff/animatediff_RcnzCartoon.py In Collection: AnimateDiff Name: animatediff_RcnzCartoon Results: - Dataset: '-' Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/rcnzCartoon3d_v10.safetensors - Config: configs/animatediff/animatediff_MajicMix.py In Collection: AnimateDiff Name: animatediff_MajicMix Results: - Dataset: '-' Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/majicmixRealistic_v5Preview.safetensors - Config: configs/animatediff/animatediff_RealisticVision.py In Collection: AnimateDiff Name: animatediff_RealisticVision Results: - Dataset: '-' Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/realisticVisionV51_v20Novae.safetensors - Config: configs/animatediff/animatediff_RealisticVision_v2.py In Collection: AnimateDiff Name: animatediff_RealisticVision_v2 Results: - Dataset: WebVid Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/mm_sd_v15_v2.ckpt - Config: configs/animatediff/animatediff_RealisticVision_v1.py In Collection: AnimateDiff Name: animatediff_RealisticVision_v1 Results: - Dataset: WebVid Metrics: {} Task: Text2Video - Dataset: WebVid Metrics: {} Task: Text2Video Weights: https://download.openxlab.org.cn/models/Masbfca/AnimateDiff/weight/mm_fromscratch_10Mval.ckpt ================================================ FILE: configs/aot_gan/README.md ================================================ # AOT-GAN (TVCG'2021) > [AOT-GAN: Aggregated Contextual Transformations for High-Resolution Image Inpainting](https://arxiv.org/abs/2104.01431.pdf) > **Task**: Inpainting ## Abstract State-of-the-art image inpainting approaches can suffer from generating distorted structures and blurry textures in high-resolution images (e.g., 512x512). The challenges mainly drive from (1) image content reasoning from distant contexts, and (2) fine-grained texture synthesis for a large missing region. To overcome these two challenges, we propose an enhanced GAN-based model, named Aggregated COntextual-Transformation GAN (AOT-GAN), for high-resolution image inpainting. Specifically, to enhance context reasoning, we construct the generator of AOT-GAN by stacking multiple layers of a proposed AOT block. The AOT blocks aggregate contextual transformations from various receptive fields, allowing to capture both informative distant image contexts and rich patterns of interest for context reasoning. For improving texture synthesis, we enhance the discriminator of AOT-GAN by training it with a tailored mask-prediction task. Such a training objective forces the discriminator to distinguish the detailed appearances of real and synthesized patches, and in turn, facilitates the generator to synthesize clear textures. Extensive comparisons on Places2, the most challenging benchmark with 1.8 million high-resolution images of 365 complex scenes, show that our model outperforms the state-of-the-art by a significant margin in terms of FID with 38.60% relative improvement. A user study including more than 30 subjects further validates the superiority of AOT-GAN. We further evaluate the proposed AOT-GAN in practical applications, e.g., logo removal, face editing, and object removal. Results show that our model achieves promising completions in the real world. We release code and models in [this https URL](https://github.com/researchmm/AOT-GAN-for-Inpainting).
## Results and models | Model | Dataset | Mask Type | Resolution | Train Iters | Test Set | l1 error | PSNR | SSIM | Training Resources | Download | | :----------------------------------------: | :-----------------: | :----------------: | :--------: | :---------: | :-----------: | :------: | :---: | :---: | :---------------------: | :--------------------------------------------: | | [AOT-GAN](./aot-gan_smpgan_4xb4_places-512x512.py) | Places365-Challenge | free-form (50-60%) | 512x512 | 500k | Places365-val | 7.07 | 19.01 | 0.682 | 4 (GeForce GTX 1080 Ti) | [model](https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.json) | More results for different mask area: | Metric | Mask Area | Paper Results | Reimplemented Results | | :-------------- | :-------- | :------------ | :-------------------- | | L1 (10^-2) | 1 – 10% | 0.55 | 0.54 | | (lower better) | 10 – 20% | 1.19 | 1.47 | | | 20 – 30% | 2.11 | 2.79 | | | 30 – 40% | 3.20 | 4.38 | | | 40 – 50% | 4.51 | 6.28 | | | 50 – 60% | 7.07 | 10.16 | | PSNR | 1 – 10% | 34.79 | inf | | (higher better) | 10 – 20% | 29.49 | 31.22 | | | 20 – 30% | 26.03 | 27.65 | | | 30 – 40% | 23.58 | 25.06 | | | 40 – 50% | 21.65 | 23.01 | | | 50 – 60% | 19.01 | 20.05 | | SSIM | 1 – 10% | 0.976 | 0.982 | | (higher better) | 10 – 20% | 0.940 | 0.951 | | | 20 – 30% | 0.890 | 0.911 | | | 30 – 40% | 0.835 | 0.866 | | | 40 – 50% | 0.773 | 0.815 | | | 50 – 60% | 0.682 | 0.739 | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py # single-gpu train python tools/train.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py # multi-gpu train ./tools/dist_train.sh configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth # single-gpu test python tools/test.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth # multi-gpu test ./tools/dist_test.sh configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{yan2021agg, author = {Zeng, Yanhong and Fu, Jianlong and Chao, Hongyang and Guo, Baining}, title = {Aggregated Contextual Transformations for High-Resolution Image Inpainting}, booktitle = {Arxiv}, pages={-}, year = {2020} } ``` ================================================ FILE: configs/aot_gan/README_zh-CN.md ================================================ # AOT-GAN (TVCG'2021) > [AOT-GAN: Aggregated Contextual Transformations for High-Resolution Image Inpainting](https://arxiv.org/abs/2104.01431.pdf) > **任务**: 图像修复 ## 摘要
## 结果与模型 **Places365-Challenge** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :------------------------------------------------: | :----------------: | :-----: | :--------: | :-----------: | :-----: | :---: | :---: | :---------------------: | :------------------------------------------------------------: | | [AOT-GAN](./aot-gan_smpgan_4xb4_places-512x512.py) | free-form (50-60%) | 512x512 | 500k | Places365-val | 7.07 | 19.01 | 0.682 | 4 (GeForce GTX 1080 Ti) | [模型](https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.json) | | 评估指标 | 掩膜缺损 | 论文结果 | 复现结果 | | :-------------- | :------- | :------- | :------- | | L1 (10^-2) | 1 – 10% | 0.55 | 0.54 | | (lower better) | 10 – 20% | 1.19 | 1.47 | | | 20 – 30% | 2.11 | 2.79 | | | 30 – 40% | 3.20 | 4.38 | | | 40 – 50% | 4.51 | 6.28 | | | 50 – 60% | 7.07 | 10.16 | | PSNR | 1 – 10% | 34.79 | inf | | (higher better) | 10 – 20% | 29.49 | 31.22 | | | 20 – 30% | 26.03 | 27.65 | | | 30 – 40% | 23.58 | 25.06 | | | 40 – 50% | 21.65 | 23.01 | | | 50 – 60% | 19.01 | 20.05 | | SSIM | 1 – 10% | 0.976 | 0.982 | | (higher better) | 10 – 20% | 0.940 | 0.951 | | | 20 – 30% | 0.890 | 0.911 | | | 30 – 40% | 0.835 | 0.866 | | | 40 – 50% | 0.773 | 0.815 | | | 50 – 60% | 0.682 | 0.739 | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py # 单个GPU上训练 python tools/train.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py # 多个GPU上训练 ./tools/dist_train.sh configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth # 单个GPU上测试 python tools/test.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth # 多个GPU上测试 ./tools/dist_test.sh configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
## 引用 ```bibtex @inproceedings{yan2021agg, author = {Zeng, Yanhong and Fu, Jianlong and Chao, Hongyang and Guo, Baining}, title = {Aggregated Contextual Transformations for High-Resolution Image Inpainting}, booktitle = {Arxiv}, pages={-}, year = {2020} } ``` ================================================ FILE: configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py ================================================ _base_ = [ '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] experiment_name = 'aot-gan_smpgan_4xb4_places-512x512' save_dir = './work_dirs' input_shape = (512, 512) # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') model = dict( type='AOTInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='AOTEncoderDecoder', encoder=dict(type='AOTEncoder'), decoder=dict(type='AOTDecoder'), dilation_neck=dict( type='AOTBlockNeck', dilation_rates=(1, 2, 4, 8), num_aotblock=8)), disc=dict( type='SoftMaskPatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, with_spectral_norm=True, ), loss_gan=dict( type='GANLoss', gan_type='smgan', loss_weight=0.01, ), loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg19', layer_weights={ '1': 1., '6': 1., '11': 1., '20': 1., '29': 1., }, layer_weights_style={ '8': 1., '17': 1., '26': 1., '31': 1., }, perceptual_weight=0.1, style_weight=250), loss_out_percep=True, loss_l1_valid=dict( type='L1Loss', loss_weight=1., ), train_cfg=dict( disc_step=1, start_iter=0, )) mask_root = 'data/pconv_mask' train_pipeline = [ dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict( type='LoadMask', mask_mode='set', mask_config=dict( mask_list_file=f'{mask_root}/train_mask_list.txt', prefix=mask_root, io_backend='local', flag='unchanged', color_type='unchanged', file_client_kwargs=dict())), dict( type='RandomResizedCrop', keys=['gt'], crop_size=input_shape, ), dict(type='Flip', keys=['gt', 'mask'], direction='horizontal'), dict( type='Resize', keys=['mask'], scale=input_shape, keep_ratio=False, interpolation='nearest'), dict(type='RandomRotation', keys=['mask'], degrees=(0.0, 45.0)), dict( type='ColorJitter', keys=['gt'], brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = [ dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict( type='LoadMask', mask_mode='set', mask_config=dict( mask_list_file=f'{mask_root}/mask_0.5-0.6_list.txt', prefix=mask_root, io_backend='local', color_type='unchanged', flag='unchanged', file_client_kwargs=dict())), dict( type='RandomResizedCrop', keys=['gt'], crop_size=(512, 512), ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] train_dataloader = dict( batch_size=4, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=500002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.9))), disc=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.9)))) ================================================ FILE: configs/aot_gan/metafile.yml ================================================ Collections: - Name: AOT-GAN Paper: Title: 'AOT-GAN: Aggregated Contextual Transformations for High-Resolution Image Inpainting' URL: https://arxiv.org/abs/2104.01431.pdf README: configs/aot_gan/README.md Task: - inpainting Year: 2021 Models: - Config: configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py In Collection: AOT-GAN Name: aot-gan_smpgan_4xb4_places-512x512 Results: - Dataset: Places365-Challenge Metrics: PSNR: 19.01 SSIM: 0.682 l1 error: 7.07 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/aot_gan/AOT-GAN_512x512_4x12_places_20220509-6641441b.pth ================================================ FILE: configs/basicvsr/README.md ================================================ # BasicVSR (CVPR'2021) > [BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond](https://arxiv.org/abs/2012.02181) > **Task**: Video Super-Resolution ## Abstract Video super-resolution (VSR) approaches tend to have more components than the image counterparts as they need to exploit the additional temporal dimension. Complex designs are not uncommon. In this study, we wish to untangle the knots and reconsider some most essential components for VSR guided by four basic functionalities, i.e., Propagation, Alignment, Aggregation, and Upsampling. By reusing some existing components added with minimal redesigns, we show a succinct pipeline, BasicVSR, that achieves appealing improvements in terms of speed and restoration quality in comparison to many state-of-the-art algorithms. We conduct systematic analysis to explain how such gain can be obtained and discuss the pitfalls. We further show the extensibility of BasicVSR by presenting an information-refill mechanism and a coupled propagation scheme to facilitate information aggregation. The BasicVSR and its extension, IconVSR, can serve as strong baselines for future VSR approaches.
## Results and models Evaluated on RGB channels for REDS4 and Y channel for others. The metrics are `PSNR` / `SSIM` . The pretrained weights of SPyNet can be found [here](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth). | Model | Dataset | PSNR (RGB) | SSIM (RGB) | PSNR (Y) | SSIM (Y) | Training Resources | Download | | :----------------------------------------------------: | :----------------: | :---------: | :--------: | :---------: | :--------: | :----------------------: | :------------------------------------------------------------: | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | REDS4 (BIx4) | **31.4170** | **0.8909** | - | - | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | UDM10 (BDx4) | - | - | 33.4478 | 0.9306 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | Vimeo-90K-T (BIx4) | - | - | 36.2848 | 0.9395 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | Vimeo-90K-T (BDx4) | - | - | 34.4700 | 0.9286 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | Vid4 (BIx4) | - | - | 27.2694 | 0.8318 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | Vid4 (BDx4) | - | - | 24.4541 | 0.7455 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | REDS4 (BIx4) | 30.3128 | 0.8660 | - | - | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409_132702.log.json) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | UDM10 (BDx4) | - | - | 34.5554 | **0.9451** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | Vimeo-90K-T (BIx4) | - | - | **37.2026** | 0.9434 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | Vimeo-90K-T (BDx4) | - | - | 34.8097 | 0.9316 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | Vid4 (BIx4) | - | - | **27.2755** | **0.8248** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | Vid4 (BDx4) | - | - | 25.0517 | 0.7636 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | REDS4 (BIx4) | 29.0376 | 0.8481 | - | - | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | UDM10 (BDx4) | - | - | **39.9953** | **0.9695** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | Vimeo-90K-T (BIx4) | - | - | 34.6427 | 0.9335 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | Vimeo-90K-T (BDx4) | - | - | **37.5501** | **0.9499** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | Vid4 (BIx4) | - | - | 26.2708 | 0.8022 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | Vid4 (BDx4) | - | - | **27.9791** | **0.8556** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/basicvsr/basicvsr_2xb4_reds4.py # single-gpu train python tools/train.py configs/basicvsr/basicvsr_2xb4_reds4.py # multi-gpu train ./tools/dist_train.sh configs/basicvsr/basicvsr_2xb4_reds4.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth # single-gpu test python tools/test.py configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth # multi-gpu test ./tools/dist_test.sh configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{chan2021basicvsr, author = {Chan, Kelvin CK and Wang, Xintao and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ``` ================================================ FILE: configs/basicvsr/README_zh-CN.md ================================================ # BasicVSR (CVPR'2021) > **任务**: 视频超分辨率
BasicVSR (CVPR'2021) ```bibtex @InProceedings{chan2021basicvsr, author = {Chan, Kelvin CK and Wang, Xintao and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ```

对于 REDS4,我们对 RGB 通道进行评估。对于其他数据集,我们对 Y 通道进行评估。我们使用 `PSNR` 和 `SSIM` 作为指标。 SPyNet 的 预训练权重在[这里](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth)。 | 算法 | REDS4 (BIx4)
PSNR/SSIM (RGB) | Vimeo-90K-T (BIx4)
PSNR/SSIM (Y) | Vid4 (BIx4)
PSNR/SSIM (Y) | UDM10 (BDx4)
PSNR/SSIM (Y) | Vimeo-90K-T (BDx4)
PSNR/SSIM (Y) | Vid4 (BDx4)
PSNR/SSIM (Y) | GPU 信息 | 下载 | | :-: | :-----------------------------: | :---------------------------------: | :--------------------------: | :---------------------------: | :---------------------------------: | :--------------------------: | :-----: | :--: | | [basicvsr_reds4](./basicvsr_2xb4_reds4.py) | **31.4170/0.8909** | 36.2848/0.9395 | 27.2694/0.8318 | 33.4478/0.9306 | 34.4700/0.9286 | 24.4541/0.7455 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20210409_092646.log.json) | | [basicvsr_vimeo90k_bi](./basicvsr_2xb4_vimeo90k-bi.py) | 30.3128/0.8660 | **37.2026/0.9451** | **27.2755/0.8248** | 34.5554/0.9434 | 34.8097/0.9316 | 25.0517/0.7636 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409_132702.log.json) | | [basicvsr_vimeo90k_bd](./basicvsr_2xb4_vimeo90k-bd.py) | 29.0376/0.8481 | 34.6427/0.9335 | 26.2708/0.8022 | **39.9953/0.9695** | **37.5501/0.9499** | **27.9791/0.8556** | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409_132740.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/basicvsr/basicvsr_2xb4_reds4.py # 单个GPU上训练 python tools/train.py configs/basicvsr/basicvsr_2xb4_reds4.py # 多个GPU上训练 ./tools/dist_train.sh configs/basicvsr/basicvsr_2xb4_reds4.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth # 单个GPU上测试 python tools/test.py configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth # 多个GPU上测试 ./tools/dist_test.sh configs/basicvsr/basicvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/basicvsr/basicvsr_2xb4_reds4.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/basicvsr_test_config.py' ] experiment_name = 'basicvsr_2xb4_reds4' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 4 # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRNet', mid_channels=64, num_blocks=30, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=256), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data/REDS' train_dataloader = dict( num_workers=6, batch_size=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_train.txt', depth=1, num_input_frames=15, pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_val.txt', depth=1, num_input_frames=100, fixed_seq_len=100, pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=300_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.99)), paramwise_cfg=dict(custom_keys={'spynet': dict(lr_mult=0.125)})) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[300000], restart_weights=[1], eta_min=1e-7) find_unused_parameters = True ================================================ FILE: configs/basicvsr/basicvsr_2xb4_vimeo90k-bd.py ================================================ _base_ = './basicvsr_2xb4_reds4.py' scale = 4 experiment_name = 'basicvsr_2xb4_vimeo90k-bd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' train_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=256), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='MirrorSequence', keys=['img', 'gt']), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data' file_list = [ 'im1.png', 'im2.png', 'im3.png', 'im4.png', 'im5.png', 'im6.png', 'im7.png' ] train_dataloader = dict( num_workers=6, batch_size=4, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vimeo90k_seq', task_name='vsr'), data_root=f'{data_root}/vimeo90k', data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vimeo90K_train_GT.txt', depth=2, num_input_frames=7, fixed_seq_len=7, load_frames_list=dict(img=file_list, gt=file_list), pipeline=train_pipeline)) val_dataloader = dict( _delete_=True, num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=f'{data_root}/Vid4', data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=1, pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', convert_to='Y'), dict(type='SSIM', convert_to='Y'), ]) find_unused_parameters = True ================================================ FILE: configs/basicvsr/basicvsr_2xb4_vimeo90k-bi.py ================================================ _base_ = './basicvsr_2xb4_vimeo90k-bd.py' experiment_name = 'basicvsr_2xb4_vimeo90k-bi' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' train_dataloader = dict( dataset=dict( type='BasicFramesDataset', data_prefix=dict(img='BIx4', gt='GT'))) val_dataloader = dict( dataset=dict( type='BasicFramesDataset', data_prefix=dict(img='BIx4', gt='GT'))) find_unused_parameters = True ================================================ FILE: configs/basicvsr/metafile.yml ================================================ Collections: - Name: BasicVSR Paper: Title: 'BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond' URL: https://arxiv.org/abs/2012.02181 README: configs/basicvsr/README.md Task: - video super-resolution Year: 2021 Models: - Config: configs/basicvsr/basicvsr_2xb4_reds4.py In Collection: BasicVSR Name: basicvsr_2xb4_reds4 Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 31.417 SSIM (RGB): 0.8909 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 33.4478 SSIM (Y): 0.9306 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 36.2848 SSIM (Y): 0.9395 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 34.47 SSIM (Y): 0.9286 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.2694 SSIM (Y): 0.8318 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 24.4541 SSIM (Y): 0.7455 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_reds4_20120409-0e599677.pth - Config: configs/basicvsr/basicvsr_2xb4_vimeo90k-bi.py In Collection: BasicVSR Name: basicvsr_2xb4_vimeo90k-bi Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 30.3128 SSIM (RGB): 0.866 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 34.5554 SSIM (Y): 0.9451 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 37.2026 SSIM (Y): 0.9434 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 34.8097 SSIM (Y): 0.9316 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.2755 SSIM (Y): 0.8248 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 25.0517 SSIM (Y): 0.7636 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bi_20210409-d2d8f760.pth - Config: configs/basicvsr/basicvsr_2xb4_vimeo90k-bd.py In Collection: BasicVSR Name: basicvsr_2xb4_vimeo90k-bd Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 29.0376 SSIM (RGB): 0.8481 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 39.9953 SSIM (Y): 0.9695 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 34.6427 SSIM (Y): 0.9335 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 37.5501 SSIM (Y): 0.9499 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 26.2708 SSIM (Y): 0.8022 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 27.9791 SSIM (Y): 0.8556 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr/basicvsr_vimeo90k_bd_20210409-0154dd64.pth ================================================ FILE: configs/basicvsr_pp/README.md ================================================ # BasicVSR++ (CVPR'2022) > [BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment](https://arxiv.org/abs/2104.13371) > **Task**: Video Super-Resolution ## Abstract A recurrent structure is a popular framework choice for the task of video super-resolution. The state-of-the-art method BasicVSR adopts bidirectional propagation with feature alignment to effectively exploit information from the entire input video. In this study, we redesign BasicVSR by proposing second-order grid propagation and flow-guided deformable alignment. We show that by empowering the recurrent framework with the enhanced propagation and alignment, one can exploit spatiotemporal information across misaligned video frames more effectively. The new components lead to an improved performance under a similar computational constraint. In particular, our model BasicVSR++ surpasses BasicVSR by 0.82 dB in PSNR with similar number of parameters. In addition to video super-resolution, BasicVSR++ generalizes well to other video restoration tasks such as compressed video enhancement. In NTIRE 2021, BasicVSR++ obtains three champions and one runner-up in the Video Super-Resolution and Compressed Video Enhancement Challenges. Codes and models will be released to MMagic.
## Results and models The pretrained weights of SPyNet can be found [here](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth). | Model | Dataset | PSNR (RGB) | SSIM (RGB) | PSNR (Y) | SSIM (Y) | Training Resources | Download | | :------------------------------------------------------: | :----------------: | :---------: | :--------: | :---------: | :--------: | :----------------------: | :----------------------------------------------------------: | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | REDS4 (BIx4) | **32.3855** | **0.9069** | - | - | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | UDM10 (BDx4) | - | - | 34.6868 | 0.9417 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | Vid4 (BIx4) | - | - | 27.7674 | 0.8444 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | Vid4 (BDx4) | - | - | 24.6209 | 0.7540 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | Vimeo-90K-T (BIx4) | - | - | 36.4445 | 0.9411 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | Vimeo-90K-T (BDx4) | - | - | 34.0372 | 0.9244 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | REDS4 (BIx4) | 31.0126 | 0.8804 | - | - | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | UDM10 (BDx4) | - | - | 33.1211 | 0.9270 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | Vid4 (BIx4) | - | - | **27.7882** | **0.8401** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | Vid4 (BDx4) | - | - | 23.6086 | 0.7033 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | Vimeo-90K-T (BIx4) | - | - | **37.7864** | **0.9500** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | Vimeo-90K-T (BDx4) | - | - | 33.8972 | 0.9195 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | REDS4 (BIx4) | 29.2041 | 0.8528 | - | - | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | UDM10 (BDx4) | - | - | **40.7216** | **0.9722** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | Vid4 (BIx4) | - | - | 26.4377 | 0.8074 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | Vid4 (BDx4) | - | - | **29.0400** | **0.8753** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | Vimeo-90K-T (BIx4) | - | - | 34.7248 | 0.9351 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | Vimeo-90K-T (BDx4) | - | - | **38.2054** | **0.9550** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) | **NTIRE 2021 checkpoints** Note that the following models are finetuned from smaller models. The training schemes of these models will be released when MMagic reaches 5k stars. We provide the pre-trained models here. | Model | Dataset | Download | | :------------------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------------------: | | [basicvsr-pp_c128n25_600k_ntire-vsr](./basicvsr-pp_c128n25_600k_ntire-vsr.py) | NTIRE 2021 Video Super-Resolution - Track 1 | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_vsr_20210311-1ff35292.pth) | | [basicvsr-pp_c128n25_600k_ntire-decompress-track1](./basicvsr-pp_c128n25_600k_ntire-decompress-track1.py) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 1 | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track1_20210223-7b2eba02.pth) | | [basicvsr-pp_c128n25_600k_ntire-decompress-track2](./basicvsr-pp_c128n25_600k_ntire-decompress-track2.py) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 2 | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track2_20210314-eeae05e6.pth) | | [basicvsr-pp_c128n25_600k_ntire-decompress-track3](./basicvsr-pp_c128n25_600k_ntire-decompress-track3.py) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 3 | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track3_20210304-6daf4a40.pth) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py # single-gpu train python tools/train.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py # multi-gpu train ./tools/dist_train.sh configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth # single-gpu test python tools/test.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth # multi-gpu test ./tools/dist_test.sh configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{chan2022basicvsrplusplus, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2022} } ``` ================================================ FILE: configs/basicvsr_pp/README_zh-CN.md ================================================ # BasicVSR++ (CVPR'2022) > **任务**: 视频超分辨率
BasicVSR++ (CVPR'2022) ```bibtex @InProceedings{chan2022basicvsrplusplus, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2022} } ```
SPyNet 的 预训练权重在[这里](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth)。 | 算法 | REDS4 (BIx4) PSNR/SSIM (RGB) | Vimeo-90K-T (BIx4) PSNR/SSIM (Y) | Vid4 (BIx4) PSNR/SSIM (Y) | UDM10 (BDx4) PSNR/SSIM (Y) | Vimeo-90K-T (BDx4) PSNR/SSIM (Y) | Vid4 (BDx4) PSNR/SSIM (Y) | GPU 信息 | Download | | :-----: | :--------------------------: | :------------------------------: | :-----------------------: | :------------------------: | :------------------------------: | :-----------------------: | :---------: | :------------: | | [basicvsr_plusplus_c64n7_8x1_600k_reds4](./basicvsr-pp_c64n7_8xb1-600k_reds4.py) | **32.3855/0.9069** | 36.4445/0.9411 | 27.7674/0.8444 | 34.6868/0.9417 | 34.0372/0.9244 | 24.6209/0.7540 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217_113115.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bi](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py) | 31.0126/0.8804 | **37.7864/0.9500** | **27.7882/0.8401** | 33.1211/0.9270 | 33.8972/0.9195 | 23.6086/0.7033 | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305_141254.log.json) | | [basicvsr_plusplus_c64n7_4x2_300k_vimeo90k_bd](./basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py) | 29.2041/0.8528 | 34.7248/0.9351 | 26.4377/0.8074 | **40.7216/0.9722** | **38.2054/0.9550** | **29.0400/0.8753** | 4 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305_140921.log.json) |
NTIRE 2021 模型权重文件 请注意,以下模型是从较小的模型中微调而来的。 这些模型的训练方案将在 MMagic 达到 5k star 时发布。 我们在这里提供预训练的模型。 | 算法 | 模型 | 赛道 | | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------ | | [basicvsr-pp_c128n25_600k_ntire-vsr](./basicvsr-pp_c128n25_600k_ntire-vsr.py) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_vsr_20210311-1ff35292.pth) | NTIRE 2021 Video Super-Resolution | | [basicvsr-pp_c128n25_600k_ntire-decompress-track1](./basicvsr-pp_c128n25_600k_ntire-decompress-track1.py) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track1_20210223-7b2eba02.pth) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 1 | | [basicvsr-pp_c128n25_600k_ntire-decompress-track2](./basicvsr-pp_c128n25_600k_ntire-decompress-track2.py) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track2_20210314-eeae05e6.pth) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 2 | | [basicvsr-pp_c128n25_600k_ntire-decompress-track3](./basicvsr-pp_c128n25_600k_ntire-decompress-track3.py) | [model](https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track3_20210304-6daf4a40.pth) | NTIRE 2021 Quality Enhancement of Compressed Video - Track 3 |
``` ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py # 单个GPU上训练 python tools/train.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py # 多个GPU上训练 ./tools/dist_train.sh configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth # 单个GPU上测试 python tools/test.py configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth # 多个GPU上测试 ./tools/dist_test.sh configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track1.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'basicvsr-pp_c128n25_600k_ntire-decompress-track1' work_dir = f'./work_dirs/{experiment_name}' # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRPlusPlusNet', mid_channels=128, num_blocks=25, is_low_res_input=False, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', cpu_cache_length=100), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), ensemble=dict(type='SpatialTemporalEnsemble', is_temporal_ensemble=False), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) test_pipeline = [ dict( type='GenerateSegmentIndices', interval_list=[1], start_idx=1, filename_tmpl='{:03d}.png'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] test_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='ntire21_track1', task_name='vsr'), data_root='data/NTIRE21_decompression_track1', data_prefix=dict(img='LQ', gt='GT'), pipeline=test_pipeline)) test_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) test_cfg = dict(type='MultiTestLoop') ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track2.py ================================================ _base_ = './basicvsr-pp_c128n25_600k_ntire-decompress-track1.py' experiment_name = 'basicvsr-pp_c128n25_600k_ntire-decompress-track2' work_dir = f'./work_dirs/{experiment_name}' test_dataloader = dict( dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='ntire21_track2', task_name='vsr'), data_root='data/NTIRE21_decompression_track2')) ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track3.py ================================================ _base_ = './basicvsr-pp_c128n25_600k_ntire-decompress-track1.py' experiment_name = 'basicvsr-pp_c128n25_600k_ntire-decompress-track3' work_dir = f'./work_dirs/{experiment_name}' test_dataloader = dict( dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='ntire21_track3', task_name='vsr'), data_root='data/NTIRE21_decompression_track3')) ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-vsr.py ================================================ experiment_name = 'basicvsr-pp_c128n25_600k_ntire-vsr' # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRPlusPlusNet', mid_channels=128, num_blocks=25, is_low_res_input=True, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', cpu_cache_length=100), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), ensemble=dict(type='SpatialTemporalEnsemble', is_temporal_ensemble=False), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) test_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='MirrorSequence', keys=['img', 'gt']), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='MirrorSequence', keys=['img']), dict(type='PackInputs') ] test_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds_official', task_name='vsr'), data_root='data/REDS', data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_official_val.txt', depth=1, num_input_frames=100, fixed_seq_len=100, pipeline=test_pipeline)) ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_vimeo90k-bd.py' experiment_name = 'basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # load_from = 'https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth' # noqa # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRPlusPlusNet', mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=-1), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_dataloader = dict(num_workers=6, batch_size=2) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)), paramwise_cfg=dict(custom_keys={'spynet': dict(lr_mult=0.25)})) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) find_unused_parameters = True ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_vimeo90k-bi.py' experiment_name = 'basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # load_from = 'https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth' # noqa # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRPlusPlusNet', mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=-1), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_dataloader = dict(num_workers=6, batch_size=2) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)), paramwise_cfg=dict(custom_keys={'spynet': dict(lr_mult=0.25)})) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) find_unused_parameters = True ================================================ FILE: configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_reds4.py' experiment_name = 'basicvsr-pp_c64n7_8xb1-600k_reds4' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( type='BasicVSR', generator=dict( type='BasicVSRPlusPlusNet', mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_dataloader = dict( num_workers=6, batch_size=1, dataset=dict(num_input_frames=30)) train_cfg = dict( type='IterBasedTrainLoop', max_iters=600_000, val_interval=5000) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)), paramwise_cfg=dict(custom_keys={'spynet': dict(lr_mult=0.25)})) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[600000], restart_weights=[1], eta_min=1e-7) ================================================ FILE: configs/basicvsr_pp/metafile.yml ================================================ Collections: - Name: BasicVSR++ Paper: Title: 'BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment' URL: https://arxiv.org/abs/2104.13371 README: configs/basicvsr_pp/README.md Task: - video super-resolution Year: 2022 Models: - Config: configs/basicvsr_pp/basicvsr-pp_c64n7_8xb1-600k_reds4.py In Collection: BasicVSR++ Name: basicvsr-pp_c64n7_8xb1-600k_reds4 Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 32.3855 SSIM (RGB): 0.9069 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 34.6868 SSIM (Y): 0.9417 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.7674 SSIM (Y): 0.8444 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 24.6209 SSIM (Y): 0.754 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 36.4445 SSIM (Y): 0.9411 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 34.0372 SSIM (Y): 0.9244 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_600k_reds4_20210217-db622b2f.pth - Config: configs/basicvsr_pp/basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi.py In Collection: BasicVSR++ Name: basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bi Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 31.0126 SSIM (RGB): 0.8804 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 33.1211 SSIM (Y): 0.927 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.7882 SSIM (Y): 0.8401 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 23.6086 SSIM (Y): 0.7033 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 37.7864 SSIM (Y): 0.95 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 33.8972 SSIM (Y): 0.9195 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bi_20210305-4ef437e2.pth - Config: configs/basicvsr_pp/basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd.py In Collection: BasicVSR++ Name: basicvsr-pp_c64n7_4xb2-300k_vimeo90k-bd Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 29.2041 SSIM (RGB): 0.8528 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 40.7216 SSIM (Y): 0.9722 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 26.4377 SSIM (Y): 0.8074 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 29.04 SSIM (Y): 0.8753 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 34.7248 SSIM (Y): 0.9351 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 38.2054 SSIM (Y): 0.955 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c64n7_8x1_300k_vimeo90k_bd_20210305-ab315ab1.pth - Config: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-vsr.py In Collection: BasicVSR++ Name: basicvsr-pp_c128n25_600k_ntire-vsr Results: - Dataset: NTIRE2021VideoSuper-Resolution-Track1 Metrics: {} Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_vsr_20210311-1ff35292.pth - Config: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track1.py In Collection: BasicVSR++ Name: basicvsr-pp_c128n25_600k_ntire-decompress-track1 Results: - Dataset: NTIRE2021QualityEnhancementofCompressedVideo-Track1 Metrics: {} Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track1_20210223-7b2eba02.pth - Config: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track2.py In Collection: BasicVSR++ Name: basicvsr-pp_c128n25_600k_ntire-decompress-track2 Results: - Dataset: NTIRE2021QualityEnhancementofCompressedVideo-Track2 Metrics: {} Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track2_20210314-eeae05e6.pth - Config: configs/basicvsr_pp/basicvsr-pp_c128n25_600k_ntire-decompress-track3.py In Collection: BasicVSR++ Name: basicvsr-pp_c128n25_600k_ntire-decompress-track3 Results: - Dataset: NTIRE2021QualityEnhancementofCompressedVideo-Track3 Metrics: {} Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/basicvsr_plusplus/basicvsr_plusplus_c128n25_ntire_decompress_track3_20210304-6daf4a40.pth ================================================ FILE: configs/biggan/README.md ================================================ # BigGAN (ICLR'2019) > [Large Scale GAN Training for High Fidelity Natural Image Synthesis](https://openreview.net/forum?id=B1xsqj09Fm) > **Task**: Conditional GANs ## Abstract Despite recent progress in generative image modeling, successfully generating high-resolution, diverse samples from complex datasets such as ImageNet remains an elusive goal. To this end, we train Generative Adversarial Networks at the largest scale yet attempted, and study the instabilities specific to such scale. We find that applying orthogonal regularization to the generator renders it amenable to a simple "truncation trick," allowing fine control over the trade-off between sample fidelity and variety by reducing the variance of the Generator's input. Our modifications lead to models which set the new state of the art in class-conditional image synthesis. When trained on ImageNet at 128x128 resolution, our models (BigGANs) achieve an Inception Score (IS) of 166.5 and Frechet Inception Distance (FID) of 7.4, improving over the previous best IS of 52.52 and FID of 18.6.
## Introduction The `BigGAN/BigGAN-Deep` is a conditional generation model that can generate both high-resolution and high-quality images by scaling up the batch size and the number of model parameters. We have finished training `BigGAN` in `Cifar10` (32x32) and are aligning training performance in `ImageNet1k` (128x128). Some sampled results are shown below for your reference.
Results from our BigGAN trained in CIFAR10
Results from our BigGAN trained in ImageNet
Evaluation of our trained BigGAN. | Model | Dataset | FID (Iter) | IS (Iter) | Download | | :-------------------------------------------------------------------------: | :--------: | :---------------: | :-----------------: | :-----------------------------------------------------------------------------: | | [BigGAN 32x32](./biggan_2xb25-500kiters_cifar10-32x32.py) | CIFAR10 | 9.78(390000) | 8.70(390000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_cifar10_32x32_b25x2_500k_20210728_110906-08b61a44.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_cifar10_32_b25x2_500k_20210706_171051.log.json) | | [BigGAN 128x128 Best FID](./biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py) | ImageNet1k | **8.69**(1232000) | 101.15(1232000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_1500k_20211111_122548-5315b13d.log.json) | | [BigGAN 128x128 Best IS](./biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py) | ImageNet1k | 13.51(1328000) | **129.07**(1328000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_is_iter_1328000_20211111_122911-28c688bc.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_1500k_20211111_122548-5315b13d.log.json) | ### Note on reproducibility `BigGAN 128x128` model is trained with V100 GPUs and CUDA 10.1 and can hardly reproduce the result with A100 and CUDA 11.3. If you have any idea about the reproducibility, please feel free to contact with us. ## Converted weights Since we haven't finished training our models, we provide you with several pre-trained weights which have been evaluated. Here, we refer to [BigGAN-PyTorch](https://github.com/ajbrock/BigGAN-PyTorch) and [pytorch-pretrained-BigGAN](https://github.com/huggingface/pytorch-pretrained-BigGAN). Evaluation results and download links are provided below. | Model | Dataset | FID | IS | Download | Original Download link | | :--------------------------------------------------: | :--------: | :-----: | :-----: | :-----------------------------------------------------: | :-------------------------------------------------------------------: | | [BigGAN 128x128](./biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py) | ImageNet1k | 10.1414 | 96.728 | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_cvt_BigGAN-PyTorch_rgb_20210730_125223-3e353fef.pth) | [link](https://drive.google.com/open?id=1nAle7FCVFZdix2--ks0r5JBkFnKw8ctW) | | [BigGAN-Deep 128x128](./biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py) | ImageNet1k | 5.9471 | 107.161 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_128x128_cvt_hugging-face_rgb_20210728_111659-099e96f9.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-128-pytorch_model.bin) | | [BigGAN-Deep 256x256](./biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py) | ImageNet1k | 11.3151 | 135.107 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_256x256_cvt_hugging-face_rgb_20210728_111735-28651569.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-256-pytorch_model.bin) | | [BigGAN-Deep 512x512](./biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py) | ImageNet1k | 16.8728 | 124.368 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_512x512_cvt_hugging-face_rgb_20210728_112346-a42585f2.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-512-pytorch_model.bin) | Sampling results are shown below.
Results from our BigGAN-Deep with Pre-trained weights in ImageNet 128x128 with truncation factor 0.4
Results from our BigGAN-Deep with Pre-trained weights in ImageNet 256x256 with truncation factor 0.4
Results from our BigGAN-Deep with Pre-trained weights in ImageNet 512x512 truncation factor 0.4
Sampling with truncation trick above can be performed by command below. ```bash python demo/conditional_demo.py CONFIG_PATH CKPT_PATH --sample-cfg truncation=0.4 # set truncation value as you want ``` For converted weights, we provide model configs under `configs/_base_/models` listed as follows: ```bash # biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py # biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py # biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py # biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py ``` ## Interpolation To perform image Interpolation on BigGAN(or other conditional models), run ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH ```
Image interpolating Results of our BigGAN-Deep
To perform image Interpolation on BigGAN with fixed noise, run ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH --fix-z ```
Image interpolating Results of our BigGAN-Deep with fixed noise
To perform image Interpolation on BigGAN with fixed label, run ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH --fix-y ```
Image interpolating Results of our BigGAN-Deep with fixed label
## Citation ```latex @inproceedings{ brock2018large, title={Large Scale {GAN} Training for High Fidelity Natural Image Synthesis}, author={Andrew Brock and Jeff Donahue and Karen Simonyan}, booktitle={International Conference on Learning Representations}, year={2019}, url={https://openreview.net/forum?id=B1xsqj09Fm}, } ``` ================================================ FILE: configs/biggan/README_zh-CN.md ================================================ # BigGAN (ICLR'2019) > [Large Scale GAN Training for High Fidelity Natural Image Synthesis](https://openreview.net/forum?id=B1xsqj09Fm) > **任务**: 条件生成对抗网络 ## Abstract Despite recent progress in generative image modeling, successfully generating high-resolution, diverse samples from complex datasets such as ImageNet remains an elusive goal. To this end, we train Generative Adversarial Networks at the largest scale yet attempted, and study the instabilities specific to such scale. We find that applying orthogonal regularization to the generator renders it amenable to a simple "truncation trick," allowing fine control over the trade-off between sample fidelity and variety by reducing the variance of the Generator's input. Our modifications lead to models which set the new state of the art in class-conditional image synthesis. When trained on ImageNet at 128x128 resolution, our models (BigGANs) achieve an Inception Score (IS) of 166.5 and Frechet Inception Distance (FID) of 7.4, improving over the previous best IS of 52.52 and FID of 18.6.
## Introduction `BigGAN/BigGAN-Deep`是一个条件生成模型,通过扩大批次大小和模型参数的数量,可以生成高分辨率和高质量的图像。 我们已经在`Cifar10`(32x32)中完成了`BigGAN`的训练,并在`ImageNet1k`(128x128)上对齐了训练性能。下面是一些抽样的结果,供你参考。
我们在 CIFAR10 上训练的 BigGAN 的结果
我们在 ImageNet 上训练的 BigGAN 的结果
对我们训练的 BigGAN 进行评估. | 算法 | 数据集 | FID (Iter) | IS (Iter) | 下载 | | :---------------------------------------------------------------------------: | :--------: | :---------------: | :-----------------: | :---------------------------------------------------------------------------: | | [BigGAN 32x32](./biggan_2xb25-500kiters_cifar10-32x32.py) | CIFAR10 | 9.78(390000) | 8.70(390000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_cifar10_32x32_b25x2_500k_20210728_110906-08b61a44.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_cifar10_32_b25x2_500k_20210706_171051.log.json) | | [BigGAN 128x128 Best FID](./biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py) | ImageNet1k | **8.69**(1232000) | 101.15(1232000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_1500k_20211111_122548-5315b13d.log.json) | | [BigGAN 128x128 Best IS](./biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py) | ImageNet1k | 13.51(1328000) | **129.07**(1328000) | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_is_iter_1328000_20211111_122911-28c688bc.pth)\|[log](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_1500k_20211111_122548-5315b13d.log.json) | ### 关于可复现性的说明 `BigGAN 128x128`模型是用 V100 GPU 和 CUDA 10.1 训练的,用 A100 和 CUDA 11.3 很难再现结果。如果你对复现有任何想法,请随时与我们联系。 ## 转换后的权重 由于我们还没有完成对模型的训练,我们为您提供了几个已经评估过的预训练权重。这里,我们指的是[BigGAN-PyTorch](https://github.com/ajbrock/BigGAN-PyTorch)和[pytorch-pretrained-BigGAN](https://github.com/huggingface/pytorch-pretrained-BigGAN)。 下面提供了评估结果和下载链接 | 模型 | 数据集 | FID | IS | 下载 | 原始权重下载链接 | | :------------------------------------------------------: | :--------: | :-----: | :-----: | :-------------------------------------------------------: | :-------------------------------------------------------------: | | [BigGAN 128x128](./biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py) | ImageNet1k | 10.1414 | 96.728 | [model](https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_cvt_BigGAN-PyTorch_rgb_20210730_125223-3e353fef.pth) | [link](https://drive.google.com/open?id=1nAle7FCVFZdix2--ks0r5JBkFnKw8ctW) | | [BigGAN-Deep 128x128](./biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py) | ImageNet1k | 5.9471 | 107.161 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_128x128_cvt_hugging-face_rgb_20210728_111659-099e96f9.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-128-pytorch_model.bin) | | [BigGAN-Deep 256x256](./biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py) | ImageNet1k | 11.3151 | 135.107 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_256x256_cvt_hugging-face_rgb_20210728_111735-28651569.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-256-pytorch_model.bin) | | [BigGAN-Deep 512x512](./biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py) | ImageNet1k | 16.8728 | 124.368 | [model](https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_512x512_cvt_hugging-face_rgb_20210728_112346-a42585f2.pth) | [link](https://s3.amazonaws.com/models.huggingface.co/biggan/biggan-deep-512-pytorch_model.bin) | 采样结果如下。
BigGAN-Deep 在 ImageNet 128x128 中使用预训练权重的结果,截断因子为 0.4
BigGAN-Deep 在 ImageNet 256x256 中使用预训练权重的结果,截断因子为 0.4
BigGAN-Deep 在 ImageNet 512x512 中使用预训练权重的结果,截断因子为 0.4
上面的截断取样技巧可以通过下面的命令进行。 ```bash python demo/conditional_demo.py CONFIG_PATH CKPT_PATH --sample-cfg truncation=0.4 # set truncation value as you want ``` 对于转换后的权重,我们在`configs/_base_/models`下提供模型配置,列举如下。 ```bash # biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py # biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py # biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py # biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py ``` ## Interpolation 要在 BigGAN(或其他条件模型)上执行图像插值,请运行 ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH ```
我们的 BigGAN-Deep 的图像插值结果
要在 BigGAN 上进行具有固定噪声的图像插值,请运行 ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH --fix-z ```
我们的 BigGAN-Deep 在固定噪音下的图像插值结果
要在 BigGAN 上执行具有固定标签的图像插值,请运行 ```bash python apps/conditional_interpolate.py CONFIG_PATH CKPT_PATH --samples-path SAMPLES_PATH --fix-y ```
我们的 BigGAN-Deep 带有固定标签的图像插值结果
## Citation ```latex @inproceedings{ brock2018large, title={Large Scale {GAN} Training for High Fidelity Natural Image Synthesis}, author={Andrew Brock and Jeff Donahue and Karen Simonyan}, booktitle={International Conference on Learning Representations}, year={2019}, url={https://openreview.net/forum?id=B1xsqj09Fm}, } ``` ================================================ FILE: configs/biggan/biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/datasets/imagenet_noaug_128.py', '../_base_/gen_default_runtime.py', ] ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), ema_config=ema_config, generator=dict( type='BigGANDeepGenerator', output_scale=128, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDeepDiscriminator', input_scale=128, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py ================================================ _base_ = [ '../_base_/datasets/imagenet_noaug_128.py', '../_base_/gen_default_runtime.py', ] # setting image size to 256x256 _base_.train_dataloader.dataset.pipeline[2].scale = (256, 256) _base_.test_dataloader.dataset.pipeline[2].scale = (256, 256) _base_.val_dataloader.dataset.pipeline[2].scale = (256, 256) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), ema_config=ema_config, generator=dict( type='BigGANDeepGenerator', output_scale=256, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDeepDiscriminator', input_scale=256, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py ================================================ _base_ = [ '../_base_/datasets/imagenet_noaug_128.py', '../_base_/gen_default_runtime.py', ] # setting image size to 512x512 _base_.train_dataloader.dataset.pipeline[2].scale = (512, 512) _base_.test_dataloader.dataset.pipeline[2].scale = (512, 512) _base_.val_dataloader.dataset.pipeline[2].scale = (512, 512) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), ema_config=ema_config, generator=dict( type='BigGANDeepGenerator', output_scale=512, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDeepDiscriminator', input_scale=512, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py ================================================ _base_ = [ '../_base_/datasets/cifar10_noaug.py', '../_base_/gen_default_runtime.py', ] # define model ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, start_iter=1000) model = dict( type='BigGAN', num_classes=10, data_preprocessor=dict( type='DataPreprocessor', output_channel_order='BGR'), generator=dict( type='BigGANGenerator', output_scale=32, noise_size=128, num_classes=10, base_channels=64, with_shared_embedding=False, sn_eps=1e-8, sn_style='torch', split_noise=False, auto_sync_bn=False, init_cfg=dict(type='N02')), discriminator=dict( type='BigGANDiscriminator', input_scale=32, num_classes=10, base_channels=64, sn_eps=1e-8, sn_style='torch', with_spectral_norm=True, init_cfg=dict(type='N02')), generator_steps=1, discriminator_steps=4, ema_config=ema_config) # define dataset train_dataloader = dict(batch_size=25, num_workers=8) val_dataloader = dict(batch_size=25, num_workers=8) test_dataloader = dict(batch_size=25, num_workers=8) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), ] optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999)))) train_cfg = dict(max_iters=500000) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/models/biggan/base_biggan_128x128.py', '../_base_/datasets/imagenet_noaug_128.py', '../_base_/gen_default_runtime.py', ] # define model ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict(ema_config=ema_config) train_cfg = dict(max_iters=1500000) # define dataset train_dataloader = dict( batch_size=32, num_workers=8, dataset=dict(data_root='data/imagenet')) # define optimizer optim_wrapper = dict( generator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=10000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), ] metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/datasets/imagenet_noaug_128.py', '../_base_/gen_default_runtime.py', ] ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), ema_config=ema_config, generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/biggan/metafile.yml ================================================ Collections: - Name: BigGAN Paper: Title: Large Scale GAN Training for High Fidelity Natural Image Synthesis URL: https://openreview.net/forum?id=B1xsqj09Fm README: configs/biggan/README.md Task: - conditional gans Year: 2019 Models: - Config: configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py In Collection: BigGAN Name: biggan_2xb25-500kiters_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID (Iter): 9.78 IS (Iter): 8.7 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan_cifar10_32x32_b25x2_500k_20210728_110906-08b61a44.pth - Config: configs/biggan/biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py In Collection: BigGAN Name: biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128 Results: - Dataset: ImageNet1k Metrics: FID (Iter): 8.69 IS (Iter): 101.15 Task: Conditional GANs - Dataset: ImageNet1k Metrics: FID (Iter): 13.51 IS (Iter): 129.07 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_is_iter_1328000_20211111_122911-28c688bc.pth - Config: configs/biggan/biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py In Collection: BigGAN Name: biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128 Results: - Dataset: ImageNet1k Metrics: FID: 10.1414 IS: 96.728 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_cvt_BigGAN-PyTorch_rgb_20210730_125223-3e353fef.pth - Config: configs/biggan/biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py In Collection: BigGAN Name: biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128 Results: - Dataset: ImageNet1k Metrics: FID: 5.9471 IS: 107.161 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_128x128_cvt_hugging-face_rgb_20210728_111659-099e96f9.pth - Config: configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py In Collection: BigGAN Name: biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256 Results: - Dataset: ImageNet1k Metrics: FID: 11.3151 IS: 135.107 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_256x256_cvt_hugging-face_rgb_20210728_111735-28651569.pth - Config: configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py In Collection: BigGAN Name: biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512 Results: - Dataset: ImageNet1k Metrics: FID: 16.8728 IS: 124.368 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/biggan/biggan-deep_imagenet1k_512x512_cvt_hugging-face_rgb_20210728_112346-a42585f2.pth ================================================ FILE: configs/cain/README.md ================================================ # CAIN (AAAI'2020) > [Channel Attention Is All You Need for Video Frame Interpolation](https://aaai.org/ojs/index.php/AAAI/article/view/6693/6547) > **Task**: Video Interpolation ## Abstract Prevailing video frame interpolation techniques rely heavily on optical flow estimation and require additional model complexity and computational cost; it is also susceptible to error propagation in challenging scenarios with large motion and heavy occlusion. To alleviate the limitation, we propose a simple but effective deep neural network for video frame interpolation, which is end-to-end trainable and is free from a motion estimation network component. Our algorithm employs a special feature reshaping operation, referred to as PixelShuffle, with a channel attention, which replaces the optical flow computation module. The main idea behind the design is to distribute the information in a feature map into multiple channels and extract motion information by attending the channels for pixel-level frame synthesis. The model given by this principle turns out to be effective in the presence of challenging motion and occlusion. We construct a comprehensive evaluation benchmark and demonstrate that the proposed approach achieves outstanding performance compared to the existing models with a component for optical flow computation.
## Results and models Evaluated on RGB channels. The metrics are `PSNR / SSIM` . The learning rate adjustment strategy is `Step LR scheduler with min_lr clipping`. | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :---------------------------------------------------------------------: | :--------: | :-----: | :----: | :----------------------: | :--------------------------------------------------------------------------------: | | [cain_b5_g1b32_vimeo90k_triplet](./cain_g1b32_1xb5_vimeo90k-triplet.py) | vimeo90k-T | 34.6010 | 0.9578 | 1 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth)/[log](https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py # single-gpu train python tools/train.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py # multi-gpu train ./tools/dist_train.sh configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth # single-gpu test python tools/test.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth # multi-gpu test ./tools/dist_test.sh configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{choi2020channel, title={Channel attention is all you need for video frame interpolation}, author={Choi, Myungsub and Kim, Heewon and Han, Bohyung and Xu, Ning and Lee, Kyoung Mu}, booktitle={Proceedings of the AAAI Conference on Artificial Intelligence}, volume={34}, number={07}, pages={10663--10671}, year={2020} } ``` ================================================ FILE: configs/cain/README_zh-CN.md ================================================ # CAIN (AAAI'2020) > **任务**: 视频插帧
CAIN (AAAI'2020) ```bibtex @inproceedings{choi2020channel, title={Channel attention is all you need for video frame interpolation}, author={Choi, Myungsub and Kim, Heewon and Han, Bohyung and Xu, Ning and Lee, Kyoung Mu}, booktitle={Proceedings of the AAAI Conference on Artificial Intelligence}, volume={34}, number={07}, pages={10663--10671}, year={2020} } ```

在 RGB 通道上进行评估。 我们使用 `PSNR` 和 `SSIM` 作为指标。 学习率调整策略是等间隔调整策略。 | 算法 | vimeo-90k-triplet | GPU 信息 | 下载 | | :---------------------------------------------------------------------: | :---------------: | :----------------------: | :--------------------------------------------------------------------------------------: | | [cain_b5_g1b32_vimeo90k_triplet](./cain_g1b32_1xb5_vimeo90k-triplet.py) | 34.6010 / 0.9578 | 1 (Tesla V100-SXM2-32GB) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth)/[日志](https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py # 单个GPU上训练 python tools/train.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py # 多个GPU上训练 ./tools/dist_train.sh configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth # 单个GPU上测试 python tools/test.py configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth # 多个GPU上测试 ./tools/dist_test.sh configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'cain_g1b32_1xb5_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( type='CAIN', generator=dict(type='CAINNet'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', pad_mode='reflect', )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type='FixedCrop', keys=['img', 'gt'], crop_size=(256, 256)), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict( type='ColorJitter', keys=['img', 'gt'], channel_order='rgb', brightness=0.05, contrast=0.05, saturation=0.05, hue=0.05), dict(type='TemporalReverse', keys=['img'], reverse_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] demo_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] # dataset settings train_dataset_type = 'BasicFramesDataset' val_dataset_type = 'BasicFramesDataset' data_root = 'data/vimeo_triplet' train_dataloader = dict( num_workers=32, batch_size=32, # 1 gpu persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=True), dataset=dict( type=train_dataset_type, ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=train_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=val_dataset_type, ann_file='tri_testlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=val_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=500) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)), ) # learning policy param_scheduler = dict( type='ReduceLR', by_epoch=True, mode='min', factor=0.5, patience=5, cooldown=0) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=1, save_optimizer=True, by_epoch=True, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), sampler_seed=dict(type='DistSamplerSeedHook'), param_scheduler=dict( type='ReduceLRSchedulerHook', by_epoch=True, interval=1, val_metric='MAE'), ) log_processor = dict(type='LogProcessor', by_epoch=True) ================================================ FILE: configs/cain/metafile.yml ================================================ Collections: - Name: CAIN Paper: Title: Channel Attention Is All You Need for Video Frame Interpolation URL: https://aaai.org/ojs/index.php/AAAI/article/view/6693/6547 README: configs/cain/README.md Task: - video interpolation Year: 2020 Models: - Config: configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py In Collection: CAIN Name: cain_g1b32_1xb5_vimeo90k-triplet Results: - Dataset: vimeo90k-T Metrics: PSNR: 34.601 SSIM: 0.9578 Task: Video Interpolation Weights: https://download.openmmlab.com/mmediting/video_interpolators/cain/cain_b5_g1b32_vimeo90k_triplet_20220530-3520b00c.pth ================================================ FILE: configs/controlnet/README.md ================================================ # Control Net (2023) > [Adding Conditional Control to Text-to-Image Diffusion Models](https://arxiv.org/abs/2302.05543) > **Task**: Text2Image ## Abstract We present a neural network structure, ControlNet, to control pretrained large diffusion models to support additional input conditions. The ControlNet learns task-specific conditions in an end-to-end way, and the learning is robust even when the training dataset is small (\< 50k). Moreover, training a ControlNet is as fast as fine-tuning a diffusion model, and the model can be trained on a personal devices. Alternatively, if powerful computation clusters are available, the model can scale to large amounts (millions to billions) of data. We report that large diffusion models like Stable Diffusion can be augmented with ControlNets to enable conditional inputs like edge maps, segmentation maps, keypoints, etc. This may enrich the methods to control large diffusion models and further facilitate related applications.
## Pretrained models We use ControlNet's weights provided by HuggingFace Diffusers. You do not have to download the weights manually. If you use Diffusers wrapper, the weights will be downloaded automatically. This model has several weights including vae, unet and clip. You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'pretrained_model_path' in config to the weights dir. | Model | Dataset | Download | | :---------------------------------------------: | :-----: | :----------------------------------------------------------------------------------------------: | | [ControlNet-Demo](./controlnet-1xb1-fill50k.py) | - | - | | [ControlNet-Canny](./controlnet-canny.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_canny.pth) | | [ControlNet-Pose](./controlnet-pose.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_openpose.pth) | | [ControlNet-Segmentation](./controlnet-seg.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_seg.pth) | Noted that, [ControlNet-Demo](./controlnet-1xb1-demo_dataset.py) is a demo config to train ControlNet with toy dataset named Fill50K. Besides above configs, ControlNet have weight with other condition inputs, such as [depth](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_depth.pth), [hed](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_hed.pth), [mlsd](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_mlsd.pth), [normal](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_normal.pth), [scribble](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_scribble.pth). You can simple change the `from_pretrained` field of ControlNet to use these weights. For example: ```python # Switch from canny.... controlnet=dict( type='ControlNetModel', from_pretrained='lllyasviel/sd-controlnet-canny') # To normal.... controlnet=dict( type='ControlNetModel', from_pretrained='lllyasviel/sd-controlnet-normal') ``` ## Quick Start Running the following codes, you can get a text-generated image. ```python import cv2 import numpy as np import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() cfg = Config.fromfile('configs/controlnet/controlnet-canny.py') controlnet = MODELS.build(cfg.model).cuda() prompt = 'Room with blue walls and a yellow ceiling.' control_url = 'https://user-images.githubusercontent.com/28132635/230288866-99603172-04cb-47b3-8adb-d1aa532d1d2c.jpg' control_img = mmcv.imread(control_url) control = cv2.Canny(control_img, 100, 200) control = control[:, :, None] control = np.concatenate([control] * 3, axis=2) control = Image.fromarray(control) output_dict = controlnet.infer(prompt, control=control) samples = output_dict['samples'] for idx, sample in enumerate(samples): sample.save(f'sample_{idx}.png') controls = output_dict['controls'] for idx, control in enumerate(controls): control.save(f'control_{idx}.png') ```

'control_0.png'

'sample_0.png'
If you want to pretrained weights rather than original Stable-Diffusion v1.5, you can refers to the following codes. ```python import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() cfg = Config.fromfile('configs/controlnet/controlnet-pose.py') # convert ControlNet's weight from SD-v1.5 to Counterfeit-v2.5 cfg.model.unet.from_pretrained = 'gsdf/Counterfeit-V2.5' cfg.model.vae.from_pretrained = 'gsdf/Counterfeit-V2.5' cfg.model.init_cfg['type'] = 'convert_from_unet' controlnet = MODELS.build(cfg.model).cuda() # call init_weights manually to convert weight controlnet.init_weights() prompt = 'masterpiece, best quality, sky, black hair, skirt, sailor collar, looking at viewer, short hair, building, bangs, neckerchief, long sleeves, cloudy sky, power lines, shirt, cityscape, pleated skirt, scenery, blunt bangs, city, night, black sailor collar, closed mouth' control_url = 'https://user-images.githubusercontent.com/28132635/230380893-2eae68af-d610-4f7f-aa68-c2f22c2abf7e.png' control_img = mmcv.imread(control_url) control = Image.fromarray(control_img) control.save('control.png') output_dict = controlnet.infer(prompt, control=control, width=512, height=512, guidance_scale=7.5) samples = output_dict['samples'] for idx, sample in enumerate(samples): sample.save(f'sample_{idx}.png') controls = output_dict['controls'] for idx, control in enumerate(controls): control.save(f'control_{idx}.png') ```

'control_0.png'

'sample_0.png'
### Using MMInferencer You can only use several lines of codes to play controlnet by MMagic! ```python from mmagic.apis import MMagicInferencer # controlnet-canny controlnet_canny_inferencer = MMagicInferencer(model_name='controlnet', model_setting=1) text_prompts = 'Room with blue walls and a yellow ceiling.' control = 'https://user-images.githubusercontent.com/28132635/230297033-4f5c32df-365c-4cf4-8e4f-1b76a4cbb0b7.png' result_out_dir = 'controlnet_canny_res.png' controlnet_canny_inferencer.infer(text=text_prompts, control=control, result_out_dir=result_out_dir) # controlnet-pose controlnet_pose_inferencer = MMagicInferencer(model_name='controlnet', model_setting=2) text_prompts = 'masterpiece, best quality, sky, black hair, skirt, sailor collar, looking at viewer, short hair, building, bangs, neckerchief, long sleeves, cloudy sky, power lines, shirt, cityscape, pleated skirt, scenery, blunt bangs, city, night, black sailor collar, closed mouth' control = 'https://user-images.githubusercontent.com/28132635/230380893-2eae68af-d610-4f7f-aa68-c2f22c2abf7e.png' result_out_dir = 'controlnet_pose_res.png' controlnet_pose_inferencer.infer(text=text_prompts, control=control, result_out_dir=result_out_dir) # controlnet-seg controlnet_seg_inferencer = MMagicInferencer(model_name='controlnet', model_setting=3) text_prompts = 'black house, blue sky' control = 'https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/243599897-553a4c46-c61d-46df-b820-59a49aaf6678.png' result_out_dir = 'controlnet_seg_res.png' controlnet_seg_inferencer.infer(text=text_prompts, control=control, result_out_dir=result_out_dir) ``` ## Train your own ControlNet! You can start training your own ControlNet with the toy dataset [Fill50K](https://huggingface.co/lllyasviel/ControlNet/blob/main/training/fill50k.zip) with the following command: ```bash bash tools/dist_train.sh configs/controlnet/controlnet-1xb1-demo_dataset 1 ``` If you want use gradient accumulation, you can add `accumulative_counts` field to the optimizer's config as follow: ```python # From... optim_wrapper = dict(controlnet=dict(optimizer=dict(type='AdamW', lr=1e-5))) # To... optim_wrapper = dict( controlnet=dict(accumulative_counts=4, optimizer=dict(type='AdamW', lr=1e-5))) ``` ## Use ToMe to accelerate your training and inference We support **[tomesd](https://github.com/dbolya/tomesd)** now! It is developed for stable-diffusion-based models referring to [ToMe](https://github.com/facebookresearch/ToMe), an efficient ViT speed-up tool based on token merging. To work on with **tomesd** in `mmagic`, you just need to add `tomesd_cfg` to `model` in [ControlNet-Canny](./controlnet-canny.py). The only requirement is `torch >= 1.12.1` in order to properly support `torch.Tensor.scatter_reduce()` functionality. Please do check it before running the demo. ```python model = dict( type='ControlStableDiffusion', ... tomesd_cfg=dict(ratio=0.5), ... init_cfg=dict(type='init_from_unet')) ``` For more details, you can refer to [Stable Diffusion Acceleration](../stable_diffusion/README.md#use-tome-to-accelerate-your-stable-diffusion-model). ## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py) and [ControlNet](https://huggingface.co/lllyasviel/ControlNet/tree/main/models). Thanks for the efforts of the community! ## Citation ```bibtex @misc{zhang2023adding, title={Adding Conditional Control to Text-to-Image Diffusion Models}, author={Lvmin Zhang and Maneesh Agrawala}, year={2023}, eprint={2302.05543}, archivePrefix={arXiv}, primaryClass={cs.CV} } ``` ================================================ FILE: configs/controlnet/controlnet-1xb1-fill50k.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' controlnet_canny_url = 'lllyasviel/sd-controlnet-canny' model = dict( type='ControlStableDiffusion', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, controlnet=dict( type='ControlNetModel', # from_pretrained=controlnet_canny_rul from_config=controlnet_canny_url # train from scratch ), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), init_cfg=dict(type='init_from_unet')) # config for training train_cfg = dict(max_iters=10000) optim_wrapper = dict(controlnet=dict(optimizer=dict(type='AdamW', lr=1e-5))) # Config for data loader pipeline = [ dict(type='LoadImageFromFile', key='source', channel_order='rgb'), dict(type='LoadImageFromFile', key='target', channel_order='rgb'), dict( type='PackInputs', keys=['source', 'target'], data_keys='prompt', meta_keys=[ 'source_channel_order', 'source_color_type', 'target_channel_order', 'target_color_type' ]) ] dataset = dict( type='ControlNetDataset', data_root='./data/fill50k', ann_file='prompt.json', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=4) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks custom_hooks = [ dict( type='VisualizationHook', interval=300, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=4, n_row=2) ] ================================================ FILE: configs/controlnet/controlnet-canny.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' controlnet_canny_url = 'lllyasviel/sd-controlnet-canny' model = dict( type='ControlStableDiffusion', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, controlnet=dict( type='ControlNetModel', from_pretrained=controlnet_canny_url), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), init_cfg=dict(type='init_from_unet')) ================================================ FILE: configs/controlnet/controlnet-pose.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' controlnet_canny_url = 'lllyasviel/sd-controlnet-openpose' model = dict( type='ControlStableDiffusion', vae=dict( type='AutoencoderKL', from_pretrained='gsdf/Counterfeit-V2.5', subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained='gsdf/Counterfeit-V2.5'), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, controlnet=dict( type='ControlNetModel', from_pretrained=controlnet_canny_url), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), init_cfg=dict(type='convert_from_unet')) ================================================ FILE: configs/controlnet/controlnet-seg.py ================================================ # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' controlnet_canny_url = 'lllyasviel/sd-controlnet-seg' model = dict( type='ControlStableDiffusion', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, controlnet=dict( type='ControlNetModel', from_pretrained=controlnet_canny_url), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), init_cfg=dict(type='init_from_unet')) ================================================ FILE: configs/controlnet/metafile.yml ================================================ Collections: - Name: Control Net Paper: Title: Adding Conditional Control to Text-to-Image Diffusion Models URL: https://arxiv.org/abs/2302.05543 README: configs/controlnet/README.md Task: - text2image Year: 2023 Models: - Config: configs/controlnet/controlnet-1xb1-fill50k.py In Collection: Control Net Name: controlnet-1xb1-fill50k Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/controlnet/controlnet-canny.py In Collection: Control Net Name: controlnet-canny Results: - Dataset: '-' Metrics: {} Task: Text2Image Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_canny.pth - Config: configs/controlnet/controlnet-pose.py In Collection: Control Net Name: controlnet-pose Results: - Dataset: '-' Metrics: {} Task: Text2Image Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_openpose.pth - Config: configs/controlnet/controlnet-seg.py In Collection: Control Net Name: controlnet-seg Results: - Dataset: '-' Metrics: {} Task: Text2Image Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_seg.pth ================================================ FILE: configs/controlnet_animation/README.md ================================================ # Controlnet Animation (2023) > [Controlnet](https://github.com/lllyasviel/ControlNet) Application > **Task**: controlnet_animation ## Abstract It is difficult to keep consistency and avoid video frame flickering when using stable diffusion to generate video frame by frame. Here we reproduce two methods that effectively avoid video flickering: **Controlnet with multi-frame rendering**. [ControlNet](https://github.com/lllyasviel/ControlNet) is a neural network structure to control diffusion models by adding extra conditions. [Multi-frame rendering](https://xanthius.itch.io/multi-frame-rendering-for-stablediffusion) is a community method to reduce flickering. We use controlnet with hed condition and stable diffusion img2img for multi-frame rendering. **Controlnet with attention injection**. Attention injection is widely used to generate the current frame from a reference image. There is an implementation in [sd-webui-controlnet](https://github.com/Mikubill/sd-webui-controlnet#reference-only-control) and we use some of their code to create the animation in this repo. You may need 40G GPU memory to run controlnet with multi-frame rendering and 10G GPU memory for controlnet with attention injection. If the config file is not changed, it defaults to using controlnet with attention injection. ## Demos prompt key words: a handsome man, silver hair, smiling, play basketball
prompt key words: a handsome man
  **Change prompt to get different result** prompt key words: a girl, black hair, white pants, smiling, play basketball
## Pretrained models We use pretrained model from hugging face. | Model | Dataset | Download | | :-----------------------------------------: | :-----: | :-------------------------------------------------------------------------------: | | [anythingv3 config](./anythingv3_config.py) | - | [stable diffusion model](https://huggingface.co/Linaqruf/anything-v3.0/tree/main) | ## Quick Start There are two ways to try controlnet animation. ### 1. Use MMagic inference API. Running the following codes, you can get an generated animation video. ```python from mmagic.apis import MMagicInferencer # Create a MMEdit instance and infer editor = MMagicInferencer(model_name='controlnet_animation') prompt = 'a girl, black hair, T-shirt, smoking, best quality, extremely detailed' negative_prompt = 'longbody, lowres, bad anatomy, bad hands, missing fingers, ' + \ 'extra digit, fewer digits, cropped, worst quality, low quality' # you can download the example video with this link # https://user-images.githubusercontent.com/12782558/227418400-80ad9123-7f8e-4c1a-8e19-0892ebad2a4f.mp4 video = '/path/to/your/input/video.mp4' save_path = '/path/to/your/output/video.mp4' # Do the inference to get result editor.infer(video=video, prompt=prompt, negative_prompt=negative_prompt, save_path=save_path) ``` ### 2. Use controlnet animation gradio demo. ```python python demo/gradio_controlnet_animation.py ``` ### 3. Change config to use multi-frame rendering or attention injection. change "inference_method" in [anythingv3 config](./anythingv3_config.py) To use multi-frame rendering. ```python inference_method = 'multi-frame rendering' ``` To use attention injection. ```python inference_method = 'attention_injection' ``` ## Play animation with SAM We also provide a demo to play controlnet animation with sam, for details, please see [OpenMMLab PlayGround](https://github.com/open-mmlab/playground/blob/main/mmediting_sam/README.md). ## Citation ```bibtex @misc{zhang2023adding, title={Adding Conditional Control to Text-to-Image Diffusion Models}, author={Lvmin Zhang and Maneesh Agrawala}, year={2023}, eprint={2302.05543}, archivePrefix={arXiv}, primaryClass={cs.CV} } ``` ================================================ FILE: configs/controlnet_animation/anythingv3_config.py ================================================ # config for model stable_diffusion_v15_url = 'Linaqruf/anything-v3.0' controlnet_hed_url = 'lllyasviel/sd-controlnet-hed' control_detector = 'lllyasviel/ControlNet' control_scheduler = 'UniPCMultistepScheduler' # method type : 'multi-frame rendering' or 'attention_injection' inference_method = 'attention_injection' model = dict( type='ControlStableDiffusionImg2Img', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, controlnet=dict( type='ControlNetModel', from_pretrained=controlnet_hed_url), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), init_cfg=dict(type='init_from_unet'), enable_xformers=False, ) ================================================ FILE: configs/controlnet_animation/metafile.yml ================================================ Collections: - Name: Controlnet Animation Paper: Title: Controlnet URL: https://github.com/lllyasviel/ControlNet README: configs/controlnet_animation/README.md Task: - controlnet_animation Year: 2023 Models: - Config: configs/controlnet_animation/anythingv3_config.py In Collection: Controlnet Animation Name: anythingv3_config Results: - Dataset: '-' Metrics: {} Task: controlnet_animation Weights: https://huggingface.co/Linaqruf/anything-v3.0/tree/main ================================================ FILE: configs/cyclegan/README.md ================================================ # CycleGAN (ICCV'2017) > [CycleGAN: Unpaired Image-to-Image Translation Using Cycle-Consistent Adversarial Networks](https://openaccess.thecvf.com/content_iccv_2017/html/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.html) > **Task**: Image2Image ## Abstract Image-to-image translation is a class of vision and graphics problems where the goal is to learn the mapping between an input image and an output image using a training set of aligned image pairs. However, for many tasks, paired training data will not be available. We present an approach for learning to translate an image from a source domain X to a target domain Y in the absence of paired examples. Our goal is to learn a mapping G: X \\rightarrow Y such that the distribution of images from G(X) is indistinguishable from the distribution Y using an adversarial loss. Because this mapping is highly under-constrained, we couple it with an inverse mapping F: Y \\rightarrow X and introduce a cycle consistency loss to push F(G(X)) \\approx X (and vice versa). Qualitative results are presented on several tasks where paired training data does not exist, including collection style transfer, object transfiguration, season transfer, photo enhancement, etc. Quantitative comparisons against several prior methods demonstrate the superiority of our approach.
## Results and Models
Results from CycleGAN trained by mmagic
We use `FID` and `IS` metrics to evaluate the generation performance of CycleGAN.1 https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_80k_facades_20210902_165905-5e2c0876.pth https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_in_1x1_80k_facades_20210902_165905-5e2c0876.pth | Model | Dataset | FID | IS | Download | | :--------------------------------------------------------------------: | :---------------: | :------: | :---: | :--------------------------------------------------------------------------------------------------: | | [Ours](./cyclegan_lsgan-resnet-in_1xb1-80kiters_facades.py) | facades | 124.8033 | 1.792 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_80k_facades_20210902_165905-5e2c0876.pth) \| [log](https://download.openmmlab.com/mmediting/cyclegan/cyclegan_lsgan_resnet_in_1x1_80k_facades_20210317_160938.log.json) 2 | | [Ours](./cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py) | facades-id0 | 125.1694 | 1.905 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_80k_facades_convert-bgr_20210902_164411-d8e72b45.pth) | | [Ours](./cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter.py) | summer2winter | 83.7177 | 2.771 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165932-fcf08dc1.pth) | | [Ours](./cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) | summer2winter-id0 | 83.1418 | 2.720 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165640-8b825581.pth) | | [Ours](./cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter.py) | winter2summer | 72.8025 | 3.129 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165932-fcf08dc1.pth) | | [Ours](./cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) | winter2summer-id0 | 73.5001 | 3.107 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165640-8b825581.pth) | | [Ours](./cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra.py) | horse2zebra | 64.5225 | 1.418 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_170004-a32c733a.pth) | | [Ours](./cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra.py) | horse2zebra-id0 | 74.7770 | 1.542 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_165724-77c9c806.pth) | | [Ours](./cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra.py) | zebra2horse | 141.1517 | 3.154 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_170004-a32c733a.pth) | | [Ours](./cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra.py) | zebra2horse-id0 | 134.3728 | 3.091 | [model](https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_165724-77c9c806.pth) | `FID` comparison with official: | Dataset | facades | facades-id0 | summer2winter | summer2winter-id0 | winter2summer | winter2summer-id0 | horse2zebra | horse2zebra-id0 | zebra2horse | zebra2horse-id0 | average | | :------: | :---------: | :---------: | :-----------: | :---------------: | :-----------: | :---------------: | :---------: | :-------------: | :---------: | :-------------: | :--------: | | official | **123.626** | **119.726** | **77.342** | **76.773** | **72.631** | 74.239 | **62.111** | 77.202 | **138.646** | **137.050** | **95.935** | | ours | 124.8033 | 125.1694 | 83.7177 | 83.1418 | 72.8025 | **73.5001** | 64.5225 | **74.7770** | 141.1571 | **134.3728** | 97.79 | `IS` comparison with evaluation: | Dataset | facades | facades-id0 | summer2winter | summer2winter-id0 | winter2summer | winter2summer-id0 | horse2zebra | horse2zebra-id0 | zebra2horse | zebra2horse-id0 | average | | :------: | :-------: | :---------: | :-----------: | :---------------: | :-----------: | :---------------: | :---------: | :-------------: | :---------: | :-------------: | :-------: | | official | 1.638 | 1.697 | 2.762 | **2.750** | **3.293** | **3.110** | 1.375 | **1.584** | **3.186** | 3.047 | 2.444 | | ours | **1.792** | **1.905** | **2.771** | 2.720 | 3.129 | 3.107 | **1.418** | 1.542 | 3.154 | **3.091** | **2.462** | Note: 1. With a larger identity loss, the image-to-image translation becomes more conservative, which makes less changes. The original authors did not say what is the best weight for identity loss. Thus, in addition to the default setting, we also set the weight of identity loss to 0 (denoting `id0`) to make a more comprehensive comparison. 2. This is the training log before refactoring. Updated logs will be released soon. ## Citation ```latex @inproceedings{zhu2017unpaired, title={Unpaired image-to-image translation using cycle-consistent adversarial networks}, author={Zhu, Jun-Yan and Park, Taesung and Isola, Phillip and Efros, Alexei A}, booktitle={Proceedings of the IEEE international conference on computer vision}, pages={2223--2232}, year={2017}, url={https://openaccess.thecvf.com/content_iccv_2017/html/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.html}, } ``` ================================================ FILE: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] domain_a = 'summer' domain_b = 'winter' train_cfg = dict(max_iters=250000) model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.), default_domain=domain_b, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) dataroot = './data/cyclegan/summer2winter_yosemite' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # learning policy param_scheduler = dict( type='LinearLrInterval', interval=1250, by_epoch=False, start_factor=0.0002, end_factor=0, begin=125000, end=250000) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] # testA: 309, testB:238 num_images_a = 309 num_images_b = 238 metrics = [ dict( type='TransIS', prefix=f'IS-{domain_a}-to-{domain_b}', fake_nums=num_images_b, fake_key=f'fake_{domain_b}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransIS', prefix=f'IS-{domain_b}-to-{domain_a}', fake_nums=num_images_a, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix=f'FID-{domain_a}-to-{domain_b}', fake_nums=num_images_b, inception_style='PyTorch', real_key=f'img_{domain_b}', fake_key=f'fake_{domain_b}'), dict( type='TransFID', prefix=f'FID-{domain_b}-to-{domain_a}', fake_nums=num_images_a, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=270000) domain_a = 'horse' domain_b = 'zebra' model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.), default_domain=domain_b, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) dataroot = './data/cyclegan/horse2zebra' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) param_scheduler = dict( type='LinearLrInterval', interval=1350, by_epoch=False, start_factor=0.0002, end_factor=0, begin=135000, end=270000) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] num_images_a = 120 num_images_b = 140 metrics = [ dict( type='TransIS', prefix=f'IS-{domain_a}-to-{domain_b}', fake_nums=num_images_b, fake_key=f'fake_{domain_b}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransIS', prefix=f'IS-{domain_b}-to-{domain_a}', fake_nums=num_images_a, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix=f'FID-{domain_a}-to-{domain_b}', fake_nums=num_images_b, inception_style='PyTorch', real_key=f'img_{domain_b}', fake_key=f'fake_{domain_b}'), dict( type='TransFID', prefix=f'FID-{domain_b}-to-{domain_a}', fake_nums=num_images_a, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=80000) domain_a = 'photo' domain_b = 'mask' model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.), default_domain=domain_a, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) param_scheduler = dict( type='LinearLrInterval', interval=400, by_epoch=False, start_factor=0.0002, end_factor=0, begin=40000, end=80000) dataroot = './data/cyclegan/facades' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] num_images = 106 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=num_images, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix='FID-Full', fake_nums=num_images, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=250000) domain_a = 'summer' domain_b = 'winter' model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.5), default_domain=domain_b, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) dataroot = './data/cyclegan/summer2winter_yosemite' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # learning policy param_scheduler = dict( type='LinearLrInterval', interval=1250, by_epoch=False, start_factor=0.0002, end_factor=0, begin=125000, end=250000) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] num_images_a = 309 num_images_b = 238 metrics = [ dict( type='TransIS', prefix=f'IS-{domain_a}-to-{domain_b}', fake_nums=num_images_b, fake_key=f'fake_{domain_b}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransIS', prefix=f'IS-{domain_b}-to-{domain_a}', fake_nums=num_images_a, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix=f'FID-{domain_a}-to-{domain_b}', fake_nums=num_images_b, inception_style='PyTorch', real_key=f'img_{domain_b}', fake_key=f'fake_{domain_b}'), dict( type='TransFID', prefix=f'FID-{domain_b}-to-{domain_a}', fake_nums=num_images_a, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=270000) domain_a = 'horse' domain_b = 'zebra' model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.5), default_domain=domain_b, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) dataroot = './data/cyclegan/horse2zebra' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) param_scheduler = dict( type='LinearLrInterval', interval=1350, by_epoch=False, start_factor=0.0002, end_factor=0, begin=135000, end=270000) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] num_images_a = 120 num_images_b = 140 metrics = [ dict( type='TransIS', prefix=f'IS-{domain_a}-to-{domain_b}', fake_nums=num_images_b, fake_key=f'fake_{domain_b}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransIS', prefix=f'IS-{domain_b}-to-{domain_a}', fake_nums=num_images_a, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix=f'FID-{domain_a}-to-{domain_b}', fake_nums=num_images_b, inception_style='PyTorch', real_key=f'img_{domain_b}', fake_key=f'fake_{domain_b}'), dict( type='TransFID', prefix=f'FID-{domain_b}-to-{domain_a}', fake_nums=num_images_a, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-80kiters_facades.py ================================================ _base_ = [ '../_base_/models/base_cyclegan.py', '../_base_/datasets/unpaired_imgs_256x256.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=80000) domain_a = 'photo' domain_b = 'mask' model = dict( loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.5), default_domain=domain_a, reachable_domains=[domain_a, domain_b], related_domains=[domain_a, domain_b], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) param_scheduler = dict( type='LinearLrInterval', interval=400, by_epoch=False, start_factor=0.0002, end_factor=0, begin=40000, end=80000) dataroot = './data/cyclegan/facades' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader optim_wrapper = dict( generators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminators=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] num_images = 106 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=num_images, fake_key=f'fake_{domain_a}', use_pillow_resize=False, resize_method='bilinear', inception_style='PyTorch'), dict( type='TransFID', prefix='FID-Full', fake_nums=num_images, inception_style='PyTorch', real_key=f'img_{domain_a}', fake_key=f'fake_{domain_a}') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/cyclegan/metafile.yml ================================================ Collections: - Name: CycleGAN Paper: Title: 'CycleGAN: Unpaired Image-to-Image Translation Using Cycle-Consistent Adversarial Networks' URL: https://openaccess.thecvf.com/content_iccv_2017/html/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.html README: configs/cyclegan/README.md Task: - image2image Year: 2017 Models: - Config: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-80kiters_facades.py In Collection: CycleGAN Name: cyclegan_lsgan-resnet-in_1xb1-80kiters_facades Results: - Dataset: facades Metrics: FID: 124.8033 IS: 1.792 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_80k_facades_20210902_165905-5e2c0876.pth - Config: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py In Collection: CycleGAN Name: cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades Results: - Dataset: facades-id0 Metrics: FID: 125.1694 IS: 1.905 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_80k_facades_convert-bgr_20210902_164411-d8e72b45.pth - Config: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter.py In Collection: CycleGAN Name: cyclegan_lsgan-resnet-in_1xb1-250kiters_summer2winter Results: - Dataset: summer2winter Metrics: FID: 83.7177 IS: 2.771 Task: Image2Image - Dataset: winter2summer Metrics: FID: 72.8025 IS: 3.129 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165932-fcf08dc1.pth - Config: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py In Collection: CycleGAN Name: cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter Results: - Dataset: summer2winter-id0 Metrics: FID: 83.1418 IS: 2.72 Task: Image2Image - Dataset: winter2summer-id0 Metrics: FID: 73.5001 IS: 3.107 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_246200_summer2winter_convert-bgr_20210902_165640-8b825581.pth - Config: configs/cyclegan/cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra.py In Collection: CycleGAN Name: cyclegan_lsgan-resnet-in_1xb1-270kiters_horse2zebra Results: - Dataset: horse2zebra Metrics: FID: 64.5225 IS: 1.418 Task: Image2Image - Dataset: zebra2horse Metrics: FID: 141.1517 IS: 3.154 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_170004-a32c733a.pth - Config: configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra.py In Collection: CycleGAN Name: cyclegan_lsgan-id0-resnet-in_1xb1-270kiters_horse2zebra Results: - Dataset: horse2zebra-id0 Metrics: FID: 74.777 IS: 1.542 Task: Image2Image - Dataset: zebra2horse-id0 Metrics: FID: 134.3728 IS: 3.091 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/cyclegan/refactor/cyclegan_lsgan_id0_resnet_in_1x1_266800_horse2zebra_convert-bgr_20210902_165724-77c9c806.pth ================================================ FILE: configs/dcgan/README.md ================================================ # Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks (ICLR'2016) > [Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks](https://arxiv.org/abs/1511.06434) > **Task**: Unconditional GANs ## Abstract In recent years, supervised learning with convolutional networks (CNNs) has seen huge adoption in computer vision applications. Comparatively, unsupervised learning with CNNs has received less attention. In this work we hope to help bridge the gap between the success of CNNs for supervised learning and unsupervised learning. We introduce a class of CNNs called deep convolutional generative adversarial networks (DCGANs), that have certain architectural constraints, and demonstrate that they are a strong candidate for unsupervised learning. Training on various image datasets, we show convincing evidence that our deep convolutional adversarial pair learns a hierarchy of representations from object parts to scenes in both the generator and discriminator. Additionally, we use the learned features for novel tasks - demonstrating their applicability as general image representations.
## Results and models
DCGAN 64x64, CelebA-Cropped
| Model | Dataset | SWD | MS-SSIM | Download | | :------------------------------------------------------------------: | :------------: | :----------------------: | :-----: | :-------------------------------------------------------------------------------------: | | [DCGAN 64x64](./dcgan_Glr4e-4_Dlr1e-4_1xb128-5kiters_mnist-64x64.py) | MNIST (64x64) | 21.16, 4.4, 8.41/11.32 | 0.1395 | [model](https://download.openmmlab.com/mmediting/dcgan/dcgan_mnist-64_b128x1_Glr4e-4_Dlr1e-4_5k_20210512_163926-207a1eaf.pth) \| [log](https://download.openmmlab.com//mmgen/dcgan/dcgan_mnist-64_b128x1_Glr4e-4_Dlr1e-4_5k_20210512_163926-207a1eaf.json) | | [DCGAN 64x64](./dcgan_1xb128-300kiters_celeba-cropped-64.py) | CelebA-Cropped | 8.93,10.53,50.32/23.26 | 0.2899 | [model](https://download.openmmlab.com/mmediting/dcgan/dcgan_celeba-cropped_64_b128x1_300kiter_20210408_161607-1f8a2277.pth) \| [log](https://download.openmmlab.com/mmediting/dcgan/dcgan_celeba-cropped_64_b128x1_300kiter_20210408_161607-1f8a2277.json) | | [DCGAN 64x64](./dcgan_1xb128-5epoches_lsun-bedroom-64x64.py) | LSUN-Bedroom | 42.79, 34.55, 98.46/58.6 | 0.2095 | [model](https://download.openmmlab.com/mmediting/dcgan/dcgan_lsun-bedroom_64_b128x1_5e_20210408_161713-117c498b.pth) \| [log](https://download.openmmlab.com/mmediting/dcgan/dcgan_lsun-bedroom_64_b128x1_5e_20210408_161713-117c498b.json) | ## Citation ```latex @article{radford2015unsupervised, title={Unsupervised representation learning with deep convolutional generative adversarial networks}, author={Radford, Alec and Metz, Luke and Chintala, Soumith}, journal={arXiv preprint arXiv:1511.06434}, year={2015}, url={https://arxiv.org/abs/1511.06434}, } ``` ================================================ FILE: configs/dcgan/dcgan_1xb128-300kiters_celeba-cropped-64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] # define dataset # batch_size and data_root must be set batch_size = 128 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=10000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] model = dict(type='DCGAN') train_cfg = dict(max_iters=300002) # METRICS metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] # save best checkpoints default_hooks = dict(checkpoint=dict(save_best='swd/avg', rule='less')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] # define dataset # batch_size and data_root must be set batch_size = 128 data_root = './data/lsun/images/bedroom_train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) train_cfg = dict(max_iters=1500002) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=10000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] # save best checkpoints default_hooks = dict(checkpoint=dict(save_best='swd/avg', rule='less')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/dcgan/dcgan_Glr4e-4_Dlr1e-4_1xb128-5kiters_mnist-64x64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] # output single channel model = dict( data_preprocessor=dict(mean=[127.5], std=[127.5]), generator=dict(out_channels=1), discriminator=dict(in_channels=1)) # define dataset # modify train_pipeline to load gray scale images train_pipeline = [ dict(type='LoadImageFromFile', key='gt', color_type='grayscale'), dict(type='Resize', keys='gt', scale=(64, 64)), dict(type='PackInputs') ] # set ``batch_size``` and ``data_root``` batch_size = 128 data_root = 'data/mnist_64/train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root, pipeline=train_pipeline)) val_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root, pipeline=train_pipeline)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root, pipeline=train_pipeline)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=500, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] train_cfg = dict(max_iters=5000, val_interval=500) # METRICS metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=-1, sample_model='orig', image_shape=(1, 64, 64)) ] # save best checkpoints default_hooks = dict( checkpoint=dict(interval=500, save_best='swd/avg', rule='less')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0004, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.999)))) ================================================ FILE: configs/dcgan/metafile.yml ================================================ Collections: - Name: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks Paper: Title: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks URL: https://arxiv.org/abs/1511.06434 README: configs/dcgan/README.md Task: - unconditional gans Year: 2016 Models: - Config: configs/dcgan/dcgan_Glr4e-4_Dlr1e-4_1xb128-5kiters_mnist-64x64.py In Collection: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks Name: dcgan_Glr4e-4_Dlr1e-4_1xb128-5kiters_mnist-64x64 Results: - Dataset: MNIST(64x64) Metrics: MS-SSIM: 0.1395 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/dcgan/dcgan_mnist-64_b128x1_Glr4e-4_Dlr1e-4_5k_20210512_163926-207a1eaf.pth - Config: configs/dcgan/dcgan_1xb128-300kiters_celeba-cropped-64.py In Collection: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks Name: dcgan_1xb128-300kiters_celeba-cropped-64 Results: - Dataset: CelebA-Cropped Metrics: MS-SSIM: 0.2899 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/dcgan/dcgan_celeba-cropped_64_b128x1_300kiter_20210408_161607-1f8a2277.pth - Config: configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py In Collection: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks Name: dcgan_1xb128-5epoches_lsun-bedroom-64x64 Results: - Dataset: LSUN-Bedroom Metrics: MS-SSIM: 0.2095 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/dcgan/dcgan_lsun-bedroom_64_b128x1_5e_20210408_161713-117c498b.pth ================================================ FILE: configs/deblurganv2/README.md ================================================ # DeblurGAN-v2 (ICCV'2019) > [DeblurGAN-v2: Deblurring (Orders-of-Magnitude) Faster and Better](https://arxiv.org/abs/1908.03826) > **Task**: Deblurring ## Abstract We present a new end-to-end generative adversarial network (GAN) for single image motion deblurring, named DeblurGAN-v2, which considerably boosts state-of-the-art deblurring efficiency, quality, and flexibility. DeblurGAN-v2 is based on a relativistic conditional GAN with a double-scale discriminator. For the first time, we introduce the Feature Pyramid Network into deblurring, as a core building block in the generator of DeblurGAN-v2. It can flexibly work with a wide range of backbones, to navigate the balance between performance and efficiency. The plug-in of sophisticated backbones (e.g., Inception-ResNet-v2) can lead to solid state-of-the-art deblurring. Meanwhile, with light-weight backbones (e.g., MobileNet and its variants), DeblurGAN-v2 reaches 10-100 times faster than the nearest competitors, while maintaining close to state-of-the-art results, implying the option of real-time video deblurring. We demonstrate that DeblurGAN-v2 obtains very competitive performance on several popular benchmarks, in terms of deblurring quality (both objective and subjective), as well as efficiency. Besides, we show the architecture to be effective for general image restoration tasks too.
## Results and models
DEBLURGANv2 256x256
| Model | Dataset | G Model | D Model | PSNR/
SSIM | Download | | :--------------------------------------------------------: | :----------------: | :----------------: | :--------: | :------------: | :--------------------------------------------------------------------------------: | | [fpn_inception](./deblurganv2_fpn-inception_1xb1_gopro.py) | GoPro Test Dataset | InceptionResNet-v2 | double_gan | 29.55/ 0.934 | [model](https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth) \\ [log](<>) | | [fpn_mobilenet](./deblurganv2_fpn-mobilenet_1xb1_gopro.py) | GoPro Test Dataset | MobileNet | double_gan | 28.17/ 0.925 | [model](https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-mobilenet.pth) \\ [log](<>) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py # single-gpu train python tools/train.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py # multi-gpu train ./tools/dist_train.sh configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth # single-gpu test python tools/test.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth # multi-gpu test ./tools/dist_test.sh configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{Kupyn_2019_ICCV, author = {Orest Kupyn and Tetiana Martyniuk and Junru Wu and Zhangyang Wang}, title = {DeblurGAN-v2: Deblurring (Orders-of-Magnitude) Faster and Better}, booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, month = {Oct}, year = {2019} } ``` ================================================ FILE: configs/deblurganv2/README_zh-CN.md ================================================ # DeblurGAN-v2 (ICCV'2019) > [DeblurGAN-v2: Deblurring (Orders-of-Magnitude) Faster and Better](https://arxiv.org/abs/1908.03826) > **任务**: 去模糊 ## 摘要 我们提出了一种新的端到端的用于单图像运动去模糊生成对抗网络(GAN),名为DeblurGAN-v2,它显著提高了最高水平的去模糊效率、质量和灵活性。DeblurGAN-v2是基于具有双尺度鉴别器的相对论条件GAN。我们首次将特征金字塔网络引入去模糊来作为DeblurGAN-v2生成器的核心构建块。它可以灵活地与各种主干网络一起工作,以在性能和效率之间取得平衡。先进的主干网络的插件(例如,Inception-ResNet-v2)可以带来最先进的去模糊处理。同时,凭借轻量级主干网络(例如MobileNet及其变体),DeblurGAN-v2的速度比最接近的竞争对手快10-100倍,同时保持接近最先进的结果,这意味着可用于实时视频去模糊。我们证明了DeblurGAN-v2在几个流行的基准测试中获得了非常有竞争力的性能,包括去模糊质量(客观和主观)以及效率。此外,我们还展示了该架构对于一般图像恢复任务也依然有效。
## 结果与模型
DEBLURGANv2 256x256
| 算法 | 测试集 | 生成器模型 | 判别器模型 | PSNR/
SSIM | 下载 | | :--------------------------------------------------------: | :----------------: | :----------------: | :--------: | :------------: | :--------------------------------------------------------------------------------: | | [fpn_inception](./deblurganv2_fpn-inception_1xb1_gopro.py) | GoPro Test Dataset | InceptionResNet-v2 | double_gan | 29.55/ 0.934 | [模型](https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth) \\ [日志](<>) | | [fpn_mobilenet](./deblurganv2_fpn-mobilenet_1xb1_gopro.py) | GoPro Test Dataset | MobileNet | double_gan | 28.17/ 0.925 | [模型](https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-mobilenet.pth) \\ [日志](<>) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py # single-gpu train python tools/train.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py # multi-gpu train ./tools/dist_train.sh configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth # single-gpu test python tools/test.py configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth # multi-gpu test ./tools/dist_test.sh configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
## 引用 ```bibtex @InProceedings{Kupyn_2019_ICCV, author = {Orest Kupyn and Tetiana Martyniuk and Junru Wu and Zhangyang Wang}, title = {DeblurGAN-v2: Deblurring (Orders-of-Magnitude) Faster and Better}, booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, month = {Oct}, year = {2019} } ``` ================================================ FILE: configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. _base_ = ['../_base_/default_runtime.py'] save_dir = './work_dir/' model = dict( type='DeblurGanV2', generator=dict( type='DeblurGanV2Generator', backbone='FPNInception', norm_layer='instance', output_ch=3, num_filter=128, num_filter_fpn=256, ), discriminator=dict( type='DeblurGanV2Discriminator', backbone='DoubleGan', norm_layer='instance', d_layers=3, ), pixel_loss=dict( type='PerceptualLoss', layer_weights={'14': 1}, criterion='mse'), disc_loss=dict(type='AdvLoss', loss_type='ragan-ls'), adv_lambda=0.001, warmup_num=3, data_preprocessor=dict( type='DataPreprocessor', mean=[127.5] * 3, std=[127.5] * 3, )) train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedAlbuTransForms', size=256, lq_key='img', gt_key='gt'), dict( type='AlbuCorruptFunction', keys=['img'], config=[{ 'name': 'cutout', 'prob': 0.5, 'num_holes': 3, 'max_h_size': 25, 'max_w_size': 25 }, { 'name': 'jpeg', 'quality_lower': 70, 'quality_upper': 90 }, { 'name': 'motion_blur' }, { 'name': 'median_blur' }, { 'name': 'gamma' }, { 'name': 'rgb_shift' }, { 'name': 'hsv_shift' }, { 'name': 'sharpen' }]), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedAlbuTransForms', size=256, lq_key='img', gt_key='gt'), dict( type='AlbuCorruptFunction', keys=['img'], config=[{ 'name': 'cutout', 'prob': 0.5, 'num_holes': 3, 'max_h_size': 25, 'max_w_size': 25 }, { 'name': 'jpeg', 'quality_lower': 70, 'quality_upper': 90 }, { 'name': 'motion_blur' }, { 'name': 'median_blur' }, { 'name': 'gamma' }, { 'name': 'rgb_shift' }, { 'name': 'hsv_shift' }, { 'name': 'sharpen' }]), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='PackInputs') ] data_root = 'data/gopro' train_dataloader = dict( batch_size=1, num_workers=4, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/train', data_prefix=dict(img='input', gt='target'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/test', data_prefix=dict(img='input', gt='target'), pipeline=val_pipeline)) test_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/test', data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=100) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') test_evaluator = val_evaluator # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.999))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.999))), ) # learning policy param_scheduler = dict( type='LinearLR', start_factor=0.0001, end_factor=0.0000001, begin=50, ) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=1000, save_optimizer=True, by_epoch=False, out_dir=save_dir, save_best='auto', ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=1), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) load_from = 'https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/'\ 'weight/DeblurGANv2_fpn-inception.pth' ================================================ FILE: configs/deblurganv2/deblurganv2_fpn-mobilenet_1xb1_gopro.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. _base_ = ['../_base_/default_runtime.py'] save_dir = './work_dir/' model = dict( type='DeblurGanV2', generator=dict( type='DeblurGanV2Generator', backbone='FPNMobileNet', norm_layer='instance', output_ch=3, num_filter=64, num_filter_fpn=128, ), discriminator=dict( type='DeblurGanV2Discriminator', backbone='DoubleGan', norm_layer='instance', d_layers=3, ), pixel_loss=dict( type='PerceptualLoss', layer_weights={'14': 1}, criterion='mse'), disc_loss=dict(type='AdvLoss', loss_type='ragan-ls'), adv_lambda=0.001, warmup_num=3, data_preprocessor=dict( type='DataPreprocessor', mean=[127.5] * 3, std=[127.5] * 3, )) train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedAlbuTransForms', size=256, lq_key='img', gt_key='gt'), dict( type='AlbuCorruptFunction', keys=['img'], config=[{ 'name': 'cutout', 'prob': 0.5, 'num_holes': 3, 'max_h_size': 25, 'max_w_size': 25 }, { 'name': 'jpeg', 'quality_lower': 70, 'quality_upper': 90 }, { 'name': 'motion_blur' }, { 'name': 'median_blur' }, { 'name': 'gamma' }, { 'name': 'rgb_shift' }, { 'name': 'hsv_shift' }, { 'name': 'sharpen' }]), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedAlbuTransForms', size=256, lq_key='img', gt_key='gt'), dict( type='AlbuCorruptFunction', keys=['img'], config=[{ 'name': 'cutout', 'prob': 0.5, 'num_holes': 3, 'max_h_size': 25, 'max_w_size': 25 }, { 'name': 'jpeg', 'quality_lower': 70, 'quality_upper': 90 }, { 'name': 'motion_blur' }, { 'name': 'median_blur' }, { 'name': 'gamma' }, { 'name': 'rgb_shift' }, { 'name': 'hsv_shift' }, { 'name': 'sharpen' }]), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='PackInputs') ] data_root = 'data/gopro' train_dataloader = dict( batch_size=1, num_workers=4, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/train', data_prefix=dict(img='input', gt='target'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/test', data_prefix=dict(img='input', gt='target'), pipeline=val_pipeline)) test_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root=data_root + '/test', data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=100) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') test_evaluator = val_evaluator # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.999))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.999))), ) # learning policy param_scheduler = dict( type='LinearLR', start_factor=0.0001, end_factor=0.0000001, begin=50, ) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=1000, save_optimizer=True, by_epoch=False, out_dir=save_dir, save_best='auto', ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=1), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) load_from = 'https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/'\ 'weight/DeblurGANv2_fpn-mobilenet.pth' ================================================ FILE: configs/deblurganv2/metafile.yml ================================================ Collections: - Name: DeblurGAN-v2 Paper: Title: 'DeblurGAN-v2: Deblurring (Orders-of-Magnitude) Faster and Better' URL: https://arxiv.org/abs/1908.03826 README: configs/deblurganv2/README.md Task: - deblurring Year: 2019 Models: - Config: configs/deblurganv2/deblurganv2_fpn-inception_1xb1_gopro.py In Collection: DeblurGAN-v2 Name: deblurganv2_fpn-inception_1xb1_gopro Results: - Dataset: GoProTestDataset Metrics: PSNR/
SSIM: PSNR: 29.55 SSIM: 0.934 Task: Deblurring Weights: https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-inception.pth - Config: configs/deblurganv2/deblurganv2_fpn-mobilenet_1xb1_gopro.py In Collection: DeblurGAN-v2 Name: deblurganv2_fpn-mobilenet_1xb1_gopro Results: - Dataset: GoProTestDataset Metrics: PSNR/
SSIM: PSNR: 28.17 SSIM: 0.925 Task: Deblurring Weights: https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/weight/DeblurGANv2_fpn-mobilenet.pth ================================================ FILE: configs/deepfillv1/README.md ================================================ # DeepFillv1 (CVPR'2018) > [Generative Image Inpainting with Contextual Attention](https://arxiv.org/abs/1801.07892) > **Task**: Inpainting ## Abstract Recent deep learning based approaches have shown promising results for the challenging task of inpainting large missing regions in an image. These methods can generate visually plausible image structures and textures, but often create distorted structures or blurry textures inconsistent with surrounding areas. This is mainly due to ineffectiveness of convolutional neural networks in explicitly borrowing or copying information from distant spatial locations. On the other hand, traditional texture and patch synthesis approaches are particularly suitable when it needs to borrow textures from the surrounding regions. Motivated by these observations, we propose a new deep generative model-based approach which can not only synthesize novel image structures but also explicitly utilize surrounding image features as references during network training to make better predictions. The model is a feed-forward, fully convolutional neural network which can process images with multiple holes at arbitrary locations and with variable sizes during the test time. Experiments on multiple datasets including faces (CelebA, CelebA-HQ), textures (DTD) and natural images (ImageNet, Places2) demonstrate that our proposed approach generates higher-quality inpainting results than existing ones.
## Results and models **CelebA-HQ** | Model | Mask Type | Resolution | Train Iters | Dataset | l1 error | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------: | :---------: | :--------: | :---------: | :--------: | :------: | :----: | :---: | :----------------: | :----------------------------------------------------------------------: | | [DeepFillv1](./deepfillv1_4xb4_celeba-256x256.py) | square bbox | 256x256 | 1500k | CelebA-val | 6.677 | 26.878 | 0.911 | 4 | [model](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_4x4_celeba_20200619-dd51a855.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_4x4_celeba_20200619-dd51a855.log.json) | **Places365-Challenge** | Model | Mask Type | Resolution | Train Iters | Dataset | l1 error | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------: | :---------: | :--------: | :---------: | :-----------: | :------: | :----: | :---: | :----------------: | :-------------------------------------------------------------------: | | [DeepFillv1](./deepfillv1_8xb2_places-256x256.py) | square bbox | 256x256 | 3500k | Places365-val | 11.019 | 23.429 | 0.862 | 8 | [model](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py # single-gpu train python tools/train.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py # multi-gpu train ./tools/dist_train.sh configs/deepfillv1/deepfillv1_8xb2_places-256x256.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth # single-gpu test python tools/test.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth # multi-gpu test ./tools/dist_test.sh configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{yu2018generative, title={Generative image inpainting with contextual attention}, author={Yu, Jiahui and Lin, Zhe and Yang, Jimei and Shen, Xiaohui and Lu, Xin and Huang, Thomas S}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={5505--5514}, year={2018} } ``` ================================================ FILE: configs/deepfillv1/README_zh-CN.md ================================================ # DeepFillv1 (CVPR'2018) > **任务**: 图像修复
DeepFillv1 (CVPR'2018) ```bibtex @inproceedings{yu2018generative, title={Generative image inpainting with contextual attention}, author={Yu, Jiahui and Lin, Zhe and Yang, Jimei and Shen, Xiaohui and Lu, Xin and Huang, Thomas S}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={5505--5514}, year={2018} } ```

**CelebA-HQ** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :-----------------------------------------------: | :---------: | :-----: | :--------: | :--------: | :-----: | :----: | :---: | :------: | :-------------------------------------------------------------------------------------: | | [DeepFillv1](./deepfillv1_4xb4_celeba-256x256.py) | square bbox | 256x256 | 1500k | CelebA-val | 6.677 | 26.878 | 0.911 | 4 | [模型](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_4x4_celeba_20200619-dd51a855.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_4x4_celeba_20200619-dd51a855.log.json) | **Places365-Challenge** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :-----------------------------------------------: | :---------: | :-----: | :--------: | :-----------: | :-----: | :----: | :---: | :------: | :----------------------------------------------------------------------------------: | | [DeepFillv1](./deepfillv1_8xb2_places-256x256.py) | square bbox | 256x256 | 3500k | Places365-val | 11.019 | 23.429 | 0.862 | 8 | [模型](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py # 单个GPU上训练 python tools/train.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py # 多个GPU上训练 ./tools/dist_train.sh configs/deepfillv1/deepfillv1_8xb2_places-256x256.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth # 单个GPU上测试 python tools/test.py configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth # 多个GPU上测试 ./tools/dist_test.sh configs/deepfillv1/deepfillv1_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/deepfillv1/deepfillv1_4xb4_celeba-256x256.py ================================================ _base_ = [ '../_base_/models/base_deepfillv1.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/celeba.py' ] experiment_name = 'deepfillv1_4xb4_celeba-256x256' save_dir = './work_dirs' model = dict( train_cfg=dict(disc_step=2, start_iter=0, local_size=(128, 128)), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='bbox', mask_config=dict( max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20, img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=4, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=1500003, val_interval=250000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') checkpoint = dict( type='CheckpointHook', interval=250000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/deepfillv1/deepfillv1_8xb2_places-256x256.py ================================================ _base_ = [ '../_base_/models/base_deepfillv1.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] experiment_name = 'deepfillv1_8xb2_places-256x256' save_dir = './work_dirs' model = dict(train_cfg=dict(disc_step=5, start_iter=0, local_size=(128, 128))) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='bbox', mask_config=dict( max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20, img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=2, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=5000003, val_interval=250000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') checkpoint = dict( type='CheckpointHook', interval=250000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/deepfillv1/metafile.yml ================================================ Collections: - Name: DeepFillv1 Paper: Title: Generative Image Inpainting with Contextual Attention URL: https://arxiv.org/abs/1801.07892 README: configs/deepfillv1/README.md Task: - inpainting Year: 2018 Models: - Config: configs/deepfillv1/deepfillv1_4xb4_celeba-256x256.py In Collection: DeepFillv1 Name: deepfillv1_4xb4_celeba-256x256 Results: - Dataset: CelebA-val Metrics: PSNR: 26.878 SSIM: 0.911 l1 error: 6.677 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_4x4_celeba_20200619-dd51a855.pth - Config: configs/deepfillv1/deepfillv1_8xb2_places-256x256.py In Collection: DeepFillv1 Name: deepfillv1_8xb2_places-256x256 Results: - Dataset: Places365-val Metrics: PSNR: 23.429 SSIM: 0.862 l1 error: 11.019 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/deepfillv1/deepfillv1_256x256_8x2_places_20200619-c00a0e21.pth ================================================ FILE: configs/deepfillv2/README.md ================================================ # DeepFillv2 (CVPR'2019) > [Free-Form Image Inpainting with Gated Convolution](https://arxiv.org/abs/1806.03589) > **Task**: Inpainting ## Abstract We present a generative image inpainting system to complete images with free-form mask and guidance. The system is based on gated convolutions learned from millions of images without additional labelling efforts. The proposed gated convolution solves the issue of vanilla convolution that treats all input pixels as valid ones, generalizes partial convolution by providing a learnable dynamic feature selection mechanism for each channel at each spatial location across all layers. Moreover, as free-form masks may appear anywhere in images with any shape, global and local GANs designed for a single rectangular mask are not applicable. Thus, we also present a patch-based GAN loss, named SN-PatchGAN, by applying spectral-normalized discriminator on dense image patches. SN-PatchGAN is simple in formulation, fast and stable in training. Results on automatic image inpainting and user-guided extension demonstrate that our system generates higher-quality and more flexible results than previous methods. Our system helps user quickly remove distracting objects, modify image layouts, clear watermarks and edit faces.
## Results and models **CelebA-HQ** | Model | Mask Type | Resolution | Train Iters | Dataset | l1 error | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------: | :-------: | :--------: | :---------: | :--------: | :------: | :----: | :---: | :----------------: | :------------------------------------------------------------------------: | | [DeepFillv2](./deepfillv2_8xb2_celeba-256x256.py) | free-form | 256x256 | 20k | CelebA-val | 5.411 | 25.721 | 0.871 | 8 | [model](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.log.json) | **Places365-Challenge** | Model | Mask Type | Resolution | Train Iters | Dataset | l1 error | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------: | :-------: | :--------: | :---------: | :-----------: | :------: | :----: | :---: | :----------------: | :---------------------------------------------------------------------: | | [DeepFillv2](./deepfillv2_8xb2_places-256x256.py) | free-form | 256x256 | 100k | Places365-val | 8.635 | 22.398 | 0.815 | 8 | [model](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py # single-gpu train python tools/train.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py # multi-gpu train ./tools/dist_train.sh configs/deepfillv2/deepfillv2_8xb2_places-256x256.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth # single-gpu test python tools/test.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth # multi-gpu test ./tools/dist_test.sh configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{yu2019free, title={Free-form image inpainting with gated convolution}, author={Yu, Jiahui and Lin, Zhe and Yang, Jimei and Shen, Xiaohui and Lu, Xin and Huang, Thomas S}, booktitle={Proceedings of the IEEE International Conference on Computer Vision}, pages={4471--4480}, year={2019} } ``` ================================================ FILE: configs/deepfillv2/README_zh-CN.md ================================================ # DeepFillv2 (CVPR'2019) > **任务**: 图像修复
DeepFillv2 (CVPR'2019) ```bibtex @inproceedings{yu2019free, title={Free-form image inpainting with gated convolution}, author={Yu, Jiahui and Lin, Zhe and Yang, Jimei and Shen, Xiaohui and Lu, Xin and Huang, Thomas S}, booktitle={Proceedings of the IEEE International Conference on Computer Vision}, pages={4471--4480}, year={2019} } ```

**CelebA-HQ** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :-----------------------------------------------: | :-------: | :-----: | :--------: | :--------: | :-----: | :----: | :---: | :------: | :---------------------------------------------------------------------------------------: | | [DeepFillv2](./deepfillv2_8xb2_celeba-256x256.py) | free-form | 256x256 | 20k | CelebA-val | 5.411 | 25.721 | 0.871 | 8 | [模型](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.log.json) | **Places365-Challenge** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :-----------------------------------------------: | :-------: | :-----: | :--------: | :-----------: | :-----: | :----: | :---: | :------: | :------------------------------------------------------------------------------------: | | [DeepFillv2](./deepfillv2_8xb2_places-256x256.py) | free-form | 256x256 | 100k | Places365-val | 8.635 | 22.398 | 0.815 | 8 | [模型](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py # 单个GPU上训练 python tools/train.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py # 多个GPU上训练 ./tools/dist_train.sh configs/deepfillv2/deepfillv2_8xb2_places-256x256.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth # 单个GPU上测试 python tools/test.py configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth # 多个GPU上测试 ./tools/dist_test.sh configs/deepfillv2/deepfillv2_8xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/deepfillv2/deepfillv2_8xb2_celeba-256x256.py ================================================ _base_ = [ '../_base_/models/base_deepfillv2.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/celeba.py' ] save_dir = './work_dirs' experiment_name = 'deepfillv2_8xb2_celeba-256x256' model = dict(train_cfg=dict(disc_step=1, start_iter=0)) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=2, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline)) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=500003, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') checkpoint = dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/deepfillv2/deepfillv2_8xb2_places-256x256.py ================================================ _base_ = [ '../_base_/models/base_deepfillv2.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] save_dir = './work_dirs' experiment_name = 'deepfillv2_8xb2_places-256x256' model = dict(train_cfg=dict(disc_step=1, start_iter=0)) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=2, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline)) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=1000003, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') checkpoint = dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/deepfillv2/metafile.yml ================================================ Collections: - Name: DeepFillv2 Paper: Title: Free-Form Image Inpainting with Gated Convolution URL: https://arxiv.org/abs/1806.03589 README: configs/deepfillv2/README.md Task: - inpainting Year: 2019 Models: - Config: configs/deepfillv2/deepfillv2_8xb2_celeba-256x256.py In Collection: DeepFillv2 Name: deepfillv2_8xb2_celeba-256x256 Results: - Dataset: CelebA-val Metrics: PSNR: 25.721 SSIM: 0.871 l1 error: 5.411 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_celeba_20200619-c96e5f12.pth - Config: configs/deepfillv2/deepfillv2_8xb2_places-256x256.py In Collection: DeepFillv2 Name: deepfillv2_8xb2_places-256x256 Results: - Dataset: Places365-val Metrics: PSNR: 22.398 SSIM: 0.815 l1 error: 8.635 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/deepfillv2/deepfillv2_256x256_8x2_places_20200619-10d15793.pth ================================================ FILE: configs/dic/README.md ================================================ # DIC (CVPR'2020) > [Deep Face Super-Resolution with Iterative Collaboration between Attentive Recovery and Landmark Estimation](https://arxiv.org/abs/2003.13063) > **Task**: Image Super-Resolution ## Abstract Recent works based on deep learning and facial priors have succeeded in super-resolving severely degraded facial images. However, the prior knowledge is not fully exploited in existing methods, since facial priors such as landmark and component maps are always estimated by low-resolution or coarsely super-resolved images, which may be inaccurate and thus affect the recovery performance. In this paper, we propose a deep face super-resolution (FSR) method with iterative collaboration between two recurrent networks which focus on facial image recovery and landmark estimation respectively. In each recurrent step, the recovery branch utilizes the prior knowledge of landmarks to yield higher-quality images which facilitate more accurate landmark estimation in turn. Therefore, the iterative information interaction between two processes boosts the performance of each other progressively. Moreover, a new attentive fusion module is designed to strengthen the guidance of landmark maps, where facial components are generated individually and aggregated attentively for better restoration. Quantitative and qualitative experimental results show the proposed method significantly outperforms state-of-the-art FSR methods in recovering high-quality face images.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . In the log data of `dic_gan_x8c48b6_g4_150k_CelebAHQ`, DICGAN is verified on the first 9 pictures of the test set of CelebA-HQ, so `PSNR` and `SSIM` shown in the follow table is different from the log data. `Training Resources`: Training Resourcesrmation during training. | Model | Dataset | scale | PSNR | SSIM | Training Resources | Download | | :--------------------------------------------------------------------------: | :------: | :---: | :-----: | :----: | :-----------------: | :-----------------------------------------------------------------------------: | | [dic_x8c48b6_g4_150k_CelebAHQ](./dic_x8c48b6_4xb2-150k_celeba-hq.py) | CelebAHQ | x8 | 25.2319 | 0.7422 | 4 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/restorers/dic/dic_x8c48b6_g4_150k_CelebAHQ_20210611-5d3439ca.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/dic/dic_x8c48b6_g4_150k_CelebAHQ_20210611-5d3439ca.log.json) | | [dic_gan_x8c48b6_g4_500k_CelebAHQ](./dic_gan-x8c48b6_4xb2-500k_celeba-hq.py) | CelebAHQ | x8 | 23.6241 | 0.6721 | 4 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py # single-gpu train python tools/train.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py # multi-gpu train ./tools/dist_train.sh configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth # single-gpu test python tools/test.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth # multi-gpu test ./tools/dist_test.sh configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{ma2020deep, title={Deep face super-resolution with iterative collaboration between attentive recovery and landmark estimation}, author={Ma, Cheng and Jiang, Zhenyu and Rao, Yongming and Lu, Jiwen and Zhou, Jie}, booktitle={Proceedings of the IEEE/CVF conference on computer vision and pattern recognition}, pages={5569--5578}, year={2020} } ``` ================================================ FILE: configs/dic/README_zh-CN.md ================================================ # DIC (CVPR'2020) > **任务**: 图像超分辨率
DIC (CVPR'2020) ```bibtex @inproceedings{ma2020deep, title={Deep face super-resolution with iterative collaboration between attentive recovery and landmark estimation}, author={Ma, Cheng and Jiang, Zhenyu and Rao, Yongming and Lu, Jiwen and Zhou, Jie}, booktitle={Proceedings of the IEEE/CVF conference on computer vision and pattern recognition}, pages={5569--5578}, year={2020} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 在 `dic_gan_x8c48b6_g4_150k_CelebAHQ` 的日志中,DICGAN 在 CelebA-HQ 测试集的前9张图片上进行了验证,因此下表中的 `PSNR/SSIM` 与日志数据不同。 `GPU 信息`: 训练过程中的 GPU 信息. | 算法 | scale | CelebA-HQ | GPU 信息 | 下载 | | :--------------------------------------------------------------------------: | :---: | :--------------: | :-----------------: | :----------------------------------------------------------------------------------: | | [dic_x8c48b6_g4_150k_CelebAHQ](./dic_x8c48b6_4xb2-150k_celeba-hq.py) | x8 | 25.2319 / 0.7422 | 4 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/restorers/dic/dic_x8c48b6_g4_150k_CelebAHQ_20210611-5d3439ca.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/dic/dic_x8c48b6_g4_150k_CelebAHQ_20210611-5d3439ca.log.json) | | [dic_gan_x8c48b6_g4_500k_CelebAHQ](./dic_gan-x8c48b6_4xb2-500k_celeba-hq.py) | x8 | 23.6241 / 0.6721 | 4 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py # 单个GPU上训练 python tools/train.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py # 多个GPU上训练 ./tools/dist_train.sh configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth # 单个GPU上测试 python tools/test.py configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth # 多个GPU上测试 ./tools/dist_test.sh configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py ================================================ _base_ = './dic_x8c48b6_4xb2-150k_celeba-hq.py' experiment_name = 'dic_gan-x8c48b6_4xb2-500k_celeba-hq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 8 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings pretrained_light_cnn = 'https://download.openmmlab.com/mmediting/' + \ 'restorers/dic/light_cnn_feature.pth' model = dict( type='DIC', generator=dict( type='DICNet', in_channels=3, out_channels=3, mid_channels=48), discriminator=dict(type='LightCNN', in_channels=3), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), align_loss=dict(type='MSELoss', loss_weight=0.1, reduction='mean'), feature_loss=dict( type='LightCNNFeatureLoss', pretrained=pretrained_light_cnn, loss_weight=0.1, criterion='l1'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.005, real_label_val=1.0, fake_label_val=0), train_cfg=dict(pixel_init=10000, disc_repeat=2), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[129.795, 108.12, 96.39], std=[255, 255, 255], )) train_cfg = dict( type='IterBasedTrainLoop', max_iters=500_000, val_interval=5000) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4)), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-5))) # learning policy param_scheduler = dict( _delete_=True, type='MultiStepLR', by_epoch=False, milestones=[100000, 200000, 300000, 400000], gamma=0.5) ================================================ FILE: configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'dic_x8c48b6_4xb2-150k_celeba-hq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 8 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings model = dict( type='DIC', generator=dict( type='DICNet', in_channels=3, out_channels=3, mid_channels=48), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), align_loss=dict(type='MSELoss', loss_weight=0.1, reduction='mean'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[129.795, 108.12, 96.39], std=[255, 255, 255], )) train_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Resize', scale=(128, 128), keys=['gt'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=1 / 8, keep_ratio=True, keys=['gt'], output_keys=['img'], interpolation='bicubic', backend='pillow'), dict( type='GenerateFacialHeatmap', image_key='gt', ori_size=128, target_size=32, sigma=1.0), dict(type='PackInputs') ] valid_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Resize', scale=(128, 128), keys=['gt'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=1 / 8, keep_ratio=True, keys=['gt'], output_keys=['img'], interpolation='bicubic', backend='pillow'), dict(type='PackInputs') ] test_pipeline = valid_pipeline inference_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Resize', scale=(128, 128), keys=['img'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=1 / 8, keep_ratio=True, keys=['img'], output_keys=['img'], interpolation='bicubic', backend='pillow'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=2, # gpus 4 persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='celeba', task_name='fsr'), data_root=data_root + '/CelebA-HQ', data_prefix=dict(gt='train_256/all_256'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='celeba', task_name='fsr'), data_root=data_root + '/CelebA-HQ', data_prefix=dict(gt='test_256/all_256'), pipeline=test_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=150_000, val_interval=2000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[10000, 20000, 40000, 80000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=2000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/dic/metafile.yml ================================================ Collections: - Name: DIC Paper: Title: Deep Face Super-Resolution with Iterative Collaboration between Attentive Recovery and Landmark Estimation URL: https://arxiv.org/abs/2003.13063 README: configs/dic/README.md Task: - image super-resolution Year: 2020 Models: - Config: configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py In Collection: DIC Name: dic_x8c48b6_4xb2-150k_celeba-hq Results: - Dataset: CelebAHQ Metrics: PSNR: 25.2319 SSIM: 0.7422 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/dic/dic_x8c48b6_g4_150k_CelebAHQ_20210611-5d3439ca.pth - Config: configs/dic/dic_gan-x8c48b6_4xb2-500k_celeba-hq.py In Collection: DIC Name: dic_gan-x8c48b6_4xb2-500k_celeba-hq Results: - Dataset: CelebAHQ Metrics: PSNR: 23.6241 SSIM: 0.6721 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/dic/dic_gan_x8c48b6_g4_500k_CelebAHQ_20210625-3b89a358.pth ================================================ FILE: configs/diffusers_pipeline/README.md ================================================ # Diffusers Pipeline (2023) > [Diffusers Pipeline](https://github.com/huggingface/diffusers) > **Task**: Diffusers Pipeline ## Abstract For the convenience of our community users, this inferencer supports using the pipelines from diffusers for inference to compare the results with the algorithms supported within our algorithm library. ## Configs | Model | Dataset | Download | | :---------------------------------------: | :-----: | :------: | | [diffusers pipeline](./sd_xl_pipeline.py) | - | - | ## Quick Start ### sd_xl_pipeline To run stable diffusion XL with mmagic inference API, follow these codes: ```python from mmagic.apis import MMagicInferencer # Create a MMEdit instance and infer editor = MMagicInferencer(model_name='diffusers_pipeline') text_prompts = 'Japanese anime style, girl, beautiful, cute, colorful, best quality, extremely detailed' negative_prompt = 'bad face, bad hands' result_out_dir = 'sd_xl_japanese.png' editor.infer(text=text_prompts, negative_prompt=negative_prompt, result_out_dir=result_out_dir) ``` You will get this picture:
## Citation ```bibtex @misc{von-platen-etal-2022-diffusers, author = {Patrick von Platen and Suraj Patil and Anton Lozhkov and Pedro Cuenca and Nathan Lambert and Kashif Rasul and Mishig Davaadorj and Thomas Wolf}, title = {Diffusers: State-of-the-art diffusion models}, year = {2022}, publisher = {GitHub}, journal = {GitHub repository}, howpublished = {\url{https://github.com/huggingface/diffusers}} } ``` ================================================ FILE: configs/diffusers_pipeline/metafile.yml ================================================ Collections: - Name: Diffusers Pipeline Paper: Title: Diffusers Pipeline URL: https://github.com/huggingface/diffusers README: configs/diffusers_pipeline/README.md Task: - diffusers pipeline Year: 2023 Models: - Config: configs/diffusers_pipeline/sd_xl_pipeline.py In Collection: Diffusers Pipeline Name: sd_xl_pipeline Results: - Dataset: '-' Metrics: {} Task: Diffusers Pipeline ================================================ FILE: configs/diffusers_pipeline/sd_xl_pipeline.py ================================================ # config for model model = dict( type='DiffusionPipeline', from_pretrained='stabilityai/stable-diffusion-xl-base-1.0') ================================================ FILE: configs/dim/README.md ================================================ # DIM (CVPR'2017) > [Deep Image Matting](https://arxiv.org/abs/1703.03872) > **Task**: Matting ## Abstract Image matting is a fundamental computer vision problem and has many applications. Previous algorithms have poor performance when an image has similar foreground and background colors or complicated textures. The main reasons are prior methods 1) only use low-level features and 2) lack high-level context. In this paper, we propose a novel deep learning based algorithm that can tackle both these problems. Our deep model has two parts. The first part is a deep convolutional encoder-decoder network that takes an image and the corresponding trimap as inputs and predict the alpha matte of the image. The second part is a small convolutional network that refines the alpha matte predictions of the first network to have more accurate alpha values and sharper edges. In addition, we also create a large-scale image matting dataset including 49300 training images and 1000 testing images. We evaluate our algorithm on the image matting benchmark, our testing set, and a wide variety of real images. Experimental results clearly demonstrate the superiority of our algorithm over previous methods.
## Results and models | Model | Dataset | SAD | MSE | GRAD | CONN | Training Resources | Download | | :--------------------------------------------------------------------: | :------------: | :--: | :---: | :------: | :------: | :----------------: | :-----------------------------------------------------------------------: | | [stage1 (our)](./dim_stage1-v16_1xb1-1000k_comp1k.py) | Composition-1k | 53.8 | 0.017 | 32.7 | 54.5 | 1 | [model](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage1_v16_1x1_1000k_comp1k_SAD-53.8_20200605_140257-979a420f.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage1_v16_1x1_1000k_comp1k_20200605_140257.log.json) | | [stage2 (our)](./dim_stage2-v16-pln_1xb1-1000k_comp1k.py) | Composition-1k | 52.3 | 0.016 | 29.4 | 52.4 | 1 | [model](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage2_v16_pln_1x1_1000k_comp1k_SAD-52.3_20200607_171909-d83c4775.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage2_v16_pln_1x1_1000k_comp1k_20200607_171909.log.json) | | [stage3 (our)](./dim_stage3-v16-pln_1xb1-1000k_comp1k.py) | Composition-1k | 50.6 | 0.015 | **29.0** | **50.7** | 1 | [model](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_20200609_111851.log.json) | | [stage1 (online merge)](./dim_stage1-v16_1xb1-1000k_comp1k_online-merge.py) | Composition-1k | - | - | - | - | - | - | **NOTE** - stage1: train the encoder-decoder part without the refinement part. - stage2: fix the encoder-decoder part and train the refinement part. - stage3: fine-tune the whole network. > The performance of the model is not stable during the training. Thus, the reported performance is not from the last checkpoint. Instead, it is the best performance of all validations during training. > The performance of training (best performance) with different random seeds diverges in a large range. You may need to run several experiments for each setting to obtain the above performance. ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. DIM is trained with three stages. **Stage 1**: train the encoder-decoder part without the refinement part. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py # single-gpu train python tools/train.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py # multi-gpu train ./tools/dist_train.sh configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py 8 ``` **Stage 2**: fix the encoder-decoder part and train the refinement part. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py # single-gpu train python tools/train.py configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py # multi-gpu train ./tools/dist_train.sh configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py 8 ``` **Stage 3**: fine-tune the whole network. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py # single-gpu train python tools/train.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py # multi-gpu train ./tools/dist_train.sh configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth # single-gpu test python tools/test.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth # multi-gpu test ./tools/dist_test.sh configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{xu2017deep, title={Deep image matting}, author={Xu, Ning and Price, Brian and Cohen, Scott and Huang, Thomas}, booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, pages={2970--2979}, year={2017} } ``` ================================================ FILE: configs/dim/README_zh-CN.md ================================================ # DIM (CVPR'2017) > **任务**: 图像抠图
DIM (CVPR'2017) ```bibtex @inproceedings{xu2017deep, title={Deep image matting}, author={Xu, Ning and Price, Brian and Cohen, Scott and Huang, Thomas}, booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, pages={2970--2979}, year={2017} } ```

| 算法 | SAD | MSE | GRAD | CONN | GPU 信息 | 下载 | | :---------------------------------------------------------------------------: | :------: | :-------: | :------: | :------: | :------: | :--------------------------------------------------------------------------------: | | 第一阶段 (原文) | 54.6 | 0.017 | 36.7 | 55.3 | - | - | | 第三阶段 (原文) | **50.4** | **0.014** | 31.0 | 50.8 | - | - | | [第一阶段 (复现)](./dim_stage1-v16_1xb1-1000k_comp1k.py) | 53.8 | 0.017 | 32.7 | 54.5 | 1 | [模型](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage1_v16_1x1_1000k_comp1k_SAD-53.8_20200605_140257-979a420f.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage1_v16_1x1_1000k_comp1k_20200605_140257.log.json) | | [第二阶段 (复现)](./dim_stage2-v16-pln_1xb1-1000k_comp1k.py) | 52.3 | 0.016 | 29.4 | 52.4 | 1 | [模型](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage2_v16_pln_1x1_1000k_comp1k_SAD-52.3_20200607_171909-d83c4775.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage2_v16_pln_1x1_1000k_comp1k_20200607_171909.log.json) | | [第三阶段 (复现)](./dim_stage3-v16-pln_1xb1-1000k_comp1k.py) | 50.6 | 0.015 | **29.0** | **50.7** | 1 | [模型](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_20200609_111851.log.json) | | [第一阶段 (online merge)](./dim_stage1-v16_1xb1-1000k_comp1k_online-merge.py) | - | - | - | - | - | - | **注** - 第一阶段:训练不带精炼器的编码器-解码器部分。 \\ - 第二阶段:固定编码器-解码器部分,训练精炼器部分。 \\ - 第三阶段:微调整个网络模型。 > 模型在训练过程中的性能不稳定。因此,展示的性能并非来自最后一个模型权重文件,而是训练期间在验证集上取得的最佳性能。 > 不同随机种子的训练性能(最佳性能)的发散程度很大,您可能需要为每个设置运行多个实验以获得上述性能。 ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 DIM 训练有三个阶段。 **阶段 1**: 训练不带精炼器的编码器-解码器部分。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py # 单个GPU上训练 python tools/train.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py # 多个GPU上训练 ./tools/dist_train.sh configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py 8 ``` **阶段 2**: 固定编码器-解码器部分,训练精炼器部分。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py # 单个GPU上训练 python tools/train.py configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py # 多个GPU上训练 ./tools/dist_train.sh configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py 8 ``` **阶段 3**: 微调整个网络模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py # 单个GPU上训练 python tools/train.py configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py # 多个GPU上训练 ./tools/dist_train.sh configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py onfigs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth # 单个GPU上测试 python tools/test.py onfigs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth # 多个GPU上测试 ./tools/dist_test.sh onfigs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py ================================================ _base_ = [ '../_base_/datasets/comp1k.py', '../_base_/matting_default_runtime.py' ] save_dir = './work_dirs/' experiment_name = 'dim_stage1-v16_1xb1-1000k_comp1k' # model settings model = dict( type='DIM', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='VGG16', in_channels=4, init_cfg=dict( type='Pretrained', checkpoint='open-mmlab://mmedit/vgg16')), decoder=dict(type='PlainDecoder')), loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5), loss_comp=dict(type='CharbonnierCompLoss', loss_weight=0.5), train_cfg=dict(train_backbone=True, train_refiner=False), test_cfg=dict( refine=False, resize_method='pad', resize_mode='reflect', size_divisor=32, ), ) train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='LoadImageFromFile', key='bg'), dict(type='LoadImageFromFile', key='merged'), dict( type='CropAroundUnknown', keys=['alpha', 'merged', 'fg', 'bg'], crop_sizes=[320, 480, 640]), dict(type='Flip', keys=['alpha', 'merged', 'fg', 'bg']), dict( type='Resize', keys=['alpha', 'merged', 'fg', 'bg'], scale=(320, 320), keep_ratio=False), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='PackInputs'), ] train_dataloader = dict(batch_size=1, dataset=dict(pipeline=train_pipeline)) val_dataloader = dict(batch_size=1, dataset=dict(pipeline=test_pipeline)) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=40000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) # checkpoint saving default_hooks = dict( checkpoint=dict(type='CheckpointHook', interval=40000, out_dir=save_dir)) ================================================ FILE: configs/dim/dim_stage1-v16_1xb1-1000k_comp1k_online-merge.py ================================================ _base_ = ['./dim_stage1-v16_1xb1-1000k_comp1k.py'] save_dir = './work_dirs/' experiment_name = 'dim_stage1-v16_1xb1-1000k_comp1k_online-merge' # dataset settings train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='LoadImageFromFile', key='bg'), dict(type='MergeFgAndBg'), dict( type='CropAroundUnknown', keys=['alpha', 'merged', 'fg', 'bg'], crop_sizes=[320, 480, 640]), dict(type='Flip', keys=['alpha', 'merged', 'fg', 'bg']), dict( type='Resize', keys=['alpha', 'merged', 'fg', 'bg'], scale=(320, 320), keep_ratio=False), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='PackInputs'), ] train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) ================================================ FILE: configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py ================================================ _base_ = ['./dim_stage1-v16_1xb1-1000k_comp1k.py'] save_dir = './work_dirs/' experiment_name = 'dim_stage2-v16-pln_1xb1-1000k_comp1k' # model settings model = dict( refiner=dict(type='PlainRefiner'), loss_refine=dict(type='CharbonnierLoss'), train_cfg=dict(train_backbone=False, train_refiner=True), test_cfg=dict(refine=True), ) # load_from = \ # 'https://download.openmmlab.com/mmediting/mattors/dim/'\ # 'dim_stage1_v16_1x1_1000k_comp1k_SAD-53.8_20200605_140257-979a420f.pth' ================================================ FILE: configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py ================================================ _base_ = ['./dim_stage1-v16_1xb1-1000k_comp1k.py'] save_dir = './work_dirs' experiment_name = 'dim_stage3-v16-pln_1xb1-1000k_comp1k' # model settings model = dict( refiner=dict(type='PlainRefiner'), loss_refine=dict(type='CharbonnierLoss'), train_cfg=dict(train_backbone=True, train_refiner=True), test_cfg=dict(refine=True), ) # load_from = \ # 'https://download.openmmlab.com/mmediting/mattors/dim/'\ # 'dim_stage2_v16_pln_1x1_1000k_comp1k_SAD-52.3_20200607_171909-d83c4775.pth' ================================================ FILE: configs/dim/metafile.yml ================================================ Collections: - Name: DIM Paper: Title: Deep Image Matting URL: https://arxiv.org/abs/1703.03872 README: configs/dim/README.md Task: - matting Year: 2017 Models: - Config: configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py In Collection: DIM Name: dim_stage1-v16_1xb1-1000k_comp1k Results: - Dataset: Composition-1k Metrics: CONN: 54.5 GRAD: 32.7 MSE: 0.017 SAD: 53.8 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/dim/dim_stage1_v16_1x1_1000k_comp1k_SAD-53.8_20200605_140257-979a420f.pth - Config: configs/dim/dim_stage2-v16-pln_1xb1-1000k_comp1k.py In Collection: DIM Name: dim_stage2-v16-pln_1xb1-1000k_comp1k Results: - Dataset: Composition-1k Metrics: CONN: 52.4 GRAD: 29.4 MSE: 0.016 SAD: 52.3 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/dim/dim_stage2_v16_pln_1x1_1000k_comp1k_SAD-52.3_20200607_171909-d83c4775.pth - Config: configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py In Collection: DIM Name: dim_stage3-v16-pln_1xb1-1000k_comp1k Results: - Dataset: Composition-1k Metrics: CONN: 50.7 GRAD: 29.0 MSE: 0.015 SAD: 50.6 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/dim/dim_stage3_v16_pln_1x1_1000k_comp1k_SAD-50.6_20200609_111851-647f24b6.pth - Config: configs/dim/dim_stage1-v16_1xb1-1000k_comp1k_online-merge.py In Collection: DIM Name: dim_stage1-v16_1xb1-1000k_comp1k_online-merge Results: - Dataset: Composition-1k Metrics: {} Task: Matting ================================================ FILE: configs/disco_diffusion/README.md ================================================ # Disco Diffusion (2022) > [Disco Diffusion](https://github.com/alembics/disco-diffusion) > **Task**: Text2Image, Image2Image ## Abstract Disco Diffusion (DD) is a Google Colab Notebook which leverages an AI Image generating technique called CLIP-Guided Diffusion to allow you to create compelling and beautiful images from text inputs. Created by Somnai, augmented by Gandamu, and building on the work of RiversHaveWings, nshepperd, and many others. See more details in [Credits](#credits).
## Results and models We have converted several `unet` weights and offer related configs. See more details of different `unet` in [Tutorial](#tutorials). | Model | Dataset | Task | Download | | :---------------------------------------------------------------------------------------: | :------: | :--------: | :-------------------------------------------------------------------------------------------: | | [512x512_diffusion_uncond_finetune_008100](./disco-diffusion_adm-u-finetuned_imagenet-512x512.py) | ImageNet | Text2Image | [model](https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth) | | [256x256_diffusion_uncond](./disco-diffusion_adm-u-finetuned_imagenet-256x256.py) | ImageNet | Text2Image | [model](<>) | | [portrait_generator_v001](./disco-diffusion_portrait-generator-v001.py) | unknown | Text2Image | [model](https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_portrait-v001-f4a3f3bc.pth) | | Model | Download | | :--------------------------: | :----------: | | pixelartdiffusion_expanded | Coming soon! | | pixel_art_diffusion_hard_256 | Coming soon! | | pixel_art_diffusion_soft_256 | Coming soon! | | pixelartdiffusion4k | Coming soon! | | watercolordiffusion_2 | Coming soon! | | watercolordiffusion | Coming soon! | | PulpSciFiDiffusion | Coming soon! | ## To-do List - [x] Text2Image - [x] Image2Image - [x] Imagenet, portrait diffusion models - [ ] pixelart, watercolor, sci-fiction diffusion models - [ ] image prompt - [ ] video generation - [ ] faster sampler(plms, dpm-solver etc.) We really welcome community users supporting these items and any other interesting stuffs! ## Quick Start Running the following codes, you can get a text-generated image. ```python from mmengine import Config, MODELS from mmengine.registry import init_default_scope from torchvision.utils import save_image init_default_scope('mmagic') disco = MODELS.build( Config.fromfile('configs/disco_diffusion/disco-baseline.py').model).cuda().eval() text_prompts = { 0: [ "A beautiful painting of a singular lighthouse, shining its light across a tumultuous sea of blood by greg rutkowski and thomas kinkade, Trending on artstation.", "yellow color scheme" ] } image = disco.infer( height=768, width=1280, text_prompts=text_prompts, show_progress=True, num_inference_steps=250, eta=0.8)['samples'] save_image(image, "image.png") ``` ## Tutorials Considering that `disco-diffusion` contains many adjustable parameters, we provide users with a [jupyter-notebook](./tutorials.ipynb) / [colab](https://githubtocolab.com/open-mmlab/mmagic/blob/main/configs/disco_diffusion/tutorials.ipynb) tutorial that exhibits the meaning of different parameters, and gives results corresponding to adjustment. Refer to [Disco Sheet](https://docs.google.com/document/d/1l8s7uS2dGqjztYSjPpzlmXLjl5PM3IGkRWI3IiCuK7g/edit). ## Credits Since our adaptation of disco-diffusion are heavily influenced by disco [colab](https://colab.research.google.com/github/alembics/disco-diffusion/blob/main/Disco_Diffusion.ipynb#scrollTo=License), here we copy the credits below.
Credits Original notebook by Katherine Crowson (https://github.com/crowsonkb, https://twitter.com/RiversHaveWings). It uses either OpenAI's 256x256 unconditional ImageNet or Katherine Crowson's fine-tuned 512x512 diffusion model (https://github.com/openai/guided-diffusion), together with CLIP (https://github.com/openai/CLIP) to connect text prompts with images. Modified by Daniel Russell (https://github.com/russelldc, https://twitter.com/danielrussruss) to include (hopefully) optimal params for quick generations in 15-100 timesteps rather than 1000, as well as more robust augmentations. Further improvements from Dango233 and nshepperd helped improve the quality of diffusion in general, and especially so for shorter runs like this notebook aims to achieve. Vark added code to load in multiple Clip models at once, which all prompts are evaluated against, which may greatly improve accuracy. The latest zoom, pan, rotation, and keyframes features were taken from Chigozie Nri's VQGAN Zoom Notebook (https://github.com/chigozienri, https://twitter.com/chigozienri) Advanced DangoCutn Cutout method is also from Dango223. \-- Disco: Somnai (https://twitter.com/Somnai_dreams) added Diffusion Animation techniques, QoL improvements and various implementations of tech and techniques, mostly listed in the changelog below. 3D animation implementation added by Adam Letts (https://twitter.com/gandamu_ml) in collaboration with Somnai. Creation of disco.py and ongoing maintenance. Turbo feature by Chris Allen (https://twitter.com/zippy731) Improvements to ability to run on local systems, Windows support, and dependency installation by HostsServer (https://twitter.com/HostsServer) VR Mode by Tom Mason (https://twitter.com/nin_artificial) Horizontal and Vertical symmetry functionality by nshepperd. Symmetry transformation_steps by huemin (https://twitter.com/huemin_art). Symmetry integration into Disco Diffusion by Dmitrii Tochilkin (https://twitter.com/cut_pow). Warp and custom model support by Alex Spirin (https://twitter.com/devdef). Pixel Art Diffusion, Watercolor Diffusion, and Pulp SciFi Diffusion models from KaliYuga (https://twitter.com/KaliYuga_ai). Follow KaliYuga's Twitter for the latest models and for notebooks with specialized settings. Integration of OpenCLIP models and initiation of integration of KaliYuga models by Palmweaver / Chris Scalf (https://twitter.com/ChrisScalf11) Integrated portrait_generator_v001 from Felipe3DArtist (https://twitter.com/Felipe3DArtist)
## Citation ```bibtex @misc{github, author={alembics}, title={disco-diffusion}, year={2022}, url={https://github.com/alembics/disco-diffusion}, } ``` ================================================ FILE: configs/disco_diffusion/README_zh-CN.md ================================================ # Disco Diffusion (2022) > [Disco Diffusion](https://github.com/alembics/disco-diffusion) > **任务**: 图文生成, 图像到图像的翻译, 扩散模型 ## 摘要 Disco Diffusion(DD)是一个 Google Colab 笔记本,它利用一种叫做 CLIP-Guided Diffusion 的人工智能图像生成技术,让你从文本输入中创造出引人注目的精美图像。 由 Somnai 创建,由 Gandamu 改进,并建立在 RiversHaveWings、nshepperd 和许多其他人的工作之上。更多细节见[Credits](#credits)。
## 模型与结果 我们已经转换了几个 `unet` 的权重,并提供相关的配置文件。在[Tutorial](#tutorials)中可以看到更多关于不同 `unet` 的细节。 | 模型 | 数据集 | 下载 | | :----------------------------------------------------------------------------------------------: | :------: | :----------------------------------------------------------------------------------------------: | | [512x512_diffusion_uncond_finetune_008100](./disco-diffusion_adm-u-finetuned_imagenet-512x512.py) | ImageNet | [model](https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth) | | [256x256_diffusion_uncond](./disco-diffusion_adm-u-finetuned_imagenet-256x256.py) | ImageNet | [model](<>) | | [portrait_generator_v001](./disco-diffusion_portrait-generator-v001.py) | unknown | [model](https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_portrait-v001-f4a3f3bc.pth) | | 模型 | 下载 | | :--------------------------: | :----------: | | pixelartdiffusion_expanded | Coming soon! | | pixel_art_diffusion_hard_256 | Coming soon! | | pixel_art_diffusion_soft_256 | Coming soon! | | pixelartdiffusion4k | Coming soon! | | watercolordiffusion_2 | Coming soon! | | watercolordiffusion | Coming soon! | | PulpSciFiDiffusion | Coming soon! | ## 待办列表 - [x] 图文生成 - [x] 图像到图像的翻译 - [x] Imagenet, portrait 扩散模型 - \[\] 像素艺术,水彩,科幻小说的扩散模型 - \[\] 支持图像提示 - \[\] 支持视频生成 - \[\] 支持更快的采样器(plms,dpm-solver等) 我们很欢迎社区用户支持这些项目和任何其他有趣的工作! ## Quick Start 运行以下代码,你可以使用文本生成图像。 ```python from mmengine import Config, MODELS from mmagic.utils import register_all_modules from torchvision.utils import save_image register_all_modules() disco = MODELS.build( Config.fromfile('configs/disco_diffusion/disco-baseline.py').model).cuda().eval() text_prompts = { 0: [ "A beautiful painting of a singular lighthouse, shining its light across a tumultuous sea of blood by greg rutkowski and thomas kinkade, Trending on artstation.", "yellow color scheme" ] } image = disco.infer( height=768, width=1280, text_prompts=text_prompts, show_progress=True, num_inference_steps=250, eta=0.8)['samples'] save_image(image, "image.png") ``` ## 教程 考虑到`disco-diffusion`包含许多可调整的参数,我们为用户提供了一个[jupyter-notebook](./tutorials.ipynb)/[colab](https://githubtocolab.com/open-mmlab/mmagic/blob/main/configs/disco_diffusion/tutorials.ipynb)的教程,展示了不同参数的含义,并给出相应的调整结果。 请参考[Disco Sheet](https://docs.google.com/document/d/1l8s7uS2dGqjztYSjPpzlmXLjl5PM3IGkRWI3IiCuK7g/edit)。 ## 鸣谢 Since our adaptation of disco-diffusion are heavily influenced by disco [colab](https://colab.research.google.com/github/alembics/disco-diffusion/blob/main/Disco_Diffusion.ipynb#scrollTo=License), here we copy the credits below.
鸣谢 Original notebook by Katherine Crowson (https://github.com/crowsonkb, https://twitter.com/RiversHaveWings). It uses either OpenAI's 256x256 unconditional ImageNet or Katherine Crowson's fine-tuned 512x512 diffusion model (https://github.com/openai/guided-diffusion), together with CLIP (https://github.com/openai/CLIP) to connect text prompts with images. Modified by Daniel Russell (https://github.com/russelldc, https://twitter.com/danielrussruss) to include (hopefully) optimal params for quick generations in 15-100 timesteps rather than 1000, as well as more robust augmentations. Further improvements from Dango233 and nshepperd helped improve the quality of diffusion in general, and especially so for shorter runs like this notebook aims to achieve. Vark added code to load in multiple Clip models at once, which all prompts are evaluated against, which may greatly improve accuracy. The latest zoom, pan, rotation, and keyframes features were taken from Chigozie Nri's VQGAN Zoom Notebook (https://github.com/chigozienri, https://twitter.com/chigozienri) Advanced DangoCutn Cutout method is also from Dango223. \-- Disco: Somnai (https://twitter.com/Somnai_dreams) added Diffusion Animation techniques, QoL improvements and various implementations of tech and techniques, mostly listed in the changelog below. 3D animation implementation added by Adam Letts (https://twitter.com/gandamu_ml) in collaboration with Somnai. Creation of disco.py and ongoing maintenance. Turbo feature by Chris Allen (https://twitter.com/zippy731) Improvements to ability to run on local systems, Windows support, and dependency installation by HostsServer (https://twitter.com/HostsServer) VR Mode by Tom Mason (https://twitter.com/nin_artificial) Horizontal and Vertical symmetry functionality by nshepperd. Symmetry transformation_steps by huemin (https://twitter.com/huemin_art). Symmetry integration into Disco Diffusion by Dmitrii Tochilkin (https://twitter.com/cut_pow). Warp and custom model support by Alex Spirin (https://twitter.com/devdef). Pixel Art Diffusion, Watercolor Diffusion, and Pulp SciFi Diffusion models from KaliYuga (https://twitter.com/KaliYuga_ai). Follow KaliYuga's Twitter for the latest models and for notebooks with specialized settings. Integration of OpenCLIP models and initiation of integration of KaliYuga models by Palmweaver / Chris Scalf (https://twitter.com/ChrisScalf11) Integrated portrait_generator_v001 from Felipe3DArtist (https://twitter.com/Felipe3DArtist)
## Citation ```bibtex @misc{github, author={alembics}, title={disco-diffusion}, year={2022}, url={https://github.com/alembics/disco-diffusion}, } ``` ================================================ FILE: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py ================================================ unet = dict( type='DenoisingUnet', image_size=256, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.0, num_classes=0, use_fp16=True, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True) unet_ckpt_path = 'https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_finetuned_imagenet-256x256-f0f6e11b.pth' # noqa secondary_model_ckpt_path = 'https://download.openmmlab.com/mmediting/synthesizers/disco/secondary_model_imagenet_2.pth' # noqa pretrained_cfgs = dict( unet=dict(ckpt_path=unet_ckpt_path, prefix='unet'), secondary_model=dict(ckpt_path=secondary_model_ckpt_path, prefix='')) secondary_model = dict(type='SecondaryDiffusionImageNet2') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear', clip_sample=False) clip_models = [ dict(type='ClipWrapper', clip_type='clip', name='ViT-B/32', jit=False), dict(type='ClipWrapper', clip_type='clip', name='ViT-B/16', jit=False), dict(type='ClipWrapper', clip_type='clip', name='RN50', jit=False) ] model = dict( type='DiscoDiffusion', unet=unet, diffusion_scheduler=diffusion_scheduler, secondary_model=secondary_model, clip_models=clip_models, use_fp16=True, pretrained_cfgs=pretrained_cfgs) ================================================ FILE: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py ================================================ unet = dict( type='DenoisingUnet', image_size=512, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.0, num_classes=0, use_fp16=True, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True) unet_ckpt_path = 'https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth' # noqa secondary_model_ckpt_path = 'https://download.openmmlab.com/mmediting/synthesizers/disco/secondary_model_imagenet_2.pth' # noqa pretrained_cfgs = dict( unet=dict(ckpt_path=unet_ckpt_path, prefix='unet'), secondary_model=dict(ckpt_path=secondary_model_ckpt_path, prefix='')) secondary_model = dict(type='SecondaryDiffusionImageNet2') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear', clip_sample=False) clip_models = [ dict(type='ClipWrapper', clip_type='clip', name='ViT-B/32', jit=False), dict(type='ClipWrapper', clip_type='clip', name='ViT-B/16', jit=False), dict(type='ClipWrapper', clip_type='clip', name='RN50', jit=False) ] model = dict( type='DiscoDiffusion', unet=unet, diffusion_scheduler=diffusion_scheduler, secondary_model=secondary_model, clip_models=clip_models, use_fp16=True, pretrained_cfgs=pretrained_cfgs) ================================================ FILE: configs/disco_diffusion/disco-diffusion_portrait-generator-v001.py ================================================ _base_ = ['./disco-diffusion_adm-u-finetuned_imagenet-512x512.py'] unet_ckpt_path = 'https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_portrait-v001-f4a3f3bc.pth' # noqa model = dict( unet=dict(base_channels=128), secondary_model=None, pretrained_cfgs=dict( _delete_=True, unet=dict(ckpt_path=unet_ckpt_path, prefix='unet'))) ================================================ FILE: configs/disco_diffusion/metafile.yml ================================================ Collections: - Name: Disco Diffusion Paper: Title: Disco Diffusion URL: https://github.com/alembics/disco-diffusion README: configs/disco_diffusion/README.md Task: - text2image - image2image Year: 2022 Models: - Config: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py In Collection: Disco Diffusion Name: disco-diffusion_adm-u-finetuned_imagenet-512x512 Results: - Dataset: ImageNet Metrics: {} Task: Text2Image Weights: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth - Config: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py In Collection: Disco Diffusion Name: disco-diffusion_adm-u-finetuned_imagenet-256x256 Results: - Dataset: ImageNet Metrics: {} Task: Text2Image Weights: <> - Config: configs/disco_diffusion/disco-diffusion_portrait-generator-v001.py In Collection: Disco Diffusion Name: disco-diffusion_portrait-generator-v001 Results: - Dataset: unknown Metrics: {} Task: Text2Image Weights: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_portrait-v001-f4a3f3bc.pth ================================================ FILE: configs/disco_diffusion/tutorials.ipynb ================================================ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Disco Tutorials" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Disco Diffusion is a colab work cooperated by many talented people. From the algorithm aspect, this work is based on guided-diffusion and clip-guided diffusion. \n", "\n", "The generation process of disco-diffusion consists of following steps,\n", "1. Disco-diffusion takes as inputs user-provided text prompts and image prompts.\n", "2. A pretrained clip model calculates the embeddings of the text and image prompts.\n", "3. The Unet will predict the original sample.\n", "3. A list of image cutouts will be generated from original sample by a cutter.\n", "4. The generation process is optimized by calculating the similarity between the embeddings of the image cutouts, text and image prompts, and other losses.\n", "5. Finally, with the carefully-designed loss functions, the model enables classifier-guidance samping to generate desired images according to the text and image prompts.\n", "\n", "So corresponding to above processes, we will introduce what to set for generating and show your results by adjusting arguments/ configs. \n", "\n", "The contents of this tutorials are as follows:\n", "\n", "[1.Runtime Settings](#1-Runtime-Settings)\n", "\n", "[2.Unet Settings](#2-Unet-Settings)\n", "\n", "[3.CLIP Models Settings](#3-CLIP-Models-Settings)\n", "\n", "[4.Diffusion Scheduler Settings](#4-Diffusion-Scheduler-Settings)\n", "\n", "[5.Loss Settings](#5-Loss-Settings)\n", "\n", "[6.Cutter Settings](#6-Cutter-Settings)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install MMagic" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Check PyTorch version and CLIP version\n", "!pip list | grep torch\n", "!pip list | grep clip" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Install mmcv dependency via openmim\n", "!pip install openmim\n", "!mim install 'mmcv>=2.0.0'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Install mmagic from source\n", "%cd /content/\n", "!rm -rf mmagic\n", "!git clone https://github.com/open-mmlab/mmagic.git \n", "%cd mmagic\n", "!pip install -r requirements.txt\n", "!pip install -e ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Runtime Settings" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import torch\n", "from mmengine import Config, MODELS\n", "from mmengine.registry import init_default_scope\n", "from mmagic.registry import MODULES\n", "from mmcv import tensor2imgs\n", "from matplotlib import pyplot as plt\n", "\n", "from torchvision.transforms import ToPILImage, Normalize, Compose\n", "from IPython.display import Image\n", "\n", "init_default_scope('mmagic')\n", "\n", "\n", "def show_tensor(image_tensor, index=0):\n", " normalized_image = ((image_tensor + 1.) / 2.).clamp(0, 1)\n", " out = tensor2imgs(normalized_image * 255, to_rgb=False)\n", " plt.imshow(out[index])\n", " plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "config = 'configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()\n", "text_prompts = {\n", " 0: [\"clouds surround the mountains and Chinese palaces, sunshine, lake, overlook, overlook, unreal engine, light effect, Dream, Greg Rutkowski, James Gurney, artstation\"]\n", "}\n", "\n", "seed = 2022\n", "num_inference_steps = 250\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Image Resolution\n", "Despite the limit of your device limitation, you can set height and width of image as you like." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# image resolution\n", "image = disco.infer(width=768, height=1280, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### image_prompts\n", " Work in progress." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# # image prompts\n", "# image_prompts = ['path_of_image']\n", "# image = disco.infer(width=768, height=1280, image_prompts=image_prompts, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, seed=seed)['samples']\n", "# show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### clip_guidance_scale\n", "clip_guidance_scale is one of the most important parameters you will use. It tells DD how strongly you want CLIP to move toward your prompt each timestep. Higher is generally better, but if CGS is too strong it will overshoot the goal and distort the image. So a happy medium is needed, and it takes experience to learn how to adjust CGS." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# clip guidance scale\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, clip_guidance_scale=8000, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, clip_guidance_scale=4000, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Unet Settings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Disco-Diffusion provides different unet, and we offer configs for the different unets and convert the weights. You only need to select these configs to use the different unets freely." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 256x256_diffusion_uncond\n", "text_prompts = {\n", " 0: [\"clouds surround the mountains and Chinese palaces,sunshine,lake,overlook,overlook,unreal engine,light effect,Dream,Greg Rutkowski,James Gurney,artstation\"]\n", "}\n", "config = 'configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()\n", "image = disco.infer(width=512, height=448, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# 512x512_diffusion_uncond_finetune_008100\n", "config = 'configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# portrait_generator_v001\n", "text_prompts = {\n", " 0: [\"a portrait of supergirl, by artgerm, rosstran, trending on artstation.\"]\n", "}\n", "config = 'disco-diffusion_portrait-generator-v001.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()\n", "image = disco.infer(width=512, height=512, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, tv_scale=5000, range_scale = 5000, sat_scale = 15250, clip_guidance_scale=20000, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The rest unets will come soon!\n", "- pixelartdiffusion_expanded\n", "- pixel_art_diffusion_hard_256\n", "- pixelartdiffusion4k\n", "- watercolordiffusion_2\n", "- watercolordiffusion\n", "- PulpSciFiDiffusion\n", "- secondary\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.CLIP Models Settings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Disco-Diffusion uses different clip models to guide the image generation, and the images generated by different clip models have different characteristics. In practice, we combine multiple clip models to generate images.\n", " In order to study the effect of different clip models, in the following example, we only use one clip model at a time, with other settings keeping the same, you can experience the characteristics of different clip models by observing the results." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from mmagic.models.editors.disco_diffusion.guider import ImageTextGuider\n", "\n", "\n", "config = 'configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()\n", "text_prompts = {0: [\"A beautiful painting of a map of the city of Atlantis\"]}\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### ViTB32\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='ViT-B/32', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB16" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "\n", "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='ViT-B/16', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTL14" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='ViT-L/14', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTL14_336px" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper', clip_type='clip', name='ViT-L/14@336px',\n", " jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='RN50', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50x4" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='RN50x4', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50x16" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='RN50x16', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50x64" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='RN50x64', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN101" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(type='ClipWrapper', clip_type='clip', name='RN101', jit=False),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB32_laion2b_e16" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-32',\n", " pretrained='laion2b_e16',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB32_laion400m_e31" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-32',\n", " pretrained='laion400m_e31',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB32_laion400m_32" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-32',\n", " pretrained='laion400m_e32',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB32quickgelu_laion400m_e31" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-32-quickgelu',\n", " pretrained='laion400m_e31',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB32quickgelu_laion400m_e32" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-32-quickgelu',\n", " pretrained='laion400m_e32',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB16_laion400m_e31" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-16',\n", " pretrained='laion400m_e31',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ViTB16_laion400m_e32" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='ViT-B-16',\n", " pretrained='laion400m_e32',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50_yffcc15m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN50',\n", " pretrained='yfcc15m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50_cc12m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN50',\n", " pretrained='cc12m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50_quickgelu_yfcc15m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN50-quickgelu',\n", " pretrained='yfcc15m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN50_quickgelu_cc12m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN50-quickgelu',\n", " pretrained='cc12m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN101_yfcc15m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN101',\n", " pretrained='yfcc15m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RN101_quickgelu_yfcc15m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clip_models = []\n", "clip_models_cfg = [\n", " dict(\n", " type='ClipWrapper',\n", " clip_type='open_clip',\n", " model_name='RN101-quickgelu',\n", " pretrained='yfcc15m',\n", " device='cuda'),\n", "]\n", "for clip_cfg in clip_models_cfg:\n", " clip_models.append(MODULES.build(clip_cfg))\n", "disco.guider = ImageTextGuider(clip_models).cuda()\n", "\n", "image = disco.infer(\n", " width=1280,\n", " height=768,\n", " text_prompts=text_prompts,\n", " show_progress=True,\n", " num_inference_steps=num_inference_steps,\n", " eta=0.8,\n", " seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4.Diffusion Scheduler Settings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Typically, a diffusion model generates images by a reverse scheduler. Many researchers are working on designing different reverse schedulers to improve diffusion models. Now, we only support DDIM scheduler. More kinds of reverse schedulers are coming soon." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### skip_steps\n", "First, When you set the value of `init_image`, you can adjust `skip_steps` for creative reasons. With low skip_steps you can get a result “inspired by” the init_image which will retain the colors and rough layout and shapes but look quite different. With high skip_steps you can preserve most of the init_image contents and only fine-tune the texture." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!wget https://user-images.githubusercontent.com/22982797/205579254-30c3b446-63bb-4172-bbfe-8d1d05e151cf.png -O init.png" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "init_path = 'init.png'\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, init_image=init_path, skip_steps=50, seed=seed)['samples']\n", "show_tensor(image)\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, init_image=init_path, skip_steps=200, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that, you can still use `skip_steps` to reduce rendering time even you don't set the value of `init_image`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### steps\n", "Increasing steps will provide more opportunities for the AI to adjust the image, and each adjustment will be smaller, and thus will yield a more precise, detailed image. Using a larger `steps` will generally increase image quality but also increasing the render time. However, some intricate images can take 1000, 2000, or more steps. It is really up to the user. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "steps = 100\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "steps = 1000\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=steps, eta=0.8, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.Loss Settings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define `loss_cfg` in config like this. The loss function defines the distance between the generated image and the expected target, so you can adjust loss settings for you purpose." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "loss_cfg = dict(tv_scale=0, range_scale=150, sat_scale=0, init_scale=1000)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "config = 'configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py'\n", "disco = MODELS.build(Config.fromfile(config).model).cuda().eval()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### range_scale\n", "Optional, set to zero to turn off. It is used to adjust color contrast. Lower range_scale will increase contrast. Very low numbers create a reduced color palette, resulting in more vibrant or poster-like images. Higher range_scale will reduce contrast, for more muted images." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# range_scale\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, range_scale=50, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, range_scale=200, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### tv_scale\n", "Total variance denoising. Optional, set to zero to turn off. Controls ‘smoothness’ of final output. If used, tv_scale will try to smooth out your final image to reduce overall noise. If your image is too 'crunchy', increase tv_scale. TV denoising is good at preserving edges while smoothing away noise in flat regions." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# tv_scale\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, tv_scale=0.1, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, tv_scale=0.9, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### sat_scale\n", "Saturation scale. Optional, set to zero to turn off. If used, sat_scale will help mitigate oversaturation. If your image is too saturated, increase sat_scale to reduce saturation." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# sat_scale\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, sat_scale=0.1, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, sat_scale=0.9, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### init_scale\n", " This controls how strongly CLIP will try to match the init_image provided. This is balanced against the clip_guidance_scale (CGS) above. An extreamly large value of `init_scale` won't change the results dramatcally, while an exteamly large value of CGS will destroy the `init_image`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# init_scale\n", "init_path = 'init.png'\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, init_image=init_path, skip_steps=125, init_scale=1000, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, init_image=init_path, skip_steps=125, init_scale=100, seed=seed)['samples']\n", "show_tensor(image)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.Cutter Settings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cutter Settings\n", "This section determines the schedule of CLIP cuts, or snapshots that CLIP uses to evaluate your image while processing. In DD, there are two types of cuts: overview cuts, which take a snapshot of the entire image and evaluate that against the prompt, and inner cuts, which are smaller cropped images from the interior of the image, helpful in tuning fine details. The size of the inner cuts can be adjusted using the cut_ic_pow parameter." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cut_overview\n", "The schedule of overview cuts" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# cut_overview\n", "cut_overview = [12] * 100 + [4] * 900\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_overview=cut_overview, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "cut_overview = [12] * 900 + [4] * 100\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_overview=cut_overview, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cut_innercut\n", "The schedule of inner cuts" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# cut_innercut\n", "cut_innercut = [4] * 100 + [12] * 900\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_innercut=cut_innercut, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "cut_innercut = [4] * 900 + [12] * 100\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_innercut=cut_innercut, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cut_ic_pow\n", "This sets the size of the border used for inner cuts. High cut_ic_pow values have larger borders, and therefore the cuts themselves will be smaller and provide finer details. If you have too many or too-small inner cuts, you may lose overall image coherency and/or it may cause an undesirable ‘mosaic’ effect. Low cut_ic_pow values will allow the inner cuts to be larger, helping image coherency while still helping with some details." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# cut_ic_pow\n", "cut_ic_pow = [1] * 200 + [0] * 800\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_ic_pow=cut_ic_pow, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "cut_ic_pow = [1] * 800 + [0] * 200\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_ic_pow=cut_ic_pow, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cut_icgray_p\n", "In addition to the overall cut schedule, a portion of the cuts can be set to be grayscale instead of color. This may help with improved definition of shapes and edges, especially in the early diffusion steps where the image structure is being defined. cut_icgray_p affects overview and inner cuts" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# cut_icgray_p\n", "cut_icgray_p=[0.2] * 200 + [0] * 800\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_icgray_p=cut_icgray_p, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "cut_icgray_p=[0.2] * 800 + [0] * 200\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cut_icgray_p=cut_icgray_p, seed=seed)['samples']\n", "show_tensor(image)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cutn_batches\n", "Each iteration, the AI cuts the image into smaller pieces known as cuts, and compares each cut to the prompt to decide how to guide the next diffusion step. More cuts can generally lead to better images, since DD has more chances to fine-tune the image precision at each timesteps. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# cutn_batches\n", "cutn_batches = 2\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cutn_batches=cutn_batches, seed=seed)['samples']\n", "show_tensor(image)\n", "\n", "cutn_batches = 8\n", "image = disco.infer(width=1280, height=768, text_prompts=text_prompts, show_progress=True, num_inference_steps=num_inference_steps, eta=0.8, cutn_batches=cutn_batches, seed=seed)['samples']\n", "show_tensor(image)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.16 ('mmedit': conda)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "35fd9fbe4d1b297d4be2b8092ffedf61ac9a34aef1ae0231052d90ec0a3e8f9f" } } }, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: configs/draggan/README.md ================================================ # DragGAN (SIGGRAPH'2023) > [Drag Your GAN: Interactive Point-based Manipulation on the Generative Image Manifold](https://arxiv.org/pdf/2305.10973.pdf) > **Task**: DragGAN ## Abstract Synthesizing visual content that meets users’ needs often requires flexible and precise controllability of the pose, shape, expression, and layout of the generated objects. Existing approaches gain controllability of generative adversarial networks (GANs) via manually annotated training data or a prior 3D model, which often lack flexibility, precision, and generality. In this work, we study a powerful yet much less explored way of controlling GANs, that is, to "drag" any points of the image to precisely reach target points in a user-interactive manner, as shown in Fig.1. To achieve this, we propose DragGAN, which consists of two main components: 1) a feature-based motion supervision that drives the handle point to move towards the target position, and 2) a new point tracking approach that leverages the discriminative generator features to keep localizing the position of the handle points. Through DragGAN, anyone can deform an image with precise control over where pixels go, thus manipulating the pose, shape, expression,and layout of diverse categories such as animals, cars, humans, landscapes, etc. As these manipulations are performed on the learned generative image manifold of a GAN, they tend to produce realistic outputs even for challenging scenarios such as hallucinating occluded content and deforming shapes that consistently follow the object’s rigidity. Both qualitative and quantitative comparisons demonstrate the advantage of DragGAN over prior approaches in the tasks of image manipulation and point tracking. We also showcase the manipulation of real images through GAN inversion.
## Results and Models Gradio Demo of DragGAN StyleGAN2-elephants-512 by MMagic
| Model | Dataset | Comment | FID50k | Precision50k | Recall50k | Download | | :--------------------------------------------------: | :----------------: | :-----------------------------: | :----: | :----------: | :-------: | :----------------------------------------------------------------------: | | [stylegan2_lion_512x512](./stylegan2_512x512.py) | Internet Lions | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-Lions-internet) | | [stylegan2_elphants_512x512](./stylegan2_512x512.py) | Internet Elephants | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-elephants-internet) | | [stylegan2_cats_512x512](./stylegan2_512x512.py) | Cat AFHQ | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-cat-AFHQ) | | [stylegan2_face_512x512](./stylegan2_512x512.py) | FFHQ | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-FFHQ) | | [stylegan2_horse_256x256](./stylegan2_256x256.py) | LSUN-Horse | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-lsun-horses) | | [stylegan2_dogs_1024x1024](./stylegan2_1024x1024.py) | Internet Dogs | self-distilled StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-dogs-internet) | | [stylegan2_car_512x512](./stylegan2_512x512.py) | Car | transfer from official training | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-car-official) | | [stylegan2_cat_256x256](./stylegan2_256x256.py) | Cat | transfer from official training | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-cat-official) | ## Demo To run DragGAN demo, please follow these two steps: First, put your checkpoint path in `./checkpoints`, *e.g.* `./checkpoints/stylegan2_lions_512_pytorch_mmagic.pth`. To be specific, ```shell mkdir checkpoints cd checkpoints wget -O stylegan2_lions_512_pytorch_mmagic.pth https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-Lions-internet ``` Then, try on the script: ```shell python demo/gradio_draggan.py ``` ## Citation ```latex @inproceedings{pan2023drag, title={Drag your gan: Interactive point-based manipulation on the generative image manifold}, author={Pan, Xingang and Tewari, Ayush and Leimk{\"u}hler, Thomas and Liu, Lingjie and Meka, Abhimitra and Theobalt, Christian}, booktitle={ACM SIGGRAPH 2023 Conference Proceedings}, pages={1--11}, year={2023} } ``` ================================================ FILE: configs/draggan/README_zh-CN.md ================================================ # DragGAN (SIGGRAPH'2023) > [Drag Your GAN: Interactive Point-based Manipulation on the Generative Image Manifold](https://arxiv.org/pdf/2305.10973.pdf) > **Task**: DragGAN ## 摘要 要合成满足用户需求的视觉内容,通常需要灵活、精确地控制人物的姿势、形状、表情和布局。 和精确地控制生成对象的姿势、形状、表情和布局。 生成对象。现有的方法是通过人工标注训练数据来获得生成对抗网络(GANs)的可控性。 生成式对抗网络 (GAN) 的可控性是通过人工标注的训练数据或预先的 3D 模型来实现的。 生成式对抗网络(GAN)的可控性是通过人工标注的训练数据或事先建立的三维模型来实现的,而这些方法往往缺乏灵活性、精确性和通用性。在中,我们研究了一种功能强大但探索较少的生成式对抗网络(GAN)控制方法。 即 "拖动 "图像中的任意点,以用户互动的方式精确到达目标点。 如图 1 所示。为此,我们 DragGAN 由两个主要部分组成: 1) 基于特征的运动监督,驱动手柄点向目标位置移动;以及目标位置,以及 2) 一种新的点跟踪方法,利用的新点跟踪方法。 手柄点的位置。通过 DragGAN,任何人都可以对图像进行变形,并精确控制像素的移动位置。 通过 DragGAN,任何人都可以精确控制像素的位置,从而改变图像的姿态、形状、表情和布局,如动物、汽车、人类、风景等、 等等。由于这些操作是在 GAN 的学习生成图像流形上进行的流形上进行,因此即使是在具有挑战性的情况下,它们也能产生逼真的输出,例如幻觉遮挡内容和变形形状始终遵循物体的刚性。定性和定量比较都表明,在图像处理和点跟踪任务中,DragGAN 在图像处理和点跟踪任务中的优势。我们还展示了通过 GAN 反演对真实图像的操作。
## 结果和模型 MMagic下实现的DragGAN(StyleGAN2-elephants-512) Gradio示例
| 模型 | 数据集 | 评论 | FID50k | Precision50k | Recall50k | 权重下载链接 | | :--------------------------------------------------: | :----------------: | :------------: | :----: | :----------: | :-------: | :---------------------------------------------------------------------------------------: | | [stylegan2_lion_512x512](./stylegan2_512x512.py) | Internet Lions | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-Lions-internet) | | [stylegan2_elphants_512x512](./stylegan2_512x512.py) | Internet Elephants | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-elephants-internet) | | [stylegan2_cats_512x512](./stylegan2_512x512.py) | Cat AFHQ | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-cat-AFHQ) | | [stylegan2_face_512x512](./stylegan2_512x512.py) | FFHQ | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-FFHQ) | | [stylegan2_horse_256x256](./stylegan2_256x256.py) | LSUN-Horse | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-lsun-horses) | | [stylegan2_dogs_1024x1024](./stylegan2_1024x1024.py) | Internet Dogs | 自蒸馏StyleGAN | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-dogs-internet) | | [stylegan2_car_512x512](./stylegan2_512x512.py) | Car | 官方训练 | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-car-official) | | [stylegan2_cat_256x256](./stylegan2_256x256.py) | Cat | 官方训练 | 0.0 | 0.0 | 0.0 | [model](https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-cat-official) | ## 演示 为了使用DragGAN演示, 请执行以下两步: 首先,把模型文件放在 `./checkpoints`下, 比如 `./checkpoints/stylegan2_lions_512_pytorch_mmagic.pth`. 具体来说, ```shell mkdir checkpoints cd checkpoints wget -O stylegan2_lions_512_pytorch_mmagic.pth https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-Lions-internet ``` 然后,执行下面的脚本: ```shell python demo/gradio_draggan.py ``` ## 引用 ```latex @inproceedings{pan2023drag, title={Drag your gan: Interactive point-based manipulation on the generative image manifold}, author={Pan, Xingang and Tewari, Ayush and Leimk{\"u}hler, Thomas and Liu, Lingjie and Meka, Abhimitra and Theobalt, Christian}, booktitle={ACM SIGGRAPH 2023 Conference Proceedings}, pages={1--11}, year={2023} } ``` ================================================ FILE: configs/draggan/metafile.yml ================================================ Collections: - Name: DragGAN Paper: Title: 'Drag Your GAN: Interactive Point-based Manipulation on the Generative Image Manifold' URL: https://arxiv.org/pdf/2305.10973.pdf README: configs/draggan/README.md Task: - draggan Year: 2023 Models: - Config: configs/draggan/stylegan2_512x512.py In Collection: DragGAN Name: stylegan2_512x512 Results: - Dataset: InternetLions Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN - Dataset: InternetElephants Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN - Dataset: CatAFHQ Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN - Dataset: FFHQ Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN - Dataset: Car Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN Weights: https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-car-official - Config: configs/draggan/stylegan2_256x256.py In Collection: DragGAN Name: stylegan2_256x256 Results: - Dataset: LSUN-Horse Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN - Dataset: Cat Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN Weights: https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-cat-official - Config: configs/draggan/stylegan2_1024x1024.py In Collection: DragGAN Name: stylegan2_1024x1024 Results: - Dataset: InternetDogs Metrics: FID50k: 0.0 Precision50k: 0.0 Recall50k: 0.0 Task: DragGAN Weights: https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-dogs-internet ================================================ FILE: configs/draggan/stylegan2_1024x1024.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict( out_size=1024, update_mean_latent_with_ema=True, bgr2rgb=False, fixed_noise=True), discriminator=dict(in_size=1024), # useless ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 1 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/draggan/stylegan2_256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict( out_size=256, update_mean_latent_with_ema=True, bgr2rgb=False, fixed_noise=True), discriminator=dict(in_size=256), # useless ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 1 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/draggan/stylegan2_512x512.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict( out_size=512, update_mean_latent_with_ema=True, bgr2rgb=False, fixed_noise=True), discriminator=dict(in_size=512), # useless ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 1 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/dreambooth/README.md ================================================ # DreamBooth (2022) > [DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation](https://arxiv.org/abs/2208.12242) > **Task**: Text2Image ## Abstract Large text-to-image models achieved a remarkable leap in the evolution of AI, enabling high-quality and diverse synthesis of images from a given text prompt. However, these models lack the ability to mimic the appearance of subjects in a given reference set and synthesize novel renditions of them in different contexts. In this work, we present a new approach for "personalization" of text-to-image diffusion models. Given as input just a few images of a subject, we fine-tune a pretrained text-to-image model such that it learns to bind a unique identifier with that specific subject. Once the subject is embedded in the output domain of the model, the unique identifier can be used to synthesize novel photorealistic images of the subject contextualized in different scenes. By leveraging the semantic prior embedded in the model with a new autogenous class-specific prior preservation loss, our technique enables synthesizing the subject in diverse scenes, poses, views and lighting conditions that do not appear in the reference images. We apply our technique to several previously-unassailable tasks, including subject recontextualization, text-guided view synthesis, and artistic rendering, all while preserving the subject's key features. We also provide a new dataset and evaluation protocol for this new task of subject-driven generation.
## Configs | Model | Dataset | Download | | :----------------------------------------------------------------------------: | :-----: | :------: | | [DreamBooth](./dreambooth.py) | - | - | | [DreamBooth (Finetune Text Encoder)](./dreambooth-finetune_text_encoder.py) | - | - | | [DreamBooth with Prior-Preservation Loss](./dreambooth-prior_pre.py) | - | - | | [DreamBooth LoRA](./dreambooth-lora.py) | - | - | | [DreamBooth LoRA with Prior-Preservation Loss](./dreambooth-lora-prior_pre.py) | - | - | ## Quick Start 1. Download [data](https://drive.google.com/drive/folders/1BO_dyz-p65qhBRRMRA4TbZ8qW4rB99JZ) and save to `data/dreambooth/` The file structure will be like this: ```text data └── dreambooth └──imgs ├── alvan-nee-Id1DBHv4fbg-unsplash.jpeg ├── alvan-nee-bQaAJCbNq3g-unsplash.jpeg ├── alvan-nee-brFsZ7qszSY-unsplash.jpeg └── alvan-nee-eoqnr8ikwFE-unsplash.jpeg ``` 2. Start training with the following command: ```bash bash tools/dist_train.sh configs/dreambooth/dreambooth.py 1 # or bash tools/dist_train.sh configs/dreambooth/dreambooth-lora.py 1 ```

'dreambooth'

'dreambooth-lora'
## Use ToMe to accelerate your training and inference We support **[tomesd](https://github.com/dbolya/tomesd)** now! It is developed for stable-diffusion-based models referring to [ToMe](https://github.com/facebookresearch/ToMe), an efficient ViT speed-up tool based on token merging. To work on with **tomesd** in `mmagic`, you just need to add `tomesd_cfg` to `model` in [DreamBooth](./dreambooth.py). The only requirement is `torch >= 1.12.1` in order to properly support `torch.Tensor.scatter_reduce()` functionality. Please do check it before running the demo. ```python model = dict( type='DreamBooth', ... tomesd_cfg=dict(ratio=0.5), ... val_prompts=val_prompts) ``` For more details, you can refer to [Stable Diffusion Acceleration](../stable_diffusion/README.md#use-tome-to-accelerate-your-stable-diffusion-model). ## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py). Thanks for the efforts of the community! ## Citation ```bibtex @article{ruiz2022dreambooth, title={Dreambooth: Fine tuning text-to-image diffusion models for subject-driven generation}, author={Ruiz, Nataniel and Li, Yuanzhen and Jampani, Varun and Pritch, Yael and Rubinstein, Michael and Aberman, Kfir}, journal={arXiv preprint arXiv:2208.12242}, year={2022} } ``` ================================================ FILE: configs/dreambooth/dreambooth-finetune_text_encoder.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] model = dict( type='DreamBooth', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, finetune_text_encoder=True, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor', data_keys=None), val_prompts=val_prompts) train_cfg = dict(max_iters=1000) optim_wrapper = dict( modules='.*unet', optimizer=dict(type='AdamW', lr=5e-6), accumulative_counts=4) # batch size = 4 * 1 = 4 pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='Resize', scale=(512, 512)), dict(type='PackInputs') ] dataset = dict( type='DreamBoothDataset', data_root='./data/dreambooth', concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks = dict(logger=dict(interval=10)) custom_hooks = [ dict( type='VisualizationHook', interval=50, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: configs/dreambooth/dreambooth-lora-prior_pre.py ================================================ _base_ = 'dreambooth-lora.py' # config for model model = dict(prior_loss_weight=1, class_prior_prompt='a dog') ================================================ FILE: configs/dreambooth/dreambooth-lora.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] lora_config = dict(target_modules=['to_q', 'to_k', 'to_v']) model = dict( type='DreamBooth', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor', data_keys=None), prior_loss_weight=0, val_prompts=val_prompts, lora_config=lora_config) train_cfg = dict(max_iters=1000) optim_wrapper = dict( # Only optimize LoRA mappings modules='.*.lora_mapping', # NOTE: lr should be larger than dreambooth finetuning optimizer=dict(type='AdamW', lr=5e-4), accumulative_counts=1) pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='Resize', scale=(512, 512)), dict(type='PackInputs') ] dataset = dict( type='DreamBoothDataset', data_root='./data/dreambooth', # TODO: rename to instance concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks = dict(logger=dict(interval=10)) custom_hooks = [ dict( type='VisualizationHook', interval=50, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: configs/dreambooth/dreambooth-prior_pre.py ================================================ _base_ = './dreambooth.py' # config for model model = dict(prior_loss_weight=1, class_prior_prompt='a dog') ================================================ FILE: configs/dreambooth/dreambooth.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] model = dict( type='DreamBooth', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor', data_keys=None), val_prompts=val_prompts) train_cfg = dict(max_iters=1000) optim_wrapper = dict( modules='.*unet', optimizer=dict(type='AdamW', lr=5e-6), accumulative_counts=4) # batch size = 4 * 1 = 4 pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='Resize', scale=(512, 512)), dict(type='PackInputs') ] dataset = dict( type='DreamBoothDataset', data_root='./data/dreambooth', concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks = dict(logger=dict(interval=10)) custom_hooks = [ dict( type='VisualizationHook', interval=50, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: configs/dreambooth/metafile.yml ================================================ Collections: - Name: DreamBooth Paper: Title: 'DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation' URL: https://arxiv.org/abs/2208.12242 README: configs/dreambooth/README.md Task: - text2image Year: 2022 Models: - Config: configs/dreambooth/dreambooth.py In Collection: DreamBooth Name: dreambooth Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/dreambooth/dreambooth-finetune_text_encoder.py In Collection: DreamBooth Name: dreambooth-finetune_text_encoder Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/dreambooth/dreambooth-prior_pre.py In Collection: DreamBooth Name: dreambooth-prior_pre Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/dreambooth/dreambooth-lora.py In Collection: DreamBooth Name: dreambooth-lora Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/dreambooth/dreambooth-lora-prior_pre.py In Collection: DreamBooth Name: dreambooth-lora-prior_pre Results: - Dataset: '-' Metrics: {} Task: Text2Image ================================================ FILE: configs/edsr/README.md ================================================ # EDSR (CVPR'2017) > [Enhanced Deep Residual Networks for Single Image Super-Resolution](https://arxiv.org/abs/1707.02921) > **Task**: Image Super-Resolution ## Abstract Recent research on super-resolution has progressed with the development of deep convolutional neural networks (DCNN). In particular, residual learning techniques exhibit improved performance. In this paper, we develop an enhanced deep super-resolution network (EDSR) with performance exceeding those of current state-of-the-art SR methods. The significant performance improvement of our model is due to optimization by removing unnecessary modules in conventional residual networks. The performance is further improved by expanding the model size while we stabilize the training procedure. We also propose a new multi-scale deep super-resolution system (MDSR) and training method, which can reconstruct high-resolution images of different upscaling factors in a single model. The proposed methods show superior performance over the state-of-the-art methods on benchmark datasets and prove its excellence by winning the NTIRE2017 Super-Resolution Challenge.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :------------------------------------------------------------------: | :-----: | :-----: | :----: | :----------------: | :--------------------------------------------------------------------------------------------: | | [edsr_x2c64b16_1x16_300k_div2k](./edsr_x2c64b16_1xb16-300k_div2k.py) | Set5 | 35.7592 | 0.9372 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604-19fe95ea.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604_221933.log.json) | | [edsr_x2c64b16_1x16_300k_div2k](./edsr_x2c64b16_1xb16-300k_div2k.py) | Set14 | 31.4290 | 0.8874 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604-19fe95ea.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604_221933.log.json) | | [edsr_x2c64b16_1x16_300k_div2k](./edsr_x2c64b16_1xb16-300k_div2k.py) | DIV2K | 34.5896 | 0.9352 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604-19fe95ea.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604_221933.log.json) | | [edsr_x3c64b16_1x16_300k_div2k](./edsr_x3c64b16_1xb16-300k_div2k.py) | Set5 | 32.3301 | 0.8912 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608-36d896f4.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608_114850.log.json) | | [edsr_x3c64b16_1x16_300k_div2k](./edsr_x3c64b16_1xb16-300k_div2k.py) | Set14 | 28.4125 | 0.8022 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608-36d896f4.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608_114850.log.json) | | [edsr_x3c64b16_1x16_300k_div2k](./edsr_x3c64b16_1xb16-300k_div2k.py) | DIV2K | 30.9154 | 0.8711 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608-36d896f4.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608_114850.log.json) | | [edsr_x4c64b16_1x16_300k_div2k](./edsr_x4c64b16_1xb16-300k_div2k.py) | Set5 | 30.2223 | 0.8500 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608_115148.log.json) | | [edsr_x4c64b16_1x16_300k_div2k](./edsr_x4c64b16_1xb16-300k_div2k.py) | Set14 | 26.7870 | 0.7366 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608_115148.log.json) | | [edsr_x4c64b16_1x16_300k_div2k](./edsr_x4c64b16_1xb16-300k_div2k.py) | DIV2K | 28.9675 | 0.8172 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608_115148.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py # single-gpu train python tools/train.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth # single-gpu test python tools/test.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth # multi-gpu test ./tools/dist_test.sh configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{lim2017enhanced, title={Enhanced deep residual networks for single image super-resolution}, author={Lim, Bee and Son, Sanghyun and Kim, Heewon and Nah, Seungjun and Mu Lee, Kyoung}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition workshops}, pages={136--144}, year={2017} } ``` ================================================ FILE: configs/edsr/README_zh-CN.md ================================================ # EDSR (CVPR'2017) > **任务**: 图像超分辨率
EDSR (CVPR'2017) ```bibtex @inproceedings{lim2017enhanced, title={Enhanced deep residual networks for single image super-resolution}, author={Lim, Bee and Son, Sanghyun and Kim, Heewon and Nah, Seungjun and Mu Lee, Kyoung}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition workshops}, pages={136--144}, year={2017} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 | Set14 | DIV2K | GPU 信息 | 下载 | | :------------------------------------------------------------------: | :--------------: | :--------------: | :--------------: | :------: | :--------------------------------------------------------------------------: | | [edsr_x2c64b16_1x16_300k_div2k](./edsr_x2c64b16_1xb16-300k_div2k.py) | 35.7592 / 0.9372 | 31.4290 / 0.8874 | 34.5896 / 0.9352 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604-19fe95ea.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604_221933.log.json) | | [edsr_x3c64b16_1x16_300k_div2k](./edsr_x3c64b16_1xb16-300k_div2k.py) | 32.3301 / 0.8912 | 28.4125 / 0.8022 | 30.9154 / 0.8711 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608-36d896f4.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608_114850.log.json) | | [edsr_x4c64b16_1x16_300k_div2k](./edsr_x4c64b16_1xb16-300k_div2k.py) | 30.2223 / 0.8500 | 26.7870 / 0.7366 | 28.9675 / 0.8172 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608_115148.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py # 单个GPU上训练 python tools/train.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth # 单个GPU上测试 python tools/test.py configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth # 多个GPU上测试 ./tools/dist_test.sh configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x2_test_config.py' ] experiment_name = 'edsr_x2c64b16_1xb16-300k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 # model settings model = dict( type='BaseEditModel', generator=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale, res_scale=1, rgb_mean=[0.4488, 0.4371, 0.4040], rgb_std=[1.0, 1.0, 1.0]), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=96), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/edsr/edsr_x3c64b16_1xb16-300k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x3_test_config.py' ] experiment_name = 'edsr_x3c64b16_1xb16-300k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' load_from = None # based on pre-trained x2 model scale = 3 # model settings model = dict( type='BaseEditModel', generator=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale, res_scale=1, rgb_mean=[0.4488, 0.4371, 0.4040], rgb_std=[1.0, 1.0, 1.0]), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=144), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X3_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'edsr_x4c64b16_1xb16-300k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' load_from = None # based on pre-trained x2 model scale = 4 # model settings model = dict( type='BaseEditModel', generator=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale, res_scale=1, rgb_mean=[0.4488, 0.4371, 0.4040], rgb_std=[1.0, 1.0, 1.0]), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=196), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/edsr/metafile.yml ================================================ Collections: - Name: EDSR Paper: Title: Enhanced Deep Residual Networks for Single Image Super-Resolution URL: https://arxiv.org/abs/1707.02921 README: configs/edsr/README.md Task: - image super-resolution Year: 2017 Models: - Config: configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py In Collection: EDSR Name: edsr_x2c64b16_1xb16-300k_div2k Results: - Dataset: Set5 Metrics: PSNR: 35.7592 SSIM: 0.9372 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 31.429 SSIM: 0.8874 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.5896 SSIM: 0.9352 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x2c64b16_1x16_300k_div2k_20200604-19fe95ea.pth - Config: configs/edsr/edsr_x3c64b16_1xb16-300k_div2k.py In Collection: EDSR Name: edsr_x3c64b16_1xb16-300k_div2k Results: - Dataset: Set5 Metrics: PSNR: 32.3301 SSIM: 0.8912 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 28.4125 SSIM: 0.8022 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 30.9154 SSIM: 0.8711 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x3c64b16_1x16_300k_div2k_20200608-36d896f4.pth - Config: configs/edsr/edsr_x4c64b16_1xb16-300k_div2k.py In Collection: EDSR Name: edsr_x4c64b16_1xb16-300k_div2k Results: - Dataset: Set5 Metrics: PSNR: 30.2223 SSIM: 0.85 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 26.787 SSIM: 0.7366 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 28.9675 SSIM: 0.8172 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edsr/edsr_x4c64b16_1x16_300k_div2k_20200608-3c2af8a3.pth ================================================ FILE: configs/edvr/README.md ================================================ # EDVR (CVPRW'2019) > [EDVR: Video Restoration with Enhanced Deformable Convolutional Networks](https://arxiv.org/abs/1905.02716?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%253A+arxiv%252FQSXk+%2528ExcitingAds%2521+cs+updates+on+arXiv.org%2529) > **Task**: Video Super-Resolution ## Abstract Video restoration tasks, including super-resolution, deblurring, etc, are drawing increasing attention in the computer vision community. A challenging benchmark named REDS is released in the NTIRE19 Challenge. This new benchmark challenges existing methods from two aspects: (1) how to align multiple frames given large motions, and (2) how to effectively fuse different frames with diverse motion and blur. In this work, we propose a novel Video Restoration framework with Enhanced Deformable networks, termed EDVR, to address these challenges. First, to handle large motions, we devise a Pyramid, Cascading and Deformable (PCD) alignment module, in which frame alignment is done at the feature level using deformable convolutions in a coarse-to-fine manner. Second, we propose a Temporal and Spatial Attention (TSA) fusion module, in which attention is applied both temporally and spatially, so as to emphasize important features for subsequent restoration. Thanks to these modules, our EDVR wins the champions and outperforms the second place by a large margin in all four tracks in the NTIRE19 video restoration and enhancement challenges. EDVR also demonstrates superior performance to state-of-the-art published methods on video super-resolution and deblurring.
## Results and models Evaluated on RGB channels. The metrics are `PSNR and SSIM` . | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :--------------------------------------------------------------------------: | :-----: | :-----: | :----: | :----------------------: | :------------------------------------------------------------------------------: | | [edvrm_wotsa_x4_8x4_600k_reds](./edvrm_wotsa_8xb4-600k_reds.py) | REDS | 30.3430 | 0.8664 | 8 | [model](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522-0570e567.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522_141644.log.json) | | [edvrm_x4_8x4_600k_reds](./edvrm_8xb4-600k_reds.py) | REDS | 30.4194 | 0.8684 | 8 | [model](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20200622_102544.log.json) | | [edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4](./edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4.py) | REDS | 31.0010 | 0.8784 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228-d895a769.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228_144658.log.json) | | [edvrl_c128b40_8x8_lr2e-4_600k_reds4](./edvrl_c128b40_8xb8-lr2e-4-600k_reds4.py) | REDS | 31.0467 | 0.8793 | 8 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_c128b40_8x8_lr2e-4_600k_reds4_20220104-4509865f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_c128b40_8x8_lr2e-4_600k_reds4_20220104_171823.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/edvr/edvrm_8xb4-600k_reds.py # single-gpu train python tools/train.py configs/edvr/edvrm_8xb4-600k_reds.py # multi-gpu train ./tools/dist_train.sh configs/edvr/edvrm_8xb4-600k_reds.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py python tools/test.py configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth # single-gpu test python tools/test.py configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth # multi-gpu test ./tools/dist_test.sh configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{wang2019edvr, author = {Wang, Xintao and Chan, Kelvin C.K. and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {EDVR: Video restoration with enhanced deformable convolutional networks}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition Workshops (CVPRW)}, month = {June}, year = {2019}, } ``` ================================================ FILE: configs/edvr/README_zh-CN.md ================================================ # EDVR (CVPRW'2019) > **任务**: 视频超分辨率
EDVR (CVPRW'2019) ```bibtex @InProceedings{wang2019edvr, author = {Wang, Xintao and Chan, Kelvin C.K. and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {EDVR: Video restoration with enhanced deformable convolutional networks}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition Workshops (CVPRW)}, month = {June}, year = {2019}, } ```

在 RGB 通道上进行评估。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | REDS4 | GPU 信息 | 下载 | | :------------------------------------------------------------------------------: | :--------------: | :----------------------: | :------------------------------------------------------------------------------: | | [edvrm_wotsa_x4_8x4_600k_reds](./edvrm_wotsa_8xb4-600k_reds.py) | 30.3430 / 0.8664 | 8 | [模型](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522-0570e567.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522_141644.log.json) | | [edvrm_x4_8x4_600k_reds](./edvrm_8xb4-600k_reds.py) | 30.4194 / 0.8684 | 8 | [模型](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20200622_102544.log.json) | | [edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4](./edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4.py) | 31.0010 / 0.8784 | 8 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228-d895a769.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228_144658.log.json) | | [edvrl_c128b40_8x8_lr2e-4_600k_reds4](./edvrl_c128b40_8xb8-lr2e-4-600k_reds4.py) | 31.0467 / 0.8793 | 8 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_c128b40_8x8_lr2e-4_600k_reds4_20220104-4509865f.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_c128b40_8x8_lr2e-4_600k_reds4_20220104_171823.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/edvr/edvrm_8xb4-600k_reds.py # 单个GPU上训练 python tools/train.py configs/edvr/edvrm_8xb4-600k_reds.py # 多个GPU上训练 ./tools/dist_train.sh configs/edvr/edvrm_8xb4-600k_reds.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth # 单个GPU上测试 python tools/test.py configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth # 多个GPU上测试 ./tools/dist_test.sh configs/edvr/edvrm_8xb4-600k_reds.py https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/edvr/edvrl_c128b40_8xb8-lr2e-4-600k_reds4.py ================================================ _base_ = '../_base_/models/base_edvr.py' experiment_name = 'edvrl_c128b40_8xb8-lr2e-4-600k_reds4' save_dir = './work_dirs' work_dir = f'./work_dirs/{experiment_name}' # load_from = 'https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228-d895a769.pth' # noqa: E501 # model settings model = dict( type='EDVR', generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=128, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=40, center_frame_idx=2, with_tsa=True), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict(tsa_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[50000, 100000, 150000, 150000, 150000], restart_weights=[1, 0.5, 0.5, 0.5, 0.5], eta_min=1e-7) find_unused_parameters = True ================================================ FILE: configs/edvr/edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4.py ================================================ _base_ = '../_base_/models/base_edvr.py' experiment_name = 'edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4' save_dir = './work_dirs' work_dir = f'./work_dirs/{experiment_name}' # model settings model = dict( type='EDVR', generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=128, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=40, center_frame_idx=2, with_tsa=False), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict(tsa_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_dataloader = dict(num_workers=6, batch_size=8) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[150000, 150000, 150000, 150000], restart_weights=[1, 0.5, 0.5, 0.5], eta_min=1e-7) ================================================ FILE: configs/edvr/edvrm_8xb4-600k_reds.py ================================================ _base_ = '../_base_/models/base_edvr.py' experiment_name = 'edvrm_8xb4-600k_reds' save_dir = './work_dirs' work_dir = f'./work_dirs/{experiment_name}' # model settings pretrain_generator_url = ( 'https://download.openmmlab.com/mmediting/restorers/edvr/' 'edvrm_wotsa_x4_8x4_600k_reds_20200522-0570e567.pth') model = dict( type='EDVR', generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=64, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=10, center_frame_idx=2, with_tsa=True, init_cfg=dict( type='Pretrained', checkpoint=pretrain_generator_url, prefix='generator.')), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict(tsa_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_dataloader = dict(num_workers=6, batch_size=4) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[50000, 100000, 150000, 150000, 150000], restart_weights=[1, 1, 1, 1, 1], eta_min=1e-7) find_unused_parameters = True ================================================ FILE: configs/edvr/edvrm_wotsa_8xb4-600k_reds.py ================================================ _base_ = '../_base_/models/base_edvr.py' experiment_name = 'edvrm_wotsa_8xb4-600k_reds' save_dir = './work_dirs' work_dir = f'./work_dirs/{experiment_name}' # model settings model = dict( type='EDVR', generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=64, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=10, center_frame_idx=2, with_tsa=False), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict(tsa_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=4e-4, betas=(0.9, 0.999)), ) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[150000, 150000, 150000, 150000], restart_weights=[1, 0.5, 0.5, 0.5], eta_min=1e-7) ================================================ FILE: configs/edvr/metafile.yml ================================================ Collections: - Name: EDVR Paper: Title: 'EDVR: Video Restoration with Enhanced Deformable Convolutional Networks' URL: https://arxiv.org/abs/1905.02716?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%253A+arxiv%252FQSXk+%2528ExcitingAds%2521+cs+updates+on+arXiv.org%2529 README: configs/edvr/README.md Task: - video super-resolution Year: 2019 Models: - Config: configs/edvr/edvrm_wotsa_8xb4-600k_reds.py In Collection: EDVR Name: edvrm_wotsa_8xb4-600k_reds Results: - Dataset: REDS Metrics: PSNR: 30.343 SSIM: 0.8664 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522-0570e567.pth - Config: configs/edvr/edvrm_8xb4-600k_reds.py In Collection: EDVR Name: edvrm_8xb4-600k_reds Results: - Dataset: REDS Metrics: PSNR: 30.4194 SSIM: 0.8684 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_x4_8x4_600k_reds_20210625-e29b71b5.pth - Config: configs/edvr/edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4.py In Collection: EDVR Name: edvrl_wotsa-c128b40_8xb8-lr2e-4-600k_reds4 Results: - Dataset: REDS Metrics: PSNR: 31.001 SSIM: 0.8784 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_wotsa_c128b40_8x8_lr2e-4_600k_reds4_20211228-d895a769.pth - Config: configs/edvr/edvrl_c128b40_8xb8-lr2e-4-600k_reds4.py In Collection: EDVR Name: edvrl_c128b40_8xb8-lr2e-4-600k_reds4 Results: - Dataset: REDS Metrics: PSNR: 31.0467 SSIM: 0.8793 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/edvr/edvrl_c128b40_8x8_lr2e-4_600k_reds4_20220104-4509865f.pth ================================================ FILE: configs/eg3d/README.md ================================================ # EG3D (CVPR'2022) > [Efficient geometry-aware 3D generative adversarial networks](https://openaccess.thecvf.com/content/CVPR2022/html/Chan_Efficient_Geometry-Aware_3D_Generative_Adversarial_Networks_CVPR_2022_paper.html) > **Task**: 3D-aware Generation ## Abstract Unsupervised generation of high-quality multi-view-consistent images and 3D shapes using only collections of single-view 2D photographs has been a long-standing challenge. Existing 3D GANs are either compute-intensive or make approximations that are not 3D-consistent; the former limits quality and resolution of the generated images and the latter adversely affects multi-view consistency and shape quality. In this work, we improve the computational efficiency and image quality of 3D GANs without overly relying on these approximations. We introduce an expressive hybrid explicit-implicit network architecture that, together with other design choices, synthesizes not only high-resolution multi-view-consistent images in real time but also produces high-quality 3D geometry. By decoupling feature generation and neural rendering, our framework is able to leverage state-of-the-art 2D CNN generators, such as StyleGAN2, and inherit their efficiency and expressiveness. We demonstrate state-of-the-art 3D-aware synthesis with FFHQ and AFHQ Cats, among other experiments.
## Results and Models | Model | Dataset | Comment | FID50k | FID50k-Camera | Download | | :---------------------------------------------------------: | :-----------: | :-------------: | :----: | :-----------: | :--------------------------------------------------------------------------------------------: | | [ShapeNet-Car](./eg3d_cvt-official-rgb_shapenet-128x128.py) | ShaperNet-Car | official weight | 5.6573 | 5.2325 | [model](https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_shapenet-128x128-85757f4d.pth) | | [AFHQ](./eg3d_cvt-official-rgb_afhq-512x512.py) | AFHQ | official weight | 2.9134 | 6.4213 | [model](https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_afhq-512x512-ca1dd7c9.pth) | | [FFHQ](./eg3d_cvt-official-rgb_ffhq-512x512.py) | FFHQ | official weight | 4.3076 | 6.4453 | [model](https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_ffhq-512x512-5a0ddcb6.pth) | - `FID50k-Camera` denotes image generated with random sampled camera position. - `FID50k` denotes image generated with camera position randomly sampled from the original dataset. ### Influence of FP16 All metrics are evaluated under FP32, and it's hard to determine how they will change if we use FP16. For example, if we use FP16 at the super resolution module in [FFHQ model](./eg3d_cvt-official-rgb_ffhq-512x512.py), the output images will be slightly blurrier than the ones generated under FP32, but FID (**4.03**) will be better than FP32 ones. ## About generate images and videos with High-Level API You can use the following command to generate sequence images with continuous changed camera position as input. ```shell python demo/mmagic_inference_demo.py --model-name eg3d \ --model-config configs/eg3d/eg3d_cvt-official-rgb_afhq-512x512.py \ --model-ckpt https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_afhq-512x512-ca1dd7c9.pth \ --result-out-dir eg3d_output \ # save images and videos to `eg3d_output` --interpolation camera \ # interpolation camera position only --num-images 100 # generate 100 images during interpolation ``` The the following video will be saved to `eg3d_output`.
To interpolate the camera position and style code at the same time, you can use the following command. ```shell python demo/mmagic_inference_demo.py --model-name eg3d \ --model-config configs/eg3d/eg3d_cvt-official-rgb_ffhq-512x512.py \ --model-ckpt https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_ffhq-512x512-5a0ddcb6.pth \ --result-out-dir eg3d_output \ # save images and videos to `eg3d_output` --interpolation both \ # interpolation camera and conditioning both --num-images 100 # generate 100 images during interpolation --seed 233 # set random seed as 233 ```
If you only want to save video of depth map, you can use the following command: ```shell python demo/mmagic_inference_demo.py --model-name eg3d \ --model-config configs/eg3d/eg3d_cvt-official-rgb_shapenet-128x128.py \ --model-ckpt https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_shapenet-128x128-85757f4d.pth \ --result-out-dir eg3d_output \ # save images and videos to `eg3d_output` --interpolation camera \ # interpolation camera position only --num-images 100 \ # generate 100 images during interpolation --vis-mode depth # only visualize depth image ```
## How to prepare dataset You should prepare your dataset follow the official [repo](https://github.com/NVlabs/eg3d/tree/main/dataset_preprocessing). Then preprocess the `dataset.json` with the following script: ```python import json from argparse import ArgumentParser from mmengine.fileio.io import load def main(): parser = ArgumentParser() parser.add_argument( 'in-anno', type=str, help='Path to the official annotation file.') parser.add_argument( 'out-anno', type=str, help='Path to MMagicing\'s annotation file.') args = parser.parse_args() anno = load(args.in_anno) label = anno['labels'] anno_dict = {} for line in label: name, label = line anno_dict[name] = label with open(args.out_anno, 'w') as file: json.dump(anno_dict, file) if __name__ == '__main__': main() ``` ## Citation ```latex @InProceedings{Chan_2022_CVPR, author = {Chan, Eric R. and Lin, Connor Z. and Chan, Matthew A. and Nagano, Koki and Pan, Boxiao and De Mello, Shalini and Gallo, Orazio and Guibas, Leonidas J. and Tremblay, Jonathan and Khamis, Sameh and Karras, Tero and Wetzstein, Gordon}, title = {Efficient Geometry-Aware 3D Generative Adversarial Networks}, booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, month = {June}, year = {2022}, pages = {16123-16133} } ``` ================================================ FILE: configs/eg3d/eg3d_cvt-official-rgb_afhq-512x512.py ================================================ _base_ = '../_base_/gen_default_runtime.py' model = dict( type='EG3D', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='TriplaneGenerator', out_size=512, triplane_channels=32, triplane_size=256, num_mlps=2, sr_add_noise=False, sr_in_size=128, neural_rendering_resolution=128, renderer_cfg=dict( ray_start=2.25, ray_end=3.3, box_warp=1, depth_resolution=48, depth_resolution_importance=48, white_back=False, ), rgb2bgr=True), camera=dict( type='GaussianCamera', horizontal_mean=3.14 / 2, horizontal_std=0.35, vertical_mean=3.14 / 2 - 0.05, vertical_std=0.25, radius=2.7, fov=18.837, look_at=[0, 0, 0.2])) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_afhq.pkl' metrics = [ dict( type='FID-Full', prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type='FID-Full', prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img', color_type='color'), dict(type='PackInputs') ] test_dataset = dict( type='BasicConditionalDataset', data_root='./data/eg3d/afhq', ann_file='afhq.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 4` cost nearly **9.5GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: configs/eg3d/eg3d_cvt-official-rgb_ffhq-512x512.py ================================================ _base_ = '../_base_/gen_default_runtime.py' model = dict( type='EG3D', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='TriplaneGenerator', out_size=512, triplane_channels=32, triplane_size=256, num_mlps=2, neural_rendering_resolution=128, sr_add_noise=False, sr_in_size=128, # NOTE: double hidden channels and out channels for FFHQ-512 sr_hidden_channels=256, sr_out_channels=128, renderer_cfg=dict( ray_start=2.25, ray_end=3.3, box_warp=1, depth_resolution=48, depth_resolution_importance=48, white_back=False, ), rgb2bgr=True), camera=dict( type='GaussianCamera', horizontal_mean=3.14 / 2, horizontal_std=0.35, vertical_mean=3.14 / 2 - 0.05, vertical_std=0.25, radius=2.7, fov=18.837, look_at=[0, 0, 0.2])) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_ffhq_512.pkl' metrics = [ dict( type='FID-Full', prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type='FID-Full', prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img', color_type='color'), dict(type='PackInputs') ] test_dataset = dict( type='BasicConditionalDataset', data_root='./data/eg3d/ffhq_512', ann_file='ffhq_512.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 4` cost nearly **9.5GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: configs/eg3d/eg3d_cvt-official-rgb_shapenet-128x128.py ================================================ _base_ = '../_base_/gen_default_runtime.py' model = dict( type='EG3D', data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='TriplaneGenerator', out_size=128, zero_cond_input=True, cond_scale=0, sr_in_size=64, renderer_cfg=dict( # Official implementation set ray_start, ray_end and box_warp as # 0.1, 2.6 and 1.6 respectively, and FID is 7.2441 # ray_start=0.1, # ray_end=2.6, # box_warp=1.6, ray_start=0.4, ray_end=2.0, box_warp=1.7, depth_resolution=64, depth_resolution_importance=64, white_back=True, ), rgb2bgr=True), camera=dict( type='UniformCamera', horizontal_mean=3.141, horizontal_std=3.141, vertical_mean=3.141 / 2, vertical_std=3.141 / 2, focal=1.025390625, up=[0, 0, 1], radius=1.2), ) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_shapenet.pkl' metrics = [ dict( type='FID-Full', prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type='FID-Full', prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig'), ] test_pipeline = [ dict(type='LoadImageFromFile', key='img', color_type='color'), dict(type='PackInputs') ] test_dataset = dict( type='BasicConditionalDataset', data_root='./data/eg3d/shapenet-car', ann_file='shapenet.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 16` cost nearly **12GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=16, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # save_at_test=False, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: configs/eg3d/metafile.yml ================================================ Collections: - Name: EG3D Paper: Title: Efficient geometry-aware 3D generative adversarial networks URL: https://openaccess.thecvf.com/content/CVPR2022/html/Chan_Efficient_Geometry-Aware_3D_Generative_Adversarial_Networks_CVPR_2022_paper.html README: configs/eg3d/README.md Task: - 3d-aware generation Year: 2022 Models: - Config: configs/eg3d/eg3d_cvt-official-rgb_shapenet-128x128.py In Collection: EG3D Name: eg3d_cvt-official-rgb_shapenet-128x128 Results: - Dataset: ShaperNet-Car Metrics: FID50k: 5.6573 FID50k-Camera: 5.2325 Task: 3D-aware Generation Weights: https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_shapenet-128x128-85757f4d.pth - Config: configs/eg3d/eg3d_cvt-official-rgb_afhq-512x512.py In Collection: EG3D Name: eg3d_cvt-official-rgb_afhq-512x512 Results: - Dataset: AFHQ Metrics: FID50k: 2.9134 FID50k-Camera: 6.4213 Task: 3D-aware Generation Weights: https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_afhq-512x512-ca1dd7c9.pth - Config: configs/eg3d/eg3d_cvt-official-rgb_ffhq-512x512.py In Collection: EG3D Name: eg3d_cvt-official-rgb_ffhq-512x512 Results: - Dataset: FFHQ Metrics: FID50k: 4.3076 FID50k-Camera: 6.4453 Task: 3D-aware Generation Weights: https://download.openmmlab.com/mmediting/eg3d/eg3d_cvt-official-rgb_ffhq-512x512-5a0ddcb6.pth ================================================ FILE: configs/esrgan/README.md ================================================ # ESRGAN (ECCVW'2018) > [ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks](https://arxiv.org/abs/1809.00219) > **Task**: Image Super-Resolution ## Abstract The Super-Resolution Generative Adversarial Network (SRGAN) is a seminal work that is capable of generating realistic textures during single image super-resolution. However, the hallucinated details are often accompanied with unpleasant artifacts. To further enhance the visual quality, we thoroughly study three key components of SRGAN - network architecture, adversarial loss and perceptual loss, and improve each of them to derive an Enhanced SRGAN (ESRGAN). In particular, we introduce the Residual-in-Residual Dense Block (RRDB) without batch normalization as the basic network building unit. Moreover, we borrow the idea from relativistic GAN to let the discriminator predict relative realness instead of the absolute value. Finally, we improve the perceptual loss by using the features before activation, which could provide stronger supervision for brightness consistency and texture recovery. Benefiting from these improvements, the proposed ESRGAN achieves consistently better visual quality with more realistic and natural textures than SRGAN and won the first place in the PIRM2018-SR Challenge.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------------------------------------: | :-----: | :-----: | :----: | :----------------: | :---------------------------------------------------------------------------------: | | [esrgan_psnr_x4c64b23g32_1x16_1000k_div2k](./esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) | Set5 | 30.6428 | 0.8559 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth) | | [esrgan_psnr_x4c64b23g32_1x16_1000k_div2k](./esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) | Set14 | 27.0543 | 0.7447 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth) | | [esrgan_psnr_x4c64b23g32_1x16_1000k_div2k](./esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) | DIV2K | 29.3354 | 0.8263 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth) | | [esrgan_x4c64b23g32_1x16_400k_div2k](./esrgan_x4c64b23g32_1xb16-400k_div2k.py) | Set5 | 28.2700 | 0.7778 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth) | | [esrgan_x4c64b23g32_1x16_400k_div2k](./esrgan_x4c64b23g32_1xb16-400k_div2k.py) | Set14 | 24.6328 | 0.6491 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth) | | [esrgan_x4c64b23g32_1x16_400k_div2k](./esrgan_x4c64b23g32_1xb16-400k_div2k.py) | DIV2K | 26.6531 | 0.7340 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py # single-gpu train python tools/train.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth # single-gpu test python tools/test.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth # multi-gpu test ./tools/dist_test.sh configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{wang2018esrgan, title={Esrgan: Enhanced super-resolution generative adversarial networks}, author={Wang, Xintao and Yu, Ke and Wu, Shixiang and Gu, Jinjin and Liu, Yihao and Dong, Chao and Qiao, Yu and Change Loy, Chen}, booktitle={Proceedings of the European Conference on Computer Vision Workshops(ECCVW)}, pages={0--0}, year={2018} } ``` ================================================ FILE: configs/esrgan/README_zh-CN.md ================================================ # ESRGAN (ECCVW'2018) > **任务**: 图像超分辨率
ESRGAN (ECCVW'2018) ```bibtex @inproceedings{wang2018esrgan, title={Esrgan: Enhanced super-resolution generative adversarial networks}, author={Wang, Xintao and Yu, Ke and Wu, Shixiang and Gu, Jinjin and Liu, Yihao and Dong, Chao and Qiao, Yu and Change Loy, Chen}, booktitle={Proceedings of the European Conference on Computer Vision Workshops(ECCVW)}, pages={0--0}, year={2018} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 | Set14 | DIV2K | GPU 信息 | 下载 | | :---------------------------------------------------------------------: | :---------------: | :--------------: | :--------------: | :------: | :----------------------------------------------------------------------: | | [esrgan_psnr_x4c64b23g32_1x16_1000k_div2k](./esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) | 30.6428 / 0.8559 | 27.0543 / 0.7447 | 29.3354 / 0.8263 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420_112550.log.json) | | [esrgan_x4c64b23g32_1x16_400k_div2k](./esrgan_x4c64b23g32_1xb16-400k_div2k.py) | 28.2700 / 0.7778 | 24.6328 / 0.6491 | 26.6531 / 0.7340 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508_191042.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py # 单个GPU上训练 python tools/train.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth # 单个GPU上测试 python tools/test.py configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth # 多个GPU上测试 ./tools/dist_test.sh configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='BaseEditModel', generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=23, growth_channels=32, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=data_root + '/Set14', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[250000, 250000, 250000, 250000], restart_weights=[1, 1, 1, 1], eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py ================================================ _base_ = './esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py' experiment_name = 'esrgan_x4c64b23g32_1xb16-400k_div2k' work_dir = f'./work_dirs/{experiment_name}' scale = 4 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings pretrain_generator_url = ( 'https://download.openmmlab.com/mmediting/restorers/esrgan' '/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth') model = dict( type='ESRGAN', generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=23, growth_channels=32, upscale_factor=scale, init_cfg=dict( type='Pretrained', checkpoint=pretrain_generator_url, prefix='generator.')), discriminator=dict(type='ModifiedVGG', in_channels=3, mid_channels=64), pixel_loss=dict(type='L1Loss', loss_weight=1e-2, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'34': 1.0}, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-3, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_cfg = dict( _delete_=True, type='IterBasedTrainLoop', max_iters=400_000, val_interval=5000) # optimizer optim_wrapper = dict( _delete_=True, constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), ) # learning policy param_scheduler = dict( _delete_=True, type='MultiStepLR', by_epoch=False, milestones=[50000, 100000, 200000, 300000], gamma=0.5) ================================================ FILE: configs/esrgan/metafile.yml ================================================ Collections: - Name: ESRGAN Paper: Title: 'ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks' URL: https://arxiv.org/abs/1809.00219 README: configs/esrgan/README.md Task: - image super-resolution Year: 2018 Models: - Config: configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py In Collection: ESRGAN Name: esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 30.6428 SSIM: 0.8559 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 27.0543 SSIM: 0.7447 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 29.3354 SSIM: 0.8263 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth - Config: configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py In Collection: ESRGAN Name: esrgan_x4c64b23g32_1xb16-400k_div2k Results: - Dataset: Set5 Metrics: PSNR: 28.27 SSIM: 0.7778 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 24.6328 SSIM: 0.6491 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 26.6531 SSIM: 0.734 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth ================================================ FILE: configs/fastcomposer/README.md ================================================ # FastComposer (2023) > [FastComposer: Tuning-Free Multi-Subject Image Generation with Localized Attention](https://arxiv.org/abs/2305.10431) > **Task**: Text2Image ## Abstract Diffusion models excel at text-to-image generation, especially in subject-driven generation for personalized images. However, existing methods are inefficient due to the subject-specific fine-tuning, which is computationally intensive and hampers efficient deployment. Moreover, existing methods struggle with multi-subject generation as they often blend features among subjects. We present FastComposer which enables efficient, personalized, multi-subject text-to-image generation without fine-tuning. FastComposer uses subject embeddings extracted by an image encoder to augment the generic text conditioning in diffusion models, enabling personalized image generation based on subject images and textual instructions with only forward passes. To address the identity blending problem in the multi-subject generation, FastComposer proposes cross-attention localization supervision during training, enforcing the attention of reference subjects localized to the correct regions in the target images. Naively conditioning on subject embeddings results in subject overfitting. FastComposer proposes delayed subject conditioning in the denoising step to maintain both identity and editability in subject-driven image generation. FastComposer generates images of multiple unseen individuals with different styles, actions, and contexts. It achieves 300x-2500x speedup compared to fine-tuning-based methods and requires zero extra storage for new subjects. FastComposer paves the way for efficient, personalized, and high-quality multi-subject image creation.
## Pretrained models This model has several weights including vae, unet and clip. You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and [clipModel](https://huggingface.co/openai/clip-vit-large-patch14),and then change the 'stable_diffusion_v15_url' and 'clip_vit_url' in config to the corresponding weights path and "finetuned_model_path" to the weight path of fastcomposer. | Model | Dataset | Download | | :------------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------: | | [FastComposer](./fastcomposer_8xb16_FFHQ.py) | - | [model](https://download.openxlab.org.cn/models/xiaomile/fastcomposer/weight/pytorch_model.bin) | ## Quick Start You can run the demo locally by ```bash python demo/gradio_fastcomposer.py ``` Or running the following codes, you can get a text-generated image. ```python import numpy as np import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules import torch, gc gc.collect() torch.cuda.empty_cache() register_all_modules() cfg_file = Config.fromfile('configs/fastcomposer/fastcomposer_8xb16_FFHQ.py') fastcomposer = MODELS.build(cfg_file.model).cuda() prompt = "A man img and a man img sitting in a park" negative_prompt = "((((ugly)))), (((duplicate))), ((morbid)), ((mutilated)), [out of frame], extra fingers, mutated hands, ((poorly drawn hands)), ((poorly drawn face)), (((mutation))), (((deformed))), ((ugly)), blurry, ((bad anatomy)), (((bad proportions))), ((extra limbs)), cloned face, (((disfigured))). out of frame, ugly, extra limbs, (bad anatomy), gross proportions, (malformed limbs), ((missing arms)), ((missing legs)), (((extra arms))), (((extra legs))), mutated hands, (fused fingers), (too many fingers), (((long neck)))" alpha_ = 0.75 guidance_scale = 5 num_steps = 50 num_images = 1 image = [] seed = -1 image1 = mmcv.imread('https://user-images.githubusercontent.com/14927720/265911400-91635451-54b6-4dc6-92a7-c1d02f88b62e.jpeg') image2 = mmcv.imread('https://user-images.githubusercontent.com/14927720/265911502-66b67f53-dff0-4d25-a9af-3330e446aa48.jpeg') image.append(Image.fromarray(image1)) image.append(Image.fromarray(image2)) if len(image) == 0: raise Exception("You need to upload at least one image.") num_subject_in_text = ( np.array(fastcomposer.special_tokenizer.encode(prompt)) == fastcomposer.image_token_id ).sum() if num_subject_in_text != len(image): raise Exception(f"Number of subjects in the text description doesn't match the number of reference images, #text subjects: {num_subject_in_text} #reference image: {len(image)}", ) if seed == -1: seed = np.random.randint(0, 1000000) device = torch.device('cuda' if torch.cuda.is_available( ) else 'cpu') generator = torch.Generator(device=device) generator.manual_seed(seed) output_dict = fastcomposer.infer(prompt, negative_prompt=negative_prompt, height=512, width=512, num_inference_steps=num_steps, guidance_scale=guidance_scale, num_images_per_prompt=num_images, generator=generator, alpha_=alpha_, reference_subject_images=image) samples = output_dict['samples'] for idx, sample in enumerate(samples): sample.save(f'sample_{idx}.png') ``` ## Citation ```bibtex @article{xiao2023fastcomposer, title={FastComposer: Tuning-Free Multi-Subject Image Generation with Localized Attention}, author={Xiao, Guangxuan and Yin, Tianwei and Freeman, William T. and Durand, Frédo and Han, Song}, journal={arXiv}, year={2023} } ``` ================================================ FILE: configs/fastcomposer/README_zh-CN.md ================================================ # FastComposer (2023) > [FastComposer: Tuning-Free Multi-Subject Image Generation with Localized Attention](https://arxiv.org/abs/2305.10431) > **任务**: 文本转图像 ## 摘要 扩散模型在文本到图像生成方面表现出色,尤其在以主题驱动的个性化图像生成方面。然而,现有方法由于主题特定的微调而效率低下,因为需要大量的计算资源,而这限制了扩散模型高效部署的可能性。此外,现有方法在多主题生成方面存在困难,因为它们经常在不同主题之间混合特征。因此我们提出了FastComposer,它可以实现高效、个性化、多主题的文本到图像生成,而无需进行微调。FastComposer利用图像编码器提取的主题嵌入来增强扩散模型中的通用文本条件,只需进行前向传递即可基于主题图像和文本指令进行个性化图像生成。为了解决多主题生成中的身份混合问题,FastComposer在训练过程中提出了交叉注意力定位监督,强制参考主题的注意力定位于目标图像中的正确区域。简单地基于主题嵌入进行条件设定会导致主题过度拟合的问题。为了在以主题驱动的图像生成中同时保持身份和可编辑性,FastComposer在去噪步骤中提出了延迟主题条件设定的方法。FastComposer可以生成具有不同风格、动作和背景的多个未知个体的图像。与基于微调的方法相比,它实现了300倍到2500倍的加速,并且对于新主题不需要额外的存储空间。正因如此FastComposer为高效、个性化和高质量的多主题图像创作铺平了道路。
## 预训练模型 该模型有几个权重,包括vae,unet和clip。您应该先从[stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) 和 [clipModel](https://huggingface.co/openai/clip-vit-large-patch14) 下载权重,然后将配置中的“stable_diffusion_v15_url”和”clip_vit_url“更改为对应的权重路径,将”finetuned_model_path“更改为fastcomposer的权重路径。 | Model | Dataset | Download | | :------------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------: | | [FastComposer](./fastcomposer_8xb16_FFHQ.py) | - | [model](https://download.openxlab.org.cn/models/xiaomile/fastcomposer/weight/pytorch_model.bin) | ## 快速开始 您可以通过以下方式在本地运行来演示 ```bash python demo/gradio_fastcomposer.py ``` 或者运行一下代码,您就能获得依照文本生成的特定图像。 ```python import numpy as np import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules import torch, gc gc.collect() torch.cuda.empty_cache() register_all_modules() cfg_file = Config.fromfile('configs/fastcomposer/fastcomposer_8xb16_FFHQ.py') fastcomposer = MODELS.build(cfg_file.model).cuda() prompt = "A man img and a man img sitting in a park" negative_prompt = "((((ugly)))), (((duplicate))), ((morbid)), ((mutilated)), [out of frame], extra fingers, mutated hands, ((poorly drawn hands)), ((poorly drawn face)), (((mutation))), (((deformed))), ((ugly)), blurry, ((bad anatomy)), (((bad proportions))), ((extra limbs)), cloned face, (((disfigured))). out of frame, ugly, extra limbs, (bad anatomy), gross proportions, (malformed limbs), ((missing arms)), ((missing legs)), (((extra arms))), (((extra legs))), mutated hands, (fused fingers), (too many fingers), (((long neck)))" alpha_ = 0.75 guidance_scale = 5 num_steps = 50 num_images = 1 image = [] seed = -1 image1 = mmcv.imread('https://user-images.githubusercontent.com/14927720/265911400-91635451-54b6-4dc6-92a7-c1d02f88b62e.jpeg') image2 = mmcv.imread('https://user-images.githubusercontent.com/14927720/265911502-66b67f53-dff0-4d25-a9af-3330e446aa48.jpeg') image.append(Image.fromarray(image1)) image.append(Image.fromarray(image2)) if len(image) == 0: raise Exception("You need to upload at least one image.") num_subject_in_text = ( np.array(fastcomposer.special_tokenizer.encode(prompt)) == fastcomposer.image_token_id ).sum() if num_subject_in_text != len(image): raise Exception(f"Number of subjects in the text description doesn't match the number of reference images, #text subjects: {num_subject_in_text} #reference image: {len(image)}", ) if seed == -1: seed = np.random.randint(0, 1000000) device = torch.device('cuda' if torch.cuda.is_available( ) else 'cpu') generator = torch.Generator(device=device) generator.manual_seed(seed) output_dict = fastcomposer.infer(prompt, negative_prompt=negative_prompt, height=512, width=512, num_inference_steps=num_steps, guidance_scale=guidance_scale, num_images_per_prompt=num_images, generator=generator, alpha_=alpha_, reference_subject_images=image) samples = output_dict['samples'] for idx, sample in enumerate(samples): sample.save(f'sample_{idx}.png') ``` ## 引用 ```bibtex @article{xiao2023fastcomposer, title={FastComposer: Tuning-Free Multi-Subject Image Generation with Localized Attention}, author={Xiao, Guangxuan and Yin, Tianwei and Freeman, William T. and Durand, Frédo and Han, Song}, journal={arXiv}, year={2023} } ``` ================================================ FILE: configs/fastcomposer/fastcomposer_8xb16_FFHQ.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' clip_vit_url = 'openai/clip-vit-large-patch14' finetuned_model_path = 'https://download.openxlab.org.cn/models/xiaomile/'\ 'fastcomposer/weight/pytorch_model.bin' model = dict( type='FastComposer', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, pretrained_cfg=dict( finetuned_model_path=finetuned_model_path, enable_xformers_memory_efficient_attention=None, pretrained_model_name_or_path=stable_diffusion_v15_url, image_encoder=clip_vit_url, revision=None, non_ema_revision=None, object_localization=None, object_localization_weight=0.01, localization_layers=5, mask_loss=None, mask_loss_prob=0.5, object_localization_threshold=1.0, object_localization_normalize=None, no_object_augmentation=True, object_resolution=256), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), dtype='fp32', data_preprocessor=dict(type='DataPreprocessor')) ================================================ FILE: configs/fastcomposer/metafile.yml ================================================ Collections: - Name: FastComposer Paper: Title: 'FastComposer: Tuning-Free Multi-Subject Image Generation with Localized Attention' URL: https://arxiv.org/abs/2305.10431 README: configs/fastcomposer/README.md Task: - text2image Year: 2023 Models: - Config: configs/fastcomposer/fastcomposer_8xb16_FFHQ.py In Collection: FastComposer Name: fastcomposer_8xb16_FFHQ Results: - Dataset: '-' Metrics: {} Task: Text2Image Weights: https://download.openxlab.org.cn/models/xiaomile/fastcomposer/weight/pytorch_model.bin ================================================ FILE: configs/flavr/README.md ================================================ # FLAVR (arXiv'2020) > [FLAVR: Flow-Agnostic Video Representations for Fast Frame Interpolation](https://arxiv.org/pdf/2012.08512.pdf) > **Task**: Video Interpolation ## Abstract Most modern frame interpolation approaches rely on explicit bidirectional optical flows between adjacent frames, thus are sensitive to the accuracy of underlying flow estimation in handling occlusions while additionally introducing computational bottlenecks unsuitable for efficient deployment. In this work, we propose a flow-free approach that is completely end-to-end trainable for multi-frame video interpolation. Our method, FLAVR, is designed to reason about non-linear motion trajectories and complex occlusions implicitly from unlabeled videos and greatly simplifies the process of training, testing and deploying frame interpolation models. Furthermore, FLAVR delivers up to 6× speed up compared to the current state-of-the-art methods for multi-frame interpolation while consistently demonstrating superior qualitative and quantitative results compared with prior methods on popular benchmarks including Vimeo-90K, Adobe-240FPS, and GoPro. Finally, we show that frame interpolation is a competitive self-supervised pre-training task for videos via demonstrating various novel applications of FLAVR including action recognition, optical flow estimation, motion magnification, and video object tracking. Code and trained models are provided in the supplementary material.
## Results and models Evaluated on RGB channels. The metrics are `PSNR / SSIM` . | Model | Dataset | scale | PSNR | SSIM | Training Resources | Download | | :------------------------------------------------------------------------: | :--------: | :---: | :-----: | :-----: | :-----------------: | :----------------------------------------------------------------------------: | | [flavr_in4out1_g8b4_vimeo90k_septuplet](./flavr_in4out1_8xb4_vimeo90k-septuplet.py) | vimeo90k-T | x2 | 36.3340 | 0.96015 | 8 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.log.json) | Note: FLAVR for x8 VFI task will supported in the future. ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py # single-gpu train python tools/train.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py # multi-gpu train ./tools/dist_train.sh configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth # single-gpu test python tools/test.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth # multi-gpu test ./tools/dist_test.sh configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @article{kalluri2020flavr, title={Flavr: Flow-agnostic video representations for fast frame interpolation}, author={Kalluri, Tarun and Pathak, Deepak and Chandraker, Manmohan and Tran, Du}, journal={arXiv preprint arXiv:2012.08512}, year={2020} } ``` ================================================ FILE: configs/flavr/README_zh-CN.md ================================================ # FLAVR (arXiv'2020) > [FLAVR: Flow-Agnostic Video Representations for Fast Frame Interpolation](https://arxiv.org/abs/2012.08512.pdf) > **任务**: 视频插帧 ## 预训练模型测试结果 在 RGB 通道上评估。 评估指标 `PSNR / SSIM`。 | 算法 | scale | Vimeo90k-triplet | GPU 信息 | 下载 | | :-----------------------------------------------------------------------------: | :---: | :---------------: | :-----------------: | :------------------------------------------------------------------------------: | | [flavr_in4out1_g8b4_vimeo90k_septuplet](./flavr_in4out1_8xb4_vimeo90k-septuplet.py) | x2 | 36.3340 / 0.96015 | 8 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.log.json) | 注:FLAVR 中的 8 倍视频插帧算法将会在未来版本中支持。 ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py # 单个GPU上训练 python tools/train.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py # 多个GPU上训练 ./tools/dist_train.sh configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth # 单个GPU上测试 python tools/test.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth # 多个GPU上测试 ./tools/dist_test.sh configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
## Citation ```bibtex @article{kalluri2020flavr, title={Flavr: Flow-agnostic video representations for fast frame interpolation}, author={Kalluri, Tarun and Pathak, Deepak and Chandraker, Manmohan and Tran, Du}, journal={arXiv preprint arXiv:2012.08512}, year={2020} } ``` ================================================ FILE: configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'flavr_in4out1_8xb4_vimeo90k-septuplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BasicInterpolator', generator=dict( type='FLAVRNet', num_input_frames=4, num_output_frames=1, mid_channels_list=[512, 256, 128, 64], encoder_layers_list=[2, 2, 2, 2], bias=False, norm_cfg=None, join_type='concat', up_mode='transpose'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=4, step_frames=1, init_cfg=None, data_preprocessor=dict(type='DataPreprocessor', )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type='FixedCrop', keys=['img', 'gt'], crop_size=(256, 256)), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict( type='ColorJitter', keys=['img', 'gt'], channel_order='rgb', brightness=0.05, contrast=0.05, saturation=0.05, hue=0.05), dict(type='TemporalReverse', keys=['img'], reverse_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] demo_pipeline = [ dict( type='LoadImageFromFile', key='img', channel_order='rgb', imdecode_backend='pillow'), dict(type='PackInputs') ] # dataset settings train_dataset_type = 'BasicFramesDataset' val_dataset_type = 'BasicFramesDataset' data_root = 'data/vimeo90k' train_dataloader = dict( num_workers=16, batch_size=4, # 8 gpu persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=True), dataset=dict( type=train_dataset_type, ann_file='txt/sep_trainlist.txt', metainfo=dict(dataset_type='vimeo90k_septenary', task_name='vfi'), data_root=data_root, data_prefix=dict(img='GT', gt='GT'), pipeline=train_pipeline, depth=2, load_frames_list=dict( img=['im1.png', 'im3.png', 'im5.png', 'im7.png'], gt=['im4.png']))) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=val_dataset_type, ann_file='txt/sep_testlist.txt', metainfo=dict(dataset_type='vimeo90k_septenary', task_name='vfi'), data_root=data_root, data_prefix=dict(img='GT', gt='GT'), pipeline=val_pipeline, depth=2, load_frames_list=dict( img=['im1.png', 'im3.png', 'im5.png', 'im7.png'], gt=['im4.png']))) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=500) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)), ) # learning policy param_scheduler = dict( type='ReduceLR', by_epoch=True, mode='min', factor=0.5, patience=10, cooldown=20) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=1, save_optimizer=True, by_epoch=True, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), sampler_seed=dict(type='DistSamplerSeedHook'), param_scheduler=dict( type='ReduceLRSchedulerHook', by_epoch=True, interval=1, val_metric='MAE'), ) log_processor = dict(type='LogProcessor', by_epoch=True) ================================================ FILE: configs/flavr/metafile.yml ================================================ Collections: - Name: FLAVR Paper: Title: 'FLAVR: Flow-Agnostic Video Representations for Fast Frame Interpolation' URL: https://arxiv.org/pdf/2012.08512.pdf README: configs/flavr/README.md Task: - video interpolation Year: 2020 Models: - Config: configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py In Collection: FLAVR Name: flavr_in4out1_8xb4_vimeo90k-septuplet Results: - Dataset: vimeo90k-T Metrics: PSNR: 36.334 SSIM: 0.96015 Task: Video Interpolation Weights: https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth ================================================ FILE: configs/gca/README.md ================================================ # GCA (AAAI'2020) > [Natural Image Matting via Guided Contextual Attention](https://arxiv.org/abs/2001.04069) > **Task**: Matting ## Abstract Over the last few years, deep learning based approaches have achieved outstanding improvements in natural image matting. Many of these methods can generate visually plausible alpha estimations, but typically yield blurry structures or textures in the semitransparent area. This is due to the local ambiguity of transparent objects. One possible solution is to leverage the far-surrounding information to estimate the local opacity. Traditional affinity-based methods often suffer from the high computational complexity, which are not suitable for high resolution alpha estimation. Inspired by affinity-based method and the successes of contextual attention in inpainting, we develop a novel end-to-end approach for natural image matting with a guided contextual attention module, which is specifically designed for image matting. Guided contextual attention module directly propagates high-level opacity information globally based on the learned low-level affinity. The proposed method can mimic information flow of affinity-based methods and utilize rich features learned by deep neural networks simultaneously. Experiment results on Composition-1k testing set and this http URL benchmark dataset demonstrate that our method outperforms state-of-the-art approaches in natural image matting.
## Results and models | Model | Dataset | SAD | MSE | GRAD | CONN | Training Resources | Download | | :--------------------------------------------------------------: | :------------: | :-------: | :--------: | :-------: | :-------: | :----------------: | :-----------------------------------------------------------------: | | [baseline (our)](./baseline_r34_4xb10-200k_comp1k.py) | Composition-1K | 34.61 | 0.0083 | 16.21 | 32.12 | 4 | [model](https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.log) | | [GCA (our)](./gca_r34_4xb10-200k_comp1k.py) | Composition-1K | **33.38** | **0.0081** | **14.96** | **30.59** | 4 | [model](https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.log) | | [baseline (with DIM pipeline)](./baseline_r34_4xb10-dimaug-200k_comp1k.py) | Composition-1K | 49.95 | 0.0144 | 30.21 | 49.67 | 4 | [model](https://download.openmmlab.com/mmediting/mattors/gca/baseline_dimaug_r34_4x10_200k_comp1k_SAD-49.95_20200626_231612-535c9a11.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/gca/baseline_dimaug_r34_4x10_200k_comp1k_20200626_231612.log.json) | | [GCA (with DIM pipeline)](./gca_r34_4xb10-dimaug-200k_comp1k.py) | Composition-1K | 49.42 | 0.0129 | 28.07 | 49.47 | 4 | [model](https://download.openmmlab.com/mmediting/mattors/gca/gca_dimaug_r34_4x10_200k_comp1k_SAD-49.42_20200626_231422-8e9cc127.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/gca/gca_dimaug_r34_4x10_200k_comp1k_20200626_231422.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/gca/gca_r34_4xb10-200k_comp1k.py # single-gpu train python tools/train.py configs/gca/gca_r34_4xb10-200k_comp1k.py # multi-gpu train ./tools/dist_train.sh configs/gca/gca_r34_4xb10-200k_comp1k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth # single-gpu test python tools/test.py configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth # multi-gpu test ./tools/dist_test.sh configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{li2020natural, title={Natural Image Matting via Guided Contextual Attention}, author={Li, Yaoyi and Lu, Hongtao}, booktitle={Association for the Advancement of Artificial Intelligence (AAAI)}, year={2020} } ``` ================================================ FILE: configs/gca/README_zh-CN.md ================================================ # GCA (AAAI'2020) > **任务**: 图像抠图
GCA (AAAI'2020) ```bibtex @inproceedings{li2020natural, title={Natural Image Matting via Guided Contextual Attention}, author={Li, Yaoyi and Lu, Hongtao}, booktitle={Association for the Advancement of Artificial Intelligence (AAAI)}, year={2020} } ```

| 算法 | SAD | MSE | GRAD | CONN | GPU 信息 | 下载 | | :------------------------------------------------: | :-------: | :--------: | :-------: | :-------: | :------: | :-------------------------------------------------------------------------------------------------------: | | 基线 (原文) | 40.62 | 0.0106 | 21.53 | 38.43 | - | - | | GCA (原文) | 35.28 | 0.0091 | 16.92 | 32.53 | - | - | | [基线 (复现)](./baseline_r34_4xb10-200k_comp1k.py) | 34.61 | 0.0083 | 16.21 | 32.12 | 4 | [模型](https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.log) | | [GCA (复现)](./gca_r34_4xb10-200k_comp1k.py) | **33.38** | **0.0081** | **14.96** | **30.59** | 4 | [模型](https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.log) | **其他结果** | 算法 | SAD | MSE | GRAD | CONN | GPU 信息 | 下载 | | :------------------------------------------------------------------: | :---: | :----: | :---: | :---: | :------: | :-----------------------------------------------------------------------------------------------------: | | [基线 (使用 DIM 流水线)](./baseline_r34_4xb10-dimaug-200k_comp1k.py) | 49.95 | 0.0144 | 30.21 | 49.67 | 4 | [模型](https://download.openmmlab.com/mmediting/mattors/gca/baseline_dimaug_r34_4x10_200k_comp1k_SAD-49.95_20200626_231612-535c9a11.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/gca/baseline_dimaug_r34_4x10_200k_comp1k_20200626_231612.log.json) | | [GCA (使用 DIM 流水线)](./gca_r34_4xb10-dimaug-200k_comp1k.py) | 49.42 | 0.0129 | 28.07 | 49.47 | 4 | [模型](https://download.openmmlab.com/mmediting/mattors/gca/gca_dimaug_r34_4x10_200k_comp1k_SAD-49.42_20200626_231422-8e9cc127.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/gca/gca_dimaug_r34_4x10_200k_comp1k_20200626_231422.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/gca/gca_r34_4xb10-200k_comp1k.py # 单个GPU上训练 python tools/train.py configs/gca/gca_r34_4xb10-200k_comp1k.py # 多个GPU上训练 ./tools/dist_train.sh configs/gca/gca_r34_4xb10-200k_comp1k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth # 单个GPU上测试 python tools/test.py configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth # 多个GPU上测试 ./tools/dist_test.sh configs/gca/gca_r34_4xb10-200k_comp1k.py https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/gca/baseline_r34_4xb10-200k_comp1k.py ================================================ _base_ = [ '../_base_/datasets/comp1k.py', '../_base_/matting_default_runtime.py' ] experiment_name = 'baseline_r34_4xb10-200k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='GCA', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='as_is', # proc by pipeline FormatTrimap ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='ResShortcutEnc', block='BasicBlock', layers=[3, 4, 4, 2], in_channels=6, with_spectral_norm=True, init_cfg=dict( type='Pretrained', checkpoint='open-mmlab://mmedit/res34_en_nomixup')), decoder=dict( type='ResShortcutDec', block='BasicBlockDec', layers=[2, 3, 3, 2], with_spectral_norm=True)), loss_alpha=dict(type='L1Loss'), test_cfg=dict( resize_method='pad', resize_mode='reflect', size_divisor=32, )) # dataset settings data_root = 'data/adobe_composition-1k' bg_dir = 'data/coco/train2017' train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='RandomLoadResizeBg', bg_dir=bg_dir), dict( type='CompositeFg', fg_dirs=[ f'{data_root}/Training_set/Adobe-licensed images/fg', f'{data_root}/Training_set/Other/fg' ], alpha_dirs=[ f'{data_root}/Training_set/Adobe-licensed images/alpha', f'{data_root}/Training_set/Other/alpha' ]), dict( type='RandomAffine', keys=['alpha', 'fg'], degrees=30, scale=(0.8, 1.25), shear=10, flip_ratio=0.5), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='CropAroundCenter', crop_size=512), dict(type='RandomJitter'), dict(type='MergeFgAndBg'), dict(type='FormatTrimap', to_onehot=True), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='FormatTrimap', to_onehot=True), dict(type='PackInputs'), ] train_dataloader = dict( batch_size=10, num_workers=8, dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=200_000, val_interval=10_000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=4e-4, betas=[0.5, 0.999])) # learning policy param_scheduler = [ dict( type='LinearLR', start_factor=0.001, begin=0, end=5000, by_epoch=False, ), dict( type='CosineAnnealingLR', T_max=200_000, # TODO, need more check eta_min=0, begin=0, end=200_000, by_epoch=False, ) ] # checkpoint saving # inheritate from default_runtime.py # runtime settings # inheritate from default_runtime.py ================================================ FILE: configs/gca/baseline_r34_4xb10-dimaug-200k_comp1k.py ================================================ _base_ = ['./baseline_r34_4xb10-200k_comp1k.py'] experiment_name = 'baseline_r34_4xb10-dimaug-200k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict(backbone=dict(encoder=dict(in_channels=4))) # dataset settings train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='merged'), dict( type='CropAroundUnknown', keys=['alpha', 'merged'], crop_sizes=[320, 480, 640]), dict(type='Flip', keys=['alpha', 'merged']), dict( type='Resize', keys=['alpha', 'merged'], scale=(320, 320), keep_ratio=False), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='FormatTrimap', to_onehot=False), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='FormatTrimap', to_onehot=False), dict(type='PackInputs'), ] train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) val_dataloader = dict(dataset=dict(pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/gca/gca_r34_4xb10-200k_comp1k.py ================================================ _base_ = [ '../_base_/datasets/comp1k.py', '../_base_/matting_default_runtime.py' ] experiment_name = 'gca_r34_4xb10-200k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='GCA', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='as_is', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='ResGCAEncoder', block='BasicBlock', layers=[3, 4, 4, 2], in_channels=6, with_spectral_norm=True, init_cfg=dict( type='Pretrained', checkpoint='open-mmlab://mmedit/res34_en_nomixup')), decoder=dict( type='ResGCADecoder', block='BasicBlockDec', layers=[2, 3, 3, 2], with_spectral_norm=True)), loss_alpha=dict(type='L1Loss'), test_cfg=dict( resize_method='pad', resize_mode='reflect', size_divisor=32, )) # dataset settings data_root = 'data/adobe_composition-1k' bg_dir = 'data/coco/train2017' train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='RandomLoadResizeBg', bg_dir=bg_dir), dict( type='CompositeFg', fg_dirs=[ f'{data_root}/Training_set/Adobe-licensed images/fg', f'{data_root}/Training_set/Other/fg' ], alpha_dirs=[ f'{data_root}/Training_set/Adobe-licensed images/alpha', f'{data_root}/Training_set/Other/alpha' ]), dict( type='RandomAffine', keys=['alpha', 'fg'], degrees=30, scale=(0.8, 1.25), shear=10, flip_ratio=0.5), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='CropAroundCenter', crop_size=512), dict(type='RandomJitter'), dict(type='MergeFgAndBg'), dict(type='FormatTrimap', to_onehot=True), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='FormatTrimap', to_onehot=True), dict(type='PackInputs'), ] train_dataloader = dict( batch_size=10, num_workers=8, dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=200_000, val_interval=10_000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=4e-4, betas=[0.5, 0.999])) # learning policy param_scheduler = [ dict( type='LinearLR', start_factor=0.001, begin=0, end=5000, by_epoch=False, ), dict( type='CosineAnnealingLR', T_max=200_000, # TODO, need more check eta_min=0, begin=0, end=200_000, by_epoch=False, ) ] # checkpoint saving # inheritate from _base_ # runtime settings # inheritate from _base_ ================================================ FILE: configs/gca/gca_r34_4xb10-dimaug-200k_comp1k.py ================================================ _base_ = ['./gca_r34_4xb10-200k_comp1k.py'] experiment_name = 'gca_r34_4xb10-dimaug-200k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict(backbone=dict(encoder=dict(in_channels=4))) # dataset settings train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='merged'), dict( type='CropAroundUnknown', keys=['alpha', 'merged'], crop_sizes=[320, 480, 640]), dict(type='Flip', keys=['alpha', 'merged']), dict( type='Resize', keys=['alpha', 'merged'], scale=(320, 320), keep_ratio=False), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='FormatTrimap', to_onehot=False), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='FormatTrimap', to_onehot=False), dict(type='PackInputs'), ] train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) val_dataloader = dict(dataset=dict(pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/gca/metafile.yml ================================================ Collections: - Name: GCA Paper: Title: Natural Image Matting via Guided Contextual Attention URL: https://arxiv.org/abs/2001.04069 README: configs/gca/README.md Task: - matting Year: 2020 Models: - Config: configs/gca/baseline_r34_4xb10-200k_comp1k.py In Collection: GCA Name: baseline_r34_4xb10-200k_comp1k Results: - Dataset: Composition-1K Metrics: CONN: 32.12 GRAD: 16.21 MSE: 0.0083 SAD: 34.61 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.pth - Config: configs/gca/gca_r34_4xb10-200k_comp1k.py In Collection: GCA Name: gca_r34_4xb10-200k_comp1k Results: - Dataset: Composition-1K Metrics: CONN: 30.59 GRAD: 14.96 MSE: 0.0081 SAD: 33.38 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/gca/gca_r34_4x10_200k_comp1k_SAD-33.38_20220615-65595f39.pth - Config: configs/gca/baseline_r34_4xb10-dimaug-200k_comp1k.py In Collection: GCA Name: baseline_r34_4xb10-dimaug-200k_comp1k Results: - Dataset: Composition-1K Metrics: CONN: 49.67 GRAD: 30.21 MSE: 0.0144 SAD: 49.95 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/gca/baseline_dimaug_r34_4x10_200k_comp1k_SAD-49.95_20200626_231612-535c9a11.pth - Config: configs/gca/gca_r34_4xb10-dimaug-200k_comp1k.py In Collection: GCA Name: gca_r34_4xb10-dimaug-200k_comp1k Results: - Dataset: Composition-1K Metrics: CONN: 49.47 GRAD: 28.07 MSE: 0.0129 SAD: 49.42 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/gca/gca_dimaug_r34_4x10_200k_comp1k_SAD-49.42_20200626_231422-8e9cc127.pth ================================================ FILE: configs/ggan/README.md ================================================ # GGAN (ArXiv'2017) > [Geometric GAN](https://arxiv.org/abs/1705.02894) > **Task**: Unconditional GANs ## Abstract Generative Adversarial Nets (GANs) represent an important milestone for effective generative models, which has inspired numerous variants seemingly different from each other. One of the main contributions of this paper is to reveal a unified geometric structure in GAN and its variants. Specifically, we show that the adversarial generative model training can be decomposed into three geometric steps: separating hyperplane search, discriminator parameter update away from the separating hyperplane, and the generator update along the normal vector direction of the separating hyperplane. This geometric intuition reveals the limitations of the existing approaches and leads us to propose a new formulation called geometric GAN using SVM separating hyperplane that maximizes the margin. Our theoretical analysis shows that the geometric GAN converges to a Nash equilibrium between the discriminator and generator. In addition, extensive numerical results show that the superior performance of geometric GAN.
## Results and models
GGAN 64x64, CelebA-Cropped
| Model | Dataset | SWD | MS-SSIM | FID | Download | | :-------------------------------------------------------------------: | :------------: | :-----------------------------: | :-----: | :-----: | :----------------------------------------------------------------------: | | [GGAN 64x64](./ggan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py) | CelebA-Cropped | 11.18, 12.21, 39.16/20.85 | 0.3318 | 20.1797 | [model](https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m.pth) \| [log](https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m_20210430_113839.log.json) | | [GGAN 128x128](./ggan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py) | CelebA-Cropped | 9.81, 11.29, 19.22, 47.79/22.03 | 0.3149 | 18.7647 | [model](https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210430_143027-516423dc.pth) \| [log](https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210423_154258.log.json) | | [GGAN 64x64](./ggan_lsgan-archi_lr1e-4-1xb128-20Mimgs_lsun-bedroom-64x64.py) | LSUN-Bedroom | 9.1, 6.2, 12.27/9.19 | 0.0649 | 39.9261 | [model](https://download.openmmlab.com/mmediting/ggan/ggan_lsun-bedroom_lsgan_archi_lr-1e-4_64_b128x1_20m_20210430_143114-5d99b76c.pth) \| [log](https://download.openmmlab.com/mmediting/ggan/ggan_lsun-bedroom_lsgan_archi_lr-1e-4_64_b128x1_20m_20210428_202027.log.json) | Note: In the original implementation of [GGAN](https://github.com/lim0606/pytorch-geometric-gan), they set `G_iters` to 10. However our framework does not support `G_iters` currently, so we dropped the settings in the original implementation and conducted several experiments with our own settings. We have shown above the experiment results with the lowest `fid` score. \ Original settings and our settings: | Model | Dataset | Architecture | optimizer | lr_G | lr_D | G_iters | D_iters | | :----------------: | :------------: | :----------: | :-------: | :----: | :----: | :-----: | :-----: | | GGAN(origin) 64x64 | CelebA-Cropped | dcgan-archi | RMSprop | 0.0002 | 0.0002 | 10 | 1 | | GGAN(ours) 64x64 | CelebA-Cropped | dcgan-archi | Adam | 0.001 | 0.001 | 1 | 1 | | GGAN(origin) 64x64 | LSUN-Bedroom | dcgan-archi | RMSprop | 0.0002 | 0.0002 | 10 | 1 | | GGAN(ours) 64x64 | LSUN-Bedroom | lsgan-archi | Adam | 0.0001 | 0.0001 | 1 | 1 | ## Citation ```latex @article{lim2017geometric, title={Geometric gan}, author={Lim, Jae Hyun and Ye, Jong Chul}, journal={arXiv preprint arXiv:1705.02894}, year={2017}, url={https://arxiv.org/abs/1705.02894}, } ``` ================================================ FILE: configs/ggan/ggan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] model = dict(discriminator=dict(output_scale=4, out_channels=1)) # define dataset batch_size = 128 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0.5, 0.99)))) train_cfg = dict(max_iters=100000) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict( checkpoint=dict( max_keep_ckpts=20, save_best='FID-Full-50k/fid', rule='less')) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/ggan/ggan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_128x128.py', '../_base_/datasets/unconditional_imgs_128x128.py', '../_base_/gen_default_runtime.py' ] model = dict(discriminator=dict(output_scale=4, out_channels=1)) # define dataset batch_size = 64 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99)))) train_cfg = dict(max_iters=160000) default_hooks = dict( checkpoint=dict( max_keep_ckpts=20, save_best='FID-Full-50k/fid', rule='less')) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 128, 128)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/ggan/ggan_lsgan-archi_lr1e-4-1xb128-20Mimgs_lsun-bedroom-64x64.py ================================================ _base_ = [ '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] model = dict( type='GGAN', noise_size=1024, data_preprocessor=dict(type='DataPreprocessor'), generator=dict(type='LSGANGenerator', output_scale=64), discriminator=dict(type='LSGANDiscriminator', input_scale=64)) # define dataset batch_size = 128 data_root = 'data/lsun/images/bedroom_train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99)))) default_hooks = dict( checkpoint=dict( max_keep_ckpts=20, save_best=['FID-Full-50k/fid', 'swd/avg', 'ms-ssim/avg'], rule=['less', 'less', 'greater'])) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] train_cfg = dict(max_iters=160000) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] val_metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), ] val_evaluator = dict(metrics=val_metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/ggan/metafile.yml ================================================ Collections: - Name: GGAN Paper: Title: Geometric GAN URL: https://arxiv.org/abs/1705.02894 README: configs/ggan/README.md Task: - unconditional gans Year: 2017 Models: - Config: configs/ggan/ggan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py In Collection: GGAN Name: ggan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64 Results: - Dataset: CelebA-Cropped Metrics: FID: 20.1797 MS-SSIM: 0.3318 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m.pth - Config: configs/ggan/ggan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py In Collection: GGAN Name: ggan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128 Results: - Dataset: CelebA-Cropped Metrics: FID: 18.7647 MS-SSIM: 0.3149 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/ggan/ggan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210430_143027-516423dc.pth - Config: configs/ggan/ggan_lsgan-archi_lr1e-4-1xb128-20Mimgs_lsun-bedroom-64x64.py In Collection: GGAN Name: ggan_lsgan-archi_lr1e-4-1xb128-20Mimgs_lsun-bedroom-64x64 Results: - Dataset: LSUN-Bedroom Metrics: FID: 39.9261 MS-SSIM: 0.0649 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/ggan/ggan_lsun-bedroom_lsgan_archi_lr-1e-4_64_b128x1_20m_20210430_143114-5d99b76c.pth ================================================ FILE: configs/glean/README.md ================================================ # GLEAN (CVPR'2021) > [GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution](https://arxiv.org/abs/2012.00739) > **Task**: Image Super-Resolution ## Abstract We show that pre-trained Generative Adversarial Networks (GANs), e.g., StyleGAN, can be used as a latent bank to improve the restoration quality of large-factor image super-resolution (SR). While most existing SR approaches attempt to generate realistic textures through learning with adversarial loss, our method, Generative LatEnt bANk (GLEAN), goes beyond existing practices by directly leveraging rich and diverse priors encapsulated in a pre-trained GAN. But unlike prevalent GAN inversion methods that require expensive image-specific optimization at runtime, our approach only needs a single forward pass to generate the upscaled image. GLEAN can be easily incorporated in a simple encoder-bank-decoder architecture with multi-resolution skip connections. Switching the bank allows the method to deal with images from diverse categories, e.g., cat, building, human face, and car. Images upscaled by GLEAN show clear improvements in terms of fidelity and texture faithfulness in comparison to existing methods.
## Results and models For the meta info used in training and test, please refer to [here](https://github.com/ckkelvinchan/GLEAN). The results are evaluated on RGB channels. | Model | Dataset | PSNR | Training Resources | Download | | :------------------------------------------------------------------------------: | :------: | :---: | :----------------------: | :---------------------------------------------------------------------------------: | | [glean_cat_8x](./glean_x8_2xb8_cat.py) | LSUN-CAT | 23.98 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614_145540.log.json) | | [glean_ffhq_16x](./glean_x16_2xb8_ffhq.py) | FFHQ | 26.91 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/glean/glean_ffhq_16x_20210527-61a3afad.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/glean/glean_ffhq_16x_20210527_194536.log.json) | | [glean_cat_16x](./glean_x16_2xb8_cat.py) | LSUN-CAT | 20.88 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_16x_20210527-68912543.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_16x_20210527_103708.log.json) | | [glean_in128out1024_4x2_300k_ffhq_celebahq](./glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py) | FFHQ | 27.94 | 4 (Tesla V100-SXM3-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/glean/glean_in128out1024_4x2_300k_ffhq_celebahq_20210812-acbcb04f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/glean/glean_in128out1024_4x2_300k_ffhq_celebahq_20210812_100549.log.json) | | [glean_fp16_cat_8x](./glean_x8-fp16_2xb8_cat.py) | LSUN-CAT | - | - | - | | [glean_fp16_ffhq_16x](./glean_x16-fp16_2xb8_ffhq.py) | FFHQ | - | - | - | | [glean_fp16_in128out1024_4x2_300k_ffhq_celebahq](./glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq.py) | FFHQ | - | - | - | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/glean/glean_x8_2xb8_cat.py # single-gpu train python tools/train.py configs/glean/glean_x8_2xb8_cat.py # multi-gpu train ./tools/dist_train.sh configs/glean/glean_x8_2xb8_cat.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth # single-gpu test python tools/test.py configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth # multi-gpu test ./tools/dist_test.sh configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{chan2021glean, author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ``` ================================================ FILE: configs/glean/README_zh-CN.md ================================================ # GLEAN (CVPR'2021) > **任务**: 图像超分辨率
GLEAN (CVPR'2021) ```bibtex @InProceedings{chan2021glean, author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ```

有关训练和测试中使用的元信息,请参阅[此处](https://github.com/ckkelvinchan/GLEAN)。 结果在 RGB 通道上进行评估。 | 算法 | PSNR | GPU 信息 | 下载 | | :-----------------------------------------------------------------------------------: | :---: | :----------------------: | :------------------------------------------------------------------------------------: | | [glean_cat_8x](./glean_x8_2xb8_cat.py) | 23.98 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614_145540.log.json) | | [glean_ffhq_16x](./glean_x16_2xb8_ffhq.py) | 26.91 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/glean/glean_ffhq_16x_20210527-61a3afad.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/glean/glean_ffhq_16x_20210527_194536.log.json) | | [glean_cat_16x](./glean_x16_2xb8_cat.py) | 20.88 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_16x_20210527-68912543.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_16x_20210527_103708.log.json) | | [glean_in128out1024_4x2_300k_ffhq_celebahq](./glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py) | 27.94 | 4 (Tesla V100-SXM3-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/glean/glean_in128out1024_4x2_300k_ffhq_celebahq_20210812-acbcb04f.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/glean/glean_in128out1024_4x2_300k_ffhq_celebahq_20210812_100549.log.json) | | [glean_fp16_cat_8x](./glean_x8-fp16_2xb8_cat.py) | - | - | - | | [glean_fp16_ffhq_16x](./glean_x16-fp16_2xb8_ffhq.py) | - | - | - | | [glean_fp16_in128out1024_4x2_300k_ffhq_celebahq](./glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq.py) | - | - | - | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/glean/glean_x8_2xb8_cat.py # 单个GPU上训练 python tools/train.py configs/glean/glean_x8_2xb8_cat.py # 多个GPU上训练 ./tools/dist_train.sh configs/glean/glean_x8_2xb8_cat.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth # 单个GPU上测试 python tools/test.py configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth # 多个GPU上测试 ./tools/dist_test.sh configs/glean/glean_x8_2xb8_cat.py https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/glean/glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq.py ================================================ _base_ = './glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py' experiment_name = 'glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( generator=dict(fp16_enabled=True), discriminator=dict(fp16_enabled=True)) ================================================ FILE: configs/glean/glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py ================================================ _base_ = '../_base_/models/base_glean.py' experiment_name = 'glean_in128out1024_4xb2-300k_ffhq-celeba-hq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 8 # model settings model = dict( type='SRGAN', generator=dict( type='GLEANStyleGANv2', in_size=128, out_size=1024, style_channels=512, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-ffhq-config-f-official_20210327' '_171224-bce9310c.pth', prefix='generator_ema')), discriminator=dict( type='StyleGANv2Discriminator', in_size=1024, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-ffhq-config-f-official_20210327' '_171224-bce9310c.pth', prefix='discriminator')), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'21': 1.0}, vgg_type='vgg16', perceptual_weight=1e-2, style_weight=0, norm_img=True, criterion='mse', pretrained='torchvision://vgg16'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-2, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], ), ) train_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='CopyValues', src_keys=['gt'], dst_keys=['img']), dict( type='RandomBlur', params=dict( kernel_size=[41], kernel_list=['iso', 'aniso'], kernel_prob=[0.5, 0.5], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], ), keys=['img'], ), dict( type='RandomResize', params=dict( resize_mode_prob=[0, 1, 0], # up, down, keep resize_scale=[0.03125, 1], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), keys=['img'], ), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[0, 50], gaussian_gray_noise_prob=0), keys=['img'], ), dict( type='RandomJPEGCompression', params=dict(quality=[5, 50]), keys=['img']), dict( type='RandomResize', params=dict( target_size=(1024, 1024), resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), keys=['img'], ), dict(type='Clip', keys=['img']), dict( type='RandomResize', params=dict( target_size=(128, 128), resize_opt=['area'], resize_prob=[1]), keys=['img'], ), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='RandomResize', params=dict( target_size=(128, 128), resize_opt=['area'], resize_prob=[1]), keys=['img'], ), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=6, batch_size=2, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='ffhq_celebahq', task_name='sisr'), data_root='data/FFHQ_CelebAHQ', data_prefix=dict(gt='GT'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='ffhq', task_name='sisr'), data_root='data/CelebA-HQ', data_prefix=dict(img='BIx8_down', gt='GT'), ann_file='meta_info_CelebAHQ_val100_GT.txt', pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/glean/glean_x16-fp16_2xb8_ffhq.py ================================================ _base_ = './glean_x16_2xb8_ffhq.py' experiment_name = 'glean_x16-fp16_2xb8_ffhq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( generator=dict(fp16_enabled=True), discriminator=dict(fp16_enabled=True)) ================================================ FILE: configs/glean/glean_x16_2xb8_cat.py ================================================ _base_ = '../_base_/models/base_glean.py' experiment_name = 'glean_x16_2xb8_cat' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 16 # model settings model = dict( type='SRGAN', generator=dict( type='GLEANStyleGANv2', in_size=16, out_size=256, style_channels=512, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-cat-config-f-official_20210327' '_172444-15bc485b.pth', prefix='generator_ema')), discriminator=dict( type='StyleGANv2Discriminator', in_size=256, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-cat-config-f-official_20210327' '_172444-15bc485b.pth', prefix='discriminator')), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'21': 1.0}, vgg_type='vgg16', perceptual_weight=1e-2, style_weight=0, norm_img=False, criterion='mse', pretrained='torchvision://vgg16'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-2, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], ), ) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=8, batch_size=8, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cat', task_name='sisr'), data_root='data/cat_train', data_prefix=dict(img='BIx16_down', gt='GT'), ann_file='meta_info_LSUNcat_GT.txt', pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cat', task_name='sisr'), data_root='data/cat_test', data_prefix=dict(img='BIx16_down', gt='GT'), ann_file='meta_info_Cat100_GT.txt', pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/glean/glean_x16_2xb8_ffhq.py ================================================ _base_ = '../_base_/models/base_glean.py' experiment_name = 'glean_x16_2xb8_ffhq' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 16 # model settings model = dict( type='SRGAN', generator=dict( type='GLEANStyleGANv2', in_size=64, out_size=1024, style_channels=512, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-ffhq-config-f-official_20210327' '_171224-bce9310c.pth', prefix='generator_ema')), discriminator=dict( type='StyleGANv2Discriminator', in_size=1024, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-ffhq-config-f-official_20210327' '_171224-bce9310c.pth', prefix='discriminator')), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'21': 1.0}, vgg_type='vgg16', perceptual_weight=1e-2, style_weight=0, norm_img=False, criterion='mse', pretrained='torchvision://vgg16'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-2, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], ), ) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=8, batch_size=8, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='ffhq', task_name='sisr'), data_root='data/ffhq', data_prefix=dict(img='BIx16_down', gt='images'), ann_file='meta_info_FFHQ_GT.txt', pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='ffhq', task_name='sisr'), data_root='data/CelebA-HQ', data_prefix=dict(img='BIx16_down', gt='GT'), ann_file='meta_info_CelebAHQ_val100_GT.txt', pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/glean/glean_x8-fp16_2xb8_cat.py ================================================ _base_ = './glean_x8_2xb8_cat.py' experiment_name = 'glean_x8-fp16_2xb8_cat' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( generator=dict(fp16_enabled=True), discriminator=dict(fp16_enabled=True)) ================================================ FILE: configs/glean/glean_x8_2xb8_cat.py ================================================ _base_ = '../_base_/models/base_glean.py' experiment_name = 'glean_x8_2xb8_cat' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' scale = 8 # model settings model = dict( type='SRGAN', generator=dict( type='GLEANStyleGANv2', in_size=32, out_size=256, style_channels=512, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-cat-config-f-official_20210327' '_172444-15bc485b.pth', prefix='generator_ema')), discriminator=dict( type='StyleGANv2Discriminator', in_size=256, init_cfg=dict( type='Pretrained', checkpoint='http://download.openmmlab.com/mmediting/stylegan2/' 'official_weights/stylegan2-cat-config-f-official_20210327' '_172444-15bc485b.pth', prefix='discriminator')), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'21': 1.0}, vgg_type='vgg16', perceptual_weight=1e-2, style_weight=0, norm_img=False, criterion='mse', pretrained='torchvision://vgg16'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-2, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], ), ) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] inference_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='Resize', scale=(32, 32), keys=['img'], interpolation='bicubic', backend='pillow'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=8, batch_size=8, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cat', task_name='sisr'), data_root='data/cat_train', data_prefix=dict(img='BIx8_down', gt='GT'), ann_file='meta_info_LSUNcat_GT.txt', pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cat', task_name='sisr'), data_root='data/cat_test', data_prefix=dict(img='BIx8_down', gt='GT'), ann_file='meta_info_Cat100_GT.txt', pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/glean/metafile.yml ================================================ Collections: - Name: GLEAN Paper: Title: 'GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution' URL: https://arxiv.org/abs/2012.00739 README: configs/glean/README.md Task: - image super-resolution Year: 2021 Models: - Config: configs/glean/glean_x8_2xb8_cat.py In Collection: GLEAN Name: glean_x8_2xb8_cat Results: - Dataset: LSUN-CAT Metrics: PSNR: 23.98 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_8x_20210614-d3ac8683.pth - Config: configs/glean/glean_x16_2xb8_ffhq.py In Collection: GLEAN Name: glean_x16_2xb8_ffhq Results: - Dataset: FFHQ Metrics: PSNR: 26.91 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/glean/glean_ffhq_16x_20210527-61a3afad.pth - Config: configs/glean/glean_x16_2xb8_cat.py In Collection: GLEAN Name: glean_x16_2xb8_cat Results: - Dataset: LSUN-CAT Metrics: PSNR: 20.88 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/glean/glean_cat_16x_20210527-68912543.pth - Config: configs/glean/glean_in128out1024_4xb2-300k_ffhq-celeba-hq.py In Collection: GLEAN Name: glean_in128out1024_4xb2-300k_ffhq-celeba-hq Results: - Dataset: FFHQ Metrics: PSNR: 27.94 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/glean/glean_in128out1024_4x2_300k_ffhq_celebahq_20210812-acbcb04f.pth - Config: configs/glean/glean_x8-fp16_2xb8_cat.py In Collection: GLEAN Name: glean_x8-fp16_2xb8_cat Results: - Dataset: LSUN-CAT Metrics: {} Task: Image Super-Resolution - Config: configs/glean/glean_x16-fp16_2xb8_ffhq.py In Collection: GLEAN Name: glean_x16-fp16_2xb8_ffhq Results: - Dataset: FFHQ Metrics: {} Task: Image Super-Resolution - Config: configs/glean/glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq.py In Collection: GLEAN Name: glean_in128out1024-fp16_4xb2-300k_ffhq-celeba-hq Results: - Dataset: FFHQ Metrics: {} Task: Image Super-Resolution ================================================ FILE: configs/global_local/README.md ================================================ # Global&Local (ToG'2017) > [Globally and Locally Consistent Image Completion](http://iizuka.cs.tsukuba.ac.jp/projects/completion/data/completion_sig2017.pdf) > **Task**: Inpainting ## Abstract We present a novel approach for image completion that results in images that are both locally and globally consistent. With a fully-convolutional neural network, we can complete images of arbitrary resolutions by flling in missing regions of any shape. To train this image completion network to be consistent, we use global and local context discriminators that are trained to distinguish real images from completed ones. The global discriminator looks at the entire image to assess if it is coherent as a whole, while the local discriminator looks only at a small area centered at the completed region to ensure the local consistency of the generated patches. The image completion network is then trained to fool the both context discriminator networks, which requires it to generate images that are indistinguishable from real ones with regard to overall consistency as well as in details. We show that our approach can be used to complete a wide variety of scenes. Furthermore, in contrast with the patch-based approaches such as PatchMatch, our approach can generate fragments that do not appear elsewhere in the image, which allows us to naturally complete the image.
## Results and models *Note that we do not apply the post-processing module in Global&Local for a fair comparison with current deep inpainting methods.* | Model | Dataset | Mask Type | Resolution | Train Iters | Test Set | l1 error | PSNR | SSIM | Training Resources | Download | | :------------------------------------------: | :-----------------: | :---------: | :--------: | :---------: | :-----------: | :------: | :----: | :---: | :----------------: | :-----------------------------------------------------: | | [Global&Local](./gl_8xb12_places-256x256.py) | Places365-Challenge | square bbox | 256x256 | 500k | Places365-val | 11.164 | 23.152 | 0.862 | 8 | [model](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.log.json) | | [Global&Local](./gl_8xb12_celeba-256x256.py) | CelebA-HQ | square bbox | 256x256 | 500k | CelebA-val | 6.678 | 26.780 | 0.904 | 8 | [model](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/global_local/gl_8xb12_places-256x256.py # single-gpu train python tools/train.py configs/global_local/gl_8xb12_places-256x256.py # multi-gpu train ./tools/dist_train.sh configs/global_local/gl_8xb12_places-256x256.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth # single-gpu test python tools/test.py configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth # multi-gpu test ./tools/dist_test.sh configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @article{iizuka2017globally, title={Globally and locally consistent image completion}, author={Iizuka, Satoshi and Simo-Serra, Edgar and Ishikawa, Hiroshi}, journal={ACM Transactions on Graphics (ToG)}, volume={36}, number={4}, pages={1--14}, year={2017}, publisher={ACM New York, NY, USA} } ``` ================================================ FILE: configs/global_local/README_zh-CN.md ================================================ # Global&Local (ToG'2017) > **任务**: 图像修复
Global&Local (ToG'2017) ```bibtex @article{iizuka2017globally, title={Globally and locally consistent image completion}, author={Iizuka, Satoshi and Simo-Serra, Edgar and Ishikawa, Hiroshi}, journal={ACM Transactions on Graphics (ToG)}, volume={36}, number={4}, pages={1--14}, year={2017}, publisher={ACM New York, NY, USA} } ```

*请注意,为了与当前的深度图像修复方法进行公平比较,我们没有在 Global&Local 中使用后处理模块。* **Places365-Challenge** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :------------------------------------------: | :---------: | :-----: | :--------: | :-----------: | :-----: | :----: | :---: | :------: | :---------------------------------------------------------------------------------------: | | [Global&Local](./gl_8xb12_places-256x256.py) | square bbox | 256x256 | 500k | Places365-val | 11.164 | 23.152 | 0.862 | 8 | [模型](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.log.json) | **CelebA-HQ** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :------------------------------------------: | :---------: | :-----: | :--------: | :--------: | :-----: | :----: | :---: | :------: | :------------------------------------------------------------------------------------------: | | [Global&Local](./gl_8xb12_celeba-256x256.py) | square bbox | 256x256 | 500k | CelebA-val | 6.678 | 26.780 | 0.904 | 8 | [模型](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/global_local/gl_8xb12_places-256x256.py # 单个GPU上训练 python tools/train.py configs/global_local/gl_8xb12_places-256x256.py # 多个GPU上训练 ./tools/dist_train.sh configs/global_local/gl_8xb12_places-256x256.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth # 单个GPU上测试 python tools/test.py configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth # 多个GPU上测试 ./tools/dist_test.sh configs/global_local/gl_8xb12_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/global_local/gl_8xb12_celeba-256x256.py ================================================ _base_ = [ '../_base_/models/base_gl.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/celeba.py' ] experiment_name = 'gl_8xb12_celeba-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=1, iter_tc=40000, iter_td=50000, start_iter=0, local_size=(128, 128)), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='bbox', mask_config=dict( max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20, img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=12, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=300002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # runtime settings # inheritate from _base_ ================================================ FILE: configs/global_local/gl_8xb12_places-256x256.py ================================================ _base_ = [ '../_base_/models/base_gl.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] experiment_name = 'gl_8xb12_places-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=1, iter_tc=90000, iter_td=100000, start_iter=350000, local_size=(128, 128)), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='bbox', mask_config=dict( max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20, img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=12, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=500002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # runtime settings # inheritate from _base_ ================================================ FILE: configs/global_local/metafile.yml ================================================ Collections: - Name: Global&Local Paper: Title: Globally and Locally Consistent Image Completion URL: http://iizuka.cs.tsukuba.ac.jp/projects/completion/data/completion_sig2017.pdf README: configs/global_local/README.md Task: - inpainting Year: 2017 Models: - Config: configs/global_local/gl_8xb12_places-256x256.py In Collection: Global&Local Name: gl_8xb12_places-256x256 Results: - Dataset: Places365-Challenge Metrics: PSNR: 23.152 SSIM: 0.862 l1 error: 11.164 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_places_20200619-52a040a8.pth - Config: configs/global_local/gl_8xb12_celeba-256x256.py In Collection: Global&Local Name: gl_8xb12_celeba-256x256 Results: - Dataset: CelebA-HQ Metrics: PSNR: 26.78 SSIM: 0.904 l1 error: 6.678 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.pth ================================================ FILE: configs/guided_diffusion/README.md ================================================ # Guided Diffusion (NeurIPS'2021) > [Diffusion Models Beat GANs on Image Synthesis](https://papers.nips.cc/paper/2021/file/49ad23d1ec9fa4bd8d77d02681df5cfa-Paper.pdf) > **Task**: Image Generation ## Abstract We show that diffusion models can achieve image sample quality superior to the current state-of-the-art generative models. We achieve this on unconditional image synthesis by finding a better architecture through a series of ablations. For conditional image synthesis, we further improve sample quality with classifier guidance: a simple, compute-efficient method for trading off diversity for fidelity using gradients from a classifier. We achieve an FID of 2.97 on ImageNet 128x128, 4.59 on ImageNet 256x256, and 7.72 on ImageNet 512x512, and we match BigGAN-deep even with as few as 25 forward passes per sample, all while maintaining better coverage of the distribution. Finally, we find that classifier guidance combines well with upsampling diffusion models, further improving FID to 3.94 on ImageNet 256x256 and 3.85 on ImageNet 512x512.
## Results and models
hamster, classifier-guidance samplings with CGS=1.0
**ImageNet** | Model | Dataset | Scheduler | Steps | CGS | Time Consuming(A100) | FID-Full-50K | Download | | :----------------------------------------------------------------: | :--------------: | :-------: | :---: | :-: | :------------------: | :----------: | :-------------------------------------------------------------------: | | [adm_ddim250_8xb32_imagenet-64x64](./adm_ddim250_8xb32_imagenet-64x64.py) | ImageNet 64x64 | DDIM | 250 | - | 1h | 3.2284 | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth) | | [adm-g_ddim25_8xb32_imagenet-64x64](configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-64x64.py) | ImageNet 64x64 | DDIM | 25 | 1.0 | 2h | 3.7566 | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-64x64-2c0fbeda.pth) | | [adm_ddim250_8xb32_imagenet-256x256](configs/guided_diffusion/adm_ddim250_8xb32_imagenet-256x256.py) | ImageNet 256x256 | DDIM | 250 | - | - | - | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm_8xb32_imagenet-256x256-f94735fe.pth) | | [adm-g_ddim25_8xb32_imagenet-256x256](configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-256x256.py) | ImageNet 256x256 | DDIM | 25 | 1.0 | - | - | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-256x256-aec3fc9f.pth) | | [adm_ddim250_8xb32_imagenet-512x512](configs/guided_diffusion/adm_ddim250_8xb32_imagenet-512x512.py) | ImageNet 512x512 | DDIM | 250 | - | - | - | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm-u_8xb32_imagenet-512x512-60b381cb.pth) | | [adm-g_ddim25_8xb32_imagenet-512x512](configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-512x512.py) | ImageNet 512x512 | DDIM | 25 | 1.0 | - | - | [ckpt](https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-512x512-23cf0b58.pth) | ## Quick Start **infer**
Infer Instructions You can run adm as follows: ```python from mmengine import Config, MODELS from mmengine.registry import init_default_scope from torchvision.utils import save_image init_default_scope('mmagic') # sampling without classifier guidance, CGS=1.0 config = 'configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-64x64.py' ckpt_path = 'https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-64x64-2c0fbeda.pth' # noqa model_cfg = Config.fromfile(config).model model_cfg.pretrained_cfgs = dict(unet=dict(ckpt_path=ckpt_path, prefix='unet'), classifier=dict(ckpt_path=ckpt_path, prefix='classifier')) model = MODELS.build(model_cfg).cuda().eval() samples = model.infer( init_image=None, batch_size=4, num_inference_steps=25, labels=333, classifier_scale=1.0, show_progress=True)['samples'] # sampling without classifier guidance config = 'configs/guided_diffusion/adm_ddim250_8xb32_imagenet-64x64.py' ckpt_path = 'https://download.openmmlab.com/mmediting/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth' # noqa model_cfg = Config.fromfile(config).model model_cfg.pretrained_cfgs = dict(unet=dict(ckpt_path=ckpt_path, prefix='unet')) model = MODELS.build(model_cfg).cuda().eval() samples = model.infer( init_image=None, batch_size=4, num_inference_steps=250, labels=None, classifier_scale=0.0, show_progress=True)['samples'] ``` **Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/guided_diffusion/adm-u_ddim250_8xb32_imagenet-64x64.py https://download.openmmlab.com/mmgen/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth # single-gpu test python tools/test.py configs/guided_diffusion/adm-u_ddim250_8xb32_imagenet-64x64.py https://download.openmmlab.com/mmgen/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth # multi-gpu test ./tools/dist_test.sh configs/guided_diffusion/adm-u_ddim250_8xb32_imagenet-64x64.py https://download.openmmlab.com/mmgen/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @article{PrafullaDhariwal2021DiffusionMB, title={Diffusion Models Beat GANs on Image Synthesis}, author={Prafulla Dhariwal and Alex Nichol}, journal={arXiv: Learning}, year={2021} } ``` ================================================ FILE: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-256x256.py ================================================ _base_ = ['./adm_ddim250_8xb32_imagenet-256x256.py'] model = dict( classifier=dict( type='EncoderUNetModel', image_size=256, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=2, attention_resolutions=(8, 16, 32), channel_mult=(1, 1, 2, 2, 4, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention')) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-512x512.py ================================================ _base_ = ['./adm_ddim250_8xb32_imagenet-512x512.py'] model = dict( classifier=dict( type='EncoderUNetModel', image_size=512, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=2, attention_resolutions=(16, 32, 64), channel_mult=(0.5, 1, 1, 2, 2, 4, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention')) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-64x64.py ================================================ _base_ = ['./adm_ddim250_8xb32_imagenet-64x64.py'] model = dict( classifier=dict( type='EncoderUNetModel', image_size=64, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=4, attention_resolutions=(2, 4, 8), channel_mult=(1, 2, 3, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention')) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-256x256.py ================================================ _base_ = [ '../_base_/datasets/imagenet_64.py', '../_base_/gen_default_runtime.py', ] model = dict( type='AblatedDiffusionModel', data_preprocessor=dict(type='DataPreprocessor'), unet=dict( type='DenoisingUnet', image_size=256, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True), diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear'), rgb2bgr=True, use_fp16=False) test_dataloader = dict(batch_size=32, num_workers=8) train_cfg = dict(max_iters=100000) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) # VIS_HOOK custom_hooks = [ dict(type='VisualizationHook', interval=5000, fixed_input=True) ] ================================================ FILE: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-512x512.py ================================================ _base_ = [ '../_base_/datasets/imagenet_512.py', '../_base_/gen_default_runtime.py', ] model = dict( type='AblatedDiffusionModel', data_preprocessor=dict(type='DataPreprocessor'), unet=dict( type='DenoisingUnet', image_size=512, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True), diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear'), rgb2bgr=True, use_fp16=False) test_dataloader = dict(batch_size=32, num_workers=8) train_cfg = dict(max_iters=100000) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-64x64.py ================================================ _base_ = [ '../_base_/datasets/imagenet_64.py', '../_base_/gen_default_runtime.py', ] model = dict( type='AblatedDiffusionModel', data_preprocessor=dict(type='DataPreprocessor'), unet=dict( type='DenoisingUnet', image_size=64, in_channels=3, base_channels=192, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=True), use_scale_shift_norm=True), diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='squaredcos_cap_v2'), rgb2bgr=True, use_fp16=False) test_dataloader = dict(batch_size=32, num_workers=8) train_cfg = dict(max_iters=100000) metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/guided_diffusion/metafile.yml ================================================ Collections: - Name: Guided Diffusion Paper: Title: Diffusion Models Beat GANs on Image Synthesis URL: https://papers.nips.cc/paper/2021/file/49ad23d1ec9fa4bd8d77d02681df5cfa-Paper.pdf README: configs/guided_diffusion/README.md Task: - image generation Year: 2021 Models: - Config: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-64x64.py In Collection: Guided Diffusion Name: adm_ddim250_8xb32_imagenet-64x64 Results: - Dataset: ImageNet64x64 Metrics: FID-Full-50K: 3.2284 Steps: 250.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm-u-cvt-rgb_8xb32_imagenet-64x64-7ff0080b.pth - Config: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-64x64.py In Collection: Guided Diffusion Name: adm-g_ddim25_8xb32_imagenet-64x64 Results: - Dataset: ImageNet64x64 Metrics: CGS: 1.0 FID-Full-50K: 3.7566 Steps: 25.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-64x64-2c0fbeda.pth - Config: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-256x256.py In Collection: Guided Diffusion Name: adm_ddim250_8xb32_imagenet-256x256 Results: - Dataset: ImageNet256x256 Metrics: Steps: 250.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm_8xb32_imagenet-256x256-f94735fe.pth - Config: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-256x256.py In Collection: Guided Diffusion Name: adm-g_ddim25_8xb32_imagenet-256x256 Results: - Dataset: ImageNet256x256 Metrics: CGS: 1.0 Steps: 25.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-256x256-aec3fc9f.pth - Config: configs/guided_diffusion/adm_ddim250_8xb32_imagenet-512x512.py In Collection: Guided Diffusion Name: adm_ddim250_8xb32_imagenet-512x512 Results: - Dataset: ImageNet512x512 Metrics: Steps: 250.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm-u_8xb32_imagenet-512x512-60b381cb.pth - Config: configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet-512x512.py In Collection: Guided Diffusion Name: adm-g_ddim25_8xb32_imagenet-512x512 Results: - Dataset: ImageNet512x512 Metrics: CGS: 1.0 Steps: 25.0 Task: Image Generation Weights: https://download.openmmlab.com/mmediting/guided_diffusion/adm-g_8xb32_imagenet-512x512-23cf0b58.pth ================================================ FILE: configs/iconvsr/README.md ================================================ # IconVSR (CVPR'2021) > [BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond](https://arxiv.org/abs/2012.02181) > **Task**: Video Super-Resolution ## Abstract Video super-resolution (VSR) approaches tend to have more components than the image counterparts as they need to exploit the additional temporal dimension. Complex designs are not uncommon. In this study, we wish to untangle the knots and reconsider some most essential components for VSR guided by four basic functionalities, i.e., Propagation, Alignment, Aggregation, and Upsampling. By reusing some existing components added with minimal redesigns, we show a succinct pipeline, BasicVSR, that achieves appealing improvements in terms of speed and restoration quality in comparison to many state-of-the-art algorithms. We conduct systematic analysis to explain how such gain can be obtained and discuss the pitfalls. We further show the extensibility of BasicVSR by presenting an information-refill mechanism and a coupled propagation scheme to facilitate information aggregation. The BasicVSR and its extension, IconVSR, can serve as strong baselines for future VSR approaches.
## Results and models Evaluated on RGB channels for REDS4 and Y channel for others. The metrics are `PSNR` / `SSIM` . The pretrained weights of the IconVSR components can be found here: [SPyNet](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth), [EDVR-M for REDS](https://download.openmmlab.com/mmediting/restorers/iconvsr/edvrm_reds_20210413-3867262f.pth), and [EDVR-M for Vimeo-90K](https://download.openmmlab.com/mmediting/restorers/iconvsr/edvrm_vimeo90k_20210413-e40e99a8.pth). | Model | Dataset | PSNR (RGB) | SSIM (RGB) | PSNR (Y) | SSIM (Y) | Training Resources | Download | | :---------------: | :---------------------: | :-------------------------: | :------------------: | :-------------------: | :-------------------------: | :------------------: | :----------------------: | :-------------------: | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | REDS4 (BIx4) | **31.6926** | **0.8951** |-|-| 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | UDM10 (BDx4) | -|-|35.3377| 0.9471| 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | Vid4 (BIx4) | -|-|**27.4809**| **0.8354** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | Vid4 (BDx4) | -|-| 25.2110 | 0.7732 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | Vimeo-90K-T (BIx4) | -|-|36.4983 | 0.9416 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | Vimeo-90K-T (BDx4) | -|-| 34.4299 | 0.9287 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | REDS4 (BIx4) | 30.3452 |0.8659 |-|-| 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | UDM10 (BDx4) |-|-|34.2595 |0.9398 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | Vid4 (BIx4) |-|-|27.4238 |0.8297 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | Vid4 (BDx4) |-|-|24.6666|0.7491 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | Vimeo-90K-T (BIx4) |-|-|**37.3729**| **0.9467** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | Vimeo-90K-T (BDx4) |-|-|34.5548 | 0.9295 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | REDS4 (BIx4) |29.0150 | 0.8465 |-|-| 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | UDM10 (BDx4) |-|-| **40.0640** | **0.9697** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | Vid4 (BIx4) |-|-|26.3109| 0.8028 | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | Vid4 (BDx4) | -|-| **28.2464** | **0.8612** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | Vimeo-90K-T (BIx4) | -|-|34.6780| 0.9339| 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | Vimeo-90K-T (BDx4) |-|-|**37.7573** | **0.9517** | 2 (Tesla V100-PCIE-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) | [log](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/iconvsr/iconvsr_2xb4_reds4.py # single-gpu train python tools/train.py configs/iconvsr/iconvsr_2xb4_reds4.py # multi-gpu train ./tools/dist_train.sh configs/iconvsr/iconvsr_2xb4_reds4.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth # single-gpu test python tools/test.py configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth # multi-gpu test ./tools/dist_test.sh configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{chan2021basicvsr, author = {Chan, Kelvin CK and Wang, Xintao and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ``` ================================================ FILE: configs/iconvsr/README_zh-CN.md ================================================ # IconVSR (CVPR'2021) > **任务**: 视频超分辨率
IconVSR (CVPR'2021) ```bibtex @InProceedings{chan2021basicvsr, author = {Chan, Kelvin CK and Wang, Xintao and Yu, Ke and Dong, Chao and Loy, Chen Change}, title = {BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ```

对于 REDS4,我们对 RGB 通道进行评估。对于其他数据集,我们对 Y 通道进行评估。我们使用 `PSNR` 和 `SSIM` 作为指标。 IconVSR 组件的预训练权重可以在这里找到:[SPyNet](https://download.openmmlab.com/mmediting/restorers/basicvsr/spynet_20210409-c6c1bd09.pth),[用于 REDS 的 EDVR-M](https://download.openmmlab.com/mmediting/restorers/iconvsr/edvrm_reds_20210413-3867262f.pth),以及 [用于 Vimeo-90K 的 EDVR-M](https://download.openmmlab.com/mmediting/restorers/iconvsr/edvrm_vimeo90k_20210413-e40e99a8.pth)。 | 算法 | REDS4 (BIx4)
PSNR/SSIM (RGB) | Vimeo-90K-T (BIx4)
PSNR/SSIM (Y) | Vid4 (BIx4)
PSNR/SSIM (Y) | UDM10 (BDx4)
PSNR/SSIM (Y) | Vimeo-90K-T (BDx4)
PSNR/SSIM (Y) | Vid4 (BDx4)
PSNR/SSIM (Y) | GPU 信息 | 下载 | | :-: | :-----------------------------: | :---------------------------------: | :--------------------------: | :---------------------------: | :---------------------------------: | :--------------------------: | :-----: | :--: | | [iconvsr_reds4](./iconvsr_2xb4_reds4.py) | **31.6926/0.8951** | 36.4983/0.9416 | **27.4809/0.8354** | 35.3377/0.9471 | 34.4299/0.9287 | 25.2110/0.7732 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413_222735.log.json) | | [iconvsr_vimeo90k_bi](./iconvsr_2xb4_vimeo90k-bi.py) | 30.3452/0.8659 | **37.3729/0.9467** | 27.4238/0.8297 | 34.2595/0.9398 | 34.5548/0.9295 | 24.6666/0.7491 | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413_222757.log.json) | | [iconvsr_vimeo90k_bd](./iconvsr_2xb4_vimeo90k-bd.py) | 29.0150/0.8465 | 34.6780/0.9339 | 26.3109/0.8028 | **40.0640/0.9697** | **37.7573/0.9517** | **28.2464/0.8612** | 2 (Tesla V100-PCIE-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414_084128.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/iconvsr/iconvsr_2xb4_reds4.py # 单个GPU上训练 python tools/train.py configs/iconvsr/iconvsr_2xb4_reds4.py # 多个GPU上训练 ./tools/dist_train.sh configs/iconvsr/iconvsr_2xb4_reds4.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth # 单个GPU上测试 python tools/test.py configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth # 多个GPU上测试 ./tools/dist_test.sh configs/iconvsr/iconvsr_2xb4_reds4.py https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/iconvsr/iconvsr_2xb4_reds4.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_reds4.py' experiment_name = 'iconvsr_2xb4_reds4' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BasicVSR', generator=dict( type='IconVSRNet', mid_channels=64, num_blocks=30, keyframe_stride=5, padding=2, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', edvr_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'iconvsr/edvrm_reds_20210413-3867262f.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) ================================================ FILE: configs/iconvsr/iconvsr_2xb4_vimeo90k-bd.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_vimeo90k-bd.py' experiment_name = 'iconvsr_2xb4_vimeo90k-bd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BasicVSR', generator=dict( type='IconVSRNet', mid_channels=64, num_blocks=30, keyframe_stride=5, padding=3, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', edvr_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'iconvsr/edvrm_vimeo90k_20210413-e40e99a8.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) find_unused_parameters = True ================================================ FILE: configs/iconvsr/iconvsr_2xb4_vimeo90k-bi.py ================================================ _base_ = '../basicvsr/basicvsr_2xb4_vimeo90k-bi.py' scale = 4 experiment_name = 'iconvsr_2xb4_vimeo90k-bi' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BasicVSR', generator=dict( type='IconVSRNet', mid_channels=64, num_blocks=30, keyframe_stride=5, padding=3, spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', edvr_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'iconvsr/edvrm_vimeo90k_20210413-e40e99a8.pth'), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=5000), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) default_hooks = dict(checkpoint=dict(out_dir=save_dir)) find_unused_parameters = True ================================================ FILE: configs/iconvsr/metafile.yml ================================================ Collections: - Name: IconVSR Paper: Title: 'BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond' URL: https://arxiv.org/abs/2012.02181 README: configs/iconvsr/README.md Task: - video super-resolution Year: 2021 Models: - Config: configs/iconvsr/iconvsr_2xb4_reds4.py In Collection: IconVSR Name: iconvsr_2xb4_reds4 Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 31.6926 SSIM (RGB): 0.8951 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 35.3377 SSIM (Y): 0.9471 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.4809 SSIM (Y): 0.8354 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 25.211 SSIM (Y): 0.7732 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 36.4983 SSIM (Y): 0.9416 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 34.4299 SSIM (Y): 0.9287 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_reds4_20210413-9e09d621.pth - Config: configs/iconvsr/iconvsr_2xb4_vimeo90k-bi.py In Collection: IconVSR Name: iconvsr_2xb4_vimeo90k-bi Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 30.3452 SSIM (RGB): 0.8659 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 34.2595 SSIM (Y): 0.9398 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 27.4238 SSIM (Y): 0.8297 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 24.6666 SSIM (Y): 0.7491 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 37.3729 SSIM (Y): 0.9467 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 34.5548 SSIM (Y): 0.9295 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bi_20210413-7c7418dc.pth - Config: configs/iconvsr/iconvsr_2xb4_vimeo90k-bd.py In Collection: IconVSR Name: iconvsr_2xb4_vimeo90k-bd Results: - Dataset: REDS4(BIx4) Metrics: PSNR (RGB): 29.015 SSIM (RGB): 0.8465 Task: Video Super-Resolution - Dataset: UDM10(BDx4) Metrics: PSNR (Y): 40.064 SSIM (Y): 0.9697 Task: Video Super-Resolution - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 26.3109 SSIM (Y): 0.8028 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 28.2464 SSIM (Y): 0.8612 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BIx4) Metrics: PSNR (Y): 34.678 SSIM (Y): 0.9339 Task: Video Super-Resolution - Dataset: Vimeo-90K-T(BDx4) Metrics: PSNR (Y): 37.7573 SSIM (Y): 0.9517 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/iconvsr/iconvsr_vimeo90k_bd_20210414-5f38cb34.pth ================================================ FILE: configs/indexnet/README.md ================================================ # IndexNet (ICCV'2019) > [Indices Matter: Learning to Index for Deep Image Matting](https://arxiv.org/abs/1908.00672) > **Task**: Matting ## Abstract We show that existing upsampling operators can be unified with the notion of the index function. This notion is inspired by an observation in the decoding process of deep image matting where indices-guided unpooling can recover boundary details much better than other upsampling operators such as bilinear interpolation. By looking at the indices as a function of the feature map, we introduce the concept of learning to index, and present a novel index-guided encoder-decoder framework where indices are self-learned adaptively from data and are used to guide the pooling and upsampling operators, without the need of supervision. At the core of this framework is a flexible network module, termed IndexNet, which dynamically predicts indices given an input. Due to its flexibility, IndexNet can be used as a plug-in applying to any off-the-shelf convolutional networks that have coupled downsampling and upsampling stages.
## Results and models | Model | Dataset | SAD | MSE | GRAD | CONN | Training Resources | Download | | :------------------------------------------------------------------: | :------------: | :------: | :-------: | :------: | :--: | :----------------: | :---------------------------------------------------------------------: | | [M2O DINs (our)](./indexnet_mobv2_1xb16-78k_comp1k.py) | Composition-1k | **45.6** | **0.012** | **25.5** | 44.8 | 1 | [model](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_20200618_173817.log.json) | | [M2O DINs (with DIM pipeline)](./indexnet_mobv2-dimaug_1xb16-78k_comp1k.py) | Composition-1k | 50.1 | 0.016 | 30.8 | 49.5 | 1 | [model](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_dimaug_mobv2_1x16_78k_comp1k_SAD-50.1_20200626_231857-af359436.pth) \| [log](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_dimaug_mobv2_1x16_78k_comp1k_20200626_231857.log.json) | > The performance of training (best performance) with different random seeds diverges in a large range. You may need to run several experiments for each setting to obtain the above performance. ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py # single-gpu train python tools/train.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py # multi-gpu train ./tools/dist_train.sh configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth # single-gpu test python tools/test.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth # multi-gpu test ./tools/dist_test.sh configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{hao2019indexnet, title={Indices Matter: Learning to Index for Deep Image Matting}, author={Lu, Hao and Dai, Yutong and Shen, Chunhua and Xu, Songcen}, booktitle={Proc. IEEE/CVF International Conference on Computer Vision (ICCV)}, year={2019} } ``` ================================================ FILE: configs/indexnet/README_zh-CN.md ================================================ # IndexNet (ICCV'2019) > **任务**: 图像抠图
IndexNet (ICCV'2019) ```bibtex @inproceedings{hao2019indexnet, title={Indices Matter: Learning to Index for Deep Image Matting}, author={Lu, Hao and Dai, Yutong and Shen, Chunhua and Xu, Songcen}, booktitle={Proc. IEEE/CVF International Conference on Computer Vision (ICCV)}, year={2019} } ```

| 算法 | SAD | MSE | GRAD | CONN | GPU 信息 | 下载 | | :-----------------------------------------------------: | :------: | :-------: | :------: | :------: | :------: | :------------------------------------------------------------------------------------------------------: | | M2O DINs (原文) | 45.8 | 0.013 | 25.9 | **43.7** | - | - | | [M2O DINs (复现)](./indexnet_mobv2_1xb16-78k_comp1k.py) | **45.6** | **0.012** | **25.5** | 44.8 | 1 | [模型](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_20200618_173817.log.json) | > The performance of training (best performance) with different random seeds diverges in a large range. You may need to run several experiments for each setting to obtain the above performance. **其他结果** | 算法 | SAD | MSE | GRAD | CONN | GPU 信息 | 下载 | | :-----------------------------------------------------------------------: | :--: | :---: | :--: | :--: | :------: | :----------------------------------------------------------------------------------------------------: | | [M2O DINs (使用 DIM 流水线)](./indexnet_mobv2-dimaug_1xb16-78k_comp1k.py) | 50.1 | 0.016 | 30.8 | 49.5 | 1 | [模型](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_dimaug_mobv2_1x16_78k_comp1k_SAD-50.1_20200626_231857-af359436.pth) \| [日志](https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_dimaug_mobv2_1x16_78k_comp1k_20200626_231857.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py # 单个GPU上训练 python tools/train.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py # 多个GPU上训练 ./tools/dist_train.sh configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth # 单个GPU上测试 python tools/test.py configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth # 多个GPU上测试 ./tools/dist_test.sh configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/indexnet/indexnet_mobv2-dimaug_1xb16-78k_comp1k.py ================================================ _base_ = ['./indexnet_mobv2_1xb16-78k_comp1k.py'] experiment_name = 'indexnet_mobv2-dimaug_1xb16-78k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( test_cfg=dict( resize_method='pad', resize_mode='reflect', size_divisor=32, )) # dataset settings train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='LoadImageFromFile', key='bg'), dict(type='LoadImageFromFile', key='merged'), dict( type='CropAroundUnknown', keys=['alpha', 'merged', 'fg', 'bg'], crop_sizes=[320, 480, 640]), dict(type='Flip', keys=['alpha', 'merged', 'fg', 'bg']), dict( type='Resize', keys=['alpha', 'merged', 'fg', 'bg'], scale=(320, 320), keep_ratio=False), dict(type='GenerateTrimap', kernel_size=(1, 30)), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='PackInputs'), ] train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) val_dataloader = dict(dataset=dict(pipeline=test_pipeline)) test_dataloader = val_dataloader ================================================ FILE: configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py ================================================ _base_ = [ '../_base_/datasets/comp1k.py', '../_base_/matting_default_runtime.py' ] experiment_name = 'indexnet_mobv2_1xb16-78k_comp1k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='IndexNet', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='IndexNetEncoder', in_channels=4, freeze_bn=True, init_cfg=dict( type='Pretrained', checkpoint='open-mmlab://mmedit/mobilenet_v2')), decoder=dict(type='IndexNetDecoder')), loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5, sample_wise=True), loss_comp=dict( type='CharbonnierCompLoss', loss_weight=1.5, sample_wise=True), test_cfg=dict( resize_method='interp', resize_mode='bicubic', size_divisor=32, ), ) train_pipeline = [ dict(type='LoadImageFromFile', key='alpha', color_type='grayscale'), dict(type='LoadImageFromFile', key='fg'), dict(type='LoadImageFromFile', key='bg'), dict(type='LoadImageFromFile', key='merged'), dict(type='GenerateTrimapWithDistTransform', dist_thr=20), dict( type='CropAroundUnknown', keys=['alpha', 'merged', 'fg', 'bg', 'trimap'], crop_sizes=[320, 480, 640], interpolations=['bicubic', 'bicubic', 'bicubic', 'bicubic', 'nearest']), dict( type='Resize', keys=['trimap'], scale=(320, 320), keep_ratio=False, interpolation='nearest'), dict( type='Resize', keys=['alpha', 'merged', 'fg', 'bg'], scale=(320, 320), keep_ratio=False, interpolation='bicubic'), dict(type='Flip', keys=['alpha', 'merged', 'fg', 'bg', 'trimap']), dict(type='PackInputs'), ] test_pipeline = [ dict( type='LoadImageFromFile', key='alpha', color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', key='trimap', color_type='grayscale', save_original_img=True), dict(type='LoadImageFromFile', key='merged'), dict(type='PackInputs'), ] train_dataloader = dict( batch_size=16, num_workers=8, dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=78000, val_interval=2600, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-2), paramwise_cfg=dict(custom_keys={'encoder.layers': dict(lr_mult=0.01)}), ) # learning policy param_scheduler = dict( type='MultiStepLR', milestones=[52000, 67600], gamma=0.1, by_epoch=False, ) # checkpoint saving default_hooks = dict(checkpoint=dict(interval=2600, out_dir=save_dir)) # runtime settings # inheritate from _base_ ================================================ FILE: configs/indexnet/metafile.yml ================================================ Collections: - Name: IndexNet Paper: Title: 'Indices Matter: Learning to Index for Deep Image Matting' URL: https://arxiv.org/abs/1908.00672 README: configs/indexnet/README.md Task: - matting Year: 2019 Models: - Config: configs/indexnet/indexnet_mobv2_1xb16-78k_comp1k.py In Collection: IndexNet Name: indexnet_mobv2_1xb16-78k_comp1k Results: - Dataset: Composition-1k Metrics: CONN: 44.8 GRAD: 25.5 MSE: 0.012 SAD: 45.6 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_mobv2_1x16_78k_comp1k_SAD-45.6_20200618_173817-26dd258d.pth - Config: configs/indexnet/indexnet_mobv2-dimaug_1xb16-78k_comp1k.py In Collection: IndexNet Name: indexnet_mobv2-dimaug_1xb16-78k_comp1k Results: - Dataset: Composition-1k Metrics: CONN: 49.5 GRAD: 30.8 MSE: 0.016 SAD: 50.1 Task: Matting Weights: https://download.openmmlab.com/mmediting/mattors/indexnet/indexnet_dimaug_mobv2_1x16_78k_comp1k_SAD-50.1_20200626_231857-af359436.pth ================================================ FILE: configs/inst_colorization/README.md ================================================ # Instance-aware Image Colorization (CVPR'2020) > [Instance-Aware Image Colorization](https://openaccess.thecvf.com/content_CVPR_2020/html/Su_Instance-Aware_Image_Colorization_CVPR_2020_paper.html) > **Task**: Colorization ## Abstract Image colorization is inherently an ill-posed problem with multi-modal uncertainty. Previous methods leverage the deep neural network to map input grayscale images to plausible color outputs directly. Although these learning-based methods have shown impressive performance, they usually fail on the input images that contain multiple objects. The leading cause is that existing models perform learning and colorization on the entire image. In the absence of a clear figure-ground separation, these models cannot effectively locate and learn meaningful object-level semantics. In this paper, we propose a method for achieving instance-aware colorization. Our network architecture leverages an off-the-shelf object detector to obtain cropped object images and uses an instance colorization network to extract object-level features. We use a similar network to extract the full-image features and apply a fusion module to full object-level and image-level features to predict the final colors. Both colorization networks and fusion modules are learned from a large-scale dataset. Experimental results show that our work outperforms existing methods on different quality metrics and achieves state-of-the-art performance on image colorization.
## Results and models | Model | Dataset | Download | | :---------------------------------------------------------------------------------------------: | :-----: | :------------------------------------------------------------------------------------------------: | | [instance_aware_colorization_officiial](./inst-colorizatioon_full_official_cocostuff-256x256.py) | MS-COCO | [model](https://download.openmmlab.com/mmediting/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256-5b9d4eee.pth) | ## Quick Start
Colorization demo You can use the following commands to colorize an image. ```shell python demo/mmagic_inference_demo.py --model-name inst_colorization --img input.jpg --result-out-dir output.png ``` For more demos, you can refer to [Tutorial 3: inference with pre-trained models](https://mmagic.readthedocs.io/en/latest/user_guides/3_inference.html).
Instance-aware Image Colorization (CVPR'2020) ```bibtex @inproceedings{Su-CVPR-2020, author = {Su, Jheng-Wei and Chu, Hung-Kuo and Huang, Jia-Bin}, title = {Instance-aware Image Colorization}, booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, year = {2020} } ```
================================================ FILE: configs/inst_colorization/README_zh-CN.md ================================================ # Instance-aware Image Colorization (CVPR'2020) > [Instance-Aware Image Colorization](https://openaccess.thecvf.com/content_CVPR_2020/html/Su_Instance-Aware_Image_Colorization_CVPR_2020_paper.html) > **任务**: 图像上色 ## 摘要 Image colorization is inherently an ill-posed problem with multi-modal uncertainty. Previous methods leverage the deep neural network to map input grayscale images to plausible color outputs directly. Although these learning-based methods have shown impressive performance, they usually fail on the input images that contain multiple objects. The leading cause is that existing models perform learning and colorization on the entire image. In the absence of a clear figure-ground separation, these models cannot effectively locate and learn meaningful object-level semantics. In this paper, we propose a method for achieving instance-aware colorization. Our network architecture leverages an off-the-shelf object detector to obtain cropped object images and uses an instance colorization network to extract object-level features. We use a similar network to extract the full-image features and apply a fusion module to full object-level and image-level features to predict the final colors. Both colorization networks and fusion modules are learned from a large-scale dataset. Experimental results show that our work outperforms existing methods on different quality metrics and achieves state-of-the-art performance on image colorization.
## 结果和模型 | Model | Download | | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------: | | [instance_aware_colorization_officiial](./inst-colorizatioon_full_official_cocostuff-256x256.py) | [model](https://download.openmmlab.com/mmediting/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256-5b9d4eee.pth) | ## 快速开始
图像上色模型 您可以使用以下命令来对一张图像进行上色。 ```shell python demo/mmagic_inference_demo.py --model-name inst_colorization --img input.jpg --result-out-dir output.png ``` 更多细节可以参考 [Tutorial 3: inference with pre-trained models](https://mmagic.readthedocs.io/en/latest/user_guides/3_inference.html)。
Instance-aware Image Colorization (CVPR'2020) ```bibtex @inproceedings{Su-CVPR-2020, author = {Su, Jheng-Wei and Chu, Hung-Kuo and Huang, Jia-Bin}, title = {Instance-aware Image Colorization}, booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, year = {2020} } ```
================================================ FILE: configs/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256.py ================================================ _base_ = ['../_base_/default_runtime.py'] experiment_name = 'inst-colorization_full_official_cocostuff_256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' stage = 'full' model = dict( type='InstColorization', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), image_model=dict( type='ColorizationNet', input_nc=4, output_nc=2, norm_type='batch'), instance_model=dict( type='ColorizationNet', input_nc=4, output_nc=2, norm_type='batch'), fusion_model=dict( type='FusionNet', input_nc=4, output_nc=2, norm_type='batch'), color_data_opt=dict( ab_thresh=0, p=1.0, sample_PS=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, ], ab_norm=110, ab_max=110., ab_quant=10., l_norm=100., l_cent=50., mask_cent=0.5), which_direction='AtoB', loss=dict(type='HuberLoss', delta=.01)) # yapf: disable test_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict( type='InstanceCrop', config_file='mmdet::mask_rcnn/mask-rcnn_x101-32x8d_fpn_ms-poly-3x_coco.py', # noqa from_pretrained=None, finesize=256, box_num_upbound=5), dict( type='Resize', keys=['img', 'cropped_img'], scale=(256, 256), keep_ratio=False), dict( type='PackInputs', data_keys=['box_info', 'box_info_2x', 'box_info_4x', 'box_info_8x']), ] ================================================ FILE: configs/inst_colorization/metafile.yml ================================================ Collections: - Name: Instance-aware Image Colorization Paper: Title: Instance-Aware Image Colorization URL: https://openaccess.thecvf.com/content_CVPR_2020/html/Su_Instance-Aware_Image_Colorization_CVPR_2020_paper.html README: configs/inst_colorization/README.md Task: - colorization Year: 2020 Models: - Config: configs/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256.py In Collection: Instance-aware Image Colorization Name: inst-colorizatioon_full_official_cocostuff-256x256 Results: - Dataset: MS-COCO Metrics: {} Task: Colorization Weights: https://download.openmmlab.com/mmediting/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256-5b9d4eee.pth ================================================ FILE: configs/liif/README.md ================================================ # LIIF (CVPR'2021) > [Learning Continuous Image Representation with Local Implicit Image Function](https://arxiv.org/abs/2012.09161) > **Task**: Image Super-Resolution ## Abstract How to represent an image? While the visual world is presented in a continuous manner, machines store and see the images in a discrete way with 2D arrays of pixels. In this paper, we seek to learn a continuous representation for images. Inspired by the recent progress in 3D reconstruction with implicit neural representation, we propose Local Implicit Image Function (LIIF), which takes an image coordinate and the 2D deep features around the coordinate as inputs, predicts the RGB value at a given coordinate as an output. Since the coordinates are continuous, LIIF can be presented in arbitrary resolution. To generate the continuous representation for images, we train an encoder with LIIF representation via a self-supervised task with super-resolution. The learned continuous representation can be presented in arbitrary resolution even extrapolate to x30 higher resolution, where the training tasks are not provided. We further show that LIIF representation builds a bridge between discrete and continuous representation in 2D, it naturally supports the learning tasks with size-varied image ground-truths and significantly outperforms the method with resizing the ground-truths.
## Results and models | Model | Dataset | scale | PSNR | SSIM | Training Resources | Download | | :--------------------------------------------------------------------------: | :-----: | :---: | :-----: | :-----: | :----------------: | :------------------------------------------------------------------------------: | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x2 | 35.7131 | 0.9366 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.log.json) | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x2 | 31.5579 | 0.8889 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x2 | 34.6647 | 0.9355 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x3 | 32.3805 | 0.8915 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x3 | 0.8039 | 30.9808 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x3 | 28.4605 | 0.8724 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x4 | 30.2748 | 0.8509 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x4 | 26.8415 | 0.7381 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x4 | 29.0245 | 0.8187 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x6 | 27.1187 | 0.7774 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x6 | 24.7461 | 0.6444 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x6 | 26.7770 | 0.7425 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x18 | 20.8516 | 0.5406 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x18 | 20.0096 | 0.4525 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x18 | 22.1987 | 0.5955 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x30 | 18.8467 | 0.5010 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x30 | 18.1321 | 0.3963 | △ | △ | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x30 | 20.5050 | 0.5577 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x2 | 35.7874 | 0.9366 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/liif/liif_rdn_norm_c64b16_g1_1000k_div2k_20210717-22d6fdc8.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/liif/liif_rdn_norm_c64b16_g1_1000k_div2k_20210717-22d6fdc8.log.json) | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x2 | 31.6866 | 0.8896 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x2 | 34.7548 | 0.9356 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x3 | 32.4992 | 0.8923 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x3 | 28.4905 | 0.8037 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x3 | 31.0744 | 0.8731 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x4 | 30.3835 | 0.8513 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x4 | 26.8734 | 0.7373 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x4 | 29.1101 | 0.8197 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x6 | 27.1914 | 0.7751 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x6 | 24.7824 | 0.6434 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x6 | 26.8693 | 0.7437 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x18 | 20.8913 | 0.5329 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x18 | 20.1077 | 0.4537 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x18 | 22.2972 | 0.5950 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set5 | x30 | 18.9354 | 0.4864 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | Set14 | x30 | 18.1448 | 0.3942 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | DIV2K | x30 | 20.5663 | 0.5560 | △ | △ | Note: - △ refers to ditto. - Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py # single-gpu train python tools/train.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth # single-gpu test python tools/test.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth # multi-gpu test ./tools/dist_test.sh configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{chen2021learning, title={Learning continuous image representation with local implicit image function}, author={Chen, Yinbo and Liu, Sifei and Wang, Xiaolong}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={8628--8638}, year={2021} } ``` ================================================ FILE: configs/liif/README_zh-CN.md ================================================ # LIIF (CVPR'2021) > **任务**: 图像超分辨率
LIIF (CVPR'2021) ```bibtex @inproceedings{chen2021learning, title={Learning continuous image representation with local implicit image function}, author={Chen, Yinbo and Liu, Sifei and Wang, Xiaolong}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={8628--8638}, year={2021} } ```

| 算法 | scale | Set5
PSNR / SSIM | Set14
PSNR / SSIM | DIV2K
PSNR / SSIM | GPU 信息 | 下载 | | :-----------------------------------------------------------: | :---: | :-----------------: | :------------------: | :-------------------: | :----------: | :------------------------------------------------------------: | | [liif_edsr_norm_c64b16_g1_1000k_div2k](./liif-edsr-norm_c64b16_1xb16-1000k_div2k.py) | x2 | 35.7131 / 0.9366 | 31.5579 / 0.8889 | 34.6647 / 0.9355 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.log.json) | | △ | x3 | 32.3805 / 0.8915 | 28.4605 / 0.8039 | 30.9808 / 0.8724 | △ | △ | | △ | x4 | 30.2748 / 0.8509 | 26.8415 / 0.7381 | 29.0245 / 0.8187 | △ | △ | | △ | x6 | 27.1187 / 0.7774 | 24.7461 / 0.6444 | 26.7770 / 0.7425 | △ | △ | | △ | x18 | 20.8516 / 0.5406 | 20.0096 / 0.4525 | 22.1987 / 0.5955 | △ | △ | | △ | x30 | 18.8467 / 0.5010 | 18.1321 / 0.3963 | 20.5050 / 0.5577 | △ | △ | | [liif_rdn_norm_c64b16_g1_1000k_div2k](./liif-rdn-norm_c64b16_1xb16-1000k_div2k.py) | x2 | 35.7874 / 0.9366 | 31.6866 / 0.8896 | 34.7548 / 0.9356 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/liif/liif_rdn_norm_c64b16_g1_1000k_div2k_20210717-22d6fdc8.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/liif/liif_rdn_norm_c64b16_g1_1000k_div2k_20210717-22d6fdc8.log.json) | | △ | x3 | 32.4992 / 0.8923 | 28.4905 / 0.8037 | 31.0744 / 0.8731 | △ | △ | | △ | x4 | 30.3835 / 0.8513 | 26.8734 / 0.7373 | 29.1101 / 0.8197 | △ | △ | | △ | x6 | 27.1914 / 0.7751 | 24.7824 / 0.6434 | 26.8693 / 0.7437 | △ | △ | | △ | x18 | 20.8913 / 0.5329 | 20.1077 / 0.4537 | 22.2972 / 0.5950 | △ | △ | | △ | x30 | 18.9354 / 0.4864 | 18.1448 / 0.3942 | 20.5663 / 0.5560 | △ | △ | 注: - △ 指同上。 - 这两个配置仅在 _testing pipeline_ 上有所不同。 所以他们使用相同的检查点。 - 数据根据 [EDSR](../edsr/README.md) 进行正则化。 - 在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py # 单个GPU上训练 python tools/train.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth # 单个GPU上测试 python tools/test.py configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth # 多个GPU上测试 ./tools/dist_test.sh configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/models/base_liif.py', '../_base_/datasets/liif_test_config.py' ] experiment_name = 'liif-edsr-norm_c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale_min, scale_max = 1, 4 # model settings model = dict( type='LIIF', generator=dict( type='LIIFEDSRNet', encoder=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16), imnet=dict( type='MLPRefiner', in_dim=64, out_dim=3, hidden_list=[256, 256, 256, 256]), local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=30000), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.4488 * 255, 0.4371 * 255, 0.4040 * 255], std=[255., 255., 255.], )) ================================================ FILE: configs/liif/liif-rdn-norm_c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/models/base_liif.py', '../_base_/datasets/liif_test_config.py' ] experiment_name = 'liif-rdn-norm_c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale_min, scale_max = 1, 4 # model settings model = dict( type='LIIF', generator=dict( type='LIIFRDNNet', encoder=dict( type='RDNNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=4, num_layers=8, channel_growth=64), imnet=dict( type='MLPRefiner', in_dim=64, out_dim=3, hidden_list=[256, 256, 256, 256]), local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=30000), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.5 * 255, 0.5 * 255, 0.5 * 255], std=[0.5 * 255, 0.5 * 255, 0.5 * 255], )) ================================================ FILE: configs/liif/metafile.yml ================================================ Collections: - Name: LIIF Paper: Title: Learning Continuous Image Representation with Local Implicit Image Function URL: https://arxiv.org/abs/2012.09161 README: configs/liif/README.md Task: - image super-resolution Year: 2021 Models: - Config: configs/liif/liif-edsr-norm_c64b16_1xb16-1000k_div2k.py In Collection: LIIF Name: liif-edsr-norm_c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 35.7131 SSIM: 0.9366 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 31.5579 SSIM: 0.8889 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.6647 SSIM: 0.9355 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 32.3805 SSIM: 0.8915 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 0.8039 SSIM: 30.9808 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 28.4605 SSIM: 0.8724 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 30.2748 SSIM: 0.8509 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 26.8415 SSIM: 0.7381 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 29.0245 SSIM: 0.8187 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 27.1187 SSIM: 0.7774 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 24.7461 SSIM: 0.6444 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 26.777 SSIM: 0.7425 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 20.8516 SSIM: 0.5406 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 20.0096 SSIM: 0.4525 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 22.1987 SSIM: 0.5955 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 18.8467 SSIM: 0.501 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 18.1321 SSIM: 0.3963 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 20.505 SSIM: 0.5577 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/liif/liif_edsr_norm_c64b16_g1_1000k_div2k_20210715-ab7ce3fc.pth - Config: configs/liif/liif-rdn-norm_c64b16_1xb16-1000k_div2k.py In Collection: LIIF Name: liif-rdn-norm_c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 35.7874 SSIM: 0.9366 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 31.6866 SSIM: 0.8896 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.7548 SSIM: 0.9356 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 32.4992 SSIM: 0.8923 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 28.4905 SSIM: 0.8037 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 31.0744 SSIM: 0.8731 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 30.3835 SSIM: 0.8513 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 26.8734 SSIM: 0.7373 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 29.1101 SSIM: 0.8197 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 27.1914 SSIM: 0.7751 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 24.7824 SSIM: 0.6434 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 26.8693 SSIM: 0.7437 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 20.8913 SSIM: 0.5329 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 20.1077 SSIM: 0.4537 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 22.2972 SSIM: 0.595 Task: Image Super-Resolution - Dataset: Set5 Metrics: PSNR: 18.9354 SSIM: 0.4864 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 18.1448 SSIM: 0.3942 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 20.5663 SSIM: 0.556 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/liif/liif_rdn_norm_c64b16_g1_1000k_div2k_20210717-22d6fdc8.pth ================================================ FILE: configs/lsgan/README.md ================================================ # LSGAN (ICCV'2017) > [Least Squares Generative Adversarial Networks](https://openaccess.thecvf.com/content_iccv_2017/html/Mao_Least_Squares_Generative_ICCV_2017_paper.html) > **Task**: Unconditional GANs ## Abstract Unsupervised learning with generative adversarial networks (GANs) has proven hugely successful. Regular GANs hypothesize the discriminator as a classifier with the sigmoid cross entropy loss function. However, we found that this loss function may lead to the vanishing gradients problem during the learning process. To overcome such a problem, we propose in this paper the Least Squares Generative Adversarial Networks (LSGANs) which adopt the least squares loss function for the discriminator. We show that minimizing the objective function of LSGAN yields minimizing the Pearson χ2 divergence. There are two benefits of LSGANs over regular GANs. First, LSGANs are able to generate higher quality images than regular GANs. Second, LSGANs perform more stable during the learning process. We evaluate LSGANs on five scene datasets and the experimental results show that the images generated by LSGANs are of better quality than the ones generated by regular GANs. We also conduct two comparison experiments between LSGANs and regular GANs to illustrate the stability of LSGANs.
## Results and models
LSGAN 64x64, CelebA-Cropped
| Model | Dataset | SWD | MS-SSIM | FID | Download | | :-------------------------------------------------------------------: | :------------: | :-----------------------------: | :-----: | :-----: | :----------------------------------------------------------------------: | | [LSGAN 64x64](./lsgan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py) | CelebA-Cropped | 6.16, 6.83, 37.64/16.87 | 0.3216 | 11.9258 | [model](https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m_20210429_144001-92ca1d0d.pth)\| [log](https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m_20210422_131925.log.json) | | [LSGAN 64x64](./lsgan_dcgan-archi_lr1e-4-1xb128-12Mimgs_lsun-bedroom-64x64.py) | LSUN-Bedroom | 5.66, 9.0, 18.6/11.09 | 0.0671 | 30.7390 | [model](https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_dcgan-archi_lr-1e-4_64_b128x1_12m_20210429_144602-ec4ec6bb.pth)\| [log](https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_dcgan-archi_lr-1e-4_64_b128x1_12m_20210423_005020.log.json) | | [LSGAN 128x128](./lsgan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py) | CelebA-Cropped | 21.66, 9.83, 16.06, 70.76/29.58 | 0.3691 | 38.3752 | [model](https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210429_144229-01ba67dc.pth)\| [log](https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210423_132126.log.json) | | [LSGAN 128x128](./lsgan_lsgan-archi_lr1e-4-1xb64-10Mimgs_lsun-bedroom-128x128.py) | LSUN-Bedroom | 19.52, 9.99, 7.48, 14.3/12.82 | 0.0612 | 51.5500 | [model](https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_lsgan-archi_lr-1e-4_128_b64x1_10m_20210429_155605-cf78c0a8.pth)\| [log](https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_lsgan-archi_lr-1e-4_128_b64x1_10m_20210429_142302.log.json) | ## Citation ```latex @inproceedings{mao2017least, title={Least squares generative adversarial networks}, author={Mao, Xudong and Li, Qing and Xie, Haoran and Lau, Raymond YK and Wang, Zhen and Paul Smolley, Stephen}, booktitle={Proceedings of the IEEE international conference on computer vision}, pages={2794--2802}, year={2017}, url={https://openaccess.thecvf.com/content_iccv_2017/html/Mao_Least_Squares_Generative_ICCV_2017_paper.html}, } ``` ================================================ FILE: configs/lsgan/lsgan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] model = dict(type='LSGAN') total_iters = 100000 disc_step = 1 train_cfg = dict(max_iters=total_iters * disc_step) # define dataset # batch_size and data_root must be set batch_size = 128 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0.5, 0.99)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # METRICS metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-50k', real_nums=50000, fake_nums=50000, inception_style='StyleGAN', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/lsgan/lsgan_dcgan-archi_lr1e-4-1xb128-12Mimgs_lsun-bedroom-64x64.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_64x64.py', '../_base_/datasets/unconditional_imgs_64x64.py', '../_base_/gen_default_runtime.py' ] model = dict(type='LSGAN', discriminator=dict(output_scale=4, out_channels=1)) total_iters = 100000 disc_step = 1 train_cfg = dict(max_iters=total_iters * disc_step) # define dataset # `batch_size` and `data_root` need to be set. batch_size = 128 data_root = './data/lsun/images/bedroom_train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) test_bs = 32 val_dataloader = dict(batch_size=test_bs, dataset=dict(data_root=data_root)) test_dataloader = dict(batch_size=test_bs, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99)))) default_hooks = dict( checkpoint=dict(save_best=['FID-Full-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/lsgan/lsgan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py ================================================ _base_ = [ '../_base_/models/dcgan/base_dcgan_128x128.py', '../_base_/datasets/unconditional_imgs_128x128.py', '../_base_/gen_default_runtime.py' ] model = dict(type='LSGAN', discriminator=dict(output_scale=4, out_channels=1)) total_iters = 160000 disc_step = 1 train_cfg = dict(max_iters=total_iters * disc_step) # define dataset # you must set `samples_per_gpu` and `imgs_root` # `batch_size` and `data_root` need to be set. batch_size = 64 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99)))) default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # METRICS metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) # TODO # metrics = dict( # ms_ssim10k=dict(type='MS_SSIM', num_images=10000), # swd16k=dict(type='SWD', num_images=16384, image_shape=(3, 128, 128)), # fid50k=dict(type='FID', num_images=50000, inception_pkl=None)) ================================================ FILE: configs/lsgan/lsgan_lsgan-archi_lr1e-4-1xb64-10Mimgs_lsun-bedroom-128x128.py ================================================ _base_ = [ '../_base_/datasets/unconditional_imgs_128x128.py', '../_base_/gen_default_runtime.py' ] # define model model = dict( type='LSGAN', noise_size=1024, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='LSGANGenerator', output_scale=128, base_channels=256, noise_size=1024), discriminator=dict( type='LSGANDiscriminator', input_scale=128, base_channels=64)) total_iters = 160000 disc_step = 1 train_cfg = dict(max_iters=total_iters * disc_step) # define dataset batch_size = 64 data_root = './data/lsun/images/bedroom_train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) test_bs = 32 val_dataloader = dict(batch_size=test_bs, dataset=dict(data_root=data_root)) test_dataloader = dict(batch_size=test_bs, dataset=dict(data_root=data_root)) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.99)))) default_hooks = dict( checkpoint=dict(save_best=['FID-Full-50k/fid'], rule=['less'])) # adjust running config # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='PyTorch', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/lsgan/metafile.yml ================================================ Collections: - Name: LSGAN Paper: Title: Least Squares Generative Adversarial Networks URL: https://openaccess.thecvf.com/content_iccv_2017/html/Mao_Least_Squares_Generative_ICCV_2017_paper.html README: configs/lsgan/README.md Task: - unconditional gans Year: 2017 Models: - Config: configs/lsgan/lsgan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64.py In Collection: LSGAN Name: lsgan_dcgan-archi_lr1e-3-1xb128-12Mimgs_celeba-cropped-64x64 Results: - Dataset: CelebA-Cropped Metrics: FID: 11.9258 MS-SSIM: 0.3216 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-3_64_b128x1_12m_20210429_144001-92ca1d0d.pth - Config: configs/lsgan/lsgan_dcgan-archi_lr1e-4-1xb128-12Mimgs_lsun-bedroom-64x64.py In Collection: LSGAN Name: lsgan_dcgan-archi_lr1e-4-1xb128-12Mimgs_lsun-bedroom-64x64 Results: - Dataset: LSUN-Bedroom Metrics: FID: 30.739 MS-SSIM: 0.0671 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_dcgan-archi_lr-1e-4_64_b128x1_12m_20210429_144602-ec4ec6bb.pth - Config: configs/lsgan/lsgan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128.py In Collection: LSGAN Name: lsgan_dcgan-archi_lr1e-4-1xb64-10Mimgs_celeba-cropped-128x128 Results: - Dataset: CelebA-Cropped Metrics: FID: 38.3752 MS-SSIM: 0.3691 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/lsgan/lsgan_celeba-cropped_dcgan-archi_lr-1e-4_128_b64x1_10m_20210429_144229-01ba67dc.pth - Config: configs/lsgan/lsgan_lsgan-archi_lr1e-4-1xb64-10Mimgs_lsun-bedroom-128x128.py In Collection: LSGAN Name: lsgan_lsgan-archi_lr1e-4-1xb64-10Mimgs_lsun-bedroom-128x128 Results: - Dataset: LSUN-Bedroom Metrics: FID: 51.55 MS-SSIM: 0.0612 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/lsgan/lsgan_lsun-bedroom_lsgan-archi_lr-1e-4_128_b64x1_10m_20210429_155605-cf78c0a8.pth ================================================ FILE: configs/nafnet/README.md ================================================ # NAFNet (ECCV'2022) > [Simple Baselines for Image Restoration](https://arxiv.org/abs/2204.04676) > **Task**: Image Restoration ## Abstract Although there have been significant advances in the field of image restoration recently, the system complexity of the state-of-the-art (SOTA) methods is increasing as well, which may hinder the convenient analysis and comparison of methods. In this paper, we propose a simple baseline that exceeds the SOTA methods and is computationally efficient. To further simplify the baseline, we reveal that the nonlinear activation functions, e.g. Sigmoid, ReLU, GELU, Softmax, etc. are not necessary: they could be replaced by multiplication or removed. Thus, we derive a Nonlinear Activation Free Network, namely NAFNet, from the baseline. SOTA results are achieved on various challenging benchmarks, e.g. 33.69 dB PSNR on GoPro (for image deblurring), exceeding the previous SOTA 0.38 dB with only 8.4% of its computational costs; 40.30 dB PSNR on SIDD (for image denoising), exceeding the previous SOTA 0.28 dB with less than half of its computational costs.
## Results and models | Model | Dataset | image size | PSNR | SSIM | GPU Info | Download | | :---------------------------------------------------------------------: | :-----: | :--------: | :--------------: | :------------: | :------: | :------------------------------------------------------------------------: | | [nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd](./nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py) | SIDD | 256X256 | 40.3045(40.3045) | 0.9253(0.9614) | 1 (A100) | [model](https://download.openmmlab.com/mmediting/nafnet/NAFNet-SIDD-midc64.pth) \| log(coming soon) | | [nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro](./nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py) | GoPro | 1280x720 | 33.7246(33.7103) | 0.9479(0.9668) | 1 (A100) | [model](https://download.openmmlab.com/mmediting/nafnet/NAFNet-GoPro-midc64.pth) \| log(coming soon) | Note: - a(b) where a denotes the value run by MMagic, b denotes the value copied from the original paper. - PSNR is evaluated on RGB channels. - SSIM is evaluated by averaging SSIMs on RGB channels, however the original paper uses the 3D SSIM kernel. ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py # single-gpu train python tools/train.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py # multi-gpu train ./tools/dist_train.sh configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](../../docs/en/user_guides/train_test.md).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint # single-gpu test python tools/test.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint # multi-gpu test ./tools/dist_test.sh configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint 8 ``` Pretrained checkpoints will come soon. For more details, you can refer to **Test a pre-trained model** part in [train_test.md](../../docs/en/user_guides/train_test.md).
## Citation ```bibtex @article{chen2022simple, title={Simple Baselines for Image Restoration}, author={Chen, Liangyu and Chu, Xiaojie and Zhang, Xiangyu and Sun, Jian}, journal={arXiv preprint arXiv:2204.04676}, year={2022} } ``` ================================================ FILE: configs/nafnet/README_zh-CN.md ================================================ # NAFNET (ECCV'2022) > **任务**: 图像恢复
NAFNET (ECCV'2022) ```bibtex @article{chen2022simple, title={Simple Baselines for Image Restoration}, author={Chen, Liangyu and Chu, Xiaojie and Zhang, Xiangyu and Sun, Jian}, journal={arXiv preprint arXiv:2204.04676}, year={2022} } ```
| 方法 | 图片尺寸 | PSNR | SSIM | GPU信息 | 下载 | | :---------------------------------------------------------------------------: | :------: | :--------------: | :------------: | :------: | :---------------------------------------------------------------------------: | | [nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd](./nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py) | 256X256 | 40.3045(40.3045) | 0.9253(0.9614) | 1 (A100) | [模型](https://download.openmmlab.com/mmediting/nafnet/NAFNet-SIDD-midc64.pth) \| 日志(即将到来) | | [nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro](./nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py) | 1280x720 | 33.7246(33.7103) | 0.9479(0.9668) | 1 (A100) | [模型](https://download.openmmlab.com/mmediting/nafnet/NAFNet-GoPro-midc64.pth) \| 日志(即将到来) | Note: - 评估结果a(b)中,a代表由MMagic测量,b代表由原论文提供。 - PSNR是在RGB通道评估。 - SSIM是平均的分别在RGB通道评估的SSIM, 而原论文使用了3D的SSIM卷积核做统一评估。 ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py # 单个GPU上训练 python tools/train.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py # 多个GPU上训练 ./tools/dist_train.sh configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py 8 ``` 更多细节可以参考 [train_test.md](../../docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint # 单个GPU上测试 python tools/test.py configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint # 多个GPU上测试 ./tools/dist_test.sh configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py /path/to/checkpoint 8 ``` 预训练模型未来将会上传,敬请等待。 更多细节可以参考 [train_test.md](../../docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/nafnet/metafile.yml ================================================ Collections: - Name: NAFNet Paper: Title: Simple Baselines for Image Restoration URL: https://arxiv.org/abs/2204.04676 README: configs/nafnet/README.md Task: - image restoration Year: 2022 Models: - Config: configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py In Collection: NAFNet Name: nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd Results: - Dataset: SIDD Metrics: GPU Info: 1.0 PSNR: 40.3045 SSIM: 0.9253 Task: Image Restoration Weights: https://download.openmmlab.com/mmediting/nafnet/NAFNet-SIDD-midc64.pth - Config: configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py In Collection: NAFNet Name: nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro Results: - Dataset: GoPro Metrics: GPU Info: 1.0 PSNR: 33.7246 SSIM: 0.9479 Task: Image Restoration Weights: https://download.openmmlab.com/mmediting/nafnet/NAFNet-GoPro-midc64.pth ================================================ FILE: configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'nafnet_c64eb11128mb1db1111_lr1e-3_400k_gopro' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='NAFNetLocal', img_channels=3, mid_channels=64, enc_blk_nums=[1, 1, 1, 28], middle_blk_num=1, dec_blk_nums=[1, 1, 1, 1], ), pixel_loss=dict(type='PSNRLoss'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PairedRandomCrop', gt_patch_size=256), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=8, batch_size=8, # gpus 4 persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root='./data/gopro/train', data_prefix=dict(gt='sharp', img='blur'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='gopro', task_name='deblur'), data_root='./data/gopro/test', data_prefix=dict(gt='sharp', img='blur'), pipeline=val_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=400_000, val_interval=20000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='AdamW', lr=1e-3, weight_decay=1e-3, betas=(0.9, 0.9))) # learning policy param_scheduler = dict( type='CosineAnnealingLR', by_epoch=False, T_max=400_000, eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) randomness = dict(seed=10, diff_rank_seed=True) ================================================ FILE: configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'nafnet_c64eb2248mb12db2222_lr1e-3_400k_sidd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='NAFNet', img_channels=3, mid_channels=64, enc_blk_nums=[2, 2, 4, 8], middle_blk_num=12, dec_blk_nums=[2, 2, 2, 2], ), pixel_loss=dict(type='PSNRLoss'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0.0, 0.0, 0.0], std=[255.0, 255.0, 255.0], )) train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='LoadImageFromFile', key='gt'), dict(type='SetValues', dictionary=dict(scale=1)), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PairedRandomCrop', gt_patch_size=256), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=8, batch_size=8, # gpus 4 persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='sidd', task_name='denoising'), data_root='./data/SIDD/train', data_prefix=dict(gt='gt', img='noisy'), filename_tmpl=dict(img='{}_NOISY', gt='{}_GT'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='sidd', task_name='denoising'), data_root='./data/SIDD/val/', data_prefix=dict(gt='gt', img='noisy'), filename_tmpl=dict(gt='{}_GT', img='{}_NOISY'), pipeline=val_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=400_000, val_interval=20000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='AdamW', lr=1e-3, weight_decay=1e-3, betas=(0.9, 0.9))) # learning policy param_scheduler = dict( type='CosineAnnealingLR', by_epoch=False, T_max=400_000, eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) visualizer = dict(bgr2rgb=False) ================================================ FILE: configs/partial_conv/README.md ================================================ # PConv (ECCV'2018) > [Image Inpainting for Irregular Holes Using Partial Convolutions](https://arxiv.org/abs/1804.07723) > **Task**: Inpainting ## Abstract Existing deep learning based image inpainting methods use a standard convolutional network over the corrupted image, using convolutional filter responses conditioned on both valid pixels as well as the substitute values in the masked holes (typically the mean value). This often leads to artifacts such as color discrepancy and blurriness. Post-processing is usually used to reduce such artifacts, but are expensive and may fail. We propose the use of partial convolutions, where the convolution is masked and renormalized to be conditioned on only valid pixels. We further include a mechanism to automatically generate an updated mask for the next layer as part of the forward pass. Our model outperforms other methods for irregular masks. We show qualitative and quantitative comparisons with other methods to validate our approach.
## Results and models | Model | Mask Type | Resolution | Train Iters | Dataset | l1 error | PSNR | SSIM | Training Resources | Download | | :----------------------------------------------------: | :-------: | :--------: | :---------: | :-----------: | :------: | :----: | :---: | :----------------: | :----------------------------------------------------------------: | | [PConv_Stage1](./pconv_stage1_8xb12_places-256x256.py) | free-form | 256x256 | 500k | Places365-val | - | - | - | 8 | - | | [PConv_Stage2](./pconv_stage2_4xb2_places-256x256.py) | free-form | 256x256 | 500k | Places365-val | 8.776 | 22.762 | 0.801 | 4 | [model](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.log.json) | | [PConv_Stage1](./pconv_stage1_8xb1_celeba-256x256.py) | free-form | 256x256 | 500k | CelebA-val | - | - | - | 8 | - | | [PConv_Stage2](./pconv_stage2_4xb2_celeba-256x256.py) | free-form | 256x256 | 500k | CelebA-val | 5.990 | 25.404 | 0.853 | 4 | [model](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_celeba_20200619-860f8b95.pth) \| [log](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_celeba_20200619-860f8b95.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py # single-gpu train python tools/train.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py # multi-gpu train ./tools/dist_train.sh configs/partial_conv/pconv_stage2_4xb2_places-256x256.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth # single-gpu test python tools/test.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth # multi-gpu test ./tools/dist_test.sh configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{liu2018image, title={Image inpainting for irregular holes using partial convolutions}, author={Liu, Guilin and Reda, Fitsum A and Shih, Kevin J and Wang, Ting-Chun and Tao, Andrew and Catanzaro, Bryan}, booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, pages={85--100}, year={2018} } ``` ================================================ FILE: configs/partial_conv/README_zh-CN.md ================================================ # PConv (ECCV'2018) > **任务**: 图像修复
PConv (ECCV'2018) ```bibtex @inproceedings{liu2018image, title={Image inpainting for irregular holes using partial convolutions}, author={Liu, Guilin and Reda, Fitsum A and Shih, Kevin J and Wang, Ting-Chun and Tao, Andrew and Catanzaro, Bryan}, booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, pages={85--100}, year={2018} } ```

**Places365-Challenge** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :----------------------------------------------------: | :-------: | :-----: | :--------: | :-----------: | :-----: | :----: | :---: | :------: | :-------------------------------------------------------------------------------: | | [PConv_Stage1](./pconv_stage1_8xb12_places-256x256.py) | free-form | 256x256 | 500k | Places365-val | - | - | - | 8 | - | | [PConv_Stage2](./pconv_stage2_4xb2_places-256x256.py) | free-form | 256x256 | 500k | Places365-val | 8.776 | 22.762 | 0.801 | 4 | [模型](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.log.json) | **CelebA-HQ** | 算法 | 掩膜类型 | 分辨率 | 训练集容量 | 测试集 | l1 损失 | PSNR | SSIM | GPU 信息 | 下载 | | :---------------------------------------------------: | :-------: | :-----: | :--------: | :--------: | :-----: | :----: | :---: | :------: | :-----------------------------------------------------------------------------------: | | [PConv_Stage1](./pconv_stage1_8xb1_celeba-256x256.py) | free-form | 256x256 | 500k | CelebA-val | - | - | - | 8 | - | | [PConv_Stage2](./pconv_stage2_4xb2_celeba-256x256.py) | free-form | 256x256 | 500k | CelebA-val | 5.990 | 25.404 | 0.853 | 4 | [模型](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_celeba_20200619-860f8b95.pth) \| [日志](https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_celeba_20200619-860f8b95.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py # 单个GPU上训练 python tools/train.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py # 多个GPU上训练 ./tools/dist_train.sh configs/partial_conv/pconv_stage2_4xb2_places-256x256.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth # 单个GPU上测试 python tools/test.py configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth # 多个GPU上测试 ./tools/dist_test.sh configs/partial_conv/pconv_stage2_4xb2_places-256x256.py https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/partial_conv/metafile.yml ================================================ Collections: - Name: PConv Paper: Title: Image Inpainting for Irregular Holes Using Partial Convolutions URL: https://arxiv.org/abs/1804.07723 README: configs/partial_conv/README.md Task: - inpainting Year: 2018 Models: - Config: configs/partial_conv/pconv_stage1_8xb12_places-256x256.py In Collection: PConv Name: pconv_stage1_8xb12_places-256x256 Results: - Dataset: Places365-val Metrics: {} Task: Inpainting - Config: configs/partial_conv/pconv_stage2_4xb2_places-256x256.py In Collection: PConv Name: pconv_stage2_4xb2_places-256x256 Results: - Dataset: Places365-val Metrics: PSNR: 22.762 SSIM: 0.801 l1 error: 8.776 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_places_20200619-1ffed0e8.pth - Config: configs/partial_conv/pconv_stage1_8xb1_celeba-256x256.py In Collection: PConv Name: pconv_stage1_8xb1_celeba-256x256 Results: - Dataset: CelebA-val Metrics: {} Task: Inpainting - Config: configs/partial_conv/pconv_stage2_4xb2_celeba-256x256.py In Collection: PConv Name: pconv_stage2_4xb2_celeba-256x256 Results: - Dataset: CelebA-val Metrics: PSNR: 25.404 SSIM: 0.853 l1 error: 5.99 Task: Inpainting Weights: https://download.openmmlab.com/mmediting/inpainting/pconv/pconv_256x256_stage2_4x2_celeba_20200619-860f8b95.pth ================================================ FILE: configs/partial_conv/pconv_stage1_8xb12_places-256x256.py ================================================ _base_ = [ '../_base_/models/base_pconv.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] experiment_name = 'pconv_stage1_8xb1_places-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=0, start_iter=0, ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='SyncBN'))), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=12, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=800002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0002)) checkpoint = dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/partial_conv/pconv_stage1_8xb1_celeba-256x256.py ================================================ _base_ = [ '../_base_/models/base_pconv.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/celeba.py' ] experiment_name = 'pconv_stage1_8xb1_celeba-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=0, start_iter=0, ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='SyncBN'))), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=1, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=800002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0002)) checkpoint = dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir) ================================================ FILE: configs/partial_conv/pconv_stage2_4xb2_celeba-256x256.py ================================================ _base_ = [ '../_base_/models/base_pconv.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/celeba.py' ] experiment_name = 'pconv_stage2_4xb2_celeba-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=0, start_iter=0, ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='SyncBN', requires_grad=False), norm_eval=True), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='SyncBN'))), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=2, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict( batch_size=1, dataset=dict(pipeline=test_pipeline), ) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=300002, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00005)) checkpoint = dict( type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir) # load_from = 'pconv_stage1_8xb1_celeba-256x256/iter_800002.pth' ================================================ FILE: configs/partial_conv/pconv_stage2_4xb2_places-256x256.py ================================================ _base_ = [ '../_base_/models/base_pconv.py', '../_base_/inpaint_default_runtime.py', '../_base_/datasets/places.py' ] experiment_name = 'pconv_stage2_4xb2_places-256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' model = dict( train_cfg=dict( disc_step=0, start_iter=0, ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='SyncBN', requires_grad=False), norm_eval=True), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='SyncBN'))), ) input_shape = (256, 256) train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='irregular', mask_config=dict( num_vertices=(4, 10), max_angle=6.0, length_range=(20, 128), brush_width=(10, 45), area_ratio_range=(0.15, 0.65), img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] test_pipeline = train_pipeline train_dataloader = dict( batch_size=2, sampler=dict(shuffle=False), dataset=dict(pipeline=train_pipeline), ) val_dataloader = dict(batch_size=1, dataset=dict(pipeline=test_pipeline)) test_dataloader = val_dataloader train_cfg = dict( type='IterBasedTrainLoop', max_iters=500000, val_interval=50000, ) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00005)) checkpoint_config = dict( type='CheckpointHook', by_epoch=False, interval=50000, out_dir=save_dir) # load_from = 'pconv_stage1_8xb1_places-256x256/iter_800002.pth' ================================================ FILE: configs/pggan/README.md ================================================ # PGGAN (ICLR'2018) > [Progressive Growing of GANs for Improved Quality, Stability, and Variation](https://arxiv.org/abs/1710.10196) > **Task**: Unconditional GANs ## Abstract We describe a new training methodology for generative adversarial networks. The key idea is to grow both the generator and discriminator progressively: starting from a low resolution, we add new layers that model increasingly fine details as training progresses. This both speeds the training up and greatly stabilizes it, allowing us to produce images of unprecedented quality, e.g., CelebA images at 1024^2. We also propose a simple way to increase the variation in generated images, and achieve a record inception score of 8.80 in unsupervised CIFAR10. Additionally, we describe several implementation details that are important for discouraging unhealthy competition between the generator and discriminator. Finally, we suggest a new metric for evaluating GAN results, both in terms of image quality and variation. As an additional contribution, we construct a higher-quality version of the CelebA dataset.
## Results and models
Results (compressed) from our PGGAN trained in CelebA-HQ@1024
| Model | Dataset | MS-SSIM | SWD(xx,xx,xx,xx/avg) | Download | | :-------------------------------------------------------------: | :------------: | :-----: | :--------------------------: | :--------------------------------------------------------------------------------------: | | [pggan_128x128](./pggan_8xb4-12Mimgs_celeba-cropped-128x128.py) | celeba-cropped | 0.3023 | 3.42, 4.04, 4.78, 20.38/8.15 | [model](https://download.openmmlab.com/mmediting/pggan/pggan_celeba-cropped_128_g8_20210408_181931-85a2e72c.pth) | | [pggan_128x128](./pggan_8xb4-12Mimgs_lsun-bedroom-128x128.py) | lsun-bedroom | 0.0602 | 3.5, 2.96, 2.76, 9.65/4.72 | [model](https://download.openmmlab.com/mmediting/pggan/pggan_lsun-bedroom_128x128_g8_20210408_182033-5e59f45d.pth) | | [pggan_1024x1024](./pggan_8xb4-12Mimg_celeba-hq-1024x1024.py) | celeba-hq | 0.3379 | 8.93, 3.98, 3.07, 2.64/4.655 | [model](https://download.openmmlab.com/mmediting/pggan/pggan_celeba-hq_1024_g8_20210408_181911-f1ef51c3.pth) | ## Citation PGGAN (arXiv'2017) ```latex @article{karras2017progressive, title={Progressive growing of gans for improved quality, stability, and variation}, author={Karras, Tero and Aila, Timo and Laine, Samuli and Lehtinen, Jaakko}, journal={arXiv preprint arXiv:1710.10196}, year={2017}, url={https://arxiv.org/abs/1710.10196}, } ``` ================================================ FILE: configs/pggan/metafile.yml ================================================ Collections: - Name: PGGAN Paper: Title: Progressive Growing of GANs for Improved Quality, Stability, and Variation URL: https://arxiv.org/abs/1710.10196 README: configs/pggan/README.md Task: - unconditional gans Year: 2018 Models: - Config: configs/pggan/pggan_8xb4-12Mimgs_celeba-cropped-128x128.py In Collection: PGGAN Name: pggan_8xb4-12Mimgs_celeba-cropped-128x128 Results: - Dataset: celeba-cropped Metrics: MS-SSIM: 0.3023 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pggan/pggan_celeba-cropped_128_g8_20210408_181931-85a2e72c.pth - Config: configs/pggan/pggan_8xb4-12Mimgs_lsun-bedroom-128x128.py In Collection: PGGAN Name: pggan_8xb4-12Mimgs_lsun-bedroom-128x128 Results: - Dataset: lsun-bedroom Metrics: MS-SSIM: 0.0602 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pggan/pggan_lsun-bedroom_128x128_g8_20210408_182033-5e59f45d.pth - Config: configs/pggan/pggan_8xb4-12Mimg_celeba-hq-1024x1024.py In Collection: PGGAN Name: pggan_8xb4-12Mimg_celeba-hq-1024x1024 Results: - Dataset: celeba-hq Metrics: MS-SSIM: 0.3379 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pggan/pggan_celeba-hq_1024_g8_20210408_181911-f1ef51c3.pth ================================================ FILE: configs/pggan/pggan_8xb4-12Mimg_celeba-hq-1024x1024.py ================================================ _base_ = ['../_base_/gen_default_runtime.py'] # define GAN model model = dict( type='ProgressiveGrowingGAN', data_preprocessor=dict(type='DataPreprocessor'), noise_size=512, generator=dict(type='PGGANGenerator', out_scale=1024, noise_size=512), discriminator=dict(type='PGGANDiscriminator', in_scale=1024), nkimgs_per_scale={ '4': 600, '8': 1200, '16': 1200, '32': 1200, '64': 1200, '128': 1200, '256': 1200, '512': 1200, '1024': 12000, }, transition_kimgs=600, ema_config=dict(interval=1)) # MODEL model_wrapper_cfg = dict(find_unused_parameters=True) # TRAIN train_cfg = dict(max_iters=280000) optim_wrapper = dict( constructor='PGGANOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=dict( generator={ '128': 0.0015, '256': 0.002, '512': 0.003, '1024': 0.003 }, discriminator={ '128': 0.0015, '256': 0.002, '512': 0.003, '1024': 0.003 })) # DATA dataset_type = 'GrowScaleImgDataset' pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Flip', keys='gt', direction='horizontal'), dict(type='PackInputs') ] train_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type=dataset_type, data_roots={ '64': './data/celebahq/imgs_64', '256': './data/celebahq/imgs_256', '512': './data/celebahq/imgs_512', '1024': './data/celebahq/imgs_1024' }, gpu_samples_base=4, # note that this should be changed with total gpu number gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4 }, len_per_stage=300000, pipeline=pipeline), sampler=dict(type='InfiniteSampler', shuffle=True)) test_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type='BasicImageDataset', pipeline=pipeline, data_prefix=dict(gt=''), data_root='./data/celebahq/imgs_1024'), sampler=dict(type='DefaultSampler', shuffle=False)) # VIS_HOOK + DATAFETCH custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), dict(type='PGGANFetchDataHook') ] default_hooks = dict( checkpoint=dict( max_keep_ckpts=20, save_best=['swd/avg', 'ms-ssim/avg'], rule=['less', 'greater'])) # METRICS metrics = [ dict( type='SWD', fake_nums=16384, image_shape=(3, 1024, 1024), prefix='SWD'), dict(type='MS_SSIM', fake_nums=10000, prefix='MS-SSIM') ] # do not evaluate in training val_cfg = val_evaluator = val_dataloader = None test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/pggan/pggan_8xb4-12Mimgs_celeba-cropped-128x128.py ================================================ _base_ = ['../_base_/gen_default_runtime.py'] # define GAN model model = dict( type='ProgressiveGrowingGAN', data_preprocessor=dict(type='DataPreprocessor'), noise_size=512, generator=dict(type='PGGANGenerator', out_scale=128), discriminator=dict(type='PGGANDiscriminator', in_scale=128), nkimgs_per_scale={ '4': 600, '8': 1200, '16': 1200, '32': 1200, '64': 1200, '128': 12000 }, transition_kimgs=600, ema_config=dict(interval=1)) # MODEL model_wrapper_cfg = dict(find_unused_parameters=True) # TRAIN train_cfg = dict(max_iters=280000) optim_wrapper = dict( constructor='PGGANOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=dict(generator={'128': 0.0015}, discriminator={'128': 0.0015})) # DATA dataset_type = 'GrowScaleImgDataset' data_roots = {'128': './data/celeba-cropped/cropped_images_aligned_png'} train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(128, 128)), dict(type='Flip', keys='gt', direction='horizontal'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(128, 128)), dict(type='PackInputs') ] train_dataloader = dict( num_workers=4, batch_size=64, # initialize batch size dataset=dict( type=dataset_type, pipeline=train_pipeline, data_roots=data_roots, gpu_samples_base=4, # note that this should be changed with total gpu number gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4 }, len_per_stage=-1), sampler=dict(type='InfiniteSampler', shuffle=True)) test_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type='BasicImageDataset', pipeline=test_pipeline, data_prefix=dict(gt=''), data_root=data_roots['128']), sampler=dict(type='DefaultSampler', shuffle=False)) # VIS_HOOK + DATAFETCH custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), dict(type='PGGANFetchDataHook') ] default_hooks = dict( checkpoint=dict( max_keep_ckpts=20, save_best=['swd/avg', 'ms-ssim/avg'], rule=['less', 'greater'])) # METRICS metrics = [ dict(type='SWD', fake_nums=16384, image_shape=(3, 128, 128), prefix='SWD'), dict(type='MS_SSIM', fake_nums=10000, prefix='MS-SSIM') ] # do not evaluate in training val_cfg = val_evaluator = val_dataloader = None test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/pggan/pggan_8xb4-12Mimgs_lsun-bedroom-128x128.py ================================================ _base_ = ['./pggan_8xb4-12Mimgs_celeba-cropped-128x128.py'] # Overwrite data configs data_roots = {'128': './data/lsun/images/bedroom_train'} train_dataloader = dict(batch_size=64, dataset=dict(data_roots=data_roots)) test_dataloader = dict(dataset=dict(data_root=data_roots['128'])) ================================================ FILE: configs/pix2pix/README.md ================================================ # Pix2Pix (CVPR'2017) > [Pix2Pix: Image-to-Image Translation with Conditional Adversarial Networks](https://openaccess.thecvf.com/content_cvpr_2017/html/Isola_Image-To-Image_Translation_With_CVPR_2017_paper.html) > **Task**: Image2Image ## Abstract We investigate conditional adversarial networks as a general-purpose solution to image-to-image translation problems. These networks not only learn the mapping from input image to output image, but also learn a loss function to train this mapping. This makes it possible to apply the same generic approach to problems that traditionally would require very different loss formulations. We demonstrate that this approach is effective at synthesizing photos from label maps, reconstructing objects from edge maps, and colorizing images, among other tasks. Moreover, since the release of the pix2pix software associated with this paper, hundreds of twitter users have posted their own artistic experiments using our system. As a community, we no longer hand-engineer our mapping functions, and this work suggests we can achieve reasonable results without handengineering our loss functions either.
## Results and Models
Results from Pix2Pix trained by mmagic
We use `FID` and `IS` metrics to evaluate the generation performance of pix2pix.1 | Model | Dataset | FID | IS | Download | | :----------------------------------------------------------------------------: | :---------: | :------: | :---: | :------------------------------------------------------------------------------------------------: | | [Ours](./pix2pix_vanilla-unet-bn_1xb1-80kiters_facades.py) | facades | 124.9773 | 1.620 | [model](https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_1x1_80k_facades_20210902_170442-c0958d50.pth) \| [log](https://download.openmmlab.com/mmediting/pix2pix/pix2pix_vanilla_unet_bn_1x1_80k_facades_20210317_172625.log.json)2 | | [Ours](./pix2pix_vanilla-unet-bn_1xb1-220kiters_aerial2maps.py) | aerial2maps | 122.5856 | 3.137 | [model](https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_a2b_1x1_219200_maps_convert-bgr_20210902_170729-59a31517.pth) | | [Ours](./pix2pix_vanilla-unet-bn_1xb1-220kiters_maps2aerial.py) | maps2aerial | 88.4635 | 3.310 | [model](https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_b2a_1x1_219200_maps_convert-bgr_20210902_170814-6d2eac4a.pth) | | [Ours](./pix2pix_vanilla-unet-bn_wo-jitter-flip-1xb4-190kiters_edges2shoes.py) | edges2shoes | 84.3750 | 2.815 | [model](https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_wo_jitter_flip_1x4_186840_edges2shoes_convert-bgr_20210902_170902-0c828552.pth) | `FID` comparison with official: | Dataset | facades | aerial2maps | maps2aerial | edges2shoes | average | | :------: | :---------: | :----------: | :---------: | :---------: | :----------: | | official | **119.135** | 149.731 | 102.072 | **75.774** | 111.678 | | ours | 124.9773 | **122.5856** | **88.4635** | 84.3750 | **105.1003** | `IS` comparison with official: | Dataset | facades | aerial2maps | maps2aerial | edges2shoes | average | | :------: | :-------: | :---------: | :---------: | :---------: | :--------: | | official | **1.650** | 2.529 | **3.552** | 2.766 | 2.624 | | ours | 1.620 | **3.137** | 3.310 | **2.815** | **2.7205** | Note: 1. we strictly follow the [paper](http://openaccess.thecvf.com/content_cvpr_2017/papers/Isola_Image-To-Image_Translation_With_CVPR_2017_paper.pdf) setting in Section 3.3: "*At inference time, we run the generator net in exactly the same manner as during the training phase. This differs from the usual protocol in that we apply dropout at test time, and we apply batch normalization using the statistics of the test batch, rather than aggregated statistics of the training batch.*" (i.e., use model.train() mode), thus may lead to slightly different inference results every time. 2. This is the training log before refactoring. Updated logs will be released soon. ## Citation ```latex @inproceedings{isola2017image, title={Image-to-image translation with conditional adversarial networks}, author={Isola, Phillip and Zhu, Jun-Yan and Zhou, Tinghui and Efros, Alexei A}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={1125--1134}, year={2017}, url={https://openaccess.thecvf.com/content_cvpr_2017/html/Isola_Image-To-Image_Translation_With_CVPR_2017_paper.html}, } ``` ================================================ FILE: configs/pix2pix/metafile.yml ================================================ Collections: - Name: Pix2Pix Paper: Title: 'Pix2Pix: Image-to-Image Translation with Conditional Adversarial Networks' URL: https://openaccess.thecvf.com/content_cvpr_2017/html/Isola_Image-To-Image_Translation_With_CVPR_2017_paper.html README: configs/pix2pix/README.md Task: - image2image Year: 2017 Models: - Config: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-80kiters_facades.py In Collection: Pix2Pix Name: pix2pix_vanilla-unet-bn_1xb1-80kiters_facades Results: - Dataset: facades Metrics: FID: 124.9773 IS: 1.62 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_1x1_80k_facades_20210902_170442-c0958d50.pth - Config: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-220kiters_aerial2maps.py In Collection: Pix2Pix Name: pix2pix_vanilla-unet-bn_1xb1-220kiters_aerial2maps Results: - Dataset: aerial2maps Metrics: FID: 122.5856 IS: 3.137 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_a2b_1x1_219200_maps_convert-bgr_20210902_170729-59a31517.pth - Config: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-220kiters_maps2aerial.py In Collection: Pix2Pix Name: pix2pix_vanilla-unet-bn_1xb1-220kiters_maps2aerial Results: - Dataset: maps2aerial Metrics: FID: 88.4635 IS: 3.31 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_b2a_1x1_219200_maps_convert-bgr_20210902_170814-6d2eac4a.pth - Config: configs/pix2pix/pix2pix_vanilla-unet-bn_wo-jitter-flip-1xb4-190kiters_edges2shoes.py In Collection: Pix2Pix Name: pix2pix_vanilla-unet-bn_wo-jitter-flip-1xb4-190kiters_edges2shoes Results: - Dataset: edges2shoes Metrics: FID: 84.375 IS: 2.815 Task: Image2Image Weights: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_wo_jitter_flip_1x4_186840_edges2shoes_convert-bgr_20210902_170902-0c828552.pth ================================================ FILE: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-220kiters_aerial2maps.py ================================================ _base_ = [ '../_base_/models/base_pix2pix.py', '../_base_/datasets/paired_imgs_256x256_crop.py', '../_base_/gen_default_runtime.py' ] # deterministic training can improve the performance of Pix2Pix randomness = dict(deterministic=True) source_domain = domain_a = 'aerial' target_domain = domain_b = 'map' # model settings model = dict( default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain], data_preprocessor=dict( data_keys=[f'img_{source_domain}', f'img_{target_domain}'])) train_cfg = dict(max_iters=220000) # dataset settings dataroot = 'data/pix2pix/maps' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot, test_dir='val')) val_dataloader = dict( dataset=dict(data_root=dataroot, test_dir='val', test_mode=True)) test_dataloader = val_dataloader # optimizer optim_wrapper = dict( generators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999))), discriminators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] # save multi best checkpoints default_hooks = dict(checkpoint=dict(save_best='FID-Full/fid', rule='less')) fake_nums = 1098 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=fake_nums, fake_key=f'fake_{target_domain}', inception_style='PyTorch', sample_model='orig'), dict( type='TransFID', prefix='FID-Full', fake_nums=fake_nums, inception_style='PyTorch', real_key=f'img_{target_domain}', fake_key=f'fake_{target_domain}', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-220kiters_maps2aerial.py ================================================ _base_ = [ '../_base_/models/base_pix2pix.py', '../_base_/datasets/paired_imgs_256x256_crop.py', '../_base_/gen_default_runtime.py' ] # deterministic training can improve the performance of Pix2Pix randomness = dict(deterministic=True) source_domain = domain_b = 'map' target_domain = domain_a = 'aerial' # model settings model = dict( default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain], data_preprocessor=dict( data_keys=[f'img_{source_domain}', f'img_{target_domain}'])) train_cfg = dict(max_iters=220000) # dataset settings dataroot = 'data/pix2pix/maps' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot, test_dir='val')) val_dataloader = dict( dataset=dict(data_root=dataroot, test_dir='val', test_mode=True)) test_dataloader = val_dataloader # optimizer optim_wrapper = dict( generators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999))), discriminators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] # save multi best checkpoints default_hooks = dict(checkpoint=dict(save_best='FID-Full/fid', rule='less')) fake_nums = 1098 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=fake_nums, fake_key=f'fake_{target_domain}', inception_style='PyTorch', sample_model='orig'), dict( type='TransFID', prefix='FID-Full', fake_nums=fake_nums, inception_style='PyTorch', real_key=f'img_{target_domain}', fake_key=f'fake_{target_domain}', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/pix2pix/pix2pix_vanilla-unet-bn_1xb1-80kiters_facades.py ================================================ _base_ = [ '../_base_/models/base_pix2pix.py', '../_base_/datasets/paired_imgs_256x256_crop.py', '../_base_/gen_default_runtime.py' ] # deterministic training can improve the performance of Pix2Pix randomness = dict(deterministic=True) source_domain = domain_b = 'mask' target_domain = domain_a = 'photo' # model settings model = dict( default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain], data_preprocessor=dict(data_keys=[f'img_{domain_a}', f'img_{domain_b}'])) train_cfg = dict(max_iters=80000) # dataset settings dataroot = 'data/pix2pix/facades' train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict(dataset=dict(data_root=dataroot)) val_dataloader = dict(dataset=dict(data_root=dataroot, test_mode=True)) test_dataloader = val_dataloader # optimizer optim_wrapper = dict( generators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999))), discriminators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] # save multi best checkpoints default_hooks = dict(checkpoint=dict(save_best='FID-Full/fid', rule='less')) fake_nums = 106 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=fake_nums, inception_style='PyTorch', fake_key=f'fake_{target_domain}', sample_model='orig'), dict( type='TransFID', prefix='FID-Full', fake_nums=fake_nums, inception_style='PyTorch', real_key=f'img_{target_domain}', fake_key=f'fake_{target_domain}', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/pix2pix/pix2pix_vanilla-unet-bn_wo-jitter-flip-1xb4-190kiters_edges2shoes.py ================================================ _base_ = [ '../_base_/models/base_pix2pix.py', '../_base_/datasets/paired_imgs_256x256_crop.py', '../_base_/gen_default_runtime.py', ] # deterministic training can improve the performance of Pix2Pix randomness = dict(deterministic=True) source_domain = domain_a = 'edges' target_domain = domain_b = 'photo' # model settings model = dict( default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain], data_preprocessor=dict( data_keys=[f'img_{source_domain}', f'img_{target_domain}'])) train_cfg = dict(max_iters=190000) # dataset settings dataroot = './data/pix2pix/edges2shoes' # overwrite train pipeline since we do not use flip and crop _base_.train_dataloader.dataset.pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='A', domain_b='B', color_type='color'), dict( type='Resize', keys=['img_A', 'img_B'], scale=(256, 256), interpolation='bicubic'), ] train_pipeline = _base_.train_dataloader.dataset.pipeline val_pipeline = _base_.val_dataloader.dataset.pipeline test_pipeline = _base_.test_dataloader.dataset.pipeline key_mapping = dict( type='KeyMapper', mapping={ f'img_{domain_a}': 'img_A', f'img_{domain_b}': 'img_B' }, remapping={ f'img_{domain_a}': f'img_{domain_a}', f'img_{domain_b}': f'img_{domain_b}' }) pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) train_pipeline += [key_mapping, pack_input] val_pipeline += [key_mapping, pack_input] test_pipeline += [key_mapping, pack_input] train_dataloader = dict( batch_size=4, dataset=dict(data_root=dataroot, test_dir='val')) val_dataloader = dict( dataset=dict(data_root=dataroot, test_dir='val', test_mode=True)) test_dataloader = val_dataloader # optimizer optim_wrapper = dict( generators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999))), discriminators=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)))) custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict(type='Translation', name='trans'), dict(type='TranslationVal', name='trans_val') ]) ] # save multi best checkpoints default_hooks = dict(checkpoint=dict(save_best='FID-Full/fid', rule='less')) fake_nums = 200 metrics = [ dict( type='TransIS', prefix='IS-Full', fake_nums=fake_nums, fake_key=f'fake_{target_domain}', inception_style='PyTorch', sample_model='orig'), dict( type='TransFID', prefix='FID-Full', fake_nums=fake_nums, inception_style='PyTorch', real_key=f'img_{target_domain}', fake_key=f'fake_{target_domain}', sample_model='orig') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/README.md ================================================ # Positional Encoding in GANs (CVPR'2021) > [Positional Encoding as Spatial Inductive Bias in GANs](https://openaccess.thecvf.com/content/CVPR2021/html/Xu_Positional_Encoding_As_Spatial_Inductive_Bias_in_GANs_CVPR_2021_paper.html) > **Task**: Unconditional GANs ## Abstract SinGAN shows impressive capability in learning internal patch distribution despite its limited effective receptive field. We are interested in knowing how such a translation-invariant convolutional generator could capture the global structure with just a spatially i.i.d. input. In this work, taking SinGAN and StyleGAN2 as examples, we show that such capability, to a large extent, is brought by the implicit positional encoding when using zero padding in the generators. Such positional encoding is indispensable for generating images with high fidelity. The same phenomenon is observed in other generative architectures such as DCGAN and PGGAN. We further show that zero padding leads to an unbalanced spatial bias with a vague relation between locations. To offer a better spatial inductive bias, we investigate alternative positional encodings and analyze their effects. Based on a more flexible positional encoding explicitly, we propose a new multi-scale training strategy and demonstrate its effectiveness in the state-of-the-art unconditional generator StyleGAN2. Besides, the explicit spatial inductive bias substantially improve SinGAN for more versatile image manipulation.
## Results and models for MS-PIE
896x896 results generated from a 256 generator using MS-PIE
| Model | Dataset | Reference in Paper | Scales | FID50k | P&R10k | Download | | :--------------------------------------------------------------------: | :-----: | :----------------: | :------------: | :----: | :---------: | :------------------------------------------------------------------------: | | [stylegan2_c2_8xb3-1100kiters_ffhq-256x256](./stylegan2_c2_8xb3-1100kiters_ffhq-256x256.py) | FFHQ | Tab.5 config-a | 256 | 5.56 | 75.92/51.24 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-a_ffhq_256x256_b3x8_1100k_20210406_145127-71d9634b.pth) | | [stylegan2_c2_8xb3-1100kiters_ffhq-512x512](./stylegan2_c2_8xb3-1100kiters_ffhq-512x512.py) | FFHQ | Tab.5 config-b | 512 | 4.91 | 75.65/54.58 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-b_ffhq_512x512_b3x8_1100k_20210406_145142-e85e5cf4.pth) | | [mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-c | 256, 384, 512 | 3.35 | 73.84/55.77 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-c_ffhq_256-512_b3x8_1100k_20210406_144824-9f43b07d.pth) | | [mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-d | 256, 384, 512 | 3.50 | 73.28/56.16 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-d_ffhq_256-512_b3x8_1100k_20210406_144840-dbefacf6.pth) | | [mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-e | 256, 384, 512 | 3.15 | 74.13/56.88 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-e_ffhq_256-512_b3x8_1100k_20210406_144906-98d5a42a.pth) | | [mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-f | 256, 384, 512 | 2.93 | 73.51/57.32 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-512_b3x8_1100k_20210406_144927-4f4d5391.pth) | | [mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-g | 256, 384, 512 | 3.40 | 73.05/56.45 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-g_ffhq_256-512_b3x8_1100k_20210406_144758-2df61752.pth) | | [mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-h | 256, 384, 512 | 4.01 | 72.81/54.35 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-h_ffhq_256-512_b3x8_1100k_20210406_145006-84cf3f48.pth) | | [mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | 2 Tab.5 config-i | 56, 384, 512 | 3.76 | 73.26/54.71 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-i_ffhq_256-512_b3x8_1100k_20210406_145023-c2b0accf.pth) | | [mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-j | 256, 384, 512 | 4.23 | 73.11/54.63 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-j_ffhq_256-512_b3x8_1100k_20210406_145044-c407481b.pth) | | [mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-k | 256, 384, 512 | 4.17 | 73.05/51.07 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-k_ffhq_256-512_b3x8_1100k_20210406_145105-6d8cc39f.pth) | | [mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896](./mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896.py) | FFHQ | higher-resolution | 256, 512, 896 | 4.10 | 72.21/50.29 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-896_b3x8_1100k_20210406_144943-6c18ad5d.pth) | | [mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024](./mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024.py) | FFHQ | higher-resolution | 256, 512, 1024 | 6.24 | 71.79/49.92 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-f_ffhq_256-1024_b2x8_1600k_20210406_144716-81cbdc96.pth) | | Model | Dataset | Reference in Paper | Scales | FID50k | Precision10k | Recall10k | Download | | :---------------------------------------------------------------: | :-----: | :----------------: | :------------: | :----: | :----------: | :-------: | :-------------------------------------------------------------------: | | [stylegan2_c2_8xb3-1100kiters_ffhq-256x256](./stylegan2_c2_8xb3-1100kiters_ffhq-256x256.py) | FFHQ | Tab.5 config-a | 256 | 5.56 | 75.92 | 51.24 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-a_ffhq_256x256_b3x8_1100k_20210406_145127-71d9634b.pth) | | [stylegan2_c2_8xb3-1100kiters_ffhq-512x512](./stylegan2_c2_8xb3-1100kiters_ffhq-512x512.py) | FFHQ | Tab.5 config-b | 512 | 4.91 | 75.65 | 54.58 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-b_ffhq_512x512_b3x8_1100k_20210406_145142-e85e5cf4.pth) | | [mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-c | 256, 384, 512 | 3.35 | 73.84 | 55.77 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-c_ffhq_256-512_b3x8_1100k_20210406_144824-9f43b07d.pth) | | [mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-d | 256, 384, 512 | 3.50 | 73.28 | 56.16 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-d_ffhq_256-512_b3x8_1100k_20210406_144840-dbefacf6.pth) | | [mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-e | 256, 384, 512 | 3.15 | 74.13 | 56.88 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-e_ffhq_256-512_b3x8_1100k_20210406_144906-98d5a42a.pth) | | [mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-f | 256, 384, 512 | 2.93 | 73.51 | 57.32 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-512_b3x8_1100k_20210406_144927-4f4d5391.pth) | | [mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-g | 256, 384, 512 | 3.40 | 73.05 | 56.45 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-g_ffhq_256-512_b3x8_1100k_20210406_144758-2df61752.pth) | | [mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-h | 256, 384, 512 | 4.01 | 72.81 | 54.35 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-h_ffhq_256-512_b3x8_1100k_20210406_145006-84cf3f48.pth) | | [mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-i | 256, 384, 512 | 3.76 | 73.26 | 54.71 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-i_ffhq_256-512_b3x8_1100k_20210406_145023-c2b0accf.pth) | | [mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-j | 256, 384, 512 | 4.23 | 73.11 | 54.63 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-j_ffhq_256-512_b3x8_1100k_20210406_145044-c407481b.pth) | | [mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512](./mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512.py) | FFHQ | Tab.5 config-k | 256, 384, 512 | 4.17 | 73.05 | 51.07 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-k_ffhq_256-512_b3x8_1100k_20210406_145105-6d8cc39f.pth) | | [mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896](./mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896.py) | FFHQ | higher-resolution | 256, 512, 896 | 4.10 | 72.21 | 50.29 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-896_b3x8_1100k_20210406_144943-6c18ad5d.pth) | | [mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024](./mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024.py) | FFHQ | higher-resolution | 256, 512, 1024 | 6.24 | 71.79 | 49.92 | [model](https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-f_ffhq_256-1024_b2x8_1600k_20210406_144716-81cbdc96.pth) | Note that we report the FID and P&R metric (FFHQ dataset) in the largest scale. ## Results and Models for SinGAN
Positional Encoding in SinGAN
| Model | Dataset | Num Scales | Download | | :-----------------------------------------------------------: | :--------------------------------------------------------------: | :--------: | :---------------------------------------------------------------: | | [singan_interp-pad_balloons](./singan_interp-pad_balloons.py) | [balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png) | 8 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_balloons_20210406_180014-96f51555.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_balloons_20210406_180014-96f51555.pkl) | | [singan_interp-pad_disc-nobn_balloons](./singan_interp-pad_disc-nobn_balloons.py) | [balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png) | 8 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_balloons_20210406_180059-7d63e65d.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_balloons_20210406_180059-7d63e65d.pkl) | | [singan_interp-pad_disc-nobn_fish](./singan_interp-pad_disc-nobn_fish.py) | [fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_fis_20210406_175720-9428517a.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_fis_20210406_175720-9428517a.pkl) | | [singan-csg_fish](./singan-csg_fish.py) | [fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_fis_20210406_175532-f0ec7b61.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_fis_20210406_175532-f0ec7b61.pkl) | | [singan-csg_bohemian](./singan-csg_bohemian.py) | [bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_bohemian_20210407_195455-5ed56db2.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_bohemian_20210407_195455-5ed56db2.pkl) | | [singan_spe-dim4_fish](./singan_spe-dim4_fish.py) | [fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_fish_20210406_175933-f483a7e3.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_fish_20210406_175933-f483a7e3.pkl) | | [singan_spe-dim4_bohemian](./singan_spe-dim4_bohemian.py) | [bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_bohemian_20210406_175820-6e484a35.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_bohemian_20210406_175820-6e484a35.pkl) | | [singan_spe-dim8_bohemian](./singan_spe-dim8_bohemian.py) | [bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png) | 10 | [ckpt](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim8_bohemian_20210406_175858-7faa50f3.pth) \| [pkl](https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim8_bohemian_20210406_175858-7faa50f3.pkl) | ## Citation ```latex @article{xu2020positional, title={Positional Encoding as Spatial Inductive Bias in GANs}, author={Xu, Rui and Wang, Xintao and Chen, Kai and Zhou, Bolei and Loy, Chen Change}, journal={arXiv preprint arXiv:2012.05217}, year={2020}, url={https://openaccess.thecvf.com/content/CVPR2021/html/Xu_Positional_Encoding_As_Spatial_Inductive_Bias_in_GANs_CVPR_2021_paper.html}, } ``` ================================================ FILE: configs/positional_encoding_in_gans/metafile.yml ================================================ Collections: - Name: Positional Encoding in GANs Paper: Title: Positional Encoding as Spatial Inductive Bias in GANs URL: https://openaccess.thecvf.com/content/CVPR2021/html/Xu_Positional_Encoding_As_Spatial_Inductive_Bias_in_GANs_CVPR_2021_paper.html README: configs/positional_encoding_in_gans/README.md Task: - unconditional gans Year: 2021 Models: - Config: configs/positional_encoding_in_gans/stylegan2_c2_8xb3-1100kiters_ffhq-256x256.py In Collection: Positional Encoding in GANs Name: stylegan2_c2_8xb3-1100kiters_ffhq-256x256 Results: - Dataset: FFHQ Metrics: FID50k: 5.56 P&R10k: PSNR: 75.92 SSIM: 51.24 Scales: 256.0 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 5.56 Precision10k: 75.92 Recall10k: 51.24 Scales: 256.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-a_ffhq_256x256_b3x8_1100k_20210406_145127-71d9634b.pth - Config: configs/positional_encoding_in_gans/stylegan2_c2_8xb3-1100kiters_ffhq-512x512.py In Collection: Positional Encoding in GANs Name: stylegan2_c2_8xb3-1100kiters_ffhq-512x512 Results: - Dataset: FFHQ Metrics: FID50k: 4.91 P&R10k: PSNR: 75.65 SSIM: 54.58 Scales: 512.0 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 4.91 Precision10k: 75.65 Recall10k: 54.58 Scales: 512.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/stylegan2_c2_config-b_ffhq_512x512_b3x8_1100k_20210406_145142-e85e5cf4.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 3.35 P&R10k: PSNR: 73.84 SSIM: 55.77 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 3.35 Precision10k: 73.84 Recall10k: 55.77 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-c_ffhq_256-512_b3x8_1100k_20210406_144824-9f43b07d.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 3.5 P&R10k: PSNR: 73.28 SSIM: 56.16 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 3.5 Precision10k: 73.28 Recall10k: 56.16 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-d_ffhq_256-512_b3x8_1100k_20210406_144840-dbefacf6.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 3.15 P&R10k: PSNR: 74.13 SSIM: 56.88 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 3.15 Precision10k: 74.13 Recall10k: 56.88 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-e_ffhq_256-512_b3x8_1100k_20210406_144906-98d5a42a.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 2.93 P&R10k: PSNR: 73.51 SSIM: 57.32 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 2.93 Precision10k: 73.51 Recall10k: 57.32 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-512_b3x8_1100k_20210406_144927-4f4d5391.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 3.4 P&R10k: PSNR: 73.05 SSIM: 56.45 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 3.4 Precision10k: 73.05 Recall10k: 56.45 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-g_ffhq_256-512_b3x8_1100k_20210406_144758-2df61752.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 4.01 P&R10k: PSNR: 72.81 SSIM: 54.35 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 4.01 Precision10k: 72.81 Recall10k: 54.35 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-h_ffhq_256-512_b3x8_1100k_20210406_145006-84cf3f48.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 3.76 P&R10k: PSNR: 73.26 SSIM: 54.71 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 3.76 Precision10k: 73.26 Recall10k: 54.71 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-i_ffhq_256-512_b3x8_1100k_20210406_145023-c2b0accf.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 4.23 P&R10k: PSNR: 73.11 SSIM: 54.63 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 4.23 Precision10k: 73.11 Recall10k: 54.63 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-j_ffhq_256-512_b3x8_1100k_20210406_145044-c407481b.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512 Results: - Dataset: FFHQ Metrics: FID50k: 4.17 P&R10k: PSNR: 73.05 SSIM: 51.07 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 4.17 Precision10k: 73.05 Recall10k: 51.07 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-k_ffhq_256-512_b3x8_1100k_20210406_145105-6d8cc39f.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896 Results: - Dataset: FFHQ Metrics: FID50k: 4.1 P&R10k: PSNR: 72.21 SSIM: 50.29 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 4.1 Precision10k: 72.21 Recall10k: 50.29 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c2_config-f_ffhq_256-896_b3x8_1100k_20210406_144943-6c18ad5d.pth - Config: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024.py In Collection: Positional Encoding in GANs Name: mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024 Results: - Dataset: FFHQ Metrics: FID50k: 6.24 P&R10k: PSNR: 71.79 SSIM: 49.92 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 6.24 Precision10k: 71.79 Recall10k: 49.92 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/mspie-stylegan2_c1_config-f_ffhq_256-1024_b2x8_1600k_20210406_144716-81cbdc96.pth - Config: configs/positional_encoding_in_gans/singan_interp-pad_balloons.py In Collection: Positional Encoding in GANs Name: singan_interp-pad_balloons Results: - Dataset: '[balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png)' Metrics: Num Scales: 8.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_balloons_20210406_180014-96f51555.pth - Config: configs/positional_encoding_in_gans/singan_interp-pad_disc-nobn_balloons.py In Collection: Positional Encoding in GANs Name: singan_interp-pad_disc-nobn_balloons Results: - Dataset: '[balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png)' Metrics: Num Scales: 8.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_balloons_20210406_180059-7d63e65d.pth - Config: configs/positional_encoding_in_gans/singan_interp-pad_disc-nobn_fish.py In Collection: Positional Encoding in GANs Name: singan_interp-pad_disc-nobn_fish Results: - Dataset: '[fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_interp-pad_disc-nobn_fis_20210406_175720-9428517a.pth - Config: configs/positional_encoding_in_gans/singan-csg_fish.py In Collection: Positional Encoding in GANs Name: singan-csg_fish Results: - Dataset: '[fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_fis_20210406_175532-f0ec7b61.pth - Config: configs/positional_encoding_in_gans/singan-csg_bohemian.py In Collection: Positional Encoding in GANs Name: singan-csg_bohemian Results: - Dataset: '[bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_csg_bohemian_20210407_195455-5ed56db2.pth - Config: configs/positional_encoding_in_gans/singan_spe-dim4_fish.py In Collection: Positional Encoding in GANs Name: singan_spe-dim4_fish Results: - Dataset: '[fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_fish_20210406_175933-f483a7e3.pth - Config: configs/positional_encoding_in_gans/singan_spe-dim4_bohemian.py In Collection: Positional Encoding in GANs Name: singan_spe-dim4_bohemian Results: - Dataset: '[bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim4_bohemian_20210406_175820-6e484a35.pth - Config: configs/positional_encoding_in_gans/singan_spe-dim8_bohemian.py In Collection: Positional Encoding in GANs Name: singan_spe-dim8_bohemian Results: - Dataset: '[bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png)' Metrics: Num Scales: 10.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/pe_in_gans/singan_spe-dim8_bohemian_20210406_175858-7faa50f3.pth ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-c_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=None, deconv2conv=True, up_after_conv=True, head_pos_size=(4, 4), interp_head=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25]), ema_config=ema_config) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-d_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict(type='CSG'), deconv2conv=True, up_after_conv=True, head_pos_size=(4, 4), up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25]), ema_config=ema_config) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-e_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=True, head_pos_size=(4, 4), interp_head=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c1_8xb2-1600kiters_ffhq-256-1024.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] train_cfg = dict(max_iters=1500002) # `batch_size` and `imgs_root` need to be set. batch_size = 2 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256, channel_multiplier=1), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), train_settings=dict( num_upblocks=6, multi_input_scales=[0, 4, 12], multi_scale_probability=[0.5, 0.25, 0.25]), ema_config=ema_config) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-f_c2_8xb3-1100kiters_ffhq-256-896.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 4, 10], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-g_c1_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256, channel_multiplier=1), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True, channel_multiplier=1), train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25]), ema_config=ema_config) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-h_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=None, deconv2conv=True, up_after_conv=False, interp_pad=4, no_pad=True, head_pos_size=(6, 6), interp_head=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-i_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict(type='CSG'), deconv2conv=True, up_after_conv=False, interp_pad=4, no_pad=True, head_pos_size=(6, 6), up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-j_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=False, interp_pad=4, no_pad=True, head_pos_size=(6, 6), interp_head=True, up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/mspie-stylegan2-config-k_c2_8xb3-1100kiters_ffhq-256-512.py ================================================ _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] ema_half_life = 10. ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( type='MSPIEStyleGAN2', generator=dict( type='MSStyleGANv2Generator', head_pos_encoding=dict( type='SPE', embedding_dim=256, padding_idx=0, init_size=256, center_shift=100), deconv2conv=True, up_after_conv=False, interp_pad=4, no_pad=True, head_pos_size=(6, 6), up_config=dict(scale_factor=2, mode='bilinear', align_corners=True), out_size=256), discriminator=dict( type='MSStyleGAN2Discriminator', in_size=256, with_adaptive_pool=True), ema_config=ema_config, train_settings=dict( num_upblocks=6, multi_input_scales=[0, 2, 4], multi_scale_probability=[0.5, 0.25, 0.25])) train_cfg = dict(max_iters=1100002) # `batch_size` and `data_root` need to be set. batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root)) pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(256, 256)), dict(type='PackInputs', keys=['img']) ] val_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) test_dataloader = dict( batch_size=batch_size, # set by user dataset=dict(data_root=data_root, pipeline=pipeline)) # define optimizer d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] default_hooks = dict(checkpoint=dict(save_best=['FID-50k/fid'], rule=['less'])) # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='pytorch', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/singan-csg_bohemian.py ================================================ _base_ = ['../singan/singan_bohemian.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_csg_bohemian_20210407_195455-5ed56db2.pkl' # noqa test_pkl_data = None num_scales = 10 # start from zero model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', num_scales=num_scales, padding=1, pad_at_head=False, first_stage_in_channels=2, positional_encoding=dict(type='CSG')), discriminator=dict(num_scales=num_scales), first_fixed_noises_ch=2, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan-csg_fish.py ================================================ _base_ = ['../singan/singan_fish.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_csg_fis_20210406_175532-f0ec7b61.pkl' # noqa test_pkl_data = None num_scales = 10 # start from zero model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', num_scales=num_scales, padding=1, pad_at_head=False, first_stage_in_channels=2, positional_encoding=dict(type='CSG')), discriminator=dict(num_scales=num_scales), first_fixed_noises_ch=2, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan_interp-pad_balloons.py ================================================ _base_ = ['../singan/singan_balloons.py'] # TODO: bugs here # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_interp-pad_balloons_20210406_180014-96f51555.pkl' # noqa test_pkl_data = None model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', interp_pad=True, noise_with_pad=True), fixed_noise_with_pad=True, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan_interp-pad_disc-nobn_balloons.py ================================================ _base_ = ['../singan/singan_balloons.py'] # TODO: have bugs # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_interp-pad_disc-nobn_balloons_20210406_180059-7d63e65d.pkl' # noqa test_pkl_data = None model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', interp_pad=True, noise_with_pad=True), discriminator=dict(norm_cfg=None), fixed_noise_with_pad=True) ================================================ FILE: configs/positional_encoding_in_gans/singan_interp-pad_disc-nobn_fish.py ================================================ _base_ = ['../singan/singan_fish.py'] # TODO: have bugs # MODEL # test_pkl_data = './work_dirs/singan_pkl/singan_interp-pad_disc-nobn_fis_20210406_175720-9428517a.pkl' # noqa test_pkl_data = None model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', interp_pad=True, noise_with_pad=True), discriminator=dict(norm_cfg=None), fixed_noise_with_pad=True, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan_spe-dim4_bohemian.py ================================================ _base_ = ['../singan/singan_bohemian.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_spe-dim4_bohemian_20210406_175820-6e484a35.pkl' # noqa test_pkl_data = None embedding_dim = 4 num_scales = 10 # start from zero model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', num_scales=num_scales, padding=1, pad_at_head=False, first_stage_in_channels=embedding_dim * 2, positional_encoding=dict( type='SPE', embedding_dim=embedding_dim, padding_idx=0, init_size=512, div_half_dim=False, center_shift=200)), discriminator=dict(num_scales=num_scales), first_fixed_noises_ch=embedding_dim * 2, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan_spe-dim4_fish.py ================================================ _base_ = ['../singan/singan_fish.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_spe-dim4_fish_20210406_175933-f483a7e3.pkl' # noqa test_pkl_data = None embedding_dim = 4 num_scales = 10 # start from zero model = dict( type='PESinGAN', num_scales=num_scales, generator=dict( type='SinGANMSGeneratorPE', num_scales=num_scales, padding=1, pad_at_head=False, first_stage_in_channels=embedding_dim * 2, positional_encoding=dict( type='SPE', embedding_dim=embedding_dim, padding_idx=0, init_size=512, div_half_dim=False, center_shift=200)), discriminator=dict(num_scales=num_scales), test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/singan_spe-dim8_bohemian.py ================================================ _base_ = ['../singan/singan_bohemian.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_spe-dim8_bohemian_20210406_175858-7faa50f3.pkl' # noqa test_pkl_data = None embedding_dim = 8 num_scales = 10 # start from zero model = dict( type='PESinGAN', generator=dict( type='SinGANMSGeneratorPE', num_scales=num_scales, padding=1, pad_at_head=False, first_stage_in_channels=embedding_dim * 2, positional_encoding=dict( type='SPE', embedding_dim=embedding_dim, padding_idx=0, init_size=512, div_half_dim=False, center_shift=200)), discriminator=dict(num_scales=num_scales), first_fixed_noises_ch=embedding_dim * 2, test_pkl_data=test_pkl_data) ================================================ FILE: configs/positional_encoding_in_gans/stylegan2_c2_8xb3-1100kiters_ffhq-256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.))))) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_256' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=1100002) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/positional_encoding_in_gans/stylegan2_c2_8xb3-1100kiters_ffhq-512x512.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=512), discriminator=dict(in_size=512), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.))))) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 3 data_root = './data/ffhq/ffhq_imgs/ffhq_512' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=1100002) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=10000, prefix='PR-10K') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/rdn/README.md ================================================ # RDN (CVPR'2018) > [Residual Dense Network for Image Super-Resolution](https://arxiv.org/abs/1802.08797) > **Task**: Image Super-Resolution ## Abstract A very deep convolutional neural network (CNN) has recently achieved great success for image super-resolution (SR) and offered hierarchical features as well. However, most deep CNN based SR models do not make full use of the hierarchical features from the original low-resolution (LR) images, thereby achieving relatively-low performance. In this paper, we propose a novel residual dense network (RDN) to address this problem in image SR. We fully exploit the hierarchical features from all the convolutional layers. Specifically, we propose residual dense block (RDB) to extract abundant local features via dense connected convolutional layers. RDB further allows direct connections from the state of preceding RDB to all the layers of current RDB, leading to a contiguous memory (CM) mechanism. Local feature fusion in RDB is then used to adaptively learn more effective features from preceding and current local features and stabilizes the training of wider network. After fully obtaining dense local features, we use global feature fusion to jointly and adaptively learn global hierarchical features in a holistic way. Extensive experiments on benchmark datasets with different degradation models show that our RDN achieves favorable performance against state-of-the-art methods.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR and SSIM` . | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :----------------------------------------------------------------: | :-----: | :-----: | :----: | :----------------: | :----------------------------------------------------------------------------------------------: | | [rdn_x4c64b16_g1_1000k_div2k](./rdn_x4c64b16_1xb16-1000k_div2k.py) | Set5 | 30.4922 | 0.8548 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.log.json) | | [rdn_x4c64b16_g1_1000k_div2k](./rdn_x4c64b16_1xb16-1000k_div2k.py) | Set14 | 26.9570 | 0.7423 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.log.json) | | [rdn_x4c64b16_g1_1000k_div2k](./rdn_x4c64b16_1xb16-1000k_div2k.py) | DIV2K | 29.1925 | 0.8233 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.log.json) | | [rdn_x3c64b16_g1_1000k_div2k](./rdn_x3c64b16_1xb16-1000k_div2k.py) | Set5 | 32.6051 | 0.8943 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.log.json) | | [rdn_x3c64b16_g1_1000k_div2k](./rdn_x3c64b16_1xb16-1000k_div2k.py) | Set14 | 28.6338 | 0.8077 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.log.json) | | [rdn_x3c64b16_g1_1000k_div2k](./rdn_x3c64b16_1xb16-1000k_div2k.py) | DIV2K | 31.2153 | 0.8763 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.log.json) | | [rdn_x2c64b16_g1_1000k_div2k](./rdn_x2c64b16_1xb16-1000k_div2k.py) | Set5 | 35.9883 | 0.9385 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.log.json) | | [rdn_x2c64b16_g1_1000k_div2k](./rdn_x2c64b16_1xb16-1000k_div2k.py) | Set14 | 31.8366 | 0.8920 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.log.json) | | [rdn_x2c64b16_g1_1000k_div2k](./rdn_x2c64b16_1xb16-1000k_div2k.py) | DIV2K | 34.9392 | 0.9380 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py # single-gpu train python tools/train.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth # single-gpu test python tools/test.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth # multi-gpu test ./tools/dist_test.sh configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{zhang2018residual, title={Residual dense network for image super-resolution}, author={Zhang, Yulun and Tian, Yapeng and Kong, Yu and Zhong, Bineng and Fu, Yun}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2472--2481}, year={2018} } ``` ================================================ FILE: configs/rdn/README_zh-CN.md ================================================ # RDN (CVPR'2018) > **任务**: 图像超分辨率
RDN (CVPR'2018) ```bibtex @inproceedings{zhang2018residual, title={Residual dense network for image super-resolution}, author={Zhang, Yulun and Tian, Yapeng and Kong, Yu and Zhong, Bineng and Fu, Yun}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2472--2481}, year={2018} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 | Set14 | DIV2K | GPU 信息 | 下载 | | :----------------------------------------------------------------: | :--------------: | :--------------: | :--------------: | :----------: | :------------------------------------------------------------------------: | | [rdn_x2c64b16_g1_1000k_div2k](./rdn_x2c64b16_1xb16-1000k_div2k.py) | 35.9883 / 0.9385 | 31.8366 / 0.8920 | 34.9392 / 0.9380 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.log.json) | | [rdn_x3c64b16_g1_1000k_div2k](./rdn_x3c64b16_1xb16-1000k_div2k.py) | 32.6051 / 0.8943 | 28.6338 / 0.8077 | 31.2153 / 0.8763 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.log.json) | | [rdn_x4c64b16_g1_1000k_div2k](./rdn_x4c64b16_1xb16-1000k_div2k.py) | 30.4922 / 0.8548 | 26.9570 / 0.7423 | 29.1925 / 0.8233 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py # 单个GPU上训练 python tools/train.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth # 单个GPU上测试 python tools/test.py configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth # 多个GPU上测试 ./tools/dist_test.sh configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/rdn/metafile.yml ================================================ Collections: - Name: RDN Paper: Title: Residual Dense Network for Image Super-Resolution URL: https://arxiv.org/abs/1802.08797 README: configs/rdn/README.md Task: - image super-resolution Year: 2018 Models: - Config: configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py In Collection: RDN Name: rdn_x4c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 30.4922 SSIM: 0.8548 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 26.957 SSIM: 0.7423 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 29.1925 SSIM: 0.8233 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x4c64b16_g1_1000k_div2k_20210419-3577d44f.pth - Config: configs/rdn/rdn_x3c64b16_1xb16-1000k_div2k.py In Collection: RDN Name: rdn_x3c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 32.6051 SSIM: 0.8943 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 28.6338 SSIM: 0.8077 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 31.2153 SSIM: 0.8763 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x3c64b16_g1_1000k_div2k_20210419-b93cb6aa.pth - Config: configs/rdn/rdn_x2c64b16_1xb16-1000k_div2k.py In Collection: RDN Name: rdn_x2c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 35.9883 SSIM: 0.9385 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 31.8366 SSIM: 0.892 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.9392 SSIM: 0.938 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/rdn/rdn_x2c64b16_g1_1000k_div2k_20210419-dc146009.pth ================================================ FILE: configs/rdn/rdn_x2c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x2_test_config.py' ] experiment_name = 'rdn_x2c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 # model settings model = dict( type='BaseEditModel', generator=dict( type='RDNNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=64), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1000000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000, 400000, 600000, 800000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/rdn/rdn_x3c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x3_test_config.py' ] experiment_name = 'rdn_x3c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 3 # model settings model = dict( type='BaseEditModel', generator=dict( type='RDNNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=96), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X3_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1000000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000, 400000, 600000, 800000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/rdn/rdn_x4c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'rdn_x4c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='BaseEditModel', generator=dict( type='RDNNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), # filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1000000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[200000, 400000, 600000, 800000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/real_basicvsr/README.md ================================================ # RealBasicVSR (CVPR'2022) > [RealBasicVSR: Investigating Tradeoffs in Real-World Video Super-Resolution](https://arxiv.org/abs/2111.12704) > **Task**: Video Super-Resolution ## Abstract The diversity and complexity of degradations in real-world video super-resolution (VSR) pose non-trivial challenges in inference and training. First, while long-term propagation leads to improved performance in cases of mild degradations, severe in-the-wild degradations could be exaggerated through propagation, impairing output quality. To balance the tradeoff between detail synthesis and artifact suppression, we found an image pre-cleaning stage indispensable to reduce noises and artifacts prior to propagation. Equipped with a carefully designed cleaning module, our RealBasicVSR outperforms existing methods in both quality and efficiency. Second, real-world VSR models are often trained with diverse degradations to improve generalizability, requiring increased batch size to produce a stable gradient. Inevitably, the increased computational burden results in various problems, including 1) speed-performance tradeoff and 2) batch-length tradeoff. To alleviate the first tradeoff, we propose a stochastic degradation scheme that reduces up to 40% of training time without sacrificing performance. We then analyze different training settings and suggest that employing longer sequences rather than larger batches during training allows more effective uses of temporal information, leading to more stable performance during inference. To facilitate fair comparisons, we propose the new VideoLQ dataset, which contains a large variety of real-world low-quality video sequences containing rich textures and patterns. Our dataset can serve as a common ground for benchmarking. Code, models, and the dataset will be made publicly available.
## Results and models Evaluated on Y channel. The code for computing NRQM, NIQE, and PI can be found [here](https://github.com/roimehrez/PIRM2018). MATLAB official code is used to compute BRISQUE. | Model | Dataset | NRQM (Y) | NIQE (Y) | PI (Y) | BRISQUE (Y) | Training Resources | Download | | :----------------------------------------------------------------: | :-----: | :------: | :------: | :----: | :---------: | :----------------------: | :--------------------------------------------------------------------: | | [realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds](./realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py) | REDS | 6.0477 | 3.7662 | 3.8593 | 29.030 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth)/[log](https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104_183640.log.json) | | [realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds](./realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py) | REDS | - | - | - | - | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027-0e2ff207.pth)/[log](http://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027_114039.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py # single-gpu train python tools/train.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py # multi-gpu train ./tools/dist_train.sh configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth # single-gpu test python tools/test.py python tools/test.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth # multi-gpu test ./tools/dist_test.sh configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{chan2022investigating, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {RealBasicVSR: Investigating Tradeoffs in Real-World Video Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2022} } ``` ================================================ FILE: configs/real_basicvsr/README_zh-CN.md ================================================ # RealBasicVSR (CVPR'2022) > **任务**: 视频超分辨率
RealBasicVSR (CVPR'2022) ```bibtex @InProceedings{chan2022investigating, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {RealBasicVSR: Investigating Tradeoffs in Real-World Video Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2022} } ```

在 Y 通道上评估。 计算 NRQM、NIQE 和 PI 的代码可以在[这里](https://github.com/roimehrez/PIRM2018)找到。我们使用 MATLAB 官方代码计算 BRISQUE。 | 算法 | NRQM (Y) | NIQE (Y) | PI (Y) | BRISQUE (Y) | GPU 信息 | Download | | :------------------------------------------------------------------: | :------: | :------: | :----: | :---------: | :----------------------: | :-------------------------------------------------------------------------: | | [realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds](./realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py) | 6.0477 | 3.7662 | 3.8593 | 29.030 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth)/[log](https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104_183640.log.json) | | [realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds](./realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py) | - | - | - | - | 8 (Tesla V100-SXM2-32GB) | [model](http://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027-0e2ff207.pth)/[log](http://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027_114039.log.json) | ## 训练 训练分为两个阶段: 1. 使用 [realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py](realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py) 训练一个没有感知损失和对抗性损失的模型。 2. 使用感知损失和对抗性损失 [realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py ](realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py) 微调模型。 **注:** 1. 您可能希望将图像裁剪为子图像以加快 IO。请参阅[此处](../../tools/dataset_converters/reds/preprocess_reds_dataset.py)了解更多详情。 ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py # 单个GPU上训练 python tools/train.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py # 多个GPU上训练 ./tools/dist_train.sh configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth # 单个GPU上测试 python tools/test.py configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth # 多个GPU上测试 ./tools/dist_test.sh configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/real_basicvsr/metafile.yml ================================================ Collections: - Name: RealBasicVSR Paper: Title: 'RealBasicVSR: Investigating Tradeoffs in Real-World Video Super-Resolution' URL: https://arxiv.org/abs/2111.12704 README: configs/real_basicvsr/README.md Task: - video super-resolution Year: 2022 Models: - Config: configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py In Collection: RealBasicVSR Name: realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds Results: - Dataset: REDS Metrics: BRISQUE (Y): 29.03 NIQE (Y): 3.7662 NRQM (Y): 6.0477 PI (Y): 3.8593 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds_20211104-52f77c2c.pth - Config: configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py In Collection: RealBasicVSR Name: realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds Results: - Dataset: REDS Metrics: {} Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027-0e2ff207.pth ================================================ FILE: configs/real_basicvsr/realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds.py ================================================ _base_ = './realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py' experiment_name = 'realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # load_from = 'https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027-0e2ff207.pth' # noqa scale = 4 # model settings model = dict( type='RealBasicVSR', generator=dict( type='RealBasicVSRNet', mid_channels=64, num_propagation_blocks=20, num_cleaning_blocks=20, dynamic_refine_thres=255, # change to 5 for test spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', is_fix_cleaning=False, is_sequential_cleaning=False), discriminator=dict( type='UNetDiscriminatorWithSpectralNorm', in_channels=3, mid_channels=64, skip_connection=True), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), cleaning_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-2, real_label_val=1.0, fake_label_val=0), is_use_sharpened_gt_in_pixel=True, is_use_sharpened_gt_in_percep=True, is_use_sharpened_gt_in_gan=False, is_use_ema=True, data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) # optimizer optim_wrapper = dict( _delete_=True, constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=5e-5, betas=(0.9, 0.99))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), ) train_cfg = dict( type='IterBasedTrainLoop', max_iters=150_000, val_interval=5000) ================================================ FILE: configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='RealBasicVSR', generator=dict( type='RealBasicVSRNet', mid_channels=64, num_propagation_blocks=20, num_cleaning_blocks=20, dynamic_refine_thres=255, # change to 1.5 for test spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', is_fix_cleaning=False, is_sequential_cleaning=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), cleaning_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), is_use_sharpened_gt_in_pixel=True, is_use_ema=True, data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='FixedCrop', keys=['gt'], crop_size=(256, 256)), dict(type='Flip', keys=['gt'], flip_ratio=0.5, direction='horizontal'), dict(type='Flip', keys=['gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['gt'], transpose_ratio=0.5), dict(type='MirrorSequence', keys=['gt']), dict( type='UnsharpMasking', keys=['gt'], kernel_size=51, sigma=0, weight=0.5, threshold=10), dict(type='CopyValues', src_keys=['gt_unsharp'], dst_keys=['img']), dict( type='RandomBlur', params=dict( kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 3], sigma_y=[0.2, 3], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2], sigma_x_step=0.02, sigma_y_step=0.02, rotate_angle_step=0.31416, beta_gaussian_step=0.05, beta_plateau_step=0.1, omega_step=0.0628), keys=['img'], ), dict( type='RandomResize', params=dict( resize_mode_prob=[0.2, 0.7, 0.1], # up, down, keep resize_scale=[0.15, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3.0, 1 / 3.0, 1 / 3.0], resize_step=0.015, is_size_even=True), keys=['img'], ), dict( type='RandomNoise', params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 30], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 3], poisson_gray_noise_prob=0.4, gaussian_sigma_step=0.1, poisson_scale_step=0.005), keys=['img'], ), dict( type='RandomJPEGCompression', params=dict(quality=[30, 95], quality_step=3), keys=['img'], ), dict( type='RandomVideoCompression', params=dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5]), keys=['img'], ), dict( type='RandomBlur', params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 1.5], sigma_y=[0.2, 1.5], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2], sigma_x_step=0.02, sigma_y_step=0.02, rotate_angle_step=0.31416, beta_gaussian_step=0.05, beta_plateau_step=0.1, omega_step=0.0628), keys=['img'], ), dict( type='RandomResize', params=dict( resize_mode_prob=[0.3, 0.4, 0.3], # up, down, keep resize_scale=[0.3, 1.2], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], resize_step=0.03, is_size_even=True), keys=['img'], ), dict( type='RandomNoise', params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 25], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 2.5], poisson_gray_noise_prob=0.4, gaussian_sigma_step=0.1, poisson_scale_step=0.005), keys=['img'], ), dict( type='RandomJPEGCompression', params=dict(quality=[30, 95], quality_step=3), keys=['img'], ), dict( type='DegradationsWithShuffle', degradations=[ dict( type='RandomVideoCompression', params=dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5]), keys=['img'], ), [ dict( type='RandomResize', params=dict( target_size=(64, 64), resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), ), dict( type='RandomBlur', params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=['sinc'], kernel_prob=[1], omega=[3.1416 / 3, 3.1416], omega_step=0.0628), ), ] ], keys=['img'], ), dict(type='Clip', keys=['img']), dict(type='PackInputs') ] val_pipeline = [ dict( type='GenerateSegmentIndices', interval_list=[1], filename_tmpl='{:04d}.png'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] test_pipeline = [ dict( type='GenerateSegmentIndices', interval_list=[1], filename_tmpl='{:08d}.png'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data' train_dataloader = dict( num_workers=10, batch_size=2, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='reds', task_name='vsr'), data_root=f'{data_root}/REDS', data_prefix=dict(img='train_sharp_sub', gt='train_sharp_sub'), depth=1, num_input_frames=15, pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='udm10', task_name='vsr'), data_root=f'{data_root}/UDM10', data_prefix=dict(img='BIx4', gt='GT'), pipeline=val_pipeline)) test_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='video_lq', task_name='vsr'), data_root=f'{data_root}/VideoLQ', data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) test_evaluator = dict( type='Evaluator', metrics=[dict(type='NIQE', input_order='CHW', convert_to='Y')]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=300_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)))) # NO learning policy default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, out_dir=save_dir, max_keep_ckpts=10, save_best='PSNR', rule='greater', by_epoch=False), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) custom_hooks = [ dict(type='BasicVisualizationHook', interval=5), dict( type='ExponentialMovingAverageHook', module_keys=('generator_ema'), interval=1, interp_cfg=dict(momentum=0.001), ) ] model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=False) ================================================ FILE: configs/real_esrgan/README.md ================================================ # Real-ESRGAN (ICCVW'2021) > [Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data](https://arxiv.org/abs/2107.10833) > **Task**: Image Super-Resolution ## Abstract Though many attempts have been made in blind super-resolution to restore low-resolution images with unknown and complex degradations, they are still far from addressing general real-world degraded images. In this work, we extend the powerful ESRGAN to a practical restoration application (namely, Real-ESRGAN), which is trained with pure synthetic data. Specifically, a high-order degradation modeling process is introduced to better simulate complex real-world degradations. We also consider the common ringing and overshoot artifacts in the synthesis process. In addition, we employ a U-Net discriminator with spectral normalization to increase discriminator capability and stabilize the training dynamics. Extensive comparisons have shown its superior visual performance than prior works on various real datasets. We also provide efficient implementations to synthesize training pairs on the fly.
## Results and models Evaluated on Set5 dataset with RGB channels. The metrics are `PSNR` and `SSIM`. | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :--------------------------------------------------------------------------: | :------: | :-----: | :----: | :----------------------: | :-----------------------------------------------------------------------------: | | [realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost](./realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py) | df2k_ost | 28.0297 | 0.8236 | 4 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth)/log | | [realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost](./realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py) | df2k_ost | 26.2204 | 0.7655 | 4 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth) /[log](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20210922_142838.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py # single-gpu train python tools/train.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py # multi-gpu train ./tools/dist_train.sh configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth # single-gpu test python tools/test.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth # multi-gpu test ./tools/dist_test.sh configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{wang2021real, title={Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic data}, author={Wang, Xintao and Xie, Liangbin and Dong, Chao and Shan, Ying}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision Workshop (ICCVW)}, pages={1905--1914}, year={2021} } ``` ================================================ FILE: configs/real_esrgan/README_zh-CN.md ================================================ # Real-ESRGAN (ICCVW'2021) > **任务**: 图像超分辨率
Real-ESRGAN (ICCVW'2021) ```bibtex @inproceedings{wang2021real, title={Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic data}, author={Wang, Xintao and Xie, Liangbin and Dong, Chao and Shan, Ying}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision Workshop (ICCVW)}, pages={1905--1914}, year={2021} } ```

在 RGB 通道上进行评估,指标为 `PSNR/SSIM`。 | 算法 | Set5 | GPU 信息 | 下载 | | :-------------------------------------------------------------------------------: | :------------: | :----------------------: | :-------------------------------------------------------------------------------: | | [realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost](./realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py) | 28.0297/0.8236 | 4 (Tesla V100-SXM2-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth)/日志 | | [realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost](./realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py) | 26.2204/0.7655 | 4 (Tesla V100-SXM2-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth) /[日志](https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20210922_142838.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py # 单个GPU上训练 python tools/train.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py # 多个GPU上训练 ./tools/dist_train.sh configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth # 单个GPU上测试 python tools/test.py configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth # 多个GPU上测试 ./tools/dist_test.sh configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/real_esrgan/metafile.yml ================================================ Collections: - Name: Real-ESRGAN Paper: Title: 'Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data' URL: https://arxiv.org/abs/2107.10833 README: configs/real_esrgan/README.md Task: - image super-resolution Year: 2021 Models: - Config: configs/real_esrgan/realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py In Collection: Real-ESRGAN Name: realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost Results: - Dataset: df2k_ost Metrics: PSNR: 28.0297 SSIM: 0.8236 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrnet_c64b23g32_12x4_lr2e-4_1000k_df2k_ost_20210816-4ae3b5a4.pth - Config: configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py In Collection: Real-ESRGAN Name: realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost Results: - Dataset: df2k_ost Metrics: PSNR: 26.2204 SSIM: 0.7655 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/real_esrgan/realesrgan_c64b23g32_12x4_lr1e-4_400k_df2k_ost_20211010-34798885.pth ================================================ FILE: configs/real_esrgan/realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost.py ================================================ _base_ = './realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py' experiment_name = 'realesrgan_c64b23g32_4xb12-lr1e-4-400k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # load_from = # path of pre-trained real-esrnet scale = 4 # model settings model = dict( type='RealESRGAN', generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=23, growth_channels=32, upscale_factor=scale), discriminator=dict( type='UNetDiscriminatorWithSpectralNorm', in_channels=3, mid_channels=64, skip_connection=True), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-1, real_label_val=1.0, fake_label_val=0), is_use_sharpened_gt_in_pixel=True, is_use_sharpened_gt_in_percep=True, is_use_sharpened_gt_in_gan=False, is_use_ema=True, train_cfg=dict(start_iter=1000000), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_cfg = dict( _delete_=True, type='IterBasedTrainLoop', max_iters=400_000, val_interval=5000) # optimizer optim_wrapper = dict( _delete_=True, constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), ) # learning policy param_scheduler = None ================================================ FILE: configs/real_esrgan/realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'realesrnet_c64b23g32_4xb12-lr2e-4-1000k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 gt_crop_size = 400 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings model = dict( type='RealESRGAN', generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=23, growth_channels=32, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), is_use_sharpened_gt_in_pixel=True, is_use_ema=True, train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict( type='Crop', keys=['gt'], crop_size=(gt_crop_size, gt_crop_size), random_crop=True), dict( type='UnsharpMasking', keys=['gt'], kernel_size=51, sigma=0, weight=0.5, threshold=10), dict(type='CopyValues', src_keys=['gt_unsharp'], dst_keys=['img']), dict( type='RandomBlur', params=dict( kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 3], sigma_y=[0.2, 3], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2]), keys=['img'], ), dict( type='RandomResize', params=dict( resize_mode_prob=[0.2, 0.7, 0.1], # up, down, keep resize_scale=[0.15, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3.0, 1 / 3.0, 1 / 3.0]), keys=['img'], ), dict( type='RandomNoise', params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 30], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 3], poisson_gray_noise_prob=0.4), keys=['img'], ), dict( type='RandomJPEGCompression', params=dict(quality=[30, 95]), keys=['img']), dict( type='RandomBlur', params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 1.5], sigma_y=[0.2, 1.5], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2]), keys=['img'], ), dict( type='RandomResize', params=dict( resize_mode_prob=[0.3, 0.4, 0.3], # up, down, keep resize_scale=[0.3, 1.2], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3.0, 1 / 3.0, 1 / 3.0]), keys=['img'], ), dict( type='RandomNoise', params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 25], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 2.5], poisson_gray_noise_prob=0.4), keys=['img'], ), dict( type='DegradationsWithShuffle', degradations=[ dict( type='RandomJPEGCompression', params=dict(quality=[5, 50]), ), [ dict( type='RandomResize', params=dict( target_size=(gt_crop_size // scale, gt_crop_size // scale), resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), ), dict( type='RandomBlur', params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=['sinc'], kernel_prob=[1], omega=[3.1416 / 3, 3.1416]), ), ] ], keys=['img'], ), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PairedRandomCrop', gt_patch_size=256), dict(type='Clip', keys=['img']), dict( type='UnsharpMasking', keys=['gt'], kernel_size=51, sigma=0, weight=0.5, threshold=10), dict(type='PackInputs') ] val_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' train_dataloader = dict( num_workers=12, batch_size=12, # gpus 4 persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='df2k_ost', task_name='real_sr'), data_root='data/df2k_ost', data_prefix=dict(gt='GT_sub', img='GT_sub'), ann_file='meta_info_df2k_ost.txt', pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='real_sr'), data_root='data/Set5', data_prefix=dict(gt='GTmod12', img='LRbicx4'), pipeline=val_pipeline)) test_dataloader = val_dataloader val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=2000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.99)))) # NO learning policy default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) # custom hook vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=False) custom_hooks = [ dict(type='BasicVisualizationHook', interval=1), dict( type='ExponentialMovingAverageHook', module_keys=('generator_ema'), interval=1, interp_cfg=dict(momentum=0.001), ) ] ================================================ FILE: configs/restormer/README.md ================================================ # Restormer (CVPR'2022) > [Restormer: Efficient Transformer for High-Resolution Image Restoration](https://arxiv.org/abs/2111.09881) > **Task**: Denoising, Deblurring, Deraining ## Abstract Since convolutional neural networks (CNNs) perform well at learning generalizable image priors from large-scale data, these models have been extensively applied to image restoration and related tasks. Recently, another class of neural architectures, Transformers, have shown significant performance gains on natural language and high-level vision tasks. While the Transformer model mitigates the shortcomings of CNNs (i.e., limited receptive field and inadaptability to input content), its computational complexity grows quadratically with the spatial resolution, therefore making it infeasible to apply to most image restoration tasks involving high-resolution images. In this work, we propose an efficient Transformer model by making several key designs in the building blocks (multi-head attention and feed-forward network) such that it can capture long-range pixel interactions, while still remaining applicable to large images. Our model, named Restoration Transformer (Restormer), achieves state-of-the-art results on several image restoration tasks, including image deraining, single-image motion deblurring, defocus deblurring (single-image and dual-pixel data), and image denoising (Gaussian grayscale/color denoising, and real image denoising).
## Results and models ### **Deraining** Evaluated on Y channels. The metrics are `PSNR` / `SSIM` . | Model | Dataset | Task | PSNR (Y) | SSIM (Y) | Training Resources | Download | | :-----------------------------------------------------------: | :------: | :-------: | :------: | :------: | :----------------: | :--------------------------------------------------------------------------------------: | | [restormer_official_rain13k](./restormer_official_rain13k.py) | Rain100H | Deraining | 31.4804 | 0.9056 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | | [restormer_official_rain13k](./restormer_official_rain13k.py) | Rain100L | Deraining | 39.1023 | 0.9787 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | | [restormer_official_rain13k](./restormer_official_rain13k.py) | Test100 | Deraining | 32.0287 | 0.9239 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | | [restormer_official_rain13k](./restormer_official_rain13k.py) | Test1200 | Deraining | 33.2251 | /0.9272 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | | [restormer_official_rain13k](./restormer_official_rain13k.py) | Test2800 | Deraining | 34.2170 | 0.9451 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | ### **Motion Deblurring** Evaluated on RGB channels for GoPro and HIDE, and Y channel for ReakBlur-J and ReakBlur-R. The metrics are `PSNR` / `SSIM` . | Model | Dataset | Task | PSNR/SSIM (RGB) |
PSNR/SSIM (Y) | Training Resources | Download | | :-------------------------------------------------------: | :--------: | :--------: | :-------------: | :---------------: | :----------------: | :-----------------------------------------------------------------------: | | [restormer_official_gopro](./restormer_official_gopro.py) | GoPro | Deblurring | 32.9295/0.9496 | - | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth) \| log | | [restormer_official_gopro](./restormer_official_gopro.py) | HIDE | Deblurring | 31.2289/0.9345 | - | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth) \| log | | [restormer_official_gopro](./restormer_official_gopro.py) | RealBlur-J | Deblurring | - | 28.4356/0.8681 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth) \| log | | [restormer_official_gopro](./restormer_official_gopro.py) | RealBlur-R | Deblurring | - | 35.9141/0.9707 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth) \| log | ### **Defocus Deblurring** Evaluated on RGB channels. The metrics are `PSNR` / `SSIM` / `MAE` / `LPIPS`. | Model | Dataset | Task | PSNR | SSIM | MAE | Training Resources | Download | | :------------------------------------------------------------------: | :------------: | :--------: | :-----: | :----: | :----: | :----------------: | :---------------------------------------------------------------------: | | [restormer_official_dpdd-single](./restormer_official_dpdd-single.py) | Indoor Scenes | Deblurring | 28.8681 | 0.8859 | 0.0251 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth) \| log | | [restormer_official_dpdd-single](./restormer_official_dpdd-single.py) | Outdoor Scenes | Deblurring | 23.2410 | 0.7509 | 0.0499 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth) \| log | | [restormer_official_dpdd-single](./restormer_official_dpdd-single.py) | Combined | Deblurring | 25.9805 | 0.8166 | 0.0378 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth) \| log | | [restormer_official_dpdd-dual](./restormer_official_dpdd-dual.py) | Indoor Scenes | Deblurring | 26.6160 | 0.8346 | 0.0354 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth) \| log | | [restormer_official_dpdd-dual](./restormer_official_dpdd-dual.py) | Outdoor Scenes | Deblurring | 26.6160 | 0.8346 | 0.0354 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth) \| log | | [restormer_official_dpdd-dual](./restormer_official_dpdd-dual.py) | Combined | Deblurring | 26.6160 | 0.8346 | 0.0354 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth) \| log | ### **Gaussian Denoising** **Test Grayscale Gaussian Noise** Evaluated on grayscale images. The metrics are `PSNR` / `SSIM` . **training a separate model for each noise level** | Model | Dataset | Task | $\\sigma$ | PSNR | SSIM | Training Resources | Download | | :------------------------------------------------------------------------: | :------:|:-:| | :-------: | :-----: | :----: | :----------------: | :----------------------------------------------------------------------------: | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | Set12 |Denoising| 15 | 34.0182 | 0.9160 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth) | log | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | BSD68 |Denoising| 15 | 32.4987 | 0.8940 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth) | log | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | Urban100 |Denoising| 15 | 34.4336 | 0.9419 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth) | log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | Set12 |Denoising| 25 | 31.7289 | 0.8811 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth) | log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | BSD68 |Denoising| 25 | 30.1613 | 0.8370 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth) | log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | Urban100 |Denoising| 25 | 32.1162 | 0.9140 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth) | log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | Set12 |Denoising| 50 | 28.6269 | 0.8188 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth) | log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | BSD68 |Denoising| 50 | 27.3266 | 0.7434 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth) | log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | Urban100 |Denoising| 50 | 28.9636 | 0.8571 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth) | log | **learning a single model to handle various noise levels** | Model | Dataset | Task | $\\sigma$ | PSNR | SSIM | Training Resources | Download | | :--------------------------------------------------------------------: | :------: | :-------: | :-------: | :-----: | :----: | :----------------: | :-----------------------------------------------------------------------: | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | Set12 | Denoising | 15 | 33.9642 | 0.9153 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | BSD68 | Denoising | 15 | 32.4994 | 0.8928 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | Urban100 | Denoising | 15 | 34.3152 | 0.9409 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | Set12 | Denoising | 25 | 31.7106 | 0.8810 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | BSD68 | Denoising | 25 | 30.1486 | 0.8360 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | Urban100 | Denoising | 25 | 32.0457 | 0.9131 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | Set12 | Denoising | 50 | 28.6614 | 0.8197 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | BSD68 | Denoising | 50 | 27.3537 | 0.7422 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | Urban100 | Denoising | 50 | 28.9848 | 0.8571 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | **Test Color Gaussian Noise** Evaluated on RGB channels. The metrics are `PSNR` / `SSIM` . **training a separate model for each noise level** | Model | Dataset | Task | $\\sigma$ | PSNR (RGB) | SSIM (RGB) | Training Resources | Download | | :----------------------------------------------------------------: | :------: | :-------: | :-------: | :--------: | :--------: | :----------------: | :--------------------------------------------------------------------: | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | CBSD68 | Denoising | 15 | 34.3506 | 0.9352 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth) \| log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | Kodak24 | Denoising | 15 | 35.4900 | 0.9312 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth) \| log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | McMaster | Denoising | 15 | 35.6072 | 0.9352 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth) \| log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | Urban100 | Denoising | 15 | 35.1522 | 0.9530 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | CBSD68 | Denoising | 25 | 31.7457 | 0.8942 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | Kodak24 | Denoising | 25 | 33.0489 | 0.8943 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | McMaster | Denoising | 25 | 33.3260 | 0.9066 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | Urban100 | Denoising | 25 | 32.9670 | 0.9317 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | CBSD68 | Denoising | 50 | 28.5569 | 0.8127 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | Kodak24 | Denoising | 50 | 30.0122 | 0.8238 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | McMaster | Denoising | 50 | 30.2608 | 0.8515 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | Urban100 | Denoising | 50 | 30.0230 | 0.8902 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth) \| log | **learning a single model to handle various noise levels** | Model | Dataset |Task| $\\sigma$ | PSNR (RGB) | SSIM (RGB) | Training Resources | Download | | :---------------------------------------------------------------------: | :-----: | :-------: | :--------: | :--------: | :-----------------------------------------------------------------------------------: | :------: | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py)| CBSD68 |Denoising| 15 | 34.3422 | 0.9356 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py)| Kodak24 |Denoising| 15 | 35.4544 | 0.9308 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py)| McMaster |Denoising| 15 | 35.5473 | 0.9344 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py)| Urban100 |Denoising| 15 | 35.0754 | 0.9524 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py)| CBSD68 |Denoising| 25 | 31.7391 | 0.8945 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py)| Kodak24 |Denoising| 25 | 33.0380 | 0.8941 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py)| McMaster |Denoising| 25 | 33.3040 | 0.9063 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py)| Urban100 |Denoising| 25 | 32.9165 | 0.9312 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py)| CBSD68 |Denoising| 50 | 28.5582 | 0.8126 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py)| Kodak24 |Denoising| 50 | 30.0074 | 0.8233 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py)| McMaster |Denoising| 50 | 30.2671 | 0.8520 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py)| Urban100 |Denoising| 50 | 30.0172 | 0.8898 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) | log | ### **Real Image Denoising** Evaluated on RGB channels. The metrics are `PSNR` / `SSIM` . | Model | Dataset | Task | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------------: | :-----: | :-------: | :-----: | :----: | :----------------: | :------------------------------------------------------------------------------------------------: | | [restormer_official_sidd](./restormer_official_sidd.py) | SIDD | Denoising | 40.0156 | 0.9225 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_sidd-9e7025db.pth) \| log | ## Quick Start **Train** You can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test # Deraining CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # single-gpu test # Deraining python tools/test.py configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring python tools/test.py configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single python tools/test.py configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual python tools/test.py configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # multi-gpu test # Deraining ./tools/dist_test.sh configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring ./tools/dist_test.sh configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single ./tools/dist_test.sh configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual ./tools/dist_test.sh configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` ================================================ FILE: configs/restormer/README_zh-CN.md ================================================ # Restormer (CVPR'2022) > [Restormer: Efficient Transformer for High-Resolution Image Restoration](https://arxiv.org/abs/2111.09881) > **任务**: 图像去噪,图像去模糊,图像去雨
## **各个任务下模型的测试结果** ### **图像去雨** 所有数据集均在Y通道上进行测试,测试指标为PSNR和SSIM。 | 方法 | Rain100H
PSNR/SSIM (Y) | Rain100L
PSNR/SSIM (Y) | Test100
PSNR/SSIM (Y) | Test1200
PSNR/SSIM (Y) | Test2800
PSNR/SSIM (Y) | GPU信息 | 下载 | | :--------------------------------: | :-----------------------: | :-----------------------: | :----------------------: | :-----------------------: | :-----------------------: | :-----: | :---------------------------------: | | [restormer_official_rain13k](./restormer_official_rain13k.py) | 31.4804/0.9056 | 39.1023/0.9787 | 32.0287/0.9239 | 33.2251/0.9272 | 34.2170/0.9451 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth) \| log | ### **图像去模糊** Gopro和HIDE数据集上使用RGB通道测试,ReakBlur-J 和 ReakBlur-R数据集使用Y通道测试。测试指标为PSNR和SSIM。 | 方法 | GoPro
PSNR/SSIM (RGB) | HIDE
PSNR/SSIM (RGB) | RealBlur-J
PSNR/SSIM (Y) | RealBlur-R
PSNR/SSIM (Y) | GPU信息 | 下载 | | :--------------------------------------------: | :----------------------: | :---------------------: | :-------------------------: | :-------------------------: | :-----: | :--------------------------------------------: | | [restormer_official_gopro](./restormer_official_gopro.py) | 32.9295/0.9496 | 31.2289/0.9345 | 28.4356/0.8681 | 35.9141/0.9707 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth) \| log | ### **图像去失焦模糊** 所有指标均在RGB通道上进行测试。测试指标为PSNR、SSIM、MAE和LPIPS. | 方法 | 室内场景图像的PSNR | 室内场景图像的SSIM | 室内场景图像的MAE | 室内场景图像的LPIPS | 室外场景图像的PSNR | 室外场景图像的SSIM | 室外场景图像的MAE | 室外场景图像的LPIPS | 所有图像平均PSNR | 所有图像平均SSIM | 所有图像平均MAE | 所有图像平均LPIPS | GPU 信息 | 下载 | | :----: | :-------------: | :-------------: | :------------: | :--------------: | :-------------: | :-------------: | :------------: | :--------------: | :------------: | :-------------: | :------------: | :--------------: | :------: | :-----: | | [restormer_official_dpdd-single](./restormer_official_dpdd-single.py) | 28.8681 | 0.8859 | 0.0251 | - | 23.2410 | 0.7509 | 0.0499 | - | 25.9805 | 0.8166 | 0.0378 | - | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth) \| log | | [restormer_official_dpdd-dual](./restormer_official_dpdd-dual.py) | 26.6160 | 0.8346 | 0.0354 | - | 26.6160 | 0.8346 | 0.0354 | - | 26.6160 | 0.8346 | 0.0354 | - | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth) \| log | ### **图像高斯噪声去除** **灰度图的高斯噪声** 使用PSNR和SSIM指标对数据集上的灰度图进行测试。 | 方法 | $\\sigma$ | Set12
PSNR/SSIM | BSD68
PSNR/SSIM | Urban100
PSNR/SSIM | GPU信息 | 下载 | | :-------------------------------------------------------------: | :-------: | :----------------: | :----------------: | :-------------------: | :-----: | :--------------------------------------------------------------: | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | 15 | 34.0182/0.9160 | 32.4987/0.8940 | 34.4336/0.9419 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth) \| log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | 25 | 31.7289/0.8811 | 30.1613/0.8370 | 32.1162/0.9140 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth) \| log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | 50 | 28.6269/0.8188 | 27.3266/0.7434 | 28.9636/0.8571 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth) \| log | | | | | | | | | | [restormer_official_dfwb-gray-sigma15](./restormer_official_dfwb-gray-sigma15.py) | 15 | 33.9642/0.9153 | 32.4994/0.8928 | 34.3152/0.9409 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma25](./restormer_official_dfwb-gray-sigma25.py) | 25 | 31.7106/0.8810 | 30.1486/0.8360 | 32.0457/0.9131 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | | [restormer_official_dfwb-gray-sigma50](./restormer_official_dfwb-gray-sigma50.py) | 50 | 28.6614/0.8197 | 27.3537/0.7422 | 28.9848/0.8571 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth) \| log | > 上面三行代表每个噪声等级训练一个单独的模型,下面三行代表学习一个单一的模型来处理各种噪音水平。 **彩色图像的高斯噪声** 所有指标均在RGB通道上进行测试,测试指标为PSNR和SSIM。 | 方法 | $\\sigma$ | CBSD68
PSNR/SSIM (RGB) | Kodak24
PSNR/SSIM (RGB) | McMaster
PSNR/SSIM (RGB) | Urban100
PSNR/SSIM (RGB) | GPU信息 | 下载 | | :-------------------------------------: | :-------: | :-----------------------: | :------------------------: | :-------------------------: | :-------------------------: | :-----: | :--------------------------------------: | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | 15 | 34.3506/0.9352 | 35.4900/0.9312 | 35.6072/0.9352 | 35.1522/0.9530 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | 25 | 31.7457/0.8942 | 33.0489/0.8943 | 33.3260/0.9066 | 32.9670/0.9317 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | 50 | 28.5569/0.8127 | 30.0122/0.8238 | 30.2608/0.8515 | 30.0230/0.8902 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth) \| log | | | | | | | | | | | [restormer_official_dfwb-color-sigma15](./restormer_official_dfwb-color-sigma15.py) | 15 | 34.3422/0.9356 | 35.4544/0.9308 | 35.5473/0.9344 | 35.0754/0.9524 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) \| log | | [restormer_official_dfwb-color-sigma25](./restormer_official_dfwb-color-sigma25.py) | 25 | 31.7391/0.8945 | 33.0380/0.8941 | 33.3040/0.9063 | 32.9165/0.9312 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) \| log | | [restormer_official_dfwb-color-sigma50](./restormer_official_dfwb-color-sigma50.py) | 50 | 28.5582/0.8126 | 30.0074/0.8233 | 30.2671/0.8520 | 30.0172/0.8898 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth) \| log | > 上面三行代表每个噪声等级训练一个单独的模型,下面三行代表学习一个单一的模型来处理各种噪音水平。 ### **真实场景图像去噪** 所有指标均在RGB通道上进行测试,测试指标为PSNR和SSIM。 | 方法 | SIDD
PSNR/SSIM | GPU信息 | 下载 | | :-----------------------------------------------------: | :---------------: | :-----: | :-----------------------------------------------------------------------------------------------------: | | [restormer_official_sidd](./restormer_official_sidd.py) | 40.0156/0.9225 | 1 | [model](https://download.openmmlab.com/mmediting/restormer/restormer_official_sidd-9e7025db.pth) \| log | ## 使用方法 **训练** 可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。 **测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # cpu test # Deraining CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # single-gpu test # Deraining python tools/test.py configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring python tools/test.py configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single python tools/test.py configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual python tools/test.py configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth python tools/test.py configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth python tools/test.py configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # multi-gpu test # Deraining ./tools/dist_test.sh configs/restormer/restormer_official_rain13k.py https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth # Motion Deblurring ./tools/dist_test.sh configs/restormer/restormer_official_gopro.py https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth # Defocus Deblurring # Single ./tools/dist_test.sh configs/restormer/restormer_official_dpdd-dual.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth # Dual ./tools/dist_test.sh configs/restormer/restormer_official_dpdd-single.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth # Gaussian Denoising # Test Grayscale Gaussian Noise # sigma15 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma15-da74417f.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma25 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma25-08010841.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # sigma50 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-sigma50-ee852dfe.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-gray-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth # Test Color Gaussian Noise # sigma15 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma15-012ceb71.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma15.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma25 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma25-e307f222.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma25.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth # sigma50 ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-sigma50-a991983d.pth ./tools/dist_test.sh configs/restormer/restormer_official_dfwb-color-sigma50.py https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/restormer/metafile.yml ================================================ Collections: - Name: Restormer Paper: Title: 'Restormer: Efficient Transformer for High-Resolution Image Restoration' URL: https://arxiv.org/abs/2111.09881 README: configs/restormer/README.md Task: - denoising - deblurring - deraining Year: 2022 Models: - Config: configs/restormer/restormer_official_rain13k.py In Collection: Restormer Name: restormer_official_rain13k Results: - Dataset: Rain100H Metrics: PSNR (Y): 31.4804 SSIM (Y): 0.9056 Task: Deraining - Dataset: Rain100L Metrics: PSNR (Y): 39.1023 SSIM (Y): 0.9787 Task: Deraining - Dataset: Test100 Metrics: PSNR (Y): 32.0287 SSIM (Y): 0.9239 Task: Deraining - Dataset: Test1200 Metrics: PSNR (Y): 33.2251 Task: Deraining - Dataset: Test2800 Metrics: PSNR (Y): 34.217 SSIM (Y): 0.9451 Task: Deraining Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_rain13k-2be7b550.pth - Config: configs/restormer/restormer_official_gopro.py In Collection: Restormer Name: restormer_official_gopro Results: - Dataset: GoPro Metrics: PSNR/SSIM (RGB): PSNR: 32.9295 SSIM: 0.9496 Task: Deblurring - Dataset: HIDE Metrics: PSNR/SSIM (RGB): PSNR: 31.2289 SSIM: 0.9345 Task: Deblurring - Dataset: RealBlur-J Metrics:
PSNR/SSIM (Y): PSNR: 28.4356 SSIM: 0.8681 Task: Deblurring - Dataset: RealBlur-R Metrics:
PSNR/SSIM (Y): PSNR: 35.9141 SSIM: 0.9707 Task: Deblurring Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_gopro-db7363a0.pth - Config: configs/restormer/restormer_official_dpdd-single.py In Collection: Restormer Name: restormer_official_dpdd-single Results: - Dataset: IndoorScenes Metrics: MAE: 0.0251 PSNR: 28.8681 SSIM: 0.8859 Task: Deblurring - Dataset: OutdoorScenes Metrics: MAE: 0.0499 PSNR: 23.241 SSIM: 0.7509 Task: Deblurring - Dataset: Combined Metrics: MAE: 0.0378 PSNR: 25.9805 SSIM: 0.8166 Task: Deblurring Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-single-6bc31582.pth - Config: configs/restormer/restormer_official_dpdd-dual.py In Collection: Restormer Name: restormer_official_dpdd-dual Results: - Dataset: IndoorScenes Metrics: MAE: 0.0354 PSNR: 26.616 SSIM: 0.8346 Task: Deblurring - Dataset: OutdoorScenes Metrics: MAE: 0.0354 PSNR: 26.616 SSIM: 0.8346 Task: Deblurring - Dataset: Combined Metrics: MAE: 0.0354 PSNR: 26.616 SSIM: 0.8346 Task: Deblurring Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dpdd-dual-52c94c00.pth - Config: configs/restormer/restormer_official_dfwb-gray-sigma15.py In Collection: Restormer Name: restormer_official_dfwb-gray-sigma15 Results: - Dataset: Set12 Metrics: $\\sigma$: 15.0 PSNR: 34.0182 SSIM: 0.916 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 15.0 PSNR: 32.4987 SSIM: 0.894 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 15.0 PSNR: 34.4336 SSIM: 0.9419 Task: Denoising - Dataset: Set12 Metrics: $\\sigma$: 15.0 PSNR: 33.9642 SSIM: 0.9153 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 15.0 PSNR: 32.4994 SSIM: 0.8928 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 15.0 PSNR: 34.3152 SSIM: 0.9409 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth - Config: configs/restormer/restormer_official_dfwb-gray-sigma25.py In Collection: Restormer Name: restormer_official_dfwb-gray-sigma25 Results: - Dataset: Set12 Metrics: $\\sigma$: 25.0 PSNR: 31.7289 SSIM: 0.8811 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 25.0 PSNR: 30.1613 SSIM: 0.837 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 25.0 PSNR: 32.1162 SSIM: 0.914 Task: Denoising - Dataset: Set12 Metrics: $\\sigma$: 25.0 PSNR: 31.7106 SSIM: 0.881 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 25.0 PSNR: 30.1486 SSIM: 0.836 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 25.0 PSNR: 32.0457 SSIM: 0.9131 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth - Config: configs/restormer/restormer_official_dfwb-gray-sigma50.py In Collection: Restormer Name: restormer_official_dfwb-gray-sigma50 Results: - Dataset: Set12 Metrics: $\\sigma$: 50.0 PSNR: 28.6269 SSIM: 0.8188 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 50.0 PSNR: 27.3266 SSIM: 0.7434 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 50.0 PSNR: 28.9636 SSIM: 0.8571 Task: Denoising - Dataset: Set12 Metrics: $\\sigma$: 50.0 PSNR: 28.6614 SSIM: 0.8197 Task: Denoising - Dataset: BSD68 Metrics: $\\sigma$: 50.0 PSNR: 27.3537 SSIM: 0.7422 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 50.0 PSNR: 28.9848 SSIM: 0.8571 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-gray-blind-5f094bcc.pth - Config: configs/restormer/restormer_official_dfwb-color-sigma15.py In Collection: Restormer Name: restormer_official_dfwb-color-sigma15 Results: - Dataset: CBSD68 Metrics: $\\sigma$: 15.0 PSNR (RGB): 34.3506 SSIM (RGB): 0.9352 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.49 SSIM (RGB): 0.9312 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.6072 SSIM (RGB): 0.9352 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.1522 SSIM (RGB): 0.953 Task: Denoising - Dataset: CBSD68 Metrics: $\\sigma$: 15.0 PSNR (RGB): 34.3422 SSIM (RGB): 0.9356 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.4544 SSIM (RGB): 0.9308 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.5473 SSIM (RGB): 0.9344 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 15.0 PSNR (RGB): 35.0754 SSIM (RGB): 0.9524 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth - Config: configs/restormer/restormer_official_dfwb-color-sigma25.py In Collection: Restormer Name: restormer_official_dfwb-color-sigma25 Results: - Dataset: CBSD68 Metrics: $\\sigma$: 25.0 PSNR (RGB): 31.7457 SSIM (RGB): 0.8942 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 25.0 PSNR (RGB): 33.0489 SSIM (RGB): 0.8943 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 25.0 PSNR (RGB): 33.326 SSIM (RGB): 0.9066 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 25.0 PSNR (RGB): 32.967 SSIM (RGB): 0.9317 Task: Denoising - Dataset: CBSD68 Metrics: $\\sigma$: 25.0 PSNR (RGB): 31.7391 SSIM (RGB): 0.8945 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 25.0 PSNR (RGB): 33.038 SSIM (RGB): 0.8941 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 25.0 PSNR (RGB): 33.304 SSIM (RGB): 0.9063 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 25.0 PSNR (RGB): 32.9165 SSIM (RGB): 0.9312 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth - Config: configs/restormer/restormer_official_dfwb-color-sigma50.py In Collection: Restormer Name: restormer_official_dfwb-color-sigma50 Results: - Dataset: CBSD68 Metrics: $\\sigma$: 50.0 PSNR (RGB): 28.5569 SSIM (RGB): 0.8127 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.0122 SSIM (RGB): 0.8238 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.2608 SSIM (RGB): 0.8515 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.023 SSIM (RGB): 0.8902 Task: Denoising - Dataset: CBSD68 Metrics: $\\sigma$: 50.0 PSNR (RGB): 28.5582 SSIM (RGB): 0.8126 Task: Denoising - Dataset: Kodak24 Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.0074 SSIM (RGB): 0.8233 Task: Denoising - Dataset: McMaster Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.2671 SSIM (RGB): 0.852 Task: Denoising - Dataset: Urban100 Metrics: $\\sigma$: 50.0 PSNR (RGB): 30.0172 SSIM (RGB): 0.8898 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_dfwb-color-blind-dfd03c9f.pth - Config: configs/restormer/restormer_official_sidd.py In Collection: Restormer Name: restormer_official_sidd Results: - Dataset: SIDD Metrics: PSNR: 40.0156 SSIM: 0.9225 Task: Denoising Weights: https://download.openmmlab.com/mmediting/restormer/restormer_official_sidd-9e7025db.pth ================================================ FILE: configs/restormer/restormer_official_dfwb-color-sigma15.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_color_test_config.py' ] experiment_name = 'restormer_official_dfwb_color_sigma15' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 15 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_dfwb-color-sigma25.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_color_test_config.py' ] experiment_name = 'restormer_official_dfwb_color_sigma25' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 25 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_dfwb-color-sigma50.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_color_test_config.py' ] experiment_name = 'restormer_official_dfwb_color_sigma50' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 50 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_dfwb-gray-sigma15.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_gray_test_config.py' ] experiment_name = 'restormer_official_dfwb_gray_sigma15' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 15 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=1, out_channels=1, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.], std=[255.], )) ================================================ FILE: configs/restormer/restormer_official_dfwb-gray-sigma25.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_gray_test_config.py' ] experiment_name = 'restormer_official_dfwb_gray_sigma25' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 25 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=1, out_channels=1, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.], std=[255.], )) ================================================ FILE: configs/restormer/restormer_official_dfwb-gray-sigma50.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_gray_test_config.py' ] experiment_name = 'restormer_official_dfwb_gray_sigma50' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 50 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma * 255, sigma * 255] # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=1, out_channels=1, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.], std=[255.], )) ================================================ FILE: configs/restormer/restormer_official_dpdd-dual.py ================================================ _base_ = [ 'restormer_official_dpdd-single.py', ] experiment_name = 'restormer_official_dpdd-dual' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify PackInputs test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[4] = dict(type='PackInputs', keys=['imgL', 'imgR']) # model settings model = dict( generator=dict(inp_channels=6, dual_pixel_task=True), data_preprocessor=dict(type='DataPreprocessor')) ================================================ FILE: configs/restormer/restormer_official_dpdd-single.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/deblurring-defocus_test_config.py' ] experiment_name = 'restormer_official_dpdd-single' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_gopro.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/deblurring-motion_test_config.py' ] experiment_name = 'restormer_official_gopro' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_rain13k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/deraining_test_config.py' ] experiment_name = 'restormer_official_rain13k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/restormer/restormer_official_sidd.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-real_test_config.py' ] experiment_name = 'restormer_official_sidd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( type='BaseEditModel', generator=dict( type='Restormer', inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ================================================ FILE: configs/sagan/README.md ================================================ # SAGAN (ICML'2019) > [Self-attention generative adversarial networks](https://proceedings.mlr.press/v97/zhang19d.html) > **Task**: Conditional GANs ## Abstract In this paper, we propose the Self-Attention Generative Adversarial Network (SAGAN) which allows attention-driven, long-range dependency modeling for image generation tasks. Traditional convolutional GANs generate high-resolution details as a function of only spatially local points in lower-resolution feature maps. In SAGAN, details can be generated using cues from all feature locations. Moreover, the discriminator can check that highly detailed features in distant portions of the image are consistent with each other. Furthermore, recent work has shown that generator conditioning affects GAN performance. Leveraging this insight, we apply spectral normalization to the GAN generator and find that this improves training dynamics. The proposed SAGAN performs better than prior work, boosting the best published Inception score from 36.8 to 52.52 and reducing Fréchet Inception distance from 27.62 to 18.65 on the challenging ImageNet dataset. Visualization of the attention layers shows that the generator leverages neighborhoods that correspond to object shapes rather than local regions of fixed shape.
## Results and models
Results from our SAGAN trained in CIFAR10
| Model | Dataset | Inplace ReLU | dist_step | Total Batchsize (BZ_PER_GPU * NGPU) | Total Iters\* | Iter | IS | FID | Download | | :------------------------------------------------: | :------: | :----------: | :-------: | :---------------------------------: | :-----------: | :----: | :-----: | :-----: | :---------------------------------------------------: | | [SAGAN-32x32-woInplaceReLU Best IS](./sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w/o | 5 | 64x1 | 500000 | 400000 | 9.3217 | 10.5030 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_woReUinplace_is-iter400000_20210730_125743-4008a9ca.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_woReUinplace_20210730_125449_fid-d50568a4_is-04008a9ca.json) | | [SAGAN-32x32-woInplaceReLU Best FID](./sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w/o | 5 | 64x1 | 500000 | 480000 | 9.3174 | 9.4252 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_woReUinplace_fid-iter480000_20210730_125449-d50568a4.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_woReUinplace_20210730_125449_fid-d50568a4_is-04008a9ca.json) | | [SAGAN-32x32-wInplaceReLU Best IS](./sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w | 5 | 64x1 | 500000 | 380000 | 9.2286 | 11.7760 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_wReLUinplace_is-iter380000_20210730_124937-c77b4d25.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_wReLUinplace_20210730_125155_fid-cbefb354_is-c77b4d25.json) | | [SAGAN-32x32-wInplaceReLU Best FID](./sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w | 5 | 64x1 | 500000 | 460000 | 9.2061 | 10.7781 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_wReLUinplace_fid-iter460000_20210730_125155-cbefb354.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_wReLUinplace_20210730_125155_fid-cbefb354_is-c77b4d25.json) | | [SAGAN-128x128-woInplaceReLU Best IS](./sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128.py) | ImageNet | w/o | 1 | 64x4 | 1000000 | 980000 | 31.5938 | 36.7712 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_imagenet1k_128_Glr1e-4_Dlr4e-4_ndisc1_b32x4_woReLUinplace_is-iter980000_20210730_163140-cfbebfc6.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_imagenet1k_128_Glr1e-4_Dlr4e-4_ndisc1_b32x4_woReLUinplace_20210730_163431_fid-d7916963_is-cfbebfc6.json) | | [SAGAN-128x128-woInplaceReLU Best FID](./sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128.py) | ImageNet | w/o | 1 | 64x4 | 1000000 | 950000 | 28.4936 | 34.7838 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_imagenet1k_128_Glr1e-4_Dlr4e-4_ndisc1_b32x4_woReLUinplace_fid-iter950000_20210730_163431-d7916963.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_imagenet1k_128_Glr1e-4_Dlr4e-4_ndisc1_b32x4_woReLUinplace_20210730_163431_fid-d7916963_is-cfbebfc6.json) | | [SAGAN-128x128-BigGAN Schedule Best IS](./sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128.py) | ImageNet | w/o | 1 | 32x8 | 1000000 | 826000 | 69.5350 | 12.8295 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_128_woReLUinplace_noaug_bigGAN_imagenet1k_b32x8_Glr1e-4_Dlr-4e-4_ndisc1_20210818_210232-3f5686af.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_128_woReLUinplace_noaug_bigGAN_imagenet1k_b32x8_Glr1e-4_Dlr-4e-4_ndisc1_20210818_210232-3f5686af.json) | | [SAGAN-128x128-BigGAN Schedule Best FID](./sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128.py) | ImageNet | w/o | 1 | 32x8 | 1000000 | 826000 | 69.5350 | 12.8295 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_128_woReLUinplace_noaug_bigGAN_imagenet1k_b32x8_Glr1e-4_Dlr-4e-4_ndisc1_20210818_210232-3f5686af.pth) \| [Log](https://download.openmmlab.com/mmediting/sagan/sagan_128_woReLUinplace_noaug_bigGAN_imagenet1k_b32x8_Glr1e-4_Dlr-4e-4_ndisc1_20210818_210232-3f5686af.json) | '\*' Iteration counting rule in our implementation is different from others. If you want to align with other codebases, you can use the following conversion formula: ``` total_iters (biggan/pytorch studio gan) = our_total_iters / dist_step ``` We also provide converted pre-train models from [Pytorch-StudioGAN](https://github.com/POSTECH-CVLab/PyTorch-StudioGAN). To be noted that, in Pytorch Studio GAN, **inplace ReLU** is used in generator and discriminator. | Model | Dataset | Inplace ReLU | n_disc | Total Iters | IS (Our Pipeline) | FID (Our Pipeline) | IS (StudioGAN) | FID (StudioGAN) | Download | Original Download link | | :------------------------: | :------: | :----------: | :----: | :---------: | :---------------: | :----------------: | :------------: | :-------------: | :---------------------------: | :------------------------------------------: | | [SAGAN-32x32 StudioGAN](./sagan_cvt-studioGAN_cifar10-32x32.py) | CIFAR10 | w | 5 | 100000 | 9.116 | 10.2011 | 8.680 | 14.009 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_32_cifar10_convert-studio-rgb_20210730_153321-080da7e2.pth) | [model](https://drive.google.com/drive/folders/1FA8hcz4MB8-hgTwLuDA0ZUfr8slud5P_) | | [SAGAN0-128x128 StudioGAN](./sagan_128_cvt_studioGAN.py) | ImageNet | w | 1 | 1000000 | 27.367 | 40.1162 | 29.848 | 34.726 | [model](https://download.openmmlab.com/mmediting/sagan/sagan_128_imagenet1k_convert-studio-rgb_20210730_153357-eddb0d1d.pth) | [model](https://drive.google.com/drive/folders/1ZYaqeeumDgxOPDhRR5QLeLFIpgBJ9S6B) | - `Our Pipeline` denote results evaluated with our pipeline. - `StudioGAN` denote results released by Pytorch-StudioGAN. For IS metric, our implementation is different from PyTorch-Studio GAN in the following aspects: 1. We use [Tero's Inception](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for feature extraction. 2. We use bicubic interpolation with PIL backend to resize image before feed them to Inception. For FID evaluation, we follow the pipeline of [BigGAN](https://github.com/ajbrock/BigGAN-PyTorch/blob/98459431a5d618d644d54cd1e9fceb1e5045648d/calculate_inception_moments.py#L52), where the whole training set is adopted to extract inception statistics, and Pytorch Studio GAN uses 50000 randomly selected samples. Besides, we also use [Tero's Inception](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for feature extraction. You can download the preprocessed inception state by the following url: [CIFAR10](https://download.openmmlab.com/mmediting/evaluation/fid_inception_pkl/cifar10.pkl) and [ImageNet1k](https://download.openmmlab.com/mmediting/evaluation/fid_inception_pkl/imagenet.pkl). You can use following commands to extract those inception states by yourself. ``` # For CIFAR10 python tools/utils/inception_stat.py --data-cfg configs/_base_/datasets/cifar10_inception_stat.py --pklname cifar10.pkl --no-shuffle --inception-style stylegan --num-samples -1 --subset train # For ImageNet1k python tools/utils/inception_stat.py --data-cfg configs/_base_/datasets/imagenet_128x128_inception_stat.py --pklname imagenet.pkl --no-shuffle --inception-style stylegan --num-samples -1 --subset train ``` ## Citation ```latex @inproceedings{zhang2019self, title={Self-attention generative adversarial networks}, author={Zhang, Han and Goodfellow, Ian and Metaxas, Dimitris and Odena, Augustus}, booktitle={International conference on machine learning}, pages={7354--7363}, year={2019}, organization={PMLR}, url={https://proceedings.mlr.press/v97/zhang19d.html}, } ``` ================================================ FILE: configs/sagan/metafile.yml ================================================ Collections: - Name: SAGAN Paper: Title: Self-attention generative adversarial networks URL: https://proceedings.mlr.press/v97/zhang19d.html README: configs/sagan/README.md Task: - conditional gans Year: 2019 Models: - Config: configs/sagan/sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py In Collection: SAGAN Name: sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID: 10.503 IS: 9.3217 Iter: 400000.0 Total Iters\*: 500000.0 dist_step: 5.0 Task: Conditional GANs - Dataset: CIFAR10 Metrics: FID: 9.4252 IS: 9.3174 Iter: 480000.0 Total Iters\*: 500000.0 dist_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_woReUinplace_fid-iter480000_20210730_125449-d50568a4.pth - Config: configs/sagan/sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py In Collection: SAGAN Name: sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID: 11.776 IS: 9.2286 Iter: 380000.0 Total Iters\*: 500000.0 dist_step: 5.0 Task: Conditional GANs - Dataset: CIFAR10 Metrics: FID: 10.7781 IS: 9.2061 Iter: 460000.0 Total Iters\*: 500000.0 dist_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_cifar10_32_lr2e-4_ndisc5_b64x1_wReLUinplace_fid-iter460000_20210730_125155-cbefb354.pth - Config: configs/sagan/sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128.py In Collection: SAGAN Name: sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128 Results: - Dataset: ImageNet Metrics: FID: 36.7712 IS: 31.5938 Iter: 980000.0 Total Iters\*: 1000000.0 dist_step: 1.0 Task: Conditional GANs - Dataset: ImageNet Metrics: FID: 34.7838 IS: 28.4936 Iter: 950000.0 Total Iters\*: 1000000.0 dist_step: 1.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_imagenet1k_128_Glr1e-4_Dlr4e-4_ndisc1_b32x4_woReLUinplace_fid-iter950000_20210730_163431-d7916963.pth - Config: configs/sagan/sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128.py In Collection: SAGAN Name: sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128 Results: - Dataset: ImageNet Metrics: FID: 12.8295 IS: 69.535 Iter: 826000.0 Total Iters\*: 1000000.0 dist_step: 1.0 Task: Conditional GANs - Dataset: ImageNet Metrics: FID: 12.8295 IS: 69.535 Iter: 826000.0 Total Iters\*: 1000000.0 dist_step: 1.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_128_woReLUinplace_noaug_bigGAN_imagenet1k_b32x8_Glr1e-4_Dlr-4e-4_ndisc1_20210818_210232-3f5686af.pth - Config: configs/sagan/sagan_cvt-studioGAN_cifar10-32x32.py In Collection: SAGAN Name: sagan_cvt-studioGAN_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID (Our Pipeline): 10.2011 FID (StudioGAN): 14.009 IS (Our Pipeline): 9.116 IS (StudioGAN): 8.68 Total Iters: 100000.0 n_disc: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_32_cifar10_convert-studio-rgb_20210730_153321-080da7e2.pth - Config: configs/sagan/sagan_128_cvt_studioGAN.py In Collection: SAGAN Name: sagan_128_cvt_studioGAN Results: - Dataset: ImageNet Metrics: FID (Our Pipeline): 40.1162 FID (StudioGAN): 34.726 IS (Our Pipeline): 27.367 IS (StudioGAN): 29.848 Total Iters: 1000000.0 n_disc: 1.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sagan/sagan_128_imagenet1k_convert-studio-rgb_20210730_153357-eddb0d1d.pth ================================================ FILE: configs/sagan/sagan_128_cvt_studioGAN.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/models/sagan/base_sagan_128x128.py', '../_base_/datasets/imagenet_noaug_128.py', ] # NOTE: # * studio GAN train their model in 'RGB' order model = dict(generator=dict(rgb_to_bgr=True)) # NOTE: do not support training for converted configs train_cfg = train_dataloader = optim_wrapper = None # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # EVALUATION val_dataloader = val_evaluator = val_cfg = None test_dataloader = dict(batch_size=128) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sagan/sagan_cvt-studioGAN_cifar10-32x32.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/datasets/cifar10_noaug.py', '../_base_/models/sagan/base_sagan_32x32.py', ] # NOTE: # * CIFAR is loaded in 'RGB' # * studio GAN train their model in 'RGB' order model = dict( data_preprocessor=dict(output_channel_order='BGR'), generator=dict(rgb_to_bgr=True)) # NOTE: do not support training for converted configs train_cfg = train_dataloader = optim_wrapper = None # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # EVALUATION val_dataloader = val_evaluator = val_cfg = None test_dataloader = dict(batch_size=128) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sagan/sagan_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/datasets/cifar10_nopad.py', '../_base_/models/sagan/base_sagan_32x32.py', ] # MODEL disc_step = 5 init_cfg = dict(type='studio') model = dict( # CIFAR images are RGB, convert to BGR data_preprocessor=dict(output_channel_order='BGR'), generator=dict(act_cfg=dict(type='ReLU', inplace=True), init_cfg=init_cfg), discriminator=dict( act_cfg=dict(type='ReLU', inplace=True), init_cfg=init_cfg)) # TRAIN train_cfg = dict(max_iters=100000 * disc_step) train_dataloader = dict(batch_size=64) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sagan/sagan_woReLUinplace-Glr1e-4_Dlr4e-4_noaug-ndisc1-8xb32-bigGAN-sch_imagenet1k-128x128.py ================================================ # In this config, we follow the setting `launch_SAGAN_bz128x2_ema.sh` from # BigGAN's repo. Please refer to https://github.com/ajbrock/BigGAN-PyTorch/blob/master/scripts/launch_SAGAN_bs128x2_ema.sh # noqa # In summary, in this config: # 1. use eps=1e-8 for Spectral Norm # 2. not use syncBN # 3. not use Spectral Norm for embedding layers in cBN # 4. start EMA at iterations # 5. use xavier_uniform for weight initialization # 6. no data augmentation _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/models/sagan/base_sagan_128x128.py', '../_base_/datasets/imagenet_noaug_128.py', ] # MODEL init_cfg = dict(type='BigGAN') model = dict( num_classes=1000, generator=dict( num_classes=1000, init_cfg=init_cfg, norm_eps=1e-5, sn_eps=1e-8, auto_sync_bn=False, with_embedding_spectral_norm=False), discriminator=dict(num_classes=1000, init_cfg=init_cfg, sn_eps=1e-8), discriminator_steps=1, ema_config=dict(interval=1, momentum=0.999, start_iter=2000)) # TRAINING train_cfg = dict( max_iters=1000000, val_interval=10000, dynamic_intervals=[(800000, 4000)]) train_dataloader = dict(batch_size=32) # train on 8 gpus optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema.fake_img', 'orig.fake_img'])) ] # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='ema') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_dataloader = test_dataloader = dict(batch_size=64) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sagan/sagan_woReLUinplace_Glr1e-4_Dlr4e-4_ndisc1-4xb64_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/models/sagan/base_sagan_128x128.py', '../_base_/datasets/imagenet_128.py', ] # MODEL init_cfg = dict(type='studio') model = dict( num_classes=1000, generator=dict(num_classes=1000, init_cfg=init_cfg), discriminator=dict(num_classes=1000, init_cfg=init_cfg)) # TRAIN train_cfg = dict( max_iters=1000000, val_interval=10000, dynamic_intervals=[(800000, 4000)]) train_dataloader = dict(batch_size=64) # train on 4 gpus optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_dataloader = test_dataloader = dict(batch_size=64) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sagan/sagan_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/datasets/cifar10_nopad.py', '../_base_/models/sagan/base_sagan_32x32.py', ] # MODEL disc_step = 5 init_cfg = dict(type='studio') model = dict( # CIFAR images are RGB, convert to BGR data_preprocessor=dict(output_channel_order='BGR'), generator=dict(init_cfg=init_cfg), discriminator=dict(init_cfg=init_cfg)) # TRAIN train_cfg = dict(max_iters=100000 * disc_step) train_dataloader = dict(batch_size=64) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/singan/README.md ================================================ # SinGAN (ICCV'2019) > [Singan: Learning a Generative Model from a Single Natural Image](https://openaccess.thecvf.com/content_ICCV_2019/html/Shaham_SinGAN_Learning_a_Generative_Model_From_a_Single_Natural_Image_ICCV_2019_paper.html) > **Task**: Internal Learning ## Abstract We introduce SinGAN, an unconditional generative model that can be learned from a single natural image. Our model is trained to capture the internal distribution of patches within the image, and is then able to generate high quality, diverse samples that carry the same visual content as the image. SinGAN contains a pyramid of fully convolutional GANs, each responsible for learning the patch distribution at a different scale of the image. This allows generating new samples of arbitrary size and aspect ratio, that have significant variability, yet maintain both the global structure and the fine textures of the training image. In contrast to previous single image GAN schemes, our approach is not limited to texture images, and is not conditional (i.e. it generates samples from noise). User studies confirm that the generated samples are commonly confused to be real images. We illustrate the utility of SinGAN in a wide range of image manipulation tasks.
## Results and Models
SinGAN balloons
| Model | Dataset | Num Scales | Download | | :----------------------------: | :-----------------------------------------------------------------------------: | :--------: | :-------------------------------------------------------------------------------: | | [SinGAN](./singan_balloons.py) | [balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png) | 8 | [ckpt](https://download.openmmlab.com/mmediting/singan/singan_balloons_20210406_191047-8fcd94cf.pth) \| [pkl](https://download.openmmlab.com/mmediting/singan/singan_balloons_20210406_191047-8fcd94cf.pkl) | | [SinGAN](./singan_fish.py) | [fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg) | 10 | [ckpt](https://download.openmmlab.com/mmediting/singan/singan_fis_20210406_201006-860d91b6.pth) \| [pkl](https://download.openmmlab.com/mmediting/singan/singan_fis_20210406_201006-860d91b6.pkl) | | [SinGAN](./singan_bohemian.py) | [bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png) | 10 | [ckpt](https://download.openmmlab.com/mmediting/singan/singan_bohemian_20210406_175439-f964ee38.pth) \| [pkl](https://download.openmmlab.com/mmediting/singan/singan_bohemian_20210406_175439-f964ee38.pkl) | ## Notes for using SinGAN When training SinGAN models, users may obtain the number of scales (stages) in advance via the following commands. This number is important for constructing config file, which is related to the generator, discriminator, the training iterations and so on. ```shell >>> from mmgen.datasets.singan_dataset import create_real_pyramid >>> import mmcv >>> real = mmcv.imread('real_img_path') >>> _, _, num_scales = create_real_pyramid(real, min_size=25, max_size=300, scale_factor_init=0.75) ``` When testing SinGAN models, users have to modify the config file to add the `test_cfg`. As shown in `configs/singan/singan_balloons.py`, the only thing you need to do is add the path for `pkl` data. There are some important data containing in the pickle files which you can download from our website. ```python test_cfg = dict( _delete_ = True pkl_data = 'path to pkl data' ) ``` ## Citation ```latex @inproceedings{shaham2019singan, title={Singan: Learning a generative model from a single natural image}, author={Shaham, Tamar Rott and Dekel, Tali and Michaeli, Tomer}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, pages={4570--4580}, year={2019}, url={https://openaccess.thecvf.com/content_ICCV_2019/html/Shaham_SinGAN_Learning_a_Generative_Model_From_a_Single_Natural_Image_ICCV_2019_paper.html}, } ``` ================================================ FILE: configs/singan/metafile.yml ================================================ Collections: - Name: SinGAN Paper: Title: 'Singan: Learning a Generative Model from a Single Natural Image' URL: https://openaccess.thecvf.com/content_ICCV_2019/html/Shaham_SinGAN_Learning_a_Generative_Model_From_a_Single_Natural_Image_ICCV_2019_paper.html README: configs/singan/README.md Task: - internal learning Year: 2019 Models: - Config: configs/singan/singan_balloons.py In Collection: SinGAN Name: singan_balloons Results: - Dataset: '[balloons.png](https://download.openmmlab.com/mmediting/dataset/singan/balloons.png)' Metrics: Num Scales: 8.0 Task: Internal Learning Weights: https://download.openmmlab.com/mmediting/singan/singan_balloons_20210406_191047-8fcd94cf.pth - Config: configs/singan/singan_fish.py In Collection: SinGAN Name: singan_fish Results: - Dataset: '[fish.jpg](https://download.openmmlab.com/mmediting/dataset/singan/fish-crop.jpg)' Metrics: Num Scales: 10.0 Task: Internal Learning Weights: https://download.openmmlab.com/mmediting/singan/singan_fis_20210406_201006-860d91b6.pth - Config: configs/singan/singan_bohemian.py In Collection: SinGAN Name: singan_bohemian Results: - Dataset: '[bohemian.png](https://download.openmmlab.com/mmediting/dataset/singan/bohemian.png)' Metrics: Num Scales: 10.0 Task: Internal Learning Weights: https://download.openmmlab.com/mmediting/singan/singan_bohemian_20210406_175439-f964ee38.pth ================================================ FILE: configs/singan/singan_balloons.py ================================================ _base_ = ['./singan_fish.py'] # MODEL num_scales = 8 # start from zero generator_steps = 3 discriminator_steps = 3 iters_per_scale = 2000 # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_balloons_20210406_191047-8fcd94cf.pkl' # noqa test_pkl_data = None model = dict( num_scales=num_scales, generator=dict(num_scales=num_scales), discriminator=dict(num_scales=num_scales), test_pkl_data=test_pkl_data) # DATA pipeline = [ dict( type='PackInputs', keys=[f'real_scale{i}' for i in range(num_scales)] + ['input_sample']) ] data_root = './data/singan/balloons.png' train_dataloader = dict(dataset=dict(data_root=data_root, pipeline=pipeline)) # HOOKS custom_hooks = [ dict( type='PickleDataHook', output_dir='pickle', interval=-1, after_run=True, data_name_list=['noise_weights', 'fixed_noises', 'curr_stage']), dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='SinGAN', name='balloons')) ] # TRAINING total_iters = (num_scales + 1) * iters_per_scale * discriminator_steps train_cfg = dict(max_iters=total_iters) ================================================ FILE: configs/singan/singan_bohemian.py ================================================ _base_ = ['./singan_fish.py'] # MODEL # NOTE: add by user, e.g.: # test_pkl_data = './work_dirs/singan_pkl/singan_bohemian_20210406_175439-f964ee38.pkl' # noqa test_pkl_data = None model = dict(test_pkl_data=test_pkl_data) # HOOKS custom_hooks = [ dict( type='PickleDataHook', output_dir='pickle', interval=-1, after_run=True, data_name_list=['noise_weights', 'fixed_noises', 'curr_stage']), dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='SinGAN', name='bohemian')) ] # DATA min_size = 25 max_size = 500 data_root = './data/singan/bohemian.png' train_dataloader = dict( dataset=dict(data_root=data_root, min_size=min_size, max_size=max_size)) ================================================ FILE: configs/singan/singan_fish.py ================================================ _base_ = ['../_base_/gen_default_runtime.py'] # MODEL WRAPPER model_wrapper_cfg = dict(find_unused_parameters=True) # MODEL num_scales = 10 # start from zero generator_steps = 3 discriminator_steps = 3 iters_per_scale = 2000 # NOTE: add by user, e.g.: # test_pkl_data = ('./work_dirs/singan_fish/pickle/iter_66001.pkl') test_pkl_data = None model = dict( type='SinGAN', data_preprocessor=dict( type='DataPreprocessor', non_image_keys=['input_sample']), generator=dict( type='SinGANMultiScaleGenerator', in_channels=3, out_channels=3, num_scales=num_scales, ), discriminator=dict( type='SinGANMultiScaleDiscriminator', in_channels=3, num_scales=num_scales, ), noise_weight_init=0.1, test_pkl_data=test_pkl_data, lr_scheduler_args=dict(milestones=[1600], gamma=0.1), generator_steps=generator_steps, discriminator_steps=discriminator_steps, iters_per_scale=iters_per_scale, num_scales=num_scales) # DATA min_size = 25 max_size = 300 dataset_type = 'SinGANDataset' data_root = './data/singan/fish-crop.jpg' pipeline = [ dict( type='PackInputs', keys=[f'real_scale{i}' for i in range(num_scales)] + ['input_sample']) ] dataset = dict( type=dataset_type, data_root=data_root, min_size=min_size, max_size=max_size, scale_factor_init=0.75, pipeline=pipeline) train_dataloader = dict( batch_size=1, num_workers=0, dataset=dataset, sampler=None, persistent_workers=False) # TRAINING optim_wrapper = dict( constructor='SinGANOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999)))) total_iters = (num_scales + 1) * iters_per_scale * discriminator_steps train_cfg = dict(max_iters=total_iters) # HOOK custom_hooks = [ dict( type='PickleDataHook', output_dir='pickle', interval=-1, after_run=True, data_name_list=['noise_weights', 'fixed_noises', 'curr_stage']), dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='SinGAN', name='fish')) ] # NOTE: SinGAN do not support val_loop and test_loop, please use # 'tools/utils/inference_singan.py' to evaluate and generate images. val_cfg = test_cfg = None val_evaluator = test_evaluator = None ================================================ FILE: configs/sngan_proj/README.md ================================================ # SNGAN (ICLR'2018) > [Spectral Normalization for Generative Adversarial Networks](https://openreview.net/forum?id=B1QRgziT-) > **Task**: Conditional GANs ## Abstract One of the challenges in the study of generative adversarial networks is the instability of its training. In this paper, we propose a novel weight normalization technique called spectral normalization to stabilize the training of the discriminator. Our new normalization technique is computationally light and easy to incorporate into existing implementations. We tested the efficacy of spectral normalization on CIFAR10, STL-10, and ILSVRC2012 dataset, and we experimentally confirmed that spectrally normalized GANs (SN-GANs) is capable of generating images of better or equal quality relative to the previous training stabilization techniques.
## Results and models
Results from our SNGAN-PROJ trained in CIFAR10 and ImageNet
  
| Model | Dataset | Inplace ReLU | disc_step | Total Iters\* | Iter | IS | FID | Download | | :-----------------------------------------------------------------: | :------: | :----------: | :-------: | :-----------: | :----: | :-----: | :-----: | :---------------------------------------------------------------------: | | [SNGAN_Proj-32x32-woInplaceReLU Best IS](./sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w/o | 5 | 500000 | 400000 | 9.6919 | 9.8203 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_woReLUinplace_is-iter400000_20210709_163823-902ce1ae.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_woReLUinplace_20210624_065306_fid-ba0862a0_is-902ce1ae.json) | | [SNGAN_Proj-32x32-woInplaceReLU Best FID](./sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w/o | 5 | 500000 | 490000 | 9.5659 | 8.1158 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_woReLUinplace_fid-iter490000_20210709_163329-ba0862a0.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_woReLUinplace_20210624_065306_fid-ba0862a0_is-902ce1ae.json) | | [SNGAN_Proj-32x32-wInplaceReLU Best IS](./sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w | 5 | 500000 | 490000 | 9.5564 | 8.3462 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_wReLUinplace_is-iter490000_20210709_202230-cd863c74.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_wReLUinplace_20210624_063454_is-cd863c74_fid-191b2648.json) | | [SNGAN_Proj-32x32-wInplaceReLU Best FID](./sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py) | CIFAR10 | w | 5 | 500000 | 490000 | 9.5564 | 8.3462 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4-b64x1_wReLUinplace_fid-iter490000_20210709_203038-191b2648.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_wReLUinplace_20210624_063454_is-cd863c74_fid-191b2648.json) | | [SNGAN_Proj-128x128-woInplaceReLU Best IS](./sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py) | ImageNet | w/o | 5 | 1000000 | 952000 | 30.0651 | 33.4682 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_woReLUinplace_is-iter952000_20210730_132027-9c884a21.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_woReLUinplace_20210730_131424_fid-061bf803_is-9c884a21.json) | | [SNGAN_Proj-128x128-woInplaceReLU Best FID](./sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py) | ImageNet | w/o | 5 | 1000000 | 989000 | 29.5779 | 32.6193 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_woReLUinplace_fid-iter988000_20210730_131424-061bf803.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_woReLUinplace_20210730_131424_fid-061bf803_is-9c884a21.json) | | [SNGAN_Proj-128x128-wInplaceReLU Best IS](./sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py) | ImageNet | w | 5 | 1000000 | 944000 | 28.1799 | 34.3383 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_wReLUinplace_is-iter944000_20210730_132714-ca0ccd07.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_wReLUinplace_20210730_132401_fid-9a682411_is-ca0ccd07.json) | | [SNGAN_Proj-128x128-wInplaceReLU Best FID](./sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py) | ImageNet | w | 5 | 1000000 | 988000 | 27.7948 | 33.4821 | [ckpt](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_wReLUinplace_fid-iter988000_20210730_132401-9a682411.pth) \| [Log](https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_wReLUinplace_20210730_132401_fid-9a682411_is-ca0ccd07.json) | '\*' Iteration counting rule in our implementation is different from others. If you want to align with other codebases, you can use the following conversion formula: ``` total_iters (biggan/pytorch studio gan) = our_total_iters / disc_step ``` We also provide converted pre-train models from [Pytorch-StudioGAN](https://github.com/POSTECH-CVLab/PyTorch-StudioGAN). To be noted that, in Pytorch Studio GAN, **inplace ReLU** is used in generator and discriminator. | Model | Dataset | Inplace ReLU | disc_step | Total Iters | IS (Our Pipeline) | FID (Our Pipeline) | IS (StudioGAN) | FID (StudioGAN) | Download | Original Download link | | :-----------------------: | :------: | :----------: | :-------: | :---------: | :---------------: | :----------------: | :------------: | :-------------: | :--------------------------: | :-----------------------------------------: | | [SAGAN_Proj-32x32 StudioGAN](./sngan-proj-cvt-studioGAN_cifar10-32x32.py) | CIFAR10 | w | 5 | 100000 | 9.372 | 10.2011 | 8.677 | 13.248 | [model](https://download.openmmlab.com/mmediting/sngan_proj/sngan_cifar10_convert-studio-rgb_20210709_111346-2979202d.pth) | [model](https://drive.google.com/drive/folders/16s5Cr-V-NlfLyy_uyXEkoNxLBt-8wYSM) | | [SAGAN_Proj-128x128 StudioGAN](./sngan-proj-cvt-studioGAN_imagenet1k-128x128.py) | ImageNet | w | 2 | 1000000 | 30.218 | 29.8199 | 32.247 | 26.792 | [model](https://download.openmmlab.com/mmediting/sngan_proj/sngan_imagenet1k_convert-studio-rgb_20210709_111406-877b1130.pth) | [model](https://drive.google.com/drive/folders/1Ek2wAMlxpajL_M8aub4DKQ9B313K8XhS) | - `Our Pipeline` denote results evaluated with our pipeline. - `StudioGAN` denote results released by Pytorch-StudioGAN. For IS metric, our implementation is different from PyTorch-Studio GAN in the following aspects: 1. We use [Tero's Inception](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for feature extraction. 2. We use bicubic interpolation with PIL backend to resize image before feed them to Inception. For FID evaluation, we follow the pipeline of [BigGAN](https://github.com/ajbrock/BigGAN-PyTorch/blob/98459431a5d618d644d54cd1e9fceb1e5045648d/calculate_inception_moments.py#L52), where the whole training set is adopted to extract inception statistics, and Pytorch Studio GAN uses 50000 randomly selected samples. Besides, we also use [Tero's Inception](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for feature extraction. You can download the preprocessed inception state by the following url: [CIFAR10](https://download.openmmlab.com/mmediting/evaluation/fid_inception_pkl/cifar10.pkl) and [ImageNet1k](https://download.openmmlab.com/mmediting/evaluation/fid_inception_pkl/imagenet.pkl). You can use following commands to extract those inception states by yourself. ``` # For CIFAR10 python tools/utils/inception_stat.py --data-cfg configs/_base_/datasets/cifar10_inception_stat.py --pklname cifar10.pkl --no-shuffle --inception-style stylegan --num-samples -1 --subset train # For ImageNet1k python tools/utils/inception_stat.py --data-cfg configs/_base_/datasets/imagenet_128x128_inception_stat.py --pklname imagenet.pkl --no-shuffle --inception-style stylegan --num-samples -1 --subset train ``` ## Citation ```latex @inproceedings{miyato2018spectral, title={Spectral Normalization for Generative Adversarial Networks}, author={Miyato, Takeru and Kataoka, Toshiki and Koyama, Masanori and Yoshida, Yuichi}, booktitle={International Conference on Learning Representations}, year={2018}, url={https://openreview.net/forum?id=B1QRgziT-}, } ``` ================================================ FILE: configs/sngan_proj/metafile.yml ================================================ Collections: - Name: SNGAN Paper: Title: Spectral Normalization for Generative Adversarial Networks URL: https://openreview.net/forum?id=B1QRgziT- README: configs/sngan_proj/README.md Task: - conditional gans Year: 2018 Models: - Config: configs/sngan_proj/sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py In Collection: SNGAN Name: sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID: 9.8203 IS: 9.6919 Iter: 400000.0 Total Iters\*: 500000.0 disc_step: 5.0 Task: Conditional GANs - Dataset: CIFAR10 Metrics: FID: 8.1158 IS: 9.5659 Iter: 490000.0 Total Iters\*: 500000.0 disc_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4_b64x1_woReLUinplace_fid-iter490000_20210709_163329-ba0862a0.pth - Config: configs/sngan_proj/sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py In Collection: SNGAN Name: sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID: 8.3462 IS: 9.5564 Iter: 490000.0 Total Iters\*: 500000.0 disc_step: 5.0 Task: Conditional GANs - Dataset: CIFAR10 Metrics: FID: 8.3462 IS: 9.5564 Iter: 490000.0 Total Iters\*: 500000.0 disc_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_cifar10_32_lr-2e-4-b64x1_wReLUinplace_fid-iter490000_20210709_203038-191b2648.pth - Config: configs/sngan_proj/sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py In Collection: SNGAN Name: sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128 Results: - Dataset: ImageNet Metrics: FID: 33.4682 IS: 30.0651 Iter: 952000.0 Total Iters\*: 1000000.0 disc_step: 5.0 Task: Conditional GANs - Dataset: ImageNet Metrics: FID: 32.6193 IS: 29.5779 Iter: 989000.0 Total Iters\*: 1000000.0 disc_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_woReLUinplace_fid-iter988000_20210730_131424-061bf803.pth - Config: configs/sngan_proj/sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py In Collection: SNGAN Name: sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128 Results: - Dataset: ImageNet Metrics: FID: 34.3383 IS: 28.1799 Iter: 944000.0 Total Iters\*: 1000000.0 disc_step: 5.0 Task: Conditional GANs - Dataset: ImageNet Metrics: FID: 33.4821 IS: 27.7948 Iter: 988000.0 Total Iters\*: 1000000.0 disc_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_proj_imagenet1k_128_Glr2e-4_Dlr5e-5_ndisc5_b128x2_wReLUinplace_fid-iter988000_20210730_132401-9a682411.pth - Config: configs/sngan_proj/sngan-proj-cvt-studioGAN_cifar10-32x32.py In Collection: SNGAN Name: sngan-proj-cvt-studioGAN_cifar10-32x32 Results: - Dataset: CIFAR10 Metrics: FID (Our Pipeline): 10.2011 FID (StudioGAN): 13.248 IS (Our Pipeline): 9.372 IS (StudioGAN): 8.677 Total Iters: 100000.0 disc_step: 5.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_cifar10_convert-studio-rgb_20210709_111346-2979202d.pth - Config: configs/sngan_proj/sngan-proj-cvt-studioGAN_imagenet1k-128x128.py In Collection: SNGAN Name: sngan-proj-cvt-studioGAN_imagenet1k-128x128 Results: - Dataset: ImageNet Metrics: FID (Our Pipeline): 29.8199 FID (StudioGAN): 26.792 IS (Our Pipeline): 30.218 IS (StudioGAN): 32.247 Total Iters: 1000000.0 disc_step: 2.0 Task: Conditional GANs Weights: https://download.openmmlab.com/mmediting/sngan_proj/sngan_imagenet1k_convert-studio-rgb_20210709_111406-877b1130.pth ================================================ FILE: configs/sngan_proj/sngan-proj-cvt-studioGAN_cifar10-32x32.py ================================================ # _base_ = ['../_base_/models/base_sngan_proj_32x32.py'] _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_32x32.py', '../_base_/datasets/cifar10_nopad.py', '../_base_/default_runtime.py' ] # NOTE: # * CIFAR is loaded in 'RGB' # * studio GAN train their model in 'RGB' order model = dict( data_preprocessor=dict(output_channel_order='BGR'), generator=dict(rgb_to_bgr=True)) # NOTE: do not support training for converted configs train_cfg = train_dataloader = optim_wrapper = None # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # EVALUATION val_dataloader = test_dataloader = dict(batch_size=128) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sngan_proj/sngan-proj-cvt-studioGAN_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_128x128.py', '../_base_/datasets/imagenet_noaug_128.py', '../_base_/default_runtime.py' ] # NOTE: studio GAN train their model in 'RGB' order model = dict(generator=dict(rgb_to_bgr=True)) # NOTE: do not support training for converted configs train_cfg = train_dataloader = optim_wrapper = None # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # EVALUATION val_dataloader = test_dataloader = dict(batch_size=128) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sngan_proj/sngan-proj_wReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_128x128.py', '../_base_/datasets/imagenet_128.py', '../_base_/gen_default_runtime.py', ] # MODEL discriminator_steps = 5 num_classes = 1000 init_cfg = dict(type='studio') model = dict( num_classes=num_classes, generator=dict( num_classes=num_classes, act_cfg=dict(type='ReLU', inplace=True), init_cfg=init_cfg), discriminator=dict( num_classes=num_classes, act_cfg=dict(type='ReLU', inplace=True), init_cfg=init_cfg), discriminator_steps=discriminator_steps) # TRAINING train_cfg = dict( max_iters=500000 * discriminator_steps, val_interval=10000, dynamic_intervals=[(800000, 4000)]) train_dataloader = dict(batch_size=128) # train on 2 gpus optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # EVALUATION val_dataloader = test_dataloader = dict(batch_size=128) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sngan_proj/sngan-proj_wReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py ================================================ # follow pytorch GAN-Studio, random flip is used in the dataset _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_32x32.py', '../_base_/datasets/cifar10_nopad.py', '../_base_/gen_default_runtime.py', ] # MODEL discriminator_steps = 5 num_classes = 10 init_cfg = dict(type='studio') model = dict( num_classes=num_classes, # CIFAR images are RGB, convert to BGR data_preprocessor=dict(output_channel_order='BGR'), generator=dict( act_cfg=dict(type='ReLU', inplace=True), num_classes=num_classes, init_cfg=init_cfg), discriminator=dict( act_cfg=dict(type='ReLU', inplace=True), num_classes=num_classes, init_cfg=init_cfg), discriminator_steps=discriminator_steps) # TRAINING train_cfg = dict(max_iters=100000 * discriminator_steps) train_dataloader = dict(batch_size=64) # train on 1 gpu optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # EVALUATION val_dataloader = test_dataloader = dict(batch_size=64) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sngan_proj/sngan-proj_woReLUinplace_Glr2e-4_Dlr5e-5_ndisc5-2xb128_imagenet1k-128x128.py ================================================ _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_128x128.py', '../_base_/datasets/imagenet_128.py', '../_base_/gen_default_runtime.py', ] # MODEL discriminator_steps = 5 num_classes = 1000 init_cfg = dict(type='studio') model = dict( num_classes=num_classes, generator=dict(num_classes=num_classes, init_cfg=init_cfg), discriminator=dict(num_classes=num_classes, init_cfg=init_cfg), discriminator_steps=discriminator_steps) # TRAINING train_cfg = dict( max_iters=500000 * discriminator_steps, val_interval=10000, dynamic_intervals=[(800000, 4000)]) train_dataloader = dict(batch_size=128) # train on 2 gpus optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.00005, betas=(0.0, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/imagenet-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # EVALUATION val_dataloader = test_dataloader = dict(batch_size=128) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/sngan_proj/sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py ================================================ # follow pytorch GAN-Studio, random flip is used in the dataset _base_ = [ '../_base_/models/sngan_proj/base_sngan_proj_32x32.py', '../_base_/datasets/cifar10_nopad.py', '../_base_/gen_default_runtime.py', ] # MODEL discriminator_steps = 5 num_classes = 10 init_cfg = dict(type='studio') model = dict( num_classes=num_classes, # CIFAR images are RGB, convert to BGR data_preprocessor=dict(output_channel_order='BGR'), generator=dict(num_classes=num_classes, init_cfg=init_cfg), discriminator=dict(num_classes=num_classes, init_cfg=init_cfg), discriminator_steps=discriminator_steps) # TRAINING train_cfg = dict(max_iters=100000 * discriminator_steps) train_dataloader = dict(batch_size=64) # train on 1 gpu optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.5, 0.999)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS inception_pkl = './work_dirs/inception_pkl/cifar10-full.pkl' metrics = [ dict( type='InceptionScore', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='orig') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) # EVALUATION val_dataloader = test_dataloader = dict(batch_size=64) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/srcnn/README.md ================================================ # SRCNN (TPAMI'2015) > [Image Super-Resolution Using Deep Convolutional Networks](https://arxiv.org/abs/1501.00092) > **Task**: Image Super-Resolution ## Abstract We propose a deep learning method for single image super-resolution (SR). Our method directly learns an end-to-end mapping between the low/high-resolution images. The mapping is represented as a deep convolutional neural network (CNN) that takes the low-resolution image as the input and outputs the high-resolution one. We further show that traditional sparse-coding-based SR methods can also be viewed as a deep convolutional network. But unlike traditional methods that handle each component separately, our method jointly optimizes all layers. Our deep CNN has a lightweight structure, yet demonstrates state-of-the-art restoration quality, and achieves fast speed for practical on-line usage. We explore different network structures and parameter settings to achieve trade-offs between performance and speed. Moreover, we extend our network to cope with three color channels simultaneously, and show better overall reconstruction quality.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | PSNR | SSIM | Training Resources | Download | | :------------------------------------------------------------------: | :-----: | :-----: | :----: | :----------------: | :--------------------------------------------------------------------------------------------: | | [srcnn_x4k915_1x16_1000k_div2k](./srcnn_x4k915_1xb16-1000k_div2k.py) | Set5 | 28.4316 | 0.8099 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608_120159.log.json) | | [srcnn_x4k915_1x16_1000k_div2k](./srcnn_x4k915_1xb16-1000k_div2k.py) | Set14 | 25.6486 | 0.7014 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608_120159.log.json) | | [srcnn_x4k915_1x16_1000k_div2k](./srcnn_x4k915_1xb16-1000k_div2k.py) | DIV2K | 27.7460 | 0.7854 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608_120159.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py # single-gpu train python tools/train.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth # single-gpu test python tools/test.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth # multi-gpu test ./tools/dist_test.sh configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @article{dong2015image, title={Image super-resolution using deep convolutional networks}, author={Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou}, journal={IEEE transactions on pattern analysis and machine intelligence}, volume={38}, number={2}, pages={295--307}, year={2015}, publisher={IEEE} } ``` ================================================ FILE: configs/srcnn/README_zh-CN.md ================================================ # SRCNN (TPAMI'2015) > **任务**: 图像超分辨率
SRCNN (TPAMI'2015) ```bibtex @article{dong2015image, title={Image super-resolution using deep convolutional networks}, author={Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou}, journal={IEEE transactions on pattern analysis and machine intelligence}, volume={38}, number={2}, pages={295--307}, year={2015}, publisher={IEEE} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 | Set14 | DIV2K | GPU 信息 | 下载 | | :------------------------------------------------------------------: | :--------------: | :---------------: | :--------------: | :------: | :-------------------------------------------------------------------------: | | [srcnn_x4k915_1x16_1000k_div2k](./srcnn_x4k915_1xb16-1000k_div2k.py) | 28.4316 / 0.8099 | 25.6486 / 0.7014 | 27.7460 / 0.7854 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608_120159.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py # 单个GPU上训练 python tools/train.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth # 单个GPU上测试 python tools/test.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth # 多个GPU上测试 ./tools/dist_test.sh configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/srcnn/metafile.yml ================================================ Collections: - Name: SRCNN Paper: Title: Image Super-Resolution Using Deep Convolutional Networks URL: https://arxiv.org/abs/1501.00092 README: configs/srcnn/README.md Task: - image super-resolution Year: 2015 Models: - Config: configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py In Collection: SRCNN Name: srcnn_x4k915_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 28.4316 SSIM: 0.8099 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 25.6486 SSIM: 0.7014 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 27.746 SSIM: 0.7854 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/srcnn/srcnn_x4k915_1x16_1000k_div2k_20200608-4186f232.pth ================================================ FILE: configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'srcnn_x4k915_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='BaseEditModel', generator=dict( type='SRCNNNet', channels=(3, 64, 32, 3), kernel_sizes=(9, 1, 5), upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(metrics=['PSNR'], crop_border=scale), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1000000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[250000, 250000, 250000, 250000], restart_weights=[1, 1, 1, 1], eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/srgan_resnet/README.md ================================================ # SRGAN (CVPR'2016) > [Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network](https://arxiv.org/abs/1609.04802) > **Task**: Image Super-Resolution ## Abstract Despite the breakthroughs in accuracy and speed of single image super-resolution using faster and deeper convolutional neural networks, one central problem remains largely unsolved: how do we recover the finer texture details when we super-resolve at large upscaling factors? The behavior of optimization-based super-resolution methods is principally driven by the choice of the objective function. Recent work has largely focused on minimizing the mean squared reconstruction error. The resulting estimates have high peak signal-to-noise ratios, but they are often lacking high-frequency details and are perceptually unsatisfying in the sense that they fail to match the fidelity expected at the higher resolution. In this paper, we present SRGAN, a generative adversarial network (GAN) for image super-resolution (SR). To our knowledge, it is the first framework capable of inferring photo-realistic natural images for 4x upscaling factors. To achieve this, we propose a perceptual loss function which consists of an adversarial loss and a content loss. The adversarial loss pushes our solution to the natural image manifold using a discriminator network that is trained to differentiate between the super-resolved images and original photo-realistic images. In addition, we use a content loss motivated by perceptual similarity instead of similarity in pixel space. Our deep residual network is able to recover photo-realistic textures from heavily downsampled images on public benchmarks. An extensive mean-opinion-score (MOS) test shows hugely significant gains in perceptual quality using SRGAN. The MOS scores obtained with SRGAN are closer to those of the original high-resolution images than to those obtained with any state-of-the-art method.
## Results and models Evaluated on RGB channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model |Dataset| PSNR | SSIM | Training Resources | Download | | :-------: | :--------: | :--------: | :-------: | :--------: | :--------: | :----------------: | | [msrresnet_x4c64b16_1x16_300k_div2k](./msrresnet_x4c64b16_1xb16-1000k_div2k.py) | Set5|30.2252 | 0.8491 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521_110246.log.json) | | [msrresnet_x4c64b16_1x16_300k_div2k](./msrresnet_x4c64b16_1xb16-1000k_div2k.py) | Set14|26.7762 | 0.7369 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521_110246.log.json) | | [msrresnet_x4c64b16_1x16_300k_div2k](./msrresnet_x4c64b16_1xb16-1000k_div2k.py) | DIV2K|28.9748 | 0.8178 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521_110246.log.json) | | [srgan_x4c64b16_1x16_1000k_div2k](./srgan_x4c64b16_1xb16-1000k_div2k.py) |Set5|27.9499 | 0.7846 |1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200506_191442.log.json) | | [srgan_x4c64b16_1x16_1000k_div2k](./srgan_x4c64b16_1xb16-1000k_div2k.py) |Set14|24.7383 |0.6491 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200506_191442.log.json) | | [srgan_x4c64b16_1x16_1000k_div2k](./srgan_x4c64b16_1xb16-1000k_div2k.py) |DIV2K|26.5697 |0.7365 | 1 | [model](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth) | [log](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200506_191442.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py # single-gpu train python tools/train.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py # multi-gpu train ./tools/dist_train.sh configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth # single-gpu test python tools/test.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth # multi-gpu test ./tools/dist_test.sh configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{ledig2016photo, title={Photo-realistic single image super-resolution using a generative adversarial network}, author={Ledig, Christian and Theis, Lucas and Husz{\'a}r, Ferenc and Caballero, Jose and Cunningham, Andrew and Acosta, Alejandro and Aitken, Andrew and Tejani, Alykhan and Totz, Johannes and Wang, Zehan}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition workshops}, year={2016} } ``` ================================================ FILE: configs/srgan_resnet/README_zh-CN.md ================================================ # SRGAN (CVPR'2016) > **任务**: 图像超分辨率
SRGAN (CVPR'2016) ```bibtex @inproceedings{ledig2016photo, title={Photo-realistic single image super-resolution using a generative adversarial network}, author={Ledig, Christian and Theis, Lucas and Husz{\'a}r, Ferenc and Caballero, Jose and Cunningham, Andrew and Acosta, Alejandro and Aitken, Andrew and Tejani, Alykhan and Totz, Johannes and Wang, Zehan}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition workshops}, year={2016} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 | Set14 | DIV2K | GPU 信息 | 下载 | | :---------------------------------------------------------------------: | :---------------: | :--------------: | :--------------: | :------: | :----------------------------------------------------------------------: | | [msrresnet_x4c64b16_1x16_300k_div2k](./msrresnet_x4c64b16_1xb16-1000k_div2k.py) | 30.2252 / 0.8491 | 26.7762 / 0.7369 | 28.9748 / 0.8178 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521_110246.log.json) | | [srgan_x4c64b16_1x16_1000k_div2k](./srgan_x4c64b16_1xb16-1000k_div2k.py) | 27.9499 / 0.7846 | 24.7383 / 0.6491 | 26.5697 / 0.7365 | 1 | [模型](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200506_191442.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py # 单个GPU上训练 python tools/train.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py # 多个GPU上训练 ./tools/dist_train.sh configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth # 单个GPU上测试 python tools/test.py configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth # 多个GPU上测试 ./tools/dist_test.sh configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/srgan_resnet/metafile.yml ================================================ Collections: - Name: SRGAN Paper: Title: Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network URL: https://arxiv.org/abs/1609.04802 README: configs/srgan_resnet/README.md Task: - image super-resolution Year: 2016 Models: - Config: configs/srgan_resnet/msrresnet_x4c64b16_1xb16-1000k_div2k.py In Collection: SRGAN Name: msrresnet_x4c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 30.2252 SSIM: 0.8491 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 26.7762 SSIM: 0.7369 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 28.9748 SSIM: 0.8178 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth - Config: configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py In Collection: SRGAN Name: srgan_x4c64b16_1xb16-1000k_div2k Results: - Dataset: Set5 Metrics: PSNR: 27.9499 SSIM: 0.7846 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 24.7383 SSIM: 0.6491 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 26.5697 SSIM: 0.7365 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/srgan_x4c64b16_1x16_1000k_div2k_20200606-a1f0810e.pth ================================================ FILE: configs/srgan_resnet/msrresnet_x4c64b16_1xb16-1000k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'msrresnet_x4c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='BaseEditModel', generator=dict( type='MSRResNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=data_root + '/Set14', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_000_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='CosineRestartLR', by_epoch=False, periods=[250000, 250000, 250000, 250000], restart_weights=[1, 1, 1, 1], eta_min=1e-7) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/srgan_resnet/srgan_x4c64b16_1xb16-1000k_div2k.py ================================================ _base_ = './msrresnet_x4c64b16_1xb16-1000k_div2k.py' experiment_name = 'srgan_x4c64b16_1xb16-1000k_div2k' work_dir = f'./work_dirs/{experiment_name}' scale = 4 # load_from = 'https://download.openmmlab.com/mmediting/restorers/srresnet_srgan/msrresnet_x4c64b16_1x16_300k_div2k_20200521-61556be5.pth' # noqa # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings model = dict( type='SRGAN', generator=dict( type='MSRResNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=scale), discriminator=dict(type='ModifiedVGG', in_channels=3, mid_channels=64), pixel_loss=dict(type='L1Loss', loss_weight=1e-2, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'34': 1.0}, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-3, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) # optimizer optim_wrapper = dict( _delete_=True, constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), ) # learning policy param_scheduler = dict( _delete_=True, type='MultiStepLR', by_epoch=False, milestones=[50000, 100000, 200000, 300000], gamma=0.5) train_cfg = dict( type='IterBasedTrainLoop', max_iters=400_000, val_interval=5000) ================================================ FILE: configs/stable_diffusion/README.md ================================================ # Stable Diffusion (2022) > [Stable Diffusion](https://github.com/CompVis/stable-diffusion) > **Task**: Text2Image, Inpainting ## Abstract Stable Diffusion is a latent diffusion model conditioned on the text embeddings of a CLIP text encoder, which allows you to create images from text inputs. This model builds upon the CVPR'22 work [High-Resolution Image Synthesis with Latent Diffusion Models](https://ommer-lab.com/research/latent-diffusion-models/). The official code was released at [stable-diffusion](https://github.com/CompVis/stable-diffusion) and also implemented at [diffusers](https://github.com/huggingface/diffusers). We support this algorithm here to facilitate the community to learn together and compare it with other text2image methods.

A mecha robot in a favela in expressionist style

A Chinese palace is beside a beautiful lake

A panda is having dinner at KFC
## Pretrained models | Model | Task | Dataset | Download | | :----------------------------------------------------------------------------------: | :--------: | :-----: | :------: | | [stable_diffusion_v1.5](./stable-diffusion_ddim_denoisingunet.py) | Text2Image | - | - | | [stable_diffusion_v1.5_tomesd](./stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py) | Text2Image | - | - | | [stable_diffusion_v1.5_inpaint](./stable-diffusion_ddim_denoisingunet-inpaint.py) | Inpainting | - | - | We use stable diffusion v1.5 weights. This model has several weights including vae, unet and clip. You may download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'from_pretrained' in config to the weights dir. Download with git: ```shell git lfs install git clone https://huggingface.co/runwayml/stable-diffusion-v1-5 ``` ## Quick Start Running the following codes, you can get a text-generated image. ```python from mmengine import MODELS, Config from torchvision import utils from mmengine.registry import init_default_scope init_default_scope('mmagic') config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py' config = Config.fromfile(config).copy() # change the 'pretrained_model_path' if you have downloaded the weights manually # config.model.unet.from_pretrained = '/path/to/your/stable-diffusion-v1-5' # config.model.vae.from_pretrained = '/path/to/your/stable-diffusion-v1-5' StableDiffuser = MODELS.build(config.model) prompt = 'A mecha robot in a favela in expressionist style' StableDiffuser = StableDiffuser.to('cuda') image = StableDiffuser.infer(prompt)['samples'][0] image.save('robot.png') ``` To inpaint an image, you could run the following codes. ```python import mmcv from mmengine import MODELS, Config from mmengine.registry import init_default_scope from PIL import Image init_default_scope('mmagic') config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-inpaint.py' config = Config.fromfile(config).copy() # change the 'pretrained_model_path' if you have downloaded the weights manually # config.model.unet.from_pretrained = '/path/to/your/stable-diffusion-inpainting' # config.model.vae.from_pretrained = '/path/to/your/stable-diffusion-inpainting' StableDiffuser = MODELS.build(config.model) prompt = 'a mecha robot sitting on a bench' img_url = 'https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png' # noqa mask_url = 'https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png' # noqa image = Image.fromarray(mmcv.imread(img_url, channel_order='rgb')) mask = Image.fromarray(mmcv.imread(mask_url)).convert('L') StableDiffuser = StableDiffuser.to('cuda') image = StableDiffuser.infer( prompt, image, mask )['samples'][0] image.save('inpaint.png') ``` ## Use ToMe to accelerate your stable diffusion model We support **[tomesd](https://github.com/dbolya/tomesd)** now! It is developed based on [ToMe](https://github.com/facebookresearch/ToMe), an efficient ViT speed-up tool based on token merging. To work on with **tomesd** in `mmagic`, you just need to add `tomesd_cfg` to `model` as shown in [stable_diffusion_v1.5_tomesd](stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py). The only requirement is `torch >= 1.12.1` in order to properly support `torch.Tensor.scatter_reduce()` functionality. Please do check it before running the demo. ```python ... model = dict( type='StableDiffusion', unet=unet, vae=vae, enable_xformers=False, text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, tomesd_cfg=dict( ratio=0.5)) ``` The detailed settings for `tomesd_cfg` are as follows: - `ratio (float)`: The ratio of tokens to merge. For example, 0.4 would reduce the total number of tokens by 40%.The maximum value for this is 1-(1/(`sx` * `sy`)). **By default, the max ratio is 0.75, usually \<= 0.5 is recommended.** Higher values result in more speed-up, but with more visual quality loss. - `max_downsample (int)`: Apply ToMe to layers with at most this amount of downsampling. E.g., 1 only applies to layers with no downsampling, while 8 applies to all layers. Should be chosen from 1, 2, 4, 8. **1, 2 are recommended.** - `sx, sy (int, int)`: The stride for computing dst sets. A higher stride means you can merge more tokens, **default setting of (2, 2) works well in most cases**. `sx` and `sy` do not need to divide image size. - `use_rand (bool)`: Whether or not to allow random perturbations when computing dst sets. By default: True, but if you're having weird artifacts you can try turning this off. - `merge_attn (bool)`: Whether or not to merge tokens for attention **(recommended)**. - `merge_crossattn (bool)`: Whether or not to merge tokens for cross attention **(not recommended)**. - `merge_mlp (bool)`: Whether or not to merge tokens for the mlp layers **(especially not recommended)**. For more details about the **tomesd** setting, please refer to [Token Merging for Stable Diffusion](https://arxiv.org/abs/2303.17604). Then following the code below, you can evaluate the speed-up performance on stable diffusion models or stable-diffusion-based models ([DreamBooth](../dreambooth/README.md), [ControlNet](../controlnet/README.md)). ```python import time import numpy as np from mmengine import MODELS, Config from mmengine.registry import init_default_scope init_default_scope('mmagic') _device = 0 work_dir = '/path/to/your/work_dir' config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py' config = Config.fromfile(config).copy() # # change the 'pretrained_model_path' if you have downloaded the weights manually # config.model.unet.from_pretrained = '/path/to/your/stable-diffusion-v1-5' # config.model.vae.from_pretrained = '/path/to/your/stable-diffusion-v1-5' # w/o tomesd config.model.tomesd_cfg = None StableDiffuser = MODELS.build(config.model).to(f'cuda:{_device}') prompt = 'A mecha robot in a favela in expressionist style' # inference time evaluation params size = 512 ratios = [0.5, 0.75] samples_perprompt = 5 t = time.time() for i in range(100//samples_perprompt): image = StableDiffuser.infer(prompt, height=size, width=size, num_images_per_prompt=samples_perprompt)['samples'][0] if i == 0: image.save(f"{work_dir}/wo_tomesd.png") print(f"Generating 100 images with {samples_perprompt} images per prompt, without ToMe speed-up, time used : {time.time() - t}s") for ratio in ratios: # w/ tomesd config.model.tomesd_cfg = dict(ratio=ratio) sd_model = MODELS.build(config.model).to(f'cuda:{_device}') t = time.time() for i in range(100//samples_perprompt): image = sd_model.infer(prompt, height=size, width=size, num_images_per_prompt=samples_perprompt)['samples'][0] if i == 0: image.save(f"{work_dir}/w_tomesd_ratio_{ratio}.png") print(f"Generating 100 images with {samples_perprompt} images per prompt, merging ratio {ratio}, time used : {time.time() - t}s") ``` Here are some inference performance comparisons running on **single RTX 3090** with `torch 2.0.0+cu118` as backends. The results are reasonable, when enabling `xformers`, the speed-up ratio is a little bit lower. But `tomesd` still effectively reduces the inference time. It is especially recommended that enable `tomesd` when the `image_size` and `num_images_per_prompt` are large, since the number of similar tokens are larger and `tomesd` can achieve better performance. | Model | Task | Dataset | Download | xformer | Ratio | Size / Num images per prompt | Time (s) | | :--------------------------------------------------------------: | :--------: | :-----: | :------: | :-----: | :-------------------------: | :--------------------------: | :-----------------------------------------------: | | [stable_diffusion_v1.5-tomesd](./stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py) | Text2Image | - | - | w/o | w/o tome
0.5
0.75 | 512 / 5 | 542.20
427.65 (↓21.1%)
393.05 (↓27.5%) | | [stable_diffusion_v1.5-tomesd](./stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py) | Text2Image | - | - | w/ | w/o tome
0.5
0.75 | 512 / 5 | 541.64
428.53 (↓20.9%)
396.38 (↓26.8%) |

w/o ToMe

w/ ToMe Speed-up (token merge ratio=0.5)

w/ ToMe Speed-up (token merge ratio=0.75)
## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5). Thanks for the efforts of the community! ## Citation ```bibtex @misc{rombach2021highresolution, title={High-Resolution Image Synthesis with Latent Diffusion Models}, author={Robin Rombach and Andreas Blattmann and Dominik Lorenz and Patrick Esser and Björn Ommer}, year={2021}, eprint={2112.10752}, archivePrefix={arXiv}, primaryClass={cs.CV} } @article{bolya2023tomesd, title={Token Merging for Fast Stable Diffusion}, author={Bolya, Daniel and Hoffman, Judy}, journal={arXiv}, year={2023} } @inproceedings{bolya2023tome, title={Token Merging: Your {ViT} but Faster}, author={Bolya, Daniel and Fu, Cheng-Yang and Dai, Xiaoliang and Zhang, Peizhao and Feichtenhofer, Christoph and Hoffman, Judy}, booktitle={International Conference on Learning Representations}, year={2023} } ``` ================================================ FILE: configs/stable_diffusion/metafile.yml ================================================ Collections: - Name: Stable Diffusion Paper: Title: Stable Diffusion URL: https://github.com/CompVis/stable-diffusion README: configs/stable_diffusion/README.md Task: - text2image - inpainting Year: 2022 Models: - Config: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py In Collection: Stable Diffusion Name: stable-diffusion_ddim_denoisingunet Results: - Dataset: '-' Metrics: {} Task: Text2Image - Config: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py In Collection: Stable Diffusion Name: stable-diffusion_ddim_denoisingunet-tomesd_5e-1 Results: - Dataset: '-' Metrics: {} Task: Text2Image - Dataset: '-' Metrics: Size / Num images per prompt: PSNR: 512.0 SSIM: 5.0 Task: Text2Image - Dataset: '-' Metrics: Size / Num images per prompt: PSNR: 512.0 SSIM: 5.0 Task: Text2Image - Config: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-inpaint.py In Collection: Stable Diffusion Name: stable-diffusion_ddim_denoisingunet-inpaint Results: - Dataset: '-' Metrics: {} Task: Inpainting ================================================ FILE: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-inpaint.py ================================================ # Use DiffuserWrapper! stable_diffusion_v15_url = 'runwayml/stable-diffusion-inpainting' unet = dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url) vae = dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) model = dict( type='StableDiffusionInpaint', unet=unet, vae=vae, enable_xformers=False, text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler) ================================================ FILE: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet-tomesd_5e-1.py ================================================ # MMagic's implementation of Stable Diffusion # unet = dict( # type='DenoisingUnet', # image_size=512, # base_channels=320, # channels_cfg=[1, 2, 4, 4], # unet_type='stable', # act_cfg=dict(type='silu'), # cross_attention_dim=768, # num_heads=8, # in_channels=4, # layers_per_block=2, # down_block_types=[ # 'CrossAttnDownBlock2D', # 'CrossAttnDownBlock2D', # 'CrossAttnDownBlock2D', # 'DownBlock2D', # ], # up_block_types=[ # 'UpBlock2D', # 'CrossAttnUpBlock2D', # 'CrossAttnUpBlock2D', # 'CrossAttnUpBlock2D', # ], # output_cfg=dict(var='fixed')) # vae = dict( # type='EditAutoencoderKL', # act_fn='silu', # block_out_channels=[128, 256, 512, 512], # down_block_types=[ # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # ], # in_channels=3, # latent_channels=4, # layers_per_block=2, # norm_num_groups=32, # out_channels=3, # sample_size=512, # up_block_types=[ # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # ]) # Use DiffuserWrapper! stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' unet = dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url) vae = dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) model = dict( type='StableDiffusion', unet=unet, vae=vae, enable_xformers=False, text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, tomesd_cfg=dict(ratio=0.5)) ================================================ FILE: configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py ================================================ # MMagic's implementation of Stable Diffusion # unet = dict( # type='DenoisingUnet', # image_size=512, # base_channels=320, # channels_cfg=[1, 2, 4, 4], # unet_type='stable', # act_cfg=dict(type='silu'), # cross_attention_dim=768, # num_heads=8, # in_channels=4, # layers_per_block=2, # down_block_types=[ # 'CrossAttnDownBlock2D', # 'CrossAttnDownBlock2D', # 'CrossAttnDownBlock2D', # 'DownBlock2D', # ], # up_block_types=[ # 'UpBlock2D', # 'CrossAttnUpBlock2D', # 'CrossAttnUpBlock2D', # 'CrossAttnUpBlock2D', # ], # output_cfg=dict(var='fixed')) # vae = dict( # type='EditAutoencoderKL', # act_fn='silu', # block_out_channels=[128, 256, 512, 512], # down_block_types=[ # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # 'DownEncoderBlock2D', # ], # in_channels=3, # latent_channels=4, # layers_per_block=2, # norm_num_groups=32, # out_channels=3, # sample_size=512, # up_block_types=[ # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # 'UpDecoderBlock2D', # ]) # Use DiffuserWrapper! stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' unet = dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url) vae = dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) model = dict( type='StableDiffusion', unet=unet, vae=vae, enable_xformers=False, text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler) ================================================ FILE: configs/stable_diffusion_xl/README.md ================================================ # Stable Diffusion XL (2023) > [Stable Diffusion XL](https://arxiv.org/abs/2307.01952) > **Task**: Text2Image, Inpainting ## Abstract We present SDXL, a latent diffusion model for text-to-image synthesis. Compared to previous versions of Stable Diffusion, SDXL leverages a three times larger UNet backbone: The increase of model parameters is mainly due to more attention blocks and a larger cross-attention context as SDXL uses a second text encoder. We design multiple novel conditioning schemes and train SDXL on multiple aspect ratios. We also introduce a refinement model which is used to improve the visual fidelity of samples generated by SDXL using a post-hoc image-to-image technique. We demonstrate that SDXL shows drastically improved performance compared the previous versions of Stable Diffusion and achieves results competitive with those of black-box state-of-the-art image generators.
## Pretrained models | Model | Task | Dataset | Download | | :----------------------------------------------------------------: | :--------: | :-----: | :------: | | [stable_diffusion_xl](./stable-diffusion_xl_ddim_denoisingunet.py) | Text2Image | - | - | We use stable diffusion xl weights. This model has several weights including vae, unet and clip. You may download the weights from [stable-diffusion-xl](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0) and change the 'from_pretrained' in config to the weights dir. ## Quick Start Running the following codes, you can get a text-generated image. ```python from mmengine import MODELS, Config from mmengine.registry import init_default_scope init_default_scope('mmagic') config = 'configs/stable_diffusion_xl/stable-diffusion_xl_ddim_denoisingunet.py' config = Config.fromfile(config).copy() StableDiffuser = MODELS.build(config.model) prompt = 'A mecha robot in a favela in expressionist style' StableDiffuser = StableDiffuser.to('cuda') image = StableDiffuser.infer(prompt)['samples'][0] image.save('robot.png') ``` ## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-xl](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0). Thanks for the efforts of the community! ================================================ FILE: configs/stable_diffusion_xl/metafile.yml ================================================ Collections: - Name: Stable Diffusion XL Paper: Title: Stable Diffusion XL URL: https://arxiv.org/abs/2307.01952 README: configs/stable_diffusion_xl/README.md Task: - text2image - inpainting Year: 2023 Models: - Config: configs/stable_diffusion_xl/stable-diffusion_xl_ddim_denoisingunet.py In Collection: Stable Diffusion XL Name: stable-diffusion_xl_ddim_denoisingunet Results: - Dataset: '-' Metrics: {} Task: Text2Image ================================================ FILE: configs/stable_diffusion_xl/stable-diffusion_xl_ddim_denoisingunet.py ================================================ # Use DiffuserWrapper! stable_diffusion_xl_url = 'stabilityai/stable-diffusion-xl-base-1.0' unet = dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_xl_url) vae = dict( type='AutoencoderKL', from_pretrained=stable_diffusion_xl_url, subfolder='vae') diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) model = dict( type='StableDiffusionXL', unet=unet, vae=vae, enable_xformers=False, text_encoder_one=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_xl_url, subfolder='text_encoder'), tokenizer_one=stable_diffusion_xl_url, text_encoder_two=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_xl_url, subfolder='text_encoder_2'), tokenizer_two=stable_diffusion_xl_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler) ================================================ FILE: configs/styleganv1/README.md ================================================ # StyleGANv1 (CVPR'2019) > [A Style-Based Generator Architecture for Generative Adversarial Networks](https://openaccess.thecvf.com/content_CVPR_2019/html/Karras_A_Style-Based_Generator_Architecture_for_Generative_Adversarial_Networks_CVPR_2019_paper.html) > **Task**: Unconditional GANs ## Abstract We propose an alternative generator architecture for generative adversarial networks, borrowing from style transfer literature. The new architecture leads to an automatically learned, unsupervised separation of high-level attributes (e.g., pose and identity when trained on human faces) and stochastic variation in the generated images (e.g., freckles, hair), and it enables intuitive, scale-specific control of the synthesis. The new generator improves the state-of-the-art in terms of traditional distribution quality metrics, leads to demonstrably better interpolation properties, and also better disentangles the latent factors of variation. To quantify interpolation quality and disentanglement, we propose two new, automated methods that are applicable to any generator architecture. Finally, we introduce a new, highly varied and high-quality dataset of human faces.
## Results and Models
Results (compressed) from StyleGANv1 trained by mmagic
| Model | Dataset | FID50k | P&R50k_full | Download | | :-----------------------------------------------------------------: | :-----: | :----: | :-----------: | :---------------------------------------------------------------------------------------------------------: | | [styleganv1_ffhq_256](./styleganv1_ffhq-256x256_8xb4-25Mimgs.py) | FFHQ | 6.090 | 70.228/27.050 | [model](https://download.openmmlab.com/mmediting/styleganv1/styleganv1_ffhq_256_g8_25Mimg_20210407_161748-0094da86.pth) | | [styleganv1_ffhq_1024](./styleganv1_ffhq-1024x1024_8xb4-25Mimgs.py) | FFHQ | 4.056 | 70.302/36.869 | [model](https://download.openmmlab.com/mmediting/styleganv1/styleganv1_ffhq_1024_g8_25Mimg_20210407_161627-850a7234.pth) | ## Citation ```latex @inproceedings{karras2019style, title={A style-based generator architecture for generative adversarial networks}, author={Karras, Tero and Laine, Samuli and Aila, Timo}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={4401--4410}, year={2019}, url={https://openaccess.thecvf.com/content_CVPR_2019/html/Karras_A_Style-Based_Generator_Architecture_for_Generative_Adversarial_Networks_CVPR_2019_paper.html}, } ``` ================================================ FILE: configs/styleganv1/metafile.yml ================================================ Collections: - Name: StyleGANv1 Paper: Title: A Style-Based Generator Architecture for Generative Adversarial Networks URL: https://openaccess.thecvf.com/content_CVPR_2019/html/Karras_A_Style-Based_Generator_Architecture_for_Generative_Adversarial_Networks_CVPR_2019_paper.html README: configs/styleganv1/README.md Task: - unconditional gans Year: 2019 Models: - Config: configs/styleganv1/styleganv1_ffhq-256x256_8xb4-25Mimgs.py In Collection: StyleGANv1 Name: styleganv1_ffhq-256x256_8xb4-25Mimgs Results: - Dataset: FFHQ Metrics: FID50k: 6.09 P&R50k_full: PSNR: 70.228 SSIM: 27.05 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/styleganv1/styleganv1_ffhq_256_g8_25Mimg_20210407_161748-0094da86.pth - Config: configs/styleganv1/styleganv1_ffhq-1024x1024_8xb4-25Mimgs.py In Collection: StyleGANv1 Name: styleganv1_ffhq-1024x1024_8xb4-25Mimgs Results: - Dataset: FFHQ Metrics: FID50k: 4.056 P&R50k_full: PSNR: 70.302 SSIM: 36.869 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/styleganv1/styleganv1_ffhq_1024_g8_25Mimg_20210407_161627-850a7234.pth ================================================ FILE: configs/styleganv1/styleganv1_ffhq-1024x1024_8xb4-25Mimgs.py ================================================ _base_ = [ '../_base_/models/base_styleganv1.py', '../_base_/datasets/grow_scale_imgs_ffhq_styleganv1.py', '../_base_/gen_default_runtime.py', ] # MODEL model_wrapper_cfg = dict(find_unused_parameters=True) ema_half_life = 10. # G_smoothing_kimg ema_config = dict( interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( generator=dict(out_size=1024), discriminator=dict(in_size=1024), nkimgs_per_scale={ '8': 1200, '16': 1200, '32': 1200, '64': 1200, '128': 1200, '256': 1200, '512': 1200, '1024': 166000 }, ema_config=ema_config) # TRAIN train_cfg = dict(max_iters=670000) optim_wrapper = dict( constructor='PGGANOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=dict( generator={ '128': 0.0015, '256': 0.002, '512': 0.003, '1024': 0.003 }, discriminator={ '128': 0.0015, '256': 0.002, '512': 0.003, '1024': 0.003 })) # VIS_HOOK + DATAFETCH custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')), dict(type='PGGANFetchDataHook') ] # METRICS inception_pkl = './work_dirs/ffhq1024-full.pkl' metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, k=3, prefix='PR-50K'), ] default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv1/styleganv1_ffhq-256x256_8xb4-25Mimgs.py ================================================ _base_ = [ '../_base_/models/base_styleganv1.py', '../_base_/datasets/grow_scale_imgs_ffhq_styleganv1.py', '../_base_/gen_default_runtime.py', ] # MODEL model_wrapper_cfg = dict(find_unused_parameters=True) ema_half_life = 10. # G_smoothing_kimg ema_config = dict( interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), nkimgs_per_scale={ '8': 1200, '16': 1200, '32': 1200, '64': 1200, '128': 1200, '256': 190000 }, ema_config=ema_config) # TRAIN train_cfg = dict(max_iters=670000) optim_wrapper = dict( constructor='PGGANOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=dict( generator={ '128': 0.0015, '256': 0.002 }, discriminator={ '128': 0.0015, '256': 0.002 })) # VIS_HOOK + DATAFETCH custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')), dict(type='PGGANFetchDataHook') ] # METRICS inception_pkl = './work_dirs/ffhq256-full.pkl' metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl=inception_pkl, sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, k=3, prefix='PR-50K'), ] default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) # use low resolution image to evaluate # NOTE: use cherry-picked file list? # val_dataloader = test_dataloader = dict( # dataset=dict( # data_root='./data/ffhq/ffhq_imgs/ffhq_256', # file_list='./data/ffhq256.txt')) val_dataloader = test_dataloader = dict( dataset=dict(data_root='./data/ffhq/ffhq_imgs/ffhq_256')) val_evaluator = test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/README.md ================================================ # StyleGANv2 (CVPR'2020) > [Analyzing and Improving the Image Quality of Stylegan](https://openaccess.thecvf.com/content_CVPR_2020/html/Karras_Analyzing_and_Improving_the_Image_Quality_of_StyleGAN_CVPR_2020_paper.html) > **Task**: Unconditional GANs ## Abstract The style-based GAN architecture (StyleGAN) yields state-of-the-art results in data-driven unconditional generative image modeling. We expose and analyze several of its characteristic artifacts, and propose changes in both model architecture and training methods to address them. In particular, we redesign the generator normalization, revisit progressive growing, and regularize the generator to encourage good conditioning in the mapping from latent codes to images. In addition to improving image quality, this path length regularizer yields the additional benefit that the generator becomes significantly easier to invert. This makes it possible to reliably attribute a generated image to a particular network. We furthermore visualize how well the generator utilizes its output resolution, and identify a capacity problem, motivating us to train larger models for additional quality improvements. Overall, our improved model redefines the state of the art in unconditional image modeling, both in terms of existing distribution quality metrics as well as perceived image quality.
## Results and Models
Results (compressed) from StyleGAN2 config-f trained by mmagic
| Model | Dataset | Comment | FID50k | Precision50k | Recall50k | Download | | :----------------------------------------------------------------------: | :---------: | :-------------: | :----: | :----------: | :-------: | :-------------------------------------------------------------------------: | | [stylegan2_c2_8xb4_ffhq-1024x1024](./stylegan2_c2_8xb4_ffhq-1024x1024.py) | FFHQ | official weight | 2.8134 | 62.856 | 49.400 | [model](https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-ffhq-config-f-official_20210327_171224-bce9310c.pth) | | [stylegan2_c2_8xb4_lsun-car-384x512](./stylegan2_c2_8xb4_lsun-car-384x512.py) | LSUN_CAR | official weight | 5.4316 | 65.986 | 48.190 | [model](https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-car-config-f-official_20210327_172340-8cfe053c.pth) | | [stylegan2_c2_8xb4-800kiters_lsun-horse-256x256](./stylegan2_c2_8xb4-800kiters_lsun-horse-256x256.py) | LSUN_HORSE | official weight | - | - | - | [model](https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-horse-config-f-official_20210327_173203-ef3e69ca.pth) | | [stylegan2_c2_8xb4-800kiters_lsun-church-256x256](./stylegan2_c2_8xb4-800kiters_lsun-church-256x256.py) | LSUN_CHURCH | official weight | - | - | - | [model](https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-church-config-f-official_20210327_172657-1d42b7d1.pth) | | [stylegan2_c2_8xb4-800kiters_lsun-cat-256x256](./stylegan2_c2_8xb4-800kiters_lsun-cat-256x256.py) | LSUN_CAT | official weight | - | - | - | [model](https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-cat-config-f-official_20210327_172444-15bc485b.pth) | | [stylegan2_c2_8xb4-800kiters_ffhq-256x256](./stylegan2_c2_8xb4-800kiters_ffhq-256x256.py) | FFHQ | our training | 3.992 | 69.012 | 40.417 | [model](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth) | | [stylegan2_c2_8xb4_ffhq-1024x1024](./stylegan2_c2_8xb4_ffhq-1024x1024.py) | FFHQ | our training | 2.8185 | 68.236 | 49.583 | [model](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_1024_b4x8_20210407_150045-618c9024.pth) | | [stylegan2_c2_8xb4_lsun-car-384x512](./stylegan2_c2_8xb4_lsun-car-384x512.py) | LSUN_CAR | our training | 2.4116 | 66.760 | 50.576 | [model](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_lsun-car_384x512_b4x8_1800k_20210424_160929-fc9072ca.pth) | ## FP16 Support and Experiments Currently, we have supported FP16 training for StyleGAN2, and here are the results for the mixed-precision training. (Experiments for FFHQ1024 will come soon.)
Evaluation FID for FP32 and FP16 training
As shown in the figure, we provide **3** ways to do mixed-precision training for `StyleGAN2`: - [stylegan2_c2_fp16_PL-no-scaler](./stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py): In this setting, we try our best to follow the official FP16 implementation in [StyleGAN2-ADA](https://github.com/NVlabs/stylegan2-ada). Similar to the official version, we only adopt FP16 training for the higher-resolution feature maps (the last 4 stages in G and the first 4 stages). Note that we do not adopt the `clamp` way to avoid gradient overflow used in the official implementation. We use the `autocast` function from `torch.cuda.amp` package. - [stylegan2_c2_fp16-globalG-partialD_PL-R1-no-scaler](./stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256.py): In this config, we try to adopt mixed-precision training for the whole generator, but in partial discriminator (the first 4 higher-resolution stages). Note that we do not apply the loss scaler in the path length loss and gradient penalty loss. Because we always meet divergence after adopting the loss scaler to scale the gradient in these two losses. - [stylegan2_c2_apex_fp16_PL-R1-no-scaler](./stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256.py): In this setting, we adopt the [APEX](https://github.com/NVIDIA/apex) toolkit to implement mixed-precision training with multiple loss/gradient scalers. In APEX, you can assign different loss scalers for the generator and the discriminator respectively. Note that we still ignore the gradient scaler in the path length loss and gradient penalty loss. | Model | Comment | Dataset | FID50k | Download | | :----------------------------------------------------------------------: | :-------------------------------------: | :-----: | :----: | :--------------------------------------------------------------------------: | | [stylegan2_c2_8xb4-800kiters_ffhq-256x256](./stylegan2_c2_8xb4-800kiters_ffhq-256x256.py) | baseline | FFHQ256 | 3.992 | [ckpt](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth) | | [stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256](./stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py) | partial layers in fp16 | FFHQ256 | 4.331 | [ckpt](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_fp16_partial-GD_PL-no-scaler_ffhq_256_b4x8_800k_20210508_114854-dacbe4c9.pth) | | [stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256](./stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256.py) | the whole G in fp16 | FFHQ256 | 4.362 | [ckpt](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_fp16-globalG-partialD_PL-R1-no-scaler_ffhq_256_b4x8_800k_20210508_114930-ef8270d4.pth) | | [stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256](./stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256.py) | the whole G&D in fp16 + two loss scaler | FFHQ256 | 4.614 | [ckpt](https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_apex_fp16_PL-R1-no-scaler_ffhq_256_b4x8_800k_20210508_114701-c2bb8afd.pth) | As shown in this table, `P&R50k_full` is the metric used in StyleGANv1 and StyleGANv2. `full` indicates that we use the whole dataset for extracting the real distribution, e.g., 70000 images in FFHQ dataset. However, adopting the VGG16 provided from [Tero](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt) requires that your PyTorch version must fulfill `>=1.6.0`. Be careful about using the PyTorch's VGG16 to extract features, which will cause higher precision and recall. ## Citation ```latex @inproceedings{karras2020analyzing, title={Analyzing and improving the image quality of stylegan}, author={Karras, Tero and Laine, Samuli and Aittala, Miika and Hellsten, Janne and Lehtinen, Jaakko and Aila, Timo}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={8110--8119}, year={2020}, url={https://openaccess.thecvf.com/content_CVPR_2020/html/Karras_Analyzing_and_Improving_the_Image_Quality_of_StyleGAN_CVPR_2020_paper.html}, } ``` ================================================ FILE: configs/styleganv2/metafile.yml ================================================ Collections: - Name: StyleGANv2 Paper: Title: Analyzing and Improving the Image Quality of Stylegan URL: https://openaccess.thecvf.com/content_CVPR_2020/html/Karras_Analyzing_and_Improving_the_Image_Quality_of_StyleGAN_CVPR_2020_paper.html README: configs/styleganv2/README.md Task: - unconditional gans Year: 2020 Models: - Config: configs/styleganv2/stylegan2_c2_8xb4_ffhq-1024x1024.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4_ffhq-1024x1024 Results: - Dataset: FFHQ Metrics: FID50k: 2.8134 Precision50k: 62.856 Recall50k: 49.4 Task: Unconditional GANs - Dataset: FFHQ Metrics: FID50k: 2.8185 Precision50k: 68.236 Recall50k: 49.583 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_1024_b4x8_20210407_150045-618c9024.pth - Config: configs/styleganv2/stylegan2_c2_8xb4_lsun-car-384x512.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4_lsun-car-384x512 Results: - Dataset: LSUN_CAR Metrics: FID50k: 5.4316 Precision50k: 65.986 Recall50k: 48.19 Task: Unconditional GANs - Dataset: LSUN_CAR Metrics: FID50k: 2.4116 Precision50k: 66.76 Recall50k: 50.576 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_lsun-car_384x512_b4x8_1800k_20210424_160929-fc9072ca.pth - Config: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-horse-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4-800kiters_lsun-horse-256x256 Results: - Dataset: LSUN_HORSE Metrics: {} Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-horse-config-f-official_20210327_173203-ef3e69ca.pth - Config: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-church-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4-800kiters_lsun-church-256x256 Results: - Dataset: LSUN_CHURCH Metrics: {} Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-church-config-f-official_20210327_172657-1d42b7d1.pth - Config: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-cat-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4-800kiters_lsun-cat-256x256 Results: - Dataset: LSUN_CAT Metrics: {} Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-cat-config-f-official_20210327_172444-15bc485b.pth - Config: configs/styleganv2/stylegan2_c2_8xb4-800kiters_ffhq-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2_8xb4-800kiters_ffhq-256x256 Results: - Dataset: FFHQ Metrics: FID50k: 3.992 Precision50k: 69.012 Recall50k: 40.417 Task: Unconditional GANs - Dataset: FFHQ256 Metrics: FID50k: 3.992 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_ffhq_256_b4x8_20210407_160709-7890ae1f.pth - Config: configs/styleganv2/stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256 Results: - Dataset: FFHQ256 Metrics: FID50k: 4.331 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_fp16_partial-GD_PL-no-scaler_ffhq_256_b4x8_800k_20210508_114854-dacbe4c9.pth - Config: configs/styleganv2/stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256 Results: - Dataset: FFHQ256 Metrics: FID50k: 4.362 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_fp16-globalG-partialD_PL-R1-no-scaler_ffhq_256_b4x8_800k_20210508_114930-ef8270d4.pth - Config: configs/styleganv2/stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256.py In Collection: StyleGANv2 Name: stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256 Results: - Dataset: FFHQ256 Metrics: FID50k: 4.614 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan2/stylegan2_c2_apex_fp16_PL-R1-no-scaler_ffhq_256_b4x8_800k_20210508_114701-c2bb8afd.pth ================================================ FILE: configs/styleganv2/stylegan2_c2-PL-R1_8xb4-apex-fp16-no-scaler-800kiters_ffhq-256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = ['./stylegan2_c2_8xb4-800kiters_ffhq-256x256.py'] model = dict(loss_config=dict(r1_use_apex_amp=False, g_reg_use_apex_amp=False)) train_cfg = dict(max_iters=800002) # remain to be refactored apex_amp = dict(mode='gan', init_args=dict(opt_level='O1', num_losses=2)) resume_from = None ================================================ FILE: configs/styleganv2/stylegan2_c2-PL-R1_8xb4-fp16-globalG-partialD-no-scaler-800kiters_ffhq-256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = ['./stylegan2_c2_8xb4-800kiters_ffhq-256x256.py'] model = dict( generator=dict(out_size=256, fp16_enabled=True), discriminator=dict(in_size=256, fp16_enabled=False, num_fp16_scales=4), ) train_cfg = dict(max_iters=800000) optim_wrapper = dict( generator=dict(type='AmpOptimWrapper', loss_scale=512), discriminator=dict(type='AmpOptimWrapper', loss_scale=512)) ================================================ FILE: configs/styleganv2/stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = ['./stylegan2_c2_8xb4-800kiters_ffhq-256x256.py'] model = dict( generator=dict(out_size=256, num_fp16_scales=4), discriminator=dict(in_size=256, num_fp16_scales=4), loss_config=dict(scale_r1_loss=True)) optim_wrapper = dict( generator=dict(type='AmpOptimWrapper', loss_scale=512), discriminator=dict(type='AmpOptimWrapper', loss_scale=512)) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4-800kiters_ffhq-256x256.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/ffhq/ffhq_imgs/ffhq_256' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-cat-256x256.py ================================================ """Note that this config is just for testing.""" _base_ = [ '../_base_/datasets/lsun_stylegan.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-cat' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-church-256x256.py ================================================ """Note that this config is just for testing.""" _base_ = [ '../_base_/datasets/lsun_stylegan.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-church' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4-800kiters_lsun-horse-256x256.py ================================================ """Note that this config is just for testing.""" _base_ = [ '../_base_/datasets/lsun_stylegan.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-horse' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4_ffhq-1024x1024.py ================================================ """Config for the `config-f` setting in StyleGAN2.""" _base_ = [ '../_base_/datasets/ffhq_flip.py', '../_base_/models/base_styleganv2.py', '../_base_/gen_default_runtime.py' ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=1024), discriminator=dict(in_size=1024), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) extra_parameters = dict(num_batches=1, sample_model='orig') train_cfg = dict(max_iters=800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv2/stylegan2_c2_8xb4_lsun-car-384x512.py ================================================ _base_ = [ '../_base_/gen_default_runtime.py', '../_base_/models/base_styleganv2.py', ] # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model = dict( generator=dict(out_size=512), discriminator=dict(in_size=512), ema_config=dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg = dict(max_iters=1800002) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # DATA batch_size = 4 data_root = './data/lsun/images/car' dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='NumpyPad', keys='img', padding=((64, 64), (0, 0), (0, 0)), ), dict(type='Flip', keys=['gt'], direction='horizontal'), dict(type='PackInputs') ] val_pipeline = train_pipeline # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_root=data_root, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_root=data_root, # set by user pipeline=val_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/README.md ================================================ # StyleGANv3 (NeurIPS'2021) > [Alias-Free Generative Adversarial Networks](https://nvlabs-fi-cdn.nvidia.com/stylegan3/stylegan3-paper.pdf) > **Task**: Unconditional GANs ## Abstract We observe that despite their hierarchical convolutional nature, the synthesis process of typical generative adversarial networks depends on absolute pixel coordinates in an unhealthy manner. This manifests itself as, e.g., detail appearing to be glued to image coordinates instead of the surfaces of depicted objects. We trace the root cause to careless signal processing that causes aliasing in the generator network. Interpreting all signals in the network as continuous, we derive generally applicable, small architectural changes that guarantee that unwanted information cannot leak into the hierarchical synthesis process. The resulting networks match the FID of StyleGAN2 but differ dramatically in their internal representations, and they are fully equivariant to translation and rotation even at subpixel scales. Our results pave the way for generative models better suited for video and animation.
## Results and Models
Results (compressed) from StyleGAN3 config-T converted by mmagic
We perform experiments on StyleGANv3 paper settings and also experimental settings. For user convenience, we also offer the converted version of official weights. ### Paper Settings | Model | Dataset | Iter | FID50k | Download | | :---------------------------------------------------------------------------: | :---------------: | :----: | :---------------: | :---------------------------------------------------------------------------------: | | [stylegan3-t](./stylegan3-t_gamma32.8_8xb4-fp16-noaug_ffhq-1024x1024.py) | ffhq 1024x1024 | 490000 | 3.37\* | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma32.8_ffhq_1024_b4x8_best_fid_iter_490000_20220401_120733-4ff83434.pth) \| [log](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma32.8_ffhq_1024_b4x8_20220322_090417.log.json) | | [stylegan3-t-ada](./stylegan3-t_ada-gamma6.6_8xb4-fp16_metfaces-1024x1024.py) | metface 1024x1024 | 130000 | 15.09 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ada_fp16_gamma6.6_metfaces_1024_b4x8_best_fid_iter_130000_20220401_115101-f2ef498e.pth) \| [log](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ada_fp16_gamma6.6_metfaces_1024_b4x8_20220328_142211.log.json) | ### Experimental Settings | Model | Dataset | Iter | FID50k | Download | | :---------------------------------------------------------------------------: | :------------: | :----: | :----: | :-----------------------------------------------------------------------------------------------: | | [stylegan3-t](./stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py) | ffhq 256x256 | 740000 | 4.51 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma2.0_ffhq_256_b4x8_best_fid_iter_740000_20220401_122456-730e1fba.pth) \| [log](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma2.0_ffhq_256_b4x8_20220323_144815.log.json) | | [stylegan3-r-ada](./stylegan3-r_ada-gamma3.3_8xb4-fp16_metfaces-1024x1024.py) | ffhq 1024x1024 | - | - | [ckpt](<>) | ### Converted Weights | Model | Dataset | Comment | FID50k | EQ-T | EQ-R | Download | | :--------------------------------------------------------------------: | :------------: | :-------------: | :----: | :---: | :---: | :-----------------------------------------------------------------------------------: | | [stylegan3-t](./stylegan3-t_cvt-official-rgb_8xb4_ffhqu-256x256.py) | ffhqu 256x256 | official weight | 4.62 | 63.01 | 13.12 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhqu_256_b4x8_cvt_official_rgb_20220329_235046-153df4c8.pth) | | [stylegan3-t](./stylegan3-t_cvt-official-rgb_8xb4_afhqv2-512x512.py) | afhqv2 512x512 | official weight | 4.04 | 60.15 | 13.51 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_afhqv2_512_b4x8_cvt_official_rgb_20220329_235017-ee6b037a.pth) | | [stylegan3-t](./stylegan3-t_cvt-official-rgb_8xb4_ffhq-1024x1024.py) | ffhq 1024x1024 | official weight | 2.79 | 61.21 | 13.82 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhq_1024_b4x8_cvt_official_rgb_20220329_235113-db6c6580.pth) | | [stylegan3-r](./stylegan3-r_cvt-official-rgb_8xb4_ffhqu-256x256.py) | ffhqu 256x256 | official weight | 4.50 | 66.65 | 40.48 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhqu_256_b4x8_cvt_official_rgb_20220329_234909-4521d963.pth) | | [stylegan3-r](./stylegan3-r_cvt-official-rgb_8xb4x8_afhqv2-512x512.py) | afhqv2 512x512 | official weight | 4.40 | 64.89 | 40.34 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_afhqv2_512_b4x8_cvt_official_rgb_20220329_234829-f2eaca72.pth) | | [stylegan3-r](./stylegan3-r_cvt-official-rgb_8xb4_ffhq-1024x1024.py) | ffhq 1024x1024 | official weight | 3.07 | 64.76 | 46.62 | [ckpt](https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhq_1024_b4x8_cvt_official_rgb_20220329_234933-ac0500a1.pth) | ## Interpolation We provide a tool to generate video by walking through GAN's latent space. Run this command to get the following video. ```bash python apps/interpolate_sample.py configs/styleganv3/stylegan3_t_afhqv2_512_b4x8_official.py https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_afhqv2_512_b4x8_cvt_official.pkl --export-video --samples-path work_dirs/demos/ --endpoint 6 --interval 60 --space z --seed 2022 --sample-cfg truncation=0.8 ``` https://user-images.githubusercontent.com/22982797/151506918-83da9ee3-0d63-4c5b-ad53-a41562b92075.mp4 ## Equivarience Visualization && Evaluation We also provide a tool to visualize the equivarience properties for StyleGAN3. Run these commands to get the results below. ```bash python tools/utils/equivariance_viz.py configs/styleganv3/stylegan3_r_ffhqu_256_b4x8_official.py https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhqu_256_b4x8_cvt_official.pkl --translate_max 0.5 --transform rotate --seed 5432 python tools/utils/equivariance_viz.py configs/styleganv3/stylegan3_r_ffhqu_256_b4x8_official.py https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhqu_256_b4x8_cvt_official.pkl --translate_max 0.25 --transform x_t --seed 5432 python tools/utils/equivariance_viz.py configs/styleganv3/stylegan3_r_ffhqu_256_b4x8_official.py https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhqu_256_b4x8_cvt_official.pkl --translate_max 0.25 --transform y_t --seed 5432 ``` https://user-images.githubusercontent.com/22982797/151504902-f3cbfef5-9014-4607-bbe1-deaf48ec6d55.mp4 https://user-images.githubusercontent.com/22982797/151504973-b96e1639-861d-434b-9d7c-411ebd4a653f.mp4 https://user-images.githubusercontent.com/22982797/151505099-cde4999e-aab1-42d4-a458-3bb069db3d32.mp4 If you want to get EQ-Metric for StyleGAN3, just add following codes into config. ```python metrics = dict( eqv=dict( type='Equivariance', num_images=50000, eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True))) ``` And we highly recommend you to use [slurm_test.sh](../../tools/slurm_test.sh) script to accelerate evaluation time. ## Citation ```latex @inproceedings{Karras2021, author = {Tero Karras and Miika Aittala and Samuli Laine and Erik H\"ark\"onen and Janne Hellsten and Jaakko Lehtinen and Timo Aila}, title = {Alias-Free Generative Adversarial Networks}, booktitle = {Proc. NeurIPS}, year = {2021} } ``` ================================================ FILE: configs/styleganv3/metafile.yml ================================================ Collections: - Name: StyleGANv3 Paper: Title: Alias-Free Generative Adversarial Networks URL: https://nvlabs-fi-cdn.nvidia.com/stylegan3/stylegan3-paper.pdf README: configs/styleganv3/README.md Task: - unconditional gans Year: 2021 Models: - Config: configs/styleganv3/stylegan3-t_gamma32.8_8xb4-fp16-noaug_ffhq-1024x1024.py In Collection: StyleGANv3 Name: stylegan3-t_gamma32.8_8xb4-fp16-noaug_ffhq-1024x1024 Results: - Dataset: ffhq1024x1024 Metrics: Iter: 490000.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma32.8_ffhq_1024_b4x8_best_fid_iter_490000_20220401_120733-4ff83434.pth - Config: configs/styleganv3/stylegan3-t_ada-gamma6.6_8xb4-fp16_metfaces-1024x1024.py In Collection: StyleGANv3 Name: stylegan3-t_ada-gamma6.6_8xb4-fp16_metfaces-1024x1024 Results: - Dataset: metface1024x1024 Metrics: FID50k: 15.09 Iter: 130000.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ada_fp16_gamma6.6_metfaces_1024_b4x8_best_fid_iter_130000_20220401_115101-f2ef498e.pth - Config: configs/styleganv3/stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py In Collection: StyleGANv3 Name: stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256 Results: - Dataset: ffhq256x256 Metrics: FID50k: 4.51 Iter: 740000.0 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_noaug_fp16_gamma2.0_ffhq_256_b4x8_best_fid_iter_740000_20220401_122456-730e1fba.pth - Config: configs/styleganv3/stylegan3-r_ada-gamma3.3_8xb4-fp16_metfaces-1024x1024.py In Collection: StyleGANv3 Name: stylegan3-r_ada-gamma3.3_8xb4-fp16_metfaces-1024x1024 Results: - Dataset: ffhq1024x1024 Metrics: {} Task: Unconditional GANs Weights: <> - Config: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_ffhqu-256x256.py In Collection: StyleGANv3 Name: stylegan3-t_cvt-official-rgb_8xb4_ffhqu-256x256 Results: - Dataset: ffhqu256x256 Metrics: EQ-R: 13.12 EQ-T: 63.01 FID50k: 4.62 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhqu_256_b4x8_cvt_official_rgb_20220329_235046-153df4c8.pth - Config: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_afhqv2-512x512.py In Collection: StyleGANv3 Name: stylegan3-t_cvt-official-rgb_8xb4_afhqv2-512x512 Results: - Dataset: afhqv2512x512 Metrics: EQ-R: 13.51 EQ-T: 60.15 FID50k: 4.04 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_afhqv2_512_b4x8_cvt_official_rgb_20220329_235017-ee6b037a.pth - Config: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_ffhq-1024x1024.py In Collection: StyleGANv3 Name: stylegan3-t_cvt-official-rgb_8xb4_ffhq-1024x1024 Results: - Dataset: ffhq1024x1024 Metrics: EQ-R: 13.82 EQ-T: 61.21 FID50k: 2.79 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhq_1024_b4x8_cvt_official_rgb_20220329_235113-db6c6580.pth - Config: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4_ffhqu-256x256.py In Collection: StyleGANv3 Name: stylegan3-r_cvt-official-rgb_8xb4_ffhqu-256x256 Results: - Dataset: ffhqu256x256 Metrics: EQ-R: 40.48 EQ-T: 66.65 FID50k: 4.5 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhqu_256_b4x8_cvt_official_rgb_20220329_234909-4521d963.pth - Config: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4x8_afhqv2-512x512.py In Collection: StyleGANv3 Name: stylegan3-r_cvt-official-rgb_8xb4x8_afhqv2-512x512 Results: - Dataset: afhqv2512x512 Metrics: EQ-R: 40.34 EQ-T: 64.89 FID50k: 4.4 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_afhqv2_512_b4x8_cvt_official_rgb_20220329_234829-f2eaca72.pth - Config: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4_ffhq-1024x1024.py In Collection: StyleGANv3 Name: stylegan3-r_cvt-official-rgb_8xb4_ffhq-1024x1024 Results: - Dataset: ffhq1024x1024 Metrics: EQ-R: 46.62 EQ-T: 64.76 FID50k: 3.07 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhq_1024_b4x8_cvt_official_rgb_20220329_234933-ac0500a1.pth ================================================ FILE: configs/styleganv3/stylegan3-r_ada-gamma3.3_8xb4-fp16_metfaces-1024x1024.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/ffhq_flip.py', '../_base_/gen_default_runtime.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } r1_gamma = 3.3 # set by user d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) load_from = 'https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhq_1024_b4x8_cvt_official_rgb_20220329_234933-ac0500a1.pth' # noqa # ada settings aug_kwargs = { 'xflip': 1, 'rotate90': 1, 'xint': 1, 'scale': 1, 'rotate': 1, 'aniso': 1, 'xfrac': 1, 'brightness': 1, 'contrast': 1, 'lumaflip': 1, 'hue': 1, 'saturation': 1 } ema_half_life = 10. # G_smoothing_kimg ema_kimg = 10 ema_nimg = ema_kimg * 1000 ema_beta = 0.5**(32 / max(ema_nimg, 1e-8)) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=ema_beta, start_iter=0) model = dict( generator=dict( out_size=1024, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict( type='ADAStyleGAN2Discriminator', in_size=1024, input_bgr2rgb=True, data_aug=dict(type='ADAAug', aug_pipeline=aug_kwargs, ada_kimg=100)), loss_config=dict( r1_loss_weight=r1_gamma / 2.0 * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC'), ema_config=ema_config) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/metfaces/images/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=160000) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4_ffhq-1024x1024.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/ffhq_flip.py', '../_base_/gen_default_runtime.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } r1_gamma = 32.8 d_reg_interval = 16 model = dict( generator=dict( out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg, rgb2bgr=True), discriminator=dict(type='StyleGAN2Discriminator', in_size=1024)) batch_size = 4 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4_ffhqu-256x256.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/unconditional_imgs_flip_lanczos_resize_256x256.py', '../_base_/gen_default_runtime.py' ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 32768, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } model = dict( generator=dict( out_size=256, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1)) batch_size = 4 data_root = './data/ffhqu/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-r_cvt-official-rgb_8xb4x8_afhqv2-512x512.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/gen_default_runtime.py', '../_base_/datasets/unconditional_imgs_flip_512x512.py' ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } model = dict( generator=dict( type='StyleGANv3Generator', noise_size=512, style_channels=512, out_size=512, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(type='StyleGAN2Discriminator', in_size=512)) batch_size = 4 data_root = 'data/afhqv2/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_ada-gamma6.6_8xb4-fp16_metfaces-1024x1024.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/ffhq_flip.py', '../_base_/gen_default_runtime.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 6.6 # set by user d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) load_from = 'https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhq_1024_b4x8_cvt_official_rgb_20220329_235113-db6c6580.pth' # noqa # ada settings aug_kwargs = { 'xflip': 1, 'rotate90': 1, 'xint': 1, 'scale': 1, 'rotate': 1, 'aniso': 1, 'xfrac': 1, 'brightness': 1, 'contrast': 1, 'lumaflip': 1, 'hue': 1, 'saturation': 1 } ema_half_life = 10. # G_smoothing_kimg ema_kimg = 10 ema_nimg = ema_kimg * 1000 ema_beta = 0.5**(32 / max(ema_nimg, 1e-8)) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=ema_beta, start_iter=0) model = dict( generator=dict( out_size=1024, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict( type='ADAStyleGAN2Discriminator', in_size=1024, input_bgr2rgb=True, data_aug=dict(type='ADAAug', aug_pipeline=aug_kwargs, ada_kimg=100)), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/metfaces/images/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=160000) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_afhqv2-512x512.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/gen_default_runtime.py', '../_base_/datasets/unconditional_imgs_flip_512x512.py' ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model = dict( generator=dict( out_size=512, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=512)) batch_size = 4 data_root = 'data/afhqv2/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_ffhq-1024x1024.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/gen_default_runtime.py', '../_base_/datasets/ffhq_flip.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model = dict( generator=dict( out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg, rgb2bgr=True), discriminator=dict(in_size=1024)) batch_size = 4 data_root = './data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_cvt-official-rgb_8xb4_ffhqu-256x256.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/gen_default_runtime.py', '../_base_/datasets/unconditional_imgs_flip_lanczos_resize_256x256.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 16384, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model = dict( generator=dict( out_size=256, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1)) batch_size = 4 data_root = './data/ffhqu/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/unconditional_imgs_flip_lanczos_resize_256x256.py', '../_base_/gen_default_runtime.py', ] synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 16384, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 2. # set by user d_reg_interval = 16 ema_config = dict( type='RampUpEMA', interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=32, eps=1e-8, start_iter=0) model = dict( generator=dict(out_size=256, img_channels=3, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=800002) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='Equivariance', fake_nums=50000, sample_mode='ema', prefix='EQ', eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True)) ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/styleganv3/stylegan3-t_gamma32.8_8xb4-fp16-noaug_ffhq-1024x1024.py ================================================ _base_ = [ '../_base_/models/base_styleganv3.py', '../_base_/datasets/ffhq_flip.py', '../_base_/gen_default_runtime.py', ] batch_size = 32 magnitude_ema_beta = 0.5**(batch_size / (20 * 1e3)) synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 32.8 d_reg_interval = 16 ema_config = dict( type='RampUpEMA', interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=batch_size, eps=1e-8, start_iter=0) model = dict( generator=dict(out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=1024), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper = dict( generator=dict( optimizer=dict( type='Adam', lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type='Adam', lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/ffhq/images' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=800002) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: configs/swinir/README.md ================================================ # SwinIR (ICCVW'2021) > [SwinIR: Image Restoration Using Swin Transformer](https://arxiv.org/abs/2108.10257) > **Task**: Image Super-Resolution, Image denoising, JPEG compression artifact reduction ## Abstract Image restoration is a long-standing low-level vision problem that aims to restore high-quality images from low-quality images (e.g., downscaled, noisy and compressed images). While state-of-the-art image restoration methods are based on convolutional neural networks, few attempts have been made with Transformers which show impressive performance on high-level vision tasks. In this paper, we propose a strong baseline model SwinIR for image restoration based on the Swin Transformer. SwinIR consists of three parts: shallow feature extraction, deep feature extraction and high-quality image reconstruction. In particular, the deep feature extraction module is composed of several residual Swin Transformer blocks (RSTB), each of which has several Swin Transformer layers together with a residual connection. We conduct experiments on three representative tasks: image super-resolution (including classical, lightweight and real-world image super-resolution), image denoising (including grayscale and color image denoising) and JPEG compression artifact reduction. Experimental results demonstrate that SwinIR outperforms state-of-the-art methods on different tasks by up to 0.14~0.45dB, while the total number of parameters can be reduced by up to 67%.
## Results and models ### **Classical Image Super-Resolution** Evaluated on Y channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | Task | Scale | PSNR | SSIM | Training Resources | Download | | :----------------------------------------------------------------: | :-----: | :--------------------: | :---: | :-----: | :----: | :----------------: | :-------------------------------------------------------------------: | | [swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x2 | 38.3240 | 0.9626 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth) \| log | | [swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x2 | 34.1174 | 0.9230 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth) \| log | | [swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x2 | 37.8921 | 0.9481 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth) \| log | | [swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x3 | 34.8640 | 0.9317 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth) \| log | | [swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x3 | 30.7669 | 0.8508 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth) \| log | | [swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x3 | 34.1397 | 0.8917 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth) \| log | | [swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x4 | 32.7315 | 0.9029 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth) \| log | | [swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x4 | 28.9065 | 0.7915 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth) \| log | | [swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x4 | 32.0953 | 0.8418 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth) \| log | | [swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set5 | Image Super-Resolution | x2 | 38.3971 | 0.9629 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth) \| log | | [swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set14 | Image Super-Resolution | x2 | 34.4149 | 0.9252 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth) \| log | | [swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | DIV2K | Image Super-Resolution | x2 | 37.9473 | 0.9488 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth) \| log | | [swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set5 | Image Super-Resolution | x3 | 34.9335 | 0.9323 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth) \| log | | [swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set14 | Image Super-Resolution | x3 | 30.9258 | 0.8540 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth) \| log | | [swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | DIV2K | Image Super-Resolution | x3 | 34.2830 | 0.8939 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth) \| log | | [swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set5 | Image Super-Resolution | x4 | 32.9214 | 0.9053 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth) \| log | | [swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | Set14 | Image Super-Resolution | x4 | 29.0792 | 0.7953 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth) \| log | | [swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k](/configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | DIV2K | Image Super-Resolution | x4 | 32.3021 | 0.8451 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth) \| log | ### **Lightweight Image Super-Resolution** Evaluated on Y channels, `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | Task | Scale | PSNR | SSIM | Training Resources | Download | | :----------------------------------------------------------------: | :-----: | :--------------------: | :---: | :-----: | :----: | :----------------: | :-------------------------------------------------------------------: | | [swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x2 | 38.1289 | 0.9617 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth) \| log | | [swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x2 | 33.8404 | 0.9207 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth) \| log | | [swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x2 | 37.5844 | 0.9459 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth) \| log | | [swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x3 | 34.6037 | 0.9293 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth) \| log | | [swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x3 | 30.5340 | 0.8468 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth) \| log | | [swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x3 | 33.8394 | 0.8867 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth) \| log | | [swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set5 | Image Super-Resolution | x4 | 32.4343 | 0.8984 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth) \| log | | [swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | Set14 | Image Super-Resolution | x4 | 28.7441 | 0.7861 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth) \| log | | [swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k](/configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | DIV2K | Image Super-Resolution | x4 | 31.8636 | 0.8353 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth) \| log | ### **Real-World Image Super-Resolution** Evaluated on Y channels. The metrics are `NIQE` . | Model | Dataset | Task | NIQE | Training Resources | Download | | :-----------------------------------------------------------------: | :---------------: | :--------------------: | :----: | :----------------: | :--------------------------------------------------------------------: | | [swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 5.7975 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth) \| log | | [swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 7.2738 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth) \| log | | [swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 5.2329 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth) \| log | | [swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 7.7460 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth) \| log | | [swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 5.1464 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth) \| log | | [swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost](/configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py) | RealSRSet+5images | Image Super-Resolution | 7.6378 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth) \| log | ### **Grayscale Image Deoising** Evaluated on grayscale images. The metrics are `PSNR` . | Model | Dataset | Task | PSNR | Training Resources | Download | | :------------------------------------------------------------------------: | :------: | :-------------: | :-----: | :----------------: | :----------------------------------------------------------------------------: | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py) | Set12 | Image denoising | 33.9731 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py) | BSD68 | Image denoising | 32.5203 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py) | Urban100 | Image denoising | 34.3424 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py) | Set12 | Image denoising | 31.6434 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py) | BSD68 | Image denoising | 30.1377 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py) | Urban100 | Image denoising | 31.9493 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py) | Set12 | Image denoising | 28.5651 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py) | BSD68 | Image denoising | 27.3157 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py) | Urban100 | Image denoising | 28.6626 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth) \| log | ### **Color Image Deoising** Evaluated on RGB channels. The metrics are `PSNR` . | Model | Dataset | Task | PSNR | Training Resources | Download | | :------------------------------------------------------------------------: | :------: | :-------------: | :-----: | :----------------: | :----------------------------------------------------------------------------: | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py) | CBSD68 | Image denoising | 34.4136 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py) | Kodak24 | Image denoising | 35.3555 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py) | McMaster | Image denoising | 35.6205 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py) | Urban100 | Image denoising | 35.1836 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py) | CBSD68 | Image denoising | 31.7626 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py) | Kodak24 | Image denoising | 32.9003 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py) | McMaster | Image denoising | 33.3198 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py) | Urban100 | Image denoising | 32.9458 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py) | CBSD68 | Image denoising | 28.5346 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py) | Kodak24 | Image denoising | 29.8058 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py) | McMaster | Image denoising | 30.2027 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50](/configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py) | Urban100 | Image denoising | 29.8832 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth) \| log | ### **JPEG Compression Artifact Reduction (grayscale)** Evaluated on grayscale images. The metrics are \`PSNR / SSIM | Model | Dataset | Task | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------------------: | :------: | :---------------------------------: | :-----: | :----: | :----------------: | :---------------------------------------------------------------: | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py) | Classic5 | JPEG compression artifact reduction | 30.2746 | 0.8254 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py) | LIVE1 | JPEG compression artifact reduction | 29.8611 | 0.8292 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py) | Classic5 | JPEG compression artifact reduction | 32.5331 | 0.8753 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py) | LIVE1 | JPEG compression artifact reduction | 32.2667 | 0.8914 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py) | Classic5 | JPEG compression artifact reduction | 33.7504 | 0.8966 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py) | LIVE1 | JPEG compression artifact reduction | 33.7001 | 0.9179 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py) | Classic5 | JPEG compression artifact reduction | 34.5377 | 0.9087 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py) | LIVE1 | JPEG compression artifact reduction | 34.6846 | 0.9322 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth) \| log | ### **JPEG Compression Artifact Reduction (color)** Evaluated on RGB channels. The metrics are `PSNR / SSIM` . | Model | Dataset | Task | PSNR | SSIM | Training Resources | Download | | :-----------------------------------------------------------: | :------: | :---------------------------------: | :-----: | :----: | :----------------: | :---------------------------------------------------------------: | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py) | Classic5 | JPEG compression artifact reduction | 30.1019 | 0.8217 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py) | LIVE1 | JPEG compression artifact reduction | 28.0676 | 0.8094 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py) | Classic5 | JPEG compression artifact reduction | 32.3489 | 0.8727 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py) | LIVE1 | JPEG compression artifact reduction | 30.4514 | 0.8745 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py) | Classic5 | JPEG compression artifact reduction | 33.6028 | 0.8949 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py) | LIVE1 | JPEG compression artifact reduction | 31.8235 | 0.9023 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py) | Classic5 | JPEG compression artifact reduction | 34.4344 | 0.9076 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40](/configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py) | LIVE1 | JPEG compression artifact reduction | 32.7610 | 0.9179 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth) \| log | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py # 002 Lightweight Image Super-Resolution (small size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py # 003 Real-World Image Super-Resolution CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py # 004 Grayscale Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py # 005 Color Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py # color CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py # single-gpu train # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) python tools/train.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) python tools/train.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py python tools/train.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py python tools/train.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py # 002 Lightweight Image Super-Resolution (small size) python tools/train.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py # 003 Real-World Image Super-Resolution python tools/train.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py # 004 Grayscale Image Deoising (middle size) python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py # 005 Color Image Deoising (middle size) python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py # color python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py # multi-gpu train # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) ./tools/dist_train.sh configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) ./tools/dist_train.sh configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 # 002 Lightweight Image Super-Resolution (small size) ./tools/dist_train.sh configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 # 003 Real-World Image Super-Resolution ./tools/dist_train.sh configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py 8 # 004 Grayscale Image Deoising (middle size) ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py 8 # 005 Color Image Deoising (middle size) ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py 8 # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py 8 # color ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding usesx8 blocks) # grayscale CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth # single-gpu test # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) python tools/test.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth python tools/test.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth python tools/test.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) python tools/test.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth python tools/test.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth python tools/test.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) python tools/test.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth python tools/test.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth python tools/test.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution python tools/test.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth python tools/test.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth python tools/test.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth python tools/test.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth python tools/test.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth python tools/test.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding usesx8 blocks) # grayscale python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth # multi-gpu test # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) ./tools/dist_test.sh configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth ./tools/dist_test.sh configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth ./tools/dist_test.sh configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) ./tools/dist_test.sh configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth ./tools/dist_test.sh configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth ./tools/dist_test.sh configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) ./tools/dist_test.sh configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth ./tools/dist_test.sh configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth ./tools/dist_test.sh configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution ./tools/dist_test.sh configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth ./tools/dist_test.sh configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth ./tools/dist_test.sh configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/ ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{liang2021swinir, title={Swinir: Image restoration using swin transformer}, author={Liang, Jingyun and Cao, Jiezhang and Sun, Guolei and Zhang, Kai and Van Gool, Luc and Timofte, Radu}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, pages={1833--1844}, year={2021} } ``` ================================================ FILE: configs/swinir/README_zh-CN.md ================================================ # SwinIR (ICCVW'2021) > **任务**: 图像超分辨率, 图像去噪, JPEG压缩伪影移除
SwinIR (ICCVW'2021) ```bibtex @inproceedings{liang2021swinir, title={Swinir: Image restoration using swin transformer}, author={Liang, Jingyun and Cao, Jiezhang and Sun, Guolei and Zhang, Kai and Van Gool, Luc and Timofte, Radu}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, pages={1833--1844}, year={2021} } ```

### **Classical Image Super-Resolution** 在 Y 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 PSNR | Set14 PSNR | DIV2K PSNR | Set5 SSIM | Set14 SSIM | DIV2K SSIM | GPU 信息 | 下载 | | :-----------------------------------------------------------------: | :-------: | :--------: | :--------: | :-------: | :--------: | :--------: | :------: | :-----------------------------------------------------------------: | | [swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k](./swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | 38.3240 | 34.1174 | 37.8921 | 0.9626 | 0.9230 | 0.9481 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth) \| log | | [swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k](./swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | 34.8640 | 30.7669 | 34.1397 | 0.9317 | 0.8508 | 0.8917 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth) \| log | | [swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k](./swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py) | 32.7315 | 28.9065 | 32.0953 | 0.9029 | 0.7915 | 0.8418 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth) \| log | | [swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k](./swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | 38.3971 | 34.4149 | 37.9473 | 0.9629 | 0.9252 | 0.9488 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth) \| log | | [swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k](./swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | 34.9335 | 30.9258 | 34.2830 | 0.9323 | 0.8540 | 0.8939 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth) \| log | | [swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k](./swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py) | 32.9214 | 29.0792 | 32.3021 | 0.9053 | 0.7953 | 0.8451 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth) \| log | ### **Lightweight Image Super-Resolution** 在 Y 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Set5 PSNR | Set14 PSNR | DIV2K PSNR | Set5 SSIM | Set14 SSIM | DIV2K SSIM | GPU 信息 | 下载 | | :-----------------------------------------------------------------: | :-------: | :--------: | :--------: | :-------: | :--------: | :--------: | :------: | :-----------------------------------------------------------------: | | [swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k](./swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | 38.1289 | 33.8404 | 37.5844 | 0.9617 | 0.9207 | 0.9459 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth) \| log | | [swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k](./swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | 34.6037 | 30.5340 | 33.8394 | 0.9293 | 0.8468 | 0.8867 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth) \| log | | [swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k](./swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py) | 32.4343 | 28.7441 | 31.8636 | 0.8984 | 0.7861 | 0.8353 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth) \| log | ### **Real-World Image Super-Resolution** 在 Y 通道上进行评估。 我们使用 NIQE 作为指标。 | 算法 | RealSRSet+5images NIQE | GPU 信息 | 下载 | | :-----------------------------------------------------------------------------------: | :--------------------: | :------: | :-----------------------------------------------------------------------------------: | | [swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](./swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | 5.7975 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth) \| log | | [swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](./swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | 7.2738 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth) \| log | | [swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](./swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | 5.2329 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth) \| log | | [swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost](./swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py) | 7.7460 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth) \| log | | [swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost](./swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py) | 5.1464 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth) \| log | | [swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost](./swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py) | 7.6378 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth) \| log | ### **Grayscale Image Deoising** 在灰度图上进行评估。 我们使用 PSNR 作为指标。 | 算法 | Set12 PSNR | BSD68 PSNR | Urban100 PSNR | GPU 信息 | 下载 | | :-----------------------------------------------------------------------------: | :--------: | :--------: | :-----------: | :------: | :------------------------------------------------------------------------------: | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py) | 33.9731 | 32.5203 | 34.3424 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py) | 31.6434 | 30.1377 | 31.9493 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py) | 28.5651 | 27.3157 | 28.6626 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth) \| log | ### **Color Image Deoising** 在 RGB 通道上进行评估。 我们使用 PSNR 作为指标。 | 算法 | CBSD68 PSNR | Kodak24 PSNR | McMaster PSNR | Urban100 PSNR | GPU 信息 | 下载 | | :---------------------------------------------------------------------: | :---------: | :----------: | :-----------: | :-----------: | :------: | :----------------------------------------------------------------------: | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py) | 34.4136 | 35.3555 | 35.6205 | 35.1836 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py) | 31.7626 | 32.9003 | 33.3198 | 32.9458 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth) \| log | | [swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50](./swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py) | 28.5346 | 29.8058 | 30.2027 | 29.8832 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth) \| log | ### **JPEG Compression Artifact Reduction (grayscale)** 在灰度图上进行评估。 我们使用 PSNR 和 SSIM 作为指标。 | 算法 | Classic5 PSNR | Classic5 SSIM | LIVE1 PSNR | LIVE1 SSIM | GPU 信息 | 下载 | | :-----------------------------------------------------------------------: | :-----------: | :-----------: | :--------: | :--------: | :------: | :-----------------------------------------------------------------------: | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py) | 30.2746 | 0.8254 | 29.8611 | 0.8292 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py) | 32.5331 | 0.8753 | 32.2667 | 0.8914 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py) | 33.7504 | 0.8966 | 33.7001 | 0.9179 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py) | 34.5377 | 0.9087 | 34.6846 | 0.9322 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth) \| log | ### **JPEG Compression Artifact Reduction (color)** 在 RGB 通道上进行评估。 我们使用 PSNR 和 SSIM 作为指标。 | 算法 | Classic5 PSNR | Classic5 SSIM | LIVE1 PSNR | LIVE1 SSIM | GPU 信息 | 下载 | | :-----------------------------------------------------------------------: | :-----------: | :-----------: | :--------: | :--------: | :------: | :-----------------------------------------------------------------------: | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py) | 30.1019 | 0.8217 | 28.0676 | 0.8094 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py) | 32.3489 | 0.8727 | 30.3489 | 0.8745 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py) | 33.6028 | 0.8949 | 31.8235 | 0.9023 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth) \| log | | [swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40](./swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py) | 34.4344 | 0.9076 | 32.7610 | 0.9179 | 8 | [model](https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth) \| log | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py # 002 Lightweight Image Super-Resolution (small size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py # 003 Real-World Image Super-Resolution CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py # 004 Grayscale Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py # 005 Color Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py # color CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py # 单个GPU上训练 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) python tools/train.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) python tools/train.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py python tools/train.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py python tools/train.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py # 002 Lightweight Image Super-Resolution (small size) python tools/train.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py python tools/train.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py # 003 Real-World Image Super-Resolution python tools/train.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py python tools/train.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py # 004 Grayscale Image Deoising (middle size) python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py # 005 Color Image Deoising (middle size) python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py python tools/train.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py # color python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py python tools/train.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py # 多个GPU上训练 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) ./tools/dist_train.sh configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py 8 # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) ./tools/dist_train.sh configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py 8 # 002 Lightweight Image Super-Resolution (small size) ./tools/dist_train.sh configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 ./tools/dist_train.sh configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py 8 # 003 Real-World Image Super-Resolution ./tools/dist_train.sh configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py 8 ./tools/dist_train.sh configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py 8 # 004 Grayscale Image Deoising (middle size) ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py 8 # 005 Color Image Deoising (middle size) ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py 8 ./tools/dist_train.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py 8 # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py 8 # color ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py 8 ./tools/dist_train.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding usesx8 blocks) # grayscale CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth # 单个GPU上测试 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) python tools/test.py configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth python tools/test.py configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth python tools/test.py configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) python tools/test.py configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth python tools/test.py configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth python tools/test.py configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) python tools/test.py configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth python tools/test.py configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth python tools/test.py configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution python tools/test.py configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth python tools/test.py configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth python tools/test.py configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth python tools/test.py configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth python tools/test.py configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth python tools/test.py configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth python tools/test.py configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding usesx8 blocks) # grayscale python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth python tools/test.py configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth # 多GPU测试 # 001 Classical Image Super-Resolution (middle size) # (setting1: when model is trained on DIV2K and with training_patch_size=48) ./tools/dist_test.sh configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth ./tools/dist_test.sh configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth ./tools/dist_test.sh configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth # (setting2: when model is trained on DIV2K+Flickr2K and with training_patch_size=64) ./tools/dist_test.sh configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth ./tools/dist_test.sh configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth ./tools/dist_test.sh configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth # 002 Lightweight Image Super-Resolution (small size) ./tools/dist_test.sh configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth ./tools/dist_test.sh configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth ./tools/dist_test.sh configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth # 003 Real-World Image Super-Resolution ./tools/dist_test.sh configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth ./tools/dist_test.sh configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth ./tools/dist_test.sh configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth ./tools/dist_test.sh configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-25f1722a.pth # 004 Grayscale Image Deoising (middle size) ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth # 005 Color Image Deoising (middle size) ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth ./tools/dist_test.sh configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth # 006 JPEG Compression Artifact Reduction (middle size, using window_size=7 because JPEG encoding uses 8x8 blocks) # grayscale ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth # color ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth ./tools/dist_test.sh configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/swinir/metafile.yml ================================================ Collections: - Name: SwinIR Paper: Title: 'SwinIR: Image Restoration Using Swin Transformer' URL: https://arxiv.org/abs/2108.10257 README: configs/swinir/README.md Task: - image super-resolution - image denoising - jpeg compression artifact reduction Year: 2021 Models: - Config: configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 38.324 SSIM: 0.9626 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 34.1174 SSIM: 0.923 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 37.8921 SSIM: 0.9481 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k-ed2d419e.pth - Config: configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 34.864 SSIM: 0.9317 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 30.7669 SSIM: 0.8508 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.1397 SSIM: 0.8917 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k-926950f1.pth - Config: configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 32.7315 SSIM: 0.9029 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 28.9065 SSIM: 0.7915 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 32.0953 SSIM: 0.8418 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k-88e4903d.pth - Config: configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py In Collection: SwinIR Name: swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k Results: - Dataset: Set5 Metrics: PSNR: 38.3971 SSIM: 0.9629 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 34.4149 SSIM: 0.9252 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 37.9473 SSIM: 0.9488 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k-69e15fb6.pth - Config: configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py In Collection: SwinIR Name: swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k Results: - Dataset: Set5 Metrics: PSNR: 34.9335 SSIM: 0.9323 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 30.9258 SSIM: 0.854 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 34.283 SSIM: 0.8939 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k-d6982f7b.pth - Config: configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py In Collection: SwinIR Name: swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k Results: - Dataset: Set5 Metrics: PSNR: 32.9214 SSIM: 0.9053 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 29.0792 SSIM: 0.7953 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 32.3021 SSIM: 0.8451 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k-0502d775.pth - Config: configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 38.1289 SSIM: 0.9617 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 33.8404 SSIM: 0.9207 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 37.5844 SSIM: 0.9459 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k-131d3f64.pth - Config: configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 34.6037 SSIM: 0.9293 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 30.534 SSIM: 0.8468 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 33.8394 SSIM: 0.8867 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k-309cb239.pth - Config: configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py In Collection: SwinIR Name: swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k Results: - Dataset: Set5 Metrics: PSNR: 32.4343 SSIM: 0.8984 Task: Image Super-Resolution - Dataset: Set14 Metrics: PSNR: 28.7441 SSIM: 0.7861 Task: Image Super-Resolution - Dataset: DIV2K Metrics: PSNR: 31.8636 SSIM: 0.8353 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k-d6622d03.pth - Config: configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 5.7975 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-c6425057.pth - Config: configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 7.2738 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-6f0c425f.pth - Config: configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 5.2329 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-36960d18.pth - Config: configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 7.746 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-os-a016a72f.pth - Config: configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 5.1464 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth - Config: configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py In Collection: SwinIR Name: swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost Results: - Dataset: RealSRSet+5images Metrics: NIQE: 7.6378 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-os-9f1599b5.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15 Results: - Dataset: Set12 Metrics: PSNR: 33.9731 Task: Image denoising - Dataset: BSD68 Metrics: PSNR: 32.5203 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 34.3424 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15-6782691b.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25 Results: - Dataset: Set12 Metrics: PSNR: 31.6434 Task: Image denoising - Dataset: BSD68 Metrics: PSNR: 30.1377 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 31.9493 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25-d0d8d4da.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50 Results: - Dataset: Set12 Metrics: PSNR: 28.5651 Task: Image denoising - Dataset: BSD68 Metrics: PSNR: 27.3157 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 28.6626 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50-54c9968a.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15 Results: - Dataset: CBSD68 Metrics: PSNR: 34.4136 Task: Image denoising - Dataset: Kodak24 Metrics: PSNR: 35.3555 Task: Image denoising - Dataset: McMaster Metrics: PSNR: 35.6205 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 35.1836 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15-c74a2cee.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25 Results: - Dataset: CBSD68 Metrics: PSNR: 31.7626 Task: Image denoising - Dataset: Kodak24 Metrics: PSNR: 32.9003 Task: Image denoising - Dataset: McMaster Metrics: PSNR: 33.3198 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 32.9458 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25-df2b1c0c.pth - Config: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py In Collection: SwinIR Name: swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50 Results: - Dataset: CBSD68 Metrics: PSNR: 28.5346 Task: Image denoising - Dataset: Kodak24 Metrics: PSNR: 29.8058 Task: Image denoising - Dataset: McMaster Metrics: PSNR: 30.2027 Task: Image denoising - Dataset: Urban100 Metrics: PSNR: 29.8832 Task: Image denoising Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50-e369874c.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10 Results: - Dataset: Classic5 Metrics: PSNR: 30.2746 SSIM: 0.8254 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 29.8611 SSIM: 0.8292 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10-da93c8e9.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20 Results: - Dataset: Classic5 Metrics: PSNR: 32.5331 SSIM: 0.8753 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 32.2667 SSIM: 0.8914 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20-d47367b1.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30 Results: - Dataset: Classic5 Metrics: PSNR: 33.7504 SSIM: 0.8966 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 33.7001 SSIM: 0.9179 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30-52c083cf.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40 Results: - Dataset: Classic5 Metrics: PSNR: 34.5377 SSIM: 0.9087 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 34.6846 SSIM: 0.9322 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40-803e8d9b.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10 Results: - Dataset: Classic5 Metrics: PSNR: 30.1019 SSIM: 0.8217 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 28.0676 SSIM: 0.8094 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10-09aafadc.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20 Results: - Dataset: Classic5 Metrics: PSNR: 32.3489 SSIM: 0.8727 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 30.4514 SSIM: 0.8745 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20-b8a42b5e.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30 Results: - Dataset: Classic5 Metrics: PSNR: 33.6028 SSIM: 0.8949 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 31.8235 SSIM: 0.9023 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30-e9fe6859.pth - Config: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py In Collection: SwinIR Name: swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40 Results: - Dataset: Classic5 Metrics: PSNR: 34.4344 SSIM: 0.9076 Task: JPEG compression artifact reduction - Dataset: LIVE1 Metrics: PSNR: 32.761 SSIM: 0.9179 Task: JPEG compression artifact reduction Weights: https://download.openmmlab.com/mmediting/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40-5b77a6e6.pth ================================================ FILE: configs/swinir/swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py'] experiment_name = 'swinir_gan-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' ================================================ FILE: configs/swinir/swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py'] experiment_name = 'swinir_gan-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' ================================================ FILE: configs/swinir/swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py'] experiment_name = 'swinir_gan-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' ================================================ FILE: configs/swinir/swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['../_base_/default_runtime.py'] experiment_name = 'swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 img_size = 64 # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=scale, in_chans=3, img_size=img_size, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='nearest+conv', resi_connection='1conv'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) test_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] test_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicImageDataset', metainfo=dict(dataset_type='realsrset', task_name='realsr'), data_root='data/RealSRSet+5images', data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) test_evaluator = [dict(type='NIQE', input_order='CHW', convert_to='Y')] test_cfg = dict(type='TestLoop') ================================================ FILE: configs/swinir/swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['swinir_psnr-x2s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py'] experiment_name = 'swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict(generator=dict(upscale=scale)) ================================================ FILE: configs/swinir/swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost.py ================================================ _base_ = ['swinir_psnr-x4s64w8d6e180_8xb4-lr1e-4-600k_df2k-ost.py'] experiment_name = 'swinir_psnr-x4s64w8d9e240_8xb4-lr1e-4-600k_df2k-ost' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # model settings model = dict( generator=dict( depths=[6, 6, 6, 6, 6, 6, 6, 6, 6], embed_dim=240, num_heads=[8, 8, 8, 8, 8, 8, 8, 8, 8], resi_connection='3conv')) ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/decompression_test_config.py' ] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' quality = 10 # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=1, in_chans=3, img_size=126, window_size=7, img_range=255.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='', resi_connection='1conv'), pixel_loss=dict(type='CharbonnierLoss', eps=1e-9), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedRandomCrop', gt_patch_size=126), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict( type='RandomJPEGCompression', params=dict(quality=[quality, quality], color_type='color'), keys=['img']), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomJPEGCompression', params=dict(quality=[quality, quality], color_type='color'), keys=['img']), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=2, batch_size=1, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DFWB8550sub_GT.txt', metainfo=dict(dataset_type='dfwb', task_name='CAR'), data_root=data_root + '/DFWB', data_prefix=dict(img='', gt=''), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=2, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='live1', task_name='CAR'), data_root=data_root + '/LIVE1', data_prefix=dict(img='', gt=''), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', prefix='LIVE1'), dict(type='SSIM', prefix='LIVE1'), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_600_000, val_interval=5000) val_cfg = dict(type='ValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[800000, 1200000, 1400000, 1500000, 1600000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR20' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 20 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR30' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 30 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-colorCAR40' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 40 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/decompression_test_config.py' ] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' quality = 10 # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=1, in_chans=1, img_size=126, window_size=7, img_range=255.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='', resi_connection='1conv'), pixel_loss=dict(type='CharbonnierLoss', eps=1e-9), data_preprocessor=dict(type='DataPreprocessor', mean=[0.], std=[255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='grayscale', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='grayscale', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedRandomCrop', gt_patch_size=126), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict( type='RandomJPEGCompression', params=dict(quality=[quality, quality], color_type='grayscale'), keys=['img']), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='grayscale', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='grayscale', imdecode_backend='cv2'), dict( type='RandomJPEGCompression', params=dict(quality=[quality, quality], color_type='grayscale'), keys=['img']), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=1, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DFWB8550sub_GT.txt', metainfo=dict(dataset_type='dfwb', task_name='CAR'), data_root=data_root + '/DFWB', data_prefix=dict(img='', gt=''), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='classic5', task_name='CAR'), data_root=data_root + '/Classic5', data_prefix=dict(img='', gt=''), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', prefix='Classic5'), dict(type='SSIM', prefix='Classic5'), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_600_000, val_interval=5000) val_cfg = dict(type='ValLoop') test_dataloader = _base_.test_dataloader for idx in range(len(test_dataloader)): test_pipeline = test_dataloader[idx]['dataset']['pipeline'] if idx > 0: test_pipeline[0]['to_y_channel'] = True test_pipeline[1]['to_y_channel'] = True else: test_pipeline[0]['color_type'] = 'grayscale' test_pipeline[1]['color_type'] = 'grayscale' test_pipeline[2]['color_type'] = 'grayscale' # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[800000, 1200000, 1400000, 1500000, 1600000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR20' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 20 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR30' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 30 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40.py ================================================ _base_ = ['swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR10.py'] experiment_name = 'swinir_s126w7d6e180_8xb1-lr2e-4-1600k_dfwb-grayCAR40' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify JPEG quality factor of RandomJPEGCompression quality = 40 train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['quality'] = [quality, quality] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['quality'] = [quality, quality] test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['quality'] = [quality, quality] ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_color_test_config.py' ] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 15 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=1, in_chans=3, img_size=128, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='', resi_connection='1conv'), pixel_loss=dict(type='CharbonnierLoss', eps=1e-9), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma * 255, sigma * 255], gaussian_gray_noise_prob=0), keys=['img']), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma * 255, sigma * 255], gaussian_gray_noise_prob=0), keys=['img']), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=1, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DFWB8550sub_GT.txt', metainfo=dict(dataset_type='dfwb', task_name='denoising'), data_root=data_root + '/DFWB', data_prefix=dict(img='', gt=''), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='mcmaster', task_name='denoising'), data_root=data_root + '/McMaster', data_prefix=dict(img='', gt=''), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', prefix='McMaster'), dict(type='SSIM', prefix='McMaster'), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_600_000, val_interval=5000) val_cfg = dict(type='ValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[800000, 1200000, 1400000, 1500000, 1600000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25.py ================================================ _base_ = ['swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py'] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN25' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 25 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['gaussian_sigma'] = [sigma, sigma] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50.py ================================================ _base_ = ['swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN15.py'] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-colorDN50' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 50 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['gaussian_sigma'] = [sigma, sigma] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/denoising-gaussian_gray_test_config.py' ] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 15 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=1, in_chans=1, img_size=128, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='', resi_connection='1conv'), pixel_loss=dict(type='CharbonnierLoss', eps=1e-9), data_preprocessor=dict(type='DataPreprocessor', mean=[0.], std=[255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='grayscale', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='grayscale', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=1)), dict(type='PairedRandomCrop', gt_patch_size=128), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=0), keys=['img']), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='grayscale', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='grayscale', imdecode_backend='cv2'), dict( type='RandomNoise', params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=0), keys=['img']), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=1, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DFWB8550sub_GT.txt', metainfo=dict(dataset_type='dfwb', task_name='denoising'), data_root=data_root + '/DFWB', data_prefix=dict(img='', gt=''), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set12', task_name='denoising'), data_root=data_root + '/Set12', data_prefix=dict(img='', gt=''), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', prefix='Set12'), dict(type='SSIM', prefix='Set12'), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=1_600_000, val_interval=5000) val_cfg = dict(type='ValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[800000, 1200000, 1400000, 1500000, 1600000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25.py ================================================ _base_ = ['swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py'] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN25' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 25 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['gaussian_sigma'] = [sigma, sigma] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] ================================================ FILE: configs/swinir/swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50.py ================================================ _base_ = ['swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN15.py'] experiment_name = 'swinir_s128w8d6e180_8xb1-lr2e-4-1600k_dfwb-grayDN50' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # modify sigma of RandomNoise sigma = 50 test_dataloader = _base_.test_dataloader for dataloader in test_dataloader: test_pipeline = dataloader['dataset']['pipeline'] test_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[-2]['params']['gaussian_sigma'] = [sigma, sigma] val_dataloader = _base_.val_dataloader val_pipeline = val_dataloader['dataset']['pipeline'] val_pipeline[2]['params']['gaussian_sigma'] = [sigma, sigma] ================================================ FILE: configs/swinir/swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x2_test_config.py' ] experiment_name = 'swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 img_size = 48 # evaluated on Y channels test_evaluator = _base_.test_evaluator for evaluator in test_evaluator: for metric in evaluator['metrics']: metric['convert_to'] = 'Y' # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=scale, in_chans=3, img_size=img_size, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='pixelshuffle', resi_connection='1conv'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=img_size * scale), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=500_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[250000, 400000, 450000, 475000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = ['swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x2s64w8d4e60_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 img_size = 64 # model settings model = dict( generator=dict( img_size=img_size, depths=[6, 6, 6, 6], embed_dim=60, num_heads=[6, 6, 6, 6], upsampler='pixelshuffledirect')) # modify patch size of train_dataloader train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[3]['gt_patch_size'] = img_size * scale ================================================ FILE: configs/swinir/swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k.py ================================================ _base_ = ['swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x2s64w8d6e180_8xb4-lr2e-4-500k_df2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 2 img_size = 64 # model settings model = dict(generator=dict(img_size=img_size)) # modify patch size of train_pipeline train_pipeline = _base_.train_pipeline train_pipeline[3]['gt_patch_size'] = img_size * scale # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DF2K3450sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DF2K', data_prefix=dict( img='DF2K_train_LR_bicubic/X2_sub', gt='DF2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) ================================================ FILE: configs/swinir/swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x3_test_config.py' ] experiment_name = 'swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 3 img_size = 48 # evaluated on Y channels test_evaluator = _base_.test_evaluator for evaluator in test_evaluator: for metric in evaluator['metrics']: metric['convert_to'] = 'Y' # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=scale, in_chans=3, img_size=img_size, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='pixelshuffle', resi_connection='1conv'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=img_size * scale), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X3_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=500_000, val_interval=5000) val_cfg = dict(type='ValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[250000, 400000, 450000, 475000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = ['swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x3s64w8d4e60_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 3 img_size = 64 # model settings model = dict( generator=dict( img_size=img_size, depths=[6, 6, 6, 6], embed_dim=60, num_heads=[6, 6, 6, 6], upsampler='pixelshuffledirect')) # modify patch size of train_dataloader train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[3]['gt_patch_size'] = img_size * scale ================================================ FILE: configs/swinir/swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k.py ================================================ _base_ = ['swinir_x3s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x3s64w8d6e180_8xb4-lr2e-4-500k_df2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 3 img_size = 64 # model settings model = dict(generator=dict(img_size=img_size)) # modify patch size of train_pipeline train_pipeline = _base_.train_pipeline train_pipeline[3]['gt_patch_size'] = img_size * scale # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DF2K3450sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DF2K', data_prefix=dict( img='DF2K_train_LR_bicubic/X3_sub', gt='DF2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) ================================================ FILE: configs/swinir/swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/sisr_x4_test_config.py' ] experiment_name = 'swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 img_size = 48 # evaluated on Y channels test_evaluator = _base_.test_evaluator for evaluator in test_evaluator: for metric in evaluator['metrics']: metric['convert_to'] = 'Y' # model settings model = dict( type='BaseEditModel', generator=dict( type='SwinIRNet', upscale=scale, in_chans=3, img_size=img_size, window_size=8, img_range=1.0, depths=[6, 6, 6, 6, 6, 6], embed_dim=180, num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler='pixelshuffle', resi_connection='1conv'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=img_size * scale), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = [ dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ] train_cfg = dict( type='IterBasedTrainLoop', max_iters=500_000, val_interval=5000) val_cfg = dict(type='ValLoop') # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[250000, 400000, 450000, 475000], gamma=0.5) ================================================ FILE: configs/swinir/swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k.py ================================================ _base_ = ['swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x4s64w8d4e60_8xb4-lr2e-4-500k_div2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 img_size = 64 # model settings model = dict( generator=dict( img_size=img_size, depths=[6, 6, 6, 6], embed_dim=60, num_heads=[6, 6, 6, 6], upsampler='pixelshuffledirect')) # modify patch size of train_dataloader train_dataloader = _base_.train_dataloader train_pipeline = train_dataloader['dataset']['pipeline'] train_pipeline[3]['gt_patch_size'] = img_size * scale ================================================ FILE: configs/swinir/swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k.py ================================================ _base_ = ['swinir_x4s48w8d6e180_8xb4-lr2e-4-500k_div2k.py'] experiment_name = 'swinir_x4s64w8d6e180_8xb4-lr2e-4-500k_df2k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 img_size = 64 # model settings model = dict(generator=dict(img_size=img_size)) # modify patch size of train_pipeline train_pipeline = _base_.train_pipeline train_pipeline[3]['gt_patch_size'] = img_size * scale # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=4, batch_size=4, drop_last=True, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DF2K3450sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DF2K', data_prefix=dict( img='DF2K_train_LR_bicubic/X4_sub', gt='DF2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=train_pipeline)) ================================================ FILE: configs/tdan/README.md ================================================ # TDAN (CVPR'2020) > [TDAN: Temporally Deformable Alignment Network for Video Super-Resolution](https://arxiv.org/abs/1812.02898) > **Task**: Video Super-Resolution ## Abstract Video super-resolution (VSR) aims to restore a photo-realistic high-resolution (HR) video frame from both its corresponding low-resolution (LR) frame (reference frame) and multiple neighboring frames (supporting frames). Due to varying motion of cameras or objects, the reference frame and each support frame are not aligned. Therefore, temporal alignment is a challenging yet important problem for VSR. Previous VSR methods usually utilize optical flow between the reference frame and each supporting frame to wrap the supporting frame for temporal alignment. Therefore, the performance of these image-level wrapping-based models will highly depend on the prediction accuracy of optical flow, and inaccurate optical flow will lead to artifacts in the wrapped supporting frames, which also will be propagated into the reconstructed HR video frame. To overcome the limitation, in this paper, we propose a temporal deformable alignment network (TDAN) to adaptively align the reference frame and each supporting frame at the feature level without computing optical flow. The TDAN uses features from both the reference frame and each supporting frame to dynamically predict offsets of sampling convolution kernels. By using the corresponding kernels, TDAN transforms supporting frames to align with the reference frame. To predict the HR video frame, a reconstruction network taking aligned frames and the reference frame is utilized. Experimental results demonstrate the effectiveness of the proposed TDAN-based VSR model.
## Results and models Evaluated on Y-channel. 8 pixels in each border are cropped before evaluation. The metrics are `PSNR / SSIM` . | Model | Dataset | PSNR (Y) | SSIM (Y) | Training Resources | Download | | :--------------------------------------------------------------------: | :-------------: | :-------: | :-------: | :----------------------: | :-----------------------------------------------------------------------: | | [tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi](./tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py) | - | - | - | 8 (Tesla V100-SXM2-32GB) | - | | [tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bd](./tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py) | - | - | - | 8 (Tesla V100-SXM2-32GB) | - | | [tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi](./tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py) | Vid4 (BIx4) | **26.49** | **0.792** | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528_135616.log.json) | | [tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi](./tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py) | SPMCS-30 (BIx4) | **30.42** | **0.856** | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528_135616.log.json) | | [tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi](./tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py) | Vid4 (BDx4) | 25.93 | 0.772 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528_135616.log.json) | | [tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi](./tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py) | SPMCS-30 (BDx4) | 29.69 | 0.842 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528_135616.log.json) | | [tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd](./tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py) | Vid4 (BIx4) | 25.80 | 0.784 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528_122401.log.json) | | [tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd](./tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py) | SPMCS-30 (BIx4) | 29.56 | 0.851 | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528_122401.log.json) | | [tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd](./tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py) | Vid4 (BDx4) | **26.87** | **0.815** | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528_122401.log.json) | | [tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd](./tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py) | SPMCS-30 (BDx4) | **30.77** | **0.868** | 8 (Tesla V100-SXM2-32GB) | [model](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528_122401.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. TDAN is trained with two stages. **Stage 1**: Train with a larger learning rate (1e-4) ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py # single-gpu train python tools/train.py configs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py # multi-gpu train ./tools/dist_train.sh cconfigs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py 8 ``` **Stage 2**: Fine-tune with a smaller learning rate (5e-5) ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py # single-gpu train python tools/train.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py # multi-gpu train ./tools/dist_train.sh configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth # single-gpu test python tools/test.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth # multi-gpu test ./tools/dist_test.sh configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @InProceedings{tian2020tdan, title={TDAN: Temporally-Deformable Alignment Network for Video Super-Resolution}, author={Tian, Yapeng and Zhang, Yulun and Fu, Yun and Xu, Chenliang}, booktitle = {Proceedings of the IEEE conference on Computer Vision and Pattern Recognition}, year = {2020} } ``` ================================================ FILE: configs/tdan/README_zh-CN.md ================================================ # TDAN (CVPR'2020) > **任务**: 视频超分辨率
TDAN (CVPR'2020) ```bibtex @InProceedings{tian2020tdan, title={TDAN: Temporally-Deformable Alignment Network for Video Super-Resolution}, author={Tian, Yapeng and Zhang, Yulun and Fu, Yun and Xu, Chenliang}, booktitle = {Proceedings of the IEEE conference on Computer Vision and Pattern Recognition}, year = {2020} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的8像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | Vid4 (BIx4) | SPMCS-30 (BIx4) | Vid4 (BDx4) | SPMCS-30 (BDx4) | GPU 信息 | 下载 | | :--------------------------------------------------------: | :-------------: | :-------------: | :-------------: | :-------------: | :----------------------: | :--------------------------------------------------------: | | [tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi](./tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py) | - | - | - | - | 8 (Tesla V100-SXM2-32GB) | - | | [tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bd](./tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py) | - | - | - | - | 8 (Tesla V100-SXM2-32GB) | - | | [tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi](./tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py) | **26.49/0.792** | **30.42/0.856** | 25.93/0.772 | 29.69/0.842 | 8 (Tesla V100-SXM2-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528_135616.log.json) | | [tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd](./tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py) | 25.80/0.784 | 29.56/0.851 | **26.87/0.815** | **30.77/0.868** | 8 (Tesla V100-SXM2-32GB) | [模型](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528_122401.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 TDAN 训练有两个阶段。 **阶段 1**: 以更大的学习率训练 (1e-4) ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py # 单个GPU上训练 python tools/train.py configs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py # 多个GPU上训练 ./tools/dist_train.sh configs/tdan/tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi.py 8 ``` **阶段 2**: 以较小的学习率进行微调 (5e-5) ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py # 单个GPU上训练 python tools/train.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py # 多个GPU上训练 ./tools/dist_train.sh configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth # 单个GPU上测试 python tools/test.py configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth # 多个GPU上测试 ./tools/dist_test.sh configs/tdan/tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi.py https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/tdan/metafile.yml ================================================ Collections: - Name: TDAN Paper: Title: 'TDAN: Temporally Deformable Alignment Network for Video Super-Resolution' URL: https://arxiv.org/abs/1812.02898 README: configs/tdan/README.md Task: - video super-resolution Year: 2020 Models: - Config: configs/tdan/tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py In Collection: TDAN Name: tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi Results: - Dataset: '-' Metrics: {} Task: Video Super-Resolution - Config: configs/tdan/tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py In Collection: TDAN Name: tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd Results: - Dataset: '-' Metrics: {} Task: Video Super-Resolution - Config: configs/tdan/tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py In Collection: TDAN Name: tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi Results: - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 26.49 SSIM (Y): 0.792 Task: Video Super-Resolution - Dataset: SPMCS-30(BIx4) Metrics: PSNR (Y): 30.42 SSIM (Y): 0.856 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 25.93 SSIM (Y): 0.772 Task: Video Super-Resolution - Dataset: SPMCS-30(BDx4) Metrics: PSNR (Y): 29.69 SSIM (Y): 0.842 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bix4_20210528-739979d9.pth - Config: configs/tdan/tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py In Collection: TDAN Name: tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd Results: - Dataset: Vid4(BIx4) Metrics: PSNR (Y): 25.8 SSIM (Y): 0.784 Task: Video Super-Resolution - Dataset: SPMCS-30(BIx4) Metrics: PSNR (Y): 29.56 SSIM (Y): 0.851 Task: Video Super-Resolution - Dataset: Vid4(BDx4) Metrics: PSNR (Y): 26.87 SSIM (Y): 0.815 Task: Video Super-Resolution - Dataset: SPMCS-30(BDx4) Metrics: PSNR (Y): 30.77 SSIM (Y): 0.868 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/tdan/tdan_vimeo90k_bdx4_20210528-c53ab844.pth ================================================ FILE: configs/tdan/tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py ================================================ _base_ = [ '../_base_/default_runtime.py', '../_base_/datasets/tdan_test_config.py' ] experiment_name = 'tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type='TDAN', generator=dict( type='TDANNet', in_channels=3, mid_channels=64, out_channels=3, num_blocks_before_align=5, num_blocks_after_align=10), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), lq_pixel_loss=dict(type='MSELoss', loss_weight=0.01, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.5 * 255, 0.5 * 255, 0.5 * 255], std=[255, 255, 255], )) val_evaluator = dict( type='Evaluator', metrics=[ dict(type='PSNR', crop_border=8, convert_to='Y'), dict(type='SSIM', crop_border=8, convert_to='Y'), ]) train_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=192), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateFrameIndiceswithPadding', padding='reflection'), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vimeo_seq', task_name='vsr'), data_root=f'{data_root}/vimeo90k', data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vimeo90K_train_GT.txt', depth=2, num_input_frames=5, fixed_seq_len=7, load_frames_list=dict( img=['im2.png', 'im3.png', 'im4.png', 'im5.png', 'im6.png'], gt=['im4.png']), pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=f'{data_root}/Vid4', data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=5, pipeline=val_pipeline)) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, weight_decay=1e-6), ) train_cfg = dict( type='IterBasedTrainLoop', max_iters=400_000, val_interval=50000) val_cfg = dict(type='MultiValLoop') # No learning policy default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=50000, save_optimizer=True, out_dir=save_dir, by_epoch=False)) ================================================ FILE: configs/tdan/tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py ================================================ _base_ = './tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py' experiment_name = 'tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' train_dataloader = dict(dataset=dict(data_prefix=dict(img='BIx4', gt='GT'))) val_dataloader = dict(dataset=dict(data_prefix=dict(img='BIx4', gt='GT'))) train_cfg = dict( type='IterBasedTrainLoop', max_iters=400_000, val_interval=50000) val_cfg = dict(type='MultiValLoop') # No learning policy ================================================ FILE: configs/tdan/tdan_x4ft_8xb16-lr5e-5-400k_vimeo90k-bi.py ================================================ _base_ = './tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bi.py' experiment_name = 'tdan_x4ft_1xb16-lr5e-5-400k_vimeo90k-bi' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(_delete_=True, type='Adam', lr=5e-5), ) # load_from = 'tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bi/iter_400000.pth' ================================================ FILE: configs/tdan/tdan_x4ft_8xb16-lr5e-5-800k_vimeo90k-bd.py ================================================ _base_ = './tdan_x4_8xb16-lr1e-4-400k_vimeo90k-bd.py' experiment_name = 'tdan_x4ft_1xb16-lr5e-5-800k_vimeo90k-bd' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type='OptimWrapper', optimizer=dict(_delete_=True, type='Adam', lr=5e-5), ) train_cfg = dict( type='IterBasedTrainLoop', max_iters=800_000, val_interval=50000) # load_from = 'tdan_x4_1xb16-lr1e-4-400k_vimeo90k-bd/iter_400000.pth' ================================================ FILE: configs/textual_inversion/README.md ================================================ # Textual Inversion (2022) > [An Image is Worth One Word: Personalizing Text-to-Image Generation using Textual Inversion](https://arxiv.org/abs/2208.01618) > **Task**: Text2Image ## Abstract Text-to-image models offer unprecedented freedom to guide creation through natural language. Yet, it is unclear how such freedom can be exercised to generate images of specific unique concepts, modify their appearance, or compose them in new roles and novel scenes. In other words, we ask: how can we use language-guided models to turn our cat into a painting, or imagine a new product based on our favorite toy? Here we present a simple approach that allows such creative freedom. Using only 3-5 images of a user-provided concept, like an object or a style, we learn to represent it through new "words" in the embedding space of a frozen text-to-image model. These "words" can be composed into natural language sentences, guiding personalized creation in an intuitive way. Notably, we find evidence that a single word embedding is sufficient for capturing unique and varied concepts. We compare our approach to a wide range of baselines, and demonstrate that it can more faithfully portray the concepts across a range of applications and tasks.
## Configs | Model | Dataset | Download | | :-----------------------------------------: | :-----: | :------: | | [Textual Inversion](./textual_inversion.py) | - | - | ## Quick Start 1. Download [data](https://drive.google.com/drive/folders/1fmJMs25nxS_rSNqS5hTcRdLem_YQXbq5) and [template](https://openxlab.org.cn/datasets/ferry/ViCo/tree/main)(two txt files) and save to `data` The file structure will be like this: ```text data └── cat_toy ├── 1.jpeg ├── 2.jpeg ├── 3.jpeg ├── 3.jpeg ├── 4.jpeg ├── 6.jpeg └── 7.jpeg └── imagenet_templates_small.txt └── imagenet_style_templates_small.txt ``` 2. Start training with the following command: ```bash bash tools/dist_train.sh configs/textual_inversion/textual_inversion.py 1 ```

3. Inference with trained textual embedding: ```python import torch from mmengine import Config from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def process_state_dict(state_dict): new_state_dict = dict() for k, v in state_dict.items(): new_k = k.replace('module.', '') new_state_dict[new_k] = v return new_state_dict cfg = Config.fromfile('configs/textual_inversion/textual_inversion.py') checkpoint = torch.load('work_dirs/textual_inversion/iter_3000.pth') state_dict = process_state_dict(checkpoint['state_dict']) model = MODELS.build(cfg.model) model.load_state_dict(state_dict) model = model.cuda() with torch.no_grad(): sample = model.infer('a bag')['samples'][0] sample.save('cat-toy-bag.png') ``` ## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py). Thanks for the efforts of the community! ## Citation ```bibtex @misc{gal2022textual, doi = {10.48550/ARXIV.2208.01618}, url = {https://arxiv.org/abs/2208.01618}, author = {Gal, Rinon and Alaluf, Yuval and Atzmon, Yuval and Patashnik, Or and Bermano, Amit H. and Chechik, Gal and Cohen-Or, Daniel}, title = {An Image is Worth One Word: Personalizing Text-to-Image Generation using Textual Inversion}, publisher = {arXiv}, year = {2022}, primaryClass={cs.CV} } ``` ================================================ FILE: configs/textual_inversion/metafile.yml ================================================ Collections: - Name: Textual Inversion Paper: Title: 'An Image is Worth One Word: Personalizing Text-to-Image Generation using Textual Inversion' URL: https://arxiv.org/abs/2208.01618 README: configs/textual_inversion/README.md Task: - text2image Year: 2022 Models: - Config: configs/textual_inversion/textual_inversion.py In Collection: Textual Inversion Name: textual_inversion Results: - Dataset: '-' Metrics: {} Task: Text2Image ================================================ FILE: configs/textual_inversion/textual_inversion.py ================================================ _base_ = '../_base_/gen_default_runtime.py' # config for model dtype = 'fp16' stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' placeholder_token = '' initialize_token = 'toy' num_vectors_per_token = 1 val_prompts = [ 'a on packbag', 'a on sofa', 'a in swimming pool', 'a ' ] model = dict( type='TextualInversion', placeholder_token=placeholder_token, vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', from_pretrained=stable_diffusion_v15_url, subfolder='unet'), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, initialize_token=initialize_token, num_vectors_per_token=num_vectors_per_token, val_prompts=val_prompts, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor', data_keys=None)) train_cfg = dict(max_iters=3000) optim_wrapper = dict( modules='.*trainable_embeddings', optimizer=dict(type='AdamW', lr=5e-4), accumulative_counts=1) pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='Resize', scale=(512, 512)), dict(type='PackInputs') ] dataset = dict( type='TextualInversionDataset', data_root='./data/', concept_dir='cat_toy', placeholder=placeholder_token, template='data/imagenet_templates_small.txt', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None default_hooks = dict( logger=dict(interval=10), checkpoint=dict(type='CheckpointHook', interval=10)) custom_hooks = [ dict( type='VisualizationHook', interval=50, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: configs/tof/README.md ================================================ # TOFlow (IJCV'2019) > [Video Enhancement with Task-Oriented Flow](https://arxiv.org/abs/1711.09078) > **Task**: Video Interpolation, Video Super-Resolution ## Abstract Many video enhancement algorithms rely on optical flow to register frames in a video sequence. Precise flow estimation is however intractable; and optical flow itself is often a sub-optimal representation for particular video processing tasks. In this paper, we propose task-oriented flow (TOFlow), a motion representation learned in a self-supervised, task-specific manner. We design a neural network with a trainable motion estimation component and a video processing component, and train them jointly to learn the task-oriented flow. For evaluation, we build Vimeo-90K, a large-scale, high-quality video dataset for low-level video processing. TOFlow outperforms traditional optical flow on standard benchmarks as well as our Vimeo-90K dataset in three video processing tasks: frame interpolation, video denoising/deblocking, and video super-resolution.
## Results and models Evaluated on Vimeo90k-triplet (RGB channels). The metrics are `PSNR / SSIM` . | Model | Dataset | Task | Pretrained SPyNet | PSNR | Training Resources | Download | | :---------------------------------------: | :--------------: | :-----------------: | :---------------------------------------------------: | :-----: | :-----------------: | :-------------------------------------------: | | [tof_vfi_spynet_chair_nobn_1xb1_vimeo90k](./tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Interpolation | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth) | 33.3294 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.log.json) | | [tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k](./tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Interpolation | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_kitti_20220321-dbcc1cc1.pth) | 33.3339 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.log.json) | | [tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Interpolation | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_clean_20220321-0756630b.pth) | 33.3170 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.log.json) | | [tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Interpolation | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_final_20220321-5e89dcec.pth) | 33.3237 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.log.json) | | [tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k](./tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Interpolation | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_pytoflow_20220321-5bab842d.pth) | 33.3426 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.log.json) | | Model | Dataset | Task | Pretrained SPyNet | SSIM | Training Resources | Download | | :--------------------------------------: | :--------------: | :--------------------: | :---------------------------------------------------: | :----: | :-----------------: | :------------------------------------------: | | [tof_vfi_spynet_chair_nobn_1xb1_vimeo90k](./tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Super-Resolution | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth) | 0.9465 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.log.json) | | [tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k](./tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Super-Resolution | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_kitti_20220321-dbcc1cc1.pth) | 0.9466 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.log.json) | | [tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Super-Resolution | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_clean_20220321-0756630b.pth) | 0.9464 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.log.json) | | [tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Super-Resolution | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_final_20220321-5e89dcec.pth) | 0.9465 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.log.json) | | [tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k](./tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py) | Vimeo90k-triplet | Video Super-Resolution | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_pytoflow_20220321-5bab842d.pth) | 0.9467 | 1 (Tesla PG503-216) | [model](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.pth) \| [log](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.log.json) | Note: These pretrained SPyNets don't contain BN layer since `batch_size=1`, which is consistent with `https://github.com/Coldog2333/pytoflow`. Evaluated on RGB channels. The metrics are `PSNR / SSIM` . | Model | Dataset | Task | Vid4 | Training Resources | Download | | :-------------------------------------------------------: | :------: | :--------------------: | :--------------: | :----------------: | :-----------------------------------------------------------------------------: | | [tof_x4_vimeo90k_official](./tof_x4_official_vimeo90k.py) | vimeo90k | Video Super-Resolution | 24.4377 / 0.7433 | - | [model](https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. TOF only supports video interpolation task for training now. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py # single-gpu train python tools/train.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py # multi-gpu train ./tools/dist_train.sh configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. TOF supports two tasks for testing. **Task 1**: Video Interpolation ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth # single-gpu test python tools/test.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth # multi-gpu test ./tools/dist_test.sh configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth 8 ``` **Task 2**: Video Super-Resolution ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth # single-gpu test python tools/test.py configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth # multi-gpu test ./tools/dist_test.sh configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @article{xue2019video, title={Video enhancement with task-oriented flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` ================================================ FILE: configs/tof/README_zh-CN.md ================================================ # TOFlow (IJCV'2019) > [Video Enhancement with Task-Oriented Flow](https://arxiv.org/abs/1711.09078) > **任务**: 视频插帧, 视频超分辨率 ## 预训练模型测试结果 在 RGB 通道上评估。 评估指标 `PSNR / SSIM`。 | 算法 | 预训练 SPyNet | Vimeo90k-triplet | GPU 信息 | 下载 | | :--------------------------------------------------: | :----------------------------------------------------------: | :--------------: | :-----------------: | :---------------------------------------------------: | | [tof_vfi_spynet_chair_nobn_1xb1_vimeo90k](./tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py) | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth) | 33.3294 / 0.9465 | 1 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.log.json) | | [tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k](./tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py) | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_kitti_20220321-dbcc1cc1.pth) | 33.3339 / 0.9466 | 1 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.log.json) | | [tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py) | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_clean_20220321-0756630b.pth) | 33.3170 / 0.9464 | 1 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.log.json) | | [tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k](./tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py) | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_sintel_final_20220321-5e89dcec.pth) | 33.3237 / 0.9465 | 1 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.log.json) | | [tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k](./tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py) | [spynet_chairs_final](https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_pytoflow_20220321-5bab842d.pth) | 33.3426 / 0.9467 | 1 (Tesla PG503-216) | [模型](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.pth) \| [日志](https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.log.json) | 注: 由于 `batch_size=1` 预训练的 SPyNet 不包含 BN 层,这与 `https://github.com/Coldog2333/pytoflow` 一致. ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 TOF 的训练仅支持视频插帧任务。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py # 单个GPU上训练 python tools/train.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py # 多个GPU上训练 ./tools/dist_train.sh configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 TOF 的测试支持视频插帧和视频超分辨率两种任务。 **任务 1**: 视频插帧 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth # 单个GPU上测试 python tools/test.py configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth # 多个GPU上测试 ./tools/dist_test.sh configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py https://download.openmmlab.com/mmediting/video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth 8 ``` **任务 2**: 视频超分辨率 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth # 单个GPU上测试 python tools/test.py configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth # 多个GPU上测试 ./tools/dist_test.sh configs/tof/tof_x4_official_vimeo90k.py https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
## Citation ```bibtex @article{xue2019video, title={Video enhancement with task-oriented flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` ================================================ FILE: configs/tof/metafile.yml ================================================ Collections: - Name: TOFlow Paper: Title: Video Enhancement with Task-Oriented Flow URL: https://arxiv.org/abs/1711.09078 README: configs/tof/README.md Task: - video interpolation - video super-resolution Year: 2019 Models: - Config: configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py In Collection: TOFlow Name: tof_spynet-chair-wobn_1xb1_vimeo90k-triplet Results: - Dataset: Vimeo90k-triplet Metrics: PSNR: 33.3294 Task: Video Interpolation - Dataset: Vimeo90k-triplet Metrics: SSIM: 0.9465 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_chair_nobn_1xb1_vimeo90k_20220321-2fc9e258.pth - Config: configs/tof/tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py In Collection: TOFlow Name: tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet Results: - Dataset: Vimeo90k-triplet Metrics: PSNR: 33.3339 Task: Video Interpolation - Dataset: Vimeo90k-triplet Metrics: SSIM: 0.9466 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_kitti_nobn_1xb1_vimeo90k_20220321-3f7ca4cd.pth - Config: configs/tof/tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py In Collection: TOFlow Name: tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet Results: - Dataset: Vimeo90k-triplet Metrics: PSNR: 33.317 Task: Video Interpolation - Dataset: Vimeo90k-triplet Metrics: SSIM: 0.9464 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_clean_nobn_1xb1_vimeo90k_20220321-6e52a6fd.pth - Config: configs/tof/tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py In Collection: TOFlow Name: tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet Results: - Dataset: Vimeo90k-triplet Metrics: PSNR: 33.3237 Task: Video Interpolation - Dataset: Vimeo90k-triplet Metrics: SSIM: 0.9465 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_sintel_final_nobn_1xb1_vimeo90k_20220321-8ab70dbb.pth - Config: configs/tof/tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py In Collection: TOFlow Name: tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet Results: - Dataset: Vimeo90k-triplet Metrics: PSNR: 33.3426 Task: Video Interpolation - Dataset: Vimeo90k-triplet Metrics: SSIM: 0.9467 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/video_interpolators/toflow/tof_vfi_spynet_pytoflow_nobn_1xb1_vimeo90k_20220321-5f4b243e.pth - Config: configs/tof/tof_x4_official_vimeo90k.py In Collection: TOFlow Name: tof_x4_official_vimeo90k Results: - Dataset: vimeo90k Metrics: Vid4: PSNR: 24.4377 SSIM: 0.7433 Task: Video Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/tof/tof_x4_vimeo90k_official-a569ff50.pth ================================================ FILE: configs/tof/tof_spynet-chair-wobn_1xb1_vimeo90k-triplet.py ================================================ _base_ = '../_base_/models/base_tof.py' experiment_name = 'tof_spynet-chair-wobn_1xb1_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # pretrained SPyNet load_pretrained_spynet = 'https://download.openmmlab.com/mmediting/' +\ 'video_interpolators/toflow/pretrained_spynet_chair_20220321-4d82e91b.pth' # model settings model = dict( type='BasicInterpolator', generator=dict( type='TOFlowVFINet', flow_cfg=dict(norm_cfg=None, pretrained=load_pretrained_spynet)), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], pad_size_divisor=16, pad_mode='reflect', )) ================================================ FILE: configs/tof/tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet.py ================================================ _base_ = '../_base_/models/base_tof.py' experiment_name = 'tof_spynet-kitti-wobn_1xb1_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # pretrained SPyNet load_pretrained_spynet = 'https://download.openmmlab.com/mmediting/' +\ 'video_interpolators/toflow/pretrained_spynet_kitti_20220321-dbcc1cc1.pth' # model settings model = dict( type='BasicInterpolator', generator=dict( type='TOFlowVFINet', flow_cfg=dict(norm_cfg=None, pretrained=load_pretrained_spynet)), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], pad_size_divisor=16, pad_mode='reflect', )) ================================================ FILE: configs/tof/tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet.py ================================================ _base_ = '../_base_/models/base_tof.py' experiment_name = 'tof_spynet-pytoflow-wobn_1xb1_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # pretrained SPyNet load_pretrained_spynet = 'https://download.openmmlab.com/mmediting/video_' +\ 'interpolators/toflow/pretrained_spynet_pytoflow_20220321-5bab842d.pth' # model settings model = dict( type='BasicInterpolator', generator=dict( type='TOFlowVFINet', flow_cfg=dict(norm_cfg=None, pretrained=load_pretrained_spynet)), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], pad_size_divisor=16, pad_mode='reflect', )) ================================================ FILE: configs/tof/tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet.py ================================================ _base_ = '../_base_/models/base_tof.py' experiment_name = 'tof_spynet-sintel-wobn-clean_1xb1_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # pretrained SPyNet load_pretrained_spynet = 'https://download.openmmlab.com/mmediting/video_' +\ 'interpolators/toflow/pretrained_spynet_sintel_clean_20220321-0756630b.pth' # model settings model = dict( type='BasicInterpolator', generator=dict( type='TOFlowVFINet', flow_cfg=dict(norm_cfg=None, pretrained=load_pretrained_spynet)), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], pad_size_divisor=16, pad_mode='reflect', )) ================================================ FILE: configs/tof/tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet.py ================================================ _base_ = '../_base_/models/base_tof.py' experiment_name = 'tof_spynet-sintel-wobn-final_1xb1_vimeo90k-triplet' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # pretrained SPyNet load_pretrained_spynet = 'https://download.openmmlab.com/mmediting/video_' +\ 'interpolators/toflow/pretrained_spynet_sintel_final_20220321-5e89dcec.pth' # model settings model = dict( type='BasicInterpolator', generator=dict( type='TOFlowVFINet', flow_cfg=dict(norm_cfg=None, pretrained=load_pretrained_spynet)), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), required_frames=2, step_frames=1, init_cfg=None, data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], pad_size_divisor=16, pad_mode='reflect', )) ================================================ FILE: configs/tof/tof_x4_official_vimeo90k.py ================================================ # only testing the official model is supported _base_ = '../_base_/default_runtime.py' experiment_name = 'tof_x4_official_vimeo90k' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs' # model settings model = dict( type='EDVR', # use the shared model with EDVR generator=dict(type='TOFlowVSRNet', adapt_official_weights=True), pixel_loss=dict(type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), data_preprocessor=dict( type='DataPreprocessor', mean=[0.485 * 255, 0.456 * 255, 0.406 * 255], std=[0.229 * 255, 0.224 * 255, 0.225 * 255], )) val_pipeline = [ dict(type='GenerateFrameIndiceswithPadding', padding='reflection_circle'), dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] demo_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb'), dict(type='PackInputs') ] data_root = 'data/Vid4' val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='BasicFramesDataset', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='BIx4up_direct', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=7, pipeline=val_pipeline)) # TODO: data is not uploaded yet # test_dataloader = val_dataloader val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR'), dict(type='SSIM'), ]) # test_evaluator = val_evaluator val_cfg = dict(type='MultiValLoop') # test_cfg = dict(type='MultiTestLoop') ================================================ FILE: configs/ttsr/README.md ================================================ # TTSR (CVPR'2020) > [Learning Texture Transformer Network for Image Super-Resolution](https://arxiv.org/abs/2006.04139) > **Task**: Image Super-Resolution ## Abstract We study on image super-resolution (SR), which aims to recover realistic textures from a low-resolution (LR) image. Recent progress has been made by taking high-resolution images as references (Ref), so that relevant textures can be transferred to LR images. However, existing SR approaches neglect to use attention mechanisms to transfer high-resolution (HR) textures from Ref images, which limits these approaches in challenging cases. In this paper, we propose a novel Texture Transformer Network for Image Super-Resolution (TTSR), in which the LR and Ref images are formulated as queries and keys in a transformer, respectively. TTSR consists of four closely-related modules optimized for image generation tasks, including a learnable texture extractor by DNN, a relevance embedding module, a hard-attention module for texture transfer, and a soft-attention module for texture synthesis. Such a design encourages joint feature learning across LR and Ref images, in which deep feature correspondences can be discovered by attention, and thus accurate texture features can be transferred. The proposed texture transformer can be further stacked in a cross-scale way, which enables texture recovery from different levels (e.g., from 1x to 4x magnification). Extensive experiments show that TTSR achieves significant improvements over state-of-the-art approaches on both quantitative and qualitative evaluations.
## Results and models Evaluated on CUFED dataset (RGB channels), `scale` pixels in each border are cropped before evaluation. The metrics are `PSNR and SSIM` . | Model | Dataset | scale | PSNR | SSIM | Training Resources | Download | | :------------------------------------------------------------------------: | :-----: | :---: | :-----: | :----: | :----------------: | :---------------------------------------------------------------------------------: | | [ttsr-rec_x4_c64b16_g1_200k_CUFED](./ttsr-rec_x4c64b16_1xb9-200k_CUFED.py) | CUFED | x4 | 25.2433 | 0.7491 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-rec_x4_c64b16_g1_200k_CUFED_20210525-b0dba584.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-rec_x4_c64b16_g1_200k_CUFED_20210525-b0dba584.log.json) | | [ttsr-gan_x4_c64b16_g1_500k_CUFED](./ttsr-gan_x4c64b16_1xb9-500k_CUFED.py) | CUFED | x4 | 24.6075 | 0.7234 | 1 (TITAN Xp) | [model](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth) \| [log](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.log.json) | ## Quick Start **Train**
Train Instructions You can use the following commands to train a model with cpu or single/multiple GPUs. ```shell # cpu train CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py # single-gpu train python tools/train.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py # multi-gpu train ./tools/dist_train.sh configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py 8 ``` For more details, you can refer to **Train a model** part in [train_test.md](/docs/en/user_guides/train_test.md#Train-a-model-in-MMagic).
**Test**
Test Instructions You can use the following commands to test a model with cpu or single/multiple GPUs. ```shell # cpu test CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth # single-gpu test python tools/test.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth # multi-gpu test ./tools/dist_test.sh configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth 8 ``` For more details, you can refer to **Test a pre-trained model** part in [train_test.md](/docs/en/user_guides/train_test.md#Test-a-pre-trained-model-in-MMagic).
## Citation ```bibtex @inproceedings{yang2020learning, title={Learning texture transformer network for image super-resolution}, author={Yang, Fuzhi and Yang, Huan and Fu, Jianlong and Lu, Hongtao and Guo, Baining}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={5791--5800}, year={2020} } ``` ================================================ FILE: configs/ttsr/README_zh-CN.md ================================================ # TTSR (CVPR'2020) > **任务**: 图像超分辨率
TTSR (CVPR'2020) ```bibtex @inproceedings{yang2020learning, title={Learning texture transformer network for image super-resolution}, author={Yang, Fuzhi and Yang, Huan and Fu, Jianlong and Lu, Hongtao and Guo, Baining}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={5791--5800}, year={2020} } ```

在 RGB 通道上进行评估,在评估之前裁剪每个边界中的 `scale` 像素。 我们使用 `PSNR` 和 `SSIM` 作为指标。 | 算法 | scale | CUFED | GPU 信息 | 下载 | | :------------------------------------------------------------------------: | :---: | :--------------: | :----------: | :-------------------------------------------------------------------------------------------: | | [ttsr-rec_x4_c64b16_g1_200k_CUFED](./ttsr-rec_x4c64b16_1xb9-200k_CUFED.py) | x4 | 25.2433 / 0.7491 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-rec_x4_c64b16_g1_200k_CUFED_20210525-b0dba584.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-rec_x4_c64b16_g1_200k_CUFED_20210525-b0dba584.log.json) | | [ttsr-gan_x4_c64b16_g1_500k_CUFED](./ttsr-gan_x4c64b16_1xb9-500k_CUFED.py) | x4 | 24.6075 / 0.7234 | 1 (TITAN Xp) | [模型](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth) \| [日志](https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.log.json) | ## 快速开始 **训练**
训练说明 您可以使用以下命令来训练模型。 ```shell # CPU上训练 CUDA_VISIBLE_DEVICES=-1 python tools/train.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py # 单个GPU上训练 python tools/train.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py # 多个GPU上训练 ./tools/dist_train.sh configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Train a model** 部分。
**测试**
测试说明 您可以使用以下命令来测试模型。 ```shell # CPU上测试 CUDA_VISIBLE_DEVICES=-1 python tools/test.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth # 单个GPU上测试 python tools/test.py configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth # 多个GPU上测试 ./tools/dist_test.sh configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth 8 ``` 更多细节可以参考 [train_test.md](/docs/zh_cn/user_guides/train_test.md) 中的 **Test a pre-trained model** 部分。
================================================ FILE: configs/ttsr/metafile.yml ================================================ Collections: - Name: TTSR Paper: Title: Learning Texture Transformer Network for Image Super-Resolution URL: https://arxiv.org/abs/2006.04139 README: configs/ttsr/README.md Task: - image super-resolution Year: 2020 Models: - Config: configs/ttsr/ttsr-rec_x4c64b16_1xb9-200k_CUFED.py In Collection: TTSR Name: ttsr-rec_x4c64b16_1xb9-200k_CUFED Results: - Dataset: CUFED Metrics: PSNR: 25.2433 SSIM: 0.7491 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-rec_x4_c64b16_g1_200k_CUFED_20210525-b0dba584.pth - Config: configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py In Collection: TTSR Name: ttsr-gan_x4c64b16_1xb9-500k_CUFED Results: - Dataset: CUFED Metrics: PSNR: 24.6075 SSIM: 0.7234 Task: Image Super-Resolution Weights: https://download.openmmlab.com/mmediting/restorers/ttsr/ttsr-gan_x4_c64b16_g1_500k_CUFED_20210626-2ab28ca0.pth ================================================ FILE: configs/ttsr/ttsr-gan_x4c64b16_1xb9-500k_CUFED.py ================================================ _base_ = './ttsr-rec_x4c64b16_1xb9-200k_CUFED.py' experiment_name = 'ttsr-gan_x4c64b16_1xb9-500k_CUFED' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings model = dict( type='TTSR', generator=dict( type='TTSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=(16, 16, 8, 4)), extractor=dict(type='LTE'), transformer=dict(type='SearchTransformer'), discriminator=dict(type='TTSRDiscriminator', in_size=160), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'29': 1.0}, vgg_type='vgg19', perceptual_weight=1e-2, style_weight=0, criterion='mse'), transferal_perceptual_loss=dict( type='TransferalPerceptualLoss', loss_weight=1e-2, use_attention=False, criterion='mse'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-3, real_label_val=1.0, fake_label_val=0), train_cfg=dict(pixel_init=25000, disc_repeat=2), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], )) train_cfg = dict( type='IterBasedTrainLoop', max_iters=500_000, val_interval=5000) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), extractor=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-5, betas=(0.9, 0.999))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-5, betas=(0.9, 0.999)))) # learning policy param_scheduler = dict( _delete_=True, type='MultiStepLR', by_epoch=False, milestones=[100000, 200000, 300000, 400000], gamma=0.5) ================================================ FILE: configs/ttsr/ttsr-rec_x4c64b16_1xb9-200k_CUFED.py ================================================ _base_ = '../_base_/default_runtime.py' experiment_name = 'ttsr-rec_x4c64b16_1xb9-200k_CUFED' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # DistributedDataParallel model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # model settings model = dict( type='TTSR', generator=dict( type='TTSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=(16, 16, 8, 4)), extractor=dict(type='LTE'), transformer=dict(type='SearchTransformer'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), train_cfg=dict(), test_cfg=dict(), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], )) train_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='ref', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='ModCrop', key='gt'), dict(type='CropLike', target_key='ref', reference_key='gt'), dict( type='Resize', scale=1 / scale, keep_ratio=True, keys=['gt', 'ref'], output_keys=['img', 'ref_down'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=float(scale), keep_ratio=True, keys=['img', 'ref_down'], output_keys=['img_lq', 'ref_lq'], interpolation='bicubic', backend='pillow'), dict( type='Flip', keys=['img', 'gt', 'img_lq'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt', 'img_lq'], flip_ratio=0.5, direction='vertical'), dict( type='RandomTransposeHW', keys=['img', 'gt', 'img_lq'], transpose_ratio=0.5), dict( type='Flip', keys=['ref', 'ref_lq'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['ref', 'ref_lq'], flip_ratio=0.5, direction='vertical'), dict( type='RandomTransposeHW', keys=['ref', 'ref_lq'], transpose_ratio=0.5), dict(type='PackInputs') ] valid_pipeline = [ dict( type='LoadImageFromFile', key='gt', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='ref', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='ModCrop', key='gt'), dict(type='CropLike', target_key='ref', reference_key='gt'), dict( type='Resize', scale=1 / scale, keep_ratio=True, keys=['gt', 'ref'], output_keys=['img', 'ref_down'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=float(scale), keep_ratio=True, keys=['img', 'ref_down'], output_keys=['img_lq', 'ref_lq'], interpolation='bicubic', backend='pillow'), dict(type='PackInputs') ] demo_pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict( type='LoadImageFromFile', key='ref', color_type='color', channel_order='rgb', imdecode_backend='pillow'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='ModCrop', key='img'), dict( type='Resize', scale=1 / scale, keep_ratio=True, keys=['ref'], output_keys=['ref_down'], interpolation='bicubic', backend='pillow'), dict( type='Resize', scale=float(scale), keep_ratio=True, keys=['img', 'ref_down'], output_keys=['img_lq', 'ref_lq'], interpolation='bicubic', backend='pillow'), dict(type='PackInputs') ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=9, batch_size=9, persistent_workers=False, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cufed', task_name='refsr'), data_root=data_root + '/CUFED', data_prefix=dict(ref='ref', gt='input'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=8, persistent_workers=False, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='cufed', task_name='refsr'), data_root=data_root + '/CUFED', data_prefix=dict(ref='CUFED5', gt='CUFED5'), filename_tmpl=dict(ref='{}_1', gt='{}_0'), pipeline=valid_pipeline)) test_dataloader = val_dataloader val_evaluator = dict( type='Evaluator', metrics=[ dict(type='MAE'), dict(type='PSNR', crop_border=scale), dict(type='SSIM', crop_border=scale), ]) test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=200_000, val_interval=5000) val_cfg = dict(type='MultiValLoop') test_cfg = dict(type='MultiTestLoop') # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))), extractor=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-5, betas=(0.9, 0.999)))) # learning policy param_scheduler = dict( type='MultiStepLR', by_epoch=False, milestones=[100000], gamma=0.5) default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ================================================ FILE: configs/vico/README.md ================================================ # ViCo (2023) > [ViCo: Detail-Preserving Visual Condition for Personalized Text-to-Image Generation](https://arxiv.org/abs/2306.00971) > **Task**: Text2Image ## Abstract Personalized text-to-image generation using diffusion models has recently been proposed and attracted lots of attention. Given a handful of images containing a novel concept (e.g., a unique toy), we aim to tune the generative model to capture fine visual details of the novel concept and generate photorealistic images following a text condition. We present a plug-in method, named ViCo, for fast and lightweight personalized generation. Specifically, we propose an image attention module to condition the diffusion process on the patch-wise visual semantics. We introduce an attention-based object mask that comes almost at no cost from the attention module. In addition, we design a simple regularization based on the intrinsic properties of text-image attention maps to alleviate the common overfitting degradation. Unlike many existing models, our method does not finetune any parameters of the original diffusion model. This allows more flexible and transferable model deployment. With only light parameter training (~6% of the diffusion U-Net), our method achieves comparable or even better performance than all state-of-the-art models both qualitatively and quantitatively.
## Configs | Model | Dataset | Download | | :---------------: | :-----: | :------: | | [ViCo](./vico.py) | - | - | ## Quick Start 1. Download concept data and imagenet_templates_small.txt from [here](https://openxlab.org.cn/datasets/ferry/ViCo/tree/main). and save to `data/vico/` The file structure will be like this: ```text data └── vico └──batman ├── 1.jpg ├── 2.jpg ├── 3.jpg └── 4.jpg └──clock ├── 1.jpg ├── 2.jpg ├── 3.jpg └── 4.jpg ... └──imagenet_templates_small.txt ``` 2. Customize your config ``` # Only need to care about these # which concept you want to customize concept_dir = 'dog7' # the new token to denote the concept placeholder: str = 'S*' # better to be the superclass of concept initialize_token: str = 'dog' ``` 3. Start training with the following command: ```bash # 4 GPUS bash tools/dist_train.sh configs/vico/vico.py 4 # 1 GPU python tools/train.py configs/vico/vico.py ``` 4. Use the [pretrained checkpoins](https://openxlab.org.cn/models/detail/ferry/ViCo) to inference ```python import torch from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() # say you have downloaded the pretrained weights cfg = Config.fromfile('configs/vico/dog.py') state_dict = torch.load("./dog.pth") vico = MODELS.build(cfg.model) vico.load_state_dict(state_dict, strict=False) vico = vico.cuda() prompt = ["A photo of S*", "A photo of S* on the beach"] reference = "data/vico/dog7/01.jpg" image_ref = Image.open(reference) with torch.no_grad(): output = vico.infer(prompt=prompt, image_reference=image_ref, seed=123, num_images_per_prompt=2)['samples'][0] output.save("infer.png") ``` 5. (Optional) If you want to use the weight trained by the commands at step3, here are codes to extract the trained parameters, then you can infer with it like step4 ```python import torch def extract_vico_parameters(state_dict): new_state_dict = dict() for k, v in state_dict.items(): if 'image_cross_attention' in k or 'trainable_embeddings' in k: new_k = k.replace('module.', '') new_state_dict[new_k] = v return new_state_dict checkpoint = torch.load("work_dirs/vico/iter_400.pth") new_checkpoint = extract_vico_parameters(checkpoint['state_dict']) torch.save(new_checkpoint, "work_dirs/vico/dog.pth") ```

'vico'
## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py). Thanks for the efforts of the community! ## Citation ```bibtex @inproceedings{Hao2023ViCo, title={ViCo: Detail-Preserving Visual Condition for Personalized Text-to-Image Generation}, author={Shaozhe Hao and Kai Han and Shihao Zhao and Kwan-Yee K. Wong}, year={2023} } ``` ================================================ FILE: configs/vico/README_zh-CN.md ================================================ # ViCo (2023) > [ViCo: Detail-Preserving Visual Condition for Personalized Text-to-Image Generation](https://arxiv.org/abs/2306.00971) > **Task**: 文本图像生成 ## 摘要 最近,个性化文本到图像生成使用扩散模型的方法被提出,并引起了广泛关注。给定包含新概念(例如独特的玩具)的少量图像,我们旨在调整生成模型,以捕捉新概念的精细视觉细节,并根据文本条件生成逼真的图像。我们提出了一种名为ViCo的插件方法,用于快速轻量级个性化生成。具体而言,我们提出了一个图像注意力模块,以对基于补丁的视觉语义进行扩散过程的条件建模。我们引入了一种基于注意力模块的对象蒙版,几乎没有额外计算成本。此外,我们设计了一个简单的正则化方法,基于文本-图像注意力图的内在属性,以减轻常见的过拟合退化问题。与许多现有模型不同,我们的方法不对原始扩散模型的任何参数进行微调。这使得模型的部署更加灵活和可转移。通过仅进行轻量级参数训练(约为扩散U-Net的6%),我们的方法在质量和数量上都达到了与所有最先进模型相当甚至更好的性能。
## 模型结构 | 模型 | 数据集 | 下载 | | :---------------: | :-----------------------------------------------------------------------: | :--: | | [ViCo](./vico.py) | [textual_inversion_dataset](mmagic/datasets/textual_inversion_dataset.py) | - | ## Quick Start 1. 下载 [数据集](https://drive.google.com/drive/folders/1m8TCsY-C1tIOflHtWnFzTbw2C6dq67mC) 和 [模板](https://drive.google.com/drive/folders/1SpByLKECISmj5fhkaicT4yrsyqqpWL_T) and save to `data/vico/` 文件夹结构应如下: ```text data └── vico └──batman ├── 1.jpg ├── 2.jpg ├── 3.jpg └── 4.jpg └──clock ├── 1.jpg ├── 2.jpg ├── 3.jpg └── 4.jpg ... └──imagenet_templates_small.txt ``` 2. 自定义你自己的config文件 ``` # 请关注以下需自定义的内容 # 设置concept文件夹名 concept_dir = 'dog7' # 设置代表这个concept的新字符 placeholder: str = 'S*' # 初始化字符,最好是设置这个concept所属的类别 initialize_token: str = 'dog' ``` 3. 使用以下命令进行**训练**: ```bash # 4 GPUS bash tools/dist_train.sh configs/vico/vico.py 4 # 1 GPU python tools/train.py configs/vico/vico.py ``` 4. 使用 [预训练的权重](https://drive.google.com/drive/folders/1GQGVzzOP2IgEfsQ-6ii6o2DqElnFThHM) 进行**推理** ```python import torch from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() # say you have downloaded the pretrained weights cfg = Config.fromfile('configs/vico/dog.py') state_dict = torch.load("./dog.pth") vico = MODELS.build(cfg.model) vico.load_state_dict(state_dict, strict=False) vico = vico.cuda() prompt = ["A photo of S*", "A photo of S* on the beach"] reference = "data/vico/dog7/01.jpg" image_ref = Image.open(reference) with torch.no_grad(): output = vico.infer(prompt=prompt, image_reference=image_ref, seed=123, num_images_per_prompt=2)['samples'][0] output.save("infer.png") ``` 5. (可选) 如果你想使用第3步训练得到的checkpoint进行推理,可以先使用以下脚本将训练过的参数提取出来(文件大小会轻量很多),再使用第4步进行推理 ```python import torch def extract_vico_parameters(state_dict): new_state_dict = dict() for k, v in state_dict.items(): if 'image_cross_attention' in k or 'trainable_embeddings' in k: new_k = k.replace('module.', '') new_state_dict[new_k] = v return new_state_dict checkpoint = torch.load("work_dirs/vico/iter_400.pth") new_checkpoint = extract_vico_parameters(checkpoint['state_dict']) torch.save(new_checkpoint, "work_dirs/vico/dog.pth") ```

'vico'
## Comments Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py). Thanks for the efforts of the community! ## Citation ```bibtex @inproceedings{Hao2023ViCo, title={ViCo: Detail-Preserving Visual Condition for Personalized Text-to-Image Generation}, author={Shaozhe Hao and Kai Han and Shihao Zhao and Kwan-Yee K. Wong}, year={2023} } ``` ================================================ FILE: configs/vico/metafile.yml ================================================ Collections: - Name: ViCo Paper: Title: 'ViCo: Detail-Preserving Visual Condition for Personalized Text-to-Image Generation' URL: https://arxiv.org/abs/2306.00971 README: configs/vico/README.md Task: - text2image Year: 2023 Models: - Config: configs/vico/vico.py In Collection: ViCo Name: vico Results: - Dataset: '-' Metrics: {} Task: Text2Image ================================================ FILE: configs/vico/vico.py ================================================ _base_ = '../_base_/gen_default_runtime.py' randomness = dict(seed=2023, diff_rank_seed=True) # dtype="fp32" # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' data_root = './data/vico' concept_dir = 'dog7' # 1 for using image cross image_cross_layers = [ # down blocks (2x transformer block) * (3x down blocks) = 6 0, 0, 0, 0, 0, 0, # mid block (1x transformer block) * (1x mid block)= 1 0, # up blocks (3x transformer block) * (3x up blocks) = 9 0, 1, 0, 1, 0, 1, 0, 1, 0, ] reg_loss_weight: float = 5e-4 placeholder: str = 'S*' val_prompts = ['a photo of a S*'] initialize_token: str = 'dog' num_vectors_per_token: int = 1 model = dict( type='ViCo', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_v15_url), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), # dtype=dtype, data_preprocessor=dict(type='DataPreprocessor', data_keys=None), image_cross_layers=image_cross_layers, reg_loss_weight=reg_loss_weight, placeholder=placeholder, initialize_token=initialize_token, num_vectors_per_token=num_vectors_per_token, val_prompts=val_prompts) train_cfg = dict(max_iters=500) paramwise_cfg = dict( custom_keys={ 'image_cross_attention': dict(lr_mult=2e-3), 'trainable_embeddings': dict(lr_mult=1.0) }) optim_wrapper = dict( optimizer=dict(type='AdamW', lr=0.005, weight_decay=0.01), constructor='DefaultOptimWrapperConstructor', paramwise_cfg=paramwise_cfg, accumulative_counts=1) pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='img_ref', channel_order='rgb'), dict(type='Resize', keys=['img', 'img_ref'], scale=(512, 512)), dict( type='PackInputs', keys=['img', 'img_ref'], data_keys='prompt', meta_keys=[ 'img_channel_order', 'img_color_type', 'img_ref_channel_order', 'img_ref_color_type' ]) ] dataset = dict( type='TextualInversionDataset', data_root=data_root, concept_dir=concept_dir, placeholder=placeholder, template='data/vico/imagenet_templates_small.txt', with_image_reference=True, pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type='InfiniteSampler', shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks = dict(logger=dict(interval=10)) custom_hooks = [ dict( type='VisualizationHook', interval=50, fixed_input=True, # visualize train dataset vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: configs/wgan-gp/README.md ================================================ # WGAN-GP (NeurIPS'2017) > [Improved Training of Wasserstein GANs](https://arxiv.org/abs/1704.00028) > **Task**: Unconditional GANs ## Abstract Generative Adversarial Networks (GANs) are powerful generative models, but suffer from training instability. The recently proposed Wasserstein GAN (WGAN) makes progress toward stable training of GANs, but sometimes can still generate only low-quality samples or fail to converge. We find that these problems are often due to the use of weight clipping in WGAN to enforce a Lipschitz constraint on the critic, which can lead to undesired behavior. We propose an alternative to clipping weights: penalize the norm of gradient of the critic with respect to its input. Our proposed method performs better than standard WGAN and enables stable training of a wide variety of GAN architectures with almost no hyperparameter tuning, including 101-layer ResNets and language models over discrete data. We also achieve high quality generations on CIFAR-10 and LSUN bedrooms.
## Results and models
WGAN-GP 128, CelebA-Cropped
| Model | Dataset | Details | SWD | MS-SSIM | Download | | :--------------------------------------------------------------: | :------------: | :----------------: | :---------------------------: | :-----: | :------------------------------------------------------------------: | | [WGAN-GP 128](./wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py) | CelebA-Cropped | GN | 5.87, 9.76, 9.43, 18.84/10.97 | 0.2601 | [model](https://download.openmmlab.com/mmediting/wgangp/wgangp_GN_celeba-cropped_128_b64x1_160k_20210408_170611-f8a99336.pth) | | [WGAN-GP 128](./wgangp_GN-GP-50_1xb64-160kiters_lsun-bedroom-128x128.py) | LSUN-Bedroom | GN, GP-lambda = 50 | 11.7, 7.87, 9.82, 25.36/13.69 | 0.059 | [model](https://download.openmmlab.com/mmediting/wgangp/wgangp_GN_GP-50_lsun-bedroom_128_b64x1_130k_20210408_170509-56f2a37c.pth) | ## Citation ```latex @article{gulrajani2017improved, title={Improved Training of Wasserstein GANs}, author={Gulrajani, Ishaan and Ahmed, Faruk and Arjovsky, Martin and Dumoulin, Vincent and Courville, Aaron}, journal={arXiv preprint arXiv:1704.00028}, year={2017}, url={https://arxiv.org/abs/1704.00028}, } ``` ================================================ FILE: configs/wgan-gp/metafile.yml ================================================ Collections: - Name: WGAN-GP Paper: Title: Improved Training of Wasserstein GANs URL: https://arxiv.org/abs/1704.00028 README: configs/wgan-gp/README.md Task: - unconditional gans Year: 2017 Models: - Config: configs/wgan-gp/wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py In Collection: WGAN-GP Name: wgangp_GN_1xb64-160kiters_celeba-cropped-128x128 Results: - Dataset: CelebA-Cropped Metrics: MS-SSIM: 0.2601 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/wgangp/wgangp_GN_celeba-cropped_128_b64x1_160k_20210408_170611-f8a99336.pth - Config: configs/wgan-gp/wgangp_GN-GP-50_1xb64-160kiters_lsun-bedroom-128x128.py In Collection: WGAN-GP Name: wgangp_GN-GP-50_1xb64-160kiters_lsun-bedroom-128x128 Results: - Dataset: LSUN-Bedroom Metrics: MS-SSIM: 0.059 Task: Unconditional GANs Weights: https://download.openmmlab.com/mmediting/wgangp/wgangp_GN_GP-50_lsun-bedroom_128_b64x1_130k_20210408_170509-56f2a37c.pth ================================================ FILE: configs/wgan-gp/wgangp_GN-GP-50_1xb64-160kiters_lsun-bedroom-128x128.py ================================================ _base_ = ['./wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py'] loss_config = dict(gp_norm_mode='HWC', gp_loss_weight=50) model = dict(loss_config=loss_config) batch_size = 64 data_root = './data/lsun/images/bedroom_train' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) ================================================ FILE: configs/wgan-gp/wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py ================================================ _base_ = [ '../_base_/datasets/unconditional_imgs_128x128.py', '../_base_/gen_default_runtime.py', ] # MODEL loss_config = dict(gp_norm_mode='HWC', gp_loss_weight=10) model = dict( type='WGANGP', data_preprocessor=dict(type='DataPreprocessor'), generator=dict(type='WGANGPGenerator', noise_size=128, out_scale=128), discriminator=dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128, conv_module_cfg=dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='GN'), order=('conv', 'norm', 'act'))), discriminator_steps=5, loss_config=loss_config) # `batch_size` and `data_root` need to be set. batch_size = 64 data_root = './data/celeba-cropped/cropped_images_aligned_png/' train_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader = dict(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader = dict( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = dict(max_iters=160000) optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.9))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0001, betas=(0.5, 0.9)))) # VIS_HOOK custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig'), dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 128, 128)) ] # save multi best checkpoints default_hooks = dict(checkpoint=dict(save_best='swd/avg')) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: demo/README.md ================================================ # MMagic Demo There are some mmagic demos in this folder. We provide python command line usage here to run these demos and more guidance could also be found in the [documentation](https://mmagic.readthedocs.io/en/latest/user_guides/inference.html) Table of contents: [1. Download sample images or videos](#1-download-sample-images-or-videos) [2. MMagic inference demo](#2-mmagic-inference-demo)     [2.1. Check supported tasks and models](#21-check-supported-tasks-and-models)     [2.2. Perform inference with command line](#22-perform-inference-with-command-line)       [2.2.1. Text-to-Image example](#221-text-to-image)       [2.2.2. Conditional GANs example](#222-conditional-gans)       [2.2.3. Unconditional GANs example](#223-unconditional-gans)       [2.2.4. Image Translation (Image2Image) example](#224-image-translation)       [2.2.5. Inpainting example](#225-inpainting)       [2.2.6. Matting example](#226-matting)       [2.2.7. Image Restoration example](#227-image-restoration)       [2.2.8. Image Super-Resolution example](#228-image-super-resolution)       [2.2.9. Video Super-Resolution example](#229-video-super-resolution)       [2.2.10. Video Interpolation example](#2210-video-interpolation)       [2.2.11. Image Colorization example](#2211-image-colorization)       [2.2.12. 3D-aware Generation example](#2212-3d-aware-generation) [3. Other demos](#3-other-demos)     [3.1. Gradio demo](#31-gradio-demo)       [3.1.1. DragGAN](#311-draggan)       [3.1.2. ViCo](#312-vico)       [3.1.3. FastComposer](#313-fastcomposer)       [3.1.4. AnimateDiff](#314-animatediff) ## 1. Download sample images or videos We prepared some images and videos for you to run demo with. After MMagic is well installed, you could use demos in this folder to infer these data. Download with python script [download_inference_resources.py](./download_inference_resources.py). ```shell # see all resources python demo/download_inference_resources.py --print-all # see all task types python demo/download_inference_resources.py --print-task-type # see resources of one specific task python demo/download_inference_resources.py --print-task 'Inpainting' # download all resources to default dir './resources' python demo/download_inference_resources.py # download resources of one task python demo/download_inference_resources.py --task 'Inpainting' # download to the directory you want python demo/download_inference_resources.py --root-dir './resources' ``` ## 2. MMagic inference demo ### 2.1 Check supported tasks and models print all supported models for inference. ```shell python demo/mmagic_inference_demo.py --print-supported-models ``` print all supported tasks for inference. ```shell python demo/mmagic_inference_demo.py --print-supported-tasks ``` print all supported models for one task, take 'Image2Image' for example. ```shell python demo/mmagic_inference_demo.py --print-task-supported-models 'Text2Image' ``` ### 2.2 Perform inference with command line You can use the following commands to perform inference with a MMagic model. Usage of python API can also be found in this [tutotial](./mmagic_inference_tutorial.ipynb). ```shell python demo/mmagic_inference_demo.py \ [--img] \ [--video] \ [--label] \ [--trimap] \ [--mask] \ [--result-out-dir] \ [--model-name] \ [--model-setting] \ [--model-config] \ [--model-ckpt] \ [--device ] \ [--extra-parameters] ``` Examples for each kind of task: #### 2.2.1 Text-to-Image stable diffusion ```shell python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir demo_text2image_stable_diffusion_res.png ``` controlnet-canny ```shell python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 1 \ --text "Room with blue walls and a yellow ceiling." \ --control 'https://user-images.githubusercontent.com/28132635/230297033-4f5c32df-365c-4cf4-8e4f-1b76a4cbb0b7.png' \ --result-out-dir demo_text2image_controlnet_canny_res.png ``` controlnet-pose ```shell python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 2 \ --text "masterpiece, best quality, sky, black hair, skirt, sailor collar, looking at viewer, short hair, building, bangs, neckerchief, long sleeves, cloudy sky, power lines, shirt, cityscape, pleated skirt, scenery, blunt bangs, city, night, black sailor collar, closed mouth" \ --control 'https://user-images.githubusercontent.com/28132635/230380893-2eae68af-d610-4f7f-aa68-c2f22c2abf7e.png' \ --result-out-dir demo_text2image_controlnet_pose_res.png ``` controlnet-seg ```shell python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 3 \ --text "black house, blue sky" \ --control 'https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/243599897-553a4c46-c61d-46df-b820-59a49aaf6678.png' \ --result-out-dir demo_text2image_controlnet_seg_res.png ``` #### 2.2.2 Conditional GANs ```shell python demo/mmagic_inference_demo.py \ --model-name biggan \ --model-setting 3 \ --label 1 \ --result-out-dir demo_conditional_biggan_res.jpg ``` #### 2.2.3 Unconditional GANs ```shell python demo/mmagic_inference_demo.py \ --model-name styleganv1 \ --result-out-dir demo_unconditional_styleganv1_res.jpg ``` #### 2.2.4 Image Translation ```shell python demo/mmagic_inference_demo.py \ --model-name pix2pix \ --img ./resources/input/translation/gt_mask_0.png \ --result-out-dir ./resources/output/translation/demo_translation_pix2pix_res.png ``` #### 2.2.5 Inpainting ```shell python demo/mmagic_inference_demo.py \ --model-name deepfillv2 \ --img ./resources/input/inpainting/celeba_test.png \ --mask ./resources/input/inpainting/bbox_mask.png \ --result-out-dir ./resources/output/inpainting/demo_inpainting_deepfillv2_res.jpg ``` #### 2.2.6 Matting ```shell python demo/mmagic_inference_demo.py \ --model-name aot_gan \ --img ./resources/input/matting/GT05.jpg \ --trimap ./resources/input/matting/GT05_trimap.jpg \ --result-out-dir ./resources/output/matting/demo_matting_gca_res.png ``` #### 2.2.7 Image Restoration ```shell python demo/mmagic_inference_demo.py \ --model-name nafnet \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_nafnet_res.png ``` #### 2.2.8 Image Super-resolution ```shell python demo/mmagic_inference_demo.py \ --model-name esrgan \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_esrgan_res.png ``` ```shell python demo/mmagic_inference_demo.py \ --model-name ttsr \ --img ./resources/input/restoration/000001.png \ --ref ./resources/input/restoration/000001.png \ --result-out-dir ./resources/output/restoration/demo_restoration_ttsr_res.png ``` #### 2.2.9 Video Super-Resolution BasicVSR / BasicVSR++ / IconVSR / RealBasicVSR ```shell python demo/mmagic_inference_demo.py \ --model-name basicvsr \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_basicvsr_res.mp4 ``` EDVR ```shell python demo/mmagic_inference_demo.py \ --model-name edvr \ --extra-parameters window_size=5 \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_edvr_res.mp4 ``` TDAN ```shell python demo/mmagic_inference_demo.py \ --model-name tdan \ --model-setting 2 \ --extra-parameters window_size=5 \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_tdan_res.mp4 ``` #### 2.2.10 Video interpolation ```shell python demo/mmagic_inference_demo.py \ --model-name flavr \ --video ./resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4 \ --result-out-dir ./resources/output/video_interpolation/demo_video_interpolation_flavr_res.mp4 ``` #### 2.2.11 Image Colorization ``` python demo/mmagic_inference_demo.py \ --model-name inst_colorization \ --img https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg \ --result-out-dir demo_colorization_res.png ``` #### 2.2.12 3D-aware Generation ```shell python demo/mmagic_inference_demo.py \ --model-name eg3d \ --result-out-dir ./resources/output/eg3d-output ``` ## 3. Other demos ## 3.1 gradio demo #### 3.1.1 DragGAN First, put your checkpoint path in `./checkpoints`, *e.g.* `./checkpoints/stylegan2_lions_512_pytorch_mmagic.pth`. For example, ```shell mkdir checkpoints cd checkpoints wget -O stylegan2_lions_512_pytorch_mmagic.pth https://download.openxlab.org.cn/models/qsun1/DragGAN-StyleGAN2-checkpoint/weight//StyleGAN2-Lions-internet ``` Then, try on the script: ```shell python demo/gradio_draggan.py ``` #### 3.1.2 ViCo Launch the UI. ```shell python demo/gradio_vico.py ``` *Training* 1. Submit your concept sample images to the interface and fill in the *init_token* and *placeholder*. 2. Click the *Start Training* button. 3. Your training results will be under the folder `./work_dirs/vico_gradio`. *Inference* Follow the [instructions](../configs/vico/README.md#quick-start#4) to download the pretrained weights (or [use your own weights](../configs/vico/README.md#quick-start#5)) and put them under the folder `./ckpts` ``` mkdir ckpts ``` your folder structure should be like: ``` ckpts └── barn.pth └── batman.pth └── clock.pth ... ``` Then launch the UI and you can use the pretrained weights to generate images. 1. Upload reference image. 2. (Optional) Customize advanced settings. 3. Click inference button. #### 3.1.3 FastComposer First, run the script: ```shell python demo/gradio_fastcomposer.py ``` Second, upload reference subject images.For example,

'reference_0.png'

'reference_1.png'
Then, add prompt like `A man img and a man img sitting together` and press `run` button. Finally, you can get text-generated images.
#### 3.1.4 AnimateDiff 1. Download [ToonYou](https://civitai.com/api/download/models/78775) and MotionModule checkpoint ```bash #!/bin/bash mkdir models && cd models mkdir Motion_Module && mkdir DreamBooth_LoRA gdown 1RqkQuGPaCO5sGZ6V6KZ-jUWmsRu48Kdq -O models/Motion_Module/ gdown 1ql0g_Ys4UCz2RnokYlBjyOYPbttbIpbu -O models/Motion_Module/ wget https://civitai.com/api/download/models/78775 -P models/DreamBooth_LoRA/ --content-disposition --no-check-certificate ``` 2. Modify the config file in `configs/animatediff/animatediff_ToonYou.py` ```python models_path = '/home/AnimateDiff/models/' ``` 3. Then, try on the script: ```shell # may need to install imageio[ffmpeg]: # pip install imageio-ffmpeg python demo/gradio_animatediff.py ``` 4. Select SD, MotionModule and DreamBooth checkpoints. Adjust inference parameters. Then input a selected prompt and its relative negative_prompt: ```python prompts = [ "best quality, masterpiece, 1girl, looking at viewer, blurry background, upper body, contemporary, dress", "masterpiece, best quality, 1girl, solo, cherry blossoms, hanami, pink flower, white flower, spring season, wisteria, petals, flower, plum blossoms, outdoors, falling petals, white hair, black eyes,", "best quality, masterpiece, 1boy, formal, abstract, looking at viewer, masculine, marble pattern", "best quality, masterpiece, 1girl, cloudy sky, dandelion, contrapposto, alternate hairstyle," ] negative_prompts = [ "", "badhandv4,easynegative,ng_deepnegative_v1_75t,verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, teeth", "", "", ] # More test samples could be generated with other config files. Please check 'configs/animatediff/README.md' ``` 5. Click the 'Generate' button. ================================================ FILE: demo/download_inference_resources.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os.path as osp import mmengine import requests RESOURCES = { 'Matting': [ 'https://download.openmmlab.com/mmediting/resources/input/matting/GT05.jpg', # noqa 'https://download.openmmlab.com/mmediting/resources/input/matting/GT05_trimap.jpg', # noqa 'https://download.openmmlab.com/mmediting/resources/input/matting/readme.md' # noqa ], 'Inpainting': [ 'https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png', # noqa 'https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png', # noqa 'https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md' # noqa ], 'Image Super-Resolution': [ 'https://download.openmmlab.com/mmediting/resources/input/restoration/000001.png', # noqa 'https://download.openmmlab.com/mmediting/resources/input/restoration/0901x2.png', # noqa 'https://download.openmmlab.com/mmediting/resources/input/restoration/readme.md' # noqa ], 'Image2Image Translation': [ 'https://download.openmmlab.com/mmediting/resources/input/translation/gt_mask_0.png', # noqa 'https://download.openmmlab.com/mmediting/resources/input/translation/readme.md' # noqa ], 'Video Interpolation': [ 'https://download.openmmlab.com/mmediting/resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4', # noqa 'https://download.openmmlab.com/mmediting/resources/input/video_interpolation/readme.md' # noqa ], 'Video Super-Resolution': [ 'https://download.openmmlab.com/mmediting/resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4', # noqa 'https://download.openmmlab.com/mmediting/resources/input/video_restoration/readme.md', # noqa 'https://download.openmmlab.com/mmediting/resources/input/video_restoration/v_Basketball_g01_c01.avi' # noqa ] } def parse_args(): parser = argparse.ArgumentParser(description='Download resources') parser.add_argument( '--root-dir', type=str, help='resource root dir', default='../resources') parser.add_argument( '--task', type=str, help='one specific task, if None : download all resources', default=None) parser.add_argument( '--print-all', action='store_true', help='print all resources') parser.add_argument( '--print-task-type', action='store_true', help='print all task types') parser.add_argument( '--print-task', type=str, help='print all tasks that need input resources', default=None) args = parser.parse_args() return args def main(): args = parse_args() if args.print_all: print('all inference resources:') for key in RESOURCES.keys(): print(key) for value in RESOURCES[key]: print(value) return if args.print_task_type: print('all task type:') for key in RESOURCES.keys(): print(key) return if args.print_task: print('RESOURCES of task ' + args.print_task + ':') for value in RESOURCES[args.print_task]: print(value) return to_be_download = [] if args.task and args.task in RESOURCES.keys(): to_be_download.extend(RESOURCES[args.task]) else: for key in RESOURCES.keys(): to_be_download.extend(RESOURCES[key]) put_root_path = osp.join(osp.dirname(__file__), args.root_dir) for item in to_be_download: item_relative_path = item[item.find('input'):] put_path = osp.join(put_root_path, item_relative_path) mmengine.mkdir_or_exist(osp.dirname(put_path)) response = requests.get(item) open(put_path, 'wb').write(response.content) print('Download finished: ' + item + ' to ' + put_path) if __name__ == '__main__': main() ================================================ FILE: demo/gradio_animatediff.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import json import os import random from datetime import datetime from glob import glob import gradio as gr import torch from diffusers import DDIMScheduler, EulerDiscreteScheduler, PNDMScheduler from mmengine import Config from safetensors import safe_open from mmagic.models.editors.animatediff import save_videos_grid from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() sample_idx = 0 scheduler_dict = { 'Euler': EulerDiscreteScheduler, 'PNDM': PNDMScheduler, 'DDIM': DDIMScheduler, } cfg = Config.fromfile('configs/animatediff/animatediff_ToonYou.py') css = """ .toolbutton { margin-buttom: 0em 0em 0em 0em; max-width: 2.5em; min-width: 2.5em !important; height: 2.5em; } """ class AnimateController: def __init__(self): # config dirs self.basedir = cfg.models_path self.stable_diffusion_dir = os.path.join(self.basedir, 'StableDiffusion') self.motion_module_dir = os.path.join(self.basedir, 'Motion_Module') self.personalized_model_dir = os.path.join(self.basedir, 'DreamBooth_LoRA') self.savedir = os.path.join( os.getcwd(), 'samples', datetime.now().strftime('Gradio-%Y-%m-%dT%H-%M-%S')) self.savedir_sample = os.path.join(self.savedir, 'sample') os.makedirs(self.savedir, exist_ok=True) self.stable_diffusion_list = [] self.motion_module_list = [] self.personalized_model_list = [] self.refresh_stable_diffusion() self.refresh_motion_module() self.refresh_personalized_model() # config models self.config = cfg self.animatediff = None self.lora_model_state_dict = {} def refresh_stable_diffusion(self): self.stable_diffusion_list = ['runwayml/stable-diffusion-v1-5'] def refresh_motion_module(self): motion_module_list = glob( os.path.join(self.motion_module_dir, '*.ckpt')) self.motion_module_list = [ os.path.basename(p) for p in motion_module_list ] def refresh_personalized_model(self): personalized_model_list = glob( os.path.join(self.personalized_model_dir, '*.safetensors')) self.personalized_model_list = [ os.path.basename(p) for p in personalized_model_list ] def update_stable_diffusion(self, stable_diffusion_dropdown): self.config['stable_diffusion_v15_url'] = stable_diffusion_dropdown self.animatediff = MODELS.build(self.config.model).cuda() return gr.Dropdown.update() def update_motion_module(self, motion_module_dropdown): if self.animatediff.unet is None: gr.Info('Please select a pretrained model path.') return gr.Dropdown.update(value=None) else: motion_module_dropdown = os.path.join(self.motion_module_dir, motion_module_dropdown) self.config.model['motion_module_cfg']['path'] = \ motion_module_dropdown self.animatediff.init_motion_module( self.config.model['motion_module_cfg']) return gr.Dropdown.update() def update_base_model(self, base_model_dropdown): if self.animatediff.unet is None: gr.Info('Please select a pretrained model path.') return gr.Dropdown.update(value=None) else: base_model_dropdown = os.path.join(self.personalized_model_dir, base_model_dropdown) self.config.model['dream_booth_lora_cfg'][ 'path'] = base_model_dropdown self.animatediff.init_dreambooth_lora( self.config.model['dream_booth_lora_cfg']) return gr.Dropdown.update() def update_lora_model(self, lora_model_dropdown): lora_model_dropdown = os.path.join(self.personalized_model_dir, lora_model_dropdown) self.lora_model_state_dict = {} if lora_model_dropdown == 'none': pass else: with safe_open( lora_model_dropdown, framework='pt', device='cpu') as f: for key in f.keys(): self.lora_model_state_dict[key] = f.get_tensor(key) return gr.Dropdown.update() def animate( self, stable_diffusion_dropdown, motion_module_dropdown, base_model_dropdown, lora_alpha_slider, prompt_textbox, negative_prompt_textbox, # sampler_dropdown, sample_step_slider, width_slider, length_slider, height_slider, cfg_scale_slider, seed_textbox): if self.animatediff.unet is None: raise gr.Error('Please select a pretrained model path.') if motion_module_dropdown == '': raise gr.Error('Please select a motion module.') if base_model_dropdown == '': raise gr.Error('Please select a base DreamBooth model.') self.animatediff.cuda() self.animatediff.unet.set_use_memory_efficient_attention_xformers(True) # TODO: update lora # if self.lora_model_state_dict != {}: # pipeline = convert_lora( # pipeline, # self.lora_model_state_dict, # alpha=lora_alpha_slider) sample = self.animatediff.infer( prompt_textbox, negative_prompt=negative_prompt_textbox, num_inference_steps=sample_step_slider, guidance_scale=cfg_scale_slider, width=width_slider, height=height_slider, video_length=length_slider, seed=int(seed_textbox))['samples'] save_sample_path = os.path.join(self.savedir_sample, f'{sample_idx}.mp4') save_videos_grid(sample, save_sample_path) seed = torch.initial_seed() sample_config = { 'prompt': prompt_textbox, 'n_prompt': negative_prompt_textbox, # "sampler": sampler_dropdown, # TODO: More samplers 'num_inference_steps': sample_step_slider, 'guidance_scale': cfg_scale_slider, 'width': width_slider, 'height': height_slider, 'video_length': length_slider, 'seed': seed } json_str = json.dumps(sample_config, indent=4) with open(os.path.join(self.savedir, 'logs.json'), 'a') as f: f.write(json_str) f.write('\n\n') return gr.Video.update(value=save_sample_path) controller = AnimateController() def ui(): with gr.Blocks(css=css) as demo: gr.Markdown(""" # [AnimateDiff: Animate Your Personalized # Text-to-Image Diffusion Models without Specific Tuning] # (https://arxiv.org/abs/2307.04725) Yuwei Guo, Ceyuan Yang*, Anyi Rao, Yaohui Wang, Yu Qiao, Dahua Lin, Bo Dai (*Corresponding Author)
[Arxiv Report](https://arxiv.org/abs/2307.04725) | [Project Page](https://animatediff.github.io/) | [Github](https://github.com/guoyww/animatediff/) """) with gr.Column(variant='panel'): gr.Markdown(""" ### 1. Model checkpoints (select pretrained model path first). """) with gr.Row(): stable_diffusion_dropdown = gr.Dropdown( label='Pretrained Model Path', choices=controller.stable_diffusion_list, interactive=True, ) stable_diffusion_dropdown.change( fn=controller.update_stable_diffusion, inputs=[stable_diffusion_dropdown], outputs=[stable_diffusion_dropdown]) stable_diffusion_refresh_button = gr.Button( value='\U0001F503', elem_classes='toolbutton') def update_stable_diffusion(): controller.refresh_stable_diffusion() return gr.Dropdown.update( choices=controller.stable_diffusion_list) stable_diffusion_refresh_button.click( fn=update_stable_diffusion, inputs=[], outputs=[stable_diffusion_dropdown]) with gr.Row(): motion_module_dropdown = gr.Dropdown( label='Select motion module', choices=controller.motion_module_list, interactive=True, ) motion_module_dropdown.change( fn=controller.update_motion_module, inputs=[motion_module_dropdown], outputs=[motion_module_dropdown]) motion_module_refresh_button = gr.Button( value='\U0001F503', elem_classes='toolbutton') def update_motion_module(): controller.refresh_motion_module() return gr.Dropdown.update( choices=controller.motion_module_list) motion_module_refresh_button.click( fn=update_motion_module, inputs=[], outputs=[motion_module_dropdown]) base_model_dropdown = gr.Dropdown( label='Select base Dreambooth model (required)', choices=controller.personalized_model_list, interactive=True, ) base_model_dropdown.change( fn=controller.update_base_model, inputs=[base_model_dropdown], outputs=[base_model_dropdown]) lora_model_dropdown = gr.Dropdown( label='Select LoRA model (optional)', choices=['none'] + controller.personalized_model_list, value='none', interactive=True, ) lora_model_dropdown.change( fn=controller.update_lora_model, inputs=[lora_model_dropdown], outputs=[lora_model_dropdown]) lora_alpha_slider = gr.Slider( label='LoRA alpha', value=0.8, minimum=0, maximum=2, interactive=True) personalized_refresh_button = gr.Button( value='\U0001F503', elem_classes='toolbutton') def update_personalized_model(): controller.refresh_personalized_model() return [ gr.Dropdown.update( choices=controller.personalized_model_list), gr.Dropdown.update(choices=['none'] + controller.personalized_model_list) ] personalized_refresh_button.click( fn=update_personalized_model, inputs=[], outputs=[base_model_dropdown, lora_model_dropdown]) with gr.Column(variant='panel'): gr.Markdown(""" ### 2. Configs for AnimateDiff. """) prompt_textbox = gr.Textbox(label='Prompt', lines=2) negative_prompt_textbox = gr.Textbox( label='Negative prompt', lines=2) with gr.Row().style(equal_height=False): with gr.Column(): with gr.Row(): sample_step_slider = gr.Slider( label='Sampling steps', value=25, minimum=10, maximum=100, step=1) width_slider = gr.Slider( label='Width', value=512, minimum=256, maximum=1024, step=64) height_slider = gr.Slider( label='Height', value=512, minimum=256, maximum=1024, step=64) length_slider = gr.Slider( label='Animation length', value=16, minimum=8, maximum=24, step=1) cfg_scale_slider = gr.Slider( label='CFG Scale', value=7.5, minimum=0, maximum=20) with gr.Row(): seed_textbox = gr.Textbox(label='Seed', value=-1) seed_button = gr.Button( value='\U0001F3B2', elem_classes='toolbutton') seed_button.click( fn=lambda: gr.Textbox.update( value=random.randint(1, 1e8)), inputs=[], outputs=[seed_textbox]) generate_button = gr.Button( value='Generate', variant='primary') result_video = gr.Video( label='Generated Animation', interactive=False) generate_button.click( fn=controller.animate, inputs=[ stable_diffusion_dropdown, motion_module_dropdown, base_model_dropdown, lora_alpha_slider, prompt_textbox, negative_prompt_textbox, # sampler_dropdown, sample_step_slider, width_slider, length_slider, height_slider, cfg_scale_slider, seed_textbox, ], outputs=[result_video]) return demo if __name__ == '__main__': demo = ui() demo.launch(share=True) ================================================ FILE: demo/gradio_controlnet_animation.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import gradio as gr from mmagic.apis import MMagicInferencer editor = MMagicInferencer(model_name='controlnet_animation') def process(video, prompt, a_prompt, negative_prompt, controlnet_conditioning_scale, width, height): prompt = prompt + a_prompt save_path = editor.infer( video=video, prompt=prompt, negative_prompt=negative_prompt, width=width, height=height, controlnet_conditioning_scale=controlnet_conditioning_scale) return save_path block = gr.Blocks().queue() with block: with gr.Row(): gr.Markdown('## Controlnet Animation') with gr.Row(): with gr.Column(): video_inp = gr.Video( label='Video Source', source='upload', type='filepath', elem_id='input-vid') prompt = gr.Textbox(label='Prompt') run_button = gr.Button(label='Run') with gr.Accordion('Advanced options', open=False): a_prompt = gr.Textbox( label='Added Prompt', value='best quality, extremely detailed') n_prompt = gr.Textbox( label='Negative Prompt', value='longbody, lowres, bad anatomy, bad hands, ' + 'missing fingers, extra digit, fewer digits, ' 'cropped, worst quality, low quality') controlnet_conditioning_scale = gr.Slider( label='Control Weight', minimum=0.0, maximum=2.0, value=0.7, step=0.01) width = gr.Slider( label='Image Width', minimum=256, maximum=768, value=512, step=64) height = gr.Slider( label='Image Width', minimum=256, maximum=768, value=512, step=64) with gr.Column(): video_out = gr.Video(label='Video Result', elem_id='video-output') ips = [ video_inp, prompt, a_prompt, n_prompt, controlnet_conditioning_scale, width, height ] run_button.click(fn=process, inputs=ips, outputs=video_out) block.launch(server_name='0.0.0.0', share=True) ================================================ FILE: demo/gradio_draggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from argparse import ArgumentParser from functools import partial import gradio as gr import numpy as np import torch from PIL import Image from demo.utils.gradio_utils import (EasyDict, ImageMask, draw_mask_on_image, draw_points_on_image, get_latest_points_pair, get_valid_mask, on_change_single_global_state) from demo.utils.renderer import Renderer, add_watermark_np parser = ArgumentParser() parser.add_argument('--share', action='store_true', default='True') parser.add_argument('--cache-dir', type=str, default='./checkpoints') parser.add_argument( '--listen', action='store_true', help='' 'launch gradio with 0.0.0.0 as server name, \ allowing to respond to network requests', ) args = parser.parse_args() cache_dir = args.cache_dir def get_default_gr_state(device='cuda', init_pkl='stylegan2_lions_512_pytorch_mmagic.pth'): global_state = gr.State({ 'images': { # image_orig: the original image, change with seed/model is changed # image_raw: image with mask and points, change during optimization # image_show: image showed on screen }, 'temporal_params': { # stop }, 'mask': None, # mask for visualization, 1 for editing and 0 for unchange 'last_mask': None, # last edited mask 'show_mask': True, # add button 'generator_params': EasyDict(), 'params': { 'seed': 0, 'motion_lambda': 20, 'r1_in_pixels': 3, 'r2_in_pixels': 12, 'magnitude_direction_in_pixels': 1.0, 'latent_space': 'w+', 'trunc_psi': 0.7, 'trunc_cutoff': None, 'lr': 0.001, }, 'device': device, 'draw_interval': 1, 'renderer': Renderer(disable_timing=True), 'points': {}, 'curr_point': None, 'curr_type_point': 'start', 'editing_state': 'add_points', 'pretrained_weight': init_pkl }) return global_state def reverse_point_pairs(points): new_points = [] for p in points: new_points.append([p[1], p[0]]) return new_points def clear_state(global_state, target=None): """Clear target history state from global_state If target is not defined, points and mask will be both removed. 1. set global_state['points'] as empty dict 2. set global_state['mask'] as full-one mask. """ if target is None: target = ['point', 'mask'] if not isinstance(target, list): target = [target] if 'point' in target: global_state['points'] = dict() print('Clear Points State!') if 'mask' in target: image_raw = global_state['images']['image_raw'] global_state['mask'] = np.ones((image_raw.size[1], image_raw.size[0]), dtype=np.uint8) print('Clear mask State!') return global_state def init_images(global_state, cache_dir='./checkpoints'): """This function is called only ones with Gradio App is started. 0. pre-process global_state, unpack value from global_state of need 1. Re-init renderer 2. run `renderer._render_drag_impl` with `is_drag=False` to generate new image 3. Assign images to global state and re-generate mask """ if isinstance(global_state, gr.State): state = global_state.value else: state = global_state state['renderer'].init_network( state['generator_params'], # res os.path.join(cache_dir, state['pretrained_weight'] ), # StyleGAN2 checkpoint path from Official DragGAN state['params']['seed'], # w0_seed, None, # w_load state['params']['latent_space'] == 'w+', # w_plus 'const', state['params']['trunc_psi'], # trunc_psi, state['params']['trunc_cutoff'], # trunc_cutoff, None, # input_transform state['params']['lr'] # lr, ) state['renderer']._render_drag_impl( state['generator_params'], is_drag=False, to_pil=True) init_image = state['generator_params'].image state['images']['image_orig'] = init_image state['images']['image_raw'] = init_image state['images']['image_show'] = Image.fromarray( add_watermark_np(np.array(init_image))) state['mask'] = np.ones((init_image.size[1], init_image.size[0]), dtype=np.uint8) return global_state def update_image_draw(image, points, mask, show_mask, global_state=None): image_draw = draw_points_on_image(image, points) if show_mask and mask is not None and not (mask == 0).all() and not ( mask == 1).all(): image_draw = draw_mask_on_image(image_draw, mask) image_draw = Image.fromarray(add_watermark_np(np.array(image_draw))) if global_state is not None: global_state['images']['image_show'] = image_draw return image_draw def preprocess_mask_info(global_state, image): """Function to handle mask information. 1. last_mask is None: Do not need to change mask, return mask 2. last_mask is not None: 2.1 global_state is remove_mask: 2.2 global_state is add_mask: """ if isinstance(image, dict): last_mask = get_valid_mask(image['mask']) else: last_mask = None mask = global_state['mask'] # mask in global state is a placeholder with all 1. if (mask == 1).all(): mask = last_mask # last_mask = global_state['last_mask'] editing_mode = global_state['editing_state'] if last_mask is None: return global_state if editing_mode == 'remove_mask': updated_mask = np.clip(mask - last_mask, 0, 1) print(f'Last editing_state is {editing_mode}, do remove.') elif editing_mode == 'add_mask': updated_mask = np.clip(mask + last_mask, 0, 1) print(f'Last editing_state is {editing_mode}, do add.') else: updated_mask = mask print(f'Last editing_state is {editing_mode}, ' 'do nothing to mask.') global_state['mask'] = updated_mask # global_state['last_mask'] = None # clear buffer return global_state valid_checkpoints_dict = { f.split('/')[-1]: osp.join(cache_dir, f) for f in os.listdir(cache_dir) if (f.endswith('pth') and osp.exists(osp.join(cache_dir, f))) } print(f'File under cache_dir ({cache_dir}):') print(os.listdir(cache_dir)) print('Valid checkpoint file:') print(valid_checkpoints_dict) if __name__ == '__main__': init_pkl = 'stylegan2_lions_512_pytorch_mmagic.pth' device = 'cuda' with gr.Blocks() as app: # renderer = Renderer() global_state = get_default_gr_state(device, init_pkl) # init image global_state = init_images(global_state) with gr.Row(): with gr.Row(): # Left --> tools with gr.Column(scale=3): # Pickle with gr.Row(): with gr.Column(scale=1, min_width=10): gr.Markdown(value='Pickle', show_label=False) with gr.Column(scale=4, min_width=10): form_pretrained_dropdown = gr.Dropdown( choices=list(valid_checkpoints_dict.keys()), label='Pretrained Model', value=init_pkl, ) # Latent with gr.Row(): with gr.Column(scale=1, min_width=10): gr.Markdown(value='Latent', show_label=False) with gr.Column(scale=4, min_width=10): form_seed_number = gr.Number( value=global_state.value['params']['seed'], interactive=True, label='Seed', ) form_lr_number = gr.Number( value=global_state.value['params']['lr'], interactive=True, label='Step Size') with gr.Row(): with gr.Column(scale=2, min_width=10): form_reset_image = gr.Button('Reset Image') with gr.Column(scale=3, min_width=10): form_latent_space = gr.Radio( ['w', 'w+'], value=global_state.value['params'] ['latent_space'], interactive=True, label='Latent space to optimize', show_label=False, ) # Drag with gr.Row(): with gr.Column(scale=1, min_width=10): gr.Markdown(value='Drag', show_label=False) with gr.Column(scale=4, min_width=10): with gr.Row(): with gr.Column(scale=1, min_width=10): enable_add_points = gr.Button('Add Points') with gr.Column(scale=1, min_width=10): undo_points = gr.Button('Reset Points') with gr.Row(): with gr.Column(scale=1, min_width=10): form_start_btn = gr.Button('Start') with gr.Column(scale=1, min_width=10): form_stop_btn = gr.Button('Stop') form_steps_number = gr.Number( value=0, label='Steps', interactive=False) # Mask with gr.Row(): with gr.Column(scale=1, min_width=10): gr.Markdown(value='Mask', show_label=False) with gr.Column(scale=4, min_width=10): enable_add_mask = gr.Button('Edit Flexible Area') with gr.Row(): with gr.Column(scale=1, min_width=10): form_reset_mask_btn = gr.Button( 'Reset mask') with gr.Column(scale=1, min_width=10): show_mask = gr.Checkbox( label='Show Mask', value=global_state.value['show_mask'], show_label=False) with gr.Row(): form_lambda_number = gr.Number( value=global_state.value['params'] ['motion_lambda'], interactive=True, label='Lambda', ) form_draw_interval_number = gr.Number( value=global_state.value['draw_interval'], label='Draw Interval (steps)', interactive=True, visible=False) # Right --> Image with gr.Column(scale=8): form_image = ImageMask( value=global_state.value['images']['image_show'], brush_radius=20).style( width=768, height=768) # NOTE: hard image size code here. gr.Markdown(""" ## Quick Start 1. Select desired `Pretrained Model` and adjust `Seed` to generate an initial image. 2. Click on image to add control points. 3. Click `Start` and enjoy it! ## Advance Usage 1. Change `Step Size` to adjust learning rate in drag optimization. 2. Select `w` or `w+` to change latent space to optimize: * Optimize on `w` space may cause greater influence to the image. * Optimize on `w+` space may work slower than `w`, but usually achieve better results. * Note that changing the latent space will reset the image, points and mask (this has the same effect as `Reset Image` button). 3. Click `Edit Flexible Area` to create a mask and constrain the unmasked region to remain unchanged. """) gr.HTML("""
Gradio demo supported by OpenMMLab MMagic
""") # Network & latents tab listeners def on_change_pretrained_dropdown(pretrained_value, global_state): """Function to handle model change. 1. Set pretrained value to global_state 2. Re-init images and clear all states """ global_state['pretrained_weight'] = pretrained_value init_images(global_state) clear_state(global_state) return global_state, global_state['images']['image_show'] form_pretrained_dropdown.change( on_change_pretrained_dropdown, inputs=[form_pretrained_dropdown, global_state], outputs=[global_state, form_image], ) def on_click_reset_image(global_state): """Reset image to the original one and clear all states 1. Re-init images 2. Clear all states """ init_images(global_state) clear_state(global_state) return global_state, global_state['images']['image_show'] form_reset_image.click( on_click_reset_image, inputs=[global_state], outputs=[global_state, form_image], ) # Update parameters def on_change_update_image_seed(seed, global_state): """Function to handle generation seed change. 1. Set seed to global_state 2. Re-init images and clear all states """ global_state['params']['seed'] = int(seed) init_images(global_state) clear_state(global_state) return global_state, global_state['images']['image_show'] form_seed_number.change( on_change_update_image_seed, inputs=[form_seed_number, global_state], outputs=[global_state, form_image], ) def on_click_latent_space(latent_space, global_state): """Function to reset latent space to optimize. NOTE: this function we reset the image and all controls 1. Set latent-space to global_state 2. Re-init images and clear all state """ global_state['params']['latent_space'] = latent_space init_images(global_state) clear_state(global_state) return global_state, global_state['images']['image_show'] form_latent_space.change( on_click_latent_space, inputs=[form_latent_space, global_state], outputs=[global_state, form_image]) # ==== Params form_lambda_number.change( partial(on_change_single_global_state, ['params', 'motion_lambda']), inputs=[form_lambda_number, global_state], outputs=[global_state], ) def on_change_lr(lr, global_state): if lr == 0: print('lr is 0, do nothing.') return global_state else: global_state['params']['lr'] = lr renderer = global_state['renderer'] renderer.update_lr(lr) print('New optimizer: ') print(renderer.w_optim) return global_state form_lr_number.change( on_change_lr, inputs=[form_lr_number, global_state], outputs=[global_state], ) def on_click_start(global_state, image): p_in_pixels = [] t_in_pixels = [] valid_points = [] # handle of start drag in mask editing mode global_state = preprocess_mask_info(global_state, image) # Prepare the points for the inference if len(global_state['points']) == 0: # yield on_click_start_wo_points(global_state, image) image_raw = global_state['images']['image_raw'] update_image_draw( image_raw, global_state['points'], global_state['mask'], global_state['show_mask'], global_state, ) yield ( global_state, 0, global_state['images']['image_show'], # gr.File.update(visible=False), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), # latent space gr.Radio.update(interactive=True), gr.Button.update(interactive=True), # NOTE: disable stop button gr.Button.update(interactive=False), # update other comps gr.Dropdown.update(interactive=True), gr.Number.update(interactive=True), gr.Number.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Checkbox.update(interactive=True), # gr.Number.update(interactive=True), gr.Number.update(interactive=True), ) else: # Transform the points into torch tensors for key_point, point in global_state['points'].items(): try: p_start = point.get('start_temp', point['start']) p_end = point['target'] if p_start is None or p_end is None: continue except KeyError: continue p_in_pixels.append(p_start) t_in_pixels.append(p_end) valid_points.append(key_point) mask = torch.tensor(global_state['mask']).float() drag_mask = 1 - mask renderer: Renderer = global_state['renderer'] global_state['temporal_params']['stop'] = False global_state['editing_state'] = 'running' # reverse points order p_to_opt = reverse_point_pairs(p_in_pixels) t_to_opt = reverse_point_pairs(t_in_pixels) print(p_to_opt) print('Running with:') print(f' Source: {p_in_pixels}') print(f' Target: {t_in_pixels}') step_idx = 0 while True: if global_state['temporal_params']['stop']: break # do drage here! renderer._render_drag_impl( global_state['generator_params'], p_to_opt, # point t_to_opt, # target drag_mask, # mask, global_state['params']['motion_lambda'], # lambda_mask reg=0, feature_idx=5, # NOTE: do not support change for now r1=global_state['params']['r1_in_pixels'], # r1 r2=global_state['params']['r2_in_pixels'], # r2 # random_seed = 0, # noise_mode = 'const', trunc_psi=global_state['params']['trunc_psi'], # force_fp32 = False, # layer_name = None, # sel_channels = 3, # base_channel = 0, # img_scale_db = 0, # img_normalize = False, # untransform = False, is_drag=True, to_pil=True) if step_idx % global_state['draw_interval'] == 0: print('Current Source:') for key_point, p_i, t_i in zip(valid_points, p_to_opt, t_to_opt): global_state['points'][key_point]['start_temp'] = [ p_i[1], p_i[0], ] global_state['points'][key_point]['target'] = [ t_i[1], t_i[0], ] start_temp = global_state['points'][key_point][ 'start_temp'] print(f' {start_temp}') image_result = global_state['generator_params'][ 'image'] image_draw = update_image_draw( # noqa image_result, global_state['points'], global_state['mask'], global_state['show_mask'], global_state, ) global_state['images']['image_raw'] = image_result yield ( global_state, step_idx, global_state['images']['image_show'], # gr.File.update(visible=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), # latent space gr.Radio.update(interactive=False), gr.Button.update(interactive=False), # enable stop button in loop gr.Button.update(interactive=True), # update other comps gr.Dropdown.update(interactive=False), gr.Number.update(interactive=False), gr.Number.update(interactive=False), gr.Button.update(interactive=False), gr.Button.update(interactive=False), gr.Checkbox.update(interactive=False), # gr.Number.update(interactive=False), gr.Number.update(interactive=False), ) # increate step step_idx += 1 image_result = global_state['generator_params']['image'] global_state['images']['image_raw'] = image_result # image_draw = update_image_draw(image_result, # global_state['points'], # global_state['mask'], # global_state['show_mask'], # global_state) # fp = NamedTemporaryFile(suffix=".png", delete=False) # image_result.save(fp, "PNG") global_state['editing_state'] = 'add_points' yield ( global_state, 0, # reset step to 0 after stop. global_state['images']['image_show'], # gr.File.update(visible=True, value=fp.name), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), gr.Button.update(interactive=True), # latent space gr.Radio.update(interactive=True), gr.Button.update(interactive=True), # NOTE: disable stop button with loop finish gr.Button.update(interactive=False), # update other comps gr.Dropdown.update(interactive=True), gr.Number.update(interactive=True), gr.Number.update(interactive=True), gr.Checkbox.update(interactive=True), gr.Number.update(interactive=True), ) form_start_btn.click( on_click_start, inputs=[global_state, form_image], outputs=[ global_state, form_steps_number, form_image, # form_download_result_file, # >>> buttons form_reset_image, enable_add_points, enable_add_mask, undo_points, form_reset_mask_btn, form_latent_space, form_start_btn, form_stop_btn, # <<< buttonm # >>> inputs comps form_pretrained_dropdown, form_seed_number, form_lr_number, show_mask, form_lambda_number, ], ) def on_click_stop(global_state): """Function to handle stop button is clicked. 1. send a stop signal by set global_state["temporal_params"]["stop"] as True 2. Disable Stop button """ global_state['temporal_params']['stop'] = True return global_state, gr.Button.update(interactive=False) form_stop_btn.click( on_click_stop, inputs=[global_state], outputs=[global_state, form_stop_btn]) form_draw_interval_number.change( partial( on_change_single_global_state, 'draw_interval', map_transform=lambda x: int(x), ), inputs=[form_draw_interval_number, global_state], outputs=[global_state], ) def on_click_remove_point(global_state): choice = global_state['curr_point'] del global_state['points'][choice] choices = list(global_state['points'].keys()) if len(choices) > 0: global_state['curr_point'] = choices[0] return ( gr.Dropdown.update(choices=choices, value=choices[0]), global_state, ) # Mask def on_click_reset_mask(global_state): global_state['mask'] = np.ones( ( global_state['images']['image_raw'].size[1], global_state['images']['image_raw'].size[0], ), dtype=np.uint8, ) image_draw = update_image_draw(global_state['images']['image_raw'], global_state['points'], global_state['mask'], global_state['show_mask'], global_state) return global_state, image_draw form_reset_mask_btn.click( on_click_reset_mask, inputs=[global_state], outputs=[global_state, form_image], ) # Image def on_click_enable_draw(global_state, image): """Function to start add mask mode. 1. Preprocess mask info from last state 2. Change editing state to add_mask 3. Set curr image with points and mask """ global_state = preprocess_mask_info(global_state, image) global_state['editing_state'] = 'add_mask' image_raw = global_state['images']['image_raw'] image_draw = update_image_draw(image_raw, global_state['points'], global_state['mask'], True, global_state) return (global_state, gr.Image.update(value=image_draw, interactive=True)) def on_click_remove_draw(global_state, image): """Function to start remove mask mode. 1. Preprocess mask info from last state 2. Change editing state to remove_mask 3. Set curr image with points and mask """ global_state = preprocess_mask_info(global_state, image) global_state['edinting_state'] = 'remove_mask' image_raw = global_state['images']['image_raw'] image_draw = update_image_draw(image_raw, global_state['points'], global_state['mask'], True, global_state) return (global_state, gr.Image.update(value=image_draw, interactive=True)) enable_add_mask.click( on_click_enable_draw, inputs=[global_state, form_image], outputs=[ global_state, form_image, ]) def on_click_add_point(global_state, image: dict): """Function switch from add mask mode to add points mode. 1. Updaste mask buffer if need 2. Change global_state['editing_state'] to 'add_points' 3. Set current image with mask """ global_state = preprocess_mask_info(global_state, image) global_state['editing_state'] = 'add_points' mask = global_state['mask'] image_raw = global_state['images']['image_raw'] image_draw = update_image_draw(image_raw, global_state['points'], mask, global_state['show_mask'], global_state) return (global_state, gr.Image.update(value=image_draw, interactive=False)) enable_add_points.click( on_click_add_point, inputs=[global_state, form_image], outputs=[global_state, form_image]) def on_click_image(global_state, evt: gr.SelectData): """This function only support click for point selection.""" xy = evt.index if global_state['editing_state'] != 'add_points': print(f'In {global_state["editing_state"]} state. ' 'Do not add points.') return global_state, global_state['images']['image_show'] points = global_state['points'] point_idx = get_latest_points_pair(points) if point_idx is None: points[0] = {'start': xy, 'target': None} print(f'Click Image - Start - {xy}') elif points[point_idx].get('target', None) is None: points[point_idx]['target'] = xy print(f'Click Image - Target - {xy}') else: points[point_idx + 1] = {'start': xy, 'target': None} print(f'Click Image - Start - {xy}') image_raw = global_state['images']['image_raw'] image_draw = update_image_draw( image_raw, global_state['points'], global_state['mask'], global_state['show_mask'], global_state, ) return global_state, image_draw form_image.select( on_click_image, inputs=[global_state], outputs=[global_state, form_image], ) def on_click_clear_points(global_state): """Function to handle clear all control points 1. clear global_state['points'] (clear_state) 2. re-init network 2. re-draw image """ clear_state(global_state, target='point') renderer: Renderer = global_state['renderer'] renderer.feat_refs = None image_raw = global_state['images']['image_raw'] image_draw = update_image_draw(image_raw, {}, global_state['mask'], global_state['show_mask'], global_state) return global_state, image_draw undo_points.click( on_click_clear_points, inputs=[global_state], outputs=[global_state, form_image]) def on_click_show_mask(global_state, show_mask): """Function to control whether show mask on image.""" global_state['show_mask'] = show_mask image_raw = global_state['images']['image_raw'] image_draw = update_image_draw( image_raw, global_state['points'], global_state['mask'], global_state['show_mask'], global_state, ) return global_state, image_draw show_mask.change( on_click_show_mask, inputs=[global_state, show_mask], outputs=[global_state, form_image], ) gr.close_all() app.queue(concurrency_count=3, max_size=20) app.launch( share=args.share, server_name='0.0.0.0' if args.listen else '127.0.0.1') ================================================ FILE: demo/gradio_fastcomposer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import gc import gradio as gr import numpy as np import PIL import torch from mmengine import Config from mmagic.registry import MODELS from mmagic.utils import register_all_modules gc.collect() torch.cuda.empty_cache() register_all_modules() class ModelWrapper: def __init__(self, model): super().__init__() self.model = model self.device = torch.device( 'cuda' if torch.cuda.is_available() else 'cpu') self.model = self.model.to(self.device) def inference( self, image1: PIL.Image.Image, image2: PIL.Image.Image, prompt: str, negative_prompt: str, seed: int, guidance_scale: float, alpha_: float, num_steps: int, num_images: int, ): print('Running model inference...') image = [] if image1 is not None: image.append(image1) if image2 is not None: image.append(image2) if len(image) == 0: return [], 'You need to upload at least one image.' num_subject_in_text = (np.array( self.model.special_tokenizer.encode(prompt)) == self.model.image_token_id).sum() if num_subject_in_text != len(image): return ( [], "Number of subjects in the text description doesn't " 'match the number of reference images, #text subjects: ' f'{num_subject_in_text} #reference image: {len(image)}', ) if seed == -1: seed = np.random.randint(0, 1000000) generator = torch.Generator(device=self.device) generator.manual_seed(seed) return ( self.model.infer( prompt=prompt, negative_prompt=negative_prompt, height=512, width=512, num_inference_steps=num_steps, guidance_scale=guidance_scale, num_images_per_prompt=num_images, generator=generator, alpha_=alpha_, reference_subject_images=image, )['samples'], 'run successfully', ) def create_demo(): TITLE = 'FastComposer Demo' DESCRIPTION = """To run the demo, you should: 1. Upload your images. The order of image1 and image2 needs to match the order of the subects in the prompt. You only need 1 image for single subject generation. 2. Input proper text prompts, such as "A woman img and a man img in the snow" or "A painting of a man img in the style of Van Gogh", where "img" specifies the token you want to augment and comes after the word. 3. Click the Run button. You can also adjust the hyperparameters to improve the results. Look at the job status to see if there are any errors with your input. """ cfg_file = Config.fromfile( 'configs/fastcomposer/fastcomposer_8xb16_FFHQ.py') fastcomposer = MODELS.build(cfg_file.model) model = ModelWrapper(fastcomposer) # model = ModelWrapper(convert_model_to_pipeline(args, "cpu")) with gr.Blocks() as demo: gr.Markdown(TITLE) gr.Markdown(DESCRIPTION) with gr.Row(): with gr.Column(): with gr.Box(): image1 = gr.Image(label='Image 1', type='pil') image2 = gr.Image(label='Image 2', type='pil') gr.Markdown('Upload the image for your subject') prompt = gr.Text( value='A man img and a man img sitting in a park', label='Prompt', placeholder= 'e.g. "A woman img and a man img in the snow", "A painting' ' of a man img in the style of Van Gogh"', info='Use "img" to specify the word you want to augment.', ) negative_prompt = gr.Text( value='((((ugly)))), (((duplicate))), ((morbid)), ' '((mutilated)), [out of frame], extra fingers, ' 'mutated hands, ((poorly drawn hands)), ' '((poorly drawn face)), (((mutation))), ' '(((deformed))), ((ugly)), blurry, ((bad anatomy)), ' '(((bad proportions))), ((extra limbs)), cloned face, ' '(((disfigured))). out of frame, ugly, extra limbs, ' '(bad anatomy), gross proportions, (malformed limbs), ' '((missing arms)), ((missing legs)), (((extra arms))), ' '(((extra legs))), mutated hands, (fused fingers), ' '(too many fingers), (((long neck)))', label='Negative Prompt', info='Features that you want to avoid.', ) alpha_ = gr.Slider( label='alpha', minimum=0, maximum=1, step=0.05, value=0.75, info= 'A smaller alpha aligns images with text better, but may ' 'deviate from the subject image. Increase alpha to improve' ' identity preservation, decrease it for ' 'prompt consistency.', ) num_images = gr.Slider( label='Number of generated images', minimum=1, maximum=8, step=1, value=4, ) run_button = gr.Button('Run') with gr.Accordion(label='Advanced options', open=False): seed = gr.Slider( label='Seed', minimum=-1, maximum=1000000, step=1, value=-1, info='If set to -1, a different seed will be ' 'used each time.', ) guidance_scale = gr.Slider( label='Guidance scale', minimum=1, maximum=10, step=1, value=5, ) num_steps = gr.Slider( label='Steps', minimum=1, maximum=300, step=1, value=50, ) with gr.Column(): result = gr.Gallery(label='Generated Images').style( grid=[2], height='auto') error_message = gr.Text(label='Job Status') inputs = [ image1, image2, prompt, negative_prompt, seed, guidance_scale, alpha_, num_steps, num_images, ] run_button.click( fn=model.inference, inputs=inputs, outputs=[result, error_message]) return demo if __name__ == '__main__': demo = create_demo() demo.queue(api_open=False) demo.launch( show_error=True, server_name='0.0.0.0', server_port=8080, ) ================================================ FILE: demo/gradio_inpainting.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import json import os import os.path as osp import subprocess import traceback import warnings from typing import Dict, List, Optional, Union import cv2 import gradio as gr import numpy as np import torch import yaml from mmengine.registry import init_default_scope from mmagic.apis.inferencers.inpainting_inferencer import InpaintingInferencer class InpaintingGradio: inpainting_supported_models = [ # inpainting models 'aot_gan', 'deepfillv1', 'deepfillv2', 'global_local', 'partial_conv', ] inpainting_supported_models_cfg = {} inpainting_supported_models_cfg_inited = False pkg_path = '' error_color = '#FF0000' success_color = '#00FF00' warning_color = '#FFFF00' notice_message = ('', None, '') def __init__(self, model_name: str = None, model_setting: int = None, model_config: str = None, model_ckpt: str = None, device: torch.device = None, extra_parameters: Dict = None, seed: int = 2022, **kwargs) -> None: init_default_scope('mmagic') InpaintingGradio.init_inference_supported_models_cfg() self.model_name = model_name self.model_setting = model_setting self.model_config = model_config self.model_ckpt = model_ckpt self.device = device self.extra_parameters = extra_parameters self.seed = seed if model_name or (model_config and model_ckpt): inpainting_kwargs = {} inpainting_kwargs.update( self._get_inpainting_kwargs(model_name, model_setting, model_config, model_ckpt, extra_parameters)) self.inference = InpaintingInferencer( device=device, seed=seed, **inpainting_kwargs) def model_reconfig(self, model_name: str = None, model_setting: int = None, model_config: str = None, model_ckpt: str = None, device: torch.device = None, extra_parameters: Dict = None, seed: int = 2022, **kwargs) -> None: inpainting_kwargs = {} # if model_config: # model_config = model_config.name # if model_ckpt: # model_ckpt = model_ckpt.name if not model_name and model_setting: self.send_notification( 'model_name should not be None when model_setting was used', self.error_color, 'error') return elif (not model_config and not model_name) and model_ckpt: self.send_notification( 'model_name and model_config should not be None when ' 'model_ckpt was used', self.error_color, 'error') return elif (not model_ckpt and not model_name) and model_config: self.send_notification( 'model_name and model_ckpt should not be None when ' 'model_config was used', self.error_color, 'error') return inpainting_kwargs.update( self._get_inpainting_kwargs(model_name, model_setting, model_config, model_ckpt, extra_parameters)) try: self.inference = InpaintingInferencer( device=device, seed=seed, **inpainting_kwargs) except Exception as e: self.send_notification('inference Exception:' + str(e), self.error_color, 'error') traceback.print_exc() return self.send_notification('Model config Finished!', self.success_color, 'success') @staticmethod def change_text2dict(input_text: str) -> Union[Dict, None]: return_dict = None try: return_dict = json.loads(input_text) except Exception as e: InpaintingGradio.send_notification( 'Convert string to dict Exception:' + str(e), InpaintingGradio.error_color, 'error') return return_dict @staticmethod def get_package_path() -> str: p = subprocess.Popen( 'pip show mmagic', shell=True, stdout=subprocess.PIPE) out, err = p.communicate() out = out.decode() if 'Location' not in out: InpaintingGradio.send_notification('module mmagic not found', InpaintingGradio.error_color, 'error') raise Exception('module mmagic not found') package_path = out[out.find('Location') + len('Location: '):].split('\r\n')[0] + os.sep return package_path def get_model_config(self, model_name: str) -> Dict: """Get the model configuration including model config and checkpoint url. Args: model_name (str): Name of the model. Returns: dict: Model configuration. """ if model_name not in self.inpainting_supported_models: self.send_notification(f'Model {model_name} is not supported.', self.error_color, 'error') raise ValueError(f'Model {model_name} is not supported.') else: return self.inpainting_supported_models_cfg[model_name] @staticmethod def init_inference_supported_models_cfg() -> None: if not InpaintingGradio.inpainting_supported_models_cfg_inited: InpaintingGradio.pkg_path = InpaintingGradio.get_package_path() # all_cfgs_dir = osp.join(osp.dirname(__file__), '..', 'configs') all_cfgs_dir = osp.join(InpaintingGradio.pkg_path, 'configs') for model_name in InpaintingGradio.inpainting_supported_models: meta_file_dir = osp.join(all_cfgs_dir, model_name, 'metafile.yml') with open(meta_file_dir, 'r') as stream: parsed_yaml = yaml.safe_load(stream) InpaintingGradio.inpainting_supported_models_cfg[ model_name] = {} InpaintingGradio.inpainting_supported_models_cfg[model_name][ 'settings'] = parsed_yaml['Models'] # noqa InpaintingGradio.inpainting_supported_models_cfg_inited = True def _get_inpainting_kwargs(self, model_name: Optional[str], model_setting: Optional[int], model_config: Optional[str], model_ckpt: Optional[str], extra_parameters: Optional[Dict]) -> Dict: """Get the kwargs for the inpainting inferencer.""" kwargs = {} if model_name: cfgs = self.get_model_config(model_name) # kwargs['task'] = cfgs['task'] setting_to_use = 0 if model_setting: if isinstance(model_setting, str): model_setting = int( model_setting[0:model_setting.find(' - ')]) setting_to_use = model_setting else: model_setting = 0 if model_setting > len( cfgs['settings']) - 1 or model_setting < -len( cfgs['settings']): self.send_notification( f"model_setting out of range of {model_name}'s " 'cfgs settings', self.error_color, 'error') config_dir = cfgs['settings'][setting_to_use]['Config'] config_dir = config_dir[config_dir.find('configs'):] # kwargs['config'] = os.path.join( # osp.dirname(__file__), '..', config_dir) kwargs['config'] = os.path.join(self.pkg_path, config_dir) kwargs['ckpt'] = cfgs['settings'][setting_to_use]['Weights'] if model_config: if kwargs.get('config', None) is not None: warnings.warn( f'{model_name}\'s default config ' f'is overridden by {model_config}', UserWarning) kwargs['config'] = model_config if model_ckpt: if kwargs.get('ckpt', None) is not None: warnings.warn( f'{model_name}\'s default checkpoint ' f'is overridden by {model_ckpt}', UserWarning) kwargs['ckpt'] = model_ckpt if extra_parameters: kwargs['extra_parameters'] = extra_parameters return kwargs @staticmethod def send_notification(msg: str, color: str, label: str) -> None: InpaintingGradio.notice_message = (msg, color, label) @staticmethod def get_inpainting_supported_models() -> List: """static function for getting inpainting inference supported modes.""" return InpaintingGradio.inpainting_supported_models def infer(self, input_img_arg: Dict) -> np.ndarray: result = self.inference( img=input_img_arg['image'], mask=input_img_arg['mask']) result = cv2.cvtColor(result[1], cv2.COLOR_RGB2BGR) return result def run(self) -> None: with gr.Blocks() as demo: with gr.Row(): with gr.Column(): input_model_dropdown = gr.Dropdown( choices=self.inpainting_supported_models, value=self.model_name, label='choose model') input_setting = gr.Dropdown( value=self.model_setting, label='choose setting') input_config = gr.Textbox( value=self.model_config, label='model_config_path') input_ckpt = gr.Textbox( value=self.model_ckpt, label='model_ckpt_path') input_device_dropdown = gr.Dropdown( choices=['cuda', 'cpu'], label='choose device', value='cuda') input_extra_parameters_input = gr.Textbox( value=json.dumps(self.extra_parameters), label='extra_parameters') input_extra_parameters = gr.JSON( value=self.extra_parameters, label='extra_parameters') input_seed = gr.Number( value=self.seed, precision=0, label='seed') config_button = gr.Button('CONFIG') input_extra_parameters_input.blur( self.change_text2dict, input_extra_parameters_input, input_extra_parameters) with gr.Column(visible=False) as output_col: input_image = gr.Image( image_mode='RGB', tool='sketch', type='filepath', label='Input image') infer_button = gr.Button('INFER') infer_button.style(full_width=False) output_image = gr.Image( label='Output image', interactive=False) output_image.style(height=500) infer_button.click( self.infer, inputs=input_image, outputs=output_image) with gr.Row(): label = gr.Label( value=self.notice_message[0], color=self.notice_message[1], label=self.notice_message[2]) def show_infer(*args) -> Dict: self.model_reconfig(*args) return { output_col: gr.update(visible=True), label: gr.update( value=self.notice_message[0], color=self.notice_message[1], label=self.notice_message[2]) } def change_setting(model_name: str) -> Dict: settings = InpaintingGradio.inpainting_supported_models_cfg[ model_name]['settings'] return { input_setting: gr.update(choices=[ str(i) + ' - ' + settings[i]['Config'] for i in range(len(settings)) ]) } input_model_dropdown.change( fn=change_setting, inputs=input_model_dropdown, outputs=input_setting) config_button.click(show_infer, [ input_model_dropdown, input_setting, input_config, input_ckpt, input_device_dropdown, input_extra_parameters, input_seed, ], [output_col, label]) demo.launch() if __name__ == '__main__': inpaintingGradio = InpaintingGradio() inpaintingGradio.run() ================================================ FILE: demo/gradio_vico.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import gradio as gr import torch from mmengine import Config from mmengine.runner import Runner from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() checkpoint_dir = 'ckpts' ckpts = os.listdir(checkpoint_dir) def load_base_model(): global cfg, model cfg = Config.fromfile('configs/vico/vico.py') model = MODELS.build(cfg.model) def train(train_data, init_token, placeholder): data_root = 'tmp' concept_dir = init_token image_dir = os.path.join(data_root, concept_dir) os.makedirs(image_dir, exist_ok=True) for i, data in enumerate(train_data): image = Image.open(data.name) image.save(os.path.join(image_dir, f'{i}.png')) global train_cfg train_cfg = Config.fromfile('configs/vico/vico.py') train_cfg.work_dir = os.path.join('./work_dirs', 'vico_gradio') train_cfg.dataset['data_root'] = data_root train_cfg.dataset['concept_dir'] = init_token train_cfg.dataset['placeholder'] = placeholder train_cfg.train_dataloader['dataset'] = train_cfg.dataset train_cfg.model['placeholder'] = placeholder train_cfg.model['initialize_token'] = init_token train_cfg.custom_hooks = None runner = Runner.from_cfg(train_cfg) runner.train() class DummyModel: def __init__(self, model): self.model = model def infer_fn(checkpoint, img_ref, prompt, negative_prompt, guidance_scale, width, height, seed, inference_steps, bs): state_dict = torch.load(os.path.join(checkpoint_dir, checkpoint)) dummy_agent = DummyModel(model) dummy_agent.model.load_state_dict(state_dict, strict=False) dummy_agent.model = dummy_agent.model.cuda() img_ref = Image.open(img_ref) with torch.no_grad(): output = dummy_agent.model.infer( prompt=prompt, image_reference=img_ref, width=width, height=height, negative_prompt=negative_prompt, guidance_scale=guidance_scale, num_inference_steps=inference_steps, num_images_per_prompt=bs, seed=int(seed))['samples'] return output if __name__ == '__main__': load_base_model() block = gr.Blocks().queue() with block: with gr.Tab('Train'): with gr.Row(): gr.Markdown('## ViCo') with gr.Row(): with gr.Column(): train_data = gr.File( label='Training Samples', file_count='directory', file_types=['image'], interactive=True, ) with gr.Column(): init_token = gr.Textbox(label='Init token') placeholder = gr.Textbox(label='Placeholder') train_button = gr.Button(value='Start Training') train_button.click( fn=train, inputs=[train_data, init_token, placeholder]) with gr.Tab('Inference'): with gr.Row(): gr.Markdown('## ViCo') with gr.Row(): with gr.Column(): checkpoint = gr.Dropdown(ckpts) img_ref = gr.Image( label='Image Reference', source='upload', type='filepath', elem_id='input-vid') prompt = gr.Textbox(label='Prompt') with gr.Accordion('Advanced options', open=False): n_prompt = gr.Textbox( label='Negative Prompt', value='') guidance_scale = gr.Slider( label='CFG', minimum=0.0, maximum=13.0, value=7.5, step=0.5) width = gr.Slider( label='Image Width', minimum=256, maximum=768, value=512, step=64) height = gr.Slider( label='Image Width', minimum=256, maximum=768, value=512, step=64) seed = gr.Number( label='Seed', value=0, ) num_inference_steps = gr.Slider( label='Inference Steps', minimum=20, maximum=80, value=50, step=5) bs = gr.Slider( label='Batch Size', minimum=1, maximum=4, value=1, step=1) with gr.Column(): output = gr.Gallery( label='Output Image', elem_id='image-output') run_button = gr.Button(label='Run') ips = [ checkpoint, img_ref, prompt, n_prompt, guidance_scale, width, height, seed, num_inference_steps, bs ] run_button.click(fn=infer_fn, inputs=ips, outputs=output) block.launch(server_name='0.0.0.0', share=True) ================================================ FILE: demo/mmagic_inference_demo.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # isort: off from argparse import ArgumentParser from mmengine import DictAction from mmagic.apis import MMagicInferencer def parse_args(): parser = ArgumentParser() parser.add_argument( '--img', type=str, default=None, help='Input image file.') parser.add_argument( '--video', type=str, default=None, help='Input video file.') parser.add_argument( '--label', type=int, default=None, help='Input label for conditional models.') parser.add_argument( '--trimap', type=str, default=None, help='Input for matting models.') parser.add_argument( '--mask', type=str, default=None, help='path to input mask file for inpainting models') parser.add_argument( '--text', type=str, default='', help='text input for text2image models') parser.add_argument( '--result-out-dir', type=str, default=None, help='Output img or video path.') parser.add_argument( '--model-name', type=str, default=None, help='Pretrained mmagic algorithm') parser.add_argument( '--model-setting', type=int, default=None, help='Pretrained mmagic algorithm setting') parser.add_argument( '--config-name', type=str, default=None, help='Pretrained mmagic algorithm config name') parser.add_argument( '--model-config', type=str, default=None, help='Path to the custom config file of the selected mmagic model.') parser.add_argument( '--model-ckpt', type=str, default=None, help='Path to the custom checkpoint file of the selected det model.') parser.add_argument( '--device', type=str, default='cuda', help='Device used for inference.') parser.add_argument( '--extra-parameters', nargs='+', action=DictAction, help='Other customized kwargs for different model') parser.add_argument( '--seed', type=int, default=2022, help='The random seed used in inference.') # print supported tasks and models parser.add_argument( '--print-supported-models', action='store_true', help='print all supported models for inference.') parser.add_argument( '--print-supported-tasks', action='store_true', help='print all supported tasks for inference.') parser.add_argument( '--print-task-supported-models', type=str, default=None, help='print all supported models for one task') args, unknown = parser.parse_known_args() return args, unknown def main(): args, unknown = parse_args() assert len(unknown) % 2 == 0, ( 'User defined arguments must be passed in pair, but receive ' f'{len(unknown)} arguments.') user_defined = {} for idx in range(len(unknown) // 2): key, val = unknown[idx * 2], unknown[idx * 2 + 1] assert key.startswith('--'), ( 'Key of user define arguments must be start with \'--\', but ' f'receive \'{key}\'.') key = key.replace('-', '_') val = int(val) if val.isdigit() else val user_defined[key[2:]] = val user_defined.update(vars(args)) if args.print_supported_models: inference_supported_models = \ MMagicInferencer.get_inference_supported_models() print('all supported models:') print(inference_supported_models) return if args.print_supported_tasks: supported_tasks = MMagicInferencer.get_inference_supported_tasks() print('all supported tasks:') print(supported_tasks) return if args.print_task_supported_models: task_supported_models = \ MMagicInferencer.get_task_supported_models( args.print_task_supported_models) print('translation models:') print(task_supported_models) return editor = MMagicInferencer(**vars(args)) editor.infer(**user_defined) if __name__ == '__main__': main() ================================================ FILE: demo/mmagic_inference_tutorial.ipynb ================================================ { "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# MMagic Inference Tutorial\n", "\n", "Welcome to MMagic! This is the official tutorial for using MMagic inference api to predict your own image or video.\n", "\n", "In this tutorial, you will learn how to\n", "\n", "[1. Install MMagic](#1-install-mmagic)\n", "\n", "[2. Check inference supported tasks and models](#2-check-inference-supported-tasks-and-models)\n", "\n", "[3. Perform inference using MMagic\n", " inference API](#3-perform-inference-with-mmagic-api)\n", "\n", "  [3.1 Prepare some images or videos for inference](#31-prepare-some-images-or-videos-for-inference)\n", "\n", "  [3.2 Perform inference with two lines of python code](#32-perform-inference-with-two-lines-of-python-code)\n", "\n", "  [3.3 Infer with different settings of a specific model](#33-infer-with-different-settings-of-a-specific-model)\n", "\n", "  [3.4 Infer with extra parameters](#34-inference-with-extra-parameters)\n", "\n", "[4. Perform inference with models of different tasks including](#4-perform-inference-with-models-of-different-tasks):\n", "\n", "  [4.1 Inference of conditional GANs models](#41-inference-of-conditional-gan-models)\n", "\n", "  [4.2 Inference of inpanting models](#42-inference-of-inpainting-models)\n", "\n", "  [4.3 Inference of matting models](#43-inference-of-matting-models)\n", "\n", "  [4.4 Inference of super resolution models](#44-inference-of-image-super-resolution-models)\n", "\n", "  [4.5 Inference of image2image models](#45-inference-of-image-translation-models)\n", "\n", "  [4.6 Inference of unconditional GANs models](#46-inference-of-unconditional-gan-models)\n", "\n", "  [4.7 Inference of video interpolation models](#47-inference-of-video-interpolation-models)\n", "\n", "  [4.8 Inference of video super resolution models](#48-inference-of-video-restoration-models)\n", "\n", "  [4.9 Inference of text-to-image models](#49-inference-of-text-to-image-models)\n", "\n", "Let's start!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Install MMagic" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "vscode": { "languageId": "shellscript" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "torch 1.12.1+cu113\n", "torchvision 0.13.1+cu113\n" ] } ], "source": [ "# Check PyTorch version\n", "!pip3 list | grep torch" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "shellscript" } }, "outputs": [], "source": [ "# Install mmcv dependency via openmim\n", "!pip3 install openmim\n", "!mim install 'mmcv>=2.0.0'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "shellscript" } }, "outputs": [], "source": [ "# Install mmagic from source\n", "%cd ..\n", "!pip3 install -e .\n", "%cd demo" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0.0rc7\n" ] } ], "source": [ "# Check MMagic installation\n", "import mmagic\n", "print(mmagic.__version__)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Check inference supported tasks and models\n", "\n", "There are multiple task types in MMagic: Matting, Inpainting, Video Super-Resolution, Image Super-Resolution, Image2Image, Unconditional GANs, Conditional GANs, Video Interpolation. \n", "\n", "We provide some models for each task. All available models and tasks could be printed out like this." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all supported models:\n", "['inst_colorization', 'biggan', 'sngan_proj', 'sagan', 'dcgan', 'wgan-gp', 'lsgan', 'ggan', 'pggan', 'styleganv1', 'styleganv2', 'styleganv3', 'gca', 'global_local', 'aot_gan', 'pix2pix', 'cyclegan', 'srcnn', 'srgan_resnet', 'edsr', 'esrgan', 'rdn', 'dic', 'ttsr', 'glean', 'real_esrgan', 'flavr', 'cain', 'edvr', 'tdan', 'basicvsr', 'iconvsr', 'basicvsr_pp', 'real_basicvsr', 'disco_diffusion', 'eg3d', 'controlnet_animation']\n", "all supported tasks:\n", "['Unconditional GANs', 'controlnet_animation', 'Video Interpolation', '3D-aware Generation', 'Conditional GANs', 'Image Super-Resolution', 'Text2Image, Image2Image', 'Colorization', 'Inpainting', 'Matting', 'Image2Image', 'Video Super-Resolution']\n", "translation models:\n", "['pix2pix', 'cyclegan']\n" ] } ], "source": [ "from mmagic.apis import MMagicInferencer\n", "\n", "# print all supported models for inference.\n", "inference_supported_models = MMagicInferencer.get_inference_supported_models()\n", "print('all supported models:')\n", "print(inference_supported_models)\n", "\n", "# print all supported tasks for inference.\n", "supported_tasks = MMagicInferencer.get_inference_supported_tasks()\n", "print('all supported tasks:')\n", "print(supported_tasks)\n", "\n", "# print all supported models for one task, take image translation for example.\n", "task_supported_models = MMagicInferencer.get_task_supported_models('Image2Image')\n", "print('translation models:')\n", "print(task_supported_models)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Perform inference with MMagic API\n", "\n", "Next we describe how to perform inference with python code snippets.\n", "\n", "(We also provide command line interface for you to do inference by running mmagic_inference_demo.py. The usage of this interface could be found in [README.md](./README.md) and more guidance could be found in the [documentation](https://mmagic.readthedocs.io/en/latest/user_guides/3_inference.html#).)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.1 Prepare some images or videos for inference\n", "\n", "Before we start to perform inference with a pretrained model, some input images or videos should be prepared. \n", "\n", "Take image translation for example. We need a input image to be translated.\n", "\n", "Put your image to some directory and make a directory to save processed image." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "vscode": { "languageId": "shellscript" } }, "outputs": [], "source": [ "# make a dir for input image and output image\n", "!mkdir -p ./../resources/input/translation\n", "!mkdir -p ./../resources/output/translation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We also have prepared some images and videos for you. You can download by running [download_inference_resouces.py](./download_inference_resources.py).\n", "\n", "This script allows you to see what resources are available and makes download easier." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "vscode": { "languageId": "shellscript" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all inference resources:\n", "Matting\n", "https://download.openmmlab.com/mmediting/resources/input/matting/GT05.jpg\n", "https://download.openmmlab.com/mmediting/resources/input/matting/GT05_trimap.jpg\n", "https://download.openmmlab.com/mmediting/resources/input/matting/readme.md\n", "Inpainting\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md\n", "Image Super-Resolution\n", "https://download.openmmlab.com/mmediting/resources/input/restoration/000001.png\n", "https://download.openmmlab.com/mmediting/resources/input/restoration/0901x2.png\n", "https://download.openmmlab.com/mmediting/resources/input/restoration/readme.md\n", "Image2Image Translation\n", "https://download.openmmlab.com/mmediting/resources/input/translation/gt_mask_0.png\n", "https://download.openmmlab.com/mmediting/resources/input/translation/readme.md\n", "Video Interpolation\n", "https://download.openmmlab.com/mmediting/resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4\n", "https://download.openmmlab.com/mmediting/resources/input/video_interpolation/readme.md\n", "Video Super-Resolution\n", "https://download.openmmlab.com/mmediting/resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4\n", "https://download.openmmlab.com/mmediting/resources/input/video_restoration/readme.md\n", "https://download.openmmlab.com/mmediting/resources/input/video_restoration/v_Basketball_g01_c01.avi\n", "all task type:\n", "Matting\n", "Inpainting\n", "Image Super-Resolution\n", "Image2Image Translation\n", "Video Interpolation\n", "Video Super-Resolution\n", "RESOURCES of task Inpainting:\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png\n", "https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/GT05.jpg to ../resources/input/matting/GT05.jpg\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/GT05_trimap.jpg to ../resources/input/matting/GT05_trimap.jpg\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/readme.md to ../resources/input/matting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png to ../resources/input/inpainting/bbox_mask.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png to ../resources/input/inpainting/celeba_test.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md to ../resources/input/inpainting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/000001.png to ../resources/input/restoration/000001.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/0901x2.png to ../resources/input/restoration/0901x2.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/readme.md to ../resources/input/restoration/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/translation/gt_mask_0.png to ../resources/input/translation/gt_mask_0.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/translation/readme.md to ../resources/input/translation/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4 to ../resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_interpolation/readme.md to ../resources/input/video_interpolation/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 to ../resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/readme.md to ../resources/input/video_restoration/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/v_Basketball_g01_c01.avi to ../resources/input/video_restoration/v_Basketball_g01_c01.avi\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png to ../resources/input/inpainting/bbox_mask.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png to ../resources/input/inpainting/celeba_test.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md to ../resources/input/inpainting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/GT05.jpg to ../your_dir/input/matting/GT05.jpg\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/GT05_trimap.jpg to ../your_dir/input/matting/GT05_trimap.jpg\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/matting/readme.md to ../your_dir/input/matting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/bbox_mask.png to ../your_dir/input/inpainting/bbox_mask.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/celeba_test.png to ../your_dir/input/inpainting/celeba_test.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/inpainting/readme.md to ../your_dir/input/inpainting/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/000001.png to ../your_dir/input/restoration/000001.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/0901x2.png to ../your_dir/input/restoration/0901x2.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/restoration/readme.md to ../your_dir/input/restoration/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/translation/gt_mask_0.png to ../your_dir/input/translation/gt_mask_0.png\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/translation/readme.md to ../your_dir/input/translation/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4 to ../your_dir/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_interpolation/readme.md to ../your_dir/input/video_interpolation/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 to ../your_dir/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/readme.md to ../your_dir/input/video_restoration/readme.md\n", "Download finished: https://download.openmmlab.com/mmediting/resources/input/video_restoration/v_Basketball_g01_c01.avi to ../your_dir/input/video_restoration/v_Basketball_g01_c01.avi\n" ] } ], "source": [ "# see all resources\n", "!python download_inference_resources.py --print-all\n", "# see all task types\n", "!python download_inference_resources.py --print-task-type\n", "# see resources of one specific task\n", "!python download_inference_resources.py --print-task 'Inpainting'\n", "# download all resouces to default dir '../resources'\n", "!python download_inference_resources.py\n", "# download resouces of one task\n", "!python download_inference_resources.py --task 'Inpainting'\n", "# download to the directory you want\n", "!python download_inference_resources.py --root-dir '../resources'" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2 Perform inference with two lines of python code. \n", "\n", "There are two steps:\n", "\n", "First, create a MMagicInferencer instance by a pretrained model name.\n", "\n", "Second, infer your own image with this MMagicInferencer instance. The translated image will be saved to result_out_dir." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_1x1_80k_facades_20210902_170442-c0958d50.pth\n" ] } ], "source": [ "from mmagic.apis import MMagicInferencer\n", "\n", "# Create a MMagicInferencer instance\n", "editor = MMagicInferencer('pix2pix')\n", "# Infer a image. Input image path and output image path is needed.\n", "results = editor.infer(img='../resources/input/translation/gt_mask_0.png', result_out_dir='../resources/output/translation/tutorial_translation_pix2pix_res.jpg')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You could see your result image by plotting it out." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# plot the result image\n", "import mmcv\n", "import matplotlib.pyplot as plt \n", "img = mmcv.imread('../resources/output/translation/tutorial_translation_pix2pix_res.jpg')\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### 3.3 Infer with different settings of a specific model\n", "\n", "There are some different configs and checkpoints for one model.\n", "\n", "You could configure different settings by passing 'model_setting' to 'MMagicInferencer'. Every model's default setting is 0.\n", "\n", "Take conditional GAN model 'biggan' as an example. We have pretrained model for Cifar and Imagenet, and all pretrained models of 'biggan' are listed in its [metafile.yaml](../configs/biggan/metafile.yml)\n", "\n", "There are six settings in this metafile. If you choose setting 1, then the config 'configs/biggan/biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py' will be used. If 'model_setting' is not passed to 'MMagicInferencer', the config ‘configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py’ will be used by default.\n", "\n", "And you could also use 'config_name' to replace 'model_setting'. For example, you can init a MMagicInferencer with 'MMagicInferencer('biggan', config_name='biggan_2xb25-500kiters_cifar10-32x32')', which is the same with 'MMagicInferencer('biggan', model_setting=0)'." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt\n", "from mmagic.apis import MMagicInferencer\n", "\n", "result_out_dir = '../resources/output/conditional/tutorial_conditinal_biggan_res_setting1.jpg'\n", "# configure setting to 1\n", "editor = MMagicInferencer('biggan', model_setting=1) \n", "results = editor.infer(label=1, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### 3.4 Infer with extra parameters\n", "\n", "Some models may have extra parameters that could be configured to perform inference.\n", "\n", "Take 'biggan' for example. You could configure 'num_batches' in a dict and pass it to 'MMagicInferencer'." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth\n" ] }, { "data": { "image/png": "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5513utfX6/jvuusuev/7309Hjx51PydOnHDvr9dxW5w6dYouueQS+tjHPkZPPPEEvfLKK/Tggw/St7/9bXfMel33FhYWJu77Qw89RADo0UcfJaL1f+/PFGvOQLnpppto37597v9KKdqxYwfdfffd5/GsfrCYNlC01rR9+3b64z/+Y/fa0tISRVFE//AP/0BERC+++CIBoP/5n/9xx3zta18jIQS9/vrr5+zcfxBYWFggALR//34i4rEGQUBf+tKX3DH/93//RwDoscceIyI28KSUdOzYMXfMPffcQ51Oh7IsO7cD+AFg06ZN9Dd/8zcbZuz9fp+uuOIKeuihh+jHf/zHnYGynsd/11130XXXXbfqe+t53Baf+cxn6Md+7Mfe8P2NtO7deeeddPnll5PWekPc+zPFmkrx5HmOp59+Gnv37nWvSSmxd+9ePPbYY+fxzN5ZvPrqqzh27NjEuLvdLnbv3u3G/dhjj2F2dhY33nijO2bv3r2QUuKJJ5445+f8drC8vAxg3LX66aefRlEUE+O/6qqrsGvXronxf+ADH8C2bdvcMR/+8IfR6/XwwgsvnMOzf3tQSuG+++7DcDjEnj17NszY9+3bh1tvvXVinMD6v/cvv/wyduzYgXe/+9247bbbcPjwYQDrf9wA8JWvfAU33ngjfvEXfxFbt27F9ddfj7/+679272+UdS/Pc3zxi1/Exz/+cQghNsS9P1OsKQPl5MmTUEpN3BQA2LZtG44dO3aezuqdhx3bm4372LFj2Lp168T7vu9jbm5uTV0brTU+9alP4YMf/CCuueYaADy2MAwxOzs7cez0+Fe7Pva9Cx3PP/882u02oijCHXfcgfvvvx9XX331hhj7fffdh//93//F3XffveK99Tz+3bt34/Of/zy+/vWv45577sGrr76KD33oQ+j3++t63BavvPIK7rnnHlxxxRV48MEH8YlPfAK/+Zu/iS984QsANs6698ADD2BpaQkf+9jHAKzvOX+28M/3CdSoUcW+fftw4MABfPOb3zzfp3JOceWVV+LZZ5/F8vIyvvzlL+P222/H/v37z/dpveM4cuQI7rzzTjz00ENoNBrn+3TOKW655Rb372uvvRa7d+/GJZdcgn/8x39EHMfn8czODbTWuPHGG/FHf/RHAIDrr78eBw4cwF/+5V/i9ttvP89nd+7wt3/7t7jllluwY8eO830qFxzWVARlfn4enuetYDMfP34c27dvP09n9c7Dju3Nxr19+3YsLCxMvF+WJU6dOrVmrs0nP/lJ/Ou//iseffRRXHzxxe717du3I89zLC0tTRw/Pf7Vro9970JHGIZ4z3vegxtuuAF33303rrvuOvzpn/7puh/7008/jYWFBfzQD/0QfN+H7/vYv38//uzP/gy+72Pbtm3revxVzM7O4r3vfS++/e1vr/v7DgAXXXQRrr766onX3ve+97k010ZY9w4dOoT/+I//wK/+6q+61zbCvT9TrCkDJQxD3HDDDXj44Yfda1prPPzww9izZ895PLN3Fpdddhm2b98+Me5er4cnnnjCjXvPnj1YWlrC008/7Y555JFHoLXG7t27z/k5nw2ICJ/85Cdx//3345FHHsFll1028f4NN9yAIAgmxn/w4EEcPnx4YvzPP//8xGL10EMPodPprFgE1wK01siybN2P/eabb8bzzz+PZ5991v3ceOONuO2229y/1/P4qxgMBvjOd76Diy66aN3fdwD44Ac/uEJO4KWXXsIll1wCYP2vewBw7733YuvWrbj11lvdaxvh3p8xzjdL92xx3333URRF9PnPf55efPFF+vVf/3WanZ2dYDOvRfT7fXrmmWfomWeeIQD0J3/yJ/TMM8/QoUOHiIjL7WZnZ+mf//mf6bnnnqOf/dmfXbXc7vrrr6cnnniCvvnNb9IVV1xxwZfbERF94hOfoG63S9/4xjcmSu9Go5E75o477qBdu3bRI488Qk899RTt2bOH9uzZ4963ZXc/8RM/Qc8++yx9/etfpy1btqyJsrvPfvaztH//fnr11Vfpueeeo89+9rMkhKB///d/J6L1PfbVUK3iIVq/4//0pz9N3/jGN+jVV1+l//7v/6a9e/fS/Pw8LSwsENH6HbfFk08+Sb7v0x/+4R/Syy+/TH//939PzWaTvvjFL7pj1vO6p5SiXbt20Wc+85kV7633e3+mWHMGChHRn//5n9OuXbsoDEO66aab6PHHHz/fp/S28eijjxKAFT+33347EXHJ3e/93u/Rtm3bKIoiuvnmm+ngwYMTn7G4uEgf/ehHqd1uU6fToV/+5V+mfr9/HkZzdlht3ADo3nvvdcckSUK/8Ru/QZs2baJms0k///M/T0ePHp34nO9+97t0yy23UBzHND8/T5/+9KepKIpzPJqzx8c//nG65JJLKAxD2rJlC918883OOCFa32NfDdMGynod/0c+8hG66KKLKAxDete73kUf+chHJjRA1uu4q/iXf/kXuuaaayiKIrrqqqvor/7qrybeX8/r3oMPPkgAVoyHaGPc+zOBICI6L6GbGjVq1KhRo0aNN8Ca4qDUqFGjRo0aNTYGagOlRo0aNWrUqHHBoTZQatSoUaNGjRoXHGoDpUaNGjVq1KhxwaE2UGrUqFGjRo0aFxxqA6VGjRo1atSoccGhNlBq1KhRo0aNGhccagOlRo0aNWrUqHHBoTZQatSoUaNGjRoXHGoDpUaNGjVq1KhxwaE2UGrUqFGjRo0aFxz+H3bgwRzto99uAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt\n", "from mmagic.apis import MMagicInferencer\n", "\n", "result_out_dir = '../resources/output/conditional/tutorial_conditinal_biggan_res_sample6.jpg'\n", "# use a dict to pass the parameters, num_batches means images output num for one inference\n", "editor = MMagicInferencer('biggan', model_setting=1, extra_parameters={'num_batches':6}) \n", "results = editor.infer(label=1, result_out_dir=result_out_dir)\n", "\n", "# plot the result image and we could see 6 images in a inference batch\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To know what extra parameters that a model have, do like this." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth\n", "['num_batches', 'sample_model']\n" ] } ], "source": [ "from mmagic.apis import MMagicInferencer\n", "\n", "editor = MMagicInferencer('biggan', model_setting=1) \n", "editor.print_extra_parameters()\n", "# 'num_batches' and 'sample_model' are extra parameters in 'biggan' model." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Perform inference with models of different tasks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.1 Inference of conditional GAN models\n", "\n", "Conditional GAN models take a label as input and output a image. We take 'biggan' as an example." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/mnt/petrelfs/liuwenran/miniconda3/envs/py38pt19cu111/lib/python3.8/site-packages/mmcv/cnn/bricks/conv_module.py:153: UserWarning: Unnecessary conv bias before batch/instance norm\n", " warnings.warn(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/biggan/biggan_imagenet1k_128x128_b32x8_best_fid_iter_1232000_20211111_122548-5315b13d.pth\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/mnt/petrelfs/liuwenran/miniconda3/envs/py38pt19cu111/lib/python3.8/site-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)\n", " return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)\n" ] }, { "data": { "image/png": "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8Hu/93vhe77ne8Lh4WG4cePG8920e9p+8Rd/MfyDf/APwn/9r/81AOGtb33rmfd/4id+IhwcHIRf+IVfCL/zO78T/vpf/+vhpS99aajrejjm67/+68OrXvWq8Bu/8Rvh//yf/xO+5Eu+JHzHd3zH5/lK7i37uq/7uvBzP/dz4QMf+EB43/veF77hG74hPPjgg2G5XA7HfN/3fV948YtfHN7+9reH3/7t3w5/7s/9ufDn//yfH9631oav/MqvDI888kh473vfG37xF38xXLp0KfzIj/zI83FJ95T99//+38P/+l//K/zhH/5h+NCHPhT+/t//+yHP8/CBD3wghLDr+8+H/eZv/mZ46KGHwitf+crwAz/wA8Pru77/3Nmb3vSm8BVf8RXhiSeeGH5u3rw5vP9C6ft7DqB8zdd8TXjDG94w/O2cC/fff39485vf/Dy26gvLtgGK9z5cu3Yt/ORP/uTw2vHxcSjLMvzH//gfQwghfPCDHwxA+K3f+q3hmF/6pV8KSqnw6U9/+vPW9nvdnnzyyQCEd77znSEE6ec8z8N//s//eTjm93//9wMQ3vWud4UQBFxqrcP169eHY372Z3827O/vh7ZtP78X8AVgFy5cCP/6X//rXd9/HmyxWISXvexl4W1ve1v4S3/pLw0AZdf3n1t705veFF71qled+94Lqe/vKRdP13W85z3v4ZFHHhle01rzyCOP8K53vet5bNkXtj366KNcv379TL8fHBzwmte8Zuj3d73rXRweHvLVX/3VwzGPPPIIWmve/e53f97bfK/ayckJAEdHRwC85z3voe/7M33/8pe/nAcffPBM33/VV30VV69eHY75uq/7Ok5PT/m93/u9z2Pr721zzvGWt7yF1WrFww8/vOv7z4O94Q1v4Bu/8RvP9DHsxv3nwz784Q9z//3380Vf9EW8/vWv55Of/CTwwur7e6pY4FNPPYVz7kynAFy9epU/+IM/eJ5a9YVv169fBzi339N7169f58qVK2fez7KMo6Oj4ZidPbN57/nBH/xBvvZrv5av/MqvBKRfi6Lg8PDwzLHbfX/evUnv7eyZ7f3vfz8PP/wwTdMwn89561vfyite8Qre97737fr+c2hvectb+H//7//xW7/1W097bzfuP7f2mte8hp//+Z/ny77sy3jiiSf4sR/7Mf7iX/yLfOADH3hB9f09BVB2trMvZHvDG97ABz7wAX7913/9+W7Knyj7si/7Mt73vvdxcnLCf/kv/4Xv/M7v5J3vfOfz3awvaHvsscf4gR/4Ad72trdRVdXz3Zw/cfa6171u+PcrX/lKXvOa1/CSl7yE//Sf/hOTyeR5bNlZu6dcPJcuXcIY8zQ18Y0bN7h27drz1KovfEt9+0z9fu3aNZ588skz71truX379u7efAb2xje+kf/5P/8nv/Irv8KLXvSi4fVr167RdR3Hx8dnjt/u+/PuTXpvZ89sRVHwJV/yJbz61a/mzW9+M6961av4qZ/6qV3ffw7tPe95D08++SR/5s/8GbIsI8sy3vnOd/LTP/3TZFnG1atXd33/ebTDw0O+9Eu/lI985CMvqHF/TwGUoih49atfzdvf/vbhNe89b3/723n44Yefx5Z9YdtLX/pSrl27dqbfT09Pefe73z30+8MPP8zx8THvec97hmPe8Y534L3nNa95zee9zfeKhRB44xvfyFvf+lbe8Y538NKXvvTM+69+9avJ8/xM33/oQx/ik5/85Jm+f//7338GIL7tbW9jf3+fV7ziFZ+fC/kCMu89bdvu+v5zaK997Wt5//vfz/ve977h56u/+qt5/etfP/x71/efP1sul3z0ox/lvvvue2GN+8+a3PbzZG95y1tCWZbh53/+58MHP/jB8L3f+73h8PDwjJp4Z8/dFotFeO973xve+973BiD883/+z8N73/ve8IlPfCKEIGHGh4eH4b/9t/8Wfvd3fzd80zd907lhxn/6T//p8O53vzv8+q//enjZy162CzN+Fvv+7//+cHBwEH71V3/1TMjfer0ejvm+7/u+8OCDD4Z3vOMd4bd/+7fDww8/HB5++OHh/RTy91f/6l8N73vf+8Iv//Ivh8uXL+/CLT8D++Ef/uHwzne+Mzz66KPhd3/3d8MP//APB6VU+N//+3+HEHZ9//m0cRRPCLu+/1zaD/3QD4Vf/dVfDY8++mj4v//3/4ZHHnkkXLp0KTz55JMhhBdO399zACWEEH7mZ34mPPjgg6EoivA1X/M14Td+4zee7ybd8/Yrv/IrAXjaz3d+53eGECTU+Ed/9EfD1atXQ1mW4bWvfW340Ic+dOYct27dCt/xHd8R5vN52N/fD9/1Xd8VFovF83A1946d1+dA+Lmf+7nhmLquw9/6W38rXLhwIUyn0/At3/It4Yknnjhzno9//OPhda97XZhMJuHSpUvhh37oh0Lf95/nq7n37Lu/+7vDS17yklAURbh8+XJ47WtfO4CTEHZ9//m0bYCy6/vPnX3bt31buO+++0JRFOGBBx4I3/Zt3xY+8pGPDO+/UPpehRDCZ4+P2dnOdrazne1sZzv749s9pUHZ2c52trOd7WxnfzJsB1B2trOd7WxnO9vZC852AGVnO9vZzna2s5294GwHUHa2s53tbGc729kLznYAZWc729nOdraznb3gbAdQdrazne1sZzvb2QvOdgBlZzvb2c52trOdveBsB1B2trOd7WxnO9vZC852AGVnO9vZzna2s5294GwHUHa2s53tbGc729kLznYAZWc729nOdraznb3gbAdQdrazne1sZzvb2QvO/v9PftkIpywvzAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "# Create a MMagicInferencer instance and infer\n", "result_out_dir = '../resources/output/conditional/tutorial_conditinal_biggan_res.jpg'\n", "editor = MMagicInferencer('biggan', model_setting=1)\n", "results = editor.infer(label=1, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.2 Inference of inpainting models\n", "\n", "Inpaiting models take a masked image and mask pair as input, and output a inpainted image. We take 'global_local' as an example." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "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Cz7L4u97q/nj3zt+/Dh2797deT+KIiwvLz8nxu26667Da17zGhw4cAD3338/3ve+9+EVr3gFDh8+DKXUc2Z8rLV4+9vfjpe97GW45JJLAOAJranjx49vOb/8ez9PstUYAcAb3vAGnH/++di3bx/uvPNOvOc978GRI0fw+c9/HsAzM0bbSnHNpSuveMUrwvPLLrsMV1xxBc4//3z88z//M/I8P4tXNpftKr/9278dnl966aW47LLLcNFFF+GWW27BVVdddRav7NmVQ4cO4a677urkjOfSlccao3a+89JLL8XevXtx1VVX4f7778dFF130jJx7W4UKd+7cCaXUJhTPQw89hJWVlbN0Vf93ZHFxEb/wC7+A++67DysrK6iqCqurq51jnstj5e/7TPNnZWVlE9BHa42TJ08+J8ftwgsvxM6dO3HfffcBeG6Mz9ve9jZ86Utfwje+8Y1Og8MnsqZWVla2nF/+vZ8Xeawx2kquuOIKAOjMoac7RttKcSVJghe/+MX42te+Fl6z1uJrX/saDh48eBav7P+GrK+v4/7778fevXvx4he/GHEcd8bqyJEjOHr06HN2rA4cOICVlZXOmKytreG2224LY3Lw4EGsrq7i9ttvD8d8/etfh7U2LMDnkvz4xz/GiRMnsHfvXgA/3+NDRHjb296GL3zhC/j617+OAwcOdN5/Imvq4MGD+P73v99R7jfffDOGwyEuvvjiZ+dGfobyeGO0ldxxxx0A0JlDT3uMniKY5KzJP/7jP1KapnTTTTfRPffcQ295y1tocXGxg1B5rsi73vUuuuWWW+iBBx6g//iP/6Crr76adu7cSQ8//DAREb31rW+l8847j77+9a/Td7/7XTp48CAdPHjwLF/1z1ZGoxF973vfo+9973sEgP76r/+avve979EPf/hDIiL6i7/4C1pcXKQvfvGLdOedd9KrX/1qOnDgAE2n0/Ad1113Hb3oRS+i2267jb71rW/R85//fHr9619/tm7pGZUzjc9oNKI/+ZM/ocOHD9MDDzxAX/3qV+mXf/mX6fnPfz7NZrPwHT+v43PDDTfQwsIC3XLLLXTs2LHwmEwm4ZjHW1Naa7rkkkvommuuoTvuuIO+8pWv0K5du+i9733v2bilZ1web4zuu+8++uhHP0rf/e536YEHHqAvfvGLdOGFF9KVV14ZvuOZGKNtp7iIiP7u7/6OzjvvPEqShF760pfSd77znbN9SWdFXve619HevXspSRLav38/ve51r6P77rsvvD+dTukP//APaWlpiYqioN/6rd+iY8eOncUr/tnLN77xDQKw6XH99dcTEUPiP/CBD9CePXsoTVO66qqr6MiRI53vOHHiBL3+9a+nfr9Pw+GQfu/3fo9Go9FZuJtnXs40PpPJhK655hratWsXxXFM559/Pr35zW/eZBT+vI7PVuMCgD71qU+FY57ImnrwwQfpFa94BeV5Tjt37qR3vetdVNf1s3w3Pxt5vDE6evQoXXnllbS8vExpmtLznvc8eve7302nT5/ufM/THaN5W5O5zGUuc5nLtpJtleOay1zmMpe5zGWuuOYyl7nMZS7bSuaKay5zmctc5rKtZK645jKXucxlLttK5oprLnOZy1zmsq1krrjmMpe5zGUu20rmimsuc5nLXOayrWSuuOYyl7nMZS7bSuaKay5zmctc5rKtZK645jKXucxlLttK5oprLnOZy1zmsq1krrjmMpe5zGUu20r+PwKBWqaN2WKvAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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rOrqam9PsrKy1NraqpqaGm9OeXm5urq6vG/AoeSrr75SS0uLUlNTJQ3u/XHOqaioSHv27FF5ebnS09Mjzl/P91RWVpY+++yziLiXlpbK7/dr+vTpA/NC+tG19qg7R44ckaSIr6Eb3qNeXkwSNa+//rrz+Xxu586d7vjx427NmjUuISEh4gqVoWLjxo2uoqLC1dfXu3/9618uOzvbJSUluebmZuecc2vXrnUTJ0505eXl7vDhwy4rK8tlZWVFedX9q62tzX3yySfuk08+cZLcH/7wB/fJJ5+4f//738455373u9+5hIQE984777hPP/3UPfjggy49Pd19++233mPk5eW5H//4x666utodPHjQ3XHHHW758uXRekl96mr709bW5p588klXVVXl6uvr3T//+U/3k5/8xN1xxx3uwoUL3mMM1v1Zt26di4+PdxUVFa6xsdEb58+f9+Zc63uqs7PTZWRkuJycHHfkyBG3b98+N27cOFdcXByNl9TnrrVHdXV17rnnnnOHDx929fX17p133nGTJ0928+bN8x6jL/bIXLicc+6ll15yEydOdCNHjnT33HOPO3ToULSXFBVLly51qampbuTIke7WW291S5cudXV1dd75b7/91j366KPulltucaNGjXIPPfSQa2xsjOKK+9/+/fudpO+NFStWOOf+75L4Z555xqWkpDifz+fmz5/vamtrIx6jpaXFLV++3I0ePdr5/X63cuVK19bWFoVX0/eutj/nz593OTk5bty4cW7EiBFu0qRJbvXq1d/7P4WDdX+62xdJbseOHd6c6/me+vLLL11+fr6Li4tzSUlJbuPGja6jo2OAX03/uNYeNTQ0uHnz5rnExETn8/nc7bff7jZt2uRCoVDE49zoHvHPmgAATDH1GRcAAIQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKb8L3uWrWd0nKDdAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmediting/inpainting/global_local/gl_256x256_8x12_celeba_20200619-5af0493f.pth\n" ] }, { "data": { "image/png": "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DTzwwAMrj7mRNfXwww/jTW96EyaTCS5cuICf//mf504WzwG7kTF69atffWIO/dRP/dTKY57uGN10jus//sf/iJ/92Z/Fu9/9bvyv//W/8MpXvhKvf/3r8eijjz7bl/as2Pd8z/fgkUceKT+f/OQny30/8zM/g//yX/4Lfu/3fg+f+MQn8I1vfAM/8iM/8ixe7bfe5vM5XvnKV+LXf/3XN97/3ve+F//m3/wb/OZv/iY+9alPYTqd4vWvf30R6gWAN7/5zfjCF76AD3/4w6XT99ve9rZv10f4ltr1xgcA3vCGN6zMqd/93d9duf+5Oj6f+MQncN999+FP/uRP8OEPfxjOObzuda/DfD4vj7nemgoh4E1vehP6vscf//Ef49/9u3+H973vffjlX/7lZ+MjPeN2I2MEAG9961tX5tB73/vect8zMkZ0k9kP/MAP0H333Vf+DiHQ7bffTu95z3uexat6duzd7343vfKVr9x439WrV8kYQ7/3e79Xbvs//+f/EAC6//77v01X+OwaAPrABz5Q/o4x0sWLF+lf/st/WW67evUqVVVFv/u7v0tERF/84hcJAP3P//k/y2P+63/9rySEoD//8z//tl37t8PWx4eI6C1veQv98A//8KnPeT6Nz6OPPkoA6BOf+AQR3dia+v3f/32SUtKlS5fKY37jN36Ddnd3qeu6b+8H+DbY+hgREf21v/bX6B/9o3906nOeiTG6qSKuvu/x6U9/Gq997WvLbVJKvPa1r8X999//LF7Zs2df/vKXcfvtt+PFL34x3vzmN+Phhx8GAHz605+Gc25lrL77u78bL3rRi563Y/WVr3wFly5dWhmTvb093HPPPWVM7r//fuzv7+Mv/+W/XB7z2te+FlJKfOpTn/q2X/OzYR//+Mdx4cIFvPSlL8Xb3/52PPHEE+W+59P4HBwcAADOnj0L4MbW1P3334+7774bt956a3nM61//ehweHuILX/jCt/Hqvz22PkbZfvu3fxvnz5/Hy1/+crzrXe/CYrEo9z0TY3RTiew+/vjjCCGsfGAAuPXWW/GlL33pWbqqZ8/uuecevO9978NLX/pSPPLII/jVX/1V/NW/+lfx+c9/HpcuXYK1Fvv7+yvPufXWW3Hp0qVn54KfZcufe9P8yfddunQJFy5cWLlfa42zZ88+L8btDW94A37kR34Ed911Fx566CH8wi/8At74xjfi/vvvh1LqeTM+MUb89E//NH7wB38QL3/5ywHghtbUpUuXNs6vfN9zyTaNEQD8xE/8BO68807cfvvt+NznPod3vvOdeOCBB/D+978fwDMzRjeV49raqr3xjW8sv7/iFa/APffcgzvvvBP/6T/9JzRN8yxe2dZuVvtbf+tvld/vvvtuvOIVr8BLXvISfPzjH8drXvOaZ/HKvr1233334fOf//xKznhrq3baGI3znXfffTduu+02vOY1r8FDDz2El7zkJc/Ie99UUOH58+ehlDrB4vnmN7+JixcvPktX9f+O7e/v4y/8hb+ABx98EBcvXkTf97h69erKY57PY5U/97Xmz8WLF08Qfbz3uHz58vNy3F784hfj/PnzePDBBwE8P8bnHe94Bz70oQ/hYx/72EqDwxtZUxcvXtw4v/J9zxU7bYw22T333AMAK3Po6Y7RTeW4rLX4vu/7PvzhH/5huS3GiD/8wz/Evffe+yxe2f8bdnx8jIceegi33XYbvu/7vg/GmJWxeuCBB/Dwww8/b8fqrrvuwsWLF1fG5PDwEJ/61KfKmNx77724evUqPv3pT5fHfPSjH0WMsSzA55N9/etfxxNPPIHbbrsNwHN7fIgI73jHO/CBD3wAH/3oR3HXXXet3H8ja+ree+/F//7f/3vFuX/4wx/G7u4uXvayl317Psi30K43Rpvss5/9LACszKGnPUZPkUzyrNl/+A//gaqqove97330xS9+kd72trfR/v7+CkPl+WI/93M/Rx//+MfpK1/5Cv33//7f6bWvfS2dP3+eHn30USIi+qmf+il60YteRB/96EfpT//0T+nee++le++991m+6m+tHR0d0Wc+8xn6zGc+QwDoX/2rf0Wf+cxn6M/+7M+IiOif//N/Tvv7+/TBD36QPve5z9EP//AP01133UXL5bK8xhve8Ab63u/9XvrUpz5Fn/zkJ+m7vuu76Md//MefrY/0jNq1xufo6Ij+8T/+x3T//ffTV77yFfrIRz5Cf+kv/SX6ru/6LmrbtrzGc3V83v72t9Pe3h59/OMfp0ceeaT8LBaL8pjrrSnvPb385S+n173udfTZz36W/uAP/oBuueUWete73vVsfKRn3K43Rg8++CD92q/9Gv3pn/4pfeUrX6EPfvCD9OIXv5he9apXldd4JsbopnNcRET/9t/+W3rRi15E1lr6gR/4AfqTP/mTZ/uSnhX7sR/7MbrtttvIWksveMEL6Md+7MfowQcfLPcvl0v6B//gH9CZM2doMpnQ3/ybf5MeeeSRZ/GKv/X2sY99jACc+HnLW95CREyJ/6Vf+iW69dZbqaoqes1rXkMPPPDAyms88cQT9OM//uM0m81od3eX/u7f/bt0dHT0LHyaZ96uNT6LxYJe97rX0S233ELGGLrzzjvprW9964lD4XN1fDaNCwD6rd/6rfKYG1lTX/3qV+mNb3wjNU1D58+fp5/7uZ8j59y3+dN8a+x6Y/Twww/Tq171Kjp79ixVVUXf+Z3fST//8z9PBwcHK6/zdMdo29Zka1vb2ta2dlPZTZXj2trWtra1rW1t67i2trWtbW1rN5VtHdfWtra1rW3tprKt49ra1ra2ta3dVLZ1XFvb2ta2trWbyraOa2tb29rWtnZT2dZxbW1rW9va1m4q2zqurW1ta1vb2k1lW8e1ta1tbWtbu6ls67i2trWtbW1rN5VtHdfWtra1rW3tprKt49ra1ra2ta3dVPb/B8Fn5pleU7fhAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "img = '../resources/input/inpainting/celeba_test.png'\n", "mask = '../resources/input/inpainting/bbox_mask.png'\n", "\n", "# show input image and mask\n", "input_img = mmcv.imread(img)\n", "plt.imshow(mmcv.bgr2rgb(input_img))\n", "plt.show()\n", "input_mask = mmcv.imread(mask)\n", "plt.imshow(mmcv.bgr2rgb(input_mask))\n", "plt.show()\n", "\n", "# Create a MMagicInferencer instance and infer\n", "result_out_dir = '../resources/output/inpainting/tutorial_inpainting_global_local_res.jpg'\n", "editor = MMagicInferencer('global_local', model_setting=1)\n", "results = editor.infer(img=img, mask=mask, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.3 Inference of matting models\n", "\n", "Inpaiting models take a image and trimap pair as input, and output a alpha image. We take 'gca' as an example." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGHCAYAAACar6kjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz92a8lSZ7fiX3MzN3Pdvc94kbEjTUj18qsNauql+pmN5vkaDQcaQRRAiRI1IMgAhwM0ICA4csM5mn+AfKJTyQgQBxq4Qxn2M1mV3O6u7przcqszMolMjJjv3H35eznuLuZ6cHcfDn33KxsEpqqlK4FTtyzuJvb8rPf7/tb7GfCWmu5KBflolyUi3JRLspF+RUq8pfdgItyUS7KRbkoF+WiXJTJcgFQLspFuSgX5aJclIvyK1cuAMpFuSgX5aJclItyUX7lygVAuSgX5aJclItyUS7Kr1y5ACgX5aJclItyUS7KRfmVKxcA5aJclItyUS7KRbkov3LlAqBclItyUS7KRbkoF+VXrlwAlItyUS7KRbkoF+Wi/MqVC4ByUS7KRbkoF+WiXJRfuXIBUC7KRbkoF+WiXJSL8itXfqkA5R/9o3/E9evXqdfrvPnmm/zoRz/6ZTbnolyUi3JRLspFuSi/IuWXBlD+2T/7Z/z+7/8+/+V/+V/y05/+lNdff52/8Tf+Bvv7+7+sJl2Ui3JRLspFuSgX5VekiF/WYYFvvvkmX//61/mH//AfAmCM4erVq/yn/+l/yn/+n//nv4wmXZSLclEuykW5KBflV6QEv4yHxnHMW2+9xT/4B/8g/05Kye/+7u/y/e9//8z14/GY8XicfzbGcHx8zPLyMkKI/0nafFEuykW5KBflolyUf79iraXb7XL58mWk/Gwnzi8FoBweHqK1Zn19vfL9+vo6H3300Znr/+v/+r/mv/qv/qv/qZp3US7KRbkoF+WiXJT/L5anT59y5cqVz7zmlwJQ/qrlH/yDf8Dv//7v55/b7TbXrl3j7/7d/wtREGKsQWtNHI/pdNrs7u1weLiPTjUbK+vcvHWLSxuXiaIQA1jhUJwUAikECAEWEAKRvVxx3i//WZR+l1KilEJKiZQCqRRB9tlag7UWYwxJohmPxvQHA7r9Hp12h+PjE46Pj+l0TonjMUa79ltrsTgLkZKKpYUFbl6/zuXNTZrNJmEYUKvVCcOQIAiQSqCUREmFkAKbtdhamz/fGI3Wrh1pmpKkCSbVJElKHCcYazDakBpNmmqSJGE0GtLptOl2OiRJXJoJgTWGslPQWhfIJATUanU2Nja4sXWdpeUlwijEWMs4TojTBGsMQkA9iqjXIwKlSIxmOBzR6/XY29vn0ePH7Ow+ZzgYgjFg3XyBs7I1602uX7/OrZu3WFhcAunaBLj6saggoBbVCMOAIFQoqdx4SZlNtZsfnbox0lnfR3HMcDhk0B8yHI4YjUaMxyMGgyG9fo/hcEAcx5lFb4Qxegq1iuzlxsT/lQLqUZ319XWuXbvO0vIKQRgU9JbRlMDRpJLZ5+x3K4q5NcZgjcUY0MZgtMZagckmRmS0KqXAeXDdSwgQUubjEYQBUS0gUMo9w7px1NrRTRwn9AdDup0up6enHB4esru3x8HhHoNBH2tcv6QUzM/Nc/eFF3j11VdZXl5GqSDTjqxbD9noGGOx2pCmGq11Nv4GY2w+x1LIYl1lY+D+uvlDSLdOtMEkmthoDNaNFQIhQSiJVJJIShSWlaU69VBzenpMbzRAhQptE8JgyHAA7723zfOdDofHp5yeHjMejUtr3rdHokQ2v1m7VBDQbDSZn5un2WpldBcRBAFhWCOshTRqikZUY3k5YGlphqPDPqkOsNQw1qKwSMAogWRMXexTrxnGdp7uqIk0IQiFCiRhGCCVzBefW+PG0YLWJGlCPI6J45gkTUmThHisGcdjxqMRw9GAfr9Hf9BnPEwYjvuMhgPGyYBWM+LO7SvcffEKjZrm9S+9zNz8HP3RiD///p/z5PE9rl3aZL21SqJi5pYWuLS5hQrqSDHLj3/0CX/5l2/T740YxQnjOCFN05yujLHYbDELDMJKR58yptZocmXzBnfvvMDq6hJKBVjr6Nevb7AIKTDZGpFSEUiVr2s3JNl4WIPWhjRJGY1GDIZ9eoMundMup8cdTjsdhuMeOh2jrGF1bYHLly/x6cNtDo46COHaJoQkDEPW1tbY2rrO6uoKjUaTehShlHuo599JkmTjPGY4GjMauvEe9PsMhgPGozHGaDcOWLS1WAsW10cnA8heGmsNQaBYWlpic3OT1dV1avWa4/dZh/26gEJu+aiNQga4tYG1TsZlTKKow8u14jt3iUBkdWjt5Ig2miROGQwH9Hs9Tjttjk+O6HQ6jMcjtC2e7+ej4ItAxqdOTg6YnZ2dwj+r5ZcCUFZWVlBKsbe3V/l+b2+PjY2NM9fXajVqtdqZ7+tRjagWOUJMU8A65qBClArAQKBCalGNWr1GFDmG4AWeAKQQCCnAToITQEwHKJ5xSqkKxqU8YBE5MWhjiOMEIYSb2CRhXKsRRSFBoDImnjohnE2qFzJSSZSUBCqgFkXUahFhGNFoNAjDEKVU9swCKBkyYs/qcETlhEAYpiSJRsUKHWikSlAqyK9RRqNUipQCYzRhGKEC93t5DKxQEwRoUdm4BEFAGIREUUS9XieMIoy1CKmQqcJqg1SCWi2iUYtQKkDpFK0tQRjTaLRotWaIojrJOMaSMShRjL3FYrRBSkktihBKVforsYSha0MUhYRhkI2VOgNQjLZu0WXMBSmwFoy2GJMBAWtJU00UhySJGw9Xl3J1nQnhmgQojjkoUdBMGIZEtRphGOYmzkII/2KA4truhZLJ2gnWM4HsXbV9DqD4sVBKEUYhtZqjRQ9QHFOzbizlGGMsSZxQq9WIoigDesoxRWGArF/IbK3VadSbBEFYCA1PmdZiNDnDS9M0o7+CZgvg78B3mRFLGWQ04MC4TlNsoAmMQVubM10h3L2BUgRCoqSh2apRrw1IEk23f0RqG2jToN/rcPPWdY6PerRPe3QCSSAVqVSZzlKsdweQHAgiW+cqa28QBERhRBiGmQLhaLAW1YlqgihqIISlVg+YnasxGIRYW8cKgyAhCDRCWkRaJxILRKrLbKuGiuokcYDWijAKCAJJEKh87XmA4ujUoBKVA7wgTYmlQgqd8yRjNUniAIwONSoNEFISRQEv3t3im2++TBK3uXnzGptXNugNhiwsLvHKyy+yv/eUB588RmxIRnbISf+UxCS8+eZvg5ljOHifIAhQQYBKdUZvMgcajgY8aw0QKBApNuNlQRgS1iJq9TpKOmVSGAvWoJTFop3OIhQCp3g4HiqydWQqY6K1JpYx1hpSE1NLI+phkyiMCcIeQSoJUCzONblxbYPne0d0ukOUCoFiXXuajKKIWq1OvV6nFoUE2frMeWgG9AUCYxxwSdPE0UQSogON1gIprePz1jjFwhisFKU59etWFGs1dPw/CmsEgarwDUeXxWfPIxy4K8bc119g7IK/eD0952IeyJgyQHEgRSDQOiKJClp386AyHiJKz5sMwRBgqnL1s8ovZRdPFEV89atf5bvf/W7+nTGG7373u3zrW9/63PVIAVLI6R0tAQ6RCQ3PcKAkRnIttwpCpr13f71GSukaSi//NN+majvKVphyKa5xbXLWFJsv7OozP9/kQiHQfDsqhC2rVqHJdpXbW+1rdXxs6VnGI+ZSfyp14AWuyIGiBwHamExAy2JiJorRhiROSOIYnWlWHrhUh6Q6ZuXBK/pY6kd5sUr3qi7gTGvLqymAyDkjnz+/wjBKrzN3lL4/Qx/ltjLt2Tb/1oOTcr3VIfDWmomhmbje99FfX4xH0UN3fZmxCjKb2pm2f55SjEF1jVX6m09fRnsZiHAaHygEygqkBYnAIjnpjjhqd9FYdKoJZcjJ0Qn3P32fOOny8qvX2diYJQwsSjreUozFJC1ZwJSY+uRcZtdXxgXixAG/KAJhXR2uHykn7Wc0mjFRCFY0wdaoBRLsCCtSEF7QnJ1LJ5SmgeXqmp18WTRWGKwEhEEFCTs7D5AiZWVljZN2nxSYmZlh49Ilrm5dodYIWdlYZPPKLXrdhP2DQyxwdHTA4dEx1ogJYFxe98V6QgiQFkSm3Wc044C4xKJyOhdC0GiGLCy23PU5FK/y5vPWoxACiURa5Z4jDUIYpLDMtEJu3LzEcDRkZ/eIVDteWR3LSd5S1PtZ5by17L6b9r0bh7O8pQAhZSvJNBly9kHV9pTXdPWe0noty4IJIFOsBTuFpgpLztn681aQ0/3nKL+0bca///u/zz/+x/+Yf/JP/gkffvghf+/v/T36/T5/9+/+3c9dhx8wIWwGHPJfgBJzybl2STDYs3WV0ed0kFK+wz/TM6pCe0XYTLucDnyKz65Nro5s4nxfhMEajUFjc1eTn9wyKCoLAl9M/iqusZW+nQFMpbbmBCmrxOVdUOXPk8U9w2CtKcZrEgRmQzQ51jqzCvibbKlPueXAGuIkJknSXHOsjml1nM+0cYqw9n/LC1GWwJwSmQWkxDCzys70v1TzlLbJQpBMobEqE5hSY4URVE25pQ5Wxmuyj0XrXL+EdXJC2mzEjXHvjXV/S8KtACkZyKVorxPEKcbo6VYlW9b4zgLiSdA2/b3J2+6tmzYTbs5JIhFIhBFI6/qmhcEoGGvBKKmRGMMLd+9yaf0K4/4QncDJ6RFxfMJXv/oi62tzSJEipXFuCFGeR+usN3mbPf3lSCUXttbi3KeZm9JYjTWS0SgmDCVKZCBIWLRNuPfxexwePmZto4UILIk1znKAyDpsAJ2PxzTFwdOv+64QFhbHTwqFJHOJSG/yV1gr6PbaJOmAS5eXMSQkJiVqNOiNj2m2amxubtFstbi8eQkrY+qNGiAYJzHPnu0zHKZYKzHG0YZCAX7dGCQaSYISCYEcEaoxYZgSBCAlCJmiZIogRZXWjxAQDweEAQRSlsaAnPaqdI7jv8I4q5QAYRXSBlhpMMIgMczUBDe3VrFW8+DhDuNYlKzZsrD25Oum4Ol+Dfi2lHnReQrIZ5WzoLx49qSM/2wA8PmfM8knq2128kOKs2DorBw7q3BPtvfftfzSYlD+zt/5OxwcHPBf/Bf/Bbu7u7zxxhv84R/+4ZnA2c9bqoNW/qGkAXmCozzpAq8XVwZScA4RTCJXUVkgOcPO2+IXksjNwtNBxdlirM3iCyY1cZOZTWWVqJzUz6/NW3ymfec/vEL8U34jAylVxl0CEMa5lKr1ZYxT4EziXnsvuVEcQIKyGbgAmqZotwWjNVqnVSCJwAo/x86l8Fcr7nopM59sxuwDKYnPBamfXRcliOXmK/u2xPimL15xling+miqEJEqPZ4F6ZPtcNpk8WvZMgMSKUBTjLd3F0wDFZUeC5OBE0MB3qvAvUKqE2M6SU+T1xUM24ESYcu0ZZ1FwrcZizQGKUWmsAmUtCgTYQmJkwQlaqyubmCjU5LYQAvm51t881tv8OTJY4ajAaBw1U7T46o8wFsIvAbs+mOyF1g02kji2NKoW8IQdJyCkIBiPEr5+Qc/5/rWTWYWFf3TBKShHkUMBhIhnXJy3hi52LeqO7b4vTreBdBUKOFcQhbJeJRwefMyRqacdA+YmV8latTY2X6K1YbWTJMrVzeYnWuRPk+o1esgyOK0EqwWzoJmBeVYE8jAntJEoWBuNmJ1ZZGVlSUajTqpsezttanVBfXakDDoI6xEEgASDFhpCAOBVAHoKs0XCqpfa1l/M8CaKxXWXRdIQRhYrmys0mpFvP/REzp9jUFlEDQDdVN4u8gVw+m0PDkvkyUHAqL47K896w4p0dc5jMfHyUx79nm0cvb+ybrLCxVHexNGj7M8JwOCwoO7vyr/nV5+qUGyf//v/33+/t//+//O9+eTW7YEZEJuqoDyoKMy/lXrQfn7MvOvCqjCnFW898RXZqaldslCC/0sxFn59lx3wGebDsu1VG+dpnkVWrkQJv9cdgVNmmsnBaF38viANmchyH6VVROzPE/Q5Z9LY1QSo34hWVxsj9ZVC5VrgGBy3s8I1pzBCKpWt+o9eQD1OfX8Yq2gvHDPZy7lPkyCoDO/42wEumJerdLoNHopGGsx/q5+KvX7h1TooxSkWo6R8XNRdMZgbOriTYQHiGcgLn5tlmNOXJs/WzOsmqdzO1G2Am1uVZEWpDYEqUaOUmSQBbAHEVpqEqnRdUG9EdBo1VgONtE6odvrsrG+wZ3bl9jaWqPd6eZBjAhPf5UW4dd/5mcqjavnS65t1loMTqlIxy4OJ4gMJBYIkQRsbGzxwUc/4E//4k/49re+zcxigyRNkEIDipzTTaHJSUtd2ZIy+V3xVyFFgBAJ0hqkhLWVFVqtWT669ynDZMzdF1+lOTvL8uIK77zzDs1WHSkFQRAiZcTO80fcvLNFoGrEY5OFFnjm56w2DiMalDKsri3ywt1rbF5aZH5+lkY9QipItWb5+TH37j/g0eMTmvVXaDUCUtN0ICOz+BiblmhK5m7doq+GwjxbzICjVQMCJIZQaC6vL7K01OLho21OTpMMnLh7PC26qff06vkNZ8o0nnAuexDFKvDXnTXy2spcy8l4NEu+FrI7ztCmn2utnXXeWussaKU2W2tLfL68/s7ni9M/W8peg6I9HnSVFba/WvlC7OL5rFKepnzA8nH0DL5MyBMLV1R98RUhcWZC/CQW4ASmEZjXnkrPkROaqCxAyzS0K5g001cJZBrImJQHZcFU1kIn7z+3VH4rgJ1vbz6eudnQBX+5XRuT5kqbCTb33o9JFIQkQVqKTM+ELN6gno9GDnysKeqvCMpz3Dfno/lJgDYNeBSLvxCQvwicFPe651fnZhrQ+TzzMR14SCZTCZx1+RSjOEnrE9jkbBuntJkzzNjRu9vVpPEMSzBJP6JgYmfouZg+D1jOdd/5dgkPTgqLjTIWNR4huwPUcESAQQYh1OqoGYWYFehEMw6HLK3OMz4Y8+OffI/n2/f4P/3d/y03brzIr//613i6vc/eXg8nCMvrvAw8pW/EVNpwX9nM1eNcPmki0aklCA1Cqqwqyc0bLzFOOrzzsx9weHTITKvOQrPB9SuvIKKrGNvM3Fhn+cAvcnP6MfW/ezedkhKJoR5a1teW+bVvfwVtRuzsdHm+t8fBQY9GI+TyxiWEUHzw/oeMe12iN2ocn5wwHI1YXl5FqZqbL1MV5O5lCULFxqVllpabCJVw1D6iOxqQjGNG4w5CWX7ykw8ZDmKENPQHQ77+lb9GWGtgjdvtIqxlOBxhdIBA5kHjOVGXWP9ZoS9ASIy0KKGZnwlYWmzxfGef5ztdjA0y64pAW4PMQAAlq8xfRbieH2/mrGC+TdX4puoc2hLorc7pWflTTHXxHB+YnMuxieZPkyXF5ymdEr49hf21kC/V924MspvySar27/OWLzRAKQTLtB+rGmxFfufCIPOnT7gqCiBzHpLMnp2bds9vo2e2WL94foGAEzibhCUT9jYX2L6+cv99g84DKFI410cZeBXCx1lNpJROizJVIV0h4lKdZy0q5aus01Yoa9F+nGyJgF2bAqUIg2zbdDaX+diKbA68xuABR/m/0iLPlN0zba+OSfH7JHjz8+Pb4bbQqoLrleYgn9eJOaku3jJzK7Z+l3/385bTRlaHFyTTihLOzWEqDKFquSsHWBczMFkKTc3dI86MS9nqlgPtqS4P8Fs8y2vOR0JXLCDSIq3AComUfix1pT35XOeWs/KaLM1FReFwcCJMNLLTQ7U7BFpjJeiawizPompzJOOY3miPVmudWq1Oqi3HRwMOD3osLh6zee0S3/61r/GHf/g9egONECpbOFVXQgH8qrQxOSaeNq21aASphnrNoFRAmpLtOAy5tHGN7mAHgeHd937O1uUVtq5cRymNMQKBKlkmLdZUAWA+5tnYSSGdUoBf986t44dXWkMkNfPrM/zNv/nraNMj1gmGiFZzFaMN9z7+ACksS8srfP8vf8j60gL1eoMbt65hA0u/m/Dw0+fEiYuX87EfLv7NENUCZuciRoMO24MD9g8UKoywNmQ8GmNFwsLyLHsHA6y1NBuK/nDsYlmVAevSCBhjGI1itFYuwD6bBr/TL58X63bzlAYqlxECS6MmaM43GQyGbO+ckJgAa9OMx9p8vMr89qxLtgCj57tRivVS8Glv93PvpRAOfOV07ACMwwImo51sh12l7nP+2kypE1X6dLxnsn1lIvWXigplu/U7KW+KvlVeuZKYc+K8nmIDQ7GmP2/5QgMUoNCgMo2rEFXuV2EVoNxfmzsjcubrTH9OWIOpDLq1UObF3t9NpsuIDNkL67yd5cmy1k22FgpIM4AyIQwtGQPPXESZKVFYn9Mh65OxYP12PeEYZkkQWkEmrESJoATSOjNovrMGv3injWPG1CZMwX4RWizKPZDCg+P+N5Xv3K4JZ9orGLi3VLltdW43g3+OUpIwcPk4gnxBZ7uYKBg8fu48APKMo0Tvtiz483krAy1Z1CNKPn3r3CcKhbepGc/vpNvWYd22sRKNSIwxRXvPLDzPdPzLtdtajRQQSD+HJRB9pv2FYHZfuVgD64WAdA3NzeDGbVf14MS5F3w9GXOwFuXppTyItvAj++crAYFwW8kVMnu5HTI2A5ze2uHpE6sy+i+YlJIuD4a2MvveZM/JArmlo/M8NFoojHBWRiMsUqgMlJniGivQuHUps+gcFyQLQZIQxWNUkmARyFiRzrSwWhHWWhwdniLMmNWlJba2rvL+uz/n3/6PP+GjB5+SpHB8fMLcUsQwHmG0BRsgRYLLwBJkw1nVfClpmLmCkc2BDw/TRjBOEupSYUgRVmENCKGYW1jltVdusf38GZuXV3n9lZe4cfU6e8cCK+JMaITZo3UJNHt6yQBCZt0pxInFCo2V0m3RlW6nU00K5hdr/M3/2W8wuzjDP/vn/4ZvfOtrvPjSHXq9EafdI9rdLiedNrduXua1V19DD3u0+8fMzs1y69Zdtp92eP7sMZ3OGGPBCI0QhkBZanUFCuLxKXPNOu1OSneQIMSQNE2wKNLUcLDfQ9oIJUDZhFdfusmXXr3OaTehczQmGaV0uz2EnEULr+ll9GoDNx8kuPgfhbQGSEmtowcjQApDSxnETECsU57sHDBMDdpqFzSbs06DycFHEYvleK6LMZJC5jznrCIk8HFIZ3hoxlAEztqEcUHQhuxZCIRweVJE5pJCWBeULQTWTFqGsm3+QiLz7xW+FzazLBbuybOgxgfCexYgvVIhqBqQHPdACOsCmj0IRqKESzPg4oZEDsbJ6N/jnJxaPz8++eWeZvzvW/KBpqx9UoABv3BtgXSnWTC8RnFGOJRGcprptAAkjrrLYpCShjtplSg054l2UKWHIqCqqsEWwqoQ3dMWSqn1ZwdvCqJ2cRclV1S5n1Puq7S7pPFWrDxTNAmfp6B4vkQFiiAsEt+dBRhey3duJJ3tFsmRfmXczptnjww9UDh/J8207evTrUt2grbKViIotg0ytS4frFh2MZXH0s+1Y3ISazMmCQQZYygEVDYbVuK22csKmPXPLW8XLjetoPsSA/OuSLJ8EFIipDxDUtZm86qLGKQS9iMPmvS+alHsMBPS162ysShciD7RFMKWNLPi4dJqJCnCpgiXZCVbi95NVGxK9Z8lAaFsMuwbkrHm1Ze/xMsvvc7h4Yjvf/8DfvTD93n65AAhwyxhmAOXxvo4C4m1hcDybSp22WU7bjI3l+MPLuDTbc5xY9+oCaRIEMIJRSVqfHr/CaenPVZXV1leXULrMStLM9RrEAQxjYal3hCoAISDiuSpD4QTcm6yvLRxkyyyHEBKOAEbKM38vOKv/bVvs76xxr/6V3/E4VEHawPiWPPkyTZPHj1n+8k+R4eH7B88pdvbp1YX9Hod3nrrbVTQpNFYwiQ1jA4xViFsQBgKrmwtMjMnSZM2szOS3/rNb7G8tIzRbgyElNTrTYwOGA2g1VhkbfUKrcYc17euML+o0PqQZzs/IUm33TjZYp3ITEHwIjG3HmVC29ogsyAZpDUoNI16ilLQbg/oDzTGSKyQIKSzyuDVtyrwrK7HMr+bpgR5N1fVvXMePyqsnBasRhAgZIggAqMIRIBCuV1fCs7ym0LOnZVPVN5P8jj/Q1FHqV4K5uD5/3lyzPPKKVKmeP5n/PZZ5YttQfHoNNO0RCm3g7WF8PZjnWGVymAVA+0vJIeOuQaY/16dwDMTXiEQgTetVZ5nSxNOdaJz8veM3bsEJgmyTHgV4eSJvmhBNkwwcR0TbZcyswZA1RqULyJRqcu3rxgVmLYoy+0o+mTxO5C8IHIJiVxStXNz25Tq8MG4RX+rwajTdjHlmqynjAnw6PswOa+TAKvMjKY3s4riSsN3BnTk4LAUlDy9z6U+ZQAEyDIhF5am3BpTAuWU+5yV89iJe34pAHmi/zIPej57r88KW57Xol5P3cX2d2SWQdU6UFywfxCBc/+QWyUmx7pY1DZXSDLBYjXGGqy0WAXaWlKhIQRkTGpSavWAeGjo90fMLta5du0mgVhk52CH004bJQQmiQiUJiHGAQ4ogjO9K0OC0Aih8eDUYvNs1Sa3LHmtUpDGkIwsQQgq0KjQgQJjJJ3OiJ29Z7xw5wVq4QLNVh0jUlopgELKmFotAFGnfZpitNcxjQMrXpiJNBt/J4AFCikMgbREQqIa8OU3XuHO3Zv8i3/5P/Deew8QUcAH9z5lHI/Y3TkgVBIZJGxvH7K9vUv7eJ+vvf4a43REqlOiKGR5ucXBzj5YBcbBtaAuSGyPTv+IKIBrm6sgYhIzdsnmVB0ZCCBAoAlUiJQhjfocQxvz8NEzbty8xKOHH/L40T3C64bNjZcYjSXGytxS5sC5LQWz+4Bibw23CKsJ0MhaitBDRp2EQc+AjRAixW9wcBYHl1xucm2U3Tz+c25DPuPSKyyXZb45Wc6CFYNSkPqdUGiUFCgMgXAgHN++M4uv3L7zzBPTwVHGyaeuZ5HVVijTk3Joiuyp/HOVTDUsf87yxQYo5WJLqDYTWODGtWySyoFjrvVkAr+qPFYEcTZNVRRaAS9TBHEGdiYnUIjCHXSGaDhLXtVAK/86++xKPZ4opqDpclvPv99lyJzMt1HODeCvK2sVWCgDlIy682cUQrZov5QSjM7myaUnn5Z/hfJ8WIstDDAZU3FzWt5tMSkkfUNFNtLlBVgGf3IigHnaHBYdnGhn6brKQynGxmd+La7ztDgxpll7rLUZEYOwKdaGTnuWGi/srTEuBiBzAXrAW4Ri2QpQ/2wmUYBgR+uOFiZTYvt6yu2cjLHx81NmoBWAI4VLoGXdTgsXpeHMLzLzv0vpkooJ6zU5CdYl8jJC4tiYRWJAaGwgMDVFWg8wCWirSWsSVR9Rn20ySAyt1gz1mqE37CFRzLVm2bE9BHWsHtFp90mTEWRCMJ9r3/jcxl/Vtimt7UK7xIEZoREiwBpFmhjCmkHIhNSM0KQ06gt89Stf5unOPHOtVcZjSbvTQdWGBMEsadpgOIhJkjGz84soZdHatcVZpgpBIrP15DPOCSRKGFSYQqi5ffcmd+/e5E//7C94770HjMYh6Tjlo48egkixGhYXZri+tcX161s8evwInQYkcYJONXGc0u6ecGn9BrPzknY3RogYSDE2pdvrYgzMzTTY2tzk+fMdUq2RUhLHkAzGaDNG62Kdtppz3Ll9ndPjPX7y4/e5sXWdo91DhNCsrs/R7zU4OB5jhHXuBCmRpfF3+C8TjkIjrMvpE8gUK4bMLbVod7tYG4D1wc+ypMhWFa9JxeXMKimt1TLNVxVa+wvvcUtTVtyzgUyYn6kjjCCSEAqFsOWFW26j/y7naBPXuc9nFMdzlKFpZZq8mxwZD0jKzz6rnJ0PoaaVLzRAsSVmWAQUFkJc5IzkLKFMgofi9+lEeWYupyDZCl52nDRjHExkbZVIoc6daPDal8l3xTiXhA/+KrT88zC6EGcBkq+3aH/xu/8+1+SpbknN66RgKB5sFEb0rB5jM/5d3dZcuKMmW+utKLKSxtk/syB8/wx/rkehqTuhlfmMSwuwbD054/z0/uzSs3IQKapt8Luwyv2fDiknxjkftypIKb8mLT/VMc9GzppCyEmnO0Y1QVSTtGbqdNoxndMBVkh0WXZS0oLctxN5XvMnF88s3VPOI+HnSEmXil9nnh6ZnQPlwIlPjiXyyix2YqhKzLM0lkJaECmIJEuhDdggO3pAkwd1C0BlOUq03w7qNGejQLSa1MN1gtE8Nk5IzZggHBFtBIzkGMM8cRLSmhsRMySMZlhbXeLBJ88JAlDSoNMUY4RTfFQxmN5a41w22d+Ku8fiLVDGCGfJQSNklg1WaCw1ksSgIoNlRG9wwvbuc9JBAPQxaLczSxhGyYBWbZbxOGXYS1GqDoHBpNmWWwE+xgThz4bS+RAbka06a1laaLIw12LUC/nmm6/z0f0H/Ozd+4xGEm1qxNpw2h6iAoM0llok6LQV2KsoGbJ17RZXr14nVAFpEvHs6QFR0CBqjDF0GMddpLRoIxiMDdIGrCzM0ohabD97QLeX0OklGB062sdklkAnpINAsbiwSrO1Tvt0h4efHtBqLTAaJfzs3Z+ztHQbYyOscG5GIRV58IUNcZlxNUgNNiUMM8CiR4QNyY07d+gNdnn87GNEfoyCV1VLSfdK1hHPQ85YAfL1WXV7VH/z4LzKB33dZWXOIhEigMxSsrJa5z/5j/8D4kHM40fbGKEJVJApINN4aPm7TAWzlGiyaO8ZvlMBFaV+n9PPs/0v9d0WfN7X9e9TvtgAZcL1UTbDez/4WRMUpXsKIT1d+xX4wNn8/oqAn5iwslacT3KRUXWSWCfBweR7bBWEnfndfTGFCMSZv9ZOIvzMSjDxPZQCZdVZt8bkswQSn2OgPEbFdSX/Jf6soerzvJZcPifm3OcJ6YLxSi4eP77SH/DF2b5Olvx7a87MiR+r4vyV6YCyXNdnFQ8WfX98TIMoMQZXx1mLT85IstgNAUihabYUi0sNDo8fQdBCKOUYnMkSl4nCYjVZ9y/UnEpj6q/3AM3lZHAWtqAUr+RDX/N7pHXgppS92QqBMO5K16LUHSlgySwmUG8o2p19xnGXWj2gVV+jUV9hOABrNWE0IoxSavUa45HEnIDWIcbizokKAlSrSa22TAgYnRLqDsZuczDYJxTX0KaF1ZpOp0e7fcjS4jyrqzUWl0JGtgayxmB0hDVB1laDCxH3bjiLRBeuBGkR0tKaiQCNJSaMFNa4aywaVEpv2CYIlghoUm/NEjUSPrj/Ic/3dhEi4tHHuxwdHTO/UOc3fn0R1Ii5+RUa4TKdY4vRtSwHiWEwTDCmlq0/D0zKYF3mio0UrhX1uuXVL20SYOn12vzgh28zHIK2YQYWJOOxxY40rXoNnUK32+XBo3uA4Mb1m1y+tMmwL7hzs86jZ9v8xfZbzM7WiHUPhDsrZzAco1PJ4lyD61uXefZ0l6dPTunFAmtrWOOFZurozAoEQS7Rm81VZhsbpHGP4/g+axvLYBdI0mYmhZ3VQ9sEYSOXFF9IB24zlS0IBBvrNZoNxScf7hHHkmfPuxy1+y7QVlqP7zIFyzgoLpwbKY9GyflPyfpQ4v2TPGby+8m1fHapFVuKwYLRKGEZDQY8efo+i3MRK5c1IpBYLRkOz9bpwhbKqR/KFsuzz6u+nyb3zpYKmJrCk/NrpliMzuv75ylfaIDiisjGuJSevbRX2+0mKBjppOo4zUTn37uK/bY8796Y4jYoNaV4m4GUbPFIb6KfmDD/zNw0TgGicpTN+cQz2Wbv4nA7fyo2mfyZSkh3BgeCIm/BJPovgz6Zm4dykGYhDz7OEyMVmWEnx1UJFytUPnSteI7ruVIiPwjRJwjz3h1XfREhbmwpC22+jbBaqm0oLGuVfkqXFt2Wzm7yroxim2YG3MT0+JjPWnxlzcJfW2Z6hfZxHl05WpaZti6EpdEUrKw06XZPGY80/d6ANK07lipDR3cy051sfnpQXlu5Xb49coIuq31zv3nrVhiGNBo1wjADb0h3iJ1ymWiLXUDlAN8scFDIiY1kPp+IpVYLmJ+PODw+IdFtlpdvk44tCR1mZ2tIFdBszXB4eIIgARKiWoPhQIBwWUBREluPsM06WrmDL3USs7NzhGoIhEpJzRCTxBBr4mSE1jGjpE99ZkhrlDKODTdvrrL9rM2gH2MBmaVtFyI7NVo4oOXsJholYow5pd6ExaU6o/iEw70Bwi4yHEN31KXb3ie6eYu19RusX2rx8YNPOTx+gggUJ0dHDAcdlpYW+c3f/AbLyxGPntyjXjdcuzSPlBalUgyGcexOUTYmcPNrvSWgRL+ZYiWlwEpDoFKESEF0qTUa/Mmf/ISjkz7aetedcxeiFRiJ0QG12hxbW1fo9g9QYYplzEnnmHqwRqu1xPpajeOjkNPOUywjgiAkGVsEipCIhVadVnOOd376AaM4wFqFsD5lv3PTuV0eAdigoD0rQQRYkaKCECGbaF1D2ywo2Lq4H7/13PGxNONDCpcLecBR+zGaOjI09E8lB58ccnTczZNHSuvnz2b1ZDsmM35Udhe7scz+5l/anAeW3ZvVtTOdt1avcYn8nB0lRKKZaUZ02z0e3D9CqDpbN6+ztBjidr1NHBtRUXKcUj2tVORM3odpci9vHJZpCnBZgSsUk7P9+vcvX2iAkgspSsm68kkiJzT/cj9NEwI215qrpWyBqCLp/IoyIp24s2QXwQug3I04LceFtUzWb201IPSzrQK+reSE5eM3qtdbF/s+oQ1U6pJFdLbMmPKkWVBMmA+tBauL01W9ZX9KR0sPqm6xdW6eIDNRllxJfot4Br7sBBAqydHSeJTGakLrOW8+3e+ydM9nb3RzdHOmhql1T5p1CxCcMcgppuDiXpOdGAoraw1EcMRx+z4ytKAaIGrgs7ja0lqoWKzOMqPCkkRpjIo2yvw4ewe0w0CxurLCC3duEkUhxhjSxJDqmGazyeLiArVajTAMSuNsnbvD6HxsnBLrBJQxXgFIGQy6SGW4c/MuVs9zOhqxe/AAK9tsXbvJOJkFGzAcGESoSYldfKYJ3LxJB3QJpPO+GIhTw0G7x/DwgLU1Qa/7nHQsWJpbpVGfQZsBh8e79IcnjMc92u0d1tcvEYWrPHy4T5oYjBFokzU8n2OBT+turKbTOWH7+Q6bV+fY2JhjOH7O9rP7xGNDbUZTj0KuJZuM4jbdYY2fvfsevcGIUawZjTQzMy1uv3ALrWP6/YTWzAJvvfUz6t+oEyezpBakaSClyyPi3ExeqOPS/VuLNdpZuoTIzvKx1OqW9bUZms2A0/Yxh0ddUh1gSd0REbggX4xAyhCdCoRoEEXLqOGI5aU6tVqD4+NjNtfXQFrCoEarsUo8HnLS67lRyQB/FEiubKxweNhh97CDoZ7xaIOQpsjhUgZXFG55IWOSdMj87GWsaWJFmCmeIVkiA/wZP8jMxWwVxmqG42O03eXh0/dp1CJm69cwzDEeg9+GK/3OOfzW9ix7Sr63NnPPw5T1WKwlfx7TdGD/eYtwrjGtUViatYAb1zZJYs3BIbRmmnQ7IYHso4JGcVd5HZc+T3iqKm3q9XqZglHUk4dBlLU8zzfwAerTNw9UXtkd3oqdK5emvMM1U54/Z/mCAxRNqh3TM1SDD/PiKImC6CbdOROM+heUz4MSM7LJD5xTqppFtgKiclni840UJbcUnDGpTQMnVaFYPIeceCfNfwIXQ2dL9RVj4ZiNkgot3RkrlafakobgtQ9bPf7dP2Pa4i0DBEtB/MXR6WS5UnzDvBmRynPK7S6D1Op8ei39nDErY1ohqGYe5gxtFJ/96/MsuKp5tDzOZYDsX1UQ49pkbUK9oYhqA+59+kMePfmIS5c3iJpX0GYRLYZYmyJkDZsHH/pzMQRly9VkO6YlJ/DamY9FkkLSbDZ58aUX+MpXXmdlZQWBIIlT4nRMmqYEQYAKonxXmHv5o9pTdKpJtUVrizExxqQuUNIIhBnSPj2hVlNE9RpprOj2O/zwJz8gqPVYXlnitNOmVbtCnKYM+seIIMLaWZQMENa7nfx4O6ulwWCl5IMP7vPwwS4ba1fBNllsXWI8CrFIao2Qb775LdqdAd/9k3+N1n2iqMXKcotGc47hULD9/AhrQfoD6LwCZEGKkFa9QZrUOT44pNkwvP76LVT4gHsfbjMaObvCD37wFnv7OywszPP06SkLi8t0O4esrqySRglPnz3mnbcPuX59A0RMMhqjv2JotZp0eiGCBhBkoC5zExrv4sgsIdK4PDnCZufswNJinevX10jTIZ3OAG0i5xoSGoHKzi1yljRjNDIMgQBrG8zOLjEedfnk4yfcvn41s26mGVmH1IIFasEyWsFAD5idDfjKy9fYWAv4/k/eJzEGpCEPjsrseFKR576RwqCkwCXFMyRmgBCCMJhFm8Cvnqy9JgMWKqNTZ9GyxrJ/8JQf//SPmZkdMzcveXB8zMt35lmev0SnNwArkCJCEGaAyLlITB4sew5Pn7r+3fSX4wvPrJ8p352x2kvQ1sWXhYHlzu0N5mdbvPv+Q/pDRX2mhrY1tBaooCp/plk+hBD5bsXJZ9dqNacAVuSF17IKnlDAcA9QqsegTL6vlNwS9u9vRfliAxTttjUKXIrifIsjtkiFTCaIM9fCBATIr5ic4PL7nAigEKbn3JPLUy+Ec0FQPMcLYq+lV55lJ5aInfyiJPAz+eiNfF5hztG9F7Juz2MOVKQU6PwwL9crH2Mw1VJTEmq5AM2Hz8Pkom0VU2fWx/PdVdVxtL5/QqC1QakJjR+fOrwYVyGrcS+T4MTiD1fMu5IzigKQlK0XJRdPJXEd5xRvdfDvq8A3vyZ7W4A4/5PNXCMiH4NiTD3VpaS6Cyqg0x3y4OEntDvHLK4skiSW8ajP7t5jrAlYmr9GrTYPIsBtWfRbkCnA8ZnOVBlnMX1uHJSQKCWoN2pcu3aFOy/cYWNjAyEkOjEkOnbbjLX29kKwlABKik5TtE5JU0uaGrROSE3icqdogU4H7O51+eDezxFhyurqTXYPnvDg4SNe+9IdFpY22N1/RCJOefj0Kb3hEQJBPJa8ePfrtOqrBEoQqGI7NN6CUAvoniTsdp8z7im+9KVvoMKIKFzi6LjL2++8x2/+1io3bm9xd+cFdrafcXjQIU5GiLGk24F8o0ymwWOdMJXKuJig5Rb11grbz4842Nvj2tYyX/7yTYy2HB51OT0eMegNWV4dc9reIx7X2XnWY+/wiGF/wNLcDHE6YnltgXavTTzus7q4TK1WJwxadHoKY91GbSUMkFAkenR/fRCxD1y31tJqhmxdXyAM4OC4y2BsSXSKVKAULobG+jSOJsNcNkvFL5mZafHJJ59g0oRXXngVk2+F9dEbIYFcJE17YEMCkdBqGIIg4atvvsF+56fs7PRcsj0kAZqwJqk36vT7Q9LUYGWKyZif1QlpOqDRmAWcdUoIlSlJGTgRGZjxViwBQqUEoabbO+b4pMPdFze5vHmJr7/5dR5/MkaIgZMBWVZeD+qstwT7M6Ty82NEaZmU+bjNrQTFOjkrN2BSORNnZLYPwBUCpNKsr89x5eoCjx7ucXDQxQYtrARjBVIGpZqq8mayvkpWrlJb6rVafl8FkJUs0MLzqqltnZCZ2cuPZT4Y3rI94UegEImfq3zBAUrJxWOs+5waKMVf5EpOvgOmXLwwcoL5vNTihSBzmTRFKZmKuy8TaIgiC6lPRS1ELoxK80ku2CdRdp6J0mmAxrgMgi5Lnw/UKwSpO9nVJ/pxxOieZzLeJTJfqxPu0hpS3PfGuL8u+1TVvSCyjIlSOR+19rsBcg3A4gMgLc40KgW5JcsY93yTtcPlF8sWihBY6RiEFeXU1J7xOUAZBI48fQIskQtW4ywF3gXkvnHMy30ozuvxfuksg+O5mhDl85KyQM6s/gpdlBiRt4DY8p7nCiwuJRyjiJvRWme7kPx84zKkinKdTivMqAljj3m2+1OMWiRJmjz8dIeZhYjHT3YZDeqIpMuTTz9gPB7x8kuG5uqrWGrO1W+zpGHCba3UGIo8o5lwK/EqR1pOEHgaEsppemEU0mg2ac3M0JiZQUiJ1paa1s4NaEwOQnPGaEzWd3dWj9EWox392WxbqtFgdEKtmfLTn/0pvc6Aem2Pu3ev8s67q2xeu8TDZx+S2FMS0eWdD3/E6VHC8vIss60IuMHyyjWUXERFEAUhrnYYDCUffXgPbJ0octp4b9Bjfb0G0rK7f0JsNQftZ7z74Tv0e2Nu3LnNa1+a4Uc/eIu9nR6jfkAgw6xPmTZpBYG01OojltcsrQVN+3mH2dkZmk1nlZidD/nyV27w3rvP2N15hJWSTx48Q6eWNBboVNNoGLa2lrl8dZWDo1OSGEaDiORoxJWtFURkCJRBiUzTzoKPgWzrtQRSjNPEHN1kSdui0LK+UWNpIWT7+ROImtgAajOGqzNNYJ4P3h8w7Ds1x/qdQJkSZo1gPNZcXr/JXHOOxfkrSFFDYMAkGAxagNYBJlu3kYTO6SnbOx2uvnibufkZ9nc7CGFQUY1LK3PcuH6Z6zdv82/+5Ps8eXaQcwBrE5JRh1ajDrKRxci49aBywKkyOrYZUAuyAw8FUhia9RpqdpmN9SssLNSZacxh0yOXYBDnBnS7qWzGFzIlxYKL6amu5JzfZVmgc96dL/lCqfG7uYqsyh5KZPwtE/wWgRECI1JAoSzMzQTcubPOYJjw8NERiQ5Qoc2e6XiJpMjBJ7J16/lFRcHKF7TN25HlectBtsMhPr5QlPrteUMVYBVWY5+CIgN4QmCFxNgiD4oflorrPev3X8Wu8oUGKE5bz4bEkB9W5QmqpI/6Oyhr7GVkWdaoy7/597k53pY/+7qqEc7Fb+XJnXbf5I4X4JzP5d0fBYIvXydKQKxURHGVF9CuydW+Fmn8S32W5bb6ESxvMSYDCL7vTmNO07TQMLKF5E2Z1jizs/LgMBubPAFYqd/eouPHrzydedso7nNauy0uszhkNKlmTJSzbg//DOlxhjPjTpwqet791bpKD7eFFmKMAytKTmSCtRTCh2wXmIqJkwO03EdbiU5rjIeKldU1njx8zPPHI2bqC5lf3XBw+Jhma4V67Yrbkpnt0LATVrMi62mWSTNjUsJKN44CEKnz8UuXVj+KQhqNOmEUIlXmVsgyg0prs3NSJnZFSQetbWZxcLpCttNEuq2h0iqMTjk8bJJqRa8TE4UdNq8scevWVYJQ8OGHH7CyPsuJ7XN83GZ/b4SUMW986U3WVxe5fuMyQiwALvW30SmJgSQecXzco93tUq+1iFPNafuY3rDN9773XWaXYGNziXa7x7vvfsS1zascHx+zfGuNxeUVkjjM4lAU2njLhAYLtRpcv7HKlWtLDEcDhqM+rWaDmRmFy3sSM7+oaDRc/4YDiOoN1tdXWZgPOWnvsbI2y9xik/6gQ697zPz8LOvrazxXKWGthlQ1opo7AVmnbgZtlkPVJSYrhIYTWoGzNsiUZk1y5coi3f6Ae588Y2ahwbUbt7h+a5nRqMfG2gbLy3X+7M/eZud5ClqgrUYpUDIgUiHra3eYbbSohyH1KERJTZaf32X/9XQqFBLN4mKT+aVl3v/hHvee/IxeP2W2WWN5qcXa+hoWQ6ff5c/+4vscHB05G4xIaYQpYRBTaywiwwY6y48DNsPxLkssmdVECYEU1ilHSqACw/xcjfW1JYTUBIHg2tWb9AeWwSjJ5PCku73MXPyCLv/xa7rY0Ud+m+ef5TXvlT1vsfRmW4mLD0sxztwDNts5hEaphJs3NpmdXeBHP3yf/shgUG6HEsKtyewZaZoShmGW3LB85hlFeybNFCWekssPkUvEkgwEr6xOK06OTciJisx0PHjSvVQeScH0uqeVLzRAAa9pAh67WVuaNEM1D0ohgKrMujpg57l7LJSyFvrfz15X+rX02yTgmdTgq3U6QWaKvgibE1kBWKoLpdyOQrhrMgCdv6bRx3RAVt1tYzMrzXn3CzxoLOJQ/IKouDryCrLsl+VnVUBTOQdBod5XxjMbx/xQOj/H2RMqoIEqGD3jCy4xHCkL8MSUxTatTAK3ym++dbkLLNvhlT1D2ALsFmc0WaTQ9HqHPH7+IePkGBOnvP7SdQJZZzQwmCTiZDCgJ2LqtYhaKDk6OmRt/ZRWc7Nwq+EtfKaC9myWQzPX87IptsIdZKaNJkmGJEkMGFqtBo1mPfdjl60l011s1UFwgaxOcwVRnHOknRspSWE0NPS7B6R6zOHRKYf7B9TqIf2OptM5INWafi/BGFhYXGRj4xJJOqBW1zSbDZRoIowFq0ktWAasrW2wu3PIt7/1Wzx68ind/inf/bf/He12j7A1jxCz7O+dMOprBCH9Xsz3//LHCCHYunGNL79xm+HQMB7HjMdjdJqQao2SY67fWkQFI/Z2D3j0aJu7t24QRQHGJiCkE9pLdRqNgOFAE49G1OuSjcuLrF4K6A/biCAhCgMadUmjDkcHB1ihmFtcQagmUb1OreYAl9fUbX74XJU+vRAOA83GWhMpLZ8+PKDdk4zSDnHyETfubHF0uM+PfvynXN64zu/83hs8e3rCo0d77O8foFMIVYAkIpSzKNVCSu3mCgcKrDXZmTJOgCoLkbJcurREu9fhpNMnqNW5emWNuZkm0lpOjk54ftCm0xuhs3juKLSsrzbYurrKbGsOFcygRbY7KePfNgNjZaXGkZjEWIu0KYk+5ejwEWG2hfjypXVefPFLPPq0T2JKq3DC7VItZSVjcjeMyHmNteV6JpVgvw5cOywZf0O7lwgw2Ox8sgAhBmysNbh8eYVHj/bYO+yjCdEWQkuW4r+wiXjg4yyjcPbQHOs1trzNk23NFWh7nuwiv64MvKpjY7Oz6MqPLoOTvMXFSE8DhJ9RvtAAJWeM3lzlwUgO1bzZ3vsSSxhuAvV5UADnaL+5cD5rVTi3TRPfIarPrVgMiovxE2uxWaInk+efKNfnLQjl+jxJGKB86Fsu87LcJ2fbfH6U9pnmle6bFgBbjrFwfSyBn+xVAIRybEx2BPyElSIfO7/wsh4VY+D6mnuezoyzH9Pq92djLiYE7Jm+f/bYlK+r/HVPzjUVP0lSeJdgBhBsNmeA8JsfhaHXO+Dxo8fAiH5T8PXXmwSBot1u02g0aXf6DEZDjI64eucud+68QmvmEmkc5AGUMndx+VdhIaM0FtqkpGlKnCQMh0OGwx7DQY/xaIS1mnpjnnq9nrvfPqucGQchM9At8znzRi8pnal5a+sWX/rSN/jjf/P/ptms8/DRPR482CGOA0axZu9wn0azycL8Ksn4hMODHqenfcLQsLv/CKNHhCqiWQ9ZnJ+hMTNHvWGRMmVxaY7f+Wt/g4ePH/D9H/4Bdi5kOJR0TnuMBovUowWuX3mZ2dYs8/PzHBwc0+mcEtUi3vzmV6nXl0liU4qnSdBpn5PuI/YOH3FwcIxOLcenp1zavEyrVSdQilRrrl9f5+tft3zvzz5gPLLsPd8Fety5u0GiJVEtQBjL5uVNJCEP7n+CMZL5hUWarTlUWKfRSkisA3XOXWEycOfoSRu3ZVZlW19bM5K1tSb7B8ccHscIsYC1fZQMGY0TLl+5wcxHD3j/o7fZurrFV77+Cv/Rf/y7nJwMePedexzs9YgihZQhUimsSDKrYhEL4mk4AKQdMz8fsrTY4uNPnnLlyioz84sMxwMOTo/Z320z6I1IdIjNUu+3mooX7mxy48YVkgQGQ8tcPSB36WaH3hWJ8KDYrZYdBCsscdLhweMfsHV1ha2tb3F60nF3p4peb4xPN3FmDZ+h2YwTlNIvVBW2Ik2CX8uejeT8oKwUlwSywPMUp5jZFEIhaTUFN7aW6XV6jtaz8SHbUlw46N0zAuXch4UCeFaOCG/m4ewOo0m2VYktPCdAJNcJszVbyNSJvmeXFK6eKeDpr1D+fwKgQCHwcpePLR3jVSIyP8l4YSEKzR88yhMFbWXPyk1itjCPlVrymW3Mk1xVBJsnZpFbO6omwmq/Jt0H+eISVeLIXRyZ5SEHXSVyKTd+msD17+W070vtLmEFvDnHZicVGx8DMmFBEaU2nh0riVRZJtlSG4tdKKXnl0c+wx8CsgyTcqKPxcv3Y+qiFaW+TwFLk4DkvKDSyb8+q255LsjmxuuGpVqrljGhGYw6Wep1Q9wYobVmZqbB02fbBLUaUkiiMGBhYZZXXn2ZjbU7HBzobOutcwU6hlW4Bx0xZ1tks5ilOI0ZDocMBj0GgwHj8Zg4HqHTBGs1KgOyLpGezDC75QyDnhiPYm2JDCCLXDsWAoRU+bbTufklfvd3/0OEMfT6x9Tryxwe/IC9nS5Xti5xcNRB2Aat1hyH9Dk86PMv/+UfcfXaPDNzV/jSa6+SJEO6J/scP3yMJaLX73B8ssvySpO19QUuX/414uQYqVL6vZif/fxteu2E3/mPfpej/R5/8K//OV//xjf52ld/jZ///APiJKXebHL50iWsCTFGY0wMxjIedRjc33HjImFjY43FhTk63SHj8RxYaDRbiADu3Nqkf5ry6OEBFri0ukk8SolUE6lrWBMwM7fB/Nwa75pDTo93OT48RNyCWqvOnKlRb9WwooFFYUzqtvWnbmux1gmpNiSpQScJC7M1sJbjkxTkDNZKTCJQ1ImHkrhuuLx5ldP2KalJ6fZOkeGIN758l62tTXZ3Dzg9TBiOEywhSkmMTZBhQtRMkd0Ey4igNma5KQhCy9Jsk16vy2joto8/f7rLcadLd2RIjXPrKWEJVcrK8gxvvPYijVaNDz/6lEZjnZu3LoHVKC+QyZSPChLQzgLu40cY8/DJhxwdb/OVr95hfe0Kr762RJyOqEUtknincr6YlOW8WGdptggTOEPNUKrHg+uqJdatYS/I3XX+98ABO+Fi5YQUhCrl6uYitSDgZz9/RL9vgBCTHfngYBXO8kmJb9lCtvimFVbQTD5Z/0OWK8r6hBy+jiyZ4pRyRkkXpb6dUeT8PTr/zTfStSWLm8Kz6ul5WqaVLzRAgcyVkTN/1/0KcVUEeIH6yoDE+fjcZ5mBk+xqvFrur3NfuUOpKsDnHNP+ZFuLxeGecGb3CaV1CC7AcCLnR/5cWRBkpVTATlaXkOAzTk7EnziA5LZPVgSyrC5ma12gZ3khOC3CCzwnsLwFJdfYs0WtkO4w8xL48sBC+rYIUUrSVrUAgU/KVAVe/l6bjZ8o9csZJlz7psWIFPMsEUJXUtp7YnFbxavz/VkWlOpUWIoRY8o8nnOjZ37G0O12SY1mFCegBe32MWtrK9y//4i07w7Ga0QBrZmIweiEdqeD1ctIGZDqkWNOkpxR+GBZIyRGa0wyZjAa0Ot16fU6DAY9kjTBxxG5YTSQJVTL42otTlAIjXex+X5N/0s2D1m/vYvCuJkUQiBVwNLSJf723/7fEUaSex+/x/z8Jp1ODysHHBwe0ekMCZXFmIBxPOLwcEivO+Lg6J/wwovfZ35uhppSfP2Nb3P79ovc+/h9lpcW2Nl5zPd/8K/42//h/56vf/nbpHqAsZZ2+5Qf/ehH/MF//4fMzbQwJmamtcy33vybfOXLv8dp+4S52TmiWsNZJ40AG2RCL6F9eko8HrK0PM+L61eoh3NYm3K4e0C3c8S1rcs06i5Y/aW7t2jUaqhAcfvOq3T7fTqdXZYXlnjxxW8yO7/Bwvwyzx8P+d6f//fsPN0l/eoILRKGyZDlxWUazTVSLTE2dXF32m0MsNagtSHVKWkcoGhjTIuF5SbDtMN4tMtwmPBsu8+mbNEd7FBvznH9xovUa4Lbd+4yOzcLSrCw3EKoAQsLlkePTjHjBG0EBsMoPqYz2ObR9j7JSNBoWV569RIRt3j28Dn3P3nM7kFCt58QDzUJLj09NiYQmmYIt25f4RvfeIWd3R3+8vtvk2jF1vUlhIgzt4HEkji6QILVmOwARBcs6rL8SpHS7ezw/vs/RdZi2r0xG5uC9uCEQNaJwhZo4YCBLKczKJKMTfJxZz0pL0yBTwSar+vMeuRj8qprvroOvNxxYEBlZ0+BFAmrqzXW1pbY3j7g5FRjCR12lybLtyayfRM+riVXu3M+L0q8N+dLXh6WQIjbTu3740e2ys8n1201NsX/VlXQRUUJzZHRxLhMWlI+X/lCA5SCwbvJmzQfnT3GnlzoeIBQrmvyfREMVNzzixLW+FIAJia+K7f9rEXAI/R8dwweIxXZcX1dToBkMQU+M6woW4lKKDfzFTrzW1VwVCPAy+NXtR4YYyfa6zVhf0h5EWNRxI5ki1NkWS1LmRe9BcG3RWYnUle0m2wchHDJ4vzuE2tcHhwofp9K/jb/b+ocF25mn1ehdL6TcOn3yycNnx2j882iec2iAE353Ga0KIR3B/q5EL7bGb1K1lYvMze7SL+3xyhNefToKZc2NgiCCJOAUpZmK2BtfYF6Q5CkIxACbVOktGCzfDICkO4MGWM0o1HMeDyiN+jR7XYYjgak6RhjUoSwyGybqcORBiMgCBVSue9MlnWz3PvJMapYArN+ZtSHN3kLFMZmOT2soNWao9logdWsrmzyv/xf/G+YmZnlu//j/5OPP75P+3RAvz8oQL4JCVST58867O6+hZCaulK89867/Gf/2f+VS5dW+cbXvsFH9yIOD5/w8OHPUXKG2ZkFgiDi6uWb/MS+zfbTbdL1Zf7ab/0e3/rmd2i15mk0BfMLi9kYSLDGCSa/kUZKRqMRo9GIjUvrfOm1r3Dn5tdp1pfo93ocH+3w7rs/ZDh4QiANoYK7d2+xvLLGCy98GRXUaZ884eTwkC+9+hXqMxtYo/jOd/46H3/4NjXVBGMZ9Ht0u11u35gjiuaw1BxAsU6QeRI0WmP0iM7pKcLOEdauImqQ6h1Oj44ZETAaJJyejFjaqHN8dMxoOKbXPWUcX6bZvAUohIR6s8nu7kPiWKDsHMYoMIrRCJ5tb/P+Bx+QxnB5c461tQE3N29x6coaH3xywEl/TBwXwlSaMVGQsL40z9feeInVSy0ebd8jMbB1+xIqgGYjJqqdEGsLBqIwRMom1jQxVqHQaGsJZOg2BMox/eEhT57+nE77hNPRiH/6f/sXvPzKNf7X/6v/OavLl9jbOWLQHRZCONtG7Xm5p80yw/AKW0bB+dos6Lu0AWPiPC8QLlgdlSlf2VEOuLgdHwio0LRasLbR4uCwzaPHbRIdOcBP4iwdLk9EFsA+jcf4LMKcaYN7ciZDKlb0iY0g57Cu6cqXrfD1fDwgO8hQli+lACuTz/ns5Jfl8gUHKLkMy0o2gC4lYMb8sq1lQuKSAFURbj5h9mzd/priu+ma8y/Spgu30HQXT1n7zKz//sbcggKetcvcgpDHM5xDZXmTsnXk877mAl0UYKEsQH2fpPC5QFyKd0MZTRdacL4UsnYVMSiTW7vPLvZ8/KRfVJkVS4gyeVeuL6y9Hnh4ge4yQ/qOF1ak8+fGz0UZeEpZ5Eg4D4BOvp8Wi1O+LjPQVpLYIYpxFKUMlmUtRIqQjbUt7tx5mcOjE4adhHsfPeLq1SssLMxydNRhZq7Blc05Ll9aZW9vj+XFDWqRdVvvjUFkOz2ksFhc0rQkHTEaDuh0OrS7bcajIQhLEChUZpmTGUryhzjOzLZYWlykXq8jpcoYaBV0TxubfExy06Rbl96Ib0z2XWbK1zqjHWsZJTFLCws0my7Yc35uljDYRwhNsxGCaaAQ1MKIqF7jtNPFJoJECU6PTzg62mZp2dLtDtBpwNLyGqO4z/LyHLWaRKk6ly9fpTUzx9HBHuurK7xw5yVWV9ZxwaYBOjsEEWtRKkIbjRAaS4K1Cc2ZBmFfkegxhpiZuVkitUCztcLq+iZXr77A3t499vc/5vn2Y1ZWNmnNLPPH3/1jDo8PIO5w+8Y1Hnz6Uy5vvUartcLdF1/k5ZffQJsDkjghqsPp8RFGDwkDQapBKumUBuV3uwgIDfGgQzweM7+0SlhbIrYjoijIdtw4fpiMLbOtRZJ4TE3BcDzm+bMnvHDzyygkg2Gf8Sjm8ZOnKDYJAjc/xkAUzvDC3Vf44P0HtE97zM3PUa/NEY9GDMcBCWAkmbXUIoWlWYeX7m7x1ddfo90+4O13f8SXv/517rz0Mrt7z7j34Xs8ffyU4eCUIKwRhhHXrl1jbvYKybhGmgaYbKusMRoZaBLdY2f/AVHDbXHWqeD4eMizZ08ZjXqsrKyyv32QJ2HzSmqV13nXvdtCXF7Gk0qmv75Yu5kM4qx7POfxNlv9wmAzd6sSligwXL60gDGWp8/ajNMI488Sy/XijI8Jt42XTBl3bSv4e9W6UVg7rC211183cWSLH4/J9TppbTYlxdav5vNKWa4UKn6hmHzWvZPlCw1QMoiam5iqsRpe8BSnVoKoEFnOPMt0Jz7D7F4qZYFVdkWUP5ddEWXCrbhRfJvKxFRaFy63hC0E8LlC8/zFVOq9G6sJH6tv65m2CTd+Mg8MmzjHwUyAO+H667KGao/fz4xb8VciSt5mIThrQSmNqcy25Pp6y3OdVee2vFafmN8/ba78d5NxPtU2yzNjX7p76j2+j5NCe/JZhU3Kg7mydmHBKqRoUm+0kIHbVfPk8R7dzoAb169yePAOjfoMm1cWqEWKmeYqUW0eo929gjAbA5/ZNWYcx/SHHbrdNt1ul9FoiLWWMAiwxh2bFihFFIaosEYUhdTqitm5GWbn5qhFtQzEibwP5TVUpvlJV5qt0KmLY3GKg8ZmgZeWLK+NsCR6yDhV1ExAnPZ4+ZW7nJz2XdbaSJAmhoAQIWNW1he498kDdp7vMje7zO2bNzAJfO/P/i3Ptp/w7NlzpGqxde0FDGMG4yG1CBqtGrPzizx88Ij9/X267b6LDal5nhGCjLPkiylSOYEhLBg0Bnjy9DlHJ4ccnfZZW3mBW9cXSTPXe2N2gUvqRbafP2Z1/Roba9dpNpc4af8b3v/obZaadW5vbfDn3/tvSf7sj/nyV3+Tr7zxm/zab36Ht976IwaDAVHUYnfnCZ3OPjMzl5zCILK08dZt8XUKi6Hb3qEWKaLWkkvIKNJsbWVAxlp6vTHJOGFpfgHBLFIssrP3hKODHa5u1TnYf8bxcZtxTzEzU8Odop1tQRaCer2GJuHrb34FrWOebe8xv1XjYK9Lv6NRRhAJjQhj1taW+da3vszK8ixvv/02u0fP+LXf+CoLSy1aTcHcTEirWWd+fpGlpRXiZEAcD5idCXnx7jWOj1KePuthdYgxCYYhwiYcHu1yfHKCFZqoWWd9toUVmktrc3xy7z7X199gMIjR1gGmgi7L6zPnEPlvky6aYt1P3lO9rixzCo5LDsUtZPmiEtZWG1xaX+STB3t0+oIxWZI8BBKF0eVTwRVkLi23viqscWqZzsrExPspsrDUpwpIKV0ncsWqJG8odJUKX5763P8/AShV40FVmJUH3oMAZzE5r6Jq8ZNQ/e6ssPGf/TNthsgnT+3Nk7lNBl1OYiRRfPKBYVVBP/G3AjSKNufxHTYTT1Jm2Ve9BJ8kTNfuYtdTMW5SFAGzhXnP97f4WPZl5rEp5UmqgL8J4JIt7EApFyhb0nAKrWHSOlKMnQcu5bEqxvsXL8BJ8JF/tm4cvDWpAt6oljNANZuf/FkVkOLPVyp6UPz1LsssVbvV6HRMoNxBa+Ox5NP7T/nKV1/lnXfeQylDq1VD64RWawNBCyEDTArulFgQwqJNyjgZ0uv36PXb9HpdkiQu5sS6rK8SCMKIIAgIArc90qSGQbfDYNAvLBz5nNiqFfCc8cgQrP8xP4W1MsdkcU/CBYE2GiEf3X8HheL59mMGA1hdXWVvfxdsyvJSk0trmwQ1Q2M2ojc+ZW1tnt9487d547U36faOOTj4Hs+f7xOEDRaW1hiOU4bDEe3uMePBU5IYJJJLG1vcuH6Vhfk16vUmUgm0Sd082CzltwSTnRk06HawZgQG4tgSRTM0Gk1OT0+xViOlYjTqYXSfk6M9VFDnzp3XGQ1S4jRBBBBGildee5XWbJNWLDjsnpLqPtpqNi5fYfbjJT748B7x+D0OD5+zv/+QTjdGBi20iZmdm2NxcZ0oapKmQ9LxiF7/kJXVK0hZz4Y7we9yc+4LwXCU0Ov22dxcRGCZm19hdnaRo5N9ltYWePr0IffuPWSmfhPTlCANWiRoETNMO9y7/xG9fp8gCghsgIpjhA3YfXZA3DUEBmZaES9/6QVe+dJLHB+3+YM//HP2jg741ndeZuXyIrs7n9JoWXQaImTErTt3ee3VrxIGMB63mZ9f5NrWdRaXUw4PP6LfT+n1D9g7fEgc9zk6OOLo+ISFxVk2r1ymO2gTxwOElehxwONHexzsGZdAzGdr8GC6cs5OET9RVVK8EPdLt0ynZaBdNrsUiqmzTFu8C9y5Bw2zLbi0PsfpSZe9gwGJUdgsHYTAZjxHUTklHn9gaKFuVkv5+6pi6PnPNJnmXejlayffCyEQpmxtL/hfRY5NVJ2NbKlFxT2ft3yxAYonPDy9iczF5xi8ysyyZZHhLQV+sN02OZf51Vc0bQAnLSSVAE4vhMhiQvDC3BAIiSlZb/JzTcrbtDyKsH4aC2997ioR7qwGF+2Y5XfJzqDwlg5RIgYo0hqVepF/IzKhBd7YngkM6UzHQrqtZIGUpNmOFg1ZrECRCwGb7YXPx4Y8W2qeeEWIUmvKiYUM+Oy4ZRCXWW2wJmOspgTmnLndWO0yk9pii660bu6tyCLl84U6PYhZCJHdlGkrJbOnlAIlJUoKlAAlXGIohUAYm/uVyzQxQTG4eJKStcSWY3T8jhrP/Pw2SoE7WdbiArENUg7ADN0BaaEliS0PHzzj229+jcsby4RNdzqssIIgCFz8v/XZYt2kaDMm0SMGwyHdngcaaR6UjHHxPYEQKAnGJMSJJk1HSOHOSgmjgOGwhzGJo1Dh87lQwR7lMrlOCvBdIgO0o0FTOCGtEQgbMNta5Aff/x5SWuLekHfe/Yi5xQ3mFuZoNCTJqM9Hn77P5aurqJHg408/5W/89b/Or//WX2dz/Q5/9Ef/Lw6ODlAovvK1N7lx846L6egNmW0u0Dt5TF02+T//H/8PIJqsLK9z3DnCuHODMaSkOkVQyyx4kl7vgO1n95hrLHF0ss846TIc9ej1Rnzy0X3+5m/PIpCk4x4/+ss/4Gj/E+ZmWtx99TssLl9nL93meG+bUdrn9Zfvcm3rMv32Ka2gxeLta2xevslMa4VQJlzeeIF7H7/HvU8/YnUpon38lO/9/M/YPT6m1Qz5vd/5PZq1L9HvhZwcPEUYTRTNUWssI6hhzKhIgiizZHzCgZQk1nS7HRI9QjPHtSu32Tt8xB9/90/4yY/eo9Md8eorK2zOhqTpkKPOU/oHz7n/8fs8euhypezsHLKytMTG7CLjWNA5HRMKwfrVeb72ja+wemmZH//kh7z99j0GA1haneHatTU+eP8dWs0Ww5GgFrW4cvUOK6urhPWQ2VaLrcUtZmabiKhBMBgjZYjQCfv7Dzg4fsCrL79Kv3NKp3vI2kaLb3ztyzx58pB275irm1vcvPllDg4SRsMAYSTSCDAZP7LeQuv4qtf8CwWsrARazu5OAR8rltfj14G1uH3fjl9robOMtwJFShgkbK4tUA9DPn24wzAF7fmOcTzVgRWbxRNapDQIMl7nActEjqrqX99Gk1uEzipUwjVRTgcL06yg1t/HxI5U6eNkytUXqTbykfv8hpO8fMEBShGf4QW6MzpkLgxZMEdRue/sSJVdLv7zpAY43bVyXj2l97J6XyWleqV+CqZdBuU5scgKBPlFODTHP1OsEeUr8hon+ld2a5T7V/5bJV73zp2LpCs7eRBFyyfrcG3IxkZVt/eSWVZsdUByi1XFOiJEluCybOUoxnyyD9MWoa+vegbP9DEg2xlVuPTKY5sByBI9Tbp5BFDNol/S7koGMguEtRARCpbXFhFxDR3H7O084cU7W7SHJwRhiLGSZ/uf0Goa5ps3MNny1lZj7IhxPGAw7DMa9dA6yZirQFibHdQGWEMSJyRYd/CfdMAsCCAKFYFUKJmlC/fz6VffxBiU53mai23SYuX769CmRhjJTGuZ69e+xPPnnyLCmPmZGdJ0wK1bd9nf2+fJ430S3Wdj8zI//dGHnBwmvPfe+/z2bzxnNOjw53/xb+m0Y37j13+d23fvEgYhaTxkNB6gQsHq8jq9kyNMfMiNW6+DVBx1ehg7ZH9/lw8++glHh7sszK1x5/aLbKxf52DnIfHwlJWrd5FhxMOnHxMGMwx7XRpLLVqtBQyS/rDN/Xs/w47azN9+mZWVTRAN6vUWve4xa0uLtGqKk5Mu9z/6hK31JS7fWmNleRUrDLV6xO07L/PWO9/Hmk8YjUeMel0GJ20Onx9xIGMe3/iYrc1rSLXIQmOD7afvsnXrCjJoAm49gQIhXXp066xFGEG70+W016HRlCwszhCEARbDW2/9jPv3t0mNJdF/QSpOODo+5rh9yjgec7rXZTgyXNpY4fb126T9McvzLQhCWgs1tu5s8vobL3NyMuBf/rd/zNPtx1gB65cWuHZzgU77iIW5Ta5dvY0Qkr39PT59cJ/Lm+usr6+wvLjK8vIbTuglgqODI+J4AEJzef0qUhxz7coqCwsLbO89Y/vZNru7T7h16wZaX+fSxjUGvRppYjOFTiBEgMhO5nYWOpm7jMvC2wv0yTJpWfHWVHd8Q844suM8ikXtlC2FsZZQSi6tz3D5yipPnxxzcpoiCLEUp3x73uE5vMgsN1VLd2YJzxVfKBQ+StcV95ztUxGGUOGh5V6W16Yt1mv5+3L6DCbqmMoT8bukPl/5QgMUbIlwSmbzYkyqbpVJyZ8DknMk/eSkTdPCK3XlgMTtOffJpwqLyfmvc7s4GR9hyczNWfBvtRUeaWRtclaSKrKeBClUCKsMooTMFpzK/nqCE04TcTlIXWyKD4gqzuKZDJIq6SUVS0LWPg8MsvGT5yB71wOb5aIoBQ8LwJaBVeaqmkhu9wtLJVj2bMK4Sh0lWpsUwGULQVn4VubTNzt3gRVznNuYtOake0qvP6bZXKLVnEMaS9zpM+p3uX5zjSXT4rB3xMHJCYiA1swqQqYIE2JFijVDB05GQ4bDfpYBVWCsAYsDHLjYoTSOSZMYKQUmCJBCoHWMlDAex6RxmmXALOhl2hbjyc/TAP+ZoS/95uxZhlqtyd/8G/8Jnc4Of/qv/xuGA3j/o49QwrJ5+RLdTpv67Aqn7TaHh6dobXm+vcuzZ/cYj1M+ffgR9VqTqBES1WpICyJQhJEgToY8uv8pp7vbzLeaHOxus3H1Fu3BISoY8tH9j7j/6Qc8e/KEra2rtE8esHX9BdZXN9l+fsjbP/9Tbt56CakMgVJ86xu/zQsvvMrC4ioWiEcjmhEEQY1r116i1ljEIqjXmywvrrA0t8De3i4np1129w+ZqSluxy79uZISayKWV65wfetl7n/yAUK2eb5zxMLcHL2PnmADy4NHT/j2t2JmGyGHJ7u0ZuoEtSZWBBSCKcBtFHCHHAorUEIRJ4ad/W3uvniNIKwhpZvvtdUlDve7nHb7nHSO+PDe+8Q6Jk4MndMR454mDBVXr9ygIWdQNQnE9MYdvv1bbzA3e5n33v2IH/zgfdrtActrK9x9+QpXrq0zMxvQ7/cZDVO63QGNRoCxY9Y3lmi3j9nbe4bRCZaYOy+8jhItjo+OSdIEhCUZHTPbXECpOnHS5srlZa5evc7R/jZf/vLrzLRW6HUEg57G2gCLzvmeF8SFxdkrfOBkxdk4tKl8o5D7RbHlc3o8SFFgVX7K9uxswJXLi3R6Q57udjDUEC45b+ZKzKouoaQ8vX5JTlUt+GUrbMWEQc5dpgCuqmIwXWH3f/2zpChSOVS7X1bKp8iXf4/yxQYoeSkJQ1FMTZUgM5McE4wy+84Xb/k4r3yW9je9ZR4tllw6eMIr2n7+/VRPB/bPpoxai0XmbprcDlyqTZQBT0a8Ey6Iytj4XCgqS4A2AQCr9v3MyWUMRmtsntK9lEzoDKquFiHcrpFy7pXMVpLlqhElK5kztfo+u2q99pKnJ8v7NmnFqIxnRSsoXHDTwMpkHFHVjeGeLfLZKz/b9STfhp0drOeFR14HItu250Butzvg5+9+zNzCHNtPDxkP28xFdU7bHfq9BgPdpT/sgVLUazWiSKICiRKKxI6JM4uBT77mz5uTHkBhSeKYeDwmTRKMdkGVMUBmDVNSkGdNkLKYU3DfT+dzZ+b2vO/L45j79wUgFIuLq7RadTY2Nrl27TUWl65ydLrNS6/c4PLmBrtHz/jv/rs/ZjxOCUNLGmsODp/zta9+k+9859e4f/8evcEpg8GQVr1BalI6Jx2CyDK7GFKXyxw92+ZwxxJFBmoxB3tH9Lu7PH/6hOfbe2xcWqIz2OPHP33C7TuvcXra492f/5TVt68gUfzOb/0tvvmNv0VjdgEkGD2ie/qcwAxotepc2rwOMsTalKgWMD+3gjQRuztHHJ6e0mrNoGqK/d3HzD19n3prmVq4QRA1+Mabv8ajRx+wt/8xh8ddXnv5VZYe7HPS6fJ895i33n2bN74Ee0f32dy8Tb3VwBIDAfmhbha8W1gJAVZydNil30/RBpeETWuwioWFRbauGxrHJ+wfHHB81MFIQX8QM+xZokBSb0harQbxsM9aU6JtwvP953THir/8/sd8en+Pft9lt0VqltearK636PWHPPj0MY1Gk0ePH9JsRly7foUb129hreT7f/kDPrp3j3j0Rzx7esCLL72GkAFSWPr9Q+J+j0tXXwAxx+VLEbf+9jU+uv8xH310QvukzeX1u+xvn4INMno0DoiL0nrOaa4c/F6l38ldLL7IM5w1U4z9v/xaB9yllIRKoBoBN66tUosU9z55Rn/klDnvBhdMxEeKKR9slVd91poq2l5WrKetu+rDJuvP7/Xt8/0rXeOTWjrZmjW01HaRs2hv9fn8AOYLDVCqUcbFd9b/NYUwdhNFRaMt7vUBqVQR4i8wR09pUW66zwWxKAjBL5CqRadcRBk8uxqzLbv59tSygPeILA+cKlwKZ3eleJdDoUmccc9UiNnVU07UVhXwRc3GeySyxlcBSqmXGfFOsx55wOXaNuH6IgMiYlKL8P2naHPlsKHMhDllpqaVvD1lQCsmMk/6rpSsQxO1wNRFaLBWFIDVz0+h/pRq8GZpl858cWGVUNRpH/UIZJOwFXLn5g1efPlFJB1IhjSjOa7euMr+7j6BrNNoRKSxoN8bMhoNGQ5HpEmK0Rqt3aBIYdBZWvskjtFJjNEagRNYoQpQQUhd1QiCgNnZeZrNFmEQFoA168sZBW5iXM+znkwy2zwIj4KZZZszqTVb3L79Kl/++l/jp+/+Jb3BHpBw79MPODnpubgVYUiShI8/vs/LL77M7GyNsAY/e+8dGrU5Xrj5Av1+j2HaIx4OaB9vsz63hJGCNNV0To5QTc3B6SHPdk842D+k0xnw4Uefcu3GOitrK5x0Tjg4Oqbf7xMPH/LGq99gYXadZmsZqwKwKZ/e/yl/+gf/d1ZnLLX6cpZyzJnnpZU0GvPMz63QaXcZD0esLK+xurFOMu5zfPiUeNyhFixisCwtL/Cd3/pt/vJ7CbVwzKXNTX7zN36bH/z4h2jd58nTJ8y2BMvzi/THIwbb95mdG7Iwf9Vp8KIQEkiwSmCMZDgEkza5/+Fj1peXMWP45NOPOdxrEwY1amHI5uUNRqOE53tHdNsaTIC0uFT/ZkxrbhYpYsL6Aml6yrNnAx482Gc4cqdcGwS7+0fc/+RTooam2ZxhPB4xOzeHNpb33vuI/mBMLWqwtrrOwsIKOon45P4Onc6IwVAz27hMMhxwsv+ElZUthFpkPJbcunSZeNDmJz/+Mc+3D3j6+IDF2VOSWGCNytaczZJv2jLRnaHDv5LOX3Z35NbqLCA2569uQRiTIsWYhTnB4kKdj+/vcXyiMQRokiwwVrkjKSjiNqY1M5drU0IPKtfZQg5Ur6laN/x1ZaVt2hp1Y0gWvyTydpQumDKAnj9XrcxeKf+85YsNUPJ3hWDEWwRKcqpsEcjvLU9GBbgUkzsJTj7LNVOZ7EmhU7GceOReenaleJBSgKuKK+Qzy3QkXCbY4nub3yGEO/p7co9TARq8sCzqLuotvnNxP+6v0Sk+oLVscKEcXFYeuxIYUFm6+qpmXbRrAp9n1xS/CFFazJxnTaq2uwqWqr+XLSdnk7a5sSnSY08RuKJkTLbkgHOyHdX7ih426rOsr1zh4cNPmJmd4+Uv3eXO7TvM1WYRaZc4MexuP+Lk5BELS0tsbGwQBgGnpzFJEpMkGq3J3G4aox0zTU3CeDRiNB6jdbZ7R0oa9TqtZiPLPSLQOsUiiKI6UVR357JMaft5lrFp8SeTfa58FjbP7IwVzo0oBSpSGBHQnFvlzW/+Nt/7/r/i6dP3QaY0mu7eQClUYHn08Ck/+OFfkiRut0q30+O9d37M1UvraBKM0IzjMeNUM0hGnAwGNJvLLK9t8vT5M54+7RAbWN9YxyLRGg72u1y9epdRHz799AlHJx0ur27Q7XbY231Cmo4JVAsQhEIy6J4g5xZZWLlK2JjBWuOOuxOKMGqxsrbASy9d5+2f/ZywFlFrtlx8pRb02ieEwSyDUY/RsEuzGfLrv/Ydeu0d6kGNr77xNcbjEaPhCUoNSMYJrcYSidD0B9uMRmOW5jbx6dXJRJ/fRICSCKuwcUS/PeLH338HSAlUwDg1XL5yheFohEYz0xJAyPHBQ4SwGC0Z9DUf3fuQyF5m/to1nu12eb5t6XT7JIk7KNGSYlHotMHTJx0095BKc/B8xOnpmPF4zHgk+fjeY46OD/jyG6/QmmnRaNZJ05RWcxmbzDEYa/aePGZ+rkV9Zg0jXa6eZr3Oe2//JUopZmdnidQS7ZPUJZRzxJPxgkJL8a6KSYXjjKo4RRktKy3Va/3T/No1GWBJUUIThAmrq3U67THbu11SE2ZWFzAqBV2qM7OqZnaeirI86auZFu9VseBkbVNKln77bF7orzvDj7L3UpxV2LxVSuHGVpf4eblNv1jBP1u+0AClGIAiFbzxgsK66S1yalT12rKAKW85y10nU57zWW0QXipmZdJ64QnbL5Di6O7pzD13EpRAiieE0kVuIcgCbHAOkbkvS9slc2FQGZWzAiQ7ZEtWrBpeUygQeZn2XZsz0yoeBLnTO62sWnasnYzVceCkemr0ZOZBD9o0Fu3mL3Mx+cBUUTr9eVqZXIzlRXTGunMGmMrKXBSupbMMpAJkpx0lnddJfr9nch641aIWL7/4BltXbjI7v8zc0iJhFBGngmYUsLZ6jW5vzINn2+w+/5SZ1gJb1xtokyCUwFqFSQUmMaA16JQkSRmPR8RxjLGWKAyp12vUazVazSazMy3qdSco+v0+cZwAWdI+qfL2ion4k2kg5byg9GmfHc3JzG3kQZxBSA3CWTmEkARRxOzcLG/99IcEkeB3fvebdDtj+v2YzukR8Sjh7Z9+wNxCg/F4SCAlT54+5r0PfsLO4S4pmpXlRZZXFlD1FrW5OVauXCGaW+Qrl7/MQfd/4Ps/+R/p9bsoJWjIJlfWr9OKFnjrrbc4PeqwuLRCd9Tjg3s/o9vp863Od1hcqmGNpaYC5lpzrG1s8eJr36bWmHM0bXAWIaFRUczW9SUOT1YJaookHaOEYX/vKZ88/qdsbl1FKMGVzRv0egPax2NevfsiJ/vPWV29yte/9k2ePvwpnfZzFheXGDJEySZhGKCUyiw2zqrkgm8KwG+BQAikEaQxdE5iGs2Q416P3f0DwlqDWq3OYBhz9domK0sJD+4/I05SrLWkMbSPeuzu7/P66y/Q3ztGk5Imaa6fCWmwRmJ1xOH+EGM084sN9vcMu7qNVJqwpohHKTvPesSj93njjZdZXV0kiQUvv/h1bFxj58kDakGducXbpCokkJaVhTniccwwsUDE3dtvsLx8Da0DfF4dd9iet4qW1nyJ5n6RsDzj6ilba7OirUDbTIgLA1aD1ShhCJVmeXmGel3wzjvPGYxlFrvnreECH9xaCR6deJbvw+ct07PkTl7z+SusGO2n1FOMbeGm/axnf97yhQYoXoh91jiIqhSZWodAYCaTkOX3nyXi8+IXmHbdBPJ1hFYScqVXJfOqIPf7VeNCPKByZ6OUfajCJyOypgK6XA4UU3nWZF+8wK1YC4TMc6AoIfLDF7Pm5dE1tvS/d12YiQUmpURn0epCcAYQlHOM+JT3UxdQVqcxGozfRi6Qgmw79+dD6ueNQdG74rppgOUX11syq+efc9NO4bKb6oMSWZp5i996vLZ+HdYsQkiMdPVYqYiTMTONRS5dvsrc0mWe7ezwySePWFxaxdKiFtVQaoROY9IkcRpaGhOP3OdAKcIool6vE4aKWlQjjEKEclktdabRqSAkqjUyC0pAbg7KrWLT3TjTtLzPmoviRoXPbJNTmBYYM0abHuO4zZNHDzg9GjJKxiyvalSgODw4pHPaZ9AbUa8pZuZavPLaC+zvHvHRe222d58x1gnD0RhpLBtrq4zGKTsHh9y94xJ6LW+s8hvf+Q94fnDAe+//mEjWadaXqUd1drafcHJ0wKsv3eXRzjYnJ0OaQcjB/i5vv/PnvHB3yMnhMR+/932ajTpLqzdpzGyCVFhjgQDDkN5wF61jmo2IxcUZTntjRuMxzSiifXjE4ekBMhoxGo2pBZbt3QPax5rXX3mRxI4wqocKxuw8e8TNm1cIaxFDPaBVn2XQheXFWaQKnVsxIzOJP75BoqRFCk2zpogWFhinffYPOmxv79Mf9bl02KE1V+Pk9ARthqwurrLQanF40nOJ0QJJKGBleYGgGbK0VqfX7zEzM8PjB6c4UvPpHMCmAceHKf1uzHAgMSZTroaWWtRA1WuM+hGnRyFXLn8FE6fYOKF9cIDVMetbd7FhC4OkphSLM8scHO7RnL3K1g3N1ct3UaqFE2kKIWK8NVwgs4MuCwtKJfg0W3Ne8ZKI3O5bdqdX1SR3bdVi4a2rIEmRImWupVhebPJ0e4fTfoKzoXm90NGDs7a4YN6K/cMr2d6STcGj/bo5jzeVlYUqUJgOys77rlyH51fT5J/MFTY/Dl6JLfNXmIpwPqN8oQFKMTnus0e4hXV80kVRCMcClVYFc5kAPuuZ038rvSkj73PbPVmX17ArppjqBJcBTA7QqtYaby0qX1No/tkx7eVyjvUgT3VfOihLljQwKVz8iZNRHk45oGV0scvGd8mjaiGqY1xuY/VAxbLGU8yzn0PH8Mtj/vnAyWTx/c13BYmyS2lybIog3ElkUe1T0XF/mjHCnSdUpLv3YPVsHb49PveGLTEomR1WaYwgRaFNjdbsIvVmg5m5q/zkne/x5NEeV66+jJDaCXU9AmswqSEZu6yo9ahGWItQQZDvdjLWkGrNaDQiVe5wtkajSRjVmZlbIKrVSwcn+lEQuXkbPltrmzb25ZIzQmGx3tqHRRKBEWxvf8TjJx/z/Pkz/vzPv0uvM2AYJ/T6XTavXEKnFkGNRi0gNWNOTgfs7O2xvDjL3bs3GCQpc4uLbG3Ns760zMrKIoPxACEsqU4YDbv8+Kf/htu3f42//jv/Me3OKQcHOxwcHnPz9lV2dnZYXV9m/dI6u8cnmHGX4SiFOcs4HjEYjvjn/80/RY72ePNrX+PytVcQQd2db4REi5R2b48/+/N/xdalS0jRwqSQjA0PHjznhTvXqNdrfPvNNxljeO/dD7n34X2G6Yil+RUOjz5mGB/x+PGPae8dcW1jiYVWi+c7+0RzEfOzN1lducrG2i2XrE8bkCq3dEnc2TCBNLRakiiSdLpdur0hz56e0BsYLAGaiMEwRWvDyUkXPTIsLczQ7XaJmoprV1e5eXmZm7cuo4ImSbrP/JLgzTe/zh+N3+bT+89RMsKkGoQ70FKnkn6SYLJzW7QWSBsyGmoCpVhbvcHayh0WF5bBDDnc/jmnR4fcuPEqJmyhpUJZy2yzhhCK49MxQbTM7ZuLYCOECJyFWABWOcq0Oj+uY3K9Q1VR9CvWKw1VQUy+NblQFpmQMSJTllzeoHpNsTwXomPNzu6AxB+sicuNZbIAWZvxTFviNeB4qv9cTjBhcz53tv2llURhWT6z6qrX5X/PKq8epOQ7eErPOhOfKCUurWN1Ped9sgXv/rzlCw5QyJmklwH+DI9iYvyAVomtKLbKXPF0d5bZTtt2WtQ5QTDZd/YM4WQY8xygI6gGrzr3js237fr+uhVEhb7cbQ5YOA1A5wzf2uJiDxBycFdCyl7gOILLzqXx/ZYSq3VmyhTVMbZ+JJ0ATo3JsumSu6tE0fhKKQf0FtabkgtuYvDcgs6Cc63XsjMtnmJ+HUbw/S7NFaULbOnb7JlWSEwOXkVm8UidO8mvMgEIn5q9qL8a71NenLYyF8XIeP+wyK/PW+TPzRAZuBMWYZ0LzArhLGYaRjHU6g2EUMzMzPLaa99Cp0MCItK4wzgeuwR7WHSaIoAgClEqy5OSJtnOHIVRFoEiCuo0Wk0ajZbbniuVs6DUHUDxljVPAiJ/PzkWZwb6DN1PrjWbGcFdxwUIQ5p2GY26PN99ynd++2+xurzMD77/ZwRRSF1JOt0RaWx58e4dRsOYNHHuA1TCpw8+Irx1iXFsONzv0O2PWF1eYnFxnvm5BZbCFRq/Nsdsowk65mDvEevrt3jpldf49YPf40c//rf0+x1mF5d49PgxtXqNdrtNs14jChT1SDE/3yAex6xt3GRpcY3kuM3S0hqNmUUsjsEbq3m6/YA/+dP/B08f/JTnj1b5+ldeZ3NzC9Qhz7afMYrHNENJu93ByAZG17n38ROMjDlsPGNpLqFRr7O/v0N7e59La8vs7Me89/FD7r7+Eq36IkuLt1HBbBbU6GKPEpOSps6CFikDYcpR55DhcEivn3B0PCbVCms1MnS2yEF/SKoNs3NzdHt9gsDywp0NFhYjbt26TZ2Uxflleh3Nwc4x65eWWF1dxpo0c/G6RIepcbRnvEJhLWTn9BhjUdIJf6TCZCndTTzm5OSA9Y3L1FpLJKIOSAKpmZtrcHLaJjUKQeBsDNlBpEiBNSl+Z0zBQ6qWbhdLUd5wkHN+prqGvbDJKNmd6g7CyiLFYmaFl1YipTt/aKZV5+P7TxnGbs0ak+br3qfIdHxMFEZoD1U8n4b8uV6pyRh32Tnv3CuV9VaWMaVNBfl73yV30Ky3kU8qwtXxmyL78nflFvixEmR+zX+n8sUGKLh9/Y4us0mxnr6mm8P8NtvSHBeEVzJRn4kfKD93ApgUiFe6Q50QiMz/aUrXTIIXD5xywZj78912XgdW3ImVDndlMSQ+Q6sVTjPKtxKW2mtNtkBxWVJt9hJZplsr3WFw1hQgyjrzpvDIWYAVmbjIBiyHOVZmCXAtLl2ZyYSsE1TaaHTlzB+JIJ1Kp+UgWQ9QhJSZ7pzrDW5MhEQbi7EC7a1lfkFZ1658yQgPEix5llYXpog7/dliRDbeWf0OCEgQMj/A0J0tFDNORiTGkBp3BoslBauRVuUAwj2rHKTntCWf1sWBKHfomrHFkq5aUfy9JYaQ06Ov2rnLrFCkRlGzITo9RkaSqD6D1TVItTud2IKSIToZoNPUAQwlSU2KNQYpA6JA0ag1mZ2bZ35+kZmZOeqNJioMQbj5lEqiggClguzE1mxuct5aRoYZK8wPFMzta1UzdqlUTMr5mob+4Ii33/k3PN99zNa1l9i69hqHx4fML66zc3BKr3tCPIK9nUNqNcHS4ixh2HTWIARhIEjGmkZ9kWZTMzfXJB6NGScDtF2mHsyyvj7DoH2EEIZ0FHN4/IDly5t87Rvfpttt8+z5hzzffcrJ8SnjwYAwFKTxGOyYrZtb9E4PSUd9wnpIo1VHDhrUZ2cxSiANICyj4YA//qN/wb37P6DVkswuNKnPzNLo95mdGdCciRiNxqxtrHF6eIwWI47abT558pwgSllfiej0u6ytb4AeM6q3sQHowNAddTlqtxknfYxJUN5ih8JgSZIx4/EAIRLStMPx4WMsCmtbjMcDjB2jlGVtrU6jKdi8tIgKV3j46BnHh6ck4yGtZsSrN69z9cocszPrJL2EeBSgA8PdO7eYX1wkiTW9/sCdVSQsxqZIYTFGILODTguxanExGwKsxBh3CrDQMd3jHRYX51lc3cTKBjIL9q1Fgkaryc7zEzBRth4ExroxdoqAd5d7/lClOL/eBD6ODlzrIGVyu3BBmwaLOzHK7WpxbEQgsxOl3QOdEhEGhoUZOGl3OO5LUiOxWjjeIByPVQKMFQiyE7KRaJkpo5l88rjFZPPp+YwVFiOMi+uj2AwgPXCxPiXEWSXBfeVd/p73GZwFKluv+ZgZjD81eTJ+MRuXijAtL2pL3p5/1/KFBigVN4otbS+G0pjYYhCp/HCmTMs2Ovl5GjjxQrWou2y1qNavlMq3Z7pFctbVU4AMKkTmBUK51jKgKrc//106EFMFauSAQEqJ1mlF2y9nUZXqbJI5m2lA5f66fmTeW+tOpC3vVPH1TRsXZ8IsXDtqws1jrS3NmoMtPhD3s2Ic3DWFr7mwnGRbAq0DMNZbf4RBGEso3KFo1iSM4gGdfpeT9ind7oBuZ0Q8HrvgUm3d4s1blx1HgDu8bRqtufgcf83ZNk9cjXcpFeDEueh8MJo7rkchlSAIA+JxHyVn0VJhhTO2Kqmw2mbn7rjxHMcpVkpqYY1mo8X8wgJLC0ssLC7TmpklCCLITldNtTu5N1CKWlBDycABvUryk+zEVtfJbJyzl/UalLcoZtaiDIjZMl9zJ/C57OHGjdFwMGbz0k1OD04JoyZCCVQYoIIa3faQ8diQaujHY/ZPjlhcq3N16wrxOCGJRyx87XXmZme4feMrvPPue/SHbcbjPp8+/JSoVgerOD4+4mj/OS/evMM4Tnnrp3/GzMo8N66+wSt37vDs0Xs8ePwp9fkmQQj12YixTrl6/TLXtq7y7tE+QRRycvyU0eCQS1cWic2YVGuibN4Gwy7Pdx9xdWuTvZ1dtq7fZX3jKv3eiFq3z8ryOt3OMXpNoq1gZ3+PDz/5hETg1AAlaM21ODg+YWF2ic3rlwmU5bTbo1UP6Hf6nJzuEdWWWVxoEckG0moCYzHxGJ306LQP6PU6NGfX6I8Mw94AI0PqTcnycoOZuZTf+PVvsbRyhUdP9/n04TaDQUIyTCFN0XFM0uvTj/do1FZ49myf5+0nbF5Z5PWvvsGgp4jqAimKTKe2kgbBWXaxIdKGQOqCaWV27IhNGXRP6PV3uXLtRaRYxIgoSw6YMrcQobWh149BKAwpiqDMijIBm2Wxlu6ZHrBUlCBR5ms5AU5fiRNucPzaUxqpU6QCoTM4qMYstSRKRuwc7LuTp6VTLgUms76UOJrwYL688j1PLbm9hTiTmj5XpDm7lWDSMllWAKpuLpU/M1ullXZYqxH2bEzLeYp6zrM/k7d9vvLFBiiT1hEoBGBJqMsSEeaMvVR+0WCe79KhMmlecLpFWakht5YAOaGJCYIrCKikWQh3gNtZv12G/rOXR8JCeJCWBcpaMgtMgYA9esaPiS2b6ovxVErl2rYHKvm6EuCPoPef/SLzu6mKGBSRWSc+a3yrAElKmcs3KYrF4RR2V9/kVl1/f7kPrmnZeT++grwLXnD6MdcIxgRCM9vSDIdDTtu7HByf0u116PeGjIcpo/GYOBlijEW603moko/JgJHAn9lhMzCEKHacFfP4i0FKgbEz0y0yBxAyDJABRMEMca9NFBliE5Fod2aOTQ06ThxwtAaTaoRU1Gt1FubnWV5aZXl5ldm5eeqNJlI6i5CxYLXGT7uS0h0gqNw2TzdqorLemKTTymdPl6aydnNVEbKD0jLNS2iwhmZzjtnZF9h/fkCaOrqemZvl9S9/lXsf3aM7aGOlpTEzw9LqHFeubXD7hRv0TttcvXyZ0ShByhozM6ssrazxgx99jw8+fId4f4hJJeurbU5OjvD7K2Zm5/nk2SfsPH/EXGOR5cWQO9fWGA0PSZVChJJGY5ZWa5FmTTI3V+PO7VvMzczw/ttv0T08YGvjOiPtNtpmBhRmmov8zm/9LR4++jHt/RNuXN3icO8h7e4zZufrWLnI82d73L+/y8nRAYenh+g0QSpBI1IsLiyhVJ1eb0AYNjBxn8OdI04Pu6hYcrjd5uGDR0i1xNzsVYwICUiwSZthf5fj42dobZlbWCdNa6S2hxFDjNDU6iHNVp00OWH72WOUCqgFltWlJiuLN9l5vkstgM31TeYijbUpxiTsHhzTGw/pdBocHBwSqAYLCzV2tgUidnNrhXLKRH6EQ5ZE0bqtzm5NSKSwkJ5y3H7EyuoyUbSCtjXHBWxCGFoW5mY4bZ9kLl4JmZuycNF7xUMUOzqpKl5nrOpTSlmYOzKeUIREZrHGWZiV0EhrkFLTao5o1UN2DhLGSR3LMHe3+ezfFjBCZFZXv4YozgUq/XN3ZW0wls9kFxNtnfZ9rv9amx2DFmSKcAYUK7xSooTNU/h/HuBx9vllReavVr7YAGWi5ONWJsrcwmRLr9I9lJjkmfrE1L/l38uvKvqerK/43bXrnF0qnnhKAaBm0lJQeZOBE0EGVvwz3G8+iv5MuzOcXLVyVAFK+Xqf+t5/nY+bj7mdeIjRpeRy1j+zOm5QImZb/Kay83iq1/hESOTfTSL5qQG42bj7v54D5FsGMwCXn2+hxqTjLqNRn+WVGfaPYXu3i9ZDpBiDdGm4tU7R2plpfZ4B95QsOK/UhtwCVGIMZStKuQ9naax4VecvA9sSwihCRaDkDMGwQyATrGowGmmXHTRNSeMxcTImTl0m0Wa9zuLiEuvr66wsrzM7O08YRiBdVlhjDcK401RdTKNEKIkMA0QgySzIpVFW2RfVmBxwrsXc0Gz9NBSR/3kcjv8/A7lSSBCWRnMGjEGpGoNBG2s1gQr5zd/4bT6+/3N68QnHp23GoyGDXsD+7hEv3bLcunWL2dYMgpDROOXo+BitNUGouXX7GsuLa7z11js8fvAcnaa8+EK2jUfD8UGf7edHXLnWoRVIbt25Qn22TiwVf/a9v+CIY+I4pR5a7NVlXrh9EzNOMcmAhZkGlzdfYOPGqzQbcyjhzluJohprqxs8fhLy4ksvoU2fWLcZjtsszc9hkIigwQf3ntEbHLGyPosMBUGgmJ+ts7K8TL05TxQ2qdcj+qMxUX2Jfr/NpbXLbM5cZ6a+Ri2YweouJ+1dmlGTD97/Ae/+7EcEKqTeaJHqEG0iJBEqs0wMh0NuXN8gCuYQQhKFBqxkY3mOuy+/BlLywfs/Z2FhGTE4QihBO+4hIsPG0iW+8tUv02rN0e2eEkSWKAoZ9JMJndzFOjipqAuXqMjcE2ZE5/gRS4uKhaUVEmuwjElMlyBICetNlJqn3x9hrEQEPomfczMzASoKa0fBDyd59ufV8ivXWQs22/ZuBcbG1KIEa8fo9JSZxpBENzntpRhCLKPMSntWcc1XRsno6P/mL1Gy/vo1hQfx/+5WCu9u9jqaFcVBsMK3N9dJq0rkeZ6Ec55EEZ9W7uUvLl94gOKZ9VkG70c2Ezz5UikkbG7uE8707K0f55muyvVPn4yCMZ8FLJVWn/uTF2TCmXtyQVwOBi0unP7sya/P9gcHNoy/b7KeMtFxvjk0b1/WVvdFBnw0WuszDMO7eSpPzGNQQGTWoLPZW32G0SwR3IR242iAQgKe6ZOLvymOGBCAqgAVgQGpkYHg6PiY/rDNl167Sqjg5z//lE4yJlWQBO6cnzQ1pDZ1wcSZRuUeVwDGCplU5tPkwPOzmKT73YFM58LLQJh1jCQIFWEUEIQCYSEKA6yJUYEhSRPi8ZhkFJOMxyRJikHRbDRZXFzh0sZlVlZXmZ2ZQ6kIIWXpYIbsP2mx2ll+ZCBQKjuALiPhwtGXxQsJ67Z/lygr342QzZ13ORY5VNx9wuKEVkYHRmeT6l2iUrhDDq3g4YNHvPveO5yc7lGv15ibneP4+IDtx0NOD9p0Dkf83u/9Fl/56lexRtAMYnb22rz/wXvsHWyzurLK8vICa2srPHm4ByZgbeU6MzMrdGqnJEPBw0+eMb8yT9w/YaU1h4pCiMcsLjZ59OBjOu0hM40mw0GfYTemfdhD6JCtS6u89OpXmb/0IogmRrtD+MbJgJPOPsedQ155+SapHLBx9RpBfRYpQ/70vR/w/Nk+e4eHzC/VsMoS1gJmW7NEkUAGIbOzs5hRjFI1mssL3Lx2mWFPcfX/Q96fxdiWpnfd4O8d1lp7jDlOnDnPyalOZpVrtKtsY4P92f3ZpptmkrotuSUECEtIvkBcICEBEhYSEuICmRtafdFAi0+tT93gj1bTBgzGE3aVK12VWVk55zknzxzzjh177zW8U1+8a629d0ScGhA3JVYqMk7sYc3rff7v//k//+faZe780E9yUhaMTna5+/HX2Vjt8+iTQ3afjbh58yWe7R1TlI1vUBV5xQCZiE3v9p484rOfe4UXXtiirGaMRjlCBCbjPT792dc4PFylM0ipckNvdYNPHj6kt5pw69ZNlNIkOo1yOOGwzkRizDeItHnOI3MCjiArfIjMbCIqkjBj/9k+w5UbWFmh0jHTWUVhDrDFiNW12+wfO8pihYCG1olVL4GTc6mMRbBc/1PKixuBNiDmwvYiLaAG2YzHUoCDopgxOnyEKY7YGGwxqXJkEiDYNq4sluOffcab8e8i8mNRBtBMbmX9hSU2aCn2XDwxbY5x6Xh9FP+HmtmMjsyy7lAcEI2e5wLwd+7nzHEtH+/3D6Z+sAFKK3CaL4vi1hZ9njl5i5dnfsvx3BN8brMXAJbzy3LO8yy1qOrOms+7YUUz2AtRW/ZHV9Z5EL6YfnzessgyLLIqZ7e/9CDI87na+KFmw/X325drpFwDiEYPJBrwLZ7zgLZ6DJa2256L5zy4y14izXUM83sAMT9fwrczmMVS4eY8S0CKQFCK04nh0eN9fDhhdc3w4gvrJOIV3vjGO5RVFVun18A2Hmd0zBRzPf/S9RH1ATTiu7YXzwXs1uI9t3zOm9lgaNkHCGitUImMQdwHer0B45MjlDYgHM5YqrKirEzsqJomrG1ssn35Ghvbl+j2hwSZEqSur2NN9SIjCPQhUrxEY69ERXG1AlzwjfPDPAA1PHV7XI3MuTnWGtLUgvLa0qW+xjF4Clmn3kQUeHo8UgaUAmcrRBD0u0OG/T44C85TFRUiKIrcYgrLt751l9c+/Rqf/qxFkVGVlqIosdbinY/pSwnDfo+11VU+/dqX+fKX/yeq6pRef4VEpjx68JD90WP6XcWf/fmf58mjJ0ymhyg5Rnct/aDpZCkuKD744BEHTw65tnOFL/7Qa0yKCYPgaga34nSyz6PHd7n/4EP2D58wmgzZubzO+sYO+A7vvv0u3/r62xztTxGuAqep8opOknE6PiWfBW7fFmgtya2jo9aYzU55+aUX2Np5xpvvfoOvvv0OVhSMT/b57Gdep5Nc5ujkPj/8I/87TsaWp4cn+GDAF3UVS6zokV3Fy7dv8eqrl+gPUh4+esDd+/coTeDK1Uu88+4blOaY3mADG3K8KEn6XZyAtY0Vrly9jDexuq/bHaB1hrWu9fxoxor2/g4+glMpcDgkimFfYMtjrl69xo3bL7PzwhqfPP6Et975Nnl+QpqVPHr4IS/d+jyrvS/g6+oZ0WhNaAaa8+NhM66092ObRznPdMJcYHvREtPLINEEwGIQZATfx8wctih4+OQY2euR9bqosa2HA7G0jXP7GeZ/nwVY7Zz0TCxpAF8sbGhXu3TccHa8nceOiP0DWgTSRJEbjw1NX9h6klVPDMOZifvyds7Hw+fFpIvG/++0/EADlAZZxpgY5gGzIa7qGTsLYOVcqmQR3bWBcOHmYBn0XLgfYoF9YX5jNO81wbcRyZ6zWV5ab0TaodZHBO9rPUdo9+Xstr/Tfs3R9MKPj2DnouNsZuyLfiTnQYqYe3vURyqa89esy/slBmXpOtVL3F709FgETGfZmvbYxTzu+bqMeVHLsVgeKJib8M0b8QWamcXcFyeGQBEs3pfYMGP34CnTasr2VpeT0z0Ont1nZ+s2P/7jn+UPv/omxaPj2HDN14yR8ERNbO15IjwtC0bdmY+FoF2TDHEcnAPks/fCWYDs8ciFy6+UIM0UWtfHJjVpNkSII4KfEZylqgx5UVCaiiTpsLW2yeVLV9jc3CHtDPFSxxLjuqOxEKJNzxECwnsmo5PoqKoVOMv+02eEEMGREBKtElSW4gOkSRIrsEJo7/UkSUiShE6nQ7eTorVCJwlZJ0UQkLIW4klPCBZJiPoCOghU1Gl5S5aleGuRSK5cvoGSnt/+L/+GTibROpBmiry0GOsoS8+zp4949PAjVgc7WBNI0z6ffv1LvP3WN1lfWWfvcB/jHT/5Uz/Jz/3sL7K5eZ233v4DOr0hm5tbzPYfMjstMLnk8ZNnHB4esbbeY2drB2cTxocTkkRzZWuTcSiQq5JhljE+2ufhR9/E2RmD3g7OBn779/8dH3zwHoOVdezY8sbvf50EwfbGNQKB49ExZV5xdXsdmUmMMPQGffYP9lBBIb3GFCXj0YidtRcopxmTyT7HowM+vPchv/eH3yC3gSvX11lbiU6yvX4XIQJf+8a/pzIpM+MRWoHVCNdB49m51OHFl6/Q63seP3nEG2/tc/feQ7yoWN/M2N65wenJkCePTnjttZd4eP9Dbqx3yF1B1tN8+vU7ZGlG7gt63T5KZZyMCoJflGw2N+28OCB4AV4hZKDXUWyudRkOUzYvb+MTwTsfvcvDx484Hh1wfHjM9euXCEnKzVu3qWYps2lMK4qw/NwvPkdhPqice+/CcXNhXvFcpqM9ovjsS+9wQiCFZXOtS1Vd4dSsMh2DKW09LF3ElC4wPCJ2hl88U2f39ez2IR520/CzeT8yk/G1i6qRFhfvPTI4kszx+mt3ePRsxNO9Y1TtuuJa5nkpn7u0b83v7xTTzk+O/wcBKIvZjrlGYoERuWDgb8DsOUblHPqco9SzQOXsOhc/P9/+WVZi/pwIIYgu981M+OxxNTQoEGRkUJgH+4tU1Bft++Jnlm6K5d177vcvcru9iGWCBnzMX2sbHPrYdfjC7FNNbZ49FiHqRnQ1qLloAGqA1jKVW2e5z12vZt1i/lML3BAeEQxBVIRg2d9/xsHRY0anzxiurzMuE9796H1OpwVXr93ky195HWvf5N69/ZpZaC6siNeK+ayuYVNC8MvnjEDwC74Q9WcbIHXR9W3wYBDz4mulJEkiUbI51gSpenS6PSbTU1xpyfOCwhpUkrGyus7OpR0217dI0xQlQDiH9ya6tDpDMZtFBsxaZtMJj++9z/6Th0ynp7HlPaCUao34ogeFREiF8w6tYwdd7z1KSpRWcVtKk6YZSa9Pp9dha3uLVz71Irdu32Blrc9gmJF1JVlHoaRGig2kWEeqTp1ClKRJFxcCLgSkVtgAlYMk02TdgPWBEDReBlId2H26ywfvvc+VKxO6nSF7+48iE5PAcLjOt779VfZ3R/zET36KldUtEt0lVR1cd8if/Omf5Xf+8Hd48PQerrQ8erjHzRsvcfvGTZ49vYc/FayUGZubQ65uXWYUjlBrHVZ7msSMSB69y2T/AYVIQXpu5of0hpbKnrDWyTgtHDzcZS/9FpWQrCbwyo0trl6/TrbWZWxyhMrgA8HR/glFXjI5qeh3NqhMwub2i5RlyeHRCafjktkMptZxfDwFNCeTU1SiuHzlCr/xH36LyczS6XW5emWbnZ0rTI8LNtc2eOnly1hxwsf3P+QP//gtpjNPbivSzLN9aYMvfu6LpGmPt956hBYp0njW1rY4dlPW1ztcu3yF1bWrHB2dMJ3OmE0Mo6Oy7YcjhGfukF1POIKPacIg6CrBtZ0h1uZkK+vcffoJ43vvMBqfYCuDxPPiyzf5oc/cwVmPTnr4JEVISwgOKXQ7/jxvaSayZ6s05ZkxezkitOoMWlaxZrHjBCQAHonDiwJjjuj2ugS1Ci6aKHo/IwSzNGbOx6YILsLC63O7B+ZdMerXzjnbLqzr3NBaT+TOMzL+7MeQImDNCe+/93W6KzeYW1yEeaxkrpWZs+vy3Dld3K+LQMj3y57ADzpAmZPHsHgBw/zKL9J7DQ04H/cXQMvztnAGbT8PFEDzCC6uelmD0ICUhk0513CpAUTtAxePbVGr8J0Yk+ctZ1H4d0Kxot7BZh8XQcpyF+bFm3/xFo6LqxkU3+Rqz00NlgFb87sBmm36a+G8hhAIcuHc1M0hF5mi+bWeM0d42bogtk++EERnA4uQFik9xSznwYOHPHvyhOPRPsN1xdqlHZ6NjjnNc0pX8fqnPsOf+MlP4/1bfPDhM7zVSBQEBXW5XrPXkalp9lbMj+HMD/Un2vvxzP3W0ryi+UQ8zlQrtBSEtoWAJMiUrNtnNNrDlgFTOnwQ9FZW2N6+xMbGBkJIxsdH5LMJ4/EIY0r6vYy93Wfs7T7FG0tZFJRFATYnuLINMhGcRMAllYo+DD4QvG1Bi9YqllI2rRKkxHuHdQEhVXQfVvAfpSDrJHS6KYPVHtuXYm+cnctXuHrzDq+88iV2bryK6g4QKLJkSF4U2ODRwNbOFf7P/5e/yv/zf/1nHI0PSXXCla1LsQ/OygoffPhtkuQ91tcvEfyUk9NDptMjLm/fJM8tu0/HvHDz00h6KJUhkGRJykw6fuRH/yRpf5N3334DPzvhzktXuHXlKsXoCDMZsdqRdK+sojSI0122OhblKwQO6SqSWYKYHeCdQ0rBRgisJIqSKawpbOiizBh571t4p7jUSflTL18mdHuU/S6jgxE2WNY31jneO0ULx/XLl9nauM50mrBx6SZFMWE2nfAzP/0zfPDhXSZPdzk9nXHpymVOpjNK42I36rRHmgo2dvq89vpNtte22Xt8zKCvOa2e8fjJA45Hp5QVnM7K+Gz4AFLSHww4Hk15/+77vHi1pJcYnJuik4rLl/oo4Rn219DZkHsffcwf/sHXmJ56CIoQbLyvhZuzJgBC4kJA4dlZH9BPLSubPbav7fC7X/0jnu4eMj2tEAG6nYBWnoODPX7yJ38aGS5xf3eC93JB93WGIWnHp3mkn08Sm+dqPg43fzdj9uLq5kzxgndWM4Ch8dKgzBRkhVArGJ+BMHXqUkZ/FualwMtFAWFO/IZ2j+fHcGaC0oCOCyUBLbhZjofxJb/AUDe/a2Y5ePL8EK0zTscDQujO900Awp9hwy5ezjIoFy3/LVqUH2iAIloaay44bNmQ+UR5fuJEoziZo/kmNbEYQC9kDdqTH+qrvHjFG3C07A1CvS/z3alvHDG3TebsuttQNn9pMZg1AKK9WTl7uZsA3nyuOSdi4YP1uqDt07O8hmaGwbwXT1OHf+HNFZZ+ArGKx1kXRXIBGqey5vqIZkMLkXcOhOofIWjMzufnvXlQlweP9uyG0LJSS4xWkBGoqBCDiDBETU+FUIaymvLg0T32Dw+YzkpA8fDRHiY4gswwXpB1+hweHjDLx/zoj36WTtLl2+9+Ug9CNfBtBcPzwaApNV6cEc1PV1PZoNt1zPGIbK9ZO2DVniJCCYSuWSZfp+REiG2YZIZUHUw5QgTHoNdBK810POK9vWccHJ1wfHzE6fgYHxzOmfhd5wjB1ekrH6+dqH0bBCitUA6qqlq4U+I90suS2jcnghPqZxMhUIlEeYEQFolHK4UxNuoQCsjzisnhmMcfP46lzGmC7vx7BsMtti/f4qXXPs3tl16hmyrKWYXJcxLdIwTHYLjO6CTn5DhnZ/MKP/7lP8HG6hov3LzJ/+3//n/low8f8Oqre7z6qduIIEhVRr+3wt6zCYd7E/5Pf/5n+MxnP0+a9lAqQaqUWT4hEZLP336VrfIYd3QfNXrK5OkHyFCwbmbgDGl9oUzlEN4hcPgAWkm00uhUY7A4Ax2dUlYzlLMkArJOik4UzpSsWIm3ii2dcpo7no72yaZj1HAVm2QQHL2O5OWXb9HprnL58isknTXWNm4wOnwLa0bcvr3D3vERwRuUyDg5meJDoNvtcXlnh7QjeP1zn2J9c4Xjw33uP3mfj+4/RGnN9voWVeGoSo8znua2mxUl/9//+O9IdJeP776DNhM+c+sKaSoZ5YbcjHiQfcLK6i2CTHn2ZJ9337mPqeLzJgW4ViQbU8fe11U3Ijqtbm50yDolV17YobPWxzjBybEhOIX3FmcdTx4fk3U+4uWXXmNjZYfgE5rKr+aZaUNfWJjth4Vnrf2siClD0YxJzTg5By7x+W0Y1oX7vJ6wRQuEOCHAeWx5TJIkVC7DhJQgHYiqHupV+6gsT+EWQETLMM1tKZuPNKCqGXmfl+5p9m8RXES9TL2dFmPE1iWBaOSphEeKqE2bVb7daKjH/8brKNTbvmiCuziB5QKWpJmiLZ7L73X5gQYooc71z51WoWEdmvryaB62vCyC5eZCLn7muSyFgKXKDAEN+TbfTr3SICFE468FvESTOmka8TVBq72I1Oucx+P2hpCtVoCIlBugshi46x2L5tKydh0kWkAvgJRljHUG4oi53bwStD+SRgY6Bz2hRQqhDrZxf5wPWOdbnUWkMNv7vX54RFxjWD7fDZir7/d65hHPcWgif2hEtM235pRsA5NCoE6lzQWqwnuErEAYCKBUhdQVH3z0Ht9+5xvsH42wzjGezDDWMj4pIARKb3jrrQ+4efMy62s97t37iC9+8Q6p1rz/4WMKY3EIEFFP0zo6olog7alp3ToF1g4mLcCqS/yaezfIehLo5iC6Sf0Jor23iNcZBM5VOO+oCo9zHaqqIpiC6dGIJ08eURUzZABvHB6onIEQGTop5g3VnIhjt1QCULHnkvMY43CirtqqbyDvPEEpZsZFQOmjK6YIsTJAyuj4K4AsSQmuwvlobKWkwHkTZ8LxQAkuECzY05yjk4fsP3jIu2/8V1TWJev1Ga6tcrR7zK3bL1HaiuPJAcVhzqXBFa5tXmdzdQvrDA8fP+Ty1cs8PXzMH/7RH1L5EZtrGyihUWrIyy+9wp/7P27xw1/4UdbWL+MEWGfRMoGy4OCDN3H7+6i9d+iUT+g4T1VMqZxBKkXwPmqvpUQrkFrgXLxekVkCV5nIoAhBcBVZIvBSoGQgEwLlozdIRztciLPugbJ0ZMXqQDPSimOdMd5YRWWC/mAV40DpjOjknHD/4w84HH3C2maf9dU+x4cjUjLK2YzDwyOuX7nNymqfWTlGKUWWddgb7ZMHy+7xDGc9R8dTsqRDUZW1L4bHeSgLy+Mnj9BpwtpqRpZJuoMBaWfA9mCF/ZMTeoM1RqMRDx/s83v/5Q1OjyuCqzuyBB97syzOyImizkRatrf6DNYTVtZXGc9y8r19nu0eYUqPVoGVlR6JFvT6nkFvnZXBJWYTR3Cqfa7nI97C4BHipFU06VCxyD7HfWl9qFTt/i0hWlOHdryhnnC23w0GRBGfUeXi2G6OkeQouY2pujhZPyOxaHwhwPs2diyndufeVYSw4IPS/MT/4qg/N4U8mwZuUy01oAkippFlEHXrDodDIGufIVFPmqQo6XQyfOjjXRKf/xpAChQqKAKWuX7oglgh5vHzfLSN+7Q8Tn/vyw80QGmhxYII8rvpM+o3599uO1r6pe+cLZFqKLqz612i15aYkOdteo7UGyROk5ZqTUVEHVTrCfkZ7cni/gCtz0T7twjnjz/E4OhqcNCUrJ49znnX46hxmKd5VJuWmkfL+TlohgkhQqSHfcB7hyf6BbTATAaC80vfXTymuA0VewB9h3Mdzl7rZsYwX9t8/cLXswFPVZVYP0MSqewkq1C64N4n7/Fk9yFSp+RFGYcUHzDGo6XGmUBeeNbWL7OxtcLuk/d54xt/zI984ctknS7fevsjikpgPQSpscEhRD1Iza8MjbGZD54gHE36S9ReEDG1vVzJg1BQB/x4d0gSBFoohFQEITDOUU1z7r33Hk8e3efp4wccHR5ycjyJ5dDOELxFKxA+IKVC16ZxSkQgF7yrJ5bR2VeLWKVkrYMQ0FLgrI33hBKouhRRSqJtvpQ47xFKxR8RqKylzEukgKK0dDuKRCc089yAx1S2ntnGqp2qMnVJcd12LFjKqiKfTjje2+XxvXsonaCEINMiXidneTqa8ZuPn6F6KSGBtJ+RdQbcuPkSt299iizp0O/2GHSu8drrP8GP/nhGKrooPJPJMR+99xb7996k2v0Wo2DplgU+P6YIM0LWiToab9HCI7TEOd+WXUshY88jF8XLQkiK6QznLForOmkPrRWusiRakUhwzmGNieJfbxBekErNUBh6VFwJnpGZsHVjjdNsiJs5Dg92MZVDqU1+7z/8eyaHD/nxP/UT3N8/4a13HyPHJT4kZKrLeFzSfWmFy1d3uHTpi4ik5OD4IU+ePuV4NMVUHiU0lbFoVZJ1JL4IcRKkPNNiSqefsL7aiRPABIySeCUIqsS4GQTBgwdP+c3f+H0ePTrGOUG0p3OIeqbeDkAhjndKVqyuSi7tDOgOEnb39slt4MnTDxgf5kgR2NruoaSmLHMkCS+/9Dm8W+F0PCXQadb4fc3HZfCRPxAJigwlErQELR3GGwQ2siZIRLBzG3nvUCKQZCVOPmZSVtzaucP0ZMJs8gnD3hqV7eG8rlPKqp5AOhDzLvKEpopQnBl3F8eIhRFsIVZ8p/T+8+QHcZMNO+QbTggXHEp6BJ4gJiRJgikz8FlMTclmXPa1g+zyts7ZTlwgkP1+tSbPW36gAUorflpgBhr78/heHbRq3rwNbqL53wXrPHNyz+bWvlNFz4VrXAjOQix0gV28wEIst/hm+eFrUhfNzFsq1W6vJToXbua4zB+MpRDZnIuFDZylDRsg4ls/kjmF1wCHc4ry+n9LQlkXRbKirWSZH8/iuZpfr3rO0D4E0fRsWacR2iDflLU257NZ4ndZ+g6AkIo07ZCQIKVFSRhPPuH+o2/S7UGaSYTUIEqcd8xt5iMoK4qKd9/9gKybkqoedz9+SJl/jT/xoz9GqjR//OYHzMo430BIAq61tY4DVASTQNvjqFXvh9pvQDbvi3bcijA8OtZ6PF44fCLxaUCrgCtKnn7ymLfe+CYfvPNtxicHOFvinSV4GfsWOYtUITqxBoFumqnFXY3OsCECEklkAlzb9LG+xoEaeDTdVWuWC6IWpgZeQugIwBCxFYASGOPw0iPK2AYgSePQ431AaokxBuEdSkfbcudD7ccQ8M7G/WqElzLEHkM0oui4E3lVMjsdYwnIRJH1u/Q6KddWrpPKdZQQaNllfXWbTtrHaUXlBNX4hHf+6D/x8dd/k155wKo+JVMWURpE5QjCYXwOSUJHK/AliUqRIXatlUiMqcAHpBLYyqCTtD0+JSWyrsBSOjJVEhBK4kz0INFaoKWNQUVFx1/I6SSCrjPkImF2tM9RMeMPfud3cHnK1as3+cJP/TRZP6E3M2xd3uLwYERvMKA7sGT9lLST8MKtVxkOVxjPnrL79JT9vWMePRzhjSJJBWki2NjosXLzEvfuPqOocoarGVJ5kjRjOBjgTMXu0RO0lGysf4bJTNLtvsDxkWb32SmjkcNUCdbFoOyDhYbhDYFGCyJFoJtKXrx9hRduX2L/cJ+8KHi2e8LRfoF0ko2tDtevbVJMctRql5u3XmRj9SZHewYfFAgXe0EFait78T0GxQgkNTqOnTIghKPbSZDCUxQCg5kzsSHWsygyQEe2Txo2NgesrsHh4S5eVVihMQGCjCBM+rj+0IppITb9mu/nfH+bSWm9LMz95hMw2U4W248tAIXlz4p2XGyxT6S7kfXzHV3KDVoJnJ3S725QVdn8+wv7E7V7Cvyc+XgeSLqw4GNh31pO6IKih+ctP+AAZR4YW/akuVCNGdRCH5nFpSUGwzJCff7S3DWivfDtzF3Mkx/NTTj/2jx/14TlWG4sFxiJ5p15smmerohiUL9QsXLuPCwg6OUy3rpUdJljoykxDgu06yJVqJRCWYkTc/aktb2XYuGhiOcj2l7UdGokBPDB1QGy8SmoU2OhyfY2+7jAoNAwQwu5XiGWHjqaeUBtpR9LjRv2ZJE5WvzdPKkSIXSt3veYqqCsPLt7u2Q9xXB1haJobNhrQzICQViSTFGVFY+fPmF7e5PVYUJlFY8enfDVr/4xX/6RzxECvPHmu+TO151WF6FhU/wu2/RY8xPNyRyB2tJeinpwk80tOj8/CKRQ8QfBaH+f9958k6/91z9g7+lTnHEIEVDKg/dIFMEHlIyMhhQaLVVNgYOxFqzHiti9MPZuipUWVWUQSiGVRimJtbZm3yKOkiH+2xgb2yCEgFYJIdQV2HV6x7um0WCCdZZpYQhFiTWWfq9DojUuxHRIpur8PgItJdbWVRChKUkHU8UqEBuiPLhxHVZKxjJkIZEBprMRPgR+69/+Ju++eZ3rNy9z+9UX6SbXowOo84xPRow/eZ/Re19lp3zMUJZIVxJshXWgVEoiBFBBZSBNkEKQSMh0Sl5UVKZE1G0HlNCUrkSq6LXiGxDdMFUQYabzETBnKd5H3Y/WoEQgWElpBUhQwbCuK3rmEHFoOD1ZYfx4j09//k/yP/3cX8BVU95552sUZU6n38WYnOPjY4xX5HmOD4a19U3SVDGaVOSzGUVuWOkPMfmkbhIJt164QZ47sq5mWjq6vT7OF+TFlKoaEmSgCiUffXKPF2/f5iS/TJ73KGa7HB+OsLZT2xeUeB+vkw+1JirM2VopLds7XV7/7E2u3tih96RHt7/C3t7bBDdD4Nna7nHnUzfZe/yUH/rMF9ncvM14rHAhqXXoHlDM/Yzm4+BFY2QLkISO7E49bksJSgX6Q8GnXr+G9Tm7u7tUlUCKjDw32EqQJj2Gq4HCHDA+DfSHjodP3uXuJ3e598EuG5u73HzhdZJkq053OETQQNWmmi9eFsemdphYOp5mQhtCU0m0nOZ5bsyqQYkX9djb9NJpGI8AhBwlFFr1kVLQH2hk0mV8Op3vc4hALbYBma88nvrzB7Y8XjcM9pkd+x8HoCzPuuevL/zr7AWsL3hkEZq0zTICXUS57UVoX18MfPMM4XJAXP4eLOODBjidQ8Chnq03LE29vqZkF2pvj++Ao5Yf0hoMLNwsvm6ju4iSm8DeDrJKxRJRqVBKt34Wi2e3PTdCRh+QEHu3tOE4xB5C3tWMVgjtGbvoxm7P3Bm2q93DMw9jTMH42sSuBqaCpes2BzuxsV2Np+rLI8kLx8HBKScnOUOR0ev1MDbHGBNTFRJ07YyJiD4bVWFJpGAwEPSHkmoGDx4dYN0b/NhXPk9Qlj/+5vvkJbiFrsZxcK73uxkwg0IIPa8wwseW86KpjIqpKVEPLIEYqG1lqCYnPLt3xNf+8Pd4/Ml9TscndRVNPAfWWhIVU0NS1F1mnMV5CFLFoKhFbVoWWbImnWhsVWcda/bCO6yVeBd1M1LJ2t4/oLWmP1ihLIq4/QDUJm/ORrbP+zhAWhsBayCmD42HSV7SyeIgrbSOBl/eI5Wub695/49YvhzvqTgpEBhr8SpEcOJjykwKBTKays3ynOO9Q0ZHJ7z/1rsM1r/OZ774AMGAy5e3uPutrzO5+w06409I7RjwOB/ZNTzoTKJa4O1JkwRvLXle0ul2kVJRmQpUZKqKWYFQirwsowdMmsbGeTU4j92joSwrpEpQSUqoNXQKiRaSoCDYeJ6yJCPgUa5EMcHNLF+6ucPmjXWeHdxla/MyQWcc7t/no/c+ZjLJefjwCWvTDts7A46ODtjelGSdFaRQKKm4fGkLu56yMii4f/8x+SxwMsrxTpDPSiQaa2s9lJRYYQla0l/J6K2v4cMqu0drFHmGqDy2UnjTIGnR3qsRbdfB0XukMPT6gvVtwcw+YzSruPHiNV5+9VWePhmz/2yESDwv3LrCnTuv8PpLN1gZXmU00hDSCDACKDlvRMgFY+FicGzHQhFqPV7NWgrq8njBdDZi/+iUV16/wo0Xb3NybJlNKxCSqvSYyhE4YTIrqKwl7RZknYyT0wl37x/w0f19Hu0d8alXPsPaYCuyzMRn+OxItzSBPPP77Ofa42j/jse9WDDRahPPplh8fA6byU+Dg5SQkeURCu/GDHpDZlND2km5dHnIyUlM5861M4HA2bE47lVs+i6WJtotUbCwL/Wr5977XpYfbICymLa58H1apqMJfKENYhdTVedSFwJY0HSIFiA0qZq49fqanX9eAjRW8OduSTE/DpqAf+ZA6szA0k159hws/m7+3d7AzB/W1puEsPSZdvMiznZC8G1qZ7EcukmdnE15tQPTwraCjx2NFzsOn6UIl9JczXvU3ZN5fs51WUm+vO75Z+ZgJXhRK/c9CENA1ELYMaPRKWk6AAJSO6yr2oceEbUVKkCSZSAlaZoSbMntF7fYvrzKR+8fsftoxuMnx5FJ+dEfQgR44xsfU5iACxbavkuhvZdECMgQz7cg0v6x+aKIJmX1zEcFj6tKjg8OmM2mIAW7T5/w5OEnTE9GHB0fUFVlBJFCYb0HKVBCR7M8W6G1JpU18AsR8CSdBOcdXgnSNGE4GJAXBSEEOp0ORVHg6rhaliXOg0ySCC50QmUqjHFUzrWA2jkPQuMaQC0F3lqaXmPBOYKQWO9iqqhWQReVjSkiKUh1gjeGylp8XbHUSVMI0eLb183SvKOuLksgBLybCyOlFoTgSHTKoN8jryqst7hCcbp3xBu/9ZtMd/f48S9/EXnyCcnpJ2gxjXoRBCI4UglaBFQwURQeBEornHMolWK9p7IBawOTosL5EpWkGGvRIepLhBD0eqoVTEul8d5FV18kaZKCiBVyOI8rHWmm6OhopW6sQ4qEgAINKlguq5xEKT65/w1+/6v/jh/+iZ/n6WjMW2++xdNPnuKdYjrN0alhb/eA8ekYpeI529y4wnQ2ZnSU8/jRId5bZNBMxyUfffAMpRRlEeh0h5Qzj5SCznqGTCEYTy9bYb13BZ1sMi66zIqMri+xTtfA29QPnyZyWw1PHccNqaA/0Hgco/EJh6f7dLvPWBlcZ31znd6wQ5I5bt64ytbmFtXkECkSygIQCi88CknwsXs37Ri2PIE5y6SIGigFYQjCgrQgo7mi0orKBh4+3mdSTlhZGVDlUT9z6eoGvVXF8fGYyWnOejpg69I2WVeSJCkBjfWO0sDHdx+yt7fPqy/e4ode/SKmlNQyv/p/NZMm6rEJYpq3GRZahv2C4H5BUD+rSTkbG+JkswYZTYuPNvxEtlupAp328SIl6Wj29w+YzmQNbpoO0ZFxEgtUbrOZi+QD5zMVy6JYKeVcW/Y9LD/wAKX5LSDmI5dOnmoDXVyW6TRPk35YvtBtIJZxBkH77YCo+xXUGGUO5EUNOs/oLVqWRcwvZRM8451ZW+K3/w91cKrvZOoy6qVS4EUNxgJ4OXNupBAgweHn4KRB4gupmoZlEQKEEpEJkREhtyW/LUg5I15t26o3oCeeKR9C3VBvbuveGBMt3rBnBxIlasp+ocvzctoqsjaExmZ+znwtgrHmtbg1386gfL2Pp7MxB4d7TGeneG/r2Z6jKGd1cIuztarysX+ciw91lqU4b9jde8TLd15AZ+tIqXnw4YSHjyf4r77Jn/jxr1CW8K137lKaGOWdB6l1tKknBmxNIAmggiDYitksZzLJ2djcJutkyGApxke8//ab3P/o25hyQmE8noTTSc7J+BTvPYNhFyEEXrj6vo/lg90sxVtHt9tBqoDWtaet9SRJgveWJIlDgNbQ17Efj/OBrs5AxLy1cyllVfc9EdHvJS89PlOUhYkpCwSVi2WhzWAptSLR0VK+uRJSxC7ZIQSkUjgfA2FpLFpFwJLohGBNDEbN56ylKA1aaypjkFJFMSoNsCMyflIQnIPgcL5CK8Vqv4uRMDku6WhBR1Xs332T39//mGurkmsbCjoCYSq6QqK1oXICtMQGFwGqStFJFE1HETVgLaUxlDbgvCdVAZ1kJFojpcE7C84hEtXm54MQWOdJ0xTvLUppCB6BwwUwzpAoQZpG2YINDi00mYgABekxFKyZgs1E8/F7b/Nfvvpt7t17gvUBhcaYisqCMYYPPvyQKzvbPH70hM997ov0u9v0Oo8w1TM+efAAV2XYSjE6NCht8AicK9DK00kDwimyoJHZAGNX6ehrEBJyLxmbDjYMIJxg6l7Q8flrdBXzKkawDHopppixu6s5nc04PNonhH2cfcDG6g6DlSEbm5LVYcLh/kM2V9aZjMGHpB5nmzRyUo8zMdVzfo4/H0/asSqWMhJ1gJLoIF0ynhwwzccEETg8rMhnOZ0sAwzjkxNeePEyUq5ycmT41luPOBwd8drrl9nc2kRqyXC1izt2WOsZn+R8fPdDfuj129y48Qp37+0za4sv5qmNOCLNJ1hBNP9enmQu/jucGevOj3Nnjz2uran+mfcgi2y3CAXe52id0B2sM5kZTk6r+HzTVDLVD65wEGQ7ti+y75FFYYFFWY6lEXzFQ1ucNH6vyw84QGk0CvHGJSxe6Dkz0La5p0nRLFz8C26KJVZhaXuLgfmC974D4m0FqCLm7dvAOV8BgrmeYgl3hrAEeS7ap6XUSFgO1AFqvwtXA53mxlkQ6QrZUp6LFvdKLetlFm++lqGoN9mYsjWnxrmY5gln9uei9E1obmwRc6RKRWfV5b4Yc0QY6vMSFt5ZvGBzVO9BNtSoQARNVZWMRifsH+5iXU5/mKBSy0luoj+H0DgrWqGslGCtIdEZLnhM8Dx4uMdgtU+WreCDxQsonebh4wlf/eqb/MiPfAHnKt55/y6V9UiZ1o3RVAymOJyZsvdkRJam+FBx79499vaP+ck/9TOkYsDB/kM+evsNDh4/wJenpDpS5bktEMGitUerhH6nw6zIqZxDS0E/1SjhWBmkpFqTJAlSgfexrDjYCMKzrIN3ljRJqCoTmRelqKwjLyu897gQq3V0LUZUKsIRmSWUZUnWTxEydnUVNVDwnrrEPKachFRoKel2U6xzyDrNs+j620yxy6rCy9gMTdYz47Is0UohtYiz6FTVIlJQHkLwpFrVbGXcHiLqaKwLKBNTQOv9HtYUseKocuwfT5hOPcenCTc2Omx3NUI5kuDoJinOx9m1krFSKHgoygprJbZOL1XG1NMegbXRY0coSSdNsSbU4lhBcFAFj3cmPkt1oAjWo0RM/3kpKGOHxAgkfRzXbDCI2vRMy5TEOwa2YG1tjcfFEVcvSULV5/GTU/LK4RzkueXZ7oiT8ZgPOvcYDnpU1rGxvs6TR4dsbq4xHO5yYl2d/ovAP0mh1xMMegM21gYMskDHrXJ6MmWWrzBMN4Bao+QTJF0UXVzkntpxJdbv+DjRwZHoqPcwVjDeN+ztVwSX1YZrKVqUXN65zq2bW0g/xFcCKdaY5YKAno8rIbQsYCRumynPedZkeRyOz77wHuENwqeo0KWbrTLREypXYCvBxJXks4KAw4UKnSY4m3B8ZDk6rFDacmlnlU7X0BskbF0a4EzB0fEkVpNVjoODZ9z67Ke5mq8xOZ2QL451bSnEmWVxIFv4wFmmZHHMXHz9LKCJq/K1rYGKU/EQ0Hi0LBF+zHBljW5vhfHUcHpqwHfwomYh64mOI6aJm7i6lDb7npfwnN/fffmBBiiLvAO0cZmGhWhASv2vc4hjjq6XX1somv2e9mI517k882/FSe1+zdmceXrkjD5DnME/YfHY5vt5Nge5SLU1tHvcD0+rCfGRTZAh0tbR7+RiS3slJUE1Alm5JJJdGgCWHirRHpv1Drcg7m06GZ+9wRdTNUI04rVl1Xr8XM1ULZzz5fO+AIDE4kNbs2kiWlBPZzn7B/tMpmMGQ8HW1jrH430O9kcUucc7iffxHCql0ZooABQe62MBZZg63n37CZ0k5/GDU4xXSAmV09x7eESn9zZf+NwdKlvwwce7VFYghCZLO/S6XQiWD95/i73HjxDe0O2lnE5naN1D2Anvv/0O9z98kzA5pIelv9Ih6fW4/+SAysaS3qybkaYpeTmFEOjIQKYCW6sJiZb0OwnWOJwtcMbjnME5jwixOspZAwTKoqyPD0KIHjreBypj2yfB16BCYFBakySaQb8XRalaEQSkGqRQGBuYFhWVdVTGYIQlVbq+d2p4KURkSESdcqxLlLWqU0QEUp2QJZrZdIoXsXlRkqR1KqYu0a8rhExtsx/kXFSIiCyE8A4dYmeRJNNU1lPagFGCovRMyxmjccn1jT6XVhJWe5FJHCiJsZbSW9I0w6EwXlJWjsp5XA2+pVLoRLdaHmctwVtE0yyw6Y/YzGeFIPjI0nnvwDuU0GQyoTKeUrjagqBO8dVGlAKJkoFUWISZcf/ZPtVqwmuvX+Izr7/Ehx8e8Dtf+zazEozzHB5N6WSCEEYkSnM6mfCTf/LHSNIBxk65efM6d91Tul2Bq6J+J808n/7MLV64cR1vHOPRLmv9G5yWioINTkwGUiNxSFkiQnTP1c5h2gmERwiHCK5mnS29bopWUJYKU8UqLS00OI2XGu80KyuX2Nm8jcnHJAPFbKqpKvAhailkcBBUBMLPmYVflAKPzG9s8KlkXXklYsVVknQZ9jYYTY6ZFacIZdHKo5OUvPC8+85j8pnHVhIfHJUJmCpQmpJOL+XSpRV8KbG2YlZExvjp4wOebT3g+tVXePjoKaez2tuonnzGes3mPj1zAGFpMD0HPM6mxy869njvxylA9JnSbZqH4FCywNoThoMbTKae0YkjhDRGoZoRbwwNYvuOKMhvpAHPA03LY/V8PPeExUP6vgDOd/ewPbP8zu/8Dn/mz/wZrl69ihCCX//1Xz+3Y3/v7/09rly5Qrfb5Wd/9mf58MMPlz5zdHTEL/3SL7GyssLa2hp/9a/+VSaTyfe7K0BzUeoLQxO4iAF6IUUx1zrM82bzuXg4t87F9S4e28V02nkKbq57aYzdYjVNs39xH1v0RJBNUJ0/e6IOso1u5nnMzNLrTeBuzsfieWEhqIf5ZyOQW/Q8WWRRxDkWZfF8xk165iBrvnjvcX7e1Xnx98IOc/aBjD/LVU7NZ1tBLLGbbsOwiDPnvZUYC4kMjVkaFFXO0fEBx6MjrCsYT4744MOPePhgn8m4wlYSZ0PMCiFRQpPqjET16OpVEtUneIUQHWzVY/eZxVQpAhmZFASVE3zw0SPefe8jvvjZT3Pr2ib9jmQ46LO6ssKwqzh48iG7D95nfPiEg/0nPHn8gOPjffZ3H/Cf/93/yv23/gtXOzk/9qlL/Ninr/HZV2+Q5yWnhWFSWlwQdDpZNF/zJT1t2RxkbKz0kdKjgqU4OSKxOT1RspJYVhLHMAt0ZGwS5ozFGoeomzWayuJsNNdzLoDUCJXSWnbXfK61jqoymKrCOwe2AmvIlETLyA4Nuglrgx6rwz5aCqwz5PmMvIhCQ2Ms1kUL9MiyxVQPQiC1xkuJITCrKmyIjEzj3KkRJEAiIc0E/UFGwGGdwbpoQtfIvrz3WBvTJ076qCmSEiGhrEqKylIGzchlvLuf89bDEfePLGObMHWCmYGigrwSnMws+yczRnnOrKpAadJOlyRJSbQk1RKtBEpGBkE1QKnRSTiLxJFqQaokSgS6qUZLiQqgXEAHED6KjCPTAomQaBnF6omCjg5kyqOFxNgCmRp6q54vfPE2L1xbR8tY5RRQGF8blgVLcXrK3XfeQ8uUkxOBkH1WBx1Wh5KN9YztSz2u3VjnyvV1Bisdjg726OqMpHMV5G1mswGgSaRmPXNspacM9YiMCTKUdW8sUY9vHiE8Qno6maabRWfZsvB1+bggOIVqqt1CbBchhWRrbZ3L21eZTMHVXYMXR40o/Izj6bzz7kLAbM772ZFGQPQlcSBialIicUaC0ygUiZZ0h5Ir19bY2VpjfbCKzR3FrIygSwhOT0v2no3ZfXrMycmUrKe4cfMKr7zyKnde/Tyrwxc4OppRlDO2tlbrsaeJUQ3kjxiiYYVinIiNS+vgsMCELCwyWhHEVEycaDReK/OotlihWRvEEesHtfJoVZBqy+nMMBpX+KAjiFgwvvO1FKDmTeP5rcH/YnWlrCs968H23Mx6WYESj+b7IWC+bwZlOp3yuc99jr/yV/4Kf+Ev/IVz7/+jf/SP+LVf+zX+xb/4F9y+fZu/+3f/Lj/3cz/HO++8Q6cTDXZ+6Zd+iadPn/If/+N/xBjDX/7Lf5lf/uVf5n/5X/6X72tf2ssnBI0uYfHNpTSNaNDrQoVOG9zmaus5iBFtCmEOGBare84H28aaXYoF9XbzMC1oPpqLFC9U480aZ42R2w01vT0/pDOHNv/3c9JKza3W6DQaQBRC5OB9EO2NFZFz4zsyvwHreIFUy+Y8Z5cmxRNJjPiP4KMHRKN7uWifF8/PnP2IXitaJ0ipz2xvTudC9NyID/IFpOHizCPE2YSzltPJiIPjXabTCSFYjMlxLqBlH1ud4m0sZ41OiholEoJVYBP6vR28KBlNH+OtQHc7lOU05mq9av14nPfklead93YZdLt8+Uuv81+/9i55lTBIJdXJHma2h3KxssbagA2BsrL0dWBNTnn1So8Xd1bpJgLnBR8dTHh0MOa0hFnhybxFBk9Hw7CTkSqJqzUbZlbQ7wt2ttcYaEk3U3Q6UZxYGsd06jiZOca5Ia8M3jaBJeaXvakb79VlzqI5wc4jpcJ6MMEikwRdB2NXi2JFHZi1CHgRSDKFJKUoK7wXVK7x8hFoINUJGkVzJ3prQEnqgqF65hZZHefBOUuqZdS2qKh7SJVGdjt1WspibQQzSgoSqfHeY5yIs8eaaYwVToGqtJTe4INEK8lRFcifTCkrwe2dFToSRFDIKqZngnXoJJag6yQh1RrvKpSANJGAI5hoiiWlbEuLVf1sSCnIdOOcW2tysgxnLRYX02whGmSpME8Ct5IsD1oqukrQ72VUPU2QntKM6CWSm9cvcf/BPtbF9FLA0++lfOmzd/jxL32B4/0x33znMc508cYy6K5QTPfor2TonqaTdalKwe7uCb6SbF++iu7sMOj12OqestbJyZLApZ4ntTl5PmEqcnJhozEZgRDrnoCAUoFhL6GrFYenJbZ2lvZB1uXHArC163xAiIpE9ZnlKaWR9bQuiseFiExdaCdINER5Ozos/2N5PAgylt0GEZtbhhBN24RIUUKRqoTrNza58coqa/0e06OcYugZ7Z3gTEV30EMpwdFhjvcaYwqm0wmD/oAXbr7IxvAmyqe4qsKWM/b29+kNevPts1DoEPNTUSyPiB3riWByMRWyKB1AQMDVzwMoBOCgvs6iCeeC2B+sFgaDRQOJCqytKmYnU7I0ZZJLLKqOLYEQbAv2FsfO+FRH+wIhRdwk9bjQWFE03lOLGQSWp62tNk0qvtfl+wYov/ALv8Av/MIvXPheCIF/8k/+CX/n7/wd/uyf/bMA/Mt/+S/Z2dnh13/91/nFX/xF3n33XX7jN36DP/qjP+KHf/iHAfin//Sf8qf/9J/mH//jf8zVq1e/951pZyjN337xrYV/iQY+n/m+oPHZO4vqGnX4uU1+L9RiHaRFDVTO03Tz7V90UC1F3ayORcrs4u0vbvfc5xZvmhBLHZ/XQntpPxd0J4uMxrmyNpbHhIat8W6ue/leaL05HRvTSlorzqZ55tuYC3+bffBn8rLteVDgvSIvSo4OjxgdHmFMNHva3L5M1nE8eLiLtbHFgNZxm1qm4BK8UfS7a2yuXyHIHMsJeT7m8tU1OmnGJx8fYytVt8mxscOql+Qzx1vvfEJ/fZ0vfPlLvPnGuxQne8jqBG/BBMnEBKwRCOPoSM9r11d57foqN9e6JMpyOAvc3ct54/09jguofHNtozZidWVIL0soi5yyqMhkYDULXFvvcHUzoyuIbEMiSNMMHzxmBQoLR5OCw0nBwbjitHQEGQWcPsSBxwdH8G6hxUFDlUsqY6kwqCRBSNF6eSAEUjazxPgM9TopWitmeQlKYa3DGItWKqacRJNSVBhf1QLreF2j9sOjkwQlBQIZdR8hkKJRiaSyJg6UCLRKkFpRFAUWCLrWRogQHYxrgCKEiLqWToeyLGOJtJB4KZlWgo8ej5nMKjaHioxAqhSJknS7MVXVzTRJqhHOkypBkki0jj14CpcvGNnVnU+sI9GCLE1aVtLbONLLOpVKXYKMC3WbiVrzE2IKzHsorcB48DIa72VZgjXRi6W7vkLwhkubfYyN+iSVSj5z5zr/+z/9c9y8fJ1Hn+zz7CAlLwQ60YyOJGJV41WB7HS5svkql69+isnpKfL0Y1Y3XqIUHbbWunSVp6NLurpi2A0UM4fBI72E0PTHqT2WRDTLWelIBhlYJzideRwCLyQEhZceGUqa7sAySLI00F/pMsllBDFiPuNuU7wtC3wm1XxujFgalWgqiwQOGeLzraQiS6EsQATJ9cs73Lq6xuhgHy0sX/j8pzk6nuLu77F5ZQ2pY4l4WVYkGi5tbfDirTtsrL1EqAaYwuPCBIGJ7s22ik/Cwvg91+RdtJ/tyEWMBQtCg0DNNNW2niKyVKGdITbgR0V7+2AiMPaejvYMVgRaTSnLCXqwiTUDQkho7WQWQ5hvJo7zc9/s63J63dfXrzGlW2TzaWO0OBODvtflv6sG5d69ezx79oyf/dmfbV9bXV3lK1/5Cn/wB3/AL/7iL/IHf/AHrK2tteAE4Gd/9meRUvLVr36VP//n//y59ZZlSVmW7d/j8RigTUU4788E7uUZecuKLN0czUmraxBa19CluT6LfRzaV78TSGB+ic6Kti7KIV6Y06uZlbObmd8UF7MmZz+78MfS933w4OaVFs0sufnxjcmdaM7xXIPSeKJ813MQQtvR+DuDq7OalgZln9egnD0P4cy6F9uXt58lztiNgfF4wsH+AWUxRRGwlef0xNDt9zk4Oqht/nUEGCFhehpwxrE+XOXS9k1WVzYx/oRhuUFZTTjcf8QLN1/GGcUnd48jdU3tyCoETkumpeOdbz/g9gs3cfmY0+M9hDckqaRyYD3YYFjval65PORTVzpc6liUsIwLydff3+et+2NyFMgINLI0djEe9jMG3QxvLd4Fulqw1hFcX0u5tJaxmjoyEUiFJEs0OhpC4hSEJLCiFWudHuv9HnsnFYeTktPcYAOxtDDEOXik7sGGyPiE2LCFEASuzqU07NucZI5UtatFsomSdLKU0rhYESME3jkqY8myLPKHvq7YqYWkzrm6qWas9oksjqtTJ7XbbB3kBQGtE6Z5RWiEqwGUj8yIEPMqNt8wp0LUQFhTFCVZmrC6sk4+UUyqkgfHJaelZpgIOlQMuhqZ9kkDJFpHjUUwJElSC15tDKo+snDOO1KVobVG1uJDIUTrBaOTmjkKAaVVbZOvMI0AuJ2ohJbtVVphiJV2s/KUaZEwKWdsDNfReh3hR1zb3ubOp14EITkaH3Dn5dsMOhkPH32CkF1++Ie/gBRDPr77bQ73R7z84hXQivWtO+ys38G5DDP5gF7WIeguOOimnmQgkcGjqMjqsmdZW6iLehK42Jelm2jW+57VQZ+PH4ywoam79e1nvGiMBwNd7Rl0BF4EZoUjhMgI1nmQ+irXY1mjQfoO48/Sbx+iU3OY31P9fsLlq1fRyTaHR894+vgZJq94+NFDqtkMJRMO9vdYW+9xU2zTW0mZTMekmWLQyUi1ZGU4YGfrGjJ0MdLjhEEKgZOONOlyfJKfC9AN6Fpk5CPIkO11XloW40bdLmA+GdcL52GhgjTYmr2TdDPLoBMZwMn0iOADlgFeJHGbXLTNsLQ+0aRmnuPAvvDF9rwvTqzDmRj0vS7/XQHKs2fPANjZ2Vl6fWdnp33v2bNnXLp0aXkntGZjY6P9zNnlH/7Df8jf//t//9zrcyLiLDoL7UzpnP2uoLbzFvNswQWNkBbTMYuvidoGvAE3ov3MAlMTxOLX5sF/gY1okPE5oRO0rMtiRVJzYwixvO45ZXj+xlkGSPNthRBV+A0D0exHaxHflKmH+T7FwVyyaNq2yATNacv5l3wNUBqW46JSOSHCudcXS5sbMHTupq5zZOEMO9M+rM2lIJY8T4sJR0fPKPIxSljAo4SnyHNMlbGxvsFkUiCEwhlJPjGUhaff6bO9dZntzWv0OhmneUW/u8Hp6R5HR8fk+bukagOVGIIReBf312FxXiArwfSk5MH7H1OdjiimY6z3mHFtBe8DKgTW+5qbGynbHUGmYWI8f/zxAW/dP6YMKUmaIIRntZ+S51NECPTTHjIYrCkRrmSlq7my3mVzJaGbCFRwJIAW0WdEE708hFBYb8lSRZYKhj3JMJOsdmD32HJaeKamAlQcupRCelqQ0DQX9M5jRCyjbYJpm84TdfuGQOv4KwWkOrIvnSzFWIedFbFvE3X5ogelNLK5H4gCXYkEKREyBvPgHdZZcLH0W9Vlx90QyCuDtY1BHVgX2YtGDB41Nq59LrWOnaSLoiTPS0yQVGiETjkqSowX9KUkSM/QEZlFIaCuHkq0Am8JtShcKklwHqV1M1yjpULrWnjuayM9naKkpKqq2P1Yx/MoktocUcRKoRgnBASHcR4TBJVL6PfXOCiPSdJAJ1vjtdf+JLev/Tz/5T/8a65vbdJf3cRri/S75JMn3P/4HllnyPbVTzE6ecrdB3/E4cljhvue//nn/jyb21+imnY4PRljZ1M21tZxPiV4icSSao+vHCoEtBA16PJQp3diStkihCMRnpW+pte1jMczpoXDtYG4Nr4L8ZxKEe+0lV5gddBnNgtYrxq6ZPGhb5/yxTHkgoHv3PshCGTIkBQI4RkMJStr65ycnPDowVOkKvmRH36NldWUR0/vMg3w9Ok++4djVje26XVSvC24eXWbmzeuE1zF8eiAXmeDbrKCrRIcOUrlIHM6XYG1iqPD2XmiOsyPoRkX58t3AwDx+CJuUy2rJGpBS0wRKSQeREWWBVb7CbYsmE4NRT5lMFyhcFk9Mb94E018C37O9rQ/fhlHLVYUnV3d8yQI3+vyA1HF87f/9t/mb/7Nv9n+PR6PuXHjxhyMXCjGiYPbnKWaD3iytvpdFCGdYzHg/MULiy8uCDFpZpFz8NHuz9JD1rADyy6y59iVxWMQc/Bzlg06rwk5A6bOgp+WoQlt4G71Ke13zoigpKidQ5ddZS/AfTWdR7uP4QIG5TtRssv7ELd99r3mmjfMSPA1UGlmIu1sq/5cgLIyjMcjprN9bl5fhdBn79kBo9EhnRUFwTMdO7To470kPy0oi1hRsrmxwbUrV9hYX4+mZ1WKosvq4DJFXlDkFZ//yotcu5bzjTc+pMyjO6tQElBooeknmunoGcFO2VjrcTKtcIWvA71HectQOy4PE7qJIveSD/dPOSgTJk6xNkhZWRkwmZ7SSyTCRVGbsybm9L0jEY7VbofVjqKr63mVE8hEkKYKXXcPVvX1VTrFBotSgV4Q9LRkJU0YpF32J469U8PRxGJ81IMsagCaZobRUC92OlY6/h0HsXk6JUqq4t9aaYT0OAHBGxKlsVphjCFJk/ZGss61FV9JmuBd1KaEEM3gZO1yHIJDELDGIhRIqehkCZ1uxmSa46yPHZOto7IerRTUHhhQ95vyHq01nU6GUoLZrIhNC73HOIkNCl8FZCdhoGVsgVe/H0RAyuhj4pwFwLvYe6eTdfDO1N2O6+q3Ou2ZaIUNHu9c82TH74fYjoA6fdFqgGRMRDfuoJ4UR4dut48OOVJKrl19navXPoO8vMEHb32TKj/mx37sc5Ruynvv3uX+h0/ITy1lXvDVb77J08NTimlBOSsoKsPaxtf5M/+HL0MnQ44qqsmI4fY6s5lEJ5qmf4qtRdRxklNPAHBQd9wWAgiG1a5iYwjD4ToPn+xjfD2xqrtxyyAJwpFmlpW+pp9ZNobQzTqcjhPCAot7nvXmwr/b18+OdxA7ZvvYiqDbjffI7rNdnj494uhgRJ4fMDp8yg999hargyFHe4ekqebOZ15jOqt49/27vPLqbX74i1/i2pVrfPLgY/LplF5niCAw6GtMljI5LfA+VmftH5zgrGyfifkYtrCTF45vy68tL7XXCMQSbuHamBQrFWMKSwtHpxcYrKSUp47JVOBt1GzJJMXOBCLMxbVnU1CijVvL+7RY5HE+3cNy8GrQ03e5Xt9p+e8KUC5fvgzA7u4uV65caV/f3d3l85//fPuZvb29pe9Zazk6Omq/f3bJsowsyy54p04J1BToYoXKInvSshLN73bG/32iugWqsf0tzr43T8E02wjLK4AzAOMiIDG/KeZMS2upL5ZvqMWeFN8XYl24ueb7Et+SUhJkXU0gGoDSeKPMzdri73gjztF2PGZ/BqAs7l+7Cz4aFS2+17A9Z9M88/XUYk7vn3MNawV6iAzFLJ9yeHhACAVXr+9QzaZc2foUT3bvIdOKJ89GTMcOX3UpC48rLVo4VgdDrl6+xuVLl0hTSylzRFEQgoOQ0e9tkaaOECw6ESSJosxBiAQRIFUJK90UXIEzU7odiQuqDuaGbpYwmZzQ6yquXFqll6VUwL39KXef5Zy6BOehKCr6PUNHK7QS9Pt9xrOcWeXopAlKKLKsS6qTqNRHkEiFAnxtACYcderJk8omhSDRKmpLUiFJhSbTmm4n0Ol5tJ6yO8rxxiN1ivfxXkyTBOdMff08xgWUTKPpWF2eKOvmgVJEFoUQ6p49kUVxLuCco9NJKcpYoJokCcZamsqsueukQEgVgYuKHZRDPdBrraMIOgSCt0ipcdaRJYqpMYTgCHiq0iI6stYXRb1HbHvvMcYQgo/VPUQhq3cea0qkVlRekDvJuDCsG41xCh+iN0dlLfjomBvBSmQJlJLYymODR0lIdUoIFmMNWsk6ReWXuocjFoA20UfINUAggEfhvcJ4ReET8sJjjeTFFz/NnTtfRierSN3l2gsv8963fpvjo6ccHDxjelQxmQiODjwnsxEfP9pnXNpa4JtwdJLzrW+/zec+/zY7lz/L+OQpifKMpwYnHVIqpI4iaKl0dJbFgVA0pdNtIBOOThJYH2g211L2R55JBV7KeoyOHb6FCKRZ4LOfu8WVrR7FeMK1a2uUxmFMAop2PDk7djxv4rXEzgrRntt4TgNKWQKCNO0xGo2YnIK3GXFmFat5jvZPuPnCFbY2tljfqDDmhFfvvMLlK5e4ffsVtreuIIKmyCXPnpxy48YKqZxiyghSrQFnM6azMabytbnhfH+9n4/rzx2j68A+n7AuHl8z3tdGeAKEUIhQ2+v76I806Em6vYR8ZpmMAzZkCHGC1AIbkrieIM/EpvNAhAuASPvjQzshXRh6zxzK88f+72X57wpQbt++zeXLl/lP/+k/tYBkPB7z1a9+lb/+1/86AD/2Yz/GaDTijTfe4Etf+hIA//k//2e893zlK1/5vra3hJDr301wbIDBPBXTgJk4uPlwviy2+f5ieuds58XQOAMKQZsHbB6QeiuCedxswMXiPi8G33m6ZAFo+AZkNSzNfE+FOL/P4oJq8QvL7Jobi7BMg565v+YpKYH0sbqnYU2aNM/5nGo4t62zGpRz+7OgFTpLczbn6LnfCmFBgLtwzCK03w8hUJYFx8cHHB8fEvyUk9EJxewYiWB7exXjDaencGm75PGjPWxVIKhY3+jw4u0dbt+6ynClw+n0GTac0h860FA8kXibsbq5xR9//S4noymmUtGmHoOUmtVhh8yXnB7ss7Wxxszm7O6PKSqFlAHrDFIJggzMSsfRpMRJzXsPT8hDirWGfi/FmcDh0SnDQcKkCJTG4oWiNI5JWdDRkmGmGJeRKg/es9IT9DJNQBJcIAmKJEgS6XDeoqVEI+veMLUhX6ZQwqO1JNEGaTU4xcGppXAVkMT1EdM1sganomYiqio29otOsY2uS0BdHSADLSumpKDCIpXCWoNSkiyNHYBDFScbkeGoxepSIInl4h4iGyLrDuDeY72h18nqfkAxvTLsd8nzMjYdlAJrHVBF/YjUBFORpJoQYspFa4VOFcE6EiUwPjpoeiGZVRYdPAenORvDjIGNVW6xu3T0O0proavzgcl0Fv34VaxwcDVYU0lSi4BdzTBFMayUav46oHUEpyaENk3mvKDwnplz7E6mvLv/lMuffpEv//DPsL52HUUCynPr1Tu8+c3f4pP77/Lhe3d59uQZkyJgnWY2y7EupSoqQseTphJNwuHxEb/9u7/Oz/38Ks/23ifpSh4dzNjebMa7usIvkVhfgNDx+oqAEgHhIrejBAz7irU1jZQJj54eUoVYQSZC/EwMzpY0SRkfnlIcPuHTr14jSzNG44ogBhewyHXcPjdWzJ/9OUPMfExuXhceIQ2dVMdy99xGgKUlSsPGVp/VNcHm5hAZDL2O4sN7D7Gi4jOf+xyXd15EJz3STpfj40PeevtNHj1+xGDYZ3Vwh+B6WFtgTElVBbxXsVlm3VpkYWRbmlOdlycwj1/txJEFwNIIUushPGgEaZ0aDShtGa5Iupng9LRiNpOxjFg4THnIYJjifJcoal4wLq0n2HPH8vm5bLWLS27kAd/W8y/oCJl//nnZqu8HqHzfAGUymfDRRx+1f9+7d49vfvObbGxscPPmTf7G3/gb/IN/8A945ZVX2jLjq1ev8uf+3J8D4LXXXuPnf/7n+Wt/7a/xz/7ZP8MYw6/8yq/wi7/4i99fBQ8sh+5ADOx4xFkYJ5pfzWz94rTI2aUJ5IsB+Hs5uU2QDw3F1XyXMwClDvTtQE5TnHd2tnAGAJxjXs6wNt/Dfi4BjOe8L4XEyzmbobVuwcmiNmS+z4trCy2D0oKUC/ZpMWvZnhsxTzM9b1l8aEJDVYpaX1QHQeccp9NT9g/3mOU5wQfef+8x21sJW1sZ9+7f5eGjA4TqsLU1YGfnJkWek6aS4YokTTUbGyWddEbpDJlKuPHCLYTU/OZ/+Dr7u2M++vAxeV4SQoqzgIizko4WrPQks2dHDLsa6+CTxyeMKwuhoqM1EPtlTHLPx09m9NOUylvGZSDpaLJM4mZjhFbImlXIK890ViJ0QhACUxmMkuSzisPRlExDRwk6WrDa02yuZqz0UhLvGaQpawPNsCvpZwlSxi7HUgDBgvB0M4FOYtDJZEKme2QqZ/+kYmorhEiiaFqn9a09L1GOM1ZocKX3jqYPkVKNYVO8j33wpImK4lDfCLXj3SOlwrW26aHVi8S0j0dYWgBdWocEBp0uztuYQkl0LCfWEtXLyEtDmqUUeQn1LDNJNEJpsqxDUczi/VYDLSEUSE9wETz4EKhcYCZgd2xY6Zf0dOxZ0ksVwVekUtalvQLvLMY5OklMxRlTNx+shYcOiWy6NktJEOAIrbYnhBB9W0Qsr7YBjI/mcGUQlMDYQGEcX/mRH2Xn0nV6aWx0mZtDOr0O/cEK1lbcevEVvvyVv0g2vMTdj7/NG3/0n3lysMtoNsG5irW1LQgWrRyPHt/jD7/2b+jLDoncim0VfGiTCoEIPtvnNThSYehnFjHUFDOHlJaNtYxeP+P+gxFF5ai9E+pnPDarC9IzmZR8ctew2Re4m4HD44oiSDr9rAa1or6/qIPgxSPWWSHmYlBtxzIpSRIFwlCWOS44kJYkswQ9QXcs25e3QXmOR4esbAx49c4tnCjxfoZOYHVlEB1/MVy+dgmdaqaTCuclIWgCGR6LFwYfUnyo+/6cDUcL8WQOCEJ7fzTNQdsxfmkcXAQQCmgaKDqUNqysZCSJ52TsKHOJR+KkA1fgzYxe5wqjaUogJWAXTiKEJR1j49k1ByTNM95MDOeAhZY5fN7y3VL7z1u+b4Dy9a9/nZ/+6Z9u/260IX/pL/0l/vk//+f8rb/1t5hOp/zyL/8yo9GIn/iJn+A3fuM3Wg8UgH/1r/4Vv/Irv8LP/MzPIKXkL/7Fv8iv/dqvfd873yyNMr+hnWjYkSbg1WGw5lTmyLRlKJ63Ypaehe8UMC9K1dQ7F9+/4PNyIdDP004Nppk/XOfyfHDm77OVMMufWUS1i9+bv75wfGL+72YflxkfVYOUdg2LR7Ww76INLg1A+V41KFLJKBhUzy8zZuGaz787T+t57ymKgqPjESfjU1yI/TJGY0dlpmxsXSNIwSwvGZ2c0B8cE/wply6vMxxu0u1qSnPC6fQTkgSkrtjaXqXXTzg8LJjOorGgNYLgksgqyOjboLVmY2VAOT5BS48X8GDvGZPSIFWK8BZbWYyNFTlCCnanhveejLGVw0uNLQxeKIzX9HSgIwVKaQpT0e12IAQKu5BDVooqCAprObUekQcOcs/DkwlaejpKoRH0Usn2Wo8rmz16iaCbJQy6sZlggiNLo5dHN4ksiFuJ11UrzdNRQe5C1NfUfj1K6dinSMQZ1SJglFK0FTOEaJxo7bwRpaqra5JE4VzAO4MxhihUtnjVAPelOwQhYlo4CIFxHhUCs1DSSWXbOyt2jI5sRJqmFNZjfdTmBARlaaKo1RmUqtmQ+l7VOouMgfBUpYm9dURsARCE5vHBKZcHGQoIwdCRUYeRJZo0iQJeQn0fK0ljKGSdJUs1EKuVQm0+pxNNk9YKPj6vVd1Y0QeFQ2BCBCeFl1RIJlZgvaYsZ3Q6cHJ8wMMHT/jGO1/n5vVbSGWY5jmf+8KXuPXSn8LRYTx+xtb6EKEdx/khuc8RAlKdkXUDWgnufvwtPvvaj2H8AOOneCHnE7660kQKjUDVNmEzBt2Kl2/c4Gh0SJIk9Lswqyy7xwUOFbUO9bVr7wcBiRL0s5TVYYdO0ud0YqEv0TiSxarK0MKb5g5oY/bFuobzbG4IDqUgLxzOefJizO7BU45Ge+T5EWlng6IwFNMcpSTJEI5GR2xe7vLJww+ZTgxbn18DbynzA5Qq2NxaZWNjgEoyXKWI1QUShK9ByvkUSByullPri6/X756bQjfDbQgyVgsqEPEOBFGgs4r1tS5KSE5HlsKmUTtGwEuHcCdoAd6k4DVO1PcozQT4rBXE4gQwAhUfonuy8/EcLo7tIXC+AGkhfp6NZ9/r8n0DlJ/6qZ/6rgHmV3/1V/nVX/3V535mY2Pj+zZlu3BbsmYf6p94jRsKbc6vxMA7H+za2Dr/9RwWYR6oFwHI2X83S/MQtcBHNOApnAvlc8qh+f4i1TZnFpp1uroSIjRVQogaHzTfWVzXmVKuFpjU8uv6YWi/0dSvL9W91yi+DiTOzXvznPVCEbVbbliYuTRU7LxSKJy7OUVzkln+EbX5z2JjwkUQFUGXiLPMtmQ0LJxTibEVJ+Mxh4cHVGXteBqiGdpsVvLbv/MOMKM3HLJ1ZYvRyT75NPB09wm7e4cMBwN2Lq+jZWQJUi3Z233IwdETKpOxtZnijaGcFhhRk3d135rN4ZDydEQxPiTTltM8Wr8naRJ9PxD4un9NqBydVFM5zyf7M4YdRTfTOG8gEWQ6IdOeThKvUzfTrK+tMJ3MMKNTog4gCihlXY1CsDFdoFNmtcZCORVNvvLAg/EpvSenZCogZaCbSnqJoJ9Ibu6ssTbI6CSSVHdZG3p06kiSFKU1uycFuTUIER0+G/+DQC3ClXHQjA7CgujfFjUXPgS0VnFWLhU+QD7NCaHxXzEEoh231Kq9n8+Cf6liJYz3rhW6Vs4TqkAnS+swUXdSBlSi6SqFEh1mswprPWmisc7icSReoGRsUilFFKwmaRbF4UJjjaG2tsGJ6F3z3qNDXr15mcwYnBakKiAVCB+BqpbRUTbVmuAtxniknKfD5AIb4axvBd9RMQPG1QECG+8VJEiNCwlHpeb+8SGP90741/+vf83Wxior/ev82//P/4O0L7l1a5usl3H45JDReITB8fTRe3zwztdwZsZXfvSLTDjh4wf3yfOcmYeB02wPV3C5QZQJIUkJYlZXwsXuvniBCBpEQjRPsyTC0e8q+j1BN/V0eoG0l3Lv7iGV09HAEE8IFV4EAhIpYgptZ2uFrZUevpwwLTzTk5zVTuw55IKIpdthMVU/T3kIsTzeydonppkcNTatAY8PDoTFhpKyjF2inzx7yLP9BwRluXrtKonUfHJvj6tXNkmzHr/3u99AJJZXxE22thN++3d/h4Dlxdsvc7B/j/HJLt96e487r36ZYUe1QIqFMU7KqNFpRvNm3xdBy9IEsTHrJLJMktiPjLY/TjziUJuSCglKlvS6hvW1DO8Co+OSqoq9dxr7thACtjhia30LYzv4oIk9yurOxRdMgIG6QnKhPN+7mEL1y/5WvtZzhSaMNMfGRQDyXCT8jssPRBXP85YQmpMQw20Ioh7gGlupGOxCA05qECMWWQZCnd++AKKIwLwh4XdPnTQhP4S5KiQ0ebkaVyyCnXgDNn/PK2MCZ/J3Mr4WWKD+aNppN4wQLD6w589VFJaGaPHKwsaYg5PzqTEhRdtAcC6Upba7l3jfVCI0DNUiiIi5/VCLWRdZreb8tp7kTS4zDt1E3Uv8PaeI53Cyud7RcbTJedavWcc0n3E4OmQynUQ/DClxtsR5R2kCVQmVcaTTQ24NNzD+lN6gS+UU+/unHI0qHj8+4eqlS1R5ygs3L9FbX+Htd9+Og1xlePH2C4yOxkwKSwgKJSUbwwHCTDnef0oQjqIKOBvz3bI+p07EQCVstF333qOExARBd7iCsFMyJch6GmumSJVGcy5T0hv0YiqjscRuQKsUseeMkkASqWlXgogzXoSKtDYQguLUBMYm3p+qkig80lvujQ5Z6Uh6SrCxkrG90qHX7ZAkGVsbKTLtsH8yYZqb2JOlrmLxtS12K1KvAwZCYGthoBRRiyFk9FExlQWh4+AmZF2t0ggJRc1m6KWZnFKqrR4RMpY6N/emtZbSBEIiUSGeU+8MykewkKUSrXuMxzlFVRto+Qh42olFPRUMzkYCvTZWE/Uz6IMnd4LdKbiHh9zY6BJ6ilUlkUmKSgTeRC+MRCckSSwFtaZCSh01N6EOwCLe15WxUQOjNJX3BKkprKsnFNErRGiF0IqSHvdPKu7uHzEzgYcPjvmt3/wtvvKjP4HxOQM9ZHV1k5uXP8c3fu+/8uTBfTa23+X9t/6YtW6ge2WTze0hdz71Ap6Co5OS/cMxVQ7rocf1zaskXlKG2IaAEKuVRB34jYW8rIgaIUeqJcN+nyePHtNNLMNhh9PccXxiCKETx8QQxzofLFIINJ61fgdsxcnxlLXVIaRDBFnssRSIDBZu4ZGfs76RSmg61cexJwbI0I6FEew6ZvkY5w1ZBrPZMdYN8ViELNnY6LBzZZs8dzy+/5SVjuLKpUuAZjYVZP0N3n5rQqc/xZop3373XS5tb1PmOdsbV/jMnVtsbtyMEw5v2wmyQCKCInhbj4f1mBXmE60zo3M7rgkEMkRrxDkY8+29EP8OSBHQwjLoOdZWUmwFoxOPsRk+zg7rNXt0qKiqCUrtMK0SPBpZO9e2seFcmqwBHra2CYirdM5jncV5d0Ej2HncmouT54HsYtb9Oy8/2ADlzG9YOMHNIs4kcc7E8IsErGe38N30J4tq61bUtLC5Vqjbghzav+f9b9zSupYZkMX9e57VfmigOTTI+4J9bpmU57RhWqQe5zOBeYqnMbZaTE1dhL6BOCN0bkkoNv9cc1BnCc342lkflOY77exDCBayB+25hkBpS07GJxwfH2GsoXleY8rJYKyp+8EEKmPY35tyfFjSSwXrl7r0upbjWUFReD48ecju3lMOjna485kXyZIeDz++R9KVvPKpPiubK+weHpMpzWq/i2LG4d6TSNjJBOcdxlmkCHSy2AgvS1OKokAB/SzORoVOyHOLtQUbwy6ZIvbbSWOwUlKRph1Oi4pxXlEUFa72BnE2xC6tIuCrqBXSIiHYWEYsRfSLMSY6rkqtcXWnaGc9Lkik1AShmM4se3kAb9EHhh6nrA06KBUb7Q3XBmT9LjPrsE7gvMKj0WkEA5E9E7EnTnDRu0TF0mFBBFLWOUxRodOYp3f1dVUqtjZwLnZSbq5/2y5BiAX/kphOkkHQTTMgkFcV3lR4L0mUYNDrxuAqau8RE51vB8MMYxyn0xLrA15EV9kgJFJFti+K6AONWLe5z62N/ZaMd0gCOItf74CTdNLYtVkEMM7hpaRyMT2mE4nzDusCdU00lQ/x/DtBXln6XY2NXXzqubRASI0Pcbo18Z5HM8e3H51wPK5AC/ICvvmt97j98i2+8IUvIIBOusq1K59m/FLFt9/8N3z49m9RVQUbl1bodLbRynHz2gbGXuPNdx4gfLT931pf49XXX6G/eYXDaRclJjVLr9txIPayKwkkaGmRncDqyoCPPnxAomLLiMcPn2JtEhkTaSPI8VFwL0VgtZ/RTRXGVJS2wlKQHZ7SG6RskMxTOKEey86MgYuzdOr2DgFLwOJ8xdHxEVVVsjocMJ0dcXz0lESDKS2rKzc4GT9jbVVx+eqLlMby5NEDyrLg5qsvsrW5xTe++YjTE8nRcYnxsLKmuXxlg7sfPuPq5Q+488oddncd3ZtbWJNgTT2O13bwcWd9+zs0yCQ8J70hakPEkCC8QAZLUIZQH6MkiRMMGe+bFE9CxWrXMugr8tIzOk2wLo2TuhBTlo6AChW2GpGkniAUzqs4UUVAiKX6Z52+W71JzZb4WvgdUzsRTDc/pgbXvgYsi8FYsPTnf9PyAw1QmoAUfQ3mlrtN2Sq1hoLmp/3OnC6MAP/5WpSLc5zN6p/PptTfvhA8tflGsQxoorjz7DrDwg0+D/IR88R25gjZZn0WiPDngJNQU+zPARULYEMp1d68UobWSTZqQ76HSh7mKZ7FfOR3Wpb1Lot07pl9DWeRfxw8nXPMZlOOjg6ZTqcE72IKwVsqYzHWYkxV/xgQivw0wRYDpBqifIdUVyhZkDtLmsDKeo/jkzH7+8cIIUkTzeufuUOv38MYQy/LWO33KacjprNjOplmXJXYEEt5lVZoEUg0JKjIDEjQIkHWzJEzhrVhl16m6KVdZtMp06LEVpZemuACjI5nVM5ifCDJMmZFhVQBW+eBpQAZILWWbidFBOqOxLHcWjRMgI79fZyLbqypElhjaO7XWOmmMUgqPKfTikRJwkmJ2i+QKpafI8CHHJWkyMoTgiVikMhUNuks56KQ1piyfQ5tXT9bmTohoySVtUtgwHvfirKVUm2FS3P/KxlZqaoq0VqTZRnOWYy3SJVQGEeqE/KyQItYsuwJ0TY/UyRpj/FpSWU8VWXpdDRKEn1KbNOPKbKhSskIZhwRHIuEqQNZOuTxjOAkWSJIZcpqv1Mfq6QsSyoR6HYylE6iOZ21CKmRKnZWDlLilKYwHi1TSiuwIomzXykwQTIzCU/KDt94OOXB8QlBBcARvGA6nfHRvff5qZ/6CyQyI1EDlB5w6cotvvE1iyhP2N68TJL0ybJA5Wf0ul0uXV6h94li2O2znna4evU6V26+ihEp9uSYRBnqDjFoIIRYJq6lJEsSpCjpdzxFOSV4Q3/QY3Rckk9jL55A02wumuZpLeh2FSu9pE67KGYl5N4iDk652d+JqSxEdH1tJ0C0g0ecoNSMrwh1QswzPj3g6d4Dnjx7yO6zPTbXLnHl0g7e5Tx5+jFaKF558bMc7j2mKkdsX9rCVo5Bb41LmzPSIHjhxi2ePD7m7Xc+xlhN5WK6xRnBzes3uXxVsDJcIy9KICH4BELSjkVxf2pQUvfIWWJ9Fya6c/PKOudD7Z0lAsi567ColT5BSLwIaDypNqz2A2uDHrOZ5CT3lHiQ0SxPBRe7eCOQbsbs9CmbW5uUVgNJzeRaRKhT08BcazLXnlhn6w7oUXNirV0CKM45jDEUZUlVVefWcXZcb87Fd4+b8+UHGqC0S8tKzctov5sQZ+kkNZSxWL6Jvv/dWGQxmhTKfH3LAf1MPxvRfvTCfVwUADfbanB6O5dY2MZcqHqeYXoe47H4frP9xjBLKZYYFNVWIJ0XBy+yKotOsg3DtKhcb1gh6nYDbfqr1r7EDrf1wz9nENtr3OQ+g4iMTVEVnIxHnJ6OcdbUFuqeyhiMcRjjsHWQsDZgK8Pj8T69To+dF27xyqsvcPfhmxwfvkuaOS7trBBUwAtJaTypCrx85xZXLl/j8ZMTsLA+6HI6OmA2GSG8iZ4EPqCCiQJIpRDCU5qyFlxCR0uc8ZSFIe0m0WkUz0qq6KsSkcaKFOk9O2s9xpMS3YseGNPSIBOJFhmlibR509I8BToioJyjtLHyo0nCSRnQzoOujatkQIrYVCzRGufiAORpGt1F7YgNMS0UUATroyeXjCydMRXCGFTd3TIQm0s2DGHwFmfn5Ys+RGGtF4DSqERQlmVssFlXBC3eR9bapedy7hsSRacNWKkqF9MnzrX6lmlZ4kMW/VuUQOoEgospKe9RKmFtpc9onJMXttayxLSLRKCFXJpdJmmKUJK8KAlIrNaUImFsDVkR2LQKGxQuiBrcRy2NsZaZCehEkecFxlSEUDIYDKO3iQNCQuk9lTdUHjwS4cFoOAkpHx7Dx6OcNz95xNSWGOHrJotxxl7Yit5KD+kTKjPGckDuD/HKMpsecP3F1ylNh16/x+zkiMpKVlcvc+PKBD85hLxgZW2by1d+iMJrnux+G2eOED4ChkAEd8F5gpEI7/HmlN5qwsnpKUI6ku4qew+PMK5JlwlEUCjhSJPYmiGEAuMMzsN4WlC62Cm7U3qQSZzZC2rgUSeOa4AyD3LNPRID+XhyxB+98bs8fHwP4ypev/MZPvv6D6OC5Btv/BE2F6hMsrv3BG8MK/0es4nheHqK8/sIY7nzyg163T7/9Q//mFkB1jdFCwG8IU0kqysDdnZuMBodEUSH4DXBN0ZsUTsjIKbEhapZ8WZfl1nvOfCq3w0RyAVZt3xAIENdwk0sz9ZUdFVgfSjpZJqTU8FkJrFCgbCx0zGCIA3IHFfOyE+eocIRg/5VjqeCIJpiEg/12NlodxZFr865OSCpQUoDSiJzYlqgUpYlxlb1M77AxFwYYS7IcnyH5QceoCxWqcxf47zzewsclifyof3/WbbhvA3wRWzKcrrlLAgRrT5jsadPW8Ug59bxona4bFMY7TrqPq++AQ7n00jPPze07MsieFs8nuZ8nE0tLetuYjBq9nVRLPs8kNKcVu+jY+biuRNCtIBwrkehBSLNOVJKRX2AqK9QPSto9tOHmoIM8UGzzjGZTjg+PiIvZvgQNQPGllSVrcFJwFqPsw5rLNY6EpFwafMyt2+9zK2bt7m0cwkhuhwcP8Aw5vj4lEtbW5yeTuj3NK9/+jWC6XL87AmbvTXu7z5kOj7A2xgsy1kBwUdQh4wdVAEhok4i0xrnAzpNSJJOnKVUBakUXB1oXrq+SmCNh/vHTI3CeY31nk4vw1hH36a4IEHE4EdNxwZr6WlJpgTTyjGTmpnxFC5qPIJ3WO+YTqbRcp3Ickggy1ISrVFCYm1M1XgbO6eGpv8HYEV0Sm3Ec0JInPWIJIn+J7UfilIKqQXexuqeJM2wtW27rbtc53lB0wl1LrizbUn74qAZvVXmGoPaRqStkgl1E0VRV1K5ICgLi1QarRJCXUzjjEcFCDYyr1J61oddZJgyKytA46QgkUTdRwiRPRJgXfR5yRIdZ5QepgZU1iFHcJR7Lm1kVD7QTRKMjzqZmZUYG8DAyYmJz7IzrGLiuXQBvCPLBODQtQC5ECmn9HlYZXzt8R5jHwg9gcwtiUiR3pEqgVIpT56N+Nf/2/+bK5d2uLS+SZoFnh0cs33tKidP77F/uM/K2m2uXP80N++ss7+/y+7Bh2i/z+ToLv1Oysuv3yEddJmczOj0ekBMAURTtnrmH2ui0cpRlad0sh1290d0Bz2eHE44yU0En96iQqya6nZT+j0JwmEd5FVgfJpjXMCjULXQm+DnrGnLKDTD9uK4FAOhEIG8mPDue3/M4dFjOl2NqCxZCicn+0xGY4wtOTo8ZrDSozPoMOylDIYZdDWlmjEeT9jcHHL9+gZ3P3nI7kGO8Umc2LTVRzH9SEi4e/cBJycFly9dBpL6fowgsZ14BQW1jm45rb8Yp+YVjyGEKK4WYKk1RyKglaObRcZEkzNMUzbXMrKO4nhsmBUypoVE1FsJJMbNOJw+RkvJ9OiIfHSf11/ZZmVtjaNC4E0jfBWEmpH0nqWqnOZniTGpf4cQU8UNQGl+N/5D3wmU/DfM+X/wAcpikJvP/sM55mDhG7SiBNpkT/v9drZWf+Ys4Fjc5qIQKIQQU0sLQAiW92EJzNQ/iyLZ+F4DlkK7Z0vbbdxk29QPdTXTxcApBvJ5aigCHV8HnvOlyxed18XjVUqRJEnsl3KmBPgi/YxzLuoRvkNH44t0P0pFj4zWyK5N6IV6MAutgKvJfhVlwWh0zGQ2qTUQ8wBnjKUyjsrEQbJ5IEWAwbDHiy++wLXrV+n1+nR7K/ypn/yf+d0//Le8/d4jvIc8j83ktja3SbN17n38lCd3d9l/chRn1C76Z1SmwgeHVrG1uwvx9eA8wTkSBd64KAFS1Okfy7X1DneuDrhzc5PVjmZ8ckrVkewieHg0Y280I9Mpk1lFf9gnnxWUZYUUgk6mSZRmZW2Vjgp4U4KSdKRGz0p6Poo9o1BTYEyFF4LKeLRUVMZRVpbSRJGtqHUUkY1ICMHjjEWq2oSNSA1LqWO+Wzb6DFcD2BjAg/BRj43AWR9z8AS01hjTMHxzb4XmuhPA1RU6i/dhI4Rt7gmlFJmOrIkjIFTMvwMUpaGsPEJVpElCEQyJVGQ6plUkkcFKEo/EsTaMA70LsdeWsR7vLKmWqFhPHD1RvCNLNd7FrsKTSQ6+Ax58ZehmituXBkidEKoCj6fwimkF49mUvG5m2NESJyu0ACWiC3FRORSSLEkpZcIzpzkSfS5/5kcw9/8TZjKqPXpWeemVT5FPT9neXiWvct741jt8fPcNNjZSvvCZOwyGKaUJ6EGK7G5weHzM9Rs/RNZbxyerXLq8Q1nCycH/j0F3hSvXN/n48ceMijFr6zvIxNTjRkyhBGJFStSvWTodwcowI5/lTPMpqFX2R/t1tZFH+UCqA5vrK0hhsS5HKc3RyYyJAeNj6iLG9ijCjSm1Wvwtm8Z5zXjYTMoaNtUznc54+uwhx8dHbG/v4Jzngw/e5YP332X/2V5dMi/Z3FlluDJkkp8ynVm8XieTiq1LGduXLkHpGc9OODw+xdrI6CBUfayxgjJJMgaDNT76+AGD3g0Eq4TWm6WWGNBMBOuUc/tDva5Flv7MWFiXcNfKJ7xw6ETTSQVbK4J+N+fSRockFYzGFdM8MrMhxHtGBIX0Hu/GJMmEtcELiFnAyYeUVUlv2KU7ElSVjTHAxyILH3w9FvoLwEnDNscUj3ce6+bMySKj4rwjOmzPY00css+jkv+hGJTF6zxPX8Q3LgZsdVCvBz1PkxI6y4acP4lnA/J30qc078//vfh3sw/RpXUuWBUt9RPX2yByUVNxoa4EgqgUlzTCq4v0JovrbAJBUxJGQ/UtcCpn0zvNMTdCwWWhrDrHoJxNkQXmDMo5zxIW9SXL+zxnmhSy9UKRhNqNcp49czhv8N5RGcP49JTR+ISqMtGDw4NzNWPiXGRNGnGXjQ9TmiRcu7LD7du3WVvfrL1MUpRKORlPcE6gledkNGG1u8Huo1N+e/8bPLu/y/TwhCrP0TIFnZFXJUp5OoOEEKJIrTIxMMsgwVkEAa0CWSoJokSYktUEPndtnc++uEG/k+AcaCEYJILj05xUBDItamGvZXwyQWlNZSJLY2YO7ypOJhUET7+fgpB4XyGkYLWXkqaKTtrDOYMP3ajH8TDLS6yLAlHnBUVVxd43zT0jq5iWEQLtBWnQ4D1pkhKEhxpQSAKEuqqrufYutqmw1rZsTTPHalJ9TcomNuyrdU9ubvYG0c6+SfVEgbZYYgaVSkAGyqoiILA26heUjiyTC+DqZofGlGRKkyiFMWWtUfMoJdlYG3JyWlEUJVJKqmbAFQIlQ/TRFaC1jJVUIvqclMZgul0Kqbi7O0YnmtEsMOwoOt2Mg9MZe8czJnlFlqT00gyZSPLKkmiBtxWDbEhQPUqvMaHDTHZ5/2jMRE1ZU5KymJAS7+f1zS7XrnRYX7/GxqVVHj5+wh+/+S6z0wCUPNvd49nuXR4+/YTtjR2uXHsVUaX0eisoleAIzKb7vPXm1wjeMlwd8Ox4Fz4IfObTr3Pl+nU6XYEjIXiNCNH3xIcSgeVkvEd/0Gcw6HAyOqbT6fFo11JWTXWiQ2nB5noPISpOTycEIammlmkBhuhwHJc6ASliYSyNDmpp+I1AqU3/1QE+SVJu3niJS5euQPAcH424/9Eu1aygf6UHsqAoKpJuyv7xISqJTNj+eAonOdevbnDnzovsPhvx5MkRJydl1MYQCCHOIGLlI8yKgsPDE1648UOYaoUQUmjHsDngiB2YI9hYAlU0B3V2QhgZmJjaiYyTDQEREkwlqIoZnSRnZZiSZo7TWcnpDDwZhJSAiRVwQhPEFKGmiHCK1jmVOSLpVniVcjIdU1YZwSd4X6fZfSMBiAXJzURhEYAsgpA4bhqsrZbeawsh6meljQVnYuiFwOy7LD/QAKXRXMQOw6JFoc87B22KhDPg4gzIaWdt4mK2ZPFzF2tW6u8ubGtxiVR0TPHMRYGiBZwNM4JoWmvPS5XjdmQb3AVRGNnoxs6iskVE34KyhR4VNVGzAO6WQUoLFORcgzIXyl7c8LA93mZ2vMCeLKZ0zqaGnrf9pmi7MSZqBGneW3zwsSpkNuN4dMRsNou0dGj0LwFnqXu/GJyrsLaK5alBsba6zisvvcqlSzvorIeQsQmfUorV1W3S3UfgK5To4QpNXji+/dFbVDNLN5GxySyunZnoJF4zJQUJAS88hY1plFR6Lm302R4KhlmgkwpSDVfW+3zq6jqrqSQ3JdPKErQhSQ1XNzOGQ8XxasrMGILvYGyc4U/6UV2fV4GyCjjnmRrH0UmBcbVtlAj0u4Zequl1ErQWZFnK6iCF4KnSWPKbZB2K0jArUiZlhfFQGU9exXSYkAJLwNuKNFEYa+I9ETxKx0oirXVrxNUA27IsY2uJ+j5ItcabKIXUSlPVbpZJkhAr4OeD2OK9lSRJe19EkbdoGU7rLC7EO8RaR1VFkLS1tcFslkeWDYXzcQD1SuGlQNb6IGdjqlALx6CX4WyFcS6mnqTE+nqwtR4pAnlRkihFmkYAnecl00lO6GhMqvn2wxE763221jr4ccmDx4fkVdz2ai/Q7WaUIaAAE337MT7DihUOpYDBKqdG8s6TT5hMJmRZxrUXNtjoD3n09GP6g6h7ePfdj6nenfL5L3yGF27ucHj0CeUsiqlvv/giQXiG3T46qxgMh+zu36XCcTjOefsbv8/es4dcu77JW+885enhAZX0DFb7XL52lay3SZKUMb1TX5EQLATD/U8exDYOqebytR0ePC3YP9xHWNDB0hkkDPtrTCdHlKagNDArKqxTOJ/E69oy3LV/laC1NBDNAMHymLo49kqpYhNGpciyHiJ4uskqr9y+w+n0CXmek3YdxhtG4zHeCabHJYWxrK0OGHQCw5cH9LOMTrrBowdPOTg0eB+N6WL6JSHgcMFzfGTYWO+RiD5ZNqjH61gK3TC47cS4Br3xCTwzeRQLDP/ipFUIEHEMUUIggiFVcOXSBhvrKxwc7fFgd8L61g6D1cuMx3GiIJSIjBKGrAvrg03WNq8wPYEP3voG165u01/fYTxWVEWInbxDfS29bNPgjbdJAzwqE6sdzYIYtknnOBt1Kd77OYBxDndWVxFYAin/Q6Z4gBZgLOOAhRTK877W5MUuJkyWgy3LIORscF3UoAjx3FUuf67RnjRet4Ll7S0JrOJPqJ/mc4G8PeTzqR5RgyWCqIO2W7KsXiwBvoh+m+tmFkWyegmgnD9G6oe87i8SFt9v50ntds9+r9mmqIWay9eioU4DzlmKsqCoKsbjMcaUhODnMwDjcIZIVTqLdRXORR+HTqfHrRu3ufXCiwwGKzElgUBqgXAJd179HA8f3aOalQyHqygUxWRK4gSVCeS2RCWKEKKrqRSC4EL0LPFxZlQZiwyBjYHg2kaHF3d6DJVhkCo6iWJ12GVztcugo2s2qIKqQnnoJimJFKx0FZdXE/LSREFl7YFjXZdpWeFFBE7TwnFaOPbHJaOZZ2YDpY+unnllOZpG51CtNZ0sbj+R0Ms0iapY6yWs9VPyMm5rMisoEknlJMY4nAfrYwVOwJPWVTS4QGUqXPDIutqmjkHxPBBTmFJGBqQqq1prUN/5AqqybOlwKSVNn6umYWBT0dM8s0LoaEFfxVSEVBpRV8F570nShNmsYDrL6XW7mDIKarUCHQK2smgZ022xLFOC9ejE0e0muFmFIzbKjFJHRSCCV1cHhY6GLJHIkFBZT248eeWYJjAuT3l0XGJswPgMpRKCMZRTR+EnrK8N6A062BDQnQFGZxwVnjGGTjcG0pmZxWaRZcWl7Q5rQ023c420lzCrPAcnJzhX8vjRAdvbO2TJQ4rKk+eBfv8qL97sUk0O6Q3XCJXkrTf/iE/dqXjy+JjDJ4/YXB0itWBle4XHx7s8fTKiP3jG/5+8/3qyJUuvO8HfFi6ODh1xtUidWYWSQEGQANlk06yH1t3Gnj9wHmbM5nVsxoxj3ewmG6pQQAFVCVRV6rxaxA19pIut5mG7n3Mi7k2gMG9JelpkxI04wo+Lvdde3/rWun3nFXtbQ9JUgHBEsWcAao6OX2BryenJhCSp+OA7H/Lw+TOsD2RK0O136HQ1F+MxxgkWpaQyUFmJJx43GSKr6CAyfaLRSLWmm4hVkN2yzLQ+NkaPHSXb6ctiXUUIjmsHe5x/9oj5YsFQpQiVgnRcXEyYzwqyjiLLJVka84CSxCEwiKDxIY1zRtuBI2KLtHOaszPL/m7CoJsR2utlbWy+zCRDZHza49aWpa4uwNZBStP0IARKWAYdx+98eJ33371GUVpqt02S9RCih3Wx1Kl0u4B0IAv2ro14/4P3UTLj7372K6T0dLtDnNvl7FTgrSZgo0eMlwTnccHivMWaqNGr67rxEzLUZsWU1LVZalJa1sR7u2Z7f5UZWg7va2P7P489gf9aAEpbpqE1jFrSAq8/tOUOw9rkL1bHcoXSr+D3byihXNJdiADNzeeXoGDNrCM0XSdr+y1EkzvTBFRGkqd5zebHIJpSlF89r33vpX5FtPv8j3fo+NaRdr0eGtr9e3OZR7RlpSWj0ubyyEv78drxCE3ImbUNi8JyP9uy2ooaXT+mcsUOCdGslv3yfAoEwkcatq5qJpNzFkVBWSxoxZtt/bRdBVjjmq8o6FJI9ne2eeett9ja2UOnCUiWds4hSLTqsdHZRShDNZsxm4/BBzSBTEsMEut8LI8EjzfRj0QisDagJOQqcG1Lce+gw42NnEEa6ChFJiWdLGFn1KWbRUas9gFvLKmMLqhItWRpnHcMdBJLHYAgJt26vsYFMFZS1QEbUhaux/ms5mxuuCgsk4VlVnpKE4d6ayzjynKBIFGgJXQSybCXMepmdPOEJFMM0pzaCSxQ1haHoKgs1gtmsxKCpK4cSiucA+MtQkQdS6IVQki8ddTGI5RC6rCsV0uVNNkzjeNmY+xmnSfLc7w3hLYDTAiCj8nAWkdjt7KqERAneB1FpYlOsC6QZClSamaLEms9ZWWQQpGmCWW1YDor6PUynBQYY8h1gnchAs1gY0uwkixKg7GuOb/xPAgZjdYIUFWGTqoYdHMqF5guKuZVhQua2kGBZLi9R280wDmLsBVaWXyqKHtd6iya2F1M55TUFAhUV2EWC8pFgdKOt797n//xf/q/8PO/+k9YV/D+O29zPrng+PljRsMBxycVf/03v2R//xrvvXObL798TjEzzGeWd9/+Po8ffIpUgvliwqw44+c//zPOTyw/+N7vs39tj48//zvSTLG/u8nh83PGpzOm53OkOcZUhtAJwAItK0p3ik4ruqM+Jy/O2d/v8/TpMafHc3ItSHsC7ysuJjMWhWNWeGqr8F42KzbXTPrN5N6awDVGgpfGy2ZQCKui4HKhIog+H1H4A0J4FrMJjx484PPPf8OimpN1BELCYNTn5as5k0lJJ0949+0bbGxkeFPx1cOvuX5ryK2793n/WHL0Z582Y1O7EGzLPQllAXWtlmNXuyBsRmla9+vVmLY2yrcLMnElJW6NwI9C5ECCZ6Mf+L0fvsWHH97n8GjKq9OAznZIyJgvQBQlQWgkBu8KAgvy1LB3sM/+/jbnpxWHzx8z6PbI811mVRfrkiZGIXY1ehuwPjSakhpjLKZuRK/GUtc1ta2xtsIYQ238GjBpGepWA7jKRGu1NstO2isL+X/u9q0GKO1EG5a1vYi2W6z2OpvAGrWxVg95I3vy2+3DZRajDc5rWuRatiTEJFMpWsZExKDAVty6Vpu8WrsLl97nzaLWFtSIJUq/XC7xTdcEIqycOZcXVet/u/rA6ynLqwOyAlMrR9lVN9FqX67so/dRIOphxQQ1gslLQGj9c62MuWR7XK+wSyAw1jGdzUhOjqltTW0qhGBN7GWxdkVLOhvwNrY+Dnpd7t25w/Ub18h7OUEJZGPJHxDUVc3hk2eoylNcnFHOp2gVJz2pJSiDrRwOgW07iTykIobvdTNJIi03NlLeu9ljty/pJ4FumkQLdAW9jiRPPFpEwy5f121RkFQrlPcgIwOhhMS5gE6jjbpoRkil0oaxiN4dlfVYLzjoJ8xLwaJOKJzgYm4ZF47CwryomZWewgRqB8ZCVTtm5YLxrGbUz0hk1FqkaUKuFXkamZFBJqltIBMJtQ3YxgE2Q7IoLLIBCw7T3BMxzMx7h6ktqZQkWkNznghhea7bW7I2hlQLwponSprnmLYNkghilZRLNi4OiB5jLEIlLKq6aUGPNvqDbkaaaIxRWB9YFDVplpBIjQuBREq8t7FbKos5Mf08YVFaisKgEtm0jvqm9RakaoG1R/hAliTY4JpuhyjCzYXm6fEZWUdz/8417tzaQaWCs/MplSspFiWLJIASJEqTZIrFdIGpa27f3uXarT6fffELLsbnZGzgvCXREgWUk4pUdjjY73F+dspGt8cPv/sOv/nsK/4f//f/J//zf/j3fPD+B/h6zvPnTzi4tsujBy+4eecW3/vx7/HJZ7/i888+xbgZm4MhYTsQfML5sSNTKdaC9wsW1TmqnjQArUQmlk43486t93nw5IyyqkkTy9HpCcaDcwllCdYny+7DGHvolgvDgEfIdvG2JoRvax9ybbQIPjIry0E5spNKACFmbj189DW/+c3HTKcz9g/2ePfD65zPnxEkLBYFEs2dm9fpdzO2tjo4m7CYCx4/PeXh45qnzxZIEdOY4/UVCF5BaKIpfGjcVENch14ajwUsmxeacv0lwCLwbUO4aOYnH5Yl6/bS19KyO1D84e9+wL2713nw6BUPns3pDG8y6GRLxj2COc+Ll19xfPY1nW7NxmbK/be3EeI9tBJUxTkbG5tY342eRyEuTPEebzzGW6wD40w0WzMNOKnjv2NJp27Ai4lRFC4sHWTX7e/b2AlClPius0Yt278c55dRLb/d9q0GKO22FHteodCgFbaK9Qc3P7Q3ymqSfxNL8o1hde2rXGEOvPeob+huWTZhifb3lzUcrWD1Td0w7b8v04jtY1rPgNUNfHULrABJu5+vGeusAYP1/V6CBbVuorYyU1uxIK+/71KYu1wZNaKwlshae8pKu7I6buv7sNq3eOH7YJnNZtGYUzWtr4Rl106kJ9dU6bYmOEuiNQf7B9y/373coAABAABJREFU/xabW9tNp0rzmijqes7Xn33Klx//LeX0GGyNVJJ5seBiWlBWYLxvarkAEi0kEk+mHIkWdBPPtU3Fu7c22OkKOsKSiUCiAmmi6OYJ/W6KIN741sTViBISFxxaRet8xCp0Uaqmk0qK2PEgJamOLY1SqibTJbYEei+xgwzjBJWFwgYWlafygkVRM17UTErHrApcLCzTMvqlGOd4eTyPA2aqSGSgk2q6nYQsSRj2e3RSRz9LKcsa60EqjXeOiS6wTlIHz6K2yKQZ6AV4F8PoMq3o9XqUVYUTHtvEIHjf/CyaVmWzuhaVUniiTqW9plqfnLb1MYpoJc551NJFOTKTWiucr4D4s0JR14b5rKafpzF4TUV9DMGzKAoSqdFJQq8j0VpS1jVaR12NMR4vJUomGC+oF3OUThBC0c0yaqFYFCVeQmE8h4fnGGE4Pz/j1p0/4eD6iJoF9UKT6IzBxgFCS+Zlia0tJy/PGQ776NTz6vgZVbGg1+0xnUyp6pJFXXL4asLkAibjY4Ybmv3tTRazGU5r7ty9wyeffMXhyf+NP/zD7/Pv/s2/4daduzx79JSD/cD29g7OHSP9GXf2h0wLTbe3yTtvvc+9t3/A9u4HPH58DMlTxosvyTck995+ixt7b/PyyXMefv4PHAzfYr6A8aTmbHLKbDHFBon3aQzQDI3Ts3BEy/qwmpyCXd7ncQ3XllQgJvRClJjHezqyJW4JylvLBusd5+en/OZXH/Pw0acEb/ne937IB+9/RC1OuHh0yHxWUxYlnW7KYKPLbHbONd3j/GzCfFrz1lsf8ejrUybjqplW/doi9vK20s+9Pj6/SQDaCrmFF0u33rbFV5E0jT8GITypcFzb7fB7P77Pzeu7/OLjr/j0y2M6o+tkAx09sLwAGc0zD48e8atPfkqSLbh3/yagePr8IfdfvUWq9pDKMxiNKGuNa7QmznmCtThrGuPKgHEeayzOWKwx1KZqxs2mW8cEnI0MZvAusi9rX/gYySCWZar1RfPrTSW0x/i33L7VAGVdlLnyCVlxI+uCzPZ3a7wJ7YOXeXusJuPl48OqFHJ14r6qQ2lP2qrzpPl9WHEiUq7Eva9bua/v/eozxtfwzYldB2C/HRJdalCaz7Mukm2/nHPIxjb6TTqWJSBRknWxbLsfV8FE+8YhxJWyd20rXoux3ZLNbctU0csitrku24sv1XYvl77iZ4iIXsgIAC+rzmO4lTUGY2usi0biW/0B79x7m2vXbpBkXXxT+7be4a1hcvySZ1/9hun5IfP5DOcF88LiG0dU6wMiRHAQQ/EkUkgyAZtdz7UtzfXNhP2NjEEKHeFJQiwLdTqaTidDK4ESHmcNQkqcM2Q6jbV8keJ8wLrocdIODi2bpBuWRhBIZCBLs8ge0IbwtcdKxJTgAB4VSx4eXOhQ1JrCBmqvmNeB00nFxbyiMILx3FA5KGpP7QLTuWEyi2Zsw55hMMjQGDYHXZQIaCkprGVz1CEEzflsxqxSeAll5alc1K8oJME66mKBMS4apzXH3dpYmlXSI1X0XmnLgNGbxS6vNyUFNKJbRBRxK6WYTosGKETTt/aajw6mCWmiyfOc4+MLBLHEJlVMHZ4vZvhMkyc6djfINqzSI5UmTSXGmLiQaeznyzr66qSpbsy1DN6DVgl51qO/tc8Pf+8PmP3s/+Thq2ecTWp+9ncf8z/f+9ckXYk3joMb1ymto6gK9Fzw8ukrOmlCmkhcMGiRkqYdzk5O2BsM6fc3eXU+pyg1z58cstGT9KSig2T3+nUeHD5kc/8GeZ7w6uWc//3/+CsePf2aP/rJ79JLe5yOj/FU6IfnCATbO0OyqgNScXLymDSFRGoUDqUOKasnvP/ev+Xg2gHDXofxsUJhCSLhy4dP+PLxC7zI0ckeoYqlXEcMYUSGZhKWiBAQ2Nj5FQKgiLk1ARliNrIIGoKG5tz7puwhhcI39wLCMZ6cM5uNOT094asvv+D4+AWjjYTf/dHv8/a9HyClYlyMmYwXPH5yjDEGrSXn52dMp+eoJPD0yXM2Rpu8OjymrgBSolW9g0a4vRyRw5XF76XSRdSatONQ1J2sFoIhEBn04JpmhmhG5wAlozOsFoab+z3+5R99j94w569+/mv+4VcvEMkm6SimX7ele+cN48kJn33xMUU5ZXMn50/++E+oK8eLw6959ORL7t8esHd9F1/n1HONc4LaWYILjRg2MiLWNp2NdVPmsTXGxJJOZJ/bNmO/bCOOoZbx3hNXjkloGMu22+r1uWRV5fhtt281QIE3r9qh0Sk0E6cUMaX0ytR/+aer4OPq671h0l5//3YSV0qhpFoWe5aPXQNTEFZln9cAyuudQevsUPOp157jaVcdqwviyhJgSdzIS/u8joTbUtDlbf31WDImrR/GKpPn9WO1ukFj7bIFWG1AWvv+cXJnGRS3rnVpQVBsxWZt4gGlJVknIc2TyJ6sfZ7LzIlryjtR4NVLM25ev8Gd27fp9gf4tozgPWUx5/jpl3z9yS+Ynr7k9GzCvIwlE3xkAKSSaKka8CBQQSJx9BPLtU3FvYMBB6OcvvZk0pMRyJUmkYpOrhkMu6SJAnx040RHyth5alcjpIxaiqrGu9haK4JAr5W6lIiTdPAeFQLCx3A6IWMabqJiqrAQARKJkDFBOFdJY20tMDY6ns7LmtoK7mz0WdQ5NgjmpWNeGS5mNYczz+ksMJ4ZKuMZzwoqaxChJhDoZZpUaSwBhEXLwFY/ZXOYsahqTEcw0zXSa5xz1N4giF05xocmm0bjgsc5i0xjd09pLK0NuLV+6YGSJQlaxRwX3+TorAS0EfxXdY1uVppZniIIy9q6Vpo8T0mSlMlkhhSKPE1QOomDsfSIILBltP6XKpDlGukCEk1ZmIZpFFgPRnhq5+hmGo1vAKInzXJ++JMf8W//x3+DGc44/v8cUcxLHj9/xpdfPmJ3NOLi1SOu7+2T9rrUpo7tFRbevf8+hyeHTOcliRU8uTiink34zr37pCplMbU8evCcYlHRlYob+3fZ3BxwfnHG+HxO0jnlrXsHPHp6TFFXPHjwirPj/4Ob1/a5vrfDaGPEydGYT379NZWVWOG4c/s617b3OH92SH3xU/rbW+xuSUrTYdTrIZHM5xOeP3vBgy9f8fzwS+rQYbh1DVNLxmODW+rrYgkveNswEq2TdGOL0AxPoSmKx2iEaCUQqyWhAZ4QbBsIGSjLCQ8efM7zF48pq5LziwmLxZxOT/LWuwfs7o8IwfDq6AUn4wc461BKMBx26PdHzOc1ne6QZ89PgQQhJU+ePmfUv9GA0UacfWVOudyFc3UsfzPzvno8UWdDQAaJbKwioizBkSrDu/e2+aM/+A4SzZ/+2T/w2VfHlC4jSQRBOEKoCaEGoXDe8uTZA6bTMUkq2N7ts7M7JEs22d3dJtExAuL69fs8/OoY52P3mnMOZxzBrTJ0jPVYs2KbTSOUNXXsymlLqq4RwbZl7LbUtfLXavtVfTPHxMaPy0zJ6wzTb7N96wFK3K5M6KGVybaU04rBaD0drj57nYyKgGJV8ly/ANcZlfZv6wyLENH8RqKWKKedeFevwRI4vUkn8xrmCo0HSlvPFas/LD9faJ/b1kFX5RvfIt0rSuuVRqVhfmgY2EtgaAXclgBFyKXdfVzVXmY4lscs+KX+ZR1ctfvb6lDasLh11mnpJCsvs1FtiSPLE7q9Lmmexk4PvxLHOueb9uLYIhtvsmj8tbm5yd17d9nZ3UVqhfUGFRTVYspvfvE3PPzkF9TzC6qywjlAaJQSMUROBoIQVMYgvSeRjm4S2B8q7uz3uL3TYZAKcinQCKTQpFKiEHTShF43IdUggyFNErxpBaglAHmeRWFvXTc212KprWjBopKySZeOzAHeY6roryKliFb6UsRwv6bTynuHo3EqDXGAcTqyFL2mfKKSFO91FMLWjsp1WBjHk5MFZws4Oqs4vqiZGzAYagenkwUXUpLqNAbuSUhUIE+T2J7oBV4oEiWQSSAVmjQkLMoaQkBpjQxQWRuTkUVk6Kq6xpjGy6Spu7tmBe2cQ8n294HgQlP6EWRZXJ22C4LofWPJ8hSabBFbWbqdnCzTlIkgyRSVqfEh+uYY5+l3+9SLgqqsGAxzlGzKvULRGQ2YTguctbEEITTGOioRQEsSQCjw3nB49ISPf/1TOn3P5mYHJQU3b+3x9OlLytMCXzlk8FRVwWwy4+EXj9kZ7TI+W/D44RFWwPn5EaF2vHtvl42NPuPzU86PT6OYOhU4IXj87BVHp6eYusKXgrNXY/79//RH/Ot/3eHrJw84O58iVKCYj/nNZ59RLgL9bMjhqzmLuiTvKLhxwCgb8fz0BanQHLx/gzv3P2A82cGXnn/4/Fc8ffKST3/5OaHKGe7eIenvUlYBU08BG4FFQ0evEQ2NjgRCaFPlW5rfIaRa/U44grAE4QCF9w2SETGV+NNPPubp068xtuTk7Iw067CxOcAzpXYzXr56xFE45+HjrxiMFL1exuZmzuZ2hjGK8/MFw6zL+MKzs73DdDLBWdgcisYU0kcGRYTL67vlRPzNE+ybhaBRmxKEJMgA0oFwMa1YWDqZ4aP3bvDHf/gDymLB//q//YyHT2YULsMJSGUEeaYu8b5DIGNejLkYn+Kdw/nAYl4wnZ2zdes6Bwc3WMwvSLIO/cE1KjOJQnrn8TYuAJxtQEgT/VEbQ13XTSNBE/7XZu841/gmuSUocX7lVRNo55vmODUAr50/Ca+zKP/YMXzT9l8FQAktoltOhJEraUHAko5rSh2rEs7rrMhVBuVNZZ03bZcm53Vk0pypS6BasLpzL73v5cctP1/zv7YNk0t6E+INJS7/7k36jfYxyx/X9jsCGX/pNa4+Lk6QKx+UlnK/ekgu12b9Ko8nxGTZlV4nvHbzt4xSnGSja+3KKybeHEma0Ot26XY7JIlukFlzAzWhVu3NVhuzzGzpdTvcvn2bm7du0ul2sc4wX8wpF3MefP4b/u6nf8bi4oxExi4UFTypcggVGTFjPMY4UgE7I8Xt7Q63d7vsdAWjTNBVcYJSISyBVZolKBHo9zOSJJYwCB7hoS5rjItJoADW1Bi7yiBpR/lWDBr1PuCsRSpJmkTBrTFVfE2pkHhSEY3eJB4RPMEZNNEW3rW5SEk0y0pk7FTIs1ga8ghMrqhdYFFLkqC4NhLc6CuORwknM8PMOBbO45FUJrAoSuo6gmWtoMwVzkvmhY0JwVphg0UogTciiuoCmCBiGcm3i4QAQdHrpPhgmhKdx0mLUjKea+epqposTWhQLd7FOHhrHULBaLTB+cV4KbrUWuOtQ4mACwZnDab29Lqa2nkWRU2eppHlkwpjHUmW4S0URUkICp3ErjVJY7KnJEEkVMZjfKA2AlMZBr2MLNVY53j45Wcc3Nngg997h8P37vOrTx5xcTbm7OSIp+4RP/m9j8hHHar5jE6aUs4NYSD48ouvOT6ZYkUUdGsvuX3rFkUx52y8QMa6KT5AHRzH0xkbsoN0Hq1SFuOKw2cv+ckf/YB79/+Iydzy7MVzPvviYzodxcOnD+noIXO7oNfPuXvzBjd3b5BnXbZ3d+lt9Oh2+tSl5fhZwee//AVPnjxnfHHOwd4+H334hxxPBGczQ1EvCBTNtdqONVF3onTUHhGa7Cdiok+ctC2ItuOyWYAIT2yDbVbiIQAGHypeHj7h5ctnTKczZvMZaZ6xsTlAadDJgDTtU1vLxdljkBVCd/m9H/2ALx58xeHhBYuFY7iZUdYLtE54+eIYgWc4ylF6FYYaBbuXM2UujfnNwmqdpX7TpLtkypsyd/xkFoQjEdDver7/vdv88IcfcHo85b/86S94/HxC7RNM8IimQ1IJiVYJQiZYDxeTc+bFmMqUYA2vDmecnFxw+4anWNQsipo9rel0t2I3mamwRsSxxdQNOKlj/EdlqV1NbWpMbZvFXCwtRwBkmpZkT/Ctw247VxDnkvYYwHJuaY7alWPx25d11rdvNUC5Kohtt5YWX4KMN2g63gwzLr1Kw0isyhHfJJh9neqLN6UQl2muyyzDuuD1zXuz3t0QWZCWFWlBwdXnrkDKZTZj/d+XgdD6MVyueC499nILcaz3r9iTqyWqy4Ajvs96YGD8o7jUTXj1GAoiCk+ShCRZtTNDQGlJ3sno9jqkWcuehDX25LLhUCv4SpRib2eHe/fusbW9g9YJtip4+eQRP/vpn/Hi2SMWkzGpUohUkyvJaJBzNp1TGwg+kMnAXk9wMMx47+4GBxsJPe2bOnIswygEwlmUgjST0Vm2k5BmseYsQ3RYLRYFrulsCiFElb1rO7DaY79+fDzOxdKWFNGM0LvY0iylJNVJPE4+1rpbjYpvOmWUlLE0pCMj4Qn4YEm1RwpJnoAWGmMtQUtqK0i8o7uR4YRksaE57BVsTQTT0uCb6PdEZxRFzbz0FMZSe0flApOZRyZgXIir4hBQMsFpQVXW0e6+tljjQSqEVjHcMTStxokmSxLm8wJrPNaCCClp0tTkpUSJ6Bpbm9WKL7iA1FEQ28kzpAjRHA6BM47hsI+Unv6gy6IqkbVDiIyydPggqGyk1HtpQpqnOBsIPn7O4CxCeLSCvGk3ripLVdb4RKOVYFEZbPBkaYJf1Hz1y89474N7XNse8KkvmBeOoANCB56fHfMd7rGz2+P8aEKqEsqy5PR8Qm0DzsZohM2tEfu7u3zx5WO6OqPb7aB1XJ3LTHHt/jVGw5xqPCOcWkpT8+XnX5DlhoPr1/jNp0/5zWdfUfs5//Jf/Q4725v87c8+JRt2uHf/DhvpkI3BNs55tq4dcPf+uzx79pxPfv0bvvj0EZXTbGwM+M6H3+PenWvItM/xvAJhAUcQgWiFrxHUCOFQuiZ4G8tjCKraYAiNUVi0tQ+hXbQ4pIhgWoQQ9ShIfDDUZs7Ll4/58qtPODx8SW0cUmUkSdo4ClukzDl+VSJEEc0bvYXxAh883/3ud/Ducx4/eQFYZvMp3kOaS27c2Odf/6s/YHJecXZ0jJIJkgwhKqIQ900AZI1af8PWjs+rfzsILuZFIVDKM8gt/+L33+fDD+/x9cOX/Omff8rRmaXyGTY02p3gITikBKVSQkgJQSJlgjFR4xO85Oyk5uc//w3vv/cDBr0Oxi4YT87Y3r1LtxvFwHVNE5ZaN6xJ1JrUlWtaiWPXTnCt8NUjvEN4h2wY+PbctHObkiIaH3K5cHNpDmSdQbkiO/gtt281QLm6XZpsaeuYcq3U0pQ1GtXsN638V2zGlYC7tSvvHwcV32Rg1oIS2VqzvcZyhAaltu9xmS570xtK2kjuNwpVufy8wMqt86oK/ZLo+A112FjiWdner6caX9rf5ueISVbgYXXztiJh3bBebu315VLEu7LSZ8kgpGlCt9uh08lRSjalq5VF89JIyEdTNu8NMsCo1+f+rbvcvHadrNNBKMXRy5f8/Kd/zvOHX+BsRaoFg17srnFVhSkt2kuU82z0NG/d6PLRrQ12u5pUg5YBgomAy/mme1ogElBKohUkiSRPFVJEcaupzfJxnuh0GVgvG7bnL67itI7HJAqIo25JtddjAwATFSft4KNgVagYn9CcZaSSy2OldbRn9y4OTkpFT4lEBvJEoJuE4ryT001TKitxUtGpQZIy7MY2xzzPyJRABIsWXYraM68t46LEkFJWgtm8wkrN1Ag+e3zC0bii9AKtFFoK+p0MFwzz2lJVLrZ4hkC5KBl0U3SSRLYCEY3inKcmttk663AhYGws3yVpgilin9x0tqDTyVBSUBYF0+mEbp6QZ4o0kQwGfYqiQAlFN8+o6znOWdIsJwSLcY7aghSKRCd4HzC1Q+BJOzpmEJnYWjzsppHFso0pn0qRXkBt0Urw4vkRn/zqIR99/20OXx7yyeePmFtHcAJfOp4/fsg7b93l8YMHVGXFvDiltJYgUvIsIZUVN/Y3wWo++eQJH3zwDnfv7rKx02delGzsDlG552JxTDftsn9rnzvvpuzvb5KmnuPDF4S6opdmmHnBfLrg+vUdbt29xs7+TXQQhNohE8nh2QmBLmWp+cu//BUPHj7Byx5bB/f43vfeY6szRSWSeQXWgXAJIigChiCjwFTgkNKSSMfdtw74ne++S6/X5YsvHvLk8RFnZ3NUkpIkmkUxpyprIJAlDiUdohnovKsZnx/z9cPP+fyrXzOenEfHUyLLan3g9HSC8xaVFCQyIUkFSdM5phL45NNPuPf2ffJOQqfb4XwyxzlHmko2NjP+w//y3/NHf/Df8cu/+zuePJxwelxG6wT35nF9fUC9nLrd5Np4mu/rmkGHVB7pArkUDAeaf/lHH3H/3nV+9auH/OXPvuJ84rFBERrRcBwfXDPsiyWfIwL0u5voZEBYLAihprbw8S8/Yzj8f/HHf/yHjEab1PUcParp9CTOG6oqsslVHSM+KlNhTI2rGwGsbdkvR/Amsq7BooihmyrIBkRGnaKQEheijDnQaoracMeWLbk6Wf3zwQl8ywHKioFYn+AbhoHX2RKxpKRWE0FDUDSA5SoTcJUZ+eb9eI1FCQ35JdrAv9WeSNZs+i+xKJeB0Xrb7SUV+dq2bL+9Ehj4T9X6rr5WCCul+FV9zeozRfrzkiBYJYi1drKravdl6a1ReAtiavMqHDF+7mXL8iVPmxUYEgKkihNjJ8/RWjUgyC9DASMQWoEV7+L75mnKjYNr3Lt9h43hCK0089mUv/ubv+HZgwdIV9NNBbcO9rDGcnYxoapqRAjcu5ZzYyPl7WsDbu30GeYSZ6soYrVN213rMSBi+J+ScQ2ohCJRCW0WjzMeQtMNIgRBepRQeNccj8BSPxOPm2tWib5x/xVNGSSuYLSUa+fMI5tjEgea0FhHtFLEJoyt6TJLlMTXohHl6sgcCcjyFJV4AhKPR9rojttLJYlQ7PQTEp0iBGgVmcrgHXhF7RTTSiBUHsthTlMLxWkhwRnK6pyqiOc80RLvA8NehhMBX68GyixLYmdWUHjrSbIErSK7U5QVZClpGvU10sVJwFpHmqaoJGFRViyKijyR9Lo5iYIsE6RKYm1FVUqscZS1pXIFtXEkSYLWmum8oJvqmNtjQYpYSpIywVtHVcbQOxCkOgpilc4wQcYW9NqgVIbWGucMAfjk7z/lo9+5w7v330IEydRWvDw5YWvYZ2uwCzZh1NvgXJ9SVdHTRghFr99hu9dhY5jz8tkpp+cLFrZk62DIex/d4fDVIf3RgM4gJcn6JL7LxdkUW3iGlccZCKbDrYMt3n37fR6/eM7zp0/QdLh/9y5aDzl88oq3b10HafnqwdeMBtf4/Df/b46PJ3S336Oz9xGb2zvkGwpfT8nyEWcTifQJMgREEI1dehxTlfB0enDvrWv84EfvkuXQ60o2tt5he7fLF58/BiHp9focvqyYz0o2Nja4d+8m3lZ4O2M2rXj5/DkPHn3OxcUFVWmxVlHVBqkDOksoyjnWxGMlXYXIJSpEh+s8V2zvDOh2E6yZc+feLkE4Do9OsBayNPCjH32XH//4B2RZwtbWiN39Ls+fndAKet80zq7GsdXc0MwAl8f+tV8HofFBkEjD3q7m9373I67f3Oev/+YT/vaXD5nOFS5EDZUIDtH4VSkhgYRA0ghqKyAlzzvcunmXxeIillV9TVE4fvrTXzCenPDuu2/z4Ycf0Ol36I9UtKWvy0YA66mMbco+Bu9Mk5NmSBPodCT9/gCtBc4GqtLgbGQpgw9Y57DeU9U22gQ4gXWrc7+2tl4dgitsfNz+G+ni+WbmKFz+vjbJRreKqBlvV6zrYAYuswntfwTRWGlfZlHaCbZ9LO3jhSBCYSKNufYchFiWMVd4Zn1ijkg8Aq9Y3nE+ZkIsHyXCEqd6YumAJqPkm2uiLEGDaL7av4Wmhnz1WFxiZUREzREsRAZF68YFd6mZYEnZCBHrls6vu8C2xyN+kihAbEWfK7ZkRfusQFKWJfR6PfI8jyyBkITgmiyVKIht24qdtUtPmq2NDe7ducu1a9fI8w51Nedv/uov+eTXf4+tZ9y7vsGg12E+LxifXoBx7A0Ub93Z5P072+x0YbOj6CjBdDqNZmAhrm1CCLGrJ7hmYInAIVGKXp6hdGQvoj+JI9iAa46TbBxoQwM4pIjHzNjYArhUyXtLbPGL166WagmMWmYkPj8eVec8SFBCRdDnXUxbVhKtomOnD5DmOSJEQadrummU0tgAi9JQO09d1ORZQp5ItAokiUQ21ueyvS4abQZC0U0SkALnwAeJk5pBJ8WYDc5OpxS1wQiLbkpEqZCEjopGblISvCdXKZ0kkCUaXwHeoxNFKhVWxwmxKKuoC9ESHRohdYA0kSiRUsqasjRkScKsrNno9VAKnIOiKtE6Y1bMKWyILdAKarug3+2j8Li6wgmorUV4h3NJFOOG0LREa5wxSN140bjAaJAzHs+xtkbLgBKxbHfxcszP/+xX7O1vcPfuXc7rCwbbPRbTKdNZyWT6DIMh6Urm0xlBCbQU5Fqyv7tNkqR88dVDjPdUpubkfMzBjeuoLOfs/Izj4xmnFxeMTwq8lcjgeLnXZdTPOXk5Z9Dr8Z3feYcP3nkH6xx/+ad/z3sfvMPG0CBdoJd3cTUEo/nyiy/I0w1+54f/itN6izM3IM0z8GcELHUlcU7HkiPRdyj6fAQkjqRn+OGP73Hr7g6IgucvXlHVniwbMJ4VFLZkMpmyePKEYlZQVxVlNWE4yhAh4/joBcWs5vx8TG08N27fYjpfMP7qi9jk03jfWOuJ3mAO7QVFiGWZLFPknZStrR43b22yvbNPfzDi8NUx3Y6gyjNGI8Wd29coywJbnZBmCcORoj9QXJyFZp6guU8vL+JCM0iGdgHZjqVA61Iulx1JEXTkwnJwo8sPvneX/mDEn/35r/n4V09Y1BJLwDUO5CH4ho2JYZ1LQ7MQYpmoWbBdOzjg4eMOZV1ECUEQzGeer796ydcPH/LzX/wNH333Pfa27iGTCms9Ve2oTE1loxGbd5ZgHSKUjPoZ+9d2SNJAnsOdO7vYCiYTQ6fbodPr0uv2kUI2pSLL118/5tmzI14enjGbVXF/acrza2P8qgj0JqDyT2/fboDSOig3/16t/hueJPg3sB+v61G+8fXXUoajAywNqFiVUdpyEE12hAjLGXathNQgjXVBkViZra2XVdZLPGGN1fE+KqhbYo0Qc0JasOUD6DUC4jKjtAIisVXMNSvvy2Zt7c6t+7NcLtu02UWhsShvHifF8l6KbJ9YnpeIm2LvvFgrmcXjs87UNJdu8ySBiGnNzcFIklja6XY76EQ37ElYAqCl/sRagvfIELUh3U7O3dvXuHv/HhtbO3R7OcXxBV9++vdIP2d3M2N7s8fp8QUvjydsdQQf3d/k++/sszfSSFeBt5iFjxNE41BqnYvOorCknWP4I6SpJtESRFyZI0IUcAqBF6vVQ2zZE4jGVdgb0wjRBEonSNVoSXzLjsQJPIRoHS9EBM1yDeRKJSFEfxYhPaop/wXvcUSHWudi+F/SHEdjoKxrhBNIA9MisgRKarIskGdpdO0kkASPlmJ5JS/TiNvSXxLPvJeAUJgQKeobQ81717pMyxmvFtG3Jk0yrK3p6oDpKC7mDuHj5wUwzpGkGVpGxsV6MF7hEPiqQisZJywTy2veOWrvUFrTSRUiBBaLkk6nERhOCzqdNDIpzpKkKUZAVVToVMXVf5ZxfnZOqtuE59jdVtYVQmaI0LBUzZgQgZFHeo/y0Ms1qU4RQFkVCKlxVeDBp09ZzBdcf3uTG7cPuKESvn74BaUzjM8vOBmf4hNIeoGBS7ElaOG4OL1AhC1qb7l544BisuA3//AFx6cTzicFtTPYEKl7W0OiNbmCG9dvMuhLEnHG9uYB3hvGF4dsbw64c/sOwSfkSY4UUQ/18OtnTMcl9+59xL/4k/+Bwoz4i799xCgVHIwUoTqj00nwIiVWMwNORIhCw7clWcmH393nrfd2qOsFi6LixctDJlOLtZKqClxMSooiCjStba4Rqzg7mzOfHjObLMh1zv7eDd5+//ts7e7w87/7K4SKQY1SKBqZRDOOxvtIoFA6jeyWEAz6HTZHIzaHW/QHG2wMRvR7GaaqyFKYTM4YT06YT18RvKHbVQwHOYJZs1CIAHy92iOb+3s5nNM4u2IQxBI2QizdnoSv6eiCrespH3z0Fl4E/rf//Nd8+dUZVa2wTSxLTA6P5bHgJUGoyEwSECF2egUv8C6+7mJRNd4ksbNQIHBOsVhA0hG8fHVBHT5ma/MR273bDLauMXlaUtu6Cf8LeGeQwTAcKm7d3uf8fMrT50cMBoJrN3L+7uefcn4GaI/ONL1OlzxLESKwv7fHtYM93nrrHf78z37Ol189jhm9Ps5FohkrWkB3iUX5b9FJFl6n5CIT8I+4wF5iCa7+qe30Cbyp0+fq+66m46t/W2cn3sBqfMO+h6bmtCqtXC7JiLW/tb+Xa2/9+uuGtX+v/fwGALP8TGsakKtbe3zaMk+ruQlrepnV6zQMkLPLQ9DqcFpr/tdem6iriY+Lk26nG8WBWRYnbkS00I+aE491q9RkgY+TTa64eWOHjz56l/tv32N37zo7m5s8ffgV4/NXbPY82/2cw6cvWSwMt7ZT/vB3rvHhzQEjbdHeMCsrauMaq+cItGiBYAOEVVPDS5NI60sJWZqgJUgZgWWappRFtQSdsTRF4ysTBZ+1ia6oAkGmkzgIO4sQuvE5aUC3ag3zaM4DWFsj0NC4b4JHS4USAaFkQ/GuQvoyBd7XCJnhguZsMqWu52RZ2uhmIEkCqKifIXgSFflHLWMrs3MOh48lLRkV/KrhxrQS8XxIQSeBjZ7i7VvbPB9bxuUC4z3W1tF9Vyv6UkVLbhOw1nDhApWPwL+XSXayLt0si2ZyZY0k0FUKmac466gqgxCqmSCawMBkpY96dTZDJSk6aFxhSBrWI5E6ghEXbe4vxmOSNKWTZ9RVQSfPCMZQVNHcKs9SaJx+g/foaJeLD5EhS5MkXu+1iYGaKp7HxWzCbJIxn2a8O7wLaca18gDvBf3+DoPhPn/5sz9nOBpw/607PPj0CXZWUZWCp0+PYtbP+Tk3P3qLd95+h8X0Ex4eHSO0pDfqkiQBkSisqQnOsbOzx61bI3q9lG4+oipLXrw8orKS3d0dfLDkieLzTx9ji4p80OVHf/j7/Is/+Q/k3S0+//wJyk/ZSDuMUoVflHS7PRa1bLJlmliItnNSGXb2NDduDhCixlnTTPQKLeH47BzTsB7eG9JEI70kUX0S2eXVixnG1iRKs727w4fffZ+dg32sswyGHZQWBBdNHL1rojuaor2QkjRT9HodpPTMZwvOz6ZcO9gmy1M6nQ5Z2kUrjUpqytpwcnrGbH7B8ck5ZVFwfjGNrcZavj4hvDY+rZauDk2QtskUaoqpwiOoyVXJ9rbi7r19fPD8lz/9W756cEplUzyRAcaLCMqb+yYmE7tm7loZcy7Haa+YThfUVd2Ya0b9mxABYwJpV1Jbz+mZQaczJuNf8faNhCRXzEuDrQM4gQyewUDy7vu3CEFz/nBGUVg6PbDOoNMOzkXXZLdQTM4thJKA5euvj9HqCzqdPtPpYrkgb5zomn1fIse1Mb4tn33j4X1t+1YDlCXltv7v9kQuxZVXIQavgY74yytsi1jOprEk0wKQ8E2dN5cBSrj8z9ceuwIta/vfPDGyECshVkA2ymq/pBMlsf4vm+ui1Sa0r3Hpo33DDbf+qDexLe1zr/6uPS7rXiXxlm3dO9fqtCGWKLxfCacul8aueru0pbtVGmiaaNK0EcbqODR4D85Gm+bgLDiDDFGcl6SS3nDE7VvX+d3f/TE/+vFPuHPnHYbbO1gbmMznZMKyN+oiqpqdruT+u3t8eHeDO/tDhF2wGM+Zm0Btm8HQOZIQom37msttCK3GKA4siY4OpVmqYyuojWK3JNUU3lHXZvnZQwhIH5YmbFoIgooaFYFDhXhLx/KeRBPt75VSEfD5aJvfAvHW+C8eew/eIppYeiXTyPo0wXzxHMVjWBpPaeOU00kSUi1IJOTC4wUE4VEy3hJKyvieRGAWGmdh7yxCxhKSddFyXyMgOFJhGKSSvVHCnf0eh+clh1ND0k2RQqIkWOPoKIFtynJZogiVpaw9i4Xl1M7IOilzA2czQ5ZIUDVpiKW9EKDT6zUxB3Usj3pHnmmc8RgnkFoyLy2mLOjlKdZ5ytogRNzvvJMxnsxRHUVpasqyptvNEWmKqTxlZQkY0kTF3KYQqKqKJNXLe0criXWBuvGnyXsKHyxlYVjMLfOxYTGZMTzQ9Hspi0Lx4vkJo2EPKVKm0wl37wR+/yff5fFnLzg/npOkCS9evCLUFUmacXh4yObmkN29EZ1eH+NqEKCTlLqyzKdjkJLeYMRow/PTP/97Dl+eobQmzRW37u6zt7fBi6evOD8ruXMn4eD6Br/3R/+Snd0bzBfxesxkQRYMPQWFrJFqhLEKL3y8hnzsvAFIO4LBhuBifIQPQ87Oxkwnc05PLlCqjzWBoigao0NIdYILGm8FpnLYYEAUoASnkyd8+bhm4U4xznM+fkJ/oJjNTeM/045pkdXWiWRre4MQPJPJFK09Tx4fsrU55O59x3DUo9vpgfAoJVBaM1vMePDoAc+fvqCuPN4k1LazXPGLhgm5tGhry+MillMJHidiu30QCUI6IJoYZrrm2v6Qg2tdZkXFX/z0Y548W1DbDBua7s4gwQeEj4N4WI6dfnkPLxs7QqtLs0wmZ1hXREjjm8wf76Luq1Ix+BSHdQYlLE8OP+fW/o85PT0Gr5v7IvDBBzdI84S//4eHzIsKmcBscY4TJf/m3/0L/vavn/DFV8+o6gTnQQRHCKYB47AoZo05n250eH45qUTTuxVLvpo/oqHkb7t9qwFKSxfJpVak3S7/63VEvJrMhXjd1n4dbHxTK/ClCbxlNC7P35d/uPT89jUlb+r4WbIy6yv15gJYYprQrt+/GYBcFt+2r732t2947psB2NW/r0o8b3KTXd8iW+C4jG/asha0x7s9lrG6Hb+UCHTzBKXTRnsiVy3FbbkjWFIc3VzT7w25dfsW7733AR999zu8/fa77B1cJ+v2CUjOz865uDgnzxI6wrHRhe++d5/toWCgKuanx3gbwaGpTQSKjXDVE3Uj7bUVQpvVFGI7tICk6ZIJzkYNhY/sjjUxLC92PyW4pm0vlYpURiMy32gwpGj0LVLE9kQnm0MUxdAEvxRaBxdLN1pG34houNd6p3gEHq1jV48nRKbJeApn6XRzrHcsipI0S8izFC0DWRuc6EE1zA0NwIxApRFKN/X49dJle7VJHxrLeo8Klo7SDHPBrb0uD16MGRexW0Ym0XUyk1AJQ5CBPIu5P4kU0Imak0VhuJiVVE7EgEPhMYUlry1KgLWB+XRGkmryNCEEj60dzkTH3yRRlFWFVJLRYEg5nza7Lam9w5jYLptmiuAtQidsb29EAKIVWdah8HPq2jMcDkkV1MUCpSSmttHsTokmEyiCwqq2VLVB6+ijMz6bsXuwycXplIVfgLYk2YjtnV0ENfff2WE8vsCWng9/+D3mp4EsnXDr/j34xS84eXXIYHvIF199yeb2kBt3d6iN5NXxHOtKdjZ2yTp9ikXBX/3lL/HBsb21w6ywTOYleZ6ye3CDD977Hov5gl8/f44nIUkzJuMLvvj0l/R695Bi1IjuA4QSX9UIt0DIFB80AYNzkUGJmVCOTkexWMw4PzM8fXJMnnSpTWAx8+Q5FPMapVMSrQleU80dztSR7Uw0mbbI1LK1sYnWks2dlKAmFIsFeS9w7doWz1+cMp9bgl8D4iGQpilZlvHq1avIXCrBdFrx4OtnvPfhXb77O7/D7u4uea6ZzgR5njIeX/DFFw84OT7H28DNg/cpC7cMhLw6ThEuj7VxNIhfbZk3eEEwNbY44vqNLrfvHHByOuVvf/mYk1OJMV28r2FZOGrCLmV0LW6oqfizCKtFcojlHS/j2FhVRcO0Nh2cISBEHKNq4+jlCUkW9VZplmDNjHl5gtZQlwYpa+7cPeD69Q1+/flD5uUEmQTm8wuUqXj86AV373yHH/7kPdCeB18fUZTgvSAE1X5shFAE43Ei+sjgPU6Y1bEjat3WQcpy8vott281QFnCkBbdrlu1r5UZmh8iq8JKQ7wEJQ0Y+Cff7x+ZhdvSQmAtt2et3HH5dV4HPm9iMETz4NbPYhVpHTUpq6C+9oJeA0PhdaCxLoaNtc83l1ja7+s/rwuH4+/kGoPSCMIi4bp87/YAxORkt7YyuHTkrhzblkAViBDQWsWWUS2a+q9vSm8BKT2phizrsDHY4fbNm3zw/vt88NF3uXn3HsOtXdKsg5BJM3lKEpXiyimbXc93723wzk6PUTfBuQpXOcp5jRBR1Bq8jddGaLJ68EgJut1nQEsZrf9FFIj1Oh20lti6QqSxFBKsZzqbY70ny7KloFM0qzAvHE6EZU0a1eR1eI/1sUbdakB8s0+JlCSqGeAaq/eoBYkDlhShCa1smCsR/VOCEpS1ZTZb4IiUtsCRJYJuKho3i7ZsGbuEWu2QkKtOo8jixLq7ajU03jeZSyICyeCRQqGbsberJaMcNnJBJny0zM86eBeQCLpZShAV1lm0EHS0RunodJtlGWeTOQqFEwYnY0qx14pet0OwnrqqqMuSTtojyzNqJVkUJZWxBCkxzhOsQ4qCTGq8j8DSO4tONEkiGXT62DomuJbFgrKo6fe7hBDZp+Ad88UCqwV5ksQOJogmXx5YisgV3V6X2li8Cwgk3jrm4wXnxxXnT16Rbkj6m1NGw03yNOP+/XfIdBczlxy9POXs7IzrN/fpbWj6I+j0tplVE+bVjLTWCKkpqpqiNHhhOD17xXvvfpdBr8fzJ0/4u7/9lDv3bpF2NfvXN7l//y7DwYCXz1/x9ZePcF4yGI2QUlMVc37+s79Ayn2+98N/uyyVCQUizElTRWXAusaeXtKU/ixSe6azc4w1mMpyenqGYMzGxg7OaMblAq0zrAvMS4eto46p01FIJbEmIJog0to6qrpmXhQMt0Z0XNS8TCY1WqcxEqJ2q6GuMX47PHxFWVbkeYc871CVU87Opzx7/owsz7h79z4bmxuMp69Qiac2JS9ezAlO0s0HyNCjXEyQMgKw18ruV8Z6hFyWtAONaN5bBjns9rtsbnY4n5T88lfPOBtLjMvioqRhvkFAI3pvGfL4PitQEp225dIvyfu4IOh2uo3YPbotB+doNOd4B3UdIx7MwqFcYDTKWBRnhNAlYNm71uOtDw54fvSC8WRGWc6xdoFWgeFgiyePjnh67zHf//5PIHxIXQaePb+IoYM+mif6RvMHHiFjCdyG1vXrdanD+lH8pzpM17dvNUBpt8A6EGnKH81KV6xN2pfagWl//duBkxW7sva85bu3qHrVndJ24bx5W038reNonKzefALbz3d1gg+0ktm2Hrv2DkuGIqL/dT1KoPndmg39m0S1/5T+ZB1kLUFe8xVarxWaOvVrERdrVNCV1weFimbxKCVjnkrjPBkfE8hSTZ7m7O3ucOfWXd59513u3rvHwbUbdAcjVJqBaP1AmvwfD7Je8N3bI+65a9wdSjrUYEqEF7i6rak7bAtOiOBEEFA03TLIWP9tBMJaKdJEo1V0a5VAnmVNLlCsJydpigsR/MSW6Fi+ElLgQtTpCK1ifT3E1j4lE4Ito3mVljgfXTaVTPDBRcfTJg9JLgFjBFRZkkYdgNYg9LKcEYTEuhqpGgWuD3TS6HarQyzlpEqvXTOxayii6uaaAYJzy8We97FrKALeFWMnlaIlWYSPrz9MJXcORjw/O2M+sdSNVkMnsRTTzTsUZVxZCymxPupysiShl2sKJ8msRyWxxbcoDbNFybDXJxeCspgxm86pqxLduBAnSZxUSyeYl5agDLs3rlHMZhhrSQEtLNKBqyBNEjp5xny+oNfLGY2GvHp5RJ4nuEBsS1aa2kYzKyECKgSSNMf6GLYGsZQgTDSI80GQaMd0MuP4cI7udhifjqmpUNqxMbzH7s538LXk+eOX/OJvf0kIju4g59ef/QNOVIw2BrhQsX99iyRNgNhN0+vGz6lTOH71jEFvG6VTTk7PqezXvP3ObXa33+Ls5JzDw5dUC8PFxQW2dgSfs6h2uLmzx49+910KU1OU4yYfJ5BoQXAlveEQEzJ8aJsF4jlWCoydcTE+ZmBTQrfDvfv3uTi/YDabo5MOQsLR8RidZpg6kCjoDyRvvX2Do8Mzzk8sw94GQZUU5YwkFXS63cZx2KOUpq6i+68PsmmNtWgNiEBZLvBlvC4n0xmJVqRJjhCeooguy4N+j52tLZ4+c3jblD51QCrN3vYdZpOAIEcKi6D85rL4cjxtAi2FI+CQoaaXlIw2wVrN0XHJy5MxkzI6JjtiCZjg41oSotlaHAWaQZNm8djeQ6phT6JDNjRxHcPtyFCJGT4YOt24EDLWYjx4IzCFoPawoKaT5GjpsX7B1k6ft969Ru1mzEvD6dk5EOh2Mj768G32dq/xm08+RmvJaNgjvb3JL3/+iG5uMS5Ega11OGkxogZqRJtWLQNOrNbJEci14/6qjP9PNaesb99qgLKcKNd/GdraDSzjnluKbp1NYJ1BYVWmWX/9q8hlhUXWfnF5f9Yn3deR4tXSyT91opoJPsB6x037XuslmhBCE0r1+mu+RrC1Nxnrtc2VU664AubWP9/61zLM75IHy3rNsbkR17wDxBWfk9del8h0xF2MgCBLFEKCUp4kSxkMR+zt7vHW7dvcu/sW12/eYXN7nzTvIlXSnPfVe8TzbLDzCU9++Z+5Lo5RmxLlo81zjDIPWFNDqONEj8aHaAiVKEGqot4HITBNaSdJYilBCMiyFCkCi8WcwaAPBOraRIo/yQCJc4HC1RBcY3IXBxUpZPQUERIbPDZICuujiNUYtPQEr3Ch6cJpQvSUVstryIeAIoKFNNEx/M55irIm5Jrgie2xwpOmmjRNgCj6VVKhAghrUYkCb4EQhaCOZfsyzTkRTSlKSBXHUB99V9q/0zwGVuVT1VweHQXXtnrsby44ms2Y1xYyiWzzhoKgk6UEU+E8BCVRItBJwKeK+bjG1jGVWgSHd4HCGUSYk6cJOs2oy5q6jh1UiVJoJahciB0MAeaV58XRKcIahr0OSgl6edLsoyRLNJPZrGGI4PDwFUprrA+keY41NZVx6E4Wjb+alndbG5RUWGERApwz5LnGGklRW6qqZjYtKRaG/c0RRT3n8Pkr6oXn6FnJ/sGYQWeLv//7Tzk/n/D+R2+R9hKMt2xt7dJNOlTFnNu3DxgM+jgr8F5w68Ym4/E4BrwZQyfL0UlOlnfY39/jRz/+AZ9/8jnPnj1na3MDYwsWRcH2aMTuzpB5USDzLml3wPZoHx9KhDCkyqGFIQRDp7dJMU9WC6kQxy/rSqbzYwKGonJ0+x10IvmdH3zIF5894smTE7rdASpR1MYwGPYYDiXXrg146+0bTC7mcWyzq064bidBJwGpLcYtMDaycUu34MbbR2uFkNFEPrI6EmMqzi/O2dzoRxatchRFRZKkDAY9hNdYZ+j1BWkiScQGWm7hTNMltMz+Wo2rq/EsjhPxk8fSp/MORSBLDMNhFMdOFwmvThzzhYghmG26s2jaLoJvwEm4wuhfnhsiUx7/5b1BKY/3ktFgk+sHtzg8+hIXaqQ09HoZ1mhqJ1CpREuNswrnFPNJisThQslb775Dkkl+8fe/JPgOlZnT7XZ55/4d3nn7DqPRgNHmT7h+4zohCPKsQ7CKNMkQMpZzLI4QBFrFQT4437Bp7aJ8pf9cyRBWIbFvLCt8w/atByjfpBFp/y6vDJTLLazLa9tikVx7VAMF11aEiDexIu1E+I90DC33Z/V92Vp7CTT5teJB06LVpH/6Juq6tYxvGZ3XbqAr4GjZdt2yI23g4BuO1dWS0/rf1ks868LjuHpvjwOrSUyIhkWKxy+CFP/a617+iuyIlAFEFGQpBYNeDAXb3d3i2o0b3Lh5mxs3brG/s0enN0QmGQgNqOU5XfkvevCG8xdPePzxf2H22f9Jv3iKkg5UijOWOsT0Yy9EVNc3T020RHoHwiKkJku6VJXB2TKuh7xohKmKuq4i+9KaH3kPQlJVMQU4HovYYaO1JoSYGhqcR+ok0qYiUNaBk4Vh4RWTacEg0/RTSa5FtGyXitq6qG8REhscitgNFFuYm+MdAJVQzCrmxRytFVJELxnVXA+mNlF0SxQixzZ1jzOGJNEkSjXZb6GpIEa2RwYiSGnKSF60gBJoXIHjgnB1PbfLiF6WMEhr9kYJg2NBVcQrPa6IJbZyTTCmR4ZAoiQacDZ2fox6XUozJZUgZWzVXJSeoqox1pHnCZ1BH+ENhEA/z7DOUhiDMVE7E3ygmFds9nLSJGMyXjDsd2Inj7EkSUKW59j5IoJwHf13zs/H2KIi1ZLaOJQ0JI2FeaOopCxLVGPHHwGjRWlFLqNtflUZXFNCOj+ZUAWYS5jPTnnw1SFKZkiXkHf6HJ+dMnEXXL9xg7pUTM+mnJ2eY31JbQq8g52dHe7e3SfL7hG84OWL5/QHezx8+ByAbifh5rUbnLw85Un2hL39TR4Xc/Jc89b9u4wnp1g8hsDR6Qm9wS6JsmRpQapr8tSQd1NQPVxIEWJVqvU+4EKN8wtCsFQ2MF+UTBclKM+Pfv/7WP8rHj9+SZIpso5k99qA7e2MO7e3Obi+xY9/8h0+7T3EOMPe/k1++fHfI3VCkip0EvC+Yr4wMfDSt2WFgFSQpDLm6OBxoQlplYKAYTY7J9VbzKYVrw6P2d29wfbWHlJk1LXBO0We9hnkd6jmGoFAq2iGGAWy38wixz9ERkMFR6YdmTLoJHB6Jnh+6FlUEmPjdSF8ZG9bXOeb57ZThwxERmYpivXEYEUAjw9R45TmXZwtkcJx+9Z1Or2CojjF2golU+ikjKclQkG300PmGcYGikVBVSxI8pLdvRGPHz+nKA0ESX8jZW97k043Q0jQqefDD76LUF1m84KtUZeD6yPm1RxfRsCugsQ5SQgSIRRC6fg5ZYAl072aX9fL9+1c9Ntu32qAAg1zwBoz0GwtuyDWQEVYByVrk+ybgM7V7zTvwSVgsN59EmuhS2BzZYur+Cu/e8PjLrVktbnksAQnqxJMe7LfDCaWn/e10s3lv/1j2zoIWv8upUS2PhxCxJ9lCwMvPz9Ao0EJV/azPSq+ASbxSylBkI5uV3HtYJtbt3bY3t7k5o1r7B8csLW9R6+/QZp1440RRMOYiOVxpsn5qE3FYjFjdnHC85//Z2af/Sm98hnUC4KQzSrXUhUWY+N6xnuNVxKlQtMuaFFIlFTUwVPYagkyWoF1WZb4RNLJMkITNS9kpGal0o1/TRREJ0mCwFPXhk6eE5xFNY8tneCitPzm8RlHC8m0tORKsD/q8Nb+gI0cKutIG+IkBEumJQIfs3xsLD0EL6iNYTotGE9nhADDQZ880w2gEkSkoaKXiIgGbImM5SHZjDHCBRIdO4YQsXwkpKLVnYQQBbnxOEgcvgGsAustnnhthBBzg7RU5ELSzyTbo5RhV3FeemwDTAWCRClq70B2CSFE913psM211Ot0OZDdeN0oRVp5hCgpqkBpA/W8pqwMo15GlkoyHTOS+onE9BPOCov1UHuYG091MaWbdVgUhiRSZCzKCq3TZXCakILS1AgdYVZZ1wy6eXQ2TTU6SbB1DDfsdPPlIsK5aByIkiRKxBC2ANPpFHmiGXZ3Ud1Yqpo7RyfP+eij71HOCh49+JrxeM6N7etYo7k4GzObLBhs7JB3E2wQFEXByecPuXv7FrdvD6hMRRCBui7p9/u8fHHKl58/5i/+/C8Y9PtkWcJ4PGW0scHFmWG4scXnD77i1maP8XzM1tY2i8WMrY1tDvb67O330GGOTqE2YL3AB7c0eARBEAGpHGmqMdbT7Y4IIeHps0Pee2/ID3/3+wShefDgEWlXIFTBYDQk62jyjmb/2oDhxnscH52SZ7v88pefEJwg1RIpEpTMqaqauo5ZVPF+DwgZUNrHJGbvqa2/vOgSUJYLTk8u+M2vP+O73+ny3jvfYWfrzzk8KhBuwCB7BxV2oxYL0wShyuU17NfK5FfHyqg2tKSyppMsUEpwdgGvTiWVS3AhRlgEB9EUKI5RXvqGFVGxA6dhQwNRzxE1HS3T7Bvm3EYBbD2lNs/Z2uriZ5abN0bcuPkeX33xlPkUrMtJpKN2Bd56KuswdoELhs2dTTY2YWdnjyePXmFNoCprtnc26XW3qarAo4dPGG28Tac74uKi4tHTz3n3nWt87wf3GM9mPH9xhvTx4wjVlKRUwypJT2j2+7W5rp3Hlgvy/0ZKPOvAZOm62f6xBRsi0kvrWpPYd758IEsnk7XySdv6GoJbAo6VCdvque130dDDMYUTgoxGP2HtZhbQiLOvljnWv64ISUXj6xCiUDZS6Q0rchUMCRq319Vj2la1pSq8YTuW7bEhNNkL7deKZWm/rgptlyClFcmK5nO/9rjmjDSJxu3qvmVKhPBI1ZaLNFmWkuUpeSel283p9bpsbG4wGm7Q7Q1I0wQhdQQBr126HrBEH5BAVRUcHb7g9PSI8uwlsycfMzJH9BLP3Ijophg8ReVZVB5jo4ujVgoVmhV8IhAiJtN657G1wROagSzBNaBRtYLN4Ol08oadiDXbeCYVxthlt1PwluACwQWEUE3Uu0XLQJIqUIqLRcXcpYwruCgKTqcVB0PNqKvZG+ZsBEmu4kSYJYI8TfA2RqhLoXHBU5q48up0crJUoqRfNQeE0CQCO2iM7QTReVZp1VDZHohtycu4AR99aZb3i19d3zRGfsslg48XvKCxxZfgXaDf0ewMM7Z6Cc9PC7yPwMe52NkDCust+ECCIE1zrI0+JMHVZArK2qGloqM9apBiepLT8wXWB4KHqihIg0YFS/CORAh2N3og5kwKQ+0C06qimycM8wwZHN4ZjDfoVFMu5ngRJxbnoz14ohWmMpg6UKeORClmi5JERcGyavxsPGCdI5F6uXIWBFIVV+aLRUFaDdnf2+OrJ18ipGV/d4ckycFYjl68YG9nm+6wS2UNzx68YD6NOTJlociyLW7dvsP25i5fffYAXwsujmc8fPSM45NTFuVjTk4mCBGYL2r+8qd/y/Vr29TOUUzmDHt9eh1BkgbSLOOD97/D9ds7dPIeKtOkXUWQng+/8zanRy9xdkptfTPFyqYl1hGEwHmHTiTOxDiH+WzB8fEZw2GXEDR379/m5p1dnjx9TAiB2tSNuZ/EBUd/0GFza9S0mmcoITBFXDR0OhIlNN6CqR2txYME8CEKsl3silPa40KMnsiznG5HIGVgNlvw1z/7mOAl7757j9/73d/jr/6qpp/fJBO3cUZj/BypJEEqkGljUqgIrY17Y0zol+MuqGDJdIGWE5SG8RQuphLjExxzAtHnKLSdOaHRCrZUY5BLQ7fLrEIALwhCxq6gxtPI+8B8YdjcTTm4OeDv/+YTQrC4vT0QQzwS71QMC/UKU1d4KopywXCU0O8lHBxskmUp81lFOYOyLPDDPraq2NrdYv/aBt3BCB/iAmc2m/H88CX7W312dkecnJw384pvAlpBSYWT8T6Jus+VLxZt3WK1zl4xrb/l9q0GKLDOoFz+rz0KsrGblaIxElsCgeb5BFhjB9rXXLWTrZiBwOqpr5eVYjkoND+usxtL4LOWsNzux3ISX1J7V7Mg4uq0zZkJTbunWHuVS2UZ0SLVtZ1de23vXdOK2nyG5lhdYpz+keO9YpbW24xbL44V69Tuv19qZxo32YbRiuJXRd7J6fWGjIYjhqMBg2GPXq9P1snQSYJSKUI0WRVL2rDVFjlccNR1xXRyijczNjZ2yDpdqnLGxcU584tj5o9+zdAc0xUFVVVgg8C5wMV4xrQMTCvTTKLRrwRcbHVNE4qyjHSvb/QatEGJCcE4rK9ps28G/S4AVVnivaA2jkAUyNbOUdUVzslGSBvbmHWicC42AedacWu7T1AdhHrFs/OaaRHB06uF53hh2OgkbF7U3NntcXMnJ000ItTIypLpDBMCdRk1RaWxDEdDEhlfXzRgwlsfAwITHdN68SgRV40ixPbRGOvgsS5qXSKw8rTrn9YsMBAHKetaJkyswh5DLKesSpmBLBH0tWLQ0Wz2E7q6wIZAXVlkErOMTO2RKgJ8KSK7lCYZwRfL5UTwUeMz6KaUocYnEr2Zs6hq0iSJgEH66HJMLMl0sOwNUjINBsXxpGRRGk7CmA6Bna0+wkR3Yp2m+NqxKGqyPJqvSeEZDUdsDBWzxYQ0TTHBL43hYjt30z0lmrDMIBoTu4AWEhMEVe0oFgUvXrxkMV1QmSkfvvsOTx+/4OlXT1EyYTZdkI9zgoBUZCS9nLOzM1SS0Ek3+fzTZ9jqCRfHY0y5YDQcknQGPHlyTmUtBEe/n6GzlE5Hk6Sd6FWjc5yXHOxtk6SOP/ijH3L/3h36w0GzhhdLtirr5Owe3CTvSI5ezRFCcnpWRmGoFwRvsaZAiugKnOqEujLMpzVnpwteHp0hFNy6dZP+sMPp6Rid5EzHC/x+BDsBKIo6fi/HIAxKJcxnBaONfgR9UkRDRm8hxGsw0QoZJFVhMFqQd6DXUSSJpt/r0ulJ6tpQF/Dpbx5SVQWL4pQffP/HpLrLs4dT5hcZrvZoJSNDJiPzGbvVZLMAXI7OtE0JItQkco6SU3SaMJlJZguFcQEf5o2lQpvR5ZdJ9BBLpTEYYm3xuHwHmqt7tfANoTG59AlaZ7gaTl7NsbVh1N/m5bOC2VxRW4mzcQHgrMG52NmVZ5r7d++QpIHbt++glKYoapzVbIwSNkc9dndG7O5tsLU7wnqYTCc8evwV1hmyrM/Z+BRj62asd41WKBAas0IpFFJGszixPhe0IsTlnPjP3771ACVu7WR4mXlYAohLepP4t0sw7gqkW7It4nXh7DfuQWg7eMQKLXIFPLSPbZmctbLS61qSSy8OTV1+Webhzef8svak+R5WQljfTLTRjvXSp2YdYHxT2Wu9a6cVykolmwntzfvjW2ambUITgsFwyPUbe+zs7jIabtHt9kiyFJU0vf1CsNIENcZiADhCqHG2oiguODk/5vnLpzx5+DXdRPGD7/+IW3ffjV4kwlNNj+nNn7ItC5CecVUzN4r5rGQ8t8yNYF5HrxVBtEof5ClCxtwJISRKgFYaLxRlVcaSio1dPq15U5JrtI4tq84FpFI4byJzJGIbsgkhhnTZQKY1zgWEiD4dMkQhqZIl1zLBH7y9yWkROJ47XpzMeHE2Z24k54XjfFZzPrdMa8d7aoOekiTB081iu2JdlWgJWiiyJEX66BUiCQTr0Uo3AjeHkgKhEiBeH0rE7hvVTLDRrbJpXV6axEUtgG5bzBvjqXj9y6V4OvjIGPiwCn30BLCWfp6yNegx6CyYTusYQNhoXrTQmBDt6+Xa9SeljKJiFctrtTE4F8tWzhnyVJPovFlFR3ZI4qldBFFaQiI9IQ2ovEdwgvNZiakdo1GGTBLKyYI8T/ChxrkQjb2UxNoaJFTKAI6yqkl0DPUz1iEThRYCJWUMfLSRvfIiLlSkEOCj8Ng5hwqCal6yNdxmulAo1eGHP/gJf/kXf81iUfHk5bO4Cm85OBnPCULw5Okp1ntwAW+iad3m1j61N8gUUg393oBBf4DUCYvFHBcUJyenlNUZN/evcffmAdt7m4x2Nsk7in5/QFVbtNBMxwtMXeFcTZ5npFlCt2+wvmJR15RlHOMuLg45P3+B0oJup4+3CZPJBYQErVIWswX/8IsvsRVsjEbM5xWTScHpyZjpwQzvfNRvuQprHS9fHGGMQSUCncgmvVyjtGjue0/rqdHpZGgdsMbjrKCuHUo5kgQCJd4rpEiRImU+n/Hw61c4Z9HJgA8/+IhBb8qjr085fDalMg4pLBobu7mkBynxjaBfNmOdCxawpHJGmkxRqWA+7bKYp9ELJxSRWXCx/Bp8TQj2tTiRq52k7aI2spKi0X25RhkUBanOSSSKxZnk+YPH3Lp9neC3ODsHZyzexyA/E2pMMCBrUu3oD0dYW7O5tc3x0ZijwxkhSN5++y063cDNGwfsbG1RmUUzMUmePX/Gz3/+N4ynR7w6eo6ih6+3ICQoqfESpKwbFnzFDC/pQlbVizfMCG+cJ75p+68DoKwxFW+qF7ZloPbndUAiBM0gcPlo/v8J+C5v6wDpCmBof261Fy3N99q+rzNEvlkFNyUImmCpN2lJ1o+FXz8uvmV2WoV4pOdaAHO1zXgdnFxqP14DK6oN+Wupm7DaB9Egae9acZ1HqYTNzU3efucdNre2ESqlBSE0k9xl0XEgBIc1BWU5YTo54vzsJWcnh5ycvuDps0c8efCEg70b3DrY49q1O2iVk1Jjzx5zzZ+wmVrqkPP1i3OenE05m9ZMKs/JxFEUNdt9wd2dnE4WV8t1XTcrN4etLCKJicmJkMtyG8SMmySRDAcD6qqKuTmXgKePzrANgyAEywFPCoHGgbF40boxVnhvGIlAv6e5sdHlrd0uL87nnM4qKutZ1I7p1PDw+QXzuWNr0CGVAS2ndLRnkMNmP6PTSZuIgahzUVpBoyHQSiGFX/rYeGebMoVqOroi+IQIUoQQpGm6Oq9SRkjiY7dKS0O3l7xQkoBDIJtk1vg8KaJQtmM8g1wx7GpO5iXRiy6AkHgpkA6CjMZnidZLXYdSMR9HKUkSFPN5QbeXk8qYyZQmGmuieFHIJrhNR/+Y2J0kUAFkXXEwzMml53xecTatKGrHMMsJwWGMbRg8SZamWAvGGqbzGUIouv0BVVXh6hKfSqRIG+bWoZQiTTW183jRdJ9YFz02vEMKQaI0RVEwHA45Oz/ls0++5P/6v/yQTu9zjs6es6hjyUJphYzkLLt728ymY8aTkrIKCBxKWEa9PrvXtjmdnnLr/nW6nQzhoSod89IzLzzO10zGBmNr0uuKra0RT549ZtPM2dm/Tr/fZ3F0zHw2QcrA+fkRhIput4u5MNRV4NGTRyzmFcFsUddjLsZPGQ66EHLwKa/O55yd1jgfNSKdbs7FqeGXf/sVO3ujyK5MKl6aCwbdl2yMRty/v4FzNSGkFAV4r5cJ6QGP0pIkifon2dQnpZToRLO3u8l4fM58tsBbsCYamjnvKCvH5vCAg53bPHv6cy4uSopPjzg//y88f37Ie++/xQ9+co8nO2MeffWcly9qSsKSoRPSIBrReQgitsnj0czIE0GepkzLjKLMMSZgg8G4AueqhqUOMVfHX14IrpfNl3x+WzoKIc5lEO+dRpBMkOBiNtRiNmOrv8n29i2+/npGWekmEiMmehtvcV7Q7yXs7g44PT/i7HzBxfScYuFIkyFp0kGKWMacTUuq6oiXr55xZ34NqRImZzVnZzMWi5pPfvWIa/v36He2kSJr8pAcSnqcaJ2pTdTNyHBl4lyr7Sx7lVj73T+9fesByrJj4Ap78tpjaC6OJWx9XVux/vSrkOWN5Z+rr9Fc4A2GbH53+bWCXJvcX2MdWiqQS+/eghMffETUzX9RnbIa/Nf35RLz8xro4VLL8vLYLL8EwX/Da6291zKLpxGVCclSXLb65PGzhFbX0YAxIWIAoGjSdZdeJcvum1hPNrakKMacnR9z/Oo5p8fPcXaMt3OCqzFmTicpyZVlenHO2ekRRbFgMBrQz3K28pSeFpTzGeeTGUVdsagdz04Lnp4YSufZ2cjoD7tsbvbIUklVlcjgaExbY6SEcavzIwNS61g+1AolwVuz1GVYH3DeIEIzuTct3Eo2fipS4L0jSRMSpXF1jUXidQyxk1KgQkAGg7YzUqUZ7aRUI03larxOOJ0ZzgvJZ18d8/DlDBSkqeLahubudo5OA3nmyD3kOoLIKMCDNpJAqUYw25RkAgFrbSMAjp9Fyeg7IaVcMnDx2mGZnN0yalLSMEdxlF2C2hDwNt4FOlFRbOtrOil0k0AiomU8pMusIK2j9ocQqOtqCZakktEDpawjcJFgrSPLUjAGGRwKj7d1PN5aIYIj1dFLIsm6KCcI3pAngYNRghKOk7nDGshGPabT8xhISdRKFfM5EDOTnLdknYTZfI5E0O/2MeUCLxQ+BLRKkEqQJAmVWeCdXx6HuILPCEA5XyCloioMvU6PjdGIp0+fMF/MmS/m1NaAiucoSRM2hn3+u3/3L/n889/w4OFzppOaXleyvdPlvffeimU23WUyXTCbzpmMZ1RlYFF6xpM5nTyCS4Wn14mU/NHRhD/92S958fKUf/8//HsWxZSXh89B3uTBo6+p64p33n6XEALjizEnp48py5KtQZckqXnr/m3Oz045OxtTzB1nZzPqOjKIQkJtDHmmwCcspoH5xMU06YXj+YsTbt6eInjKxcUFphaMLyqqyqG1pKhKxuMLdNKL2rQsRYoqTuAeqtIwm5X0eiPqylGWBVo3HZvBQNDs7d1i0L1Nln7OxfgIW9U8LU+Yzf6O45MTvv+9Od//zo+5fn2LP/3f/4HJuIaGvRXEXCkvYtJ4gmWUG4a9miTpMF9kLMouNgScqPHCLss5eEHw8boTjWbj6kLymxobIg/ZzgEhspM+tllbW1DVx3z00Yccn9YUNZFla8r2nlgC00Iw7GeUxRRBYDgcYjzk2YCL0xqsYqEduzu7fPXVM14dvaDTTUnTDt5JTJVw/eCdaGCoElLdx4csToyiKeWIVc6VbI6VQkQ9YjsfL0s86+Dkn7d9qwHKN03IcQ58HaWtA48Vcl21+66zGWuv9MYSR7tdQsSiBSmve4istCmr57VlEtnqPl4rO60Gfx98w0I0mpE1oNUi7/XXXt/kkslhyZQg3qRQj6uF1Wd+M9Bbb5Fu9/81P5rXP/2l/auqirqum79eLlQ6u6BYzBhfnHB29pLTsxecnBzy6tUhs/EpB3tDtjdzZBIICnqDjLzbY3y+4OL0FeX8guHmNfLuBknaxyNYlI7KQpZm7G508DKn01tgXWB/o8dOX5EIj69rvLUNEJHNKRGrhqom5VQ1IExJGrtzQydLsBBFxsTcmjxN44TegDLf+iiIWJKsLXgSPB6CjV4vUiKDxJqmrQ9Ppgy9LL6uFZ5+kjPq57w4vOBsUWCE5qL0lKc1Ksnw0pEmko6CTMeKngg+AielCY0vS1vxTpJYEqmrqgH9jehzCT4b5qhxrY1mZCtwHMK6PoVl8nYL1rWKhnIOHxNlE8VGL2Wjn5GnJbMioES0hDfG4AjRrK5hCZMkQQiw3mKtxTuH0gmgYsZQk3kUfESUSsVMEq103Pe6QgiJMzZqRYInTaLmYHOQo3XgbFJwcnJMpxvbiuuqotvJmVxMG3M8G4FQiJ4yeZbigKJ2dBwopXHeNiUdSXAehYgtmEovz7sQMW8pGww4PR+zs7dBsSj5+OOPqeqSoiqaXBMZxcGmJkslpxenjBcTrDegHFlXs7vfR2lLVVaYynB+MmU+q5jPSozzjelfDMjrZJI8lWyOhlS15/S0pFho/uLPf0Hwkj/+4z/A2pp/+PUvmM+m5J0OR6eH5FkHYxds7w5Ik22kkyjZ4/GjMS9fnDAeX9Dtpww2BVaAM5raxEkzUSlaCvq9Lotijqt8Y1QoGV9MOT46Znxxzt7uHc7PLvDeELD0en2qqgQ0WZbQ7+VcpAVVVRO8pyxqXhZH9Pu9ppxXxHKPU1gLSiXkWR+EIs0zGBNZ2FpwejLjVx9/zcXZhMV8wbXdt6ht3SSJ02gVY9lTUpMpw/Vdzb0bXYa9LrNKU9Qp1mtcqKLXSeNJ431ovjfJ48TsoCDWRrkrY287Dy3H3uVAKcFHnQfesqiO2dkbUDvJ2VkVree9JWBj11CoIRjyxNHJBkymUCw8uwcDNnsDXjyf4VyCJMEZRVlIgs/J8y0Ggx793j5adpiODQTV7JcEF699hGOZaN+ywbKdB1otolv/BGtzyz+vtNNu32qAchWVXlrpt0Di0up/RTkJ2VBsonlsZJdXFPXaZPwN785Vzcab/tYCiPbSuypBvdqa+zrb0bI+zXAvBJezDVi+/jqhtjw27euFlRYlhNj2erkuyvLZ3/SZL5V+WNOjrKUeXwU87ephVT6Kf6mqisWiYNPFzJZ2s87w/PlXPHvyBeenLykW58xmZ5RVyfR8wtnJKV1l6agNVAqFt0wnFYuFZTopOD054uL8FdvX7tPrdUma8LrSgpcJ3RyMrXCppbuh8D6QqYKk8gSl8IK46mlcdpFxovaNyE01YKw5FSghyBId82+Uoq4a0OV9dHFtxMFStjHsEcAg42BmcTjrUDLQaQBB8B7n43ENgSZXJ5BkCQIwxqKkJ0vhozsbCBF4OXO8mjjOneDLw4LTi4Kq7CKud9AqQQmPxiOCwPpAZRyZVtTOxERlGVupfYC6NiRat0XxJhjt8oDaMhpXS39tcJ9sMpMg+pWsX/Ex5MyQysConzDoJkyMw7iA1KIBQHU87jbWtcuyJE01ot1XJanrCqkSdJJiTJOQq0CplBYqWe8RMpriRdoc0iyep7Kq6XY6aBwbHU2mupxOC4SQzOYFAJmPIkrnLKIpzVQmsly1qTEGNrY2mU6nhJDS76VYU2OLguBDzJ4JYJxDqZiXZE1NqBP6ac7F4RGzckGqQWqNCwJrPNZ6YgiBIATHxdmYzz9/SNbtY/2E+XwOoWS0kTAcDpnPK2aTirrwzCY1yBRr6+gaLGlaV6HX7ZCnXSZTw7PnpxQlKBWYjBf8x//4n+h2U6yrKMuSsjR8+ukD8rRLv6vR2pMmXfKk5NmTM7764gmz+YyD65u88/5thlubfPnVI/rdXX718Re8ePaKbiej3884v3iF8xXRXFgxnpScno3pdBNu37nH7Rvv8OThXyAV9Ps53U5GXccxK9Ga7e0RZelx9iKGNnoIQVIUBUIkRCsOx3wWWCw8Wa74xS//gdm0Zl4WKA3CgE4EiMBiXvD8+St++pc/585Nw/jc46QDCarhBEKwdFLDu3dH/P7v3qXf63BxIShCjhea4A3OuyZduTWkbISxztP+t2x++OYV3Nqw74ltdiKy494hMdhqSrAT9g++y/PDOcYkEZw0nUvxPSx54rmxN0LqlJPjmtLAw68O6Q3nLOYCQQ8pFNbGvKIs3+Sgv0WaKRYzoj9USBqGhMjgCImUkSFq/V9iSae5o5tMudViv5lHlxPS6/PVb7t9qwHK1e1NH/ybrwm/BDFx4l9dJFfBydXyyfprxN/LtcdfZl/an1rIsuyeEW0L2bqXyjd9rqYDJ0TKWwSxypFaB2jt4+MfLiP010DUCkz4JpXU+7Ys883i4OXvr7BXVx++igtvHRFXJaXQTILz+WIJrpaVSm+5uHjFs2dfMh8fkQhDvZgSQnRz9XXN44dPmF1cMNoYUHrH+fmM8dmCqnScnk45Oz/hVjXBzs9xk1e4coGzUVMQihIVDJmvo3OHaBmp2CrtbbSjlk3psAV2LEEiDV3vmglLrtrGvSdNEuq6jmyDMc1kLpex9K0PSex2CY3wziGDRHqJ9GAaCxyhJNJ7EtXknxDr8loJhKtJReCdnZRRZ5/HZxVPTha8HBsWledoavBuinOe2vS4tZnR15AIhw4S5wNVo43JdUz2pbmW2y4UYx1ONBojz7Ks17oOhxCaz6KiLbn1S8Dq22Mq4vkX7UKAuOrTUtDNFN1UkkqPEoHaO4RI0IlEeRXbGLXCW4ds9CjL3CchIoiSgjRL8VpSVyVCa7Iswzapt1IIrLG42qFTTe0NRW3RUpInWWQ5QiBJohg26wx4eTJF6ISNzRF1VRAEZFmCqaPXUXQRjt0KSimKqqI0Hj+rIkhqAKXWMp7jpiRmbWNgJaJQNjrbCiZnM27fuo7zjsn4IhrKSY0zzV0dBE5Inj89AQEX5+NYFO2kdLIRVeUpmzJYXdfR3VQmhADOBKRMCDawqCoOhhsooXl1dk5RGLwPaCl4+vQ5zhuqukRKqCuLNfG8aaXo93L2d7ejOH1+ztHRKyDwne/fJ+sKRCI4vTjBMmWwuckf/+vv85/+vz+Nx10nEQTrgEZi63huj48nXLu+zcvDE85PKs7Oz5fAt9vr4p2jLE3skBtk7Oz0MXXFbFYBmqqyUd8loT/IGw8aS7EomU1rzs4eEIDhaADSI5REJQ6VxC4a7wyJ6lEVKlrJi6ipUii08MjMcudGlz/6w/fp97o8fDJBdwboXkZ0u7YRmATXCOI93sXybcAuox9W42yrw/uGcf5SKSQK8KWweDvD1mfcv3+d+cyyKFrxuY0QyEOwAh0ko0FKmmY8fXHOolA4n7GYBawrETIn1axoTgSt8FULhbeq6cJRyz1CxJJ2LAM3PieyBSHrGsXWamL1d0Jbrgf+MXT2j2z/1QKU5eFoV/nNLyM4XXNjbR4Tv71+EL8J7Yn2BeOjgPWQwNfBCUtA8sY9Z2VYtpahs9wnsZzgQmgyXHhjFWsJghBt5B5rr9N+puZYXPm8LXW3cnxdY4IuPW4FSFpTI9oJ/RJwiXsaCYm4ymj/bYxlNpvhjEXpVeFNK0mv18PWJdOLE0a9lETEGmfS73D79jXKxYK6KJicTqiDIxhHr5NhTM3FeMHp6TmL2ZgwPsLPjgiuINWC2WJBXdQ4GydPrWNBztEGf/nlTRePuoj3aIhlnEtN4iHua1vuUULi6hqZpBHohSjms23XVPsJm0HLN+3iTWIUIsSciyAFQcScnKjvsSQi4HxANjO9DwJnPdiagU7Ihgk7gy7391IeHpd8fbjg6NxwPHdMHo55flbww/vb3N/N2co0XRGzhlQSHd+sj4Zb3lik1k1OmWwGyPiZrY32/FKyLLG0f5NC4Bp6W10aUdpzbeJnUREYBe/JE03HQzeX9PKEbuowRkTldlNGazy5mvdt9E4iCk5TrRFKMV8saCPXAIy1ESB5j24EvyH4GHZn6+Y8y0bEGKiKYmmZ3tGaxHs2uhln05qL8ynBx26dbpqgE8F4NosBi819WlUVzjlGmyNMVTIva/qdhOBBJwrvHcZFQbuUYjlee+coFiVSKIyXvHh1zmg0oGpAUKsBq2uLVrH1+uT4vCnpezodxY1rN+h2hpRlQd7rcn6ywAaHC575dMpiXmOrGISIFCR4elmfVCe8ePES5xxZlrGx0eX99z/i6OSQw1eHVFVFEJCk4H0874PeHucnluOjE+qqZv9Gl5/84Q+4de+AJ88f8ez5GY8fvyRNJe++l3Lr+i5/Uv6Q//Qf/4aLs4K832U8nzULQYV3cHwyY3t7k0cPnxAMCKHp91MSnaCQdDo9qnJMXc3JMsFwqDC2S5YLBAnOC87PZwQhY4mmnNHtply/s8vJ0QVHR1NUIuj2kmg2aAM6gySJ49doMGB/5xp10XSgBYmSKZIZua64dXOD3//JOyRJws9+/jUiuc71OxKcJ5Ftqq8nOBuzqVxT2gkBj8EFF8e9deb5yvi+HE8IhGUMSOPWLCxCFNRVxe5mh52NTZ69qvBeYm2FDxYXomWcdJ5Orun3Ykjh0ekE40CquPhQVpEkqzK8R+CFjCaUIkGExsMkaGIXpVsBJtGOz4q26aFFOe1iK95WV2wq1leey1/887ZvNUBZlTFYsSErGuTKwWpgo+DyRPNPvH586tUDe/VZV8o97W/Wnr/yAIktpYJ1H5F2wHtdTAWr83ypJLP+/7XfvekSeL3eeaVcs/a1/LzCryHp17c2zXjZaixao56Y7honhjggx32nKSvF5zvvmM1mVFVB2umCj8hbSsXGxja7O/uUF68QvibVKcZ5dKbY2t5FKyhmCybnUy4WczKRIUKGFRPKxYKzoyMWszkbWR8hMggKETzKG4SrIYio0zAmTm7NKjciuzhIrJvPybVz1mCWpf9L7GCJdKi1DiEdurGgd86twMka+xBN61pmToFXTVaHQ8mWfYqsnJIKIUNT643smbXx2EZdjCEVgW6SsqUSbgw73N0b8pefvuDTlxVTnzA9s9T+lBC2SQ9ypLd0ksjUSBETmRHRVZdGdKqkIJFqCShbwOS9bcpB4soKieXqt22NbVmzNuPJ2ThgKxEZoTyRDLoZ3VxHIznrcc6ilCJpWSdCUyKKg6B1sbPF2QDOowUUizlJmpHlGVUVbeR1EgWtqU5wwmMb+22MI02z2FmjAJ3EkMYQlUBSBLppQt1RTMqSja0BUnjOx2MQ0fY+CnoDnU6OEBpnPYtFEcs33qAlKBFwvo7MSYhCy3aR4p1FqgRrDImO5SgbPJP5DEc7MbSsbDvhBaRX9LtdskRw/eY2o2Ev6jZExf71A8aTBZNpxcX5nLqG4KJ5Gj4GVHY6ms3NDYQQnF6MkUIxHPTYP9hmOr9gXlzwznt3uLiYcHJ0ynA4oJt18Tbh1fMxZycTgneMNrvsX9tlUU14+SownVWcn5ecn1bknYTHjw5RQtAbaDq9hPPTGf3QQ4kes8U86hkI6CSwKBbs7+8wGxfkeUKeRX8kqQKJ1831A0I6ul0NdBgMcqrKUZYO4zRl4zIbfDQfm04912/uUSwMQkHeFdTWYWqPzgRZHiMUbt++RTffwpYuWmwKD1QkacXdWyN+8Dv3ydIu/+t//ltOxp479/apnUd7H5lPG8XfztFoTyzOVVhXRzbFrxy018ve7XSy/F3jjyXauT8IkBBcxWw6ZXerw/3771KXFuElwcYYB+9jYKHA0sk8W6OMRVHw9OUplTcg1RJg4qMvURudKlAQoh9TMzgjgmrGsjbjq7WRa+c11+y/b8b7FqTIZnyLwvm2o+dSQWG9ovDPwCnfaoDSDvptmesSQbFkACI70YQFvIF2EMuvJRUd2p/FkpZuD3DLkrwprfiqUHe9RBQntrXJCrk8ye2E1Dqp0Hye9gQ3bsjL7onV8LXyfvHEmnWL15Y68LUyTlh2yLQgJa4uXQiI5jGr/Wve9Eop5/L35rFrYCWsPbZNNCYEVng8skDeSYpFRVnVDEKIN2QAhKLTHdEfbpJ3+ghXxJVoXeB9hRSaPO+QpiOSLCGZRkFeVUfPhPPjOeenp0wuTtncGOFcjTUVtqoxtW1cUWmyYeIAEtcGa+cstPXUtvzmG8PU2P0ipUIqgbPRC8CHQBCx7dY6h04TqkXNJVatPSZXQWJD+QYB0guC9SyDhq0DHdXyWdIk6VaG2tj4ehKC9SQZpMKTZopBAnmecnqWczIpOa4Epk54elaSiQtUGPLeXkI3TwnBYp3FyOjxkWgV2Z0gcWVFkiZInTUDlGz8T2yToCwwJtakpdT4EDt9XMNKxmspHmOl1sRdDZsWmhJQphWZlkgfE6W9TAherplyRebEWktZ1kvn4ZaNVM0gXMwLur0uidIYa8iSFGNqpIh2/bWNJblOJ6eu6ibNVtFajAuhsE1NI0szNlWGdTXjszFSQyfPKRY1gWh937InSiakaUYgYBuwOi9iCKEQjtpUBHTMGWpiDaQUCO/Q/z/y/itWti07zwS/aZYLs/3x5vqbPpMuxUySRVGURAogUGCTBXTXg0xBQAPsJAGJgCBI0IMMJAICGgIaoIRutEA1qkChWqVmSaJR0UgklWKSIjOZmTfd9ce77cMtM10/zLkiYu9zbhrWS2drXey794lYsWLZOcb8xz/+X3jKMqMoCjItyDOB8yC0AhsnUloKkNFRWoZINpXKIZXkdHIKUlA3HcfHd7l765DFvEPqjCgZJxAykhtl8Oxt7TIaVEwmM4KTXL98k9FGyXx2wu7FYVQazaHKFJf3LqFkznTa8uTRPgdPpggEeQk7F8cUQ8XR5AnTZsrdW/s8ejghOEW7sLz2+bf52lfeINcaS+xWnE87LlzYol201LZDZgLnA4fHp7zv1ee5du0CXbtgPCrxvqNpDLYDgoZgGVYD8qxkY+SxzrPoWk5nDUEL9h+e4G2GdxZkoO1qQmi5sLfDyWSCcx6p4zOuctB5oChyWlPjqkV8A1BBsDmQXLx+gZdfvgRC8Zu/8wXefPeYaryNCxZnTNQdCS4+P8bSdR1d12FMh7VdTMStJ7hwJt7Eck/f2dZjtAn7C7Guu0pjAlo6Lu2M+MD7nkdnOfcfnHKykFhiiScEiXcGFTp2tnMGpebRwQmtiV1EkcXQbzGOT6nISHKQWqLmfTKCjMnREn/vqwwBZFL/XgLmIk2mQprMLdOflbR/1K5ZTtnja351Tr7R8m2doJzFkvpAn/6WAnm22kIfnM+SPc/nLGKZMcIqOVnC/XI9br93KthrYZz/ruW3iHWi6SobXZ+RLpOktYAWE5BVMzNLFOncRX8mjEji25xNUNadks/+sCxLnDlDIg2yicGtEsFSJNXe9e6eEHqZ6CiP3H8++EDbtMznU3bDHlKsxNmyvGI83iYvKlxncFiMMzjTcOoNTdOS5SVSCqoyR9BFtdE8w/jA4dEhR4dP2PItoZ1TZYom0xQeFiagpKezXTyLoZf8X0e8zhog+uDOaJvEck+IMt8qst19IDreWotUIf5t7FMoXM9fWd0n/QQmpOqGwC/9OARKZkBENYxx1G2LdxGt8NbH2aUPCBVQKupdVEHyHc9tobTmq48b7h20TGbw9n5NVSmuXLzMrpBk3iU+RCATRFfihHr1WhTO+Uh4Tc6+SkU7ACEERvjlOjGhjr5A/cSh5+kskadEGA4i1unbzqFFYFhIqlygm0BtHVJmqXy25mHiPVpnCLnibXkfdRi0EHTBQoA8ywnBU9cNmVKUZZESCUXwDiEkSut07waqPMM5Q1HkEQELgeA6bFezvVHBxGIDjIbDRMwUGGcRWpOrjHrexGSVwKKzbG4MCNbQdpZRFV2j2xZculbWOaSQ5CLgTYfIJePRENPWDKuK4daQ2/f346PgE6IkdbwmQjBfzMkLwaKtKcoM0zlOjlsODyYsFiDI01gQeVSb22OqQc7J/iFbowHT0wltmXPj2lXqhef2O7fYuVRx7cplHj64zfGTE4LLCDbj1r0nHB9P6TqP0hlag6fG+I7nX/oQg7FEy5z69CtMDlvmiwZnBXlRURUZWRHwfoZtFYuJo61b9ra3ebB/kOJxlOJ/984dXnz+Kp1ZEGYNVZnz8P4B83lHroYMqjHdAgZbis2tHU6nE04nJzRNzcULu0gruXf/gM44MhXVVOfTGVub17l37zGdbZFZVCTWUpKNFUIE7t67RbNneeWFD3Dv3Ql55nnx5g7XLud0TvGbv/0FvvbWIa3NKbzCGo8xLabL43MaYkeZMd3yx9lIenfOp4Q+TUC8SIE88VLSxG3V6Raf/di8EShzkNRcuXiNzc0dvvK1e0zbAkuRCPsOvCMXhvFIMBpqDg/nTKcuGfnFcWEpuk16CNMvsZwOp29fEl37aWQfUyPq4hM6HsNRWJV/lma6MiJBSxVZlp9n/buf+vvrL9/WCUo/4+1P2kqjwS+RhGXpokcj+oxwuayXPMQywK4gjLXv66/ve2BUq3bj97gA36BU1HfY9JDfs9ZZT2xgrYU4bmBtpnq2lJM+HWevfk0P5qlvWH/9PBfm7L4u26TXylRPbWMNwenNr3qnzrbrmE6nUa1URhpoEDE4bmxtUQwqaj+ja00qO2S0jeX09AjnPcNBzmBYJA5IdDctSslkOmX/4IBL0kA3j6RMrdCuRyyiYqpPz6P3nv6ML9GjtTMTEhgg04NtrY19/yq61rqkEyKI3S3WmGVpBziTkFhrz90nMYn1LpqfSSVjCUel60WcPYcQMMYgpSLPsqSq2uGMia7EBGzyDAnesFuWfO+Lu+yN5tzaNnz+3UMen3Y8WBheu39EFiqujTWF1oRgo2u2jbX4XEfRuA5Qyacn6+XuXRyUY1kvni8X4sAvILYFp9PXl3ZWzxRkKvIhWmsptWJY5WwNS4ZFQ5E5ZsbiTIfKokKs6VwSm4skwzLPo4Gfiro51jo8gbLKadqa3BdRgt6Y5F3T4lJiIoSgaRvKosSYLiWWsZ25aVo2NjaZTaZoJSkLcHg2hhUn04aDx0eMxkM80JiGLOTUdRNLOM5hvEdrSdsZsA5UINeCTEdCbUTfYlIke28XZ1Faom3AynjdvYjlRWQkjAuiB02WFenYW4SXSK04nSyoa0NdG4yLQc/jUcKT5YKLexdwrmVUZey9eIOdzQ2aRIxt6zmPHu6DDFzYvYB0Gd1C0swUR4cTTk5rmjYiSrpQONMlRCaw/+SIhw+P+eDO83RdR1mVlGWOzjU6L2ia2N2SS6gGAS0ytFTMZlOubFxkPBoymc9RQmOsYzJtuPfgCdevXuLBnXtc2N3l5RdfoJvd47mrr7K9dZknh+8w3iij/9Cb7zA9nbO9scm1q5fYGoxomprHTwyaHC08WhQIn9M1seSoc8A7Wh8Im4LWdNS1597dW1y/usXFS0MUBZevDCjKjE//x9d4+50jjIllTptKs8Z0GN2lBMWlBMVgjMFau1RZXjd3jdy7NURfxM60INJEUMRrJwTJwTugheHG9Qvs7O1x684Rk4XGSJkQjUDwHYX0DArLtUsjZnPDwVGDCxpCKl0vE4WvH7PSI/rU6N/PjXs+YkR6elR5lcCcpQisxYs19Dh9dLndb3b5tk5Q1pc+EK4nLasOG4kIkiBXhMQVAagvZcA6DJWmMGuZ5wpJWZV5VqF9fYa8/v5Z7sc6qrGGrJwpASwxnGUi+nQpKf7vbG7Sf2884qXc25kbZK1rR55tMz5fvumP+r06mGK3xlnTwPMksLDc2XS8yfiqP5fWWuazGaZrybIqrSaQImdjY4+dvYsc+TnOtxQ2j0RU4VgsOk5OTtFqk9G4oJ9h98n7yWTG/pMnTFRNSUvwlkW9oDVRadTYJu6LT9btiby46lBK4GtYJYE9PWU9Eesfwj5BwUWF01U5Lp7bPlAv227XS2EyJkS92JLr7910jrz3uBDRCE9KbGT8tIrKeInwGa+VUipK8wfIvOXV7ZwL44qq1Hz6qw85mXf80ZsdhbdUL2yyW0pKQXRDDtG8UYtYOjE2WrIrqVbH2JcLQ++J09sYpARKqQQ/h2W3j1gWJNNg5z25jjXwLFgqDcNcUkhLJqETfimDHpEYmzp4YkALwTMajmhbg5SRFBrNBn3i0ESeTNd1yEohpcIGtxwTrLUpMekJ57G1dzqZgQfrTWpXFlGCX0hOJpFjEk0DM7yPnWh5ViyPK8ty6qZmYzjAmo66NVE/xXuUEmipcCGJ98VMEikEdVOD99R1jW+zRE4GhGQ8GqMziWkdWZbRuRZjPYt6wWzaYaxgsbB0HfggQTgEgpdfepGLFy/wpdf+kI3RkFFWcXJ0TJaViLnlaH9KNRhw8cpFvFV89g++wuPHj5kvFrGQqRQqA51p6qaLOj1SIJXgdLLgD//gS8wXNcNhwel0QUCwWDQMU0v3bN4SCOzslIS8wHee2dQwnc64vLtL27R0JpbL6tqzfzilyEsGwx1Oj1vqqee7P/ZxxoObHJ/OGQ42uHJ5l3u3H2IbxfNXXubq9V32Lu9hfCRvmvar1I1B+I6yGDCZzAlO4kzkRpQF7OwU3Lh+lbYxvD15wHzW8cUvfJkf+oGPc3lvG+UHfOHzd3nzzQmdKXHB4oXBhw5rDcZYjHKpHGOWCcp6crKeoHgXlmKPkUnUuxaHZXSJQ0tEVLQIFJkh04bxeIP7j2YcHls6UYJQKAIq6aIIP6WsJKUecvd4QmOgc5Fg7kNCylMce6/l/IT6WfEiJiJ9cpViYWTSL4H7vuSDWI2R6+j/2eWbL/HIb7zK/+8uzwqwgdU5ielErJGtYKf+vaeX8xfrPKH0G+3L1/v3N9pOD4X34rKB9U6aeEw+3fh9In6+a0kgziIqz/6mp85bn4ic2ZflHffsfV2iJnKFopwn254/9vWkJYgoIz+bTWkWc1YXRyDQDEfbbO1cRGZ5SqY8zaKO+hBSMR6P2drajO7BSJrO470kywtaEzh88oT68CEbReyTCQiKvEpwuVjylfoupGVi5fzSzbk/n/F9lYSIVsceEozrnSfYFUqSKZX4QE+fU60UWqqoupjGkJDgUIJIHUApbAoZdUmMxZgoAOZ6sT7hk5DaStExQqzRnr0zLeAoheHiwPHByyXfcW3MxUoTyHjrccvtY0dDAUJhfCCojCAzjPU4Y+JMzaVZoHPLFvleur4/LkVf+oqePcKfRRK9c8kvxNObu3rvcLYjzySXL2yzvTGgyCSZUvGcLC0D4s0eCbgRphdCMZ3NMaY9U05imXxEsnVWFLGDBrDWRORMxcQ/yzK8D1RVRVVWCCGx1kU0KMtiEmktOEOhYTzMETjKImd3d5tM63gvIVAqYzAY4YVA5xl102GDBJ0RRCp9poBFiF1JiDgDj9oucYLUmdjhlKssCuRJKMuCn/jxn+D7v/eTsdUzQCYVZV5ijWcxa2kXhp4HoKVEiwzbCr7whS9BsFy5OGI4EGxujbl49TIh02zt7DIab/P40TFvvn6bt752i2ax4OVXbvDx730/Fy4PQJkY2npUTEJeaKRSHB/Pee0Lb/HFL7zBrXfu0zSe4DRHRycIIcl0wfzUcHLU4D04arJSsFjM0VJw4/IlBrmO7etB4Z3i9HRCmRc0C8ebX72Nt5LFfMHh0UN2L2xwejrj9dffZj6x3Hr7Dif7hxRCs7O1zYc/+AFeev4mo0FOnkl2dzaiXD/RemA4KHj1fVf5xPd9mO/8zo/xoY98mKs3LyMzwcH+jK+9/gZ5nvHHX3iT175yh7oLWKKcexACgsY7iTMB0xmM6eg6s0Tq1n+WnL+Q/u6djFNSEqdpgsSKoS+RCOEpq0BeOF56+SXmteTuwxmNjeT66ILeElyNbabYbkJRaE5OHYcnHRYXJyxOJCfktQToPWLPctw7U0k4/5lVgrMCAM5OaFdl/TVNrDPftGYa+l8LgvKe8T7NQFcE1H79VcB/6iPPyCKfhSp8vc+d3bnVhTiPtqzv53p5ZB0m6+Gw1dVclbDSFH2VzXydY3j29z7dtbP+7xW7/GyZ6zynpk8B3zsxWUZfljyZ5a8I2Z+eHDOZnLCzdxnWCF1aV+TFmKbzWGsBj/UG0zY0dU0xKKiGJVopmi621c2nnmZhaFpPfXICOx1KRhfO4AWdjeWQqDgZO2LCahcjzLp2/JFSExM1KdaSQCkxXQdEKfhMqbXzHM+BUgqX0JU+cBNWbbsqfUbKvlulR8QCsc00tRa7QK+3I6SK7Y2sxNJEUFgbZdzbtkMKjfeOvFAo5cB7lLDsavi+Vy+yPRrwlfsnHB4veOfJgstbI3QpGKgYNGUqO4gAmdax28WYJHkfW4B7YnYsnbDURFle57X7pD/OyL3xBBlr3Z1tsUFEzojvkEnfJc8VbccShemJ1lmmk59N0qqQMhIVeyg7JZPGWvK8QKootlXXDS5TyOQ0LISK8vMpgWyaBpmSBqU0bVsjhcZaEMnhGRkoosk100VL03Q4H5NNHzzGdnStxzoXPYicwwqJEoHgIvKhISYYskfmIjFdEN1npUhDsfPkUuG9Yby9hbdw4+olfvzH/lv+P7/0S/yvv/xLbG1tMh5ucJzNOG0XhCSnL0K8T72zPLj/AOcbdnejA205GqKLEi8Vx5MTpsdzrA80bUuuMsqyRKiWnZ0x2xfHvH3nLZSOHWMrZDGQV4oyKBYLx2y6YL4ISKEodEquRUw09vZ26eqGZhGw3YyLl3bY2bE8vHdEvTjhuZsvYNw8th5rxc7emIsXh+xubDN9skCLDKUlb9/6EoONkrLa5p23H+BdfJa2NjeYzWr++HNf4srzL/Lo8UPAcuHCmI2tPba2h4w3NdaPkEpSDgIXr+ySlRrjW0RmuPH8HvP5lKPHU+49eMIbb93l8HhBa1Q0ecSlMYxUyosCeka1CBEJ9s65JXrSj8/O2ZX8vF9NNCNhlFR6idcrAssOKRx5HtCZ47nnnqczOffuHSPzAblwKFxMZ1RgNFB0gBYlpzNL5y2tL/EYokGmxK2Cz9Pj/7kkJCzH5fMdR5xZT6wjv8tJLAm5jhop75V8fDOT/Gct39YJynm0ow/uKcSn/9JNBqubYxn4n30xnrU8a733Kn0sS0Ipvq9zDnpgoieRrru1nr85lgTDZQBdC56cPfa1NZ7a71Ut1CeEwCc559Wnnq4lnj2m8wlM/9CdR0+edV56Yqh3qy4k7wVNvaCuTzg62OfGjRfQaypCQuRUw22EKJBSozNFEJ55PaNtOqpRlWzRYxfDw4f7dLPYduetQzczRiisrZmcTpnPaprOElA4G4mKCFYJnxDRCr0/lrVkJVoRJLgyeKTQ5FkkV/ZH2gfpODjF0odWCnyIP2uJXUhlrpjwRd5HphXO2wT9B/rWgn7w0zo+qjYpRkoho6qtUhRSxo4Ja/AuIkXGRH5EEFFzokBwuXRUz48ocsvnupZHTyZ8WRvqCyXXd4YM80ApA4TI2YhtjDEZiEaDa+Uq55blx1g2iaJvSqt4jW1ENM4YUAYQIUR1VxFh+UW9wLQ2+ZbE6xKfF5VQGUEgKv72RoY68WFkmnxkWeTRZFlG09pIdk3PQV7kUWhOkma0nrKqWMwXZHmGtV0saUiPaRc4Z8jJISEqea4oCo2jQ+V5JCo3jp3dXfYPDvHEwBWT6qjEa33AC4dXOfPOUuAYakGuFdbHJEuke0aEQKYleVZQFALTtOSF4oVrN/izf+7H+JVf/hX+p//xf6SeNFzY3SPXinYx5+CRIZOCzVHJ6Wl06gaFlIE8V5SFwjvNoMzoWo/xlicHBzTGcXR4gusCQgvKQlPqHNN1BGt47bWvcOnGBVCKrBA438S7VSWyuHIMhlGIz7nVOOCDIy8zQhA0TU3b1ozGA6aTOYt5jRD7/Ok/86e4cvWEr3zuTZzveOXF53j71rucTuac7B9y/coG165c5t0v36bragbjjC6ccH3vJWbzOdYKmkVs475283mODk9488u3+aMv3OLx/iP29ja4cn2b4bDi+HjCYDTi5PSY+aLGBMujx/tcuLRL5wyLZoJjweZuwcbmkMXJlEf7DxltXiKIJnayKIcUHVkeqEYaoeZYN0f7CiEiUnEePYmJSS/I1lMJ0r97VDwkVD8Q5Q9kQEpDph07O3tkxSZf/cptPJoqd/jQUgiNsJbp9ARXBq5d2mU+hZOZYOEMnY88JyUsXqz4I+vxYR3Ffuq1tdjzXmV9+tF5LR6sGlFicnIGXe9D7ZlY8szNvufybZ2g9CekX84nEUvSTq+BENdKAWktizyzPsuZ7XvV5p7ajbUZ4ypwxx08f9H7zpceDlPivQmm6RAj1B5iMPW9iFqP6i9vrjWU4hlp7Nkb8T0P5ex+PCNpWZ8tr3/mWUTZ5T4l9CckcazgwTrL8ckJXXvK0eEBxrSovCJ5/RLQDIY7jDcvYJtjAoYsj7P8zvrEig+YLvqQaCkoN4aAQJxM2SsChZmhtYxtoCFKjxtniU6pyzRyubOCdYRo3cNoPaFgqQWiUbFTR0aIViZES6duHuf8U+Wz9fswBne5Oq8mJkJx5uXwQZFlUYUz5lCxpIaTaNWbD8YOqUjU63BCIUJBpnOCMaBi67CSgkp5ilzgLg3RQvPwyRSpPMezlmEhKWSOLmWEklOiIVV0QI7PRBwEQ5oZqqTK1rewKxVNBp2zkdgrV/eOTzpA1vUS2TIiDqiEBAUKrRCNx9topKh15J/0br42tQpnWYbWgq5rsTbgQyQPhwBVFcmroipSmSQiLdiYFDnnMZ1ZDqr9PWudI/hAXpbpvlfoTOG8o6sjWVTiGVUF3nccHx1SFBmtMagQOVgBkCpLPJnAdN5QZBnCBoZ5FhNQsSb45yMC99zNm+zvH5JlBXNruH79Av/nn/q/8KGPfoLv/VOf5D/++r/lt//jf4yiXM7RdB2L2YLhMOfC3pitzTEuBBaLBp0VfOADH+D7v+/7+LVf+XcIGuYzxcH+PgcHpxRVQSYcFy5usVjMo0WA1GSZYN566oVjNmtRmUZlnjzYKITWyCVnpygF1kDbCaTUkSuE4ELyFDKmZTqbMh4Po74QOtozZPDBj7zEweNTHj5+xCsvv8DNa5c5KE6pNnKODw9xz1mqqiBTkqs3LzNtn4cguX/nCXdvPcR0husvXGW8scFb7zzgweMT5q1lNBpRDQZARLLeeuc+R8cNbRtw1pGjODg45fadBwyHOZPpET5YFs2EYAXDzQH5SLAxyKlGHVZ4qnGGDYZq5BkOOsbVgqyosTYgREHwYq1bZz05Od8N2SsIpwFnqXsSCKFDKShyz87OmJ3tC7z++rvUbUdZVijhyLWIRoGzBUEaiiqjtRM29y5xeKfBJ90UnMKHjiDccnyJidJ55Hs9QemHpNXkOYHGy/H7DB3gfJx6xqR2PR64NemKb4Uy0S/f1gnKCkUQZ07A6v317M6vZY6rDpRv6nvOIQNfLymKA/mZF55R31tDI9a+Y30wP7N+utEi6WqN8CRWnws8vR9n9i3Emfz5GuOzMunlcZ47R+91Y50vU51Z1hKplY6LYL6oOTg4xNkJJydHdM2CcrjBCkGRVIMthqNdjh5HC/bRaINF69k/mDE5XbCzO0RKgVZw5dIOMpRMp6eoVvDC7pCBnFPPFzgfO0HifkSYVaZjkaInqyWPnfRgr9qKAyJ1HfV+TatkMyYlyy4eIdfO4xosuoY29SUP71fdPCENcH1AjSa+AYKIZNFEvHXWASrqkIjUZiuiCJjtoqx+UWVkmUa4qDzbNQaZ5WglkDhKKblYZZTXSvYqxbxu6eoFTd3QFZJQlHhUTCSEW+6/CGHpU9SbQ66XTHszwLODULz4fXISlWZjO3nTmSW5OtOC0aBCiRbhLRKP6TqKsiDPs1imcX4ZDBeLBVker1WUW5GYpkUlmfueB9AjOyFE076sil0wdV1TViVt26YOm4jG2BAwJkDmkVohgK5zWOujTYKPxOqqlHROUA0KzDSWmaJqaCROjgYVi6aJnR9SUhvLyGdIGcD5ZOSoCT5wcXePH/uJ/45/9v/4v9N1bTSXdA1lmbG5scPw1RH799/l9PiYL7z2Gs5ahAiMhxu89PI1Ll7aYXNzh53dS+RFyebWFT784Y+zubWBN44/+L1Pc/v2u5ycHDAeKW5eHzMe7nLxwja3bj3k7q2H3Ly2Td20PDyosVksaXWmQyiSh03kfQWrCJaYxBKtDTwgpacoMoQMVKMCf+SRIcRJRErIsrwCmfHmO+/QBcfprObevYdcu7LLsMq5sLfLg8dz3n7rFk3bcPG5y1SjMXsXr/CFz36ZR3cP0VSUo4LRcIMvvvY69x/tY3AUQ8FgQzDeyigGjsFYozJNazqCDKAC1kraVvLwwQO0jiXarNRsb+8wnZyyaGZMJxO2xwtefnWP06nm7v27VJmlqByZXuCFZzDepZ5qTKuXPI/+572kGs5PGAUhJScRNdE6MB4VXLpwiTt3HjCbTSjKgvFQUpYC00ZX7KwqI8fOn3Lj0jab4x3uPHiAclHnxom1sv+K3Lbkvyz3aR3VTPyXNI2M/K3EfVtO8Ilj0fpyhgZAWndt0h+5fSvF5T9JcgLf5gkKy8C/xs0I64F9LaEQsXtnWTYhrbck9ZwtrbzX8vWSlGWAXgMx3utyrC7we7xOn2FDzyw8C8WtunhCWG+d7jN2VjXQHr04B+WJ1Qae2oe+HHV+v84+hKtsWSm1hP+XyVY6vBDOHlfXGQ4ODjk6PqbKHUdHh8ymU8bbF2P7aJJvznTJoNpksbDYZkpRZkiR4b3k5GTO/GRAPsjJtGJ3a0jbBayFy8UGV7dKdHdC05llicS4KKympcI6S+89FGf0qwds5cwcZ9ixgThS8fu7R4RAnmWRAOpWs6YliTWhMd47VmW/fkbjl+dKCoHMU5eMiJ1Rhc6XaEEIsQW5FzeTycTQpZMrddT1UCJ55KiAI3oBSWepco3QgAwoAjI4BlpCqJEbgUVZMM8h8w6BpOkCWilyFciEx9nEM1FxShXVcMOS5KxSJ1csl608ioTs7Q1W940QkUBcd91yshCCw3QdSkQpqVxJcg1NCCwWC4oiT9cudkqUZYaU0Sgt8kwcSmqscMt7syxL5vNFVMnVGkEkNoYQy0QGQ9e2SLXqPovnLpaS2jYa7PUS+1plaJnRdg1agURS5Jrjo1OGoxE+hKQB4nDeMhhmlEXBpK6pO0shJaezOTvDgiLL8M7jfCxnWWv4wz/8AxbzOV3XsbM5Zno64ctf/hIf+dgPMj1t+LVf/RWePH4YRfJyzSuvvMoLz73IF177Qw6O7/Jd3/k9XLr8QcabYz7yke9HZzscHjzi+OSAx08eMZ2fcPFyyZ/6+CtUyqOCpaw69r7zEu9/cZt64ambiuFmzsPTEzoM1nexIwxN07REYrnEO8WwGjM9cQgiJ8PhKPOMR4+esLu7y+bGmGbRxtJSF52L287zxT9+g8OjQ7pOYoPg/oN9hmVOVeZ0TQNB8uTJMYvFApmBdYK2hrffvEc7cwyLkuefv8qd2w95584DZJGztbfBop0w3MwYbw949PhdXv7AK5TFIaY7oawEOo9+TLNJixQdo1ERZxpeUlUjus5xNDulnjpODx5S5Sds7uzwyivPM5sfMV0cEkJHlhl2dkpuH3UEV8ZnM/T3XV/COeunQ5+8rMeLpCcicWSZZzjQXL92g/0nxyzqKbu7I7JMI/G09YxMl+T5EOtjR9He7g7VVsWHP/oix4cd77x1iHMGL0zkngS5RE2WE9i1cs+ZZCE8HReelUQsJ8DPQNXjKO+XE9pVA8X//h6cb/MEpV9iUPZrnhyQZrxC9FTOBK8Feh1R+kp1WP0tEnPlvZKU9VnxeVhrhYoEgkhEPFbJQ9wXudwOJGlgkWbm+GWcjPEn7Z9Y33di/3xqNY3rruqKq5bO1f750LPHQ2wnJT4wQYj4+9zx9ft6/vfyBvakEksPC/ZW2+tIViJNhT4ox/PinGXWzDk4fBTbKwM8ePSIo9N9LvkbKJknfCva129u7hLkgEcHCwQdAkmelwgfaGqP0FEUzXmDcIHxaMwrZWCzcJjaxCTPr3NlwrL+HzkJa9cwpLtnDRnAx3MmZX9dY2nOGrsUYlNKE1zAhShm5t1ZQ62lHkiEjwiBZTnI2r4bR6dMzseguXSbTuWREM9dbEjTkYxJwNqAtTVFlpHlCiX7pCss9VKi0JpNIFogk56BDlRZwdFpi84V9bzDWU2rXKTMeNCpYyM6C4NLsK9NjsXRhTlxQIjloF5nh1ST7u9k0iBpe3QjBLRQqX07WgSUZYZuXOL/JJv5EFvDbVKtDd6SF5rgY0lH61h2KvOczhis6cjzgkxHMmVI7dlSZzR1i5LRfdqHiGKMhqOI0PjEqZFJWTghXTaVa7Cxg0hJjQieKhMspKRtWqTWsaznLQ6YLxrKQseWaeewBBqgdoKiyJG+RcXsnsOjI955eJ+mmdNZx6yOpOc//vwX+G/+9FtU+ZgbN27w7jtfJSsUo80hWV7Q2AUb2yOOjhs+99rnEaXkxVeeZ3f/Kjujjt/4tX/LZz/3OY6Pj9kcal554TJaGjq7QBIoxIis9Fzb2qKeW/b3JzRCoRYC500UFJUCvKKQBUIpGhPPRWcDUmvyHLQmtrWrAmMc0+MF49GAjWoMSExjaFpDvaj52tcmSCWQskSIHGth/6jmg688h84bplPNpRtXeevNN2Ob8OyUz33uS5ycGILVjMZj3rr7iIePH1JWJVWpQBl2ruwyHlfcunsbnUkG403GmxU4Ry5KqkxhhabzlmYRNZfKSrBoWu7eeYggwzQa13m01AzHm0ymU5quZTyu2BrvcXr6iL2dbW5ev0gzmfD4fofzUYnYE/BS4PB4YZOnjuzDSvp3Gif7Pp5gKXLIFNy4doW2aTDWsL29TdO1cYyVihAyWiOR3iEzx3gj8NHveoWT48ds7xZ89ydfxcmv8e479/BziyfHSYVwjrM6KD0SAqsW4TVEPaR2aPn1Y98qPoRVoEqItxAKhYoq6SnG9kDOcuKeYtM3u3x7Jyiiz+ziINgTk3qIXp5PGuIfy+u0jPv967BsvnkWz+IsuvFsyGsJafXeO2vv9yWOM9tJCUp/LEs0pL+7l5Pvnr+RMvKUmKi48dXxLcsyZ3vf++9PX7pU6Vzvcur3/zw69FSScubQ18m/a0lNuizrtUxjPXVb83j/AaeTI3wITGc1d+7e5fDgCd4alOqPOwpWbW7vcunSNQ6e3OHk6CHBGQZlhRKKtnWgLDJXUQOg6ahCzrbqEKYjCElrIk8hyzI6E8mlPqEQfeuqNcljIkmYL8s79Mz11eyhF3Xryxze+9hRgk/1VoFUMsqsS7FEsASpvENIRNB4TiJaE9VprTUp+1MpsXIJbo1ZjZIC7xxoTeRTJCdkEfDK4b2IJnqEqAtiDJnOlvdbj8oI4cikwAfP5qBgVGkeG0PTNGRZVAENzmJ9eq6IPBbnPC5tW/bQsE8u2FJijDsziEVNmFh7V6kV2AebEAuHC5bgBQoo8izJ+xvwUcdBqkgiVkovZ2dCgFZxmI/+AIKma6MKb3pWtNbkeQ7B461FaU2QCmOiIJ3WCm9iW/h0Nl3ew5nuNVd86r7SaUYsEooU7x1jLZnO2BjmHM8aVJZhfcB4Hy0Pwsq5OjUPEaTidNGQKcFQxRTceE9rDG3X4oVHCI91AYTm1ju3+Pn/2/8Vax37jx4jFFEIbmK49+ARb995i+s3LjFrDNa3fOlrX6BxUwgFs/3P8Bu//h949Pgho0HG7pYGP6NrLFkumdeLOCGSJYPBAJ1HXxyJA2xU3FUgkHSNYD6J3i9aKxaLlmySMRwOCXZBUQ1w1tA1XTxOIVhMZuS5ZmNjgxvXrvDw0RPmdU2mcwajIc5pZtM5Hjg4mvH48TGvvnoREQ6oZwuChWbheOP127z91n2ODyNBdv/okKAM480htekwJy3Xb15kY5Rx/+Ed5tOa0bgC77h+dZfXMkEhPC9dv8Fi3nH/0WOCVdSnXSTSF4KurRHB0NYBZwTZIGe8tcmm3MRZz2RyxOZmgVYZg8GQvd0tLv/gy/z6r/0RR8eJZxbhQiRxQhGQ2EBKXnrhTbEkwIfgKDJQyrG7u4l1joODQzobEMZhbMB5SyCQ6QqlM0IwaOV5/4de5EMf+gBvva6omwkvvHqTYjCgrAQP7x1x//4E4x3CBYRbycgmsGQV/0JEPPu44H1AyrNl/qfoC2sxIU7i1+OFWKHLcahclf3XHZy/+dwE+BZ1UH7u536Oj3/844zHYy5evMiP//iP8/rrr59Zp2kaPvWpT7G7u8toNOInf/Inefz48Zl17ty5w4/92I8xGAy4ePEif+Nv/I3USvqtLv1ZP/9qzO6WJ289zp8rW/QliLUXz2aW55avV/5ZQmX9ujyd7PTozKoMIpZB6htteyn+s9zcqnSwvm/PSq7W3xMhxI6Vc9t/+hif3dnzNBzY36xrSUrat36zPrU0Hhwf8fjJk2gL7ywnxyc8fviYR48e0zTNMjMP6VwNqgE7OztsbgzZ3hwyqjKqQqOVpDUd09mCydTgbIF0GUPvGGcSmUzZMqWXctTLThx6BKMXExOxtVbEJELJ3kQr7rtKSWRUmugJbitSWZ9UFlkGIbYZxrZVlfQy1HteF63Ucl9kXy4JUahLKxUl34GqKCjLYpkULUXQUoIpkEnpMnqD2NRu2wfr3txwVYeO+Nywysh0JM9K6SmyiORIFY0Qg48IUd12NE27/KzzftluHEJIpaDVfbIuVBd8SFL5ARcCxrqojZHKsnkexcm0jAmWVn1HlEuCalHQq+9kckl2HxF1T0T/mu95J1FzJUvIRp5lKBETJhccxlmkVrFM5QPWuYTGRyJwX/ZRMhJyY3LboVREo/K8wAVHriWjMk+z3yi733dt1Z3FI5NXUDxfxgWmiyZ6qUhBEMkCgkCQirwsEDgyLVnMZtx69x3efecNmnYWdTNCRiYyvPXs7x/z1rv3WHQWFwR1bSjUgC/+0ef5lV/+dzx88AApA9ev7/Hqq9f5yIdf5drVS7RNy8bGBpevXGA4rHDBRuXd1sREmeTKDQihaVqH8w7rDNYG2hqmJw227Xj+uetcvXSBYVGyvbnJsMrZGFV472kay/6TE4KPYndFVlKqAcHIyAszJqGCnnfvPOD+wxPybMS9Ow/oGsv0xPDaH7/N0cGMtjN0do7QluFGgcfS2Y7GWB49OuCtN+9i6oCioJ4Z2nnNxb1tRoOoXVMVkpP9J9A0XBgMGKmCburo5mDaKDBorMH6gPOR5D0YlGgNWguauqasKmbTGqlgc7PglfdfR+aJexYEykfXcY1EuKRtojzIWAZVAYQPSDxVocgLxWBYMa8b7t5/zLw2GAuzecdk0rBYWLxXBGRUFBae4bBkUA3obODmCy8wrecoFfjgB1/hh374+/i+H/wOPvSxmxRFQEq/ashYUgTEWpLRq3r3k9tVl9H58f2pWLhETda6eaRcCmX2yEqsDIhlG3I/oH4rPJRvCUH5nd/5HT71qU/x8Y9/HGstf/tv/21+5Ed+hK985SsMh0MA/vpf/+v8yq/8Cv/qX/0rNjc3+emf/ml+4id+gv/8n//zcnD5sR/7MS5fvszv/d7v8fDhQ/7SX/pLZFnGP/pH/+hb2Z3VyX3GSVwhVyElHZzn+ay2EVaJ3XqQfVYZZ/33+feX66UNiQQfrH9OCL/299rPmqbJksPA2o7RIyx+hfaE/jWeSqye9fd6krN8fwkOPOuGe3bSFM9ReGr9daJslHrooaEYNE4mp5iThul0SkBQz+acnp7QNYKHDx5S13PGW0nwTET77zyv2NzcoawGeDPAFxrTeUwXyKtNhuNNRpt7bIx2cCcHjKfvMhIn+GYGvktiWBndrImzQKVoraWXpfcighbeB4SMkvmk8kS8DD4Jk6VruLxO6bz7gMctz0GW50s5eyXl2jU6e4/2hNLeQA4iqqBlP5OPbbpZliEC0TAxBNDRQK/XhsnzbImq5TonBIeS0fguU5qui1wC53zUVE4Bs/fhUMqSacF4XGK7JjrtZvkShazrhjzLKbICZ1uMdUDcN0GUru9Rhv6+6ssjPXm4b9OOJarkzxSifkZM3qJuRKYkuZaIYFLLt44zPUIU63Mxoek6w2AwSOdYgxOUUtN0HQDGGLz35HlO4xxt21KWBeSaIDTOB7rW4EPUKFFSYG2XjifDIehccmxVcslhiglMvP466dEMSk3roV7YhI5FvpAPEFwE+pWM5R+tBAbovEejCSIkN+yYvI+HQ5q6pgqQq5yuaRHKIbRgPmtRQrO7ucHRdIIxgdNJSznI2Njc4Nrl6xw9nvHmV9/l+GDCq+/7ME1b8+6tt9nbfo7R6ApCVszrlGQGgVCBoszZHOzw5NEx+8dzFCGWOnKJF4ZiAEU5om0Es0mDEjmu82xvbJBrQT1vKfMCKRTOWKanDVCR5QN88DzZn2NNwHYxCJpZR+sNSgi01IggWXSWN999wKsv3mBrtMEszGkWlicPDvAuMN6syIsKqR2NqSPlUwSM80wXFmklo2GO7STz+ZTp1AAG6zym8Tx6fMjFSxssppLt3SFiCmYK9SJaSigNOBeLE0LQtnOkHFJUkh21y2waUbbFvKOuZwzLCc+/cIF7959w786UIBNJd7SBNZL7d0+wrQMXOWMBixYOXSikCEgdx/G6NggU1gpa42MXnov3vQwS7yMRXmlJwHJ0uuC1L32ZvYsDLl7a4ejkhN3tU7Y2dvnoxz7Ei6+8xMvvex/Tya/y+tfu4pxdTV99D2X3cXOtESP0/lbnY9D5cX81qe7NBM9PYMWynBXLPjJqFP6Jl28pQfn3//7fn/n3v/gX/4KLFy/y2c9+lh/8wR/k9PSUf/7P/zm/+Iu/yA//8A8D8Au/8At84AMf4Pd///f5xCc+wa//+q/zla98hd/8zd/k0qVLfMd3fAf/4B/8A/7m3/yb/N2/+3cjNPtNLn3XBWI1W1s50K4H57VAfn5ZVYiWaEvczlk04lllj/PB+ywyskpUnpWBvldgTxuKCefyoq/2td9UtHDqs9K1AHru+84gL2e8ilKidC6x+XolnvPHCiwzZ9Fbba8lYy7lPy4EFnXN48cPscJG6W7TcXxywny+IFjJ/pMDZtMpFy8n1+l0YaTK2d65wHi8TbA1WgoEOUUx4sLl61y++hx7F66RyYxHX/4D1K0n5Mf7SS8jR1mwZkaW6djKrDKy4LEpqCulccGlzqvkbiyipHeU+lp16fRJyYrPIpA6GumR1ou3XoQ03Tmo9Fn3C6RSiLOUeTS6i+JgCmctJN0M5xLkm6lUgojlKkJPXI13hbUOVGz/dC4qSwoh0DpDpxJW1EuxETlShjzPGBaariqo5wtynSFVoPWWzkazOqdlFLfDRxl0HfcvpJKKcz4Jqa3apvvunf4+0kpjEyKitMYnQTopJUWWSlPBJ5mpeF97H7VVwKO0QAhN17UYa3EuJEn6DKHEsqXR+CiON5nNyfMcEQJd10SOjGOJ9phE6NVFjkTgrMXb1QSity2IJSmDSERkayOJO5pGQpVrFo0hqAwhBTYYnItJblS+DbEVXUqMN3TOM0CggiATgkGRczqboNUWZA5rHWWZR9RGRI5HWWiKQsVgpyF4SbvwWNtx5fIALQe88dV3OXg8Ze/iDn/xr/wP/Mav/zZvvf0Gr795nyuXttkc52g95I233kYJy8XLO7z80iXKwZDL13bIBjmirHhwOMEZSdACRDS/LEsNfoAzgbaZMRiWbG0NWMz3WdRziqIiINFqQNdJFnOwKRAqpRiNNxAITk4mYGMZwweLlBFdOp40HByc8uLNqxwcHDJbtNjOMKgKBsOccqARytO0JXXT0XQdnTEIKTHGc3hY07UBpeDW7SOUEjQWhMx5cjJhbydH5oFHJ4+ZNRZdDAnW4KwkOEEmc6oip8py8mxEXpRsDUfgFYu5oV545hPL73/mC3zik5LRcINXX9mmaSbMFlO294bUi0O02gDZoGVAeIHINGCxUmBMg3ELyqxE6QpjPIvGYVwkEoOmd0dPbk1EZWhPvVgwnR/SNJKX33eVhZnTzC2vvfYFhuWYLB+wtb3F7u4lntyrefzwX7N/eIJ3gV5TqVdojmO/WiYqS+mKc2PTkq5wbna/jBG9LDRPI/A9wrz+2jJ2fZ1KwfnlfxcH5fT0FICdnR0APvvZz2KM4c/9uT+3XOf9738/N2/e5DOf+Qyf+MQn+MxnPsNHPvIRLl26tFznR3/0R/mpn/opvvzlL/Od3/mdT31P27a0bbv892QyiX+kROBsQI4/Yi27iyUesYRxzy890gFnKkDPTEKW66/9/c2Ug84kATwdqFaB/WzJKb5+DglJ/wlW3xHOrXN+OYOa0KMgMaFbR1iWqEvc2HveTOHcscvkhtnXI1cJU0TN6rqmcx3VuCLLC+bzOdPpJM6Gs5Kmbqnni1T/VhGWBIRQDEc7bO1eR2UZ2xub7O1eYXvnMpvblykGG2hdgW2Ylznz2THS1ZEHEmTsavFRBn/JK4knBJGccH2IfIG+MwURlgTr9c6kGKxWYmXBO/qCq3M2JceSvm7o1xKUJVH2WfdH720jEgHXRtExQeSRCCnSrDykbqlYfiDE0olWkTHfdTaqiiKQmaYvd8R9Ta2zQsRSj/dYa8iDTuUpxeZ4hJYtxhh00CCTfboQZDpDyziTixLv0BcJ/dr91pee+nuxT+6UipoisaSp4ozbL++0ZXKiJOSZQvsoSmeNQCpwwcYkwsXv64wFBEpnkayrVNS5MQaZacqyom1bmqahzLN4vYnCUk3dxYkDAZynzDNyrTGENGv1y+1Z55BanWlfHgxKmqZFKY3xFi1gWCga62hMdLV2qbuDdDv0gm5CCNrOYbNAkUuGRcmFCxuczk9jwhck1juOTk4x1rK5OcAYx+bGCBEkTdK70QKCFdDB5GDOG9NbHD45QSnJcCuj8cfoSjDa2qRzljfefIhWMFk4Do5mjMqMm8+9j42N93EyfcDepSvsXg6owSGvvXGL1nc4KzDWoQUIryCIaLkAnMxOuPHCBXbsJvkgQ0lNMbPMTh2NNbSmi7ottGjpqPQgXhvtkU4g0cgQlX+t9/iF5/DolPe9fIPr16/xla+8g+ssSkq6xib3Y8iyMVXmEKFFS4N1Dm9bCFDlYGzHf/mDr5IXOWhJWQkCluN5jUyThs46isJSjjRt48BFPp7WmiyLIn2xFX3I0fFjVA6Hdyyuy2gWp2xs3OZ9r97k7v3b5GVHaA659/AWpoVSXkApRVFAyKKz8Xy+wJgaIRxbW2MuXrzGrVtPmM8NHkXwOsb6kCacgoggp2HU45nNFwSvqGvP5z77JrsXdlASKu25duU2O3t7WFuRD0q+63vezxe++BKf/vRnaUN/9/XjemqW8B59Llb0HXjPjmee8y8/a8K1HC9hGQ9igh+W8dp/C5DKnzhB8d7z1/7aX+P7v//7+fCHPwzAo0ePyPOcra2tM+teunSJR48eLddZT0769/v3nrX83M/9HH/v7/29p98IIc62n1W7WUMplh0877GsEyNZQ1/Ol3TWPsEzN7hEPcSZC/0UOiFS1S+EZaBfzTSXX7/8rBB94uF56i5JX3w+MXmv8s7ZZKQ3fVsdc9rasrz0XkjSOkoVXzhrpNevE2/MQGcaqmJAnmV0Xcfp6Sl1XaO8p6qGDAcbtK2J/A21jqJFwbZX3/9d4Fu2t7epBpsoPQCRpeugsO0Js5OH5GFOmYPWFbNZNPfSOmOxaGMy60NsWzUG7xyWVVK4nuT5BFetJ8Drv9ePM5JhWeZl6+iSX0s+1j/bn/dMS0SIehL9te5B1DzPQEfpeuk9xseOnzzP6FqBtw6lktGgs5RlkZLtqECLiPyZ/lpLmS2dlbXOosOzysmUjiTNKifTOYdHp7RtR1lF6L4/FqkEzvqYFOnoV+NsRGm0UinhFUtSb086jnXoVAv3YQ1lEQSbuCxhlaRkWpJZCMjUyZAsAZzDuYBWGSBx3rJYWJQ6i9YI4qSmP9bFfIFWkqJQNHVLWeSoLKNtO6oyR/hAZ6O7MSImU1prmqaJuabor42kqirapgFWAsHCW8alwi065q3HK4FKiW9IfCaRyioIiTUBgoxQvhC8+spLyCrjnbce4IC6nccWTaFpGkue5djO0rSBum3J84JBWVIvPFJlNDPL5HiGkFAOM06bI37tN/8dzUwx2KwIXceiFTy895BZFxhsjBnpAS+88l0sGsvv/M4f8ae+90Wef+ESL750jZdfvs5X37iL9zmuFRjnUXi6NpUFM4lQkA8Kii7jwvXrvPrKKxw+mvG7v/2HzLqO1ju6uiEvBEjP0ekhXRMdkZ0TCJ9RFBVCS0zdEILgZDLn9Tdvc2Fvl7q18T42DusD84NTQCR+kCMaWUXX55CMgpRUKFXQGct0Ycgrx/jiMJZRmkA9NxgXixt23lJWGXkpqcoKnGBQFYxGA4yxTE4Nk+kxQna8/NKHePv11/AmR7gN3nr9hHoRuH3rNvN6QjWUUbdmc5t2lmGk52R6St3UZKLAm6R1sjHi4qVr3Ll7yGRSg1JRpoAebY+aOjI6dSHIYonT2YjgSWiawO13jzk6NJSFQouO0fhzfPhjH0Zliq6ruXR1gz//oz/AW++8y727T2LHGz1/sf8Jq581TlsfJ85MqMJK/Xp9ibFMrr2+ItiyRFH699fpBN889fVPnKB86lOf4ktf+hKf/vSn/6Sb+KaXv/W3/hY/+7M/u/z3ZDLhxo0bnOGXLAO0WP4H/UlcnqJnohfrgbYvy8C5YLJcbz05WUFg8f1VstTPtp+1LBEQseo0WgW8sPx8Dy+HtLGQbqgEb6SylVhCcOdLNWctv58WEVod9KpkdbZ/XTx1vvpt94lWD+XFeqM4l6T05ysG0sGgQinJ0fEps+mM4BxFWXL50lW2t3Zpmw5rHVmW0K60lSyvuHb9ZQhRq+KsyVZ/8xuGOjAYFTCfY7vk32OiemeWaRpr4nkP0BvMRf2cdK+kfe87onwIhOSM2z+8z0LPVNLTiO+HqEBqV2Jh61Bpv50QYqtmn8xGnoiLJROl6LqWqigisdMZiHcXXdMyGFQURY4VifgrBCFE9Uid6dT9A3meRXRFxEGu67rl4JMlEq9zFu/iOloKRC7JMsn8dI6xniKPg6i1JiIbKjoDx+QtIlKxFdtCf0+reB5dKn3FVuC4P9J6OueQStJ1Joq3SYVUMvJBlENLyDJJ1/plopgVGd0idpiEEMttWmvariPPssi3aVtCSGTmlBxKKWmdp0ukVakUeVEmhdzVeBCdkk3slOpRyphPoRM6JWWIJGRjl+iUloK80HGgFhobWhY2gJb4IGKZI6zuVO8FJnha59He0RrD62++SR0cbdeQZwOU1AQhKcoca1rqxhNcQ11bkAqldCpdSYx1TKdzZOa5cmWPxpxyOm35/Oe/xHiwi/WWru1wfsBwY4tm1nL55lVOnjzkV/+3X6FZtLTNKa+/eZvNHc1gNODP/rmP47zg9Tf2MQtL10V35+FwjA8dyIDOSh4+OuLw6AmLZsb1m1fZ2ttk5+IO9x6+hXWwqBc0XWA4yBEogtAIIdHC4x3M2zqeyxBRus7B/vGMtgvUdURgdJYxnU0pqoIQHM7WuNAikQwGI2azDttF+QDjIcty8qyiGJbIzBC6QFFEYq0SsbW4Mx6pwXcteaXomHLp8iUuXbrAaLDBFz//Bo8fPSbLA8OhZlQecO3qDq4tCTYjWMHdWzO8G4F32FZwctrxpN6nyEY4J3BGUBQ74BzBzRgMKi5fvs7d+0ccHS3wRGuLfmIXW49duk9iAgsSKQLWtkjpo5aRyuNE7mhBrhVZbrl15x6PD/bZ2XkehKdzLR/40Mv86I/+IP/6f/k1Tk/alW/V2tgf5QTOTnjPTqbSa77nrDxDdG3tGToTR5fgQO9mvorP38ryJ0pQfvqnf5pf/uVf5nd/93e5fv368vXLly/TdR0nJydnUJTHjx9z+fLl5Tr/5b/8lzPb67t8+nXOL0VRUBTFU6+vIyMRVV+VJ57mUpCCXt/mGc5s6VnLerBfJj/i7Pvn0ZXleks05SwPYZlkJNlycQ516L9vPW3qk6wQelnx8EwQ573KMSsTK3fmuM+fIyHOknVXTJpnl7BWn1s5Ap/fj168aDgcUJUFTdswnUwwXYsIsLO5zc3rNxmNNmmalrZpKAeb/Q6khCJpJyy32evXhHReHK6rsfMZwThMEwc2nIUQyaoQz7XW+swMoYcfpZTQ+8x4Eq/kLG9pfVYhhIBEYnNu9VrfMTM3c0J4ugOqn+lLkVqGVfTTyXUk11rTIYRAK738XNzneM2tszhjU7ePj+UE6yiKAmstnXN4ZyiKLHFiwlIttYdW43WOXTTBO3ym+0NHKRiPByzqls6E5MocOzm8jaeoT35D77wsUumJpIVCOIMcRd7LSjOmP+ex3CPwJvFhtEpJbkSWaF1cL8TW3sjB0QihIzqU69gdYwzBecqyXKImPv12zuMCZHmJ9YK2bRlLhXKOZjEnyzJMD0OH6KGjVOzwEVLijaXr7FqXoUCrjCjgHpat4NY5lJBsjUrCrGHe2mV6L9KYEHx0BnMCZk2DKivK4PnqW++wMB1aarTKKYuoKaIVmC4wmza4qqBrDZubZWypJorXtcZEnkcWSxlSKYRXOBfbyjvr6DpL03VkeYELDSZYjBW88cbbNLVlUAgI9xiNLC+8fIW9vav8wPd9jNnkDzHNMdOgKQdjrDMYt2Bra4Qzii989k2yXNB1ltu3HlJmNXfvPeb0dI73WXQet4Gpbchzjc5yBBHxM9ZjbCAkXpOXDuMEk3nkiQUJeVkiM6g2M1588Rp5HphN9/G+5vkXXuTllz/Mr/3ap3nyuMYaT1c7Ohu1XoRyDIcli1OwuWcwqMhHmky2tG0X7SG6hhA8bdvgNhdc2t1k/8kph48OsY2n1BWXd2/gOwW+QQhDXlV4o2gWlrqrqVuLaS2mdWgpGV+Jzth5Lmk7QdMeMRprLl2+xuHRgv3DGSZ104SEdvbJPkIhEjcwetw4hAwEDHmhEEpSlAPCZIa3jq61CCWY15ZHjw555UWDzjSt8eRZzg//8A9w7+4j/sN/+C9RIZmIZrMs66dp7rmJ62qckMuJbz+W+7D22TOx5Ozv5TizfKGPJXFL3+zyLSUoIQR+5md+hl/6pV/it3/7t3nhhRfOvP/d3/3dZFnGb/3Wb/GTP/mTALz++uvcuXOHT37ykwB88pOf5B/+w3/IkydPuHjxIgC/8Ru/wcbGBh/84Ae/ld2JAWA5g16H4Vdllqc/dPbEhhDSBHpV6HjvHO/ZSc06D+Qs4nCuNABLXsJKOOdsN0x4autn9ztmrdFVNq6TvBbOr36uFLROkj3/nat06By6IsSZ8/GsEpKQSXcmtbGuAn9fOnEURc5oY0wQgclkEqFz5xlUA25cf46rV69TFlF6vJ7P2dwOqXbvl+dN9MV8SMducaHDGovpOrrjR2i/wNnkf+Mdzhm6doEPkdehtUYqnQam8/ouJDQusCJ4KnoC9qqTYwV1itRiuJ6AWmsTiqCwxi3ruisTwogwxOvZa6ck8bi0Pz0HwrqoZ5BlmqLImM0Wa8iYXSq5ai0Bn3RSfEIi1BLFyHNNWZaYtlseb+yKiQlcbEmOMLAUgqLQlGVBUebkKqJT3vml5xBEQqmE1OHkl+aLhNgi7SDpzHAmWXH9eU3nTwIh2OSPE/dLKQlJU0WqxIFRElmVmNZhTEzsfNct71xjo3AepO4soCwKZiYSZTsXE52sKAgE6qZG5RlS64gQSElZlnjfrXUjaSAiO03dxiTLx7KNdZ4yiwGmb3sO3lLoglIp6mBQqojmnLGROO6oFLHV2gdsCMg8x8wkNiiUCFRVSVc7TNOhMkWuFSezNnaxKEEgckPa1rKoO4IK5KVE5o7T2SlVOUCrAQTFYt5hvCdXBdY6xoOCEDynkxnGKA4PD9Eyw3fReflrXzlkNu34zu8asTUuuXa54MnDlsaCzALetoxGGXs7W5wcTpkeWwajkn0758v+HY6PFjx+dMJinp4RL1LpEmrXobp4TZwJWCtwHgSKIlPIhEgZ73F4dCbRWcG0PkFkHeUYrlweMxqOuHpll+3tPYbDy/zB54Y8PDrCBnBZR/DgjCMTAi8M5WCD4AKHBzOqasDuzjZSwN72HtPJlPl8QjVUvPjiDTaKDe6c3uf5m5fJ85KyrBBCMTma0NWGpl7QtScEq3Feo3RGkY0ZDYaUxRCtHWXpuHJlG+8cr7/+OtXAcOniBU4nCx4/OUkT04SquQy8iAlaCCmRjaKMCJtI2h15IaJPl4zI2WBYIVxELgdbUUzxyf4B88URO1tX0Vl8trd3NvgzP/yneePNO9y69YQQHMHLyHlZiyfP5CB6WDVhsHR277WhYnyVZxKQ6DMlz8TA9TiDWJV5vtnlW0pQPvWpT/GLv/iL/Jt/828Yj8dLzsjm5iZVVbG5uclf/at/lZ/92Z9lZ2eHjY0NfuZnfoZPfvKTfOITnwDgR37kR/jgBz/IX/yLf5F//I//MY8ePeLv/J2/w6c+9alnoiRfb1nN0FaZICzDx7kTyDKQC/oAG9aqNZKeeNpDWc9KcFZB2q8CG2ulomVZ7hmlkbTeSmlPkGxelm3iItV2fI8M9UmYkKkWHmf2fTALS1QnMSiEWGFzaX+999GHx/lEoozwYf/TE1yXeizLk7JGrIAzgfjMuUltPFEcL/rbxKEp2ssPxyOKqmAymzNfzPHGkAvJhe1drl2/wXBzm6AiXL+YTQi+Q4iCpepufyzpOL1vadsppmuwxuGDJLRz/OIIITw2eJwLWO8QIbadSqWwNsmji4AU8WGNBE+5FAXrZzBK9Gd0/f5ZM75yaTYCZx/sELUdVmqqMXAH7xBS4ILA+9iiKpyLGgo6GslJGSjzDOcDrbFkmSaTIgquqdiimGeaLI++MF4JpPDkWYE1jq7ryLQm0wotVTTZC4Km6RLywDIJNtbGso3ShGTR7hEooQmpDNV2DTJXaJV6CkTkkYTgl+hfCBGl0AmZtNaiswwlV2hRCCHpgaT6d3rSXBC4EH0/SChX8GA6S3QzjuhMCD6K7aV1XCJS5yqWC1oHIdXzpY/OwsJZMAaVSjVZJnHGUBY5MgRUagevFw3O++hsHDyK6DDcth2rIUImDZYVYufxGAv42OqNMUkN2jEoNLNGJQKzpsEtHycBCKkTAhVb4JUI5FJS5gNOThvauok6OC5fJrmL+ZzNrSE6i87D3hsQlrLKqUbgpcOagGkNUmuausFZicjifjQ6Y1wNqfICu4hJvZKR+KqznHIw4P7DU2rr2djd59rlPTaGJVd2NxkMJfNOUagx1UDT1IbTyTyJ8wWE1ExOWhbzDmujJH70vOrNNR1KQa5znAVnPHhQgYQ49gTN6NCdScmwyug8yQSzoW7nzJuOre0NNrdGSA0OS5DR3VtICToK6GkXDTYH2xkf+NjzmNbzhc+9zmS+YF4vUELT1JAJje0EVkMuBhw+mOAXgkFWURQVDx8dMF80dK4ltsJ7RsNNynyXXG2TZRUyU5FrhWFjAz74oavozPHk0UM+9B3PUS+mXLlyiZOTjmJUcufOPpNJQ9sKhKhi6tobSAZHEFFFWeDJS8ulK5scHR2ymFt0psm1It8YUpVRp0VpKAaOzsyZ1sdU1S516wjOUGaOcqi5cn2Du3cOsE7gg8B7sRRp61XB4+84xsbjWY28Pa8tENaqAiuhttUQKZbSFOtCqRGJWcljfCvLt5Sg/LN/9s8A+KEf+qEzr//CL/wCf+Wv/BUA/sk/+SdIKfnJn/xJ2rblR3/0R/mn//SfLtdVSvHLv/zL/NRP/RSf/OQnGQ6H/OW//Jf5+3//73/re38GZ3iaLXEmS/RhFeiWM+V0QcTTpZtnLSH0gVmc+b3ioayvF9bWP7vHyyQgoQyr2XVcI6whKytMR8Sg1Hs9rFV5PJEzdhZFWiUn6z48y/04h6D05ZylbsUzyjVnz0U4+3khVrL9IsGB3jIYVIw3xgQCs8Wcru3w1rI5HPDczee4dOkyeVnhiR4989kMZw1aFWfgrCD6JM5hXUvbLfDWkukCoXJaAhuDgtKVTNsZnYvGioIYKLXKCSEGZqU11htW5asQ1V7l6sQu880e/eivW58Qh6iPomREHuJDuergSe0mUbyLgErbcTYG6P58BRG1MSQgQ2yNDrYvWwgGgyGmqWm7LpYjjFndayGa9IW10p13Bl1GbQ8BOB/XbduYpGRZJN1aY6nKijxXeBO7IaSMrrOeDGsMXWep8gE6y+PgGYhJX7r+tufnJIXVZUeY90l2YcW5iRozGmtiB40QscW4bbvYvpxKXqFnnvo4oDnvlj5AznqSXifeOUyIujESAUm3hwgK0VpPXhUIYym1oHUBoSSZkpA8bZxSCNnRdi4lVZpcCpyw2LZFSrUsIWmt0TrDmC5OhnzACkGmo66M1gpvo+y5VoLRIMNOOxpjQMdnVysVy4IhJMsExfbmBvsnj5BOsVhY5rM5AihzhexaBJKyLAjERLSpW4yNnIKqKMjyHKUtGxs7HDw5JaAo84rgWhocxlpwAWMF1gYUkq5p2NouqIoxB08mXLp8nfFGxp27U+7eneP8O9y8dorvOobDHcpxyaP9CfcPDjk57tC5QiqBwrCxOeb0dBrLpCojz2NLLEGk9vPYTjwalSgZSb/Bp+dBCYpSYmy3HIO6tqVrNbtbA5rZhMHAs7G7xfa25uq1bQQdNlhkCNy5+4h7d55gjEdrRV6kJDyhj7N6zr3Ht1ksOqy0GGGpjQULk3mD8PHezzOBF4rgHXU9w7iW7Z0dynLIZG7I8oogG4oSPvKR9zE9VkyOFFk2ToG6RRee7/ne97OzW/KfPv2fuHf3Nh/9yHfy2mtfYj6reel9L7F9cYe9ywMePtjnycM5+48bQogTg9jk4paTUaWhKC3f+4kPMhpv8Xuf/iPeeusuIlg2NscgPGUhGY1GDMcSrQSLxYJTfcrx0QTvG0aDLR49eURn56k806OvsVutj4ur1+IzLOXZMT+EnoNCiiVn0ZenEo8UU2WfnCD+RMkJ/AlKPN9oKcuSn//5n+fnf/7n33Od5557jl/91V/9Vr76mcuZSTxrM204e0LeA1kKxMxdKrXc2FOcjKcCtFj+fL0g/l4IzPp215OC3mxvne9Cj46kG8InU8TgfOK49OWUsAKD1pKTPkE5q4ESloF2RYY6y7X4Rss6itInVrFKlmbV6T+kYDAakmUZp9NT6vkcZwxaKS5fusLNmzfZ2NhAJeTGuSh93xlDVqyX3vqpbPymTGdU1SDOzNAY55MOi8RZQ/Ae07boLCMrSpT1SXE0ft5Yj/WRwNVrkITgY5L/VOknnD1GepE1nxAEt9ZBkhJVABk7OUgdPtG7KEm+pwTUkwK4FCA0TduBiq7GeZYTvKeuW7wLZAoGuVoCZL1qallWsQtICEqXR9Mw7xGsuFY2tfo2TRsTg6S10v8XxeBishGEol60hODROnbKeBc9foKPHTyC3qsmScLnOm0Xeq2QkGZSq3MjVm2MgDGR8JllGpFk9o2NqJGSBlyvBxHRKg9Rw4FYRgsi6pcImSGcJROezpiYwDjDpLXUzNka5lSZojldkKmo9CtlIPjYvq0leC1ZzBZQBYrRMMnxR6t4lZC3vi7fW8j33VHRODF2HwkhccltvMwUuYbOOISPx2+ti+UrRFQtRaByzdVrl7h19wkiaAgdSguUFgQcSmcMcx2tC3w0JYz3nCAvBlG7pfYoZVGyoK5biiJnOK4Qi47udI73Go/GesFwWGHnNd//Az/Ixd0L/L//5b/h+PSAIKM4n6k9s2PLYlMwnRme7E85OW1oGo/zgSAcKosdURrY3ClABPafHBMbujI2N4coleEtTKczyirn4qUtJqczmpr03Hh0LlCZxYYu8nqCRAYReUoykJeBl1++yvd876sYN8djgZyT2ZR6Nuczn36D46OGrguE4NBa4L0l6R5iTeDgyYRqMGS2WKC1QkqwIundeInMMzok797fJ88FV6/u8ImPfRc3bt7kyaOGf/2v/y0oy+XrI3b2Si5c3CD4GmMktnFImaGk4uq1ERcuFty//4AvffEtOtvw6PEhppV88fPv8u69B+SjksGwxLuOK9d3kdLw4P4sGvzJ/sGOY3g5gD/1vR/h+o1LKK355Pd/FwjPu7duM59axhtDxuMR165fYDQq2NwomZ7OKeSCw4MHTGYHbG7s8dZbdzk+OsWHSLQPxJJsHKtc1CLqVWXTOOuDX7rV9QNOPynya7HifD6wPm6ufp4VP775WPNt7cVzlnG8hg6k//UQ1Loiagz9/Uz4rHfIsxOSb+774VkYzjdK6s6WoVYtWWL5/pkyVFglRqKHKtJRxVnt09/dJyl9x0oIgfN3zbLc9U0uZxObWOoQMiwJlEHEPvu8LCmrKkrST6exm8BYtkcbPP/8i1y+dJmiKBMxNyYo80VD29QMRhv0AkPLCxr6c6bIspy2a+nalrbrmM9mZIsFG0mRNMq+R1Ex7z1dZyBIpMribIEokKa0Tm2xLJGN88caQlh67yw5Iwna7KHSMyq6ISmfJjl4mRK3mLOJlMgJQoikUB+iDLq1AheiBoxOCFvPGxmUVSyNhFjCkAn+M8aQ6wx8FF8jxECiVL7kzWgictJ2LV3XURZl5Kv4HoZbJco2labKqqBubOKRhNTZFa+xVtna4HP2vpFSYqyJZoPJDbi/v+TyHESFVhsil0IrxbCq0NpjbRNncMGlcmEsFkqhEDIGfKVU5HJYj1K9YJojU4rGRedl6zzSOQaDCt91y+RQhDgp0YVe8sHKIqNpDLNZjQ9uKWkfbHxmsizW7Hsek1IR/eqMRWodW0U9SBV9gpTUBGPZGOV005bgFTaAkHHwV0KBkHgpuffoARevbrO3u8ed2TTOPJVnMCxoFh3OG4pygHVwcHCIwJPlOUJonIPZomG4oWkWFlKwsb7h4vZ2TEyJ+is2COZtze72JhcvbfPd3/N9CG+4fOUyr3/tTaQs8a7lxtU99va2ODw85d6jAxorWEwtSmZRcVXFa5xlGp1LykLTlpqd3U0ODqbU9QKC5MKFS2SDknqxYGd7yNbWiMWiBhE5WlpLhqMClXuyMifPxsyPOzSxxbsoM4Y7G+zsFMxmj1E6YzozqCzj3dt3ePftA269NcF0CueiXGmc6OlYVVUqCqFNHdbUaC3JlEpJbhT+i2U6i5Y5i86AVjjp0IPYnn1RbrCzN6LuTti7OOaDH36Z4+MT3r79DteuvJ9FsKiQAYHBQOP8jK989SscHJziReB4MkPnFdZFOw7lOg6Oj9naGBK6Yy5dvsajRwuEE0stochR8+zslXzXd3+I0aji8OQIpQMvvHSZre2KJ4+PyAvNzu6Ynd0R1aCIrfMi6kvNpqccnTzm4YNHfPXLDzg9WSTTS4Vcui7HUiVBJnTFASpFEpGoA2nS1Rd8wtNj4xmOyVpsOPva2Un8NwN09Mu3dYLSz1hD4hGcUbvjbDBfElDXExmZIN/1LZ7jWHw9Lso6J6MnDy6TlPfIc561rQj3qzP7u1qW7i/ppupvlPV1VmWH8+Ud76O1u1vnT5zjqLzXDXN+X9+LUNWXQaSSIOOMXWjBaDxEKsHJyZTpbIZpWrRUPHfzOW7efI7ReLzkMYQQ8/pF3TCfLdjeCaludRYd6xM47wOLRU0zX+CcwRpDlmqdztoY2EJIPh6xA8M6h+wdmAMEb+NMPs0Yzp+HZetwIJE7xbJkJNcfuDNXa1UK9DImXRADbfDJSTqAkCpyPUR0zG1MoPUSayW5DGTBUkhPngnwHusMnQ0EZ9BCkul8KWFvMQQceaawvi8ZxvKPdyGpnzqCjw7RZ5J0Hy3NpIwEVmvj31VZ0nWLyF0KEfbVUkY3ZmejyJ2MKEpEpeNz5JyNyNA5/tfSM0jIOBMPsTPHu8RzEiIK3/XlNiFQQtJah8iin5FWiiwX1I0hhFgS9MEmcmFAKh0Dct2QW8+47Ggmx5iQtE0yjenaiJoltWKlBcYGyqpECBEtAnQGIRJ0rbXkOqNt22Ver5VellqdC9HgL6zam601FEohpGSQW2wdPV6C7MelQEBGrkjXce/uI7Qc0tY1WnuGI7hwccy92/tE7kNgPl1gjV22NFvnqGfTdPxZvF5J9Oz5Fy5z9dp1Dg+/itaKtu6YLOYImbG3vcFHPvRRXnnpu7h1+8ts7e4gRE7GiOsXc7Y2NCenh+w/mdPUClWUhLBgMBgy3igJMooT5pVCyBbrHIvFgqoYcvFixZ3bDzHW8fjhk2VdVsoxWZYnCwKLzATVsKQcZOQFFFVJcDnz46M0znjqZsrubkFe5Bw8OebSpWvcfucRd+4fczpb4KzCRKHlyFtyHu8deSXRWVT+DV5SLyzOBnTqyHI2IJAUmcKK6HuEizwWHyQox8HJATf9i1y9eZEf/gsfR2cOgmK0UfG1N97l6PSAPL/H1uAGrlV419J2hsn0lP39/Sj4GGDRdchSEpSjKCteef917t69y3Q6wVUNW3t7DMcad5zG08RpQ1rGmxVZoaK4H5qjowcMBgWj8TUuXr6M8zaW6YYZOlMU5ZDhcJN6YXn46AF379/i6LBmeqw4PmyxxkfJ/NR52Hu69Toofbzo4895YckeeSdx0NbjQRyT1yfa5+PGahvxfb7p5ds6QVlnGS9PVO8cuXYSloHnGSeqRxTeKzH5phGVdb5E+vPrlXnOL+tIylPfnWaSkdpwtpc91XWeKtMsOQl95046YNHXCDh/I53Ngs8nIOvbPb9/y2QtHbsPjrIsKcuCtm2ZzWZ0TYM3lkt7F3ju+RfY3tlF6xy/RLYCBInpDJPpJHWoZCnan0enBMFH9MAag/UG530koIZAlmdUQdDZBmRAqpxFU6eugXh1gpTg3VpZ8Onrv7x+YcUvigqjbnluQ0IE0h9RY0XJpRhSvx7LBDkGc+s9FkHjNcczy+OTObMuUFaBLDgubWZcGGk2hKfUGi+im3BVVMgQyLReuhPb4AjOUhQVZfKMads2uh4nYqmxkXPTBzGyDEGMmlJGk7NelhwhogpoiGfFGkNRqGQgaLHOkkuJ9255flzw6blLTP5zg5XWURuGcDYhjiUojzUGpRRlkTNp2uQbJMCBtZ42tKgyQ+koBx58QsWtISgJSiKkIgNQgu96ZY/djZI37x9y76SNpQ1n8UBbWzoTL4bWGUJJvDUx6ROatm0pyjxpxUSHYykl3oXkcqyWJb5oNujjWGIsme7JyZGDNCpzmqbBIzGp+y7eCwKUwgXASZ48OYZguX59lwuXMsq84ujJKV1DFHnznuFwiPeOtjWpEuCIHVAtWg3IioLh5pgLl7aZz2dMTxdoqcnzQNc5Fguo64bNzS2qYpPrNz/E/+m/v4Cr/yfe+PIf8vzzBc+/uMObb0/ZbDd47sXrvHvrPm3W4H3HdNqhc8l4c5PtrU2CrGnqhqYx1PMp482diJj5gPMChEMqmM1nTCY5xrToTFBVGVkuY4ndg+kcJ8fHNI1BBdjeyNncGlINA6++7yWqUnDv7iGPH86ZnAiaLotJIRmB/lkUhCDxtSP3RD5KskroOk+mA7ZzBAdCJZNOFYnKWa4RZBSFpKwKquGQup1h7ILhuODNN77G/XsHDMcZjbFIqTk6OmJUXqBpPNPZXd4/eJnOWBZNnXR0BLNZjek6DIad3R1uXN7jwd13o9Gp7TicPOLClR3q6QzfCWzwIDIifyfjyf4ht969R10v2Nu7zHwxo25OCQiqYYUXgkVbkwfPoAKV5TjX0HaO46OGxQxOjjuaWiBEhvciErn9Kl6EcLb8vz72xb/XWiZCj7ysWpFXI/LZ5TxVYn35r6bEk1B2+v/3hJ2w/n6a9fbRIaTp+hJJSNs4Xyp6FoLy9U76sqNjWW4RT23z/N/L/EOsyKXr662TZCPQ5tOg5JclnpUmygpnOB9klz/pv/57ziZQZz97Hrpbf+3Zx5JImUmEazgaghBMp1MWiwVd21HkOdeuXuPy5auUg8Fqn9Mv7yPkenpyStc2VLqM13attbfP1qXM0DrHyEUUlcwLhC5pOkPuwXaxS6WzlrwaMDueU1uF9Z7hoEQLBW6BwsfZVYjEPTgr4iZEImHSC4+xRGf6deP9Fa+D6ztBUtlEK5YzqhjL+yClWXRw66jj7SctD48apq0jyzsK4bm6qfnoi7s8t12BtzEBCHHm75zBNTUIgVIZpjMUmYzePUkFNcuy6NobyUrkSapdIWmahqrIUSLJzwtJIKIpQkZ58/m8SQJ0KZFLZayofrkyBey9nUSI7dNSrCYH66J9vQhd771jnY+CY5lCmg4lJYOqQs9rCAHvDCJoBAqV0lMtJX253hOici6OION1zQBvDMELXr5+kRsXtpi1cOf4YZSed5HIPF9YvLcMh3n0hbImGbL55FWyElHUOpYKhAChI8k5hBCTlaRrEksu4LqoXiv7ZNQHpPcM8wzbRuKwpy/zxe6N4XCDo/0jFrOWwaBgb2/IaBQD1MbGkOOujiUnGZM8m0RUg/corbhy8QJFEVAiiuXt7Iypqoo3vvY2JydzqiJH65K2dXSd4HS64M23Xue/aSaMxjsMy4v8yJ//b7n1xhfZ2q547oWrTOYW52e8+sol5pMj2naKVJq2qxlvbrF3YYuTySlFqYAMKTLmrSGcThKiodI5cOSZJMvg6GSfvBRs726hZKBrHbPZIvHqHF0rCE6jZXQTL3JJUQW2doZIYdk/fELddFij6dposlkVA6KGoYUg8Kl7yCnIhyWj0Qb7+wfx+mWKza0qtl4bT9t16Cwivsa1DIdDRhtjlC5RSjGdHXH9yvO89MIHybMhxnyBr73+GgFNUWxQ5Rs4G3jw8BbF8Jjx1gfxAqrBEB8mdNYxnS7oOoNxYFuLDpAjaMhorOPg+JjrF3bY2RnwZL/GhdhNEydgktu3HvCHf/gFhNBcvtxQVDl1O6dumtiObrcpyiiAWRZDrO2Yz+fcv3fAYqqYHBsWM09w8f4MyFjSCX1yK5dlm3XEvUdWQ5p89JFtNf4+Xd4Ra1Yn32hS/l8PgpKg3fXSBqyFsr72lTKZsLIk4GzXTWoo/QZn7usjIin4n+GQnN/Xfn9WF3ilvno2OVglDKS/408fEM5ANv23rx3beWLs6rvFU7PY/qx9K/ybfnvrfBjrPcZZqkFFlufUiznz+Zy2afHWceHKZW7efJ7Nza1U4ogDbZ9gBWKZYTqdUNcLquHm2XMpRErVoiJoWZR0tYojdlnR2EAuFV1jaJro3eQJzOqWiRG8eX/Gwgp2tuHSZkUZBJUSlFIhhSc1i9D7RsTcafUAy3TupFLRFyYhKSGAd56lS7AiNpLLKLzkZYh6ISISZl0A4wULE3jn8ZSvPupoQ4bxGlpBhmXedGT5hEF5AVsqtG0Z5RnOQ6511HrIM3yALC/w3mCMQ6mo6yFE0qYRUQ+ldzUOIeqqWOsQqbVaShAyqtq2naVtHfP5nICkHA9RREPE3gwx03pNMj8KhrmeLJraj72PPiRKq3jnJhQJwFoDImI2vX2D1hrvWvyatotGge2RrOjQnOtYivHe0nUOIQIqkYdVam9fNB3Hs45cnXI6mcVuKe9TizkMh8Wy8wYC1aCka5t4PdM+mq4j1wVSSIpcs1g0IFRqN06eLiYq1wlieSqWCaMRpUgE5UJnyEozM7PYNB9WKFtZVjgrODqaIoQC5UE65gtLJmE8HjGfOsoqQ816dd6YrHe2oyjL2I6sFIt6gQ0dz718EaVLjo9mCFTk7MgOIaJw2vFkwWtf+RKf/+Pf4/v+m78AsuL97/8IH/mO72Q4OqAzBT4MODy8w2S6z2I+ZVCWlIMhk5nh+ef3+MCH388v/a+/wXyekecl1sb7+uR0Gt14RRaJqlKhNFy5tkeWG/IioyhGHB+d8uTRKabzsRwso+aMxeNdoMhypFBMT08wSaPnQx/9DqS8wf/27/8I0zqyMhpWiiQZ4IUiDSjYznF6UjObtmSZZDisyLSgKGKp1ienYxdrrYBgOq8RImc8jh1Fly5dYTjcYHf7Is+/8BKvvvp+/uW/dHz5tTeoJxNOaTmQ0Y395o7CC0PXWrJiAFLhLZjW07Ue10m6Oo5NF3e2qB8c0/hAU7c8ePiAG1c+yJODu5DkBxDx3j44mHB8XOOcpDOP2dyu0LmmbhynkxNOpzO2dkquXr3Azm7sbAw+cHLYsJgqFjODd5Hv5LxDSFK3TiLFerX27/PI5tko1pet+3H/WdSAiJzKMzEBnr3uN7t8WycoIkH/zyLpnCn9nE3+Vv/u3xdiqS56HiF4GkFgbSPffEBf536s7/OSv5GSlPVkZKVDsl7iSMTXlJz1AioCnroRenKsMWY1+5cyyYWvkJVnn7+18/MNjivW7i11XRMIlFWFc47pdEq9qOmahlznXL50lQsXLkaZbtkjQNGSvj8U7wNNXTOdTNjZuQSp62FFRBFEkTtJnmUMBhXWW2S3RShHOC8wnUEpjfQGax2nJwv2J4Y3HrXs15A/arm2lfOx58dcHpd0zpBJgRJ9qx1JfXb1fX2Zxtn4W+sskVbT+elbkdN+RqRKoJSIPA4RyZ5CSvAC6wS18cw6T+3AEktUwRHJerni0czyhVtPuLqZcXWkKTVYF6gyhUBH7RSV07UGbw1BKjLtlgJp/TH091e8JyKZ0uOxnqj7IlQk86aSRWeiG6+IUAUqy/De0LYtMkRXYlhpAIUQaNoualromNhJoZaPh006NDrJ+WeZjtfJOHxIxFrT0XVtajGXaC2iGFUaKUMqx2R5Ru48zkb5euM9MnSMSo2WkdAq85zX7uxzO4eTeUtV5mjZQ6UBreP1kzJyTpwJSXEnJshSSby1LOaWQVVRFBlFmdM20T7BhUiQDSHEUoGIsE4PnSNi66hWGpU69IosSun3kLmUUJQFJ8enhCBQuWTnwhYyy7l39wnCC5yRVOUIRCAvcoKPyN6sbpBaUtcLbFdHPyEZ6IKhri1t7agXDUpLfHD44JDpYtVd4Hiy4D/+1m/x8ssf5vKl97GxvckrH/ggv/lb/zNfff0BB/untO2cBw8P6GwOeMqiorU5QjfcfH6b51+4wte+ep+j4zn1osXaSIwPKEjPkRQwHJU89/xF8kGNzhRdKzg5sckLK2p+gEMKn0p6yW8saE4OW37/M6/xwssvcnjQ8vbbd5lPpwgvGORjOmOQGoRTOJNQ5hCiyaHxCCyDoeDateuMh0PqxQzvT+JYbwTOK5xdTkE4PZli2gWbo4wXn3sxlWM9ZTHguZsv8Wd+6Ee5d3ufk+MFweU0TYsLLU2XcfveA0LIOJ3GUnLwsSSohEIJxWwyo1k0fN8nP8GNRwf8wR+/xuMjy3xeY7abqMNk4pMZgmcymaNzjfcZPt1v08WC0hVYJzk5bTg4qunsBttbm1hjWMynWBswtaCZg3cZiI7YvuxTOSxpS4Uk8OlXjRTL+JGsB1ZxpI9HT8eFZ9EA1lY687lnVRS+0fLtnaDw9coO4kyy0pd2+t/p5TMlnmeVNPptnk18+uTkvZGS9c/3ycl7EWTPfm9YlXDOfXd/A6UmMYRYIysJlg+oSAmXtdF/JZLTVm2SXqYHeU0/Yx3B4ZnH/d777L1nvpizqOfRFyXTnJ5OmE3ntE2HM57Rxpjt7W0GgwFCRi8dv779kHrtg6Azhul0hvN9sF0lg7FSl8onWUZRVihnEGVFkBqlc7r0fgx8ls4Gaqs57gKPaoFoPLNFzcWdARuDig0V8K6N3IxUuhCplg5E/YCQoPnIrYyDnDprmSCJEus2+KUUvQgrBVW3vH6S1gQOjxfMFo4QYuIjpAIp8UFzWkck4+Cw5ehiQfXCJjuD6MRqXPTN6Qm/UkqkzhAh0HWGsowzpsBKnl9KSdu2qfyjI+FUK2zXEFuDSWUbTVYEpG4i+dBGAbk80xG9cjZ2CfWIEPFYi7JACInUKnaxOJ86YmIZyCYEZp1ULqXEdZHwGjtxejKyRMuY3OlM4FB4F8tcxnTJCFEgpEKpDJ1rcuXBGoLIsUi++mDCZqUYlgKtRCLtpmOUHiEi2uSMw9uoMSK0RMi4nypTZJlCqVja01JhhMF6C1InXReZ+sx6DlZK9lWUmpdSJXdsQVVo5takhCuiWHmWc/foNHqiSMfR6SEn00OstYzKEdY7dkYFi1mH91H0zVqHMRYpMlRCx/KspOlaOut54/XbeAfOWpwFG1wkWmPQWYaQGZ0RfPm11/l//cL/k//jf/8/MJ20/N4ffJbX39hnWBXkWWB7dwPjW2b1KUVeMqgqnhx2CAlZ6bjx/AVu337M8fGUtnV4pwlJQ8MFiyCgBGgNow3N9t4IHwxNrSiKRD6XkS+oM0mmFY3xCB8T365xmDbnK196wGf+4B1OTzrqmSNYiZYVzdwh8njfdMlhuUexJQpnQrRxKAUf/cj72dnaZf/xAU/2H/HVr32VTGo0GUb0ATiWdBfTjs/94escHR/z53/kT/P93/8DlFVJmY149eX3cWFnl8NHE7KsBG1BWIaDixwfNczmJxwfT1N88ThjqUpNKBx7ezvMZ543vnaHbJBz4+oNhKh48OgJrWvwdEgRhUoFitnUYP0hbdfgg0R1Hj+XLOYNbRNYzFu8MJzmcx49OGBrY8DOeANcgZZlRDNoEaLDBZMmeElwcamH4lOZZ5VsBC8IciWA2s8M34uPeDYuPBUo+jWfiiHf7PJtnaAE1ssVUbm0D9+rEklf4kmcgVRO6JOSlXZsSjhCmgKLwLMTk74VmOX23ysjPM9fWf5b9PLmPb/h2RloCCG9HwjLZCTuo0wmTLE9jLjfYYUEORvoWkPbdHStxdkoR65E7BxxRF5E3xF09hy6lBKoM8exIhsn995Uz2y6hsn0hICjrGL772x2StvWdG2LFJKyKCiyCJnHsqeP8Gpqc+vhQISgs57JbBIdkLOkeLt+ipfXUJEXGxTB4swcVVYMsoyQSRZW0JkAaJyCo9kJtYMgJZ31HLrAa/dmDIYVH9grEKZNpYgY/CPF3UdPFqFie3IAQhQM00iEJ7YL+9S6RyolpFJURPiSWicCpcHjsG1HoORg5jlaeNA5RZZjXMBZi5JRAt/ogqYLqBPDlaM5e1XJsKiigqmW5Dr62Lgu+tSoXEZFVO+W3jFaa7quQ0oZhcKCxzvLojVURYZSIBPE3naxO0cqRV4WmCZqhRDi7DhTiiAV3lqk7ktWsfzSuypHgT6Bc7HM5L1bXrOl5lAiM0c4OD5XWiuyXFPkGQsXZb4LLQgLGwnNIWBcDFBeRQhdCE8mBXkkZYDOcU7TOkdtAgGHzjOyjFgKkJKms7FMJiSm88tyRFkUNE1NJuI1dUBnQ0rGPIOyRFQFbWcxLlBmOtXr420bTQnTWOQdmYrKs1JGBs1ASwqV2tSVROuc2ekU2xlUkdGajnZiwUvyImdzM+fmi7vkOmc2fbJEQjrnQCisDZBBUBKRK9pFi3WWyZHj3u39GEBDQLt4HzgXr+PmZkFVlNSzBb/76d+lc56jJ8e89ebXwDq8bSnH8bPNomVQQI9w+GDJ84xFN2VWP0HlsXsspMQ9dsYl/6dCUxSCzrQcHR5x9dpVsryizRRVdYxQoDMQ3nJha8CFC3u88dVHGAe5lmRScff2MR0OY6P6skASZBQLtMaxORrRmZiYRdN0iVYlGxubPH58EMXwtKAcSW68uM14W/Po0T2G+RDTdAwHBdZ55k281iZYGtegRMaDhxN++3f/E42Z8IPf/8Nsj6/ypc9/maP9UzZGGR/+2Ad4fDjhy1+dk+U581nL4f4Jtut46cVr5HrM3bu3GFYZIz3kwx94P9O64fNf/DIIx4XdC2QyY3fnEq3p8MIk9XCNFJLOKMIiYG2PLqYSLS6KPQYoB5rZxPLG1x6wmDZsVBvcvHaZ3d0NDvb3Y7u1kwThUvSKk/NeCxHvVwqy/U8izfZcsp5GEYOU77H6uC0RYixb/vQKs+lnOWivlY7Et5aufFsnKLCGKni/vACwQgTOl21ItbQ+LTm7sadfWn3Pav1ERVhewG+aSMsaNLZWd3oWerMqvbDMm5bfxXrJRwIulhVCDA7BR5XPxaJmOp3RNE1KyFY+CqvunuSlI0TKsFeZswtRkhpWPjFAarGMSI9zjvlizryekxc5Uktmx7PIPWkbnLNURUWm8yVUHy9CLC8sSb79+fACbwOLeUPX1FTVgL5DaP1BIZ0fJQLQ4VVHMdAgHMHbREiMs1khHHmWUUiJ9lGzwks4nHXceTLhynDMroaBlnjRC3m5paJiNMuLTsrRrwYQARcCmcxSq166r6ROn4sJX0AgQ2xZlZlm3sRym3XQOoFxccYZ0kCspUJ5j0qdQE56Og/7JzWn25ILowwnFLmO94tWijyPJZtI+ksz+1RO6T15TGdiB4yMzsmRM+ORIg54EFVkm3aBTKUJK5J1gYpS76FH4RKXpScS97ok/T3c679kKrbOW5sS5PQs2iQa0nseKaWRadYfbQgESgoKrdAqGt6J9AxmecFi0VG3LbmIJajI6ciZt4ZJ45jOa7wHpXUSq4sJsE3uykopfCq1OO/RUlDXNUKEWJJLHkt13aKVBAn1oiHPc5QQOFzkL/TPVNLxibwTl8o6kWzsPWihyJSi1JKFiaRkrTRd00WxuEwi0LStRSKwJiT7g4A1luAcCpDSo7RlVOUUVYVUkStzMj3GBpueLUVZjPg//Ph/x3Sy4Hf/02/zZP9JqpzE5zXLNQspaBrDH3/ujxgPRoxHA1whUVl8NjvjCZ0ny2L5xFpDXkI1VAQML714kycPWh7cmcfkBQEiOkRLFRgMom5K8C2337nPlctjrt/cIxtmbIwHtI3Bd4rRoCRTOd5C8IoQLNZ1FGWB94KmiTP+KADpUFqSFwVKRrsQb4AQdXCUCty8eYPtrYvsPznFBctgWDKfnbCoj9nd3ebypQvcv/WQUVXy/PMX2d7d5u1bj3nn9uNosSA1SM1wOGJ7aw8tBrzxlXd5+83f5jP/+bMQAjdfuMyrH7iJunXIl776ZaaTBrnwTCYTPvqRj/Ajf/YvoNWQf/Nv/xf2H91je7DL7vYmX37zHfLBCJkFHJbxeEwXWqwJlANN0yyipovI8UEjVYFSiq4D00axRZWeG60FOGiNocNz+93HfHb4RS5dHPLRj32Ad989ojUSKzXBJm5VXz3rY0VwiaQczvxI2YskrqMkPsWF9caLs9zPddrAs5bwLdIi4P8PEpSzvBBWJABWolnn62XP2MqZ91eVjrMn81n8jGeXgZ69nPn+PtauJVLne8/P7l38vFuKrZ3b9tr2nXfUdc3JyQmnp6eEEJLnxyotC6mcsfSX6ROllP4ED4umZjafE7wnT50hfcCD6Ky7qBecnp7ifaCscmbzOdPJlKau6dro91EWZdLf6EmRyQ9IrBCwZbqVkvJmXrOY1WxurU5CvKqxFCSExdsZnhO8mdCcPGJyekIhPdlAI13HeGPI0WyG6xZUyjMSDlEJ8jKnbgyF8oRmjpIlG+OK7WEVlTmtiYO5tan8EHUwEIHO2li7TSiO8w7ronw3KaHxiIjCxCyMgEticBIpdTxvXcdgXDGousiBUCoq46rYjZNpTWsMWRZbLlt7jMhyEElgMDnWtnWLlDoKUUkdSbnB03Vd4sComJxlkffTdS3e+2gOGGIAVTLybELwUeq+tT2YhUydPFKIpZaOWpod9kTT3gQwkGdZlKwPvdlevLd6gi4I8iKnbjqMjSWntksls57Hke5NGSS5UrTI2KKMpFm0NLM62iog0iy5pA0wN5aTWU3TOpSEMos6R1KsESJFnP3ZVG4RgtSyHAW+8izHdR14T6bjPgcEdWtASJSMyZNUCmNT2c5FfRupovibtTYGEiGiqaF3CKHIM42sDRIoq5K6nSO1BgmZiufNO4tW0DUND+5MubCzBwTKPEeXmpsvXmBzewOViM6HB8c8fliTS00IGVpnlHmOt56bN26wt7vH/sGTmFB7T902tGYQDQvTJKbMCqqqgFLT2Ya66XDOEIJDSw1O4YPl2o09xlsli9mCC3tX2N06YXN8jKSjXnR4r0F6ikKT5dEDCKGZnHbcvXPApSt7aG145eVrvP3GA95+/RAlSqQYcvvWMXUX+UHlIEr4O+dxNoD0SxXhIsuQMiZaXdvRtl3sIAuSMtPsbA4p8gyZlIDzLGd//4Dr1y6QiZKPfuRD3H77AaNBznMvXuP+47tko47BlmLWdgivsZ2hntc0c8fje3M+89v/gQf375NnJRcubXDlxiW2dreZvnaLIhtyctjiRcPlq3u8/wMvMZkds7Up+ZEf/SF+/9OfZme4xf17Dzk9mJBvjdnZGSOlwzpHEI75vObixW2Gw4qjw1Os6Vg0J+g8Stp7b6N5YTFECoWUHmMbjO1i16CCtvXcvnWftqv5no//IF/8wm2+/JW3oQtkKsckSQIBkCaG4UyysYqT63ooS+S8nyH08SH0E8uVPtezYt23ymk8v3xbJyjrAfUMlyGsjIzWX++XFVmVlCGwRFa+3rJe6viTEH7ei4z69UmqcUf7bDas65qcWzGkoGGM4fT0lOPjY5qmJc/zdLRJ5jjEllol1wm6a4RdIifi8PCQt959m8V8QaY0g8GAqiwpi4KyLMmyjJPTU2azOUVREDxMTics5gu6pgMPVVWRZ0VszfX9gwExn46oTc/TEIFlELPGMJtOY+DS+qnzYbua+fFtgjxGho7m9OT/S95//dq25fl92GeEGVba+eRzbq57q6qrq8lO1d3sJgWSoAJlkoJsyzAIGLBh+0FP9r/iN9GGJMCwJEOyKMkSSZESpM7Nqq6cbz457LjSDCP54Tfm2mufe251NfxU4Ow+dc7de6255pphjN/4/r5BgCRdMd2d4dOC9dpTWtiblLx1s+SN12/hMgwtwV8FJT1vXZ9wY2eE7514OHgn6IWXVUtZVrn372gaWUmHIA9t03TS2sitxBBiJiQbwbZSQCMpuwFFUpakROrb98IJjFHnLC1FH0XVoICkDH2XePJsgR4lkrLYsiC5BqUsKQpiY6wFJccrK3ryKks8UZp1g7VZ9ZDPY1Xm9yuV2zyCupRlxWrV4r1jMqpypk8Sl1ogQ0WIokSKNa2tFDAh0LUdRVFQlxWoofAQC/iiLMWcrHNCFg7COQrBSfhilIwdrRQ6JuFHIzA02UiuLErKwtJ14vzZ9Q5VRjqfOFn1zBspKutSUxqwGuqypPdSNElgpL2USGeuTohJiszeY5QhKVHS+Ah9iGhtKMqKujS0TUuf1UYxyO9jkqIlRFHViPHd5RiTUqTQmkLscanriovVBbqwuS2tqKsxKgXKytAsV4TgONw9ZFTXuBSoRgX1nmWyK6TYGC222Odgf4933/oK0+kBdVXzx3/8B/zn/9l/ji1Kko7s7x/ges96vaYoLMtVy7pp6XtPaTxt19A1S1KKQsalENdXEmURKExFTJ7X7tygMCVnp2t+/PCH/OB7H6CT4Wh/j3M1p+0U9aigLGXxEoKonIIP3L//lF/66luUlWdvb5+/+Td/jYvTP2J+umaxWNG2CWUMhkg1qqjqitFoyqpdkBCzSWsKgheCrRiu5TZaUoxHM+raslqsWC16gpfE8vWqJ0XLcrHgYGePvb0xX/vtX+OD93/Kp48e8vDZfV5/5zVO5w08Xwsah8a1ng9//JAHHzwV88GYcErQqrP5jHXTsTc74t23foXjk+e03Rnvvf0uVVHyyScf0zTf5UvvfYXf+LXfJrYdDz74n/BtoD+dY8rE62/d4/jFBXVV86K9oLpWcv3mHrfvHNI0jvliyWK+BoTrVlcV164dMRnPCN7x4vgJfuVRMRK9jBlJIV44OwW/9Ttf5dP794V/2AkvR9Dq3MZPgTikGg9zyxbX5LPzS15wDXNWXmCqJLEagxXEq7oB+RHYvD/Gn3/O/IUuUOSkXrKPXz65f1Hx8Mrfqku58F+Eivws8uvLr/n873D5updfOyiMtg90m219pSWEXP4YI13Xs16vadsepcT+2ZhhcpL/FY8Lc4kyKWSFiWjjnes5Oz/no48/5vzsDBIUxooNdVkym07Z3d2Vm1snSlsxv7hgfr6gbXq63lPakqqqxZkz80hStlffJEsrTcwFmMrFYiDSB8fFck7Xd4ysJUZwbUvo1mjlKVQHzRnWroldS2o6ogOXRkTX0TrNsu0pyxH3bo64V9RgS3rXo6JHaYX3kZRKytjSLl0OvxM7bOd6UpKVfxvE4twamE1rCmtJSWHLgm5UsVg2tF1P2/fZpVEmWpsLv8FhNIVAMhpbFEzHitGyg+RQtiJ5UVoEJfb7IUqroPeB1ntG10tB0HwPBIL3+JgoigqlxcHVZO5LClHyfMpy40ujsuV8MVx3fDYgswSl0IWmGtW40BNDi9WWUV1SGI01mma9Fn+KqtgUk8oMPAxBS6QtJiigyyoXab8miqIAxP01ROHYxJgQDqkct7GGUV3R+A5rxV25KhKp9yRM9thIjKoakrjdruZLThdrGqeYrz0+gTEwHZeMSo1VorQR/5iE1nGD1gAYbQVdyM9G13usUVRG46KjKAqSl8G37ToIetPuvFykAOjsGry9aIIQxYk2orBJMS4LesQwLw4FnIqk6FFY9mZ7ONcQvGTqKKVYr1aMypEE9FlDWRbYSuFdxBrLwb1r/Hv/q3+Xawev8R/+R/8Rz569oOtczqhKNG1DVVWUZYFzgdVyQQwRraTV17UNxkhW0LrtqaoxWo/wriNqQ+s7CYlUFp0mfPvrP+GDHz+FMCKlRD0teO3eLY5Pl6zWS/pWWs0qaayOYMTI7+T0jNu3d3C+4drNHf7W3/kd/sl/83XOThbEqKUwV4iDcNOiMgk4qXxWtcb7tCGvA9TFiLs37zGdTHj27DFnJ+c8PzkjRo+ymsWiJYSCsprgU49La+69eQ2XVnz3B9/E1oamXTMaVaTkURQQIThP6yKzazXXbxzx1V/5Zb7zvR/Qx4Y79+5RFhN0mnL9YJ/D/Vu4sBKi6sERZ2dzzs56zk4aTp4/wK1PuXPnOl0Lq9Bx2p5xcnLO+flCpOkhcX52znTHMp4V3HvjJqcnF5ycLDl+fsFy0bJaNbw4fsz4tTeYzWZ0/S6tWxFb8TOxhefw2h7a1Nx/9AFf/Stv89GHX+b3f/8bklua3Ryiyuqdoaug0oZ1qH9Ge2aYjz5vrhvAgu0CZZDaDzPUgDr/BTjAle0XvkDRSl9Obnm75GdcbmogjnA58auUNvSHNCDAW5Xe522fB1ttoyCfry767L5+tnIo5RXY5X4u4bWt/UD24RDiXlEUeTJJOSRLb1AMSbUVV86ks2to3ndMSdQgzrFYLFgul7RdRwqRhsE1NXJ+ccbpxSmHh4fs7u3RdR2nZ2dSGDUNOilGVU1VVBg1rFbZqsTFkyKky9bIcAwqCgR/evKc02cPqApLM79gdXbM/MUjytQwKiLar4hhhW8XpK4nLs7xiyeoriH4kKPSRYVSJEVsW0kv1fneiQllRInSul5WAkbIxyZP6Cl4khJiXohSdITQy+TsAlbBzrSSTJK+xLvAfLmi63r6qLBlRTk44g73QQqMSstOFZgWlkUTM2EtYZXGBHmYY87L0UnRrhw6yecXanCIFRwq+CDyYWsxxhJVhsB7jzGKqqoF5ckEOGNNLrjEJyNGyWtJGLreE2JkZ2dKXVk00uoS6a/ZOIWCuOr6ECBkXoW1G7fY4ANt225M42KM0iLKChiVNEYntAE1ZAYZDclj8/UxBoyJIk/1EEh0XYMtR6AV58sVTZ9YtD1tEG8ZozSjUjEqDYWRc+36jpA0MT80QxE1FOiKgcMmz1BdlxCDFHhJ1ETOeUKCLjhR0RQFZKO7BFmRAihDjLLKVxmhdDGgtRT4hdFoWxJCT+96PPI7Icz3nIdzUD17+wW//MvvcnayZLVu2ZnuAUkiBmxJWRpKm/C2Y7l6wZ/8yf/AjWvv8md/+seE4FFGyOfeC3/KZbVU8EEIxpB9REz+3pGyLGlbx3rdiKS7qIBE3/ccvzhn58mIFy8WfPjj56g4gaSJXhROWmvqyuA6jTUVzapDmcRolDi4scsbb93FOzg/6ehqDWpB00qAnWQzqVygCHepa1qWi4VkfCUlRmQxt4hNiTGK2zdf5713vsLBzj5f/8b/jDaJxfka1wsXJ8VE0wR++MNPuXX7iNF4irGCKL/9xTdYdGc8ffGIqqrReoHV8rwXhaW0JdPJiJ19w7/2N3+Tr33tX+PF+TPW/Zy79+7RrhKh02gKlBYBwsXZkk8/vk9la0JX81//43/B+ckZr9855N03X8Pakjfu3mTf7fO9H79PDJqdcY3Rkfn8gpNTy+HRDkUJ2kZidCLvbiParAlphY/nKFsR8ZSlxfUhE1YDd+7cpO0iT54/pG16/vV/83eZzxd8/Rs/yveBEFcHhU5Kl1liwxbT5yyAt8avl9H+K+j7hvP5chE/vP+V0+Dnbr/QBcrmZKhLDfzwf8PvgVeelU17Z/j9VmHyeUTXv6joeFli/Hm/FzKl3vQEP3txXyqCEgwqpO0vcIXsm/kkCgnSm82mTKdTzs7OCPmhGyy6k1GUdYU2mt51+OBIWmEKiy0KgUbXa+bzuaTM9lkeSdqwu3sHla82K+OL8wsW8wXNek3wkVFdM6rHWFswQH/CLxDUJMMnaCVog4zSUnjFEOmXS15cPOFb979D4ZbE5gLtW2K3JPo1KjqS79DJU+hIaRIWT+FbYu/xQVxdXUzEoLBJvE50iiQf0aRMOpOpQavMbYkJdHaVVVK8CKHYyaCuNEZFYmhRqpRVQkwUCoq6wBcGaxVt27NsOtZtTx8To8pirEhdpegITCzc2a9Ydi2rCKa0uVgWpQhaU5aGGZGbuxV7oxIVA0FBDD6b/F0OACEFClPiey8macZQ2hJy20QZi4rZ6TSlDRIQYiT0gabrWCzXm0A87x11WdA7t7lPh6I5xLCRicd87xljMUVJCpGks/labkeGKNwYY+UcShQAGJ2oq4rGS9hhYQ3j2rJoe1xwGAXe9ShTA4GiKKTlFxMX52uWXZJrjBZZq0mMSovVKXvbDEnLKXNm7Eb2rJW01SCTxpMoi/rOEfqOoizyvarEel8B2lBoQ1A6W9yLj0cMPpOHYw5IZLOiDMHnB1YI1qYsclik8LFSUiQVc0ERGY01ZRVpu7nwV7SmDz0qJEKoUMpQ1zXBOYoi4buGR48/5PS4xYdWzrFVG6QquJxxlBIqSetRQyY3S3EqlCkpFFEJ53piUBTGMqomFNby/MmCtmsp7R4xQNc3+BB4+vSYDCJBBO8DdVWwuzfi6E7F0a0dEtA2mvVFx/NnDzm7aHj86ALfaMqygGiIqWdaF0zGNZO65vXXbxG0pixHFHbKD3/0I5q+QRGppxN+6zf/Gge7t7n/8U9omiWz6S7NWrNcOaIKJBQhKJ48uuC//sd/yI2be7z51m3efvsek8kMbXYhnUOqIbWMRyNSYVApMZ2NeP31a/zmb32Vd7/0RR4/eciz50+5eXefnd1dnl90KCTDy8fAulny/MEH+LjH7/3u3+Abf/oJjx+dYzG8eNYxP/0pF2fn3Dw7wpeJ6DUpCAqmtaFZNCwXPbNZ3CwiXe8I0dB1HX3fUY8Tnb8AMyUiAYjGKHzw1HXJcrXm008fcPfONYwJHF6b8G//vb/Fi5MzfvqTh6ReFDwCWedFb8rtmSh5Q3I/ho1YYlg0Djl3rypOLudGfeUPL82dUtykv1SR8gtdoLw8iW8jC1dQjM/0w15CSNRg/iUQ7aWC5i+BRb20vVyBfqaFc9nb2RQow/te9f6XtwHyVDFuXfC8AikMs50pOzszzs/Ps0JBSdKqkRaONgYXA8v5nNV6TVVV7Ozssbe3R12NODk54fjkWAoU73KESLb6yfyG2c4O0+mEtuuYX1zQNQ1977DGMh5NqOp60yqTKj9bqstZRqWEdx2rxZzVakXbNaxWS8lfWZ0TFs+o3Bm7Rc+sSIxsoi4So8qgkkOlnpGxWKVQpSZpT8hy7KHoMUY61YQelcRtVOuYOTi5LkLLahe7MWQT1YACY/BO2hI2W7MrpMiJ3kmRsLGLjlgNk8owKmpmkxHnq57z0wvatsFYi61GgMYQGenI3R2N6w0Pz3sWqsTFhOu8dPa8o4qBd2+VfO29a1ybakxcZcM3UdiI62pB7wcIMCMb3kvartZU1hJjwHVdLszEFwQtLYPgIuvWcT5f0/We8WwiHiCZzzSohS7vsiRtqN7lFo/e+O6YLXRCuE+XhbRKA29lmLwHPxnZq9WKUVXSemmv9c7hQ8IYjWPIRdI4H2h9YukSqz6hjXidqJQYFZpJZTAqoE2BUUMCNfm4dM550gxJywOiMxRyMSbQNnOkZPgos+tsSomIYt1KdpA2BksOSQyDtLsgBFFHJchRB9Krt9ZgSss6uE2rLFvoURYwqmH/wHLtxgRrE21+Nq1RNF3L2WnEloqi2hErfhFQsbOzw7ja3/jcjLMyyfUKSQVPgvMLZRlrM908puyxImpAY0EpIV4aLQuJvnXYQlPWJaWd4Xyi7daCgMZE03YEH7ClYlKN0UkxrUvu3D3ii7/8OvN2wf1Pn/DsyQVnz+dcXKxJyZCSFccFgiQ8I8Wk1orZzpTf++u/xWRvhxQNH37wmE8++RTncguuGEHUNOslH3z4faw2vHb3DYx6zsX8FI3GR4UPEL3i4tQzn7/gk4+O+dM/+gFaC/9iQCJ2ZiN2d/YpjGW9XmArqGaai+UF/83/97/n0cNnnJ6f8NqbNyl1SVl6lG54cXzOsxcPOTl7StOfM519kcePFvi+YFTtkoLDBSkw650JZ4s5wYLStZzbJhJSQde1nJ+uRb1WlUwmM6pqjOt9bklKNlXv1tiqx5Qt1mtMCXiFNQUP7j9HoTjYn2IKg7bwxS+/zd/7+/8G/+g/+E84OV6ggjxDbNo8Q5E88LHMRswwOG78rDlO5hx5fjeLZnVV7PHZeexfIQ7K9t+vKkheVWhccjvy33x2P58rlfqc4uXzSK7b73sVV2Z49VCkvJokO1job6E06lWNqLwy1oqyLJlOp1RVxWKxIMaAVom6rvMK2eCc48XpCU+fPiUB43rEeDxlPB6zXq94/vw5fd/LZJ8LlGEbjcccHh1iCsPqdMF6vZJQtBiYTiaMR2NJfc2TgzwKCYwoSbzvefLoEY8e3ufjDz6gXS3p+pYQPdEFVHCo2GFwjKxid2SpDexNDIc7Fbtjy8HEsFsmdstCAvRKhSk0GihybktSkdoafO/ERj27iMqAPKBOMhgbDSkafAybQEAZ0CWvR94S88AuPA+FQqSxUqAIOiDnqtCgd2pm44rFcsHJ6ZzGZ9v2GKlLzZGK7L814/Y88ePHK14sPeuQqEuFJXLnoOCvvDbl9o5iVipil/AuMZqOsSavfKKhLEp652jaFuFS9BTGZpRI410PSVQ2gzdHCEGuidLZE0dea6wmeIdS8l1NDhxUuUXY52A/a2VCCRnNKYZJnMv7dVPg2AHBC+QuFyTZd8iZQXVZcL5uhfSnTPbtyUF8IZHyqs+HxHzd0/hED5SQr3liUhoqCwqRaldlJanJvReeh5KBXvxbrqr8NmqlTIoNEYwCrSRrKCKpxE3vWHee0Uijkvh+iLI8Qc4F0sYQfVbI5RahMWLQVlQlZ/P5JnhSpcSorjg4qNndS/zyL7/G7bs36BrD6ux9+rV4CYUAsXGslivadcHOzr4cm1G88fp7fOGt3+LHP/qQTz75kK5rcF0n9yOCrqFUJkbrXBUNCrrLCSslD0rO3WRUMy4nhBC4WJzRdEumswPKcszKrxiC+JTS6CJRmEy894HCwnqx5E//+FucL9acnq9ZLTuUU5AKlLJCjs+tx2Q0MSiaxtP2PWfzMxYnJ7z3lfcwRnN4NObf+rf+DS7OW0BQt8ODQ97/6Y84v3jG7Rt3KCzEtGA8MRxdfxttKz598JDlfCmInQ+EpFn2glImFMqAsY75Rcd4tOLtt+5hq5KzizM++HABOvCTHz5gfuHY2amIrqJdRp4+fMz3vv8Nnjxe5udBsbd7xOJC8c2v/5TRaJ+336po2jkhig29D0uc68RbCVHKdG2gT5qEZb12cLIkJZjO1vRtFEfcnOoegyKphCk99SThXBIvGW3xDi5OG56VJ5ydndP1PV3fs7tb8KUvvcvduzc5P12RgrTXZT0eP9NdGOwntNLyHAt0Shr8JrhKN4hZNTjkxG0nI6ethcH2XP2XEZb8QhcosqnLE7L197BtczbkYRykVoMjR4IoCMpVFOOycHmVlPhl3smw78FN8uXXvFycDEf4uQXU8LeCwd3m5SLnyvfM/ycZI2LQNZ6MmM2mnJycsFqtZTBUCltY0ArXOZbLJRfzOd57ztSlt4b3XuSG/pLsOHTMjDFMp1PqumS9WnNxfkGTAwHrIhdGZbWZ0GIUbksk0KyX/PCH3+OjTz7k4aef0q6XqBCEX2H1ZhUq9aNMZuugOG2CyDMvEvVzT6U8d/Yq7hwU3N2vOZpZDqx4koyswSSx9LdFQWksmrwijwmClRTb5NE4tAoUuR8fCOCFA2NsAcSMOAgkL8CMEI+HNqFKQsRECawenfAwCmNkQDEJa8YYW/DkxQVdL+e0qgsKqzEGDscFt/b2+fRFw3wVGJeJo5nhzsGE/VoxwpP67GhKJhGQcK4TjyTsprXgnNjZkz1PQvY8KYxBZ74ASqTQ664BU6JUgVKOohDOhSk0OuYWkmJTHAzPl/eZO6FyNlSEZAzO9ZnbIYjLoA7SWm8CFoc7VilZ/VtrKAog3wPaaGJPtt0PhCBJtSFAFz3rqFiuO3qfvW6UZCmNSs04t3dIgmo4bza2/Trp7GYbr0j6Bz+XIb04RvG4ISVpjxrFbDLGp0hohaNji4KkdC4wItYaVC6mXIi5rZTZVlpjBEpBW5OdZiM7OzssLy7wrqOuDO+8dYdbdyp+6Zdf5+TklG9+43usFlL0heBxXUCVhuBjPjeRUVWyt3fEr3z1d7h3+1f49//9/wt/9me/zze+/qe8//5PCf2c4LycJ21kmtEKrLStVNL5uR7cq4X0bI1iOhlR2QprFZMdy4uTM87PLtg/qCjLGtdI60rrRF1ZSmNI3nN4eMhkUtA2Hc9PlyzWPW0fxHwoCZ6jlCjOUpACTWkPqSAlw3LVcO3aHh8+/oTdJ1P2DkdUox0O969x68aOtID7lmfPHvP++z+kMCVlodD2gve+fI2jG7vs7b9JTJJ39NOf/pjFciH3bxCLgyGbhqgziqdYN56PPnnI7VuHhBQ5n/c8fPSMnb0DLi5e0DSRP/+zH/PNP/kRFxdnFLbg4GjC3s7r7O3dYDyZEYJ4yATVU5UaMKzbhqQK2r4jqBKdIiSPVYpIoHdCIjZK06wcz/2c+bzd1A/eO2KEGIawP8doZFjNHcaCd4nOeVKEZuk4O7lguWpYrtbMphJ5sLu7I2NqRgXlXxk5eUXxkPL9v6EPvLSIH/798rz78rz4/+/2C1+gDL3xlFewm2yavFKS1WJeIQwFxPA+GJCpfB0ujczYqEw+W+29slBBs1X+XIE3XuamkPc7XEOj9Gc4KDB41uZ95qTLMFiGx8H1dbvgGYodmfTqesxstsNoNGK1WrJqArawlGVFXYPrJV8lBiFKyooqSEaK93jvr0iac/eDFBV96zh5fsZqtWK5XNO1HaUx7O3usTvbAWVwLohxWQpURcVyfsH/8M//KZ9+8jHOdcTg0BmNiCoRnFw+q4f+pc5IB6DFx6FL4oq5Corl85ZPTloOxyveuTnii3em3NgroEqMlM+tBbO5H6w16BikzRODtDuUfIbKeKbWGqXlO3vv0FpTWCsISVR51a82ap/oJU8m5uupEjlBOIFKmOTRUVaXxaygsgecXqw5Pl+xmq/Z2ZlS6ERUgcOxYXTTkpKYepUqUumeaVGKw37SaKupSskvKoylN57OOyojpmTGapL3aGsx2kBI9LGXu9NK0RdDImlpX7koKMe6CTjfU5U2t1Kk6B2SeU02VUNJonKMib7rJLDOFHjfo1zYXDfvvVjEW0tC+EDyTIqBnMqIg0aRnMMkGFWWcSxR80AIDpfAJYhJJNqdS7TKMF93tC6Lc5UUVAoYVYbSJCZVRdu1BBeJRj47uG5j3KYRFCukKByqzLEZjO1A5PzWWFCFSN7XHWVlJXxOldJSQ/xPlL5s08Zs/KZ1whSikgk+XHLOqoo2ejFxW6+JiBmf3Csiy//mN3/C97/zPu3aUBW7hOCwZS3BkNYymo4JWAnmVJaDo+sc7N9Cm4J7b36BG3fu8Tt/7W/zX/0X/wl/8Pv/lOfH58zXXlRMKIzyWGUZqDExO0irqKVwR+TQ03EtWdJKCt6yGLNKLc9PTplOKmY7MxlRfce0NoRQEE1gNi3pOsdyGfDOYrWi1EAK0s5L0t5NMYLWuBBJUYr+0irKosRay8V8wScPH/GF6dsY11NWnloHumbFt7/75/z0gx8QQs/Bzoz5+jnvXf8ih0f7HBz1fPzRI6r6gOBbdvdGmMIxv1iTkqA8k2JEjMLdSEDTd4QU6VpH1zmsskSnOHnaMxlHTKxYX7Q058+4fWufv/t3/za//Ctf4eNPPuL4hcW5CucEUUD1YuikZRTXaIjQ92GozuRZMoqoyUGlQQpYY3Eu4P06L/BUntLkmXN9pO8cs1nF+WmT88sEWVEm0jlH8AZDKUKB5ZKLs45mtb4yDwVkrDIbgzaIaPmTRHkYU27F5xnm5ZnwVSGDcqyXRYqMhdlllksf2p93+4UuUIYeGOQTw+V/DyXIQEvZFDLyxk0bKCNYDBXFgISQd7d9Mj9fVqzy/w/VzvARV9s+4gcRNqjJwPI3ryhONtWreulzPnsWXjonZLRDUxYlk8mEyWTC6ekpXdewWq8zP6SS9k0MaKvRGa0QmXF65U0kN6N4HJycnrBcr4R74KTI2dnd5drREXU9pm29SAJzHktKgW9/65tcnJ3IeUqBRNgoK6RVojIpRF2iXUpwKa01IZuJhaRR2uDQhKRxS0d3f8F80fLF1/b5wq0dbB0oCfiQcp87idrAmsx/Ef6IzT4fRoHPpEJSpCwKuq7Pi01FzkHHFqKg0VoTgKgCYh8vxQ5IwZkGJYoSNEIphY9gpwVlsUNRljx6fMJ6uWI8HaEt1AUUCYiJulAU2mzOlTEV3vf44Cms3nBCrC0IKtL1HSRFVReMRpUMODn40Gqz4RRoDUUhhmKrpmO5bCWBlURdFYyqirosIfYbeFel7E+SU4yFBBc3SiIxIhOEpMh8lw3KR36v0Rgjq8iklKTXekcMEWsMlVbUVUEVBhRT0JEYEiBZQT4Zus6x6vyl+itGkk9UY0thDdZoUojUZU3npAC3RUFZlnjvpTAbcoSCuAYPxcVQ/IMoS4afoTW99xSl5Oc4L7LckB1/5Rxsw9lyP2xaxSllR15FOa45Wy6wpZbYg+iy700i+kCz7ri4WNE0Hs0IpSxWy5gxGLlVZcne3g5ae6JqMUa8aHzyKFNgS0NZlUDLaFRw4+YB5XzN+UWLa73I35OG5DaTz2AsF5zInsVNODGqhMOyOF5x/OKUNhhMYVmtAylZbhwdUhWK9eqc84uG0WhESrBatvR9QCsjnigeTBqM8qSoT1FvEqZjJqrv7+9jteH0+JSzkzlNHzk5WzJfrPmtr/0ur916kx/96Ef8+EffpevX7O5OqGq49/oN6nHBxfyUw2u36PqOh4+f0HRPqeqW6e4ECLStZ1RWHB4ckKJHp8jhtQN65/jkwSN86Ek+EUMpjtZN4uT5U7SGUTnCKMPtO7d4483bHBxMWDc3OD25QKtS5OLJoZNFpRz+qiJJBbxrcL5F4QhJRryUXZSNSWImGBxlNRKH15jt+5Ugs7YEbSJ9nzg+vuCtt25jrQblZRGthF+0bjo+/fQJd+58yu7uHmUx5f79Jzx89JQUh4W6PGADepK2/j3MKFdmgMTGyRz+kuhIhhEHRsW/Ui0etVUNXLZltkTGaXhdPqkpXf57a5NiQt6/IQ4NqXBcobR8piVz+e+h6ElX33Dlc67yV4YJGC4HxE1hlT/9ChFJXe4ncXmzvAp201pjCzFXk3ZMTdutRZ1TzLGFoetblFZMpxOcC7RNh8+GVjqHtV0qIK58E9bNmq7v8oozUlcl169d4+joCOcibbeSydHIZHb/049YXJzKZBe9xPBs3fAxRAYib8orWBDTMaOl5RRTpCwLUozS068sprC41nPRG/xJ4qI9p3eJX7k34XAUKZSYpqkM1xttKa1hSOg0VhNDFDKtsXR9LxJjQJUWozRFNhpLecU/kMJ0bqHojd5fZRgViNvcFpPfI+GBowqOdmtKc8Dx+YrlumE0HtOtOyor+TjJd0RjGI3qTLj0BBfQJqGjou9F8WK0YTIZ0bY9XdtIz1qVuN5TFOWmEI7O9vYAAQAASURBVFb5nKrCCgoCJGMZjacobWmalnFdURhFCo6yKEjRS7aQ1jgvPisD0jegawNqMLRyAClcUvYayQPUIDUeyLkpCdE2KYhKk5zfUkzFvNo3GITA6gOsO0ffS2jg0HIySv6MK5tbWHL+5VqbHCsQKawUtWVV0/d9tr1nE2AosmaxxRdb/7R59opSDMIGF2etNQa9eT6vIqQ6P696g+5oLCHF7BQMMTmcW6OtpapLvO/QWXIdYsf+tTFv+Os8fbAiuI5RWWJQ4nLcKtbLnsIIz8xo2JkeYs1I2nkxoiJ88tEH/PT9H/H222+zs3+H7/3oR7iP7rP2S+FqxIBWHhJoLFYXlKXGu07QI2tABWwR2d/d5d5rb/Pg6e/ju45IxKiCZtlwFhw3ru8zne3gY2A2mdC2DWVl0GVBv+ghFmgNwcv4oq3CDGqqCEkZlEoYC6dnx7xxZ5fgFTpa3CrS60ToIn/6x3/EyTvHPPjkAet2wc5kzNH+jN2Dkt29MWfnF1RVzfHpCTfvHHB444DrN6a8ePGM5aohBs3FxZro4GJ+AT6iEB+YyWTC3mTGYrVifrYSXom2mEIzmlqMhv39XUwKPHz0Md/+tsVaxYvnDSoWaCw6yTMSExglCKYxUqi4uAbdkYi4npwILrw5HYTfFn1HDC31uCBEjfdxs/BVJlGWUuCtVy0Kzagec8ZJLrIliVwpy9n5nPff/wmTccXzZwu+882PuLhoSEmMG5Pa7iXIWDYUKeLjpEToM7g1b9pCl3PMy/PNBk3h5SXzyx2Hz/7+Z22/4AUKmcBz5SdX/mubNCvlQ0Y70jZG8BIKsXnvEGb22aLmLyoiX5Yjv8wbeblFNJikaW1yUZAd+raO6pKEFK4c85XP2uLgGCNyxOl0ymg0YrEUYuxytcAWEjS4v7fHbHeHtu149OgJ8/lC8j80GyTj848/5YEOJtMJu3t7VFWNc83W4K55/uQJi/npRvVirBQ1MSqIW8VlhgdDusyBCFG+d0qJ4CTRVdouKis8AF3QhEhIFreOfPeTU8bWM35tIq0SY3B9BylglUUp8kAihmyFtTmkDwwpG8epTeVPipihQIxhswInJYlT1JeGRIMhWiQXZ1pL8CBgVW7/KNAVlLZmNq04OW84n3e0K0coYWdWoo04K8V8blwmog55GX3niSEKRJ3E/r4obT5vkRA9yiPScY1IEpWot3yItD6xbr1MeqHB6kRdmCw3BOdE6TTI9+GS8DrY1qckeTwDp8V7KZqEtyLvNdZsECwycTUiqctJWVwI+AQoKxC280jAoPATxlXJSdPhPDifcPHSs0cphQ4wnlgqq6V1l5VMKabNENz3PSFoisLSOydFaC6mhuJKwDudJcHiB+G9GPTp7P9itcTed73Hx7hB0oZnTc7J1jlTwucgSWigZDl5Dg93CcmzalqUtlSVoSotk0nNbK9kvG+4+9oRD67N+d43H2AHczZraNpAs3SoZFAYDAXXDm8L0hTl+/e+4ezkBd5F3n7nbX7rd/9Nfuuv/y3+H//o/84PvvMtrEno0tB1OpsVgvcdRmtskaiKETu7OyitaNs1xdE+RZHVHQpJpvYKkqfeHTOfL6jHE95443WIiU8//jTnPkmqblmOScnTrAIhRaxVEomgoes6QVltSVlX+HZJSLJEDCmBi4Q+UmWZ+WoxRxvFbGfMqNRMp5bd3SkxQdt6eu8wXWLdPEcrQ7PqsKoi9Cum0xHeR1bzDtdG8LAz3cH3HS8W55uoVGVhMq4YTytslcDKPXLtaIdCKYKDL7z7Fs4lTk8uIB2hlEfpHqN7QtFhcoGtsBsLhaJUhCit+qgUprgEjbUWpLPve0ZjTT3S9P1wr4PSEWWHlib40HKwv8Pz56eEkIiBjHbKs79uGu7ff4xmxU9/8gDXS8Bryu3nYcy9Ys+R1TwxBpIW3lfcmuuGZ36bU7nd5rncz+eh79vdjZ9v+4UuULZbPBu0IQ0oyitkwrldoHL7RW3eJ3t4VftmUCTI74ZPGpjM2yjL1XbOq7bPFCVb79XqUmr8im+6Ob4rF3r4DsNx5wltuGm0EqnnZDJhOp1wdl7gnKNrW5ZLRTWqOLp+jdfffIPFcslqvcZ5J4qXwe1zgAFzRsr2MQw3ao5mYdWsCSHRNo627YBAcJH5xSkx9BI8FiRTReX/VUZvCIqb4spIaRYDWCWENq0URXF5uyog+ETQMunZwuCC9LSPe837T5bcOxizX5cYlYhKEZMSRANACRoSQiQG+XyVhLBXDDyJ7JIqZE5F0kOuipBH/ZBvodg8mCq3VYxGgufyoC4TVkKrRKkURkkYXl0kCj1iOqp5drpmuXZcLDqKIiFgh0crQ0pQFYaUVA6qi6gU6WFTyIpDbMxIQEF0npSyOzDCk0GJudqwcl2tF0xGFTvTGYVWRBcoCrt1X8l7tTGbLKdhk3OW8H0vAXvI93N9Vn3py3tT2j5y5UIQ07ukRPIeUXS9AxTOCwHYFoZSib9JYRShdaBsfhLk+dMoRkViZ1xQFWaj+IGtgDlFNnyT9pDK7aWh714Ul3LjS0TIXynKNt8hDHENbIqyAV10A/9GbaGYKOEExW1HTYjRMdsZE1SUYzCa2XSEtZa6HjOaiGndrbtjfvCdxxhj2d2ZcuvGAQ+fnXNxtqBZeNw6cHL8mOMn/28efPqUf/AP/iGJgidPPuT3/+C/o+0u+G//2X/Jh48+5W/+7b/PG2/e5Uff+waFFQPHHnkehI6kSDiqouL6tcPc4lwz2Z2yt3fAJ/efbM6tMZqqsoxsycH+Pov1gpOTU4LrePO117h54wardk3n5NzrCD4onJNFoVFQFprpzoRVY7hYzKnKAqMMQVu0NkQSXfTUVcUvfflLHB7u8emDjzk+P6EowfWeZdtysSwZ74wZz6YYqwFL2zhc39A3nkcPntE2HUWlmezP0Mrifct63WBQrNaKtumpR5bZtGQ8HXOxmKNtx/7RDsv2HHRE24LAivFozLVr17h15zaECfsHjnUTqWrN+VlDUTpmpeLkWaJz0h7TGIwpKVKNoocCYtIQ4ybh2xgpaPCGvneMZjXKQO88IRpSJvZaIyZuvV+yP9tjVFuIkd7FnCYtCOBi0fL48TnR9SzmnpQMSgcIIlZQSRRdMuZmxU3+o7SWn780X/2sAmVAUa7yUuR9Wg8qMcWrMZbP336hCxTY5pBs/0x/9od5SxljuqrMefW+P1uw5Aln8/MBa/lZ73nFMQ8X+OoPr7Z/Nr2Cl48pbr7D5nXkXiUhO70OE6IMzKPRiNlsRlVVrNdruUmyamlnZ8ZkMqFp242/yZCJs52gHGOUrJStG3H4vonAulnz6NEjrC4ISeybd6ZjLuZnhL5HE/P971F5wtQZBrfZhn9Ttg2r8xjxMVHaUpCHlLK0N0tfFRATxiq0lswbpQwUNed9z8kq8PqBEWdNGIJviHlyEwWGtNVcL9yOmESBY6yR12lxn0q5EJG8GIfRhciOM8IibQ8pWIyW1aaE1ImiA5W9WfJ+CqVJWZ48KTVVqanqGRdLz4sXC5pVzyp43CRRVRVaBbSRZGQ5jATZ08P1ibKwlIXFaGkFWK1IhaEqLNqwsbtfrMVl11PQdg7nHUUxlfwYIirLr21h8O5y8BmQkystEa2zcZ9cvaIQG/yohQciE8bw3EhR1/VOCLO6IERFSIo+BNre0wdwXhQy2geik8DD/Z2ai76hz/4woj6RInBcKSoDo9LKOSIJOTsjp8aYDVpiM4dmGDyt1VwqzYYgxG31kbiopiTOuCHfryGKo+uwcJHgQL9hkV+2crVkxqiBpwLeBSgMXdfkIjBQjyv+yq9+lX655sXzhkfHDRDZn97FOwuF5b0vvs2/9e7f4z/+f/4X3H9wn4/e/4jFfIXvA7u7p+zvHRKcZ7Ve8Kd/8gckPJ1bE3XHR/e/h/pDz8nJWloOOqGSxVppbaKk9WiLMaPRiMIWrNdrIbLv7HF8eoG2lrfefpOffviI3jVUlWVSlzRty3K5ZjobU1U1H37wCdPZjIPD6yirUPaEs9Oei6ZHJc14POJwr6ayilEtGTOkkq4P9L3Du8Dp+Rm7+yPG0xqtFC+On3D7zhF7B1POVk9BR/bqEctzePHiAoCbt2+Blmywru/o2jWEgViaWK87nh2vWa0avJdiwBYjQjKMZhWmDDizZtGuKSpDNdKMJwVdKFmsFrjYsVqtmIwq/I0bfONbf87+7g06Z3l6/ISbt2+wdi/QQLdW+DSBjNZqZanthOCWKO0paoV3wmEigLaBogTfa0wspVXbO8oROC/8nZj5OqoMFIXGuzUHBxV3bh/w6PEJaS18O21LrKkxaoflhaJdd6Rk8xiWQMu1lkW2IiTwKWBeiozZfu6HMXl7jnv5ddvP0NakRlSIuABRyr4CXPmZ2y90gbLd1/rsN5c1uvw+bXrhAxfl6gn/+Vo2ny1WrrZxhte93MbZ/tnLKMj2az/rg/LZAijGgUCV04i3v8Swv0GDrtOmzTOZiL/JYrGAnJlSFJbRuMZoRdf1OCfW00qLl8hAKh7O36uq5uE4B3+MLjopPtCkVLFaLUkxbFoqRutMTpRJW+fVdcwqmpjiwEfN30cq/JCkLeOcwxqFRlo3ymohi0UvCECMhKhYtIFlH3AxEnXafF+FkFiHhxSVY/20TFqDIdJAJh1IzSlljowV+ajOPVoQdEF2lQ3fVI4PyB4rOgfdbSS7MfumRPl+VkFhhX8zLivGVnFy2vDo6RknJ2smu4HJqMR0YlKllKLM1vBR8uYBabcYlX8+JOoaWXmZQtCHpu1xfaAPPdpaRqM6W9hLURmCFHneS85PjJKM7L3fTN7Cu2Fjytb3TtKyhwC+fC+GmI3JMkLRux7nhWwbEYVOH6DpAuvW0XqdkR1NUYB2GnxgVJQcTEsa1+CUwiuNTZHSKHantSAswTGoapJSBC9KNzWkSudioiyLzbka+DPDv4diRe47QXzKosxDhyiYxEEXovckJBgweD8MEjnP6ZJLBtLWE9ArkaJmuVxzMZ9jS8vu/pTf+q1f5c233+LDH7zPcrHgeDmnrgvOnj0kBEknL2vLX/21r/L9H3/M8elznj95ges10VVYpenbxHKx5Ps/+jovjh+CVkTAlCPGO2NWzTkxJZH/+4i2UBlJKbbZvLEwNWUxpus9bd9ircJHz4uzcxarjot5S1FooKCqKpRRXFzMISWuH+1DhOXFgsePn/L06TFvvfM6t28eYPQ5Z2dnFNZQlxU74wkpdhgVSMazvz/l+KRFKUsMsqDQJnLt+owYNZ8+fkCfPKtuTjINd+9eY3+2zw+//TFoxXhaU1WWnb19Tk/PWczPuXnzCJU0Tx4dczFf0bVOFgRWU1cl4/Eu0/EOMTmW62OUcRgrLQptI6NpwXx5Sgga7wzeR1Ql4/5qveZscc7T58ecnTouFgtW3Ql1ZVnOWyblETGOGVrxSgVGoxJtxvTBs7e7x8nxOeu23/D8isLQt46QBOkNXtqCxgiBuW896JSNIsXpd7V+wZtv3yQmz6NHx7SNxuoJhZ5i0i59L4nSikhSvVT1asv7JMHLRYb8O9tpppSfn1dbd7zqz8s2H4MDLXm82/zHz7n9Qhco2yvun7V93unYTL6ylLksKNhu13y2kJD/3j6CVxcmV45h6/ev2vTAdyDTG15KfMzo8WcIScOxpZesiMlwulJstXmmnJ+fCR8DyeIYjUYoPZinZWmueIBvPjOBxNpvVox6wJIuP4fsExKDBOUZQ0ievuswefIeCplhMgiDB8Lmu8tdLPJOqe4HHxVgE5amcx884tEobFFhjaVQ5IlYHCSbvmPdNYxSXmEbLTwKazBaURhN7zw+Oumxx8GAbVDPiLsiKsvVtdoE8UkxIxApKRsb5YJLem0x18cq28xfdWhUpE1hHFUiBYdNCaM05dSwO9plb3fE4+NzzpYN65QoJ7W005ScC20ErbFGjJRCSHjE76QoilwYDLwY6XuX1RjnWwyR8XgkwkKjCSkQvRNn2qLYpBO7XJhoY+j6jhQT9ahGKSGiSnikWLcLkVRQPKU1Ptvhk6QgcDGRlMYn6HwQVU6ItC7QukgfwKd8TYLYvosHSsvBeMRi7ehyYZBIjK2iUIIoldaScgYO2sg51sOzIBOPtVJgDfd5jDJY6+EaqcsICtc7FEo8WYJcqKbtZMmgVba1F3+fEMSCv+97aU/kYlRcUcGomBG7PD8EaRdppfjyl9/li196F+UibdfR9I7ZZJ9f+sp7PPjoCe93jzA7Iz74+Mf8V//tf8rrb93j5s0jPvpgTmVrOl/SriPf/Pq3+A/0/42L5UOSbXE4JntjlI3sHxxxfn6BjhVGKULUGKuIsWc2mRB8ZL1qKa2mqmrOL16A6jm4dogu4WLV8PH9x6yWkgxcV5I2HJwEZO7ORkwqy4vjc4yF6axmMW94+OAhr79xi9s39ljO58wvelL0NE2HVj0h9JSVZW93h9Uy4ryC6KnKgv29HZrUkVTFuut4fn7Culty994+e3s74D3jUYGdlsx2K2wBo7oUI0IFu3sTJuMJ3/3uT0k6UI8Lykpj7Jiy2mE63UNrTdetSHoXXQRMCT40BL/EB0ddV/R9YlTPiKs1s/GYO3dusr83ZTwqSKlnuT7m+MUS71tuXD/AxDH1bMa6t4BHmw5tW/rmnL/yq++C7rl+7SZ/+Id/gn/RCIVAFcQoxVNwDmstfR8oOlG+FYWGkSYER/CRrgNSQVEaxuOSt9++y/x8SWV2qOxNCl3heiv3r+pRqheKY4CBliDls4hBBl5bjFl9xuD3nTLWncd6PtvueXmxfZWPksf0YQ7JC+6/CAzY3n6hCxS2J3SGdkPa/HKDemzB0MClxXUaTtnL2wCBXWYH/HzSqu220auLlOHv4c+gitBG50Ft6NFtH9tAuru8EQbHla269kpHSG4SaS9coigTqqoiOEeKibIsGY1GxBhp23YL/pYPvlTaXPK9h6JFkY/dCBFMWjIeFSCodJn7E4NM6oh/SNrqXxqtczGUcvvAU2YZr3NB0A49rMrFYEllS3NtZALUPtC0rRhllRXtumVUldnVckCkpN2gonibpJjQtpD0XbU5YaK4UCZbgotSIyIBdAkBWaLanswEpUtRYFOVhNhpjKY0lsiwGiFPjkkIbaKxRDxFhBcVU8ytLg1WUaWItZqqPqB6NufkbC6HteE9iftojD0Q6bsOay1lNSZGsZyvamnpLVcrqvGIgKZpJOfHaiWrsSTFaXDCDVBG40KgKkoiHmPNxtMk5eKt7zvK7AyrtQTGDbk+g2ReUIZcTCuFj1HuIq0IKeGjeJu0ztH0ARdh1Tq6XuGjousCPihSslTGYJJnb2xY9AHvI4WGsVWoFLBaDPXEx6QgxERZiYx+KKWVvgoxp9wqs1ryaAZX3YELZrVl3TYUZUUMkfmyJUTFZDrKJN78LGw959YWgq7poRhN0kbU+fprjbEFqushaUL0JDy2MDRNR9M0LNYrbF/SrByT6RRbaJIOnM9P+fNv/yG9szx5Oiclxe2710ix5P79h/ig+af/9L9iZ6/inV+6x+7BjM639L6h6yPzs4Z+saTvPeNqhPMdSmtms13Oz+eMRmNmswnlSJMWgZiiGAlWhtRbLlYdhCTxEqMJShuWq5aiKLh+dEBdWKxJoD2TcU1ZTWnXjk8++JTXXr/DF995jY8/eUTTRMY7U1zfEFzEFiOcD4TkqaqKQo8pC8PB3j4n6zmPnp2gLBADlbIkn3j86XPqouD23RvUo4rDwxmjUUVdW0jSqt3b3wHgvS+9xtH1FWdnp1RFyXh8m7YtCUGhlGMyqSgrKfp735OUpnUN84XHaMWN6zdZzB3Hz8/pu8j8/FNGI4vWkeA0F+eBvu9Qque9t9/l5NmC1XKJ6xykiCnW3Lox4eHXf8STZ5bf++u/hrWWX/31L/P975f89P37gMs5VpoySUvZ9dCsFUUhXiLWBlHraJEaN+uCFBUXZ3PqesJr995ifjLDtTsE5/LItU1FyG3HJCGSctdmXlgSjtuAnmgVSVu8LJldPt8V9kq7fxtJeUXLJw+1P/f2i12gkNfuw6w5/GQwQdNbVtYpDiPKFXRieO/2YLNdtHym/bP1yytoxSald/tYPtu72/7cQVqszaUXylWi7JUjuaLQ2dSneUAV1WzY9MA3RNkshS3LkvF4TDWq6bsGbRTjUc1oNKZp22xTH7eOb6s1tn2+lchxC2svYXG0qEGyjbbSknwbe4HdxR9kCGPbanflb6ez5bdIkoWrEEMkxKutNa3ZoAYKjbEVOjoSktnS+UhVlATfUxSwO52IqZq5LCgGO3OVpCgYuBVGfO7FJC6xkT0X2uTiS1oTBmk1CclaZVWC3XwvY+W6pphQUYojlScqKVKkHWGSFI5JKRKGmPkNKRsbacT502iNuTZmOrIs172gHLVFGSWBdygKW1COLTEkvPfUZcF4VGcbPxlamt7TuUBKhqKssSoXjynSdR2VtdjSZu6MtNK8F8KstRbvPSiVw/akpTEoV5AaU85tHti887lFKOcpJvFlSdlWv3dBEJMghNbeQ99Huj7R9aJKiMkSkyK5QCAwLgpGhaGLgdIaxrXBWrmTgg+blosPQ0ZQvpdyG0epAu/D5sE2+tLhVhARQeyKoiCQU3oTG1fZspDgS2PlfhXF3bDQMPm8ZI5aDgOMMafNBvHEGeTzxmjGk5r9/R3WzYKu6cXjZdmj2sSzp+e4tkclI2imVnTO8fDBMe26wCrN2dkTdnb3M38BClvx4ukFo90Zk9kBro80rWe+eIzvYHnWoFC40HN+sWKyM+LZ8zP6rmc2G7OzN8L5NfuHM/b2dpnORkx3J7x///v4GIXuqaEsC1arhq73HO2NODzcpa6MhCs2oC1MqoK6Kjl7seT+p0947XXFe+++wcMnz2j6xHzVyip97VitT0lJzl8IgdVKMqGWa0cfcvFSyucXKWGT4frRDXYP9jg42hc0tLTs7U25dfsaSTV411DWJa+9dY2DG2OaZof5acf8okHZiEoF69Wavr8gpjWz3Slg6JqI0VOCazk98XTrU07O5ngXcD30rWF+1mYeT6J3YK2QpF8cP6Ntek5ePOfw4BrOJ8zIs1cdce3mjI/uf8Ld+1OuX79GURUcnyxZLiPaOKwNlIVmb2/Kum1wvaFrRJxQVYrCiqpGGU0KgdXSc3qyZDqqSLHnxrXb9AtNWNcy7uMBiS0QZb84LisSetArpcuF+MsCiBRjzvzKlvdcLUqGf8d8Pw8FzpUihcvFuqA5stRN6eXC5fO3X+gCJZs1k5KGqLLTpxQgemjUbBAJUJsTc5VVn09ffll2o1WXniWDmax6VXEiO8gnXeXPvex5vwpJ+UyrJ+X1ujKwyRpNG2haaXMJuG1CnjKfYWgrETcThQyMEFNAJ5k0yqpgPB4xHdf0jXAmRmNJG3ZuJaqbQdqcYfPBRXRo42gthU5VldhCCqkQZEUb1FBMGFACfWtARTmfISVi7usPhmbSlmBTJFgjMKa0lxJFURKSqIQKowm+hxBJWPo82Y1KiyViUmJaFRir8OuGg0nB0cgwoqfU4loRg/BblDHilqhlstUq2z6TxIbcXbqgaq1xrpeVdT6WFD1KZzKlAvL3suaSIJunpWymNLwuFx4JBn7U0NrbYGYaUhqKk4RVkXLHsje1nM8Vi2VDIqKVIaJp2paqLBjXFZpA08nv61paL/W4xumCJ8cXxKSYjqwkKytZRa3bDu8Vk6qEeKng6X1g3fVMjaU0GmsulT0pCd9YirdAGAY4EoQASMJqSAkTIxEl7acInkTTe9oe2hBZtZ5VF1h1icYpfJICzVpFhaLxQhRMGlGlKU+VFKNCXF3FpEq4KwoJElQ6QRRDMmM0PmVJewAzDMiJzYLAuf5KoOCw6tRaCrIQI1UpHitEj0qyCAqul/OVbcqV1RIzMMByURCaoBMuFKA0pQrMZiW7R7f47b/+Oxxcq1gtLwitou0ibRMIOvDg4eMc16BQMbG7d0SI1/j0p9/DpEBpSsnmUZ69wwnnzxv29qY07ZKP339Iu274whdusbtT8eDRMa5LolYpanwfiIjZWtFHpuOKcT1CWc2zpy/wLnAxXzHbnXLkDxhXFeOyoGsDtqqo6ylnL+aMtOb29X32dmccH89ZNhEXCharnlENSllMZdDJ8vjxM+bzBbfv3uX4eM6zthMzQ6NxGOpqTLMOrFaeYpr4yf3HLJs1RZGoa43BUtmK/Z1dbt48YP9wj52dQ/b2rzFfXPD86QP2dnd55+23Obq+S9QNZxdnnM7PWC0bYtTYuiTMl5ycHlPoGeNqF9IOz48vODl/Ql2PAEM9tqRoWXUr2i4Qo0GpgpSCtAfR6OzsHWMiarmvHzx9zLX9fUyVmOyUGKvpWKNM4PZrh/RhycPHZxwfe378o4c8eTwnhOynEwPeBfp+uXGgFdRS4brcEkYxnoyZ7Yzo+xeEaBmP91g3S16/t8PibE27cHLPaFHtDAt4oyyBnuzsIAsHJUGnV4oLAoMrgBkW9nIry3x0pUCJV4oNQU0u17RXZr6UhjbHxnbh59l+oQuUTfW35YJ3yWe45JJsCBV/CWhpeHHKk/NlcbLd/rlKflVqOID8+T+jLXQV9RkAmEu0IHGJHlzp5WUYTqLaubKPQfJKXjkPq1tpMWjqumQ6m9C3Y3wMlFVFjIl1TiHebhwptfXddWai1zWj0UiIhiptWkJKZxtzpYlKoVTMtvKSUeP6IAQ1bfJKV0irMSDOnsjN3QePBO5l+RtBCLSIvbpOQ3tFY40SvosfHFMDbd+ge9gxkbuHYw5GikkhZNpNYyRJm0UpQSDKwm6uqR5Ir0qjs/vrUDzpLMccHkiR8sp5ukSr9ObfKmWlTS7cYpTAuZTSBmGJMbd1FCijrjz8irQJKCyMuKpaM2I6qli1gd4HnOvpekfb9WKR3fd0bS/tLx/RqhfvE5Xou5aqHlMXhuhabGEJCZS2lFWJKUpUdFJgaiUOuTlZVhmFtproIy7b/5vMMUkxSFvIe5JPFLZAG0VMmhhDbmMEUCIDdyngo6LtPY2D1kVaF2l6T0DM1LRNBBcJSQob55MUHUZahZYklvwpbkjJw7kfkJOEJMB6n9OTjSUpCYqMIeCc2xCgS1tk4nnCx4Drevquo66lnWO0piwLfJDVIhmhLctic71CLsxkGZFdomGD0iktLc6yKPmH/5v/Ne995avcfv0e3/3Bv+TR4494cv6Etmklcyconj8/ZzYaQxRU0OiaxWJN3wY0AV0WKGuEDE2Fj+AC3Ln5Gk+Pn/Li2QsO90bcfu02rn1Btxb7ADuZ0AWfxxlpzY1HBbu7O6yWLYtlRwo9d+7cwhSKzomQfTqZomipyhG9C6TomUxqxuMJ5/M1T5+fsW4KvJ+gtMPNPd6v8mIkoZLm9GLFqvuY1+69zp0713l2fExRGWxVoZOStpOBoBOPnj3h1q193n77HY4O9umajm7dsbs749qN60xnOyhtGI2nWF3x+OED+s5zeHCNop5wNn9E0z2nWXc8e3qKtSNCaDg56Tg9XZLCnBs3ErPpPvvhOsenz2jbjvG4xPViibC7OyElTd9J3X1pYkku0iUkT4lNM4uVoyyXvPvmO7jegYLJpEIrqCrD0eEh8wvHB8/uc/JiTQwGoy2kuLkXo89C3CRoXMjRAAO/T+sRxnjaPvLkyRqrFjx8dJ9bN++wd63g9HSFX5gMpovRpZDzh/lpixuS64+orkqFBQXNTrbxcoL5LNfkaoEi/72ZNDd/Xy7I/xVT8cRhkiZt/qSBL5EvxqZG2JyYSx4IXD3pn/FA2Sp6NkXJwPzYeu02p0TeJx84TFqfh6IMTaFXb5cwmYpxYwYWU+7rDwZnW0XS5vspLguUDDfLIGuYTUe4bkrX90KS1Ir1ek3f95tzpNSAP0lbzFhDXY+YTWcUZSmukNmJM0Yj3itG4Eg9FGoobFFKt3Noqylyi+CytTJcsxguq3VQJKVRBAorR+I6L6vRKNfdFBoVnHAnCosqJIW48I5b10u+cH3C9allrKXgEc8V8fLo2xZrKhkUSkuKZFMuCXFLuXDYLhiGllaM/rII2bquQ2tuY5U+mH8pvXngh6tUFAXB5xRYJajRNkFTnvHcolAqu3qKysckR11VrBrH8dmZeJr4wOnFkqoeEXUBpsQnReh6lNZU1vDG3ZtYYymNIrYtHlitW7o+UBYVnY+U1uCVRmePlBB6eh8oq5LQO1rXQ0yMxyXojGzEkNVfGqUMRmn6XlpAPgouhRb/ltZH0AYXAk3n6IKmd+C8tHpCDukLSdCxPiRC0mhdEGOPiy2jyqBsyaguCNFlcqHJYY4pn3sxoxvUObawNK0Y8YXgscZuFGvbUsoQhPcUgs/XVyS5IUh7K6aUSdoK7/tLLpvKSrQ4DNzSQiTfE9YoYk7PjSnx67/2Nb74y1/DEbh3Z8H52Zz16mMSsL+/w4uzhr5NrHxGNRXMZhOUKanqihh6khYC4+JsQVkndKU5mS95e2fK7/61X+fr3/4G77//gMUiEmNBs1gI/2CYWAgYnZiMR0ynNfOLMxbrFmstb37hDl/96rt86zvfY3d8jf39mkcPzqiqEd3ac9qcUtrIdGcX5xX3Hz5BzAungkTGHtetWSyWGJPY3dtlNpuhjOHpkye0H37Ivdfv8dr0FvPlnL7PmUzKU08qTKnp+8D1w2u8/fqbzGa1oN8JljlTZjweU5Q1Ccv+3pj33v1SduPVWFVxerYm5Lbh2VnDZFShtOXFswvWK09KgafPnqBuGWY7U0JouVg8J8UWY+Ho6Ih6VLJaOU76ZnNfpaQJMW6UW6pQGS+VOIaz84Ynz1+wvzfh/OyUsimoqzEpWk5erDl+sWSx6Ak+ZfmtpMxL9EPC5MBTYy0xSZEtrS+JJVivGuGGFQZrRzx49Iznz5b803/+B7z99hsEU1BN9+h9QoW49UwAxA2VQX5+SSd4mT+ymaNemie3/71doAzvG8bnbRHH5fsYavife/uFLlA23zTlAmUgkcKGDsL2CX4Jbfi8FszP/ekvFTdD60VtFTCfaedsbxnuuUrk3dr/FZAlbf6SAeYqwVdqorT5eUqDNj0IyTN6UnSZcGWIWSoYU6Jt27zSzHtM+dhQV3xUxuPxFZRgO+BQaXK1LlV3TAldlChbgOuvnLOXq/UwKGOUSJCjEjhfKbEojz7mBNjhvCH9+RixRuPzCq1KcK3W/Nrbh7y2p6mNFDUaWUUkH4Som+XD1hgJzsvf23tRoEQvvilaD7bl27yebSRLvsPG4l1d/Z3AmlqkflnxM7iPJr01UKThPpGCcLimOreGtM6urEZBZeh9wEwKjNnjYtmwanuarifpghAiy8ahgVIHikLQs0kpqFOhFaao8WhcSLh+jfeOpoVU2axK8YQQ6X2giom2d9n7w6IMoAQxcX2X0TmL85BiwiZNQuNjlBC43M7z2UyKwtD5hIuaLihp93hwUbCHmCLOB3yUtmZMUviSV65FqXEu4UPOUrIipYxccmKUUhS2xOUiQvJ8pGUY8yp4441izMbccEBimqaRIsf7zJ0RmbseZNRaYHG5HwZZupZ8Hi/X2hpJUTamJCYPyYMyhBj46fsf8O6Xv4a2JUdHd9nf/YSTY1HXvfH6m6z6JyyX4r9CjBRG5ODVeMTOwZiT5w10jqQTPkDyjkCg7wNtd854eouvfe3X+LM/+RaP7j9nNtsjdJG6LHnnnXc4P5/z/kcfsTsb8dq9m7TrFRen5+wcHlDEyBtv32Znr+ILX3iH64fv8f3vvS+oY4pCbLWKndmI2e6E0/Mlz4+XKAPVqIBkICrWbZ85ZOIWu1g1tH2ga3sKm+jDp9y9d5Nrh9d4+vQZXRvFxyMlzk7nxNTxL7/+HZ48fcybb91kd6dif2+X2XSP/cMpqIBWlhgLYnTMZjuE2IH2dF3Per3g/GLOixcLLs4bCr1L2zas131OtxZX3kePnzKbjNnfG+N8hbWRvf0xb711k5gCjx6fSV5XdvoWnlcghJxynmRMSFHEAt5FHj56hnNTvvTlN7l9+xrzsyVnJ4GHn6zAjyhNgbKOqEJupUvMwWg0ATRFWTKd7lLXNev1kufPn+ViO881ufXovaL3gbqe8vjROW3zMcZorh/dZTK7wcXJIJ/PzuSbySQv5jfTZ9o8A8MC63Jx/tmF/OWcdjUscECnxYjxs9Lk7Xnt591+oQsUaXMM7IGhhybKm02LZnjxlYvzlyxKEnm/l+bzUvtcXrxLaJ6szPjZ27aiZ/j789AW+YyrVe6AHF2iZ3KTbcvBNqulCIPzKMmL2iaTRtuuZbVa5XbNVjtCicSyrmtmsxmz2YyyLIkx4pzbDPCDCdrmqHOR2HeOyhSMZzMu2vUGYRr2/bKpj8oFESqTq3LacN9H0gZdEQKuylQvpcDWJTEEUteyP0r86hs7fPlmzUEVRDlkLSqmbOke8LkogoE4llfPcWC9XxYOA4ox+HgMk9+21fvL98Cr5OQy0ZAnWpnUYgpopNgb+sQpXrYJtYIUPBiTZc1yzkpJCUAHjx0VFNYw6QNrlzg5m3OxXNP1JSHU7IwsKPFz6ftGjtsYdGEotWJvXFIaxXLd4UKPDyojMi63oMCHyLppKctSMlQyyTWEBEr8U4qiwgWHD4HeC/cjEdHGEJKm6RwRjUfTdY5152l9ovPgksmFjMWHHG2gcvZRVGInPNzTMUnqdXYjttbig9v0vdtWEACMptDC6fIu5kJaia16CIzq0eYaOuew2WBuo6hTiqIoSCj6vmcgtMf8XEuAoEFrKXRjTJt2z+BSnaIkhCtlhTyuJXdIW8Of/cs/5Wt/7W9y/eYdDvYO+dIXf4XrR/8jjz66T11X3L5zyP37j8Anklc455mfLShnJQfXZoLwtBHXBaJWYC3joiR0S87nC376wYfcunOT9774Dn/+Z9/l7PQUqwzJRubzc07PL4ghUhYWqy3nJ3OIirowFKbg4vyEnd2atnV0TeTs5AKrLb4LWKWoCsNsNsGHxKPHz1m3HnRkvnqGNZK8HV1HWRimU/FLmS/P6ByEpElesVx5Pv7kMeO6wpqK+bzD9Zre92irUbpgSeDTJ6e0qePLX75HGYx87+eJdm24cU0JCmw0xJK+7Tk+eczjZ/d59OwxJycrnj9d0LfQd4n5eSsJzlqRlHDjBAmbcnGxpLAjjg4mvP7GETdv7HCxOKcuc0J4SngnXKYYVR4rJcYierkWRhtShFXvOT1bc/vOHb7wznVWiyUnzyMff3RC11SysKIjFZLBpFLi4NoR664ReXGhca5hvZ6zWC6JyYsLdxRjvRRbyqLm5GSBtZHp5ICT456Lc7C2Az7l3TePUDqiM6dRYls0Kit4oqyKLseuGIlbY9nL89NmHLvy90CQvRzvRKUYNy3TK2PhEBvzl4BQfqELFGB7Zrw6ub800b+MLL18sjeIir6q01Y/g7vyeRfyLzzk4T2bz7+UHF9C/Jk2k9s1Wj5ws2qLLzOhlc5wsB6Ama3jzATGzKGIIWCKikSiaRrWbZMdT8mTpLy5LApmsym7uzvUdQ1ACINtuXxOUUypqprFYr7p60cvxNl127K3v08zP6dfO+nX5gJjG8HaDOp5ZdsHMbtKSOFgs4eIzqZbCoX3yOCMxsaOd6/X/OZbu3zpuuKwFhMqnQKFNSQfaXOOTMqeJUMLZ7geRhtysCpsKapSugzEG6B8Y4aJ6bI9MAToKSX+IdISAnJ+kjHFlWts1GWy9cBTAXG41ZntrEz23I1h08CEhNVZzqwVs0qQkbIAq2akBKfnS4J31NUBJeIrYsi8Hi03VWmgmlbMxvKnD9B6z2K5woeAQjwxyF4eznlBSMrBQVURA3jniVHg7ZSg63qiNTgfKMoKH2I2/vLooqQPsO68BP8lS+sSrYt0PrJ2MkjGkPC9RytLUajMGSpAGdounwUt+USktLGuN9YI0hYDMbu7FtZetjthYybnvZciZGulJz4QgdFolE2HL3+OTplgLQRZmwnWMT83Q9u1KIqNPb7W4i+jVT4/WjHZmfLk2SO+860/4W/9nf8F2tTcvHGPmzfvcnh4xF//vb/D2fqCDz/8iCefPuHhhx8ym814660vcuu1Oxwd3eWDH7/P0/sPOTg64s7rX2Y8m/HjH32LD3/8EU+fvcC+mFONKhIwnlmW5z3eRUKwPHn6lIvFSopLZXj6+Cld2zGbFkxrOJ6v+ej9M8aTHZ49O2f+4oecPH+CTonkvSjjjPi+FMUIbQokGkCJl05oMEpjVeLwcJ/RyFLWBW3f4uYrWT2nkqZx4vC6aHEuZblxpoL6iLGKUlWELuK6iFYlZTnF+5I//fOf8v1vf8B4NOatt9/gzbfeI0VN265w6Yyz5WPOLi44PQlcnHuiL3C9YbUYkqoDWsuYqI2iqiom9SHrxYrlReD8bMnh9YLptGIyKbHFCq3zvRAyokcuUqIhOblHo5LCOSVNt04QDKN6RmUrjg5GHB83/PEf/BjXReqqEAt9najLCavVknW/IoTIqllsJvqisBzsT/E5aNH5nqq0GFXw7PGCyVSDX0NQeK823LayFF6e0hZFti9IG+trMu0Vjc4BrhGvpDWptsY1dXUi2UwsKiO+LyMol38CgzT58vdceRZ/nu0XukAR0/OB2PnZdsrncz+uoihXL0b6nJ+/evu8kz1cqE3R8apj23BXLv97u7K4CrNdchOGOHsS2UdEjluKm7R5/ZCnE4h0XUuXWzkxRUZViTGGpm3o+n6zEiSlnM2hqeuK2WzKdDrd2ISDI8ZLw6uyrKgqcN5xMZ/j+h7npIjq+sR0XDOZTfHtEgZmSxr6onojuxRDrpi/73AjI+F+WgkpNgS0kl60ybbmul/z2q7mt97e5Su3Sg7KQKETRVkR+kZUPynhg5AdjRFUYbBtF2M2WSFpJRyUofWkt4qp4fUCtV69dzZ93twe06icWzP8HIgxFx9DB03QEptN72SSY3NsMUnS6hCcN4QQpigroLIwgoRhKLKD6rQ0HO3voG1J2yxpWkdpNCpFRlbTdQ0xWFQqSaGhLCyFLRmXhrEu6JLcZW3nWC5XhKBRqiaERN91FKVwipp1Swq5vRYCaAn5E7l4IkSRXYbk8ChQhqjEeK31ic5FOp/oYyApkUwTNSiP8+IqXNiCqHNeCZCUoXcKn8gKBUGZBo8aaw0qanGp7eOmSJAHCewG6pafSXtPZPkDkTbGgCJRlmPWTYtzjr53IivO7scqKUGIXiJLy/0s+xrubUzONAkRa0pSEnO8an+fP/qj/4nf/mt/g+mu2K3HBPtH+/z6r/8es/0jmqbnf/xn/4z/7NE/oqoKfvkrv8K7X/6r1OU3+eE3f8z+0TX+D//n/yu37rzH+flTVssXuK7nxckZrossFw2mgJ29Ce0q0PWS6n2xWND3gXFV0TaeQiWODncZVS2lXXL9YMTHj5d89P4joOD+kx/Qt57CaJJNXDuccnR0wMWqpWkiKIPK9gAqiveHTqIodM5TlhZrKsajGetG2jg+G4YlFTFlgQuOPudGWWtIsQcfKIqaW3v7HO5MsH7M+rTgu9/5CT/+8cekoLh54zX29u6xWmixyQ8RFwOLhePstOX8zNO1jvFognfivipZVSKlV9pQ2JIUFFaNmE5HtM05j+6/YGff8aWvfoHz8zWj8Zyi1OhWgxOWoyysFCnqzO2J8hRmpLddB773nZ/yxffepqpnWKv5jd/4JS5OGr777Y9xLmDKAm0iq/USF72M2Rm5lXaOZ7oz4tr1GfVoH61hvWxZLBouzlqCs3QtHPdz+uwyXU/gnbfe5Ohoxosnz+laP5AOtuaWwQNsoAOkzXM2oMvbnMorKMrAv5Oj/UwbZ9Mu2u4q5HlNnHVhe479i7Zf6AJlmx28gZpe+u7bJ3rrp1d+f+XvV+3/50BHLo9lMFv7bNH0eQWPUoMw+fLfn/s5299zCz0azsGV10ZyGJ5jvW5Yty3OeyLiBmqspe07+q7NRc+gDFIU1jKdSnFSVdWmdhpgPZUH9tVqtUkY1lrjgqfvZUU1ZJTs7u3SXpzmwVtmYrkuOntxkAuj3OYg26inKASxCFqXm4cies/IwszC60cjvvbuPu8eKm6ModJGEnWtIvbktFbxyTCVoSgsA7nLWE3XtChrIQ1F0nZ2ihQ1220p+Z7if+Fcn3vRmWfCgO9cvb+stRtJYoqJLAfa8EuGV+vsOTA84PIb8ekgSqjhxvdHbi4Sgo5UVibsUkd2pzU6Obz3dJ1BRxgXlqqspAWiDT4FQtdTJTC2wIWWFKAuLVVRYBT0Wc0SoqQPRzQ+SPuuLEuSKSAqfISIIUW1MWhTuqD3gaStcJGiwnWephP/k5jBZpeJdS7fGyFmLpDO5n8KmcCjGLgZK47BWicqK/41TdNyGb+1tULLhW6RlTspCRI5kGFjjLK/oqDrXZaQpo0nkDaGyUSQr7brcnyEFKEDEhdzVTk4EA/XL3gvCgijKazJbWLFYrHGzvb46U9+wvs//SG//Ff3IGnapkNry2i8S1XtU5aKejTbOAZbPULHigcfP0Ar+J2/8W9w+95XGNc79M2CyXhK0uJe3LWeZuXRZWLV9KybjnG9S1FWLJolCUm8bdY9sTRMZzWHe4l6tMbFCqsipycXBK/omo7KlOxMxlSHO2JJ0NV0bWK+mpOUQWkIPgCBsrSyEFCKrvesVxdCCk0KqyuUikQaCUasRgTv0RaiC7lgF4+lcWW4c32ft956k3oyoWLKt//lD/nwo48pSrjzxj3u3L3H2fmCpj2mb1t8aKkn4nx7ftaymLf4ELBG4foGpT1GRUpr0cqyt3fEdLILsSBGS0qB8XiXplmhtWZ3d8rNW0c8enLOYtHTtUlMLof2zgaMEERR0G5BVpyH73zrAw6P/pDf/Ru/we5sF2s001lFSi1VOSaiWC3PScplfpNB6URhLTF5lDHszKbcvHmNW7eusb+/z6OHL/jjP/o2Z6cinQ5B1I0KqEeJN9444vr1XebLZ+wfVjSrsJmTlMrL+bQ1QqUtMmu6JMhuCz9e2c4mL5lfauPE7HeVtn43UC+GGexfuQIlbX/noWpD/czC4nO5HnyWoRKHivFz+SHbSEfi88IKtzkKn9mXulRxvIyiXEF28k00MKWvFFSv+LwYEr3ztF1P710mL0FZScumzUXLMGnL97RUldjjj0ZjmWCTwJcxasDmh1TRNI2sUAsjclVjMCbivRAjl+sVN3YnjOqS9ToSsgEaGcmKWze3GHoJKVCp3LUC6fX7kF1vAiVwZ7/m19/c4+6e4fV9y2EdqIy0PoiK6BIxBAI6S6prikKIj4N5m9GaXkHwTgjDcTjfw2pAjms7JE8pnWXNbHxUYpBj3r4SG9Ir2XwvT54xZhl1IgcfXm7SEhCp6zBQaCPqHVFtZaM5nREWY9HkUMXe47z4wdSmwJWW1WrFOkWqYiwtELQEAHJpKGciqCDIQfQOowzKWA53prRtz6p39F0vvJMkELcpK5S1rJpuQ2IdJhdjSolNCEFgfx1wKdH20sZJymSkUO75EAMhxZy0rEUGLAxiYoSmcyyWHmtLVFFRjQpqo3BdJ4Z55MI5xs2zO6wCU26XOuc251lpae8Nz4tSalMQorWEK2pNZQuxtk+XBNrRZIJCYhb6vgfE7E2eD7luKYmSJCEGbykMvCaHsRVHRzco6gnJJ/7FP/8n3HvjbSaTg5wxVUmLNsNskZ5Elwt5+Pof/yHPnzzgf/e//z/x1nu/hrU7BN/x4vQpL06eoI1nb++As+cXzM8bRjtj1mtwXhMKxdnFgrb3lFahVJBgTKWIsePwsOb6tRHV6IC1N7z/6RldJ4uWnemEuzePuHZtD+8DT58v6LqGFDVGi3ldjGIKlkiUVYnrelZNi+slZwklBoVlbSiKxO7ulMV8JR5DJskkHxIxeIoi8c6bdzg6HHP77i0eP17y9a9/E117fvv3foXp7pjnz8748OMfsF41uOjpW0Fr6nVF1weaFXgn7WFrLM57xpMSSOzv7lGXe1g1hWRQWgwB5cQr9vducOfOPsYqRuOC3b0xFxct61UQD5mBP6fYzDcMnlwECclMiaYJ/NnXv8PF+oRfeu9X+Pin93nw6VPu3bvOs6dzmnVOKjZhk0SOyipFW1DpkrZ1nJ4sOT9d0LYtT54cc/xiTcKCErKutKoSo4nljTdvcHz6DKPg+vUvcPpiQds4UhrGeHlgpE21XThsf5erc8ir/j2Mc9sFSkpJJMtcFjGv2v6VafEAMrHDlRM9DFoqbYMMeVLcXJzP3d1LBcfnb6860ZcFxlXk5pVIyvC7obuzve+t7/LyZ26jNS+//uXXhih+Gc51mV0tg2pd1SQS67YRZCPfuIqhvVNT1zVFYTOMLfsUcqyscvvesV6vIcJkNhZH07Ikekg5IXXwGrl2MOVp37L2Ynk+oBFDmyuGLYVLEJi4sGxMwIy2qOipVOJwV/Pu7Sm/dLvmoPTs1zAqDDEFjImo6PFrMcxyKSB2/7LqCVEe1IqC4ISH0HXd5pqllL1XkqLUxZXrtq1a2v6Zd6KiGGSnxhjEyF2ujBBhL9+3mfT0oP4Z+A4C7263kTYcJRAFUrwsZPWAxBiNNgkdwWghuUp6dKSuKgoruRwSIeCkcEgaUS8H4ZZYIwqqFDA2oY2k1dqqQplmcx6WqxXWFhhT0DYtRVVJYeU92op6JnQ9XR+yXbamC4HOedadz+GAni4kXDaki0Faoeu2p/cSlpZUIjfx6Bx4IMYW5RtsYWTFXY0yJ0RvVAiokJVhuR1nLTGKwdZkPJF7ODv6xlxkl1WF814CD7WYv6UkGUXifSLScEKkd70gPNZSFKJ6cs5t7o2BizIQaxNGxh0thdC7732Zf/3v/wP+x3/xL/izr/8+//j/85/yu3/9b3J8/BTXNjgnoW4pemLsSQga893vfoPT4zP+7t/9d3j9vb9KVJYUI4vlMb//R/89j59+hDaBnd0pL56cs145lu2cVdMRghaDvyio4WSkKUyg61d0fUE93mdvf4/pyHP73h3M6DpPjv+A9bpnf3fKe194g72dMWVlePDwCcvVmjDcdykiIS/C0em7gKInRi+eMjGgDBRWM9upGc9qml5R14bTk5YQIrbIJo0xUVjDjaMdqlJxdHuP3cMj/rt/9g0eP3vAL//qaxzeHDMajen6FlNITIMuFC+ez1ktxUdmuWxpG49KBZPxDKIgWHVZcPPmDb72m1/jwScnPHu4yNL2wfXYyiLAKvb3r2XULTCdVozHlqqy9IUTHl4a2iYRsSwRTp7Rl62MmDTLeeKDnzzn/R/+D1ilmYwrEg226rE+Ml832LpEJ40PfUayxXOliZGL8yVPHh8LAhvIhoLi3aQ3btKeokygLSF5UnLMdkeMppGdXcvFecPGsFTJvKEyL2oDxspg85n54/O3lHkoV8UBKbEx5NyelPL67C+Bncj2i12g6FyaqKHtkA2dsp+SWJrndLWkN7DT9iY3GRu32GEFfWVTl68ThOSznJLN/gbL+yRw10aGu8VVkAupUNk9VmMy7DY40WYX1zT0Awfmguz/la0sQKFlVQT4mPC9I4SOrlsSfEPynuAT1pRUZU2M0DYdyQvDUbLtFNrkQLCyzAO2fILOHI6YAgmBvVfLhsoaVBxLMrGPOMgkN0NZGGbjkjfsmLTSPHCBoEoxJMowibQ5BFFR2lIZjUqOolDEqFm3AasCeyN489qYd29U3NtV3BhHxlYmWlJA5TybypYEJatcqyxKCcpAipvMH+cuc4d0UdA6R2ErsVgnZRXIUAjoDbdA7o9BSSI3iqT76o1ET9p0ue8qnVq0Fstp2Udmv0e5h6VwCYQoK01jBvdHuTFT8Btinqz48zXPhGffCzKVUlaiFIpmvsL7RFmUGCUDWYji9Btcj1UGHyMqidun2OCLxb/OkzxEbFLs1hZLSUgKRc3FopHCVGmKIK0ljRSRPnSSpRNyQRgSjYt0HjqXWLWeJhNmY1K4pGi6SO8jLihCFCM7vBRpGoUuNdFo2t6jIoyLgmQUy66lsBZjC8kfMWbzfGzL/rXVlLYQjhGBxrWkoLEYXHSEtSPGkF1jhyDBQGFLlI445wV5jCJ/ryuZIKzWdK6nyBb/vXcUxhBj2shQI/m5QmHLklt3X+POm1/mf/kP36LrOv75P/ln/Okf/xnn5yccHR4QYo84E0fOT+cEp3B9z+nxE/7Wv/nvcu8LX0XpiszZZDre53DvOmVZE2NHSh0hRJwDh8P1AZIhEil04HCS+L3ffoO2D/zZ1z/B94Z1k1g2ltg3nJ/+iJv3vsjR7IDFaeDdN67x5r09jB3xyaNn3H/2AnTJeM9w48Y1PvroAfG0BSVZTtZYacmayO6uxaia9arFWphdG6FtokhjgmspJ8JJefO1Ozx7NGd+vmZ/p+Sdt29ycDTm8NoR3/7Ot3j+/AnjkWU6KWjXSy4uVnz88VNGowlFBbs7U6aTPX7w3Q/p1j3tao1Kmv3da+zt7JPQ6KmGFIi94V/+8Y9IQbKTxqOaVeMFPc160M41fP8HH2GKFfuHY/Z3a+a7E9YXEZ+dgvtexsyYEklBVYkUHDzeRbqmoyhgXNZ0y0RVV3TRszw75Xy1RFOx7nLcBgFy4jva0LRSBMtiwZKiEvVRMrIYz8VGRKOMR9mEKcQvJfrIuNLs7VbcuFnRry0PH5zKwltFohIDthQNUljGywkuLxjyILUZy1Ked9SV9szg65QJ85tFf0INyfQkUANivj1Tbce5/OztF7pAGXgBMmG/xM3YVIqDXXuWIG+3gjKpNCU2D7zKWMx2K+Zntma2NlE9XyZAXkFErhQnaesGyJOgUsMi/koxs/VtP6enl1Ef2XtejYtKYb44Z7E4I8UWrRyDgqesRmJe5TxN0+ZU4Tyxao2xYmlvrb1MhN36MKUUzvc0TUPvHEX2a09JzoHWmqrQ4kGiRdGxvzvj1t6E+bJl4RPJWLnhY6QylpjIqzJF752QxLyk1FbKc2MCX3lzh3eujzisE3VylFqul0YRXMAWBpJG5/0lpfAhMqrLrERxaATy9TFhlMD1RWmJ8bIVUNoKawfuR9p4xBRFgfcuh9LJZDgod4ZNQKHLaxujkOeERa+umHtdtn2uDgZD60dtzumWYislUjaYGFpOiZALC+HSiDmc2brPLlf5oDKikrCFxViZUIYCZ7gfUYroPSDXcVJXRGVQ2hOTxjkpUKSQjmAUgUh0ic4Jb8j3Hh8TrU/4qKQIyX4qSSlxwfXgQ8J5mcoT0hpUSBSBKSxJiyW+5PKknIIryoTaFigFRSkeMHIN9AY9ssYSQw49dA5bWnwY/GU0wSuCcyglRX1MiCQ3RVIv7xPTOEdQiApKiUsukY0E3HsHMaCtQWVOki0KiXjohcxcVjV3X3+DZArqSclv/Obv8Pu//z/z8cefolRkPKr48IMfsru7jzUVO5MxJCl0fuNrv827X/oKyhabcMqEpirG/LXf/ts8fPgh3/vBN2ibRowUo4KosGhiElJxWXjefnOXd96YkLTm009rHj5xnM9XnJxOiXVPszjl/oMV85MFX3n3bd558zZVVfLp/cf88Ic/gcJQ1yWHh4d439OsL6jKyOHRLsF3rJcOFxJlBa+9dsi16zd59vSER48f07hTdBJ1oC4TRzdLyqrmy196k/X8JywvFijds78/Zn9/n48+fszXv/FdlE7cuHWbEEu0HqNVoGkcT5/ex1jYme1gTM1qGVheOFSquHZwwNHhbYpC3LIF2XKQpHUYUyS4gI8dXnwGQQXQLbbq6HpHSc/p8ZLX33iDe6/d4OR4SdUk6nFNs4os5g2FUUz3ZozqCVqB6xt6eupqAspRVJHpdEzTO0LfgU5iNx8infOCGivDqB6zXrcoEymLgeOnSEHlGLk8/ue0conDsER6rIWilOP3sefm9QMODvY43LtGvK0py2PaxsGA6qrLIudymlFXugdX5rWUhjLm8ji2TDWHmU7eOqz0ZdGfrkAp6pVtpJ+1/UIXKD8Tgto6WUPtp16+CD/HyfoLi5JtzgtXCZKfec3Q2hnaQEomWJWLks+GBQ6xHrnqUoNh2MsIyrBfclsw4H3Pxfyc4+dPKcvIZFLKw5kCdV1SFAUX6/XVkEB1qVgZkJOhbzkURUPbqOu6nIDsiRRSW0dhn1e2oLA5rwLFsnGEnYLXru/SNms+eLpGGUkxVSmQfMwtDJnwojFoC0TPpFRc26346usz3r5eMTUdtTHoZAjOiQW5j5I0HEHbgrYXXkhKkpYskP+lompDdjUGgxQSQ85GYe2lwoNLlvvVonEwbhrQErJsWYIDB9hz0w5Kl/u4yo5n43a6fZ8MKzOlxI8jRjYcmLDlyKuNQQWBxUNWz6QUUaagKkuawm3CfgbfgxQDo2qCUsI5kgJLbxQqKffiQ4z0vby/KMqNoR5Z9r2/NxWjN+c2lt+iBhNXWJ/AxYiL4CP0XhKM0WLyFrqIsSUmRVQI5KWhnJs86QdtaBsxiVu3OYyShPXSchyNiox8SMuyaTucd+JDlFsspITrAyoJuhg8WLRY929GBUHxUCp/J8leMtqIjJoBoRUUtg8+pz3L6Q3Bi4OpNRhjaHtHUZWYoiC0XW7JaWZ7+9y6+1qeJBLvvPtF3nj7XT559AQIPH78hP/4P/xHtKuW3/zV38S3Kwprhc+jCpQuiSGrkVREZJ6Kmzdf49/5B/+Qpm0J/Y95/mSBcwmVDIqAUWB04ua1kq/9xltcOyzY2d/li+8uefT0Q87mKxYLx35ZgBrTNIHr+3vcu3XI/v41Tk7P+eSTR6yXC3YPp4xqzYOHH7BcNtgS3nxrl1/6pTfY293je99+n/XKM5nVlGPNo8cfcT5v8LpDI62W3vcUtqAaWZLq+MlPv8Pp2RxjNUUhBPQXLy74+jd+RNsH3n73K7z51tt8fP+HdOEF916/zdtfeIPnz455+OgJD++fCEk4WspyxOHBdQ4PbuT1foO2PYW1dE2k6xIxireMUgbvRcUXU4/SHeXIMduDu68dcfvWITH2OOdwtaesIMQGjWdv/wCFIvPraZqVoB6+JxGZzWr2DyfMdiqKsuL+wycoHSmKkrqsaZZi3jcZ72Cs4eT4AqMKTGkoTEXwEo0QgiDLSZFX0WJmd3BwDaULnp8+lPGgUNgSmm7NbPcWh4dH1PWYepRJ+slxhcA/JHt/hi5wlfS6aUvnPwwk2iskhMvXb1svkIZuw9YnXH35X7j9QhcoL2+XxYG6RK02aIPanJyhCtx645ULd2WfP6M4GeS8sq+r3ISX33ZVI375GSnLTYeJdJunMBQcmWt5dX8vtatU5m6kDTI0yJEvV9/DJFfVNVobur7fWH5fFjnbfixp4wh4KR2T/fSdvDcR0VbCB0N2TC2MTAw+iANn5y1ttNyoLe/cmNK0HY+Xnj4mWRWn3DhLCYsj9R6dEkdTzds3Kt65PuX2VHFYBiqVKAyAQeuE0Zq2WWOVyHtLK49SyF4sVVXQdI3IfLcuiljbW5mUcjhgYQtxA40R7xxVWaBQBC8radeLGZm1hpT85jyJWd3gh3HJRblcO6QrxefAQdkuerbvnQ1Bdssgbti0zmnL+fukJI64hYXQyUTpYsTHyGg8oqorrEkYXVEUBavFkj5njaASfecoilIKrtw+cr3DaiMuBpmQTbwcaLRR4CNKJYrSknwUB8kIfU6hjkrThUTnAi4qIcn2AY9GGwnOi8rgvKy4lZLYA600QYFLiabrWDUOW1TUdWK+FIKnzom6RmuCdzjXk/Jxay3Flc75SeS2X995VJmorcW3Dhd6TF2jdUFKYHWi1AlbSvaPTxEXHT5qkhLTQjGnkwKudR4NVGUpsmdEyTJI11GWrm2k6NeSXH3rzl129w8YyO3j2R6//rXf4uvf+nPm52cc7N/g9dfu8R//h/+I/+mf/zNePH9OVVRYW2KLClIBw2Igw+foiEqau7e/wP/23/s/8l/+4/8XL56vWS1PISmMMqAj9SjxpV+6x2zXIAZ7JXfv3KUo7+Nc4vh4xUE9oSpnVHXL0dFNDvf38T7x/R9+yOnpEqMVBs/B7pSuXzGaJmbTir3piFvXa9r1gts3RhhdEJLi4bMXLBYNnoQpREptUHLMOmXOmCRnG2uIDqqyIMTA0+cnOO+5c+91vvCFr1BVO+ztzvn44Xe5mC8oy4qYNDuTfdzqnKosuXH9LoXZQZFRk9Sws6c4uDZFa8WLJ4knj89Zt57lssP1gdlsh1FdUZSOo6OCnX1LUcsC7+T4gp3ZDKNLjOn5whfe5dbt1zk7W3B22kIwnJ2f5CR3TQrSAtfao7TnC+/dZdUsePjoBb2T9m2MZEl1oKoMZaFYLNdCXldgjMUWFVVpads1iSAu3ci+q6JkZ7bD0eEtlsuW45OnsshCCMbz+YJHj54QXMfbr9dophQ2EdNgaBhIhDzmpjwmXo49r1LsXM45l9vlYjh99nVbRY9GfXZf/6oUKLKK3YK/hxpDXbZOfib6sXnb9uvU1n6uXrhXOb3KdfpsT23TVvocyOyyuMgXODN6td5eZQ+s61xAbUFmwzEPbQA2N4rcFmVZcnBwQGEghAZSTx8cCp1TgiNN22QFT9pUVMPxiuV5RGd/lJjSJvHVe0/vLlsdZVlmYujlWUmZmJiUofeRhYObdcG13Zov3t0jPVrQ+8DKyYq7KMTcyXjHtIQ7RxXv3Zvy2kHFYa2pUk9dFFR2hApD1L2s2hNkS3LoenG59SFm0udwvoRgVpQlKUm/tmkkY0MMuwLaarwPKGRSM9aiEsJlsYUMFEHci1Mkc0vkAfdRQt36vqfUg0z5UrK3XZyklC5N2thCZnJWypCkffn6jGxwidiknNA7+OiIx4smeY8Pib7v0aZgvV6TCtiZihrLGEnntRiUMmgdMz8l5hZWFMWPETfPGJ2EpJGI2tA7R9dLWGFR1vjghQAaFEkbkoKm6wjK0IdI0ydcSIQk6iBFToBNChekHx4Z7q+wuU49YhxnS4la8EmUYkYpqrJkVJUE32N0IdyVrfRpvM/xDlHOiUmSPJ+d+GKSojpEURpJsGXLwUhzMBZkpA2RxkXmbaDpI50PMsBrK8TeKKiP8z63eSSrJcYoQYx5sWC0FGLaFnzlV/4qRTXKLWRItuDXfv03efutf8L3v/0tFhdzHj58iLGWp8+fc/rihLqS7B/XdYgVLST8ZjkqnX6FtmPu3vkyf+dv/7t8+1vv8+jhC0lO0JrdwxGTKRS15sNPH6ODxhbHJG5y/fptHjx5zvmiZ76esKsTBwd77B0cUFRjvvv9n/DBBw/QGgqrGNUldWHZ3Z0ymmoODsb4puPBJw8gKe7eucbuzoS2F27XTz85pgNsaSgNGxVbTB6FZUiRV0pRlJrrNw6pas0X3n2NO++8jndTSjMmhZLrh29xfv6C04tjOmPp+8hq2RN8pCprZtNDoq/wvSemNfWk5/B6wXjm8S4QOCWZNS5FOt+yWK1YtqfcurnP9VsH3Lxds7NX4mLg4mzFg0+PISnKsmbdNIxGM0KA+fmKxbyhW3tCf0kIVYjaCpUwReLO3SPGs9dYt9/hYrEWM8wUabuWWzdusTxvWS4aok+MqjFaVaQARTWmrmZMRjNidNjCUtmaqhxT12OqStx3Y1xT2DHJrXBtREdDuwz/P/L+NFaSNb3vA3/vFhGZefba6+5bL7cXdrPZZF/LlERZEi3Q8iIORrPYkiEBAwiUPliA4RHgD14g2/AXwx9kwjNDC56xKWhIQtBCaShSCyWS3ewm2d3s/e63bu1Vp86WmbG823x43siT51TdZrcHM0CPAzioOnkyIzMjI+N53v/zXwgDfOebb3HyqGc2eVa8r2KW1PkS8DnWntFH7HwTcX7hdF6VE8krWsTpaOd8U3Pu+lbu+/1MeX6gG5SR/KqKne/4o4rkS6HPHOh1F7vVPG0Nxpf7/QFPeb67LAf8Ma7K+CRP2GTEk1fju7WPdu01pDMqpFPOgjxfGvN41j7sFZSmNI1rUFs7WK2Yz/fpWk/IoI2lco04Fi4WhOBlNT5+ubQqHJaI94GEPNeokshJTLlikAJbVxXT6RRrHSFGGU2kVCLp5Q36pJhHw8JuspV7ru+IDX1V9bz7YElXiF2zyrDTGDYdXNm0vLhbc6FRVHiMlgwQYzTJCyyrjCaETtj2ZCprSGRCgej74InLwOaskcTRJCt1bRSpG0DFlURUFULjiLipMeCub0UGi3BQ0Lp8yU5dEp2zMurKJcVZS6MD4JyREU0ozYzKosTBCGHZlaJmLVqvEak5vVCkIqHNIKslo9GlqKOKr4ESYnVVVZzMZYbeNBU5C0LU9wODLwiQKfyamBm8uIJmrfEps2g7QW60kZGdguSF/6ErGdlVdU1SXjxvvCjDQtIMITD4hE8an2GI0PtIUpY+RGIEn5NwPVDEpAlhzO8QErKkHytClswdN6lk3KJgczYp+T+eFCNbmxuCCvaj0+2p628s3KJxvCWZ2II+2LpwQ/yAUcKT2jCZl67OmGrJaln6TB8021bRR83Cw+FyYF78UsaYBJ31CsbOINlDxVVXF6RWG8XOhYt87Ic+TV4b4SpluHrtKX7ij/4EN99+A98v2Nzc4v/wf/yzPPvMC/zc//W/53e/+M/Z2YLlyQkqxaKELRd+EKJ5LGnixnJh7ymmk+0ydszYWvH8hy6yd2HC5taUZ64+RaW32Nm+yEde/Rzbl/4Jf+tv/88cH7fcfZiZTrdopjOazU1u3L3DN779Bp0P1E4xcXDx0g5aJTamU7IKPLh3zMnDY3TKvPDiMzSNpe8PmC8CV648w6SacPhoDiYym2gmEycGmzky9BnjQUeDJqOMoe8HjIG9CxuEw5boW0JYkIIEa77w7A9xrW/RuiL6zMHhQx4+usnW5gYq1+SshAiaPIeH+zRbNdsXL+Jqy+Zew7wN9INHL0CZiLaZrR3N9ae32Nl1oCIqGcg1KUQePjhkuXzEbDZh2DScHC9ZLgf8kEVmbWqMUSsb/JEArzVoK+nfxlX4IYMBrRM7O47PfPYV3n3zHm++fgs/QO1q/KCLhw5UrmI2nWGsKouPCqNrtJFIiJBCGb86ThaREDJ5AsNS8bEPfYr3b9zgy7/3dfZ2AsdH4H0ijjb9nPclOVvX1uvUqrlYcVZKjcqjsvP09ieBAecX6PKV+AOK7Nr2g92glO10dH9a9M9wQfLaqGf9QOYy2yuF/g8a5zxGls1nn/u7EWkf+6A4JcY+fu+zsNs6cnLGqC2fvnZ5jeKtO1oMn7XOV4XAaqmbhpRT4ZCcWtxTLrSStyMoicljFLcgKCklhmEo0lmYTCbFGlwKTcoyI2V1XCIpafYXA7eqimg32LWey1sebRXbU839R0umE8czV3eZmkTullzaqtiZGDZqLdkV2mCVFGZfrNhzGVnlwptxk4bkfXGwdNhKkJF+8GJ5njLGxBViZGwlng1FARJjFLt0zAoxGoZAXdeIYRrF6bQgXVlgWZSRhgZQ2hBKKm/OGZ0NxfGF0wC6VIi8qbD4pWkZVymqmIGN5521dvV6RhRLW41KeQXTWiOeLjkJAiIkU1PGC5ahEEGruqIuFu+SwSQU3lrXrLC54gcRRpddNCErUhcZgjRrvhBeU9bEBL339KFcBJUruTyZIcEQPD6cHpuEQtuK3veEmFZITiocl6puOG4TMRkaVQmHJFGg9CjGgErk3cZaJnWDoigf0tnwRuHOdIUkm8hWTOpykglJZqC2mpeuzvjw9U1M7MhK04bE4bzj6GSg7SKbzrLT1Mz7wFEXWPSRUDhPmYwyVoi+OULJcLLaipeP1lx7+jkuX38GxigKAKWxruLjr36cK5cuoNQW//5f+D/x0od+CI3lhZc/xO986V9ycrLk1vvvcnxyl629Z8i5EYm0lgbyNK0o8J03vs1bb76LUY56krlwdYPtPRlbXLr2HP/qH/kzXL70MtY4Mo6XXrnHzuY2i8URFy9f5PrT13DOcOfBQ77x+lss+0BMEYxjujFj+8KWvPYAi9YzPx6oqhmXdrfIRN6/eQfnFG2XMfUjJhNH7RRDyLTziO8SrjHUjXC2yIk89OQo30/fS7EVPpjja29+jcnkJs8881FS3MBow6TeICWFIXHxwhU2N7dJuSuIWCo/isPDFtMM7F6cMpnWTGab1E0i5iOMseLq22SefuYKplIsu57FsqXrMstF5uSo5fCwJcbEZGI4PFhwdDjHj5k8WcbBFVaMBwuSbUxmd29K01Tcf3DM/v0Fh488VaPZ2jLs7Gzw6NEdrNE0dcVS98SCcMj4NhJjIHhLTppcQk2jChLWqTMQiDHgKoNeamJIDD0sTgLLuecTH/8Mjx613Lp5wnyRkVDFUQJdlsQr6/vHa9T6aFmpc4v487ySJ25PqGpKkGB1jkbx3bb/v2hQ4LRBGBuTdUKiNCYjoHX+gZxJDT5FM063JzcccD6W8by88fyIZ/1Dl7HEuioHzjQm6/suNJc8clI+aIiXz+4jZ4H0ZHUfiUlWlcY5+mGgbbtCJlVr71/GD4Mf6Icemxxj+FMMpUHxnhQTk8mEjY0NtFIs2mUpIMXHQynhZRSI73DREWIgbFncZMaG9exNIo2puDxTNFXFRpNI/RJbw3ajsTqSSBjAUFKNKysr9xCw1uB9T1M3MsNOUgQpYXNVVTMMPUMZexQ6vHA3lIx2tDYMwxLnjDSpKVG5ipSkQRv7wIyMj8QKX6TGxijZn2bVsFkr3hkZ8fLwBWlSWhGS/C7nFKzMnVJgyF4QmtUoLUtORlH05CQoTy6f8dgDKgTGT3lsvkdptCmvTZNyoHaCFMlIwmAKKdQ6V6LdC6/FWNCaPgQZxVBGTGiGkErwnwJjCbnIgwN0IeMjhAA+Rvog0uKYtaz0qtKcpNHwTbgqIAnAOctYyTpDyJm2D2DEtC0l8bIZG2VrrMhZY0Jp0RcIx2c95kEeIx43EingvZB3tdIMfsB3AzvbDZc24OPP7nF9I2NSRbKGYB2zI0OtEyd6oO17fDJsVoqdacPDReCkHWgLKTfG0+uNLk1IEYKitaaabBCVKSvISMaQUkArmG1ssL29TTO1PP30S2hbkxPs7F4gJui6zHe+8y3+1v/8f+Gn/vT/nqee/jhaV6TkyTkW8ql4Cb3+nW9xcnJIVRm2Niumk4aT+YJMzWc/++Ncu/5RlJ6trjmf/NQP88lPfpyD/Xd49cMvs7W1gU+e3/vSv+Du/SOsneDDgpgMPlUMUSTzIXhSSGxt7DCbTjC2Z9kdMww9168/x6Jb8OYbb/L0s3t8+GMv8sUvfoPjo544ZHwM+D5gDExnk0JelvFzJhKiZ2/vAm/93jcZhjmf/dyHmEzFXfi9t1pC54iRtTyscnFMJcQzJXrvWbYe9ajn/RsH7O7ugKpYtpHloqPvAsMQiXGQWIMHC6wxtO1AuwycHA8cHh7j+0hVNSzajmEYOD5piUEWg+PCTzb5/mud0Dpy/anLTCYNQ/+QxXxJDpZuEWlc5sLuRZ596nlu+gWkE0jSwMUk16ZUvJC8D2J7YMSbR+mE0l5ck7Mn5YhzpqjRMkMfOTqMfPFLX+e1f2XKj//hP8Lv/e63ODx4R3gvgruWBa4q8RLnzNqeUFQ+SIyyfusH1ki1Pj6iLJ//V9egnJ2bwenq6Umw1fqjTmdu498f388ZVGT1p/PztvMf0nlo67wPSlmvrjVSZ1Q86rFdnHssqw9fabWafcobkQInnXgsoxkhzVaVQ2tF27V0Xb9yllXFByAh/IWu63CVo6qlII+k09P8GrNKOJ6fnHDw6IiTkwWD78lZMjSNlqJjLPgkpkqh19gLjmfqDbZtZlsHKhXJqUf1LRu1pakcs4mhcqBK2JqrK0iRw+M5/eBR2jIxGmNrjKvIZLrBk0MQa3EFw+DF7bUUc/FASadjmvEYauESaFXIjikW59ZMVddiQ42s6nQZFcWyUs9KODkidxc0IMXSCFhLKKRZlcWFNRUTLx/CqsiOeS5jIyQqI2kgxnM0Zml6KMqo9fluKqiJsQZnLNoE4YJ0HU5HNhpLRpKJR28XUBhTFCJBPFjU6GRbwhpBiVw4JhnjRAhRkbS4fg4h0fvIshU5cTuE4gJrydoS81DM0DTeRyFFJ2lgYgwFTdArJYQ2gij2fSDmJKZTxavBOsnhMUX+7WPEar1KGx4LhRQsI81eyUYRq3lBniTsLaJTZGM6g+jZqQyvXN1kMhzI/SpDMBk2HMSGxigWbaQdMm2UMLs95XBWcdwGjntpZNF2xQcquilpTirHZ3/sNTa3tkvh8WgsRhvafonSFuMqElGOX5amdDIVIzptKi5euUK7WPC3/qf/gZ/8U/8OH/vEj6KsYxgWvPvuuzz39Ivcu32ff/HP/xnet9TWkkJi/+Eh6bhj7+KUB/ce8MqLHmtGt0+Ybk742MdfYb6vuXZpj6Qqfv/Lv8e9+wd0fSSngHEOVMWdeyf04R2uXtldjXvn8312dna4+tQu3aDZ3rpC5x1vvH0HZQyzacWVS5u88uJTvP7tO4RoGJJHq4TWgdnU8fwrL/Pmt27zaP+IZuKYTacED4cHLU0zI+HBHbF3cZeT44qb73VknIQTpkjKnhghRWn6Ygp0/YJl23Ky6Dg+bkn5Night/s+EUOhBGTNvfv7XL6yzcHihL5LtEvPcj6waHucrdDWsWwHOZ+QkawygnTmoAghoXTEFqny5lbDpYu7OGuZTGogFH5Kpl/KCMmaKW9859s82m+JoSLFcSFUQjhDAjzJyHVb5MjFoVwV5CknUf5Yy+ATKMPgE7//tXd5593bXLu+x5Urz7G9s8PR8cPTkUypISrrssjJj63KVyKNsbaeqWyny/gzo6JztRGlztar/wXbD3SDss4KPotEULgdp02A3LRe9Z+MmazzR87zTUY0Rq2sl8b7rR699v/HBcdnVD6MKI9e8xo5K0PliSfC2nsdP/wVgfIUfhsbrZQECpT4eomFR0Hb9fT9sArrO923rG6lSenl95yJa82JZJjIF/Xo4JDDwwOOT5bCc4ieFCUlU2spIsZ2mKpCq0y3hNBZ6mc2mU2hiQs2jBbr8uypraKpFFZTosKREUIIKJXpUyZqR06KsFyyOZ0yeIHVcwyk4JlNJuIVUFAN4ypyEq+XwQ9UlUPlzKJtmSpwtSAt699CbQy+cF1CiIIkKEXwgaqqIJ42FD4EnBHkxoeIKnCvQRU7/FjksK5IYDUpRLLOhXOhz5yncl7LBfT066/KmE3ygZx2aCgeLQmULkiHKtlFRlAjFNZW+ODph0FQCmtOTfm0Fj8FFQs4pwgxYMq5EGIQ/hFGOCNJohMi4BMMg6hehiT5IwkIyYM2km+TEjl7lBGpcj8M4kORhJuREZJqiKLAMVpRV5am0cx7T8yi8BCzY0EEfZSk44wQmI2R/yslEtUYRUKqtBwHhZCirZGIhhwzTVWhFTQq8eGnL7PbiOIgJ1AOkjM0dUWFYuFqjpcDc5857AfiwkvDGqEdMkbDSdvTxwFrLbPaoVVacZaqquLK5T264wOO9u/ih4GqaugWC7q+JXjPxb1dHh3dZRhaZihS1oTi9Kmt4er1p/iJn/jX+bVf/Wf83b/7t1ksTvjMj/wRDvcP+Pn/6X/gyuXL3Hj3PjfefVfM+4Cul2tZAnzn+c53vsIzz7zMM898Cmun5JS4fftd+m6f7c0JOUbefO9N3njrbVLxUYkhMZtuELyMCfb3e06O7zNtKoyO+OCZzwNH84GJs6SUeHR0A6Vrgh+49f59cnRUZsLWxjY+GObdkuB76sryzDPXefWjL/Pem/fQytB1A0OIPHp0wre+9S4xD0y34JOffQ5lluxd3uLOrSXtwst1KSeI8lrHsNMQeuaLY4Yh4H2m78tCTXUYk5hNGuEnFT7G/KRlMq3p2oH5ycDQZ8kpyplqoyamTN/70ngaQR1NBi2cKrIMcbWB6aTmueefwvuBxXzJ1SuX2N3d4u7NnhwkauL+vUM+8mHF8889hbOH3L93wnxRvjwlxy2vrAUCSWuUsiglo00o1zsyWhuaakKMiMGj1pjKAobbtw54tB8g7xEj5DyGXApWtbqCqfUaOP7/3AJ7vMZw+idVrkvjbEKt6l+ZVZQGR52Wt7IvvuftB7pBQYm74zoSMjrjaXLJ9crkHCVxM+czxVsuaiPqUAy0yoFdB0PONxbyseS139f/ttbsJBklPDH9Vo1mN8UBV42zudNPb6UuzmINIdySQs5kfN1yHFJpJOQ9FSOpnPCDp+8C/RCJMVNX8pH37SB24aPFuj49hjEpej9g+0HeT3FOXXlxxEjbBbquY36ypO87QhDVTgpBSI/lVfYotA7YYcBVFqct93zk2w8su9cd101F5RKbTYPLFSoHKfpxtAt3dO0S3QUqZ1BUoDIhDdTO0YfI1FUEP5TGyIgBUkEyYorUzhUvi4IgAFXVMAwDfTcwnTZEPH0IVNbilPBJYgKnjBAqM0WpJBCrzrKSD4M0TlkLKdv7uDoZYvQYVxNSpu8GZhsOlBDbhiy28qoUbevM6TlixKNjHK/EKI6bSmmUMeV8klmytcXjRYlvyDIojuetJEqTiDnTDhEDaGXRWjgg3ntB1XImDT22qoqaR/6egox7YpaxVMwJHyM+SZMYMrR9JEQhQfcRhqRXhGpyQhkluTequItSvGdUxlpp4jTF60eJI60qHCZLprKOurLECPNFJzJMbaiqCVaDIlFVkiklyAkYZ/AkjBZll8IgbpZyke2HgRgi9awG3/Ly1YpPPbfJxHiiNVg0OEN2SnDIRrFVVWxPDCc+Mestle15eOTphoDVELOijZqDecQYIZbvzCxKJZQ2bGw0PHzna9x766v07ZLKaQwQ+pYQBprtPXacp3OOGBby2ZqKK9efYXNjG8UCTWb34jX+7f/tv89v/Mtf5e/9vV/g0YNDPvujP84Pf/KH+Hu//Eu8+cZd5sserRzVxFDNLF1YYI3I7VFL9h+9xdVrH0bbmsX+Q776hV8nDkeojQnv3bvHN974NkPqyCqSIxA1KimW7VLGjVnTDz0hRDY3LMbB4D337h6Rc8Dd3We2MWNzs2ZzY8L9B4e8+eZDtJngAwxtRz/v0S4zqWt2tjdQNlE10jwuWvke7l3aZefCFu1wwHSrImdPCHM2NhpqF2ij2NLnKCOd4IWgH5LHp0Tfe2IchI8SS1BnubYNJjFpNMoWS/qoIFp0jvTdgrYVm4GmETR3uewhIfEXVlA+6yyhzCtzASCsVUw2GyazLd56+xbeD3z8E5/kmaev8c4bD2lbOSffefcuzzx7gz/0R3+ErekeX/3y2/z9f/DrDEOQJqcx5AhtJyqzlCJaGbIq6rQs6FNWAxrNxsYUVESpSD1p2NnbZGdzi5OTI1I0nBx2ouhKII7qkaziWqk6u0g/01SsaltRW52vTnm95km9y2PDVmqZLm0MZQy9tor/A7cf7AZlbTtFSQRF0AWZWKETK8LP2bFMHuf2K+4KHwB3nW0D87iv8bc1mHl1zzMr4rPP+/jfS0E+79xadji2Q2ebsfFkOIWwyaczxZgSXddzdHTC4DsJ05o0ZRzSFzOys69n1aSUQDTJsdGFyxJXty+XS7q2l5WwNhhzatKj9SiNZYW4pBQl0M2JKdbN+494p9lh95KjUhGlZUUQfC4z2ch8MYhZWM7MJg3d4KmdxVkN2uFjAqNph7hyLXSuQmkIOeKcpWtblDc4U95HTmAMUWWqSUPwg4xPtCGEXmS4OctMXCn6fliNcKxz5TXGslILhWFvURjGSAK5gMgKfpSnV3UJglNim2+MxfuBuq4JQaDmFV9FGfFiSSV9N0tDaoxcKCR7Rs47rRTKlIZbBUIMEiufReUUU6LtRfpcVSLNHryHKOiQNYY+ixma0oZ2OS+Gd5bsY8mdqQgpkzH4GAkx0wXhn+Qs6cikzBDFrdhYafCqyooPzhDwIZKzXNBySiXIT2bu0Qssr5A0YG0cWoOJ4r5rtDQ6IUdpyEIgEamsxmi7kmxba+n7fjUulSwVkYUnZQkJYpbIgZQ8OxV8+uULXN3U1NkTtMQmZK3kHMmZ2cRB1liXcElTBTlXhtRy1Af0ACGXhFuySOBDYoJmwxmmE9h2Hfe+8zuQI3XlMM4U3lukMZo0HLKTHb6pSONnYxPbkwmb003m8yXJJ4gwmWzx4//qH0eryC///b/H733lt3nwaJ/9h8d0bYvRkWmtmU4rlmHAuMys0VzcnXJhZ5cwQByWnMw7fue3/hl3br7OxcsT5oueN99+l8VyIREDWmz+a5dBe4yVsVoSfzF83xO8Z2fHUdcGSLR9ILQy+rRG4e2E5bxmcTLQTAyDD7RL4aLNZg3GOu4/OKBupiR0QW/FRj6mwMaW5dLmVTa3NzCmxtoaZwz1JIOKpGBkRJmijMcIhNSyWByLeZ4yJDV+T0AWoYngE954ya9SRQAQBCXOZcRprWbaTCCLEZ+MPeUaIEIqSVpXSq67zllSyhwdtNx49z5VFfFhINPy/AsXuXfnMu++c48QDNPJlK999U3u3X3IKy+/zGy6y4//xMexzgoCGBJvvX6Pd97aJydxSo66lzGxtPnCU1MZnSPNFKomEMKAto7tnS02Jpu0bYu2NfeXR+RkyTmsFa6RIHuKepyvAes16nvZVt6y65yTEjJ7ppg9Nlv44O0HukFRSglrIp/GRDMqYxQrKeDo3Hr+sKyItet/O4eenNeDj3dcEWEpn/kaqfXc0KigNk/K4xlPDrUqXqND6WOvcwynOnMAyusq+x8htTEMcQxRa7uOvm+p623qqgYkxTjEcDrSOreJkscXjoDEf48NihQESZ4FVretAgDLixst3Mc4ghgCOQ9SbNC8fxR4fneGzQOu2NsTIQUvnhLZsCiJsjEHpk1FHsRNNYZAZUUiGvuA0ZBjwposHhc5onMmIghAVVUMvmcU2Y1fpoBYsA+9GClVdS1ZJiEWy3hN1wt0H2IskmJBYkaDs5QSfeGnyH3c6hwc83lOgwStcFGyhCOCrMZQwv8gCxcjKyHVpmKlL5QQccGMYbSCl1Rma2U0onyEHGjqipjFoh2tGHzA1gZnK0JopZCiUMYU5A38EMq4UlZBShfXzxiIvidmTcqKPiQp9jHgfSLkRAhJDNpK/ozW4nKbcsYPg5D9MvgomSfGysX8tBg4VDLSQBZvHaUzISV0CDR1w2w6YfCdjCRTlHIUMknl4u9iHjO/M0ZSn6uqZt4OhBghR6aTBhdbXroy5WPP7FCrHqcySsnnmrUi5kjwQX7PmdpZMSDrPU1laSYT6iqhlacxkb2ZYncGm7Xh6t4mE5146tIOO9sznLMotcBVFqszFnBaE6NHJ+FoWQ3ZbdDOF3jvcdqxOauZTCc8Osy0BaUcuhO+8KVf4/W3v07r5/yzf/l1+i5AsqKAqiyzaS2yeR+w2VNZy/WrV/nQKz+Cqy/y/o2vc/fdW9x6/w2aCRwfn3D33iPu3LuHqTWVqum6gNJeTBd1FKQkBXwUg0CDpesSx8cDG5vipFy5mrYdWLZz6knNyTywOAKna2plSURCykxmE6wzxKy4c+cAoyfMT1py1qQIi/nAb/3WF5htG5567hJtv6D3hkUb6dt74DJJKyKTop4J+NDiY0vbnbBYHjGG7o0kfcHDhDgeY6Zd9qCSoCSNOMoOPhThQqKqpmjt6HsxshT1+ACjMlJBygHyaM6mWSwXoDW3bj7g4kXD7s4L1JVib6fi4594hr0LGzy4e0RTX+D9G/d549uPeP/d38VYxWzTsrlTEUNiOR/QbJMJ5CRp0Tl7qROZck5KnQtpoDFQ1bmkbCtOjpfEIbOYt1TO4n0uzUIotc1BFsfr8/OW76c5ySWTbVUHz9TKcUx0qk6UOvf4Qv27bT/QDcpYXFd8jlMcZO0grXV0PP4BnMp3TydqTzrgj/mfrO8rj43peVOa84ZqZ597NNkak261HpuUx+9/utMCBq1+1t1IWTVDIBblm5tbbG5uiS+Eq9DGFgXPklAMe86TgHOWAurLlyKVbl3MwdIKFXDOrZqT9W00jztrUFaalBSATK8M9+eeW0tJOfXdgpwjVilUkrDBZjJDe8XB4SHH856NaY3T0DiNNYpgE0OQFdSkshitEPsnQUuUMwzzBaiE8wGrxevFp4imZK6gaDtpvsji8lg5JxbTtmTjWIurqvLudBnNKCEPZlH3UJCAjBw7Z4T7oI0oN0IJnHNao7Kh63qcsUWlU77AShXZbxkiKmH0p5RQUZx5tRZzq5gSBlWeR5oWtKCGTeU46QLeB7SVFdei7clpYDap8INInRMiO1daOCn90EPhcUijosjKSpNSRj0+whAHYlaEpOiGiNbiKyL3Fw6MjyJPjUVZlUMqKJAcj1hUNs650+9gShgjF/8Qk9Bjk2QkOWuxVrwp+pCwRlK2bWn8YpQR41livOw3RYlCmNSGHBMmB2Y28kPPbLFbB4zKMtKirKjJWCPvHQw5aYYgzVYcApV1VDbROMXexLExmaB0ZmvDcuXCJpuTmsZWbMwmWKMw1tB1HeSSGRQCOcnIsqorhhhwCWos8/07LC49y3bdkBQlzyeymB9x6/br/M7Xv8av/OovcXhwQAwyOvMD5CBBcc10g5ShXS5AJyprefaZl/iJf+1/w0c//hM82N/nd37z73F46z0uX9zF1TO++a3X+dbrb9L2fhUiOQwBcsa6ipN2SSiR68YoGQ0iGTIxQrcMxdb9Mvfu3SerlrqZcfCoRyvNzlbFzs6Uuw9FFq6tKQsH+a4cHi7KCBO6oefR/jGPjvb5zI9/mO3dKekw8M1vvM3h4UNyiuxtPUvlXiB1ojBctHPu3btJUh1iTT+inoKo5jG2AaCg5XIdU3RdxOiB2VSUVWTJCjLGMfSxSKwNWsfiCSWIwFhrjK3wPuEL2hxipG0j87nF2Jq+8yzmc7SKXLggvJ/jg8hykYh+ykmfMEa4XIPvZTQZa5ZzUQvlKK85JyWjypzJo029EkWVsZB1hlaLpcP+I45UYjrZKI2fKUTb03olqMbZ6/b3uq2q0rl6KFOA8wvsEQA4RVW+n+17jxUEfvZnf5ZPfvKTbG1tsbW1xWuvvcY/+kf/aPX3ruv4mZ/5GS5cuMDGxgY//dM/zb17987s48aNG/zUT/0U0+mUy5cv8x/+h//hKin2+93UOP9aG+9o1FnkJH/waGV9O9WHf3CHd4aYero3xsN4/nF51Umce91rr2/9A12/fW0v5x8NjH4oT/7ATxsUx9bWNpcuXWG2sUndTATGbzvabpQY5xUClROnTV656HvvGcoqOIRQkJIsTqqlWRkbEVPsxVeNlzptUqwx2KJuQMkseN56bjzq6PQEVzWQo4xUynij95EhZoYAUVtU1ZCNJaBBWwIKjCUhturYiohmOUTaIUp+C5aMxgfhcWQ0FHfbIcRSTBNZGUZH4H7wGOfQ1hTPF1HlaGOFU2QFovcxlvGQtBhjsV1vNEv3DFqX58uFS2GF45FYecgI1yQKbI0CZfApE5K47Q5euDntEBhCJCmKWZovvityvld1RVVVZGCxbOU5GSPiJa1aZJqCnoTCxkxZ42PCF4WOD9IkKOsIWclPojQnkJWl94F28IWjY1FajKT6wVNsTUjFuMyM/BmlVmqyUZZujZYRZFWhcpbxTJJAw5iSjG4KVF9Z8awZuoFhOB3BjeffKaIq378QBnLwTJxi6qDOPS9eaPjEsxts1GK9H1P5nMqoNUX5THxIdD4wbwcWnafzgX7ocDpxcbvm2csTPvnCLp995SI/+vJlPvnsHi9d3uH67ga7s4oLO1O2po6tacXmtGJSaSaNo6osk6Zm0tRMm4ZpZdhUnvbuWwwHdzg+2AftaCYzcgx0yxN++Zd/nl/9tV/gzt07EiEQPSH1aCMLAGcNVWVI2mNqxVPXrvLc9Ze4fOl5Xnr5syi9QRwihw8PmdQWaxQn84Uo40qa9HwRWCykmFeVYWWLnmQhZY3FOoXWqfAeNFVVo7Pi4b1jUpgR44zDg540BDZnmmvXZly8OKNuKowWT5++97TtgHVC2q/rGm1KdEQyRC98rqpyNHWFMY5uoeiXiZgWWBtQOZKiZ//gIYcnB8znJ2KP0J9GeEzrGdN6k9pOqOsZ03pG4yYYVaGUI0dN2wbm84EUDVpVVNWEdjlwcDBnufAMXURlizMNORti1ASvSEncbPtuIATP6O8Ry0Iierhzd5/Do47jkyU5R7Z3pzz/0lV292aFilAThorFieH4QLNc1Bw8UpwcISaGyRNSkfzH8fsk53dIAW0yrlJUtcVYUxbLER8XGAvDIOIIkekXhHRE+9V5NP+D0ZN1lWFWaz8rPDrzJH+Ts9SI7320M27fF4Ly9NNP81/9V/8Vr7zyCjln/sf/8X/k3/q3/i2+/OUv87GPfYz/4D/4D/jlX/5lfuEXfoHt7W3+8l/+y/yZP/Nn+M3f/E1A4O6f+qmf4urVq/zWb/0Wd+7c4c/9uT+Hc47/4r/4L77vF79CkThrjnaWM3LuIY91fY///0noxQfd/kHb+v2ftK/VeCcrzjYs6szjEqfIzGjSNkr8Hmteyq9ycZbmp2kmTKczqqqmmkxJKNq2o+/6VXaPNCTjOl6x8pzImbHLVkmVi1VeyWXX39uIqIyck3FVO77PnBWaAsGX7iXnxKPlwElwXKqn1KqnVUEaohBou0H4JUbIob6k+FqlwDpCHOiLr4gfxI+iBxSJaVOzjL1EmPsonAZt0NqCMqTkZeXT98wmU/q+lYydkg+jVTmOuiAUKdP1PVXlSEqIz+Iwq9DWSGgewr9ASXYLZEE+wjj+EFls3dTEDNEHau1I5RwQAzgreJ6S1VoKgRATVS3oV9cP+CFQ1Q6bxUxNxYBGSdNjK3xYsli0tH0nK1ZjKFCG2MvHjHHC4el8R0bh+4Gci5RXyyoaJOF3KOiNGLalQkYsPKaUQGcJWCzNhvBLEBRKCT/BWlF4DEXCrBBzuRQll8Vpjc6ZHD1WW6zRqFBW7dYS2iXTSSNmg9aSlMJqQ05xldS8nhRtjKH3YiiYQiT5hO9lLLhjMz/60iUubhi0ymjlGFKPslrQmyRZQkNIDDHT9ZGTZUsbwSeNtRXXL22I70sUC/7NSUPjtNi4oymEITEG1IpqIuO0IURs7fBBZN7GaJxROJ0xRJa3X+e+rnBPHXPtQz/E9esv8LXf+y0e3X/IoHuOD4/IMdOHXnyN6go8ZBvYmDmmU82QHVcv7PEX/t2/wN3bJ/z+d77Mrfdv8ez1mq/99uexOTGZbXI073n7xi1u3ztiCDDEosbIEkkw22iIYYGrIxZFjLoUN41X4r/iqgqUYW/3KmEI7B94kjacHHQ0VvPsM7u88NJVHh20LBYyKu36Jb3vGAIo42gqU1YzQuw2xpGi5b137nL1qW2Mhc3ZlM3pDl17hDUwnVpOHgVgIIQWKATvQYwZU8gYXTGbbUHSNPUmGUlzT0DX90Luj57oA8eHS1KckJIWJVHrC98mM/QD2kHVuBVZNCeFUharNVubFVWjQGeOT1rhmCnHu+/cxdURHwSR2tmZcHC4z49+9in+zX/nD/Glz3+bN9+4Q7eMKGtoGsfGxjZHjw6Ry1oEFRgVO9Iiis+SkGpyMX1UkBPGeHLWuKqQ08n0nSdnUxbrksMkNUgMIj+oZzhPbRgNTWU7O1HQp6zL1escV85Pnlh879v31aD86T/9p8/8/tf/+l/nZ3/2Z/nCF77A008/zc/93M/x8z//8/yxP/bHAPibf/Nv8tGPfpQvfOELfO5zn+Mf/+N/zDe/+U1+7dd+jStXrvCpT32K//w//8/5j/6j/4j/5D/5T0S++X1sK2Dp9LgxgiqrbZ0z8oTmZPx9fYzz5AantIzrXWI+ffwTX1/O4yd7updzCMm6B8r6eOcx35XV+0inzUrpXkdL//Vx18iRyWgphhliSCwWS46OjhhKirGcd2tAWiku5TQrY5m4OpnHBimtGo985mQ2xqz4AKPteEoitdJZFIFZicrKGEPbe+4vItebCXtVR05tMUmTUZA1Ys+slKTMuqYq6IqHHIk5M500DCFxdDRnYzYV1ngfqJwV2XOINHWFdg1dt5RclcIrGEIU/osRq3m0QZnC7s8ZW1mIUS5smVWAntLC4k+FQ9EPvnibqOLUK0z23g+oMvsWmbqm74OgI34o/Ikxy0VIfDFKZodRitpqKmswThKXKW6Zi3lH1w5MpsWkLkpAmY+6uL0qprMNySUaAqRIU9f0PghcnMX4TZKLMyCkUDF4kHTkfuhZ9B6MlTTiGAU9iUVqnLMojkoqsrUi9/UxSCOYRwt7OTNTGXGNK2WFIhXI3VkDKUqUgXboPBCDZ+g1VV0JwpNktJO1JudQuECZuq7EjDDJF2ZEJa2xMqZUimY2QZsEoefjz2/z8We3hMwdEyl4gvegLFpXDBF8SPRJMe8GFt3Asg8o21BPpmxubcl4I2dMVeNDoHaOyknBiskDCUmJLlJqI6GEWmWUBqed+GiUc7wSzyx0XLC89Q1yyGxeuMzO7gWSqghZ4eyMbuFJKeJqTWM1sdW0w4DRip29mkkz5dH+CWmZ6OYt0UfeefM9fvOf/2PuPXWNu29/E+M85sKzTOo9Xnz5Krq+xtV2zte/9RVyDFR2QuhSWSIbtrenVJU01zFkMW3zmq3Ny+RYc3y44MH9nsuXLzJf3GPZZZzVPH1th5dfeorp5gZf+dpNlp3HTSzzNhT0QIpbKk2zc5rZdEplhXdxcnzM/v49ppsTXKWZzBzNZIuN6TYXdrfYv3eEX7RoLWEGQMmSkgVRVTXU1USI98SCcogDdFM1cv1pl3RdpG89wRdOXlbkpATxVXrlFhwH4VcJEd9gMGKepgS9M07TNJLwvVgOvP7tW2zuzMTCLSvu3nsEquPew5uo/JCPfOI6Fy9v8t47d2n7JbauOTlckgpiImncY9EXDk1ZsooMHI0fBrouUDeJZqJplx6jHZWrJK8ndqvrsMJKk4KgX6O8+OxY5nEURWpnqQ0FtpcYFvl3VSvK46XNHfc9ckA/uE5+t+1/MQclxsgv/MIvsFgseO211/jd3/1dvPf88T/+x1f3+chHPsKzzz7L5z//eT73uc/x+c9/nk984hNcuXJldZ+f/Mmf5C/9pb/EN77xDT796U8/8bn6vhdHyLIdHx8/8X6nmIKsvLRWK5LUeAg/CFkZofn17UyTMI6RzjQOp5a/T3zcB2ynxNyznZQ+l2isRlLJY+/y9DHy2a/N98aGYaWiyYQQ6bqetm9ZLBc83N8Xm/MQCoLD6UiC9eamzJCSzD3X+SmjA+0Hdchjs7LepKisVjC9Ro53TJEb+0dcqmdsbs2oqohSJWo8sVIEaU6/LD5J9o7RijgITyanhDKOIYi6w8dYPEMU3dDjGgetWl2EKueYTCowGp8iTVURgqdGvDP6rqOupWEeV+ejUZv3Ed+L/4YPgiCghVthbUXb92zOpjJayPK5xpRw5cLb9V05zoq2H5jUjqp2RXkin53WRb2iHVVd0TSVRA8oRQiak5OWRdvRDh5tLfVkQiaz7Ad8NpiqKU6jeYXmxBQZwkBTTRkLaCwjHZS8xsGLWiErada0hVh4NzFlhhCQvERVHGgDOUoyLcpIOm2URprMytQPJJ9EAbZkDqUsSiKjxLYcDU4bAqJOcMVFV6FxVUPKkayksdVKkWIgq4RzDTlrvB/KIqd8f0pkQEIRVWaiFFs68+GntpiZgRC0cFx6T9sLCqVypgtZRobaMSSNqSZs1BvUkyl1M0Vrg9UytivLA0GhikoohihNpRElFxlMafwrVUkDakwhPpeVMAPWGiYGVGqZH9/g0Xu/z+4ELl68gG2mTKYOZw26qlGVRitYzMUrYzJpePVjH+NP/9S/y6//09/gd774z/jyV34Ha3Z5eO8+3/zql+DkOhd2NnCzLV780Kd4+plXmcx2aIeB92++zS/90v+Du3fe5+DBEa62pBjpWs3UWlyj2diq8IPHmBpMw7PPvcrv/c4bhFBxcNSzu9vx1PVt3n//Dnt7Mz70ytNcvXaFb377Bu/f3CehGIJwcbQWGWrfBZY6kgdwpmJvZ5euXWJs5NKVbawD73tCDOzsGV547iP0C8NsMmMyPeHmrWNRrXHq62G1jE5ns23hWKkIxNPrbhYOVNe28j3WoklPntKQiNOyVhlnnYxzU0Zlg1YOlQuSoqTxiEGxOElgBpRRTKczlNLMT1r6LpFUpq4qTG25eGWb2eYWd2495P337zM/6Vm0gnZO1Q6PDnpCUGgcJFMWuKk0s2vX5HKNjUGzOPY4W2G18PCGHho3JQwS9jk6X4uRdl5bZI91UZ37/RT9WOdvqlwcm0bgJY9V6ExJWt3h9JHjv/8/aFC+9rWv8dprr9F1HRsbG/ydv/N3ePXVV/nKV75CVVXs7Oycuf+VK1e4e/cuAHfv3j3TnIx/H//2Qdt/+V/+l/yn/+l/+sS/jfxgqc1rLYoalTGl0Ct15kiqsiI7vz0+lpEPcHRTVmOzsyYpPtsynO5HjWjEuRHS6vd1dOcx6Gdth+Pd11//GRhNuurVuTaiNlnuN0pb796/Q4xBRjx9X/ai0dqUn3MJ0CqvDtvqFD5zbOR4f7fOeB1yzxlMcfgorSNZGx7OW24cOa5tTLnklpADKQqzXqHAGom6hxVfKSVRe+SkabuANVL4YkpoU1HVlhgGfAzUkwkeOFq0pDgwaSYkpTleLOXLGyM1UqRDjMToSQhKZEvjZq3Fe0/btkiIYC+p0CmCEkRFjp8hBIGZFVmKs1JYJym5MQYWiyXOVStpYiweDeS8KthKicW/dQZnFDp6bApMrCIZQ44VyigWQ2Deeu4f96SsyUoxX7Q4O8FaucjmJJbrIUSsrVBGcmlEBScfsLjtKkJMOD06yApnp+tkHJYKvJ9yFmdLrYnaFEmnfCZjwR2bXKMF/UqFmKyNFqKlWPCiSOJ+qxSkiFZifDZtHC2KpLXkCOmKXBrjELsV2VaaoKL8UZJqrLX8m8rCwjorK+wh8qGnZrx0bZuY5jA4hqBYLge6PkpukveEpNGuom5mTGohqmqjC0G5jO8KmJqzuIpmBUHFFeKYkmWUtcpipBgy6tJMFxt8aw0xQ1XV2ABDVhAzwR8y3Pwas7zJC5d3uHXvLlef3qOpwSMKGKJlWM6prObipV3+6B/5ST79w3+IV175FLPNmi/99r8k9u+yNa3Y2dpktr1NdIrp1iaTzQ1MU5ONo5lNeOnlT/CXf+b/zMP7t/m5//5neXjvvijbqOhOMpt1w8svP82dO3dwdoautnjnjbssF5lIRcqRB/vHfOwjz1HpJVevXuSll57n8Ljjq7//Nn2viCqRsheCs40YZ1DU6Dwh5I7FfMH+wyOefvoyyS556rk9Ll/bxYfAxlbEKNjda1jomkf7x9SNo+tPGIYOXUwPjVakbJlsbLK9uSfHXUVEDiyIXt93tF0r560uiIA2GC3KM6PEKLJpHJOmlgDMk46klJDex5HJeO3NgrRkjDTyRgjEpBlDJ6OrOAQuzBpeeeUFFouORwcn3L55sFIJVW6C7y1D16GUJUdVUIhyDUwaVCgNihDryZmMZX6UyEkCQUD8Ydp5zfKkLbcXHhFlrLNqRE6v4etXeXUe7Tg3OPiAJf5pb6LUajG7Xur+vz7iAfjwhz/MV77yFY6OjvjFX/xF/vyf//P8+q//+ve7m+9r+2t/7a/xV//qX139fnx8zDPPPMNpP3LaVY5bKZ2nzcN6M3BuUwVxIa81POUCe/oxjjqf02dQpztd29l4gV5/2iePls7f9oGjIjK6jJfOj1WkAWDVlOQ8fmnkd20krn53Z5eDwwOOjw8JY8ZDktUXGZQ2q1ETyOpT62KeVeC9VbO39npHYubYSY3HnZzPNjvlJUrnbaBYPwcfmPvEzf2Wj1zZ5vK0wqaBFGX1rItP/ZAyWYnrKXCK/mhJJ64qBzmgNSXUUBoOYy2urvF+IPqIRtMOgoTkFLAK4Y1oRQzCrRCbdOHQ6EbCBCutsc6xXLY412CtNBYpysjDWeHJLNoOoxR975k0FdZC7wdQgmQ552iaiUiLyVTWyuqmXCPWlV0iK5bxSdaCZDmjQWliI5k5WEefDEeHhyz7zHRak3Ipylkyi4iZunBOjFakwRdvh0J4zkoM2zIoLd4l4kZXfGxEd1zOaTF68gVNsiWET7go4/lRELgUyzklfBGjNWk8n3LGFsTQai2jMg21M2RjmTWOeyctVOL50oeWphJ/oyF4kk40dQNZUoyVoszdKQ7ImdGJt55UKBI7JvOJ5y5iUsfcB1QKdMFy0nrJSBp66qljMp1SNQ22bnCmLFCU+P0IzyZhXGlWcsI5IU8POZXxpZDBjVarsXUsEmhCRttRci7kcR8BrdEmEbMSjkjydCf3sPmYpzcMi2PHxDk2ZzMOjsV9NnlN6DNNU/HC8y/wiU98FlM1bO5N+en/3V9gsej44m/9U64/fYmoFN985wYHJ4/QNvOV77zBH/6j/waf+9GfhGzResLGxjX8IkGyXLt6ldu3b+NsTfIBpys2Jltc2Mm4ao879+ccHXgofJVE4uQkcOO9G7z43DYvPCcLzy9+6escHXWnBUspJrXj8uUtXvnQKxweZqK33Lz5FsfxhOP5koPjQ3YvOy5calDaMJ3WvP/+eyu/kq3psyzbOW+9fYOT+ZGQlp0mZ3FcnU222Nu5gjMNYbQvUAkfek7mJ/J9SpJjUy5taG2x2slVXWfIHmMUdePY3GzouiicmVXRWS/wkDHSRGRD6EsIaLarxkIpQbkuX77C8fwhxjisbejaYiKnZxwe+WLXn9ecXkcfEUOxDpRKpEq0RjakoWZ+kAtpNaKAJQMpqoLvUcY4p3EZ0v6cXpvXCa5PqknffSawOgyFGzPiAY+rWr/f7ftuUKqq4uWXXwbgM5/5DF/60pf4b//b/5Y/+2f/LMMwcHh4eAZFuXfvHlevXgXg6tWrfPGLXzyzv1HlM97nSVtd1yVR9uxWXIbl/2Uudgb4GE8eNSJP683HuBMYpWenN+TTC23Zz1k2spyg6QM+SAWyqlYl72F85PnRT167LadVl7le2DPi5yLfC7m6j5bmskIrqzMgo6XRyKdwp9GZzdmEp65do64qjo6OWC5aFsuW+fKEw8NHdMVjIZVEY5XFe4sVJ+Y0GXkdZZGOOK08WhKaNH5x5KCcebMqS9ZPUgaSQSUP2ROyYt5FDgeF39qgiS2TRgINQ4hl3mnoI2SlqYxGpYB1ArNqrYXLoAxDDPhBCs7GpMbZ4igbRX2C0vRDBHoap8EoqroReWAn3JCYgZSwRkYgXdetvA7E9t5jjUPFhDYZo8QhFa1pey9qFmOxibKik0avHwaGIH83zmCNpDOnWDJFMGSVV+eqMYJwxJSlkSpIh8iYNcmKFHbhIEfFshc1z97WBHGAERSksg6sI0cxwFMqYEt6sxTdLLJSLRJfsZP34igcC0dfKTCaMIQVgVYpkTtnnYk+Q0w4balMJV45TuTeghiUJijm1fgKpamcleOoMrXVTCoxntusdTH3k1FgThGFw9UTsIHjZYv3Lc4YrBUXz+QDMcRiHCfFJAVPjoatpubDlxsubWnmx8cEND4pfIzMF0u00mxsTNjc2mEym0mqtdElCDASU7Ex0A6jEkZePrrYuyutMUmvrR4VYs2vJJrASHNVmYrBi426q2qyUlQqo2PA54wOGZuDWOmjsHnJhWrguUtbpGrCVG+yv1wym25wdNgzrSouXJ7y4ovPs3vhKXIxu9vZvcTzL3+E3/7Sr/Pw5IDDO4fC0lCRjalhumnohxNU4VwkJZlHDx7cYjpt+LHP/Rh//+//XRaLgclkglWB+dEJk+kWh0uNx+Fqy+VpxcP9Q7oAWSusM1href/mLRbtbe7f26epNXWtCBGyaahs5PqFbT72ysu88dYhKUy4d/sOmIo2BI4XJ1yfXWBzY4JSljQYjh8FHu4f8U465sqlxKMHPTdv32a57CUOwdRUbsreziWmkw2MrgpKmPG+5+TkiOXihJQSlXOAoSqeUMY4cpZrdUwFaVCajMdomDQVs6YmzXsUScbdehQXFMOzDAWPJMeCNCKcIxm7J/EjiQ6ixQ89wXfEAYzeZH6Q6JdyLdVZGpPVIlfJ1VW4ePL6EuMYRcbdo7GTvO5i84Ccg5TWBnXqpTVyRPT3OHoZ16FqLInn/762WM+c1jVVrPnPWmd8743K/8c+KKlIAD/zmc/gnOOf/JN/wk//9E8D8J3vfIcbN27w2muvAfDaa6/x1//6X+f+/ftcvnwZgF/91V9la2uLV1999ft+7lOKhjp3u8KUqPmR1HP+kKxW/gWBWUdGxobkfENx5vf83dGPESY7z9EYFS5yQ4HwlEijHxuxrPZ9uuocEZTVfkozv3qWPHbNo8ZdyGK7uxeYzTbx3hN8ZPCeuw/u8OZbr3P33l1CkNydGEtDkDLC+D49oc43Jyu+jB6JVlJB9dpxHI91Xv2bAE8KPTlFamfR2kmeS4SBikpXqJTQGHkt2oCOWCXoUA6RHBM+9TLmMeIaqknkFKmMmMQNQTxN+kE4TNba8j5KTk2lCSmuJL5DTNiYMSWvyKdM6gPa1iXXJqOMLXk7GpWleNkyqul7vzJyiinTec+kqrDWsZgvqJwED/ZB5sIRYeNnhHsSEJ8DaySKPkbhW4BiDBlMCUFFskIVRn4MoXhrUCBtI6hIzOSk6XqRAYtz8BjgKEZwqqBgSWmCD2AldbgfpCgzynazBCSGknMjXBxfZOdybmotBLyMeC6M57m1RpCPQS7w1kgWkrUaJ15y4lNSGSqdUCay3SgapxmMltGdVagYSL5jGHpqbYQ7U9DKnCKmkhTmmEQRFKNnMpsImuGX7M12SMHT+kAbMhEjzrK2om5qdi5cYGtrE+sciVzM5iR8UI+NUgaJrc8rYzj5zsiYwNrSyMZcPsOS7G3sKr1cl/cfY8RYIcuqJCvckaNlVMbpSENmZ2poVcXcGKKX9OjdzYvMjx8yLDu2t3f46Mc/ibIVqSQmp0Fs3n0YODnex6eIcpamqTBWU1eKC7sXGM3LUIocMm+88S1eeOl5lMloHVC6p5pU7F3YkHNdSWhd1dRYp3jh6StMG837t+6ztzflxRee4hMfe5WvfvVbfOXrXycki2tc4W0FGmfRRC5f3Obg8A6vv/1N6mqbRXuXlDusroFEXddYvUndzHjzzbeIITG0cOvmAW9865jFSaRdyvhyMnNMmx02NzfJqsPUC65d2eHmew85Pj7m6HBOCAOgcU4zmVZoVRR92ZKyWknhxfpTobJmGDTz+YC1HZvbNYu2Q0qmJIMnlVcNwRhno8r/10UF4qVj2L+74CtfepsrV7axcQcdIypGukVi6CGnEaVcH7Wsj17Gc6TUH3W2co21QhaDegVsl5vO1hV19nk+aFPrTc04w3n8Xmf/O4528ojwj+j+45SKP2j7vhqUv/bX/hp/6k/9KZ599llOTk74+Z//ef75P//n/Mqv/Arb29v8xb/4F/mrf/Wvsre3x9bWFn/lr/wVXnvtNT73uc8B8Cf/5J/k1Vdf5d/79/49/uv/+r/m7t27/Mf/8X/Mz/zMzzwRIfkDtxXhZ/2NqzM/60RUhVoduDNToXMr/fMd3joxdhzsnCI353cxdgxPCBp8rIlRxY5/JGKeNgGn9zndZy5PlHNepe2OP2dHL+eeo3BAmqZh0kwRT4yEjwO3bs+YTCbEmFku2pVLqkoZpUfJcHrs9a93yMoUy3Vk7j4y9OXeo9eKKrP5tDomVmcuXrjApK4xccCEgW9/+yYffW6bqa4BKYw+iGLDWC1AZxKIJ+tMzpHoA8YYfBAXVbSS1S9SYGOU4umqmvnJCXXlqKd1kRBr5stOkBYklNAEK5yXlDEqM51OxIsAmG1tsVx0dF1HU4l3gzaG3vcoJWhfCpGu76lxNJWm61r6wTPd2EQbUQ75IZKNAmsKF0QyT2KJNdWGIiWX2XtWZTW/knHLWR+TnNPaaJraUdcVPsg5HEMQXgiQ0iAFxgrS0/virZAiRltc1RAZ8Cky+IgyDrEFjwwhoLQoe2QUJc3PeB64kiNU1RV91wvygTQmo/dJilGQuJzQOYlJmdUQ5f05q9ioNc6Ks26PYlpLE1JVTs5jP6BUpDJl3q6zQPgosjWEJDLpWBx/xZclo/zA3lRxYXPCYrkUdVBUmEqzvb3DZLaBsYbJtME6K+9HKZKC6AUyF3fg8h1Thpwzfd8TitPveCGX8EWNNqVxjAHvfZGQ69UqdrRojyGuDO5GJZ41erVK1ho6C4ZAHFo+8tGP8Ef+9X+bX//Nz3O0uMHWrOIzn/ksP/wjPw7KicQ5eN76zrf54m/9S65cvoA9HHh0dCKZUmlAmwnNtGI6qaXBylLoF8ePuHfvBp/+zGfpltIEd92C2SyhzaYcAyLNtGIZwGjHndu3+ehHnicOJzx9/QKvvPgi7aB4/e0HzFuDtonQB05OFjirxbnVwN7eBR4cPqRPx6QQwAwiOU8aP2ROTgLvvXfA3bvf4P6DO+ztbbI5mzE/esj8OJOSNOGucly/+gJNM2O5PKbr51y4MOHBg9vcf3CP+fGA0RZTKbHLryohviIKmZRk5JGLPxMK9Hg9zYpuCJwsWvb2tpht1rQdQvZXoiQbre5LcRBYDWQkP2IqSgE1vodvfe0mb377FihJ7Q5eC5o8Xt/PLOzG6/nji19yiecbAf3V86xezZnm4oO3J3Un6glNywrOeWKTclrr1qvuk+73+Pv5btv31aDcv3+fP/fn/hx37txhe3ubT37yk/zKr/wKf+JP/AkA/pv/5r9Ba81P//RP0/c9P/mTP8l/99/9d6vHG2P4B//gH/CX/tJf4rXXXmM2m/Hn//yf5z/7z/6z7+dlrLYRLjolypYTa62hkH/GQ3baMJyXx67t9bHnWR+3jOfhWfTktHNdjYCykiZCnXqXfJC8WOtTfocxI4Ky1knJI868uvE9rxoF+eX0tqxRqhybM125XCRTEAhxe3ubjc0pj/YPeOutd4ixL+oXijpDVoJN06y8LCRBd+TZRFRKRJUR28ORQKZWByaXy63cKoZuu5sNF7enXNmaUZGpTcPhwwcc39tHqcSHntlj6sCkhENWC1YLZBrLKEpoNkK+zYB2opJJKReai+XweA5JCpaPiZhhseykWKqGSWVZtguqGpR14hPTe1KM1JUE/T06PKGuDHXjiAjhVYibCmMq2kEKlbGGqrLUdc1iPkdpuzI8m25siHV99FhXEb0nJQSG1mJ8pa2FrBl8wCFKAlCliCWytitfnDHJtfMRlGY6ndEeS0J19EoafiXEZ2s1gx/ICGriUBhbkXPADwNt7MopIr4qMSkG30mTpgSpCVEs7Y11GOsIMZXwRDm/YwwEL6GHJmt8aY5iyOIJUs7laVOjgdpqaidNhs6Bxsl4p7JQ1wavDdlnFl2LUorKOFwzYen7U5QxK6zTWG2QD9yQVQICEY81ClJkZjIvXt0G3zIPvVjCuAqjKybTGRsbG2QtLq8ZIblqY1fNtJgQCkKYcy41yFBV1SoHSGlJeh7dbMdCZYxwaFIqybtKroOUxyjABy/OrNpQ1ZbkB0IAqzJaJWqrcBr6ecezL36cS1ef5q233yWTuXr1Kp/9sX+FerIr3wGVOT58wD/6+7/A/TvvsrvXcP3KNXxICG9XeFpKwdD50uwrcox8++u/R04tL7/8CnduH1G7GbWbyGgmC/+mMhSpuAIcR4f7HB084OMffZaLF3YxxvGPf/23uXFnHx9h1hiqesKyDdgqM9twbE9qQvAcnczpg0fbhFEOq63EMXjPw4dL3r11h647oZlC07Rc3rvASy9c4+HDBct2ICRFXTfs7GxwfHzM4eE+WkVuvfeQ46NDNBV1Oc8nkwZrG9AOcMIdy4lccsBUyeQRlY8mZQlKDdHivZy9167v8fD+CX2bSEmTxmK9Ki3nrtcF+T6lAsjYyQ/CmUrJAbrI44tv0riXP7CIr7cBZ+vd+N/vAozIfQon6DF0ZXz9Z/Z2dv8ffN+1Rfnq3bDqn1JOfJcdPbZ9Xw3Kz/3cz33XvzdNw9/4G3+Dv/E3/sYH3ue5557jH/7Df/j9PO133VaGZo+NcUqXiyw186pmPn5wznyY5z7Zx4ieeX0f56GrU9mxKmjLkxCO9dd9+kSnjqx6jDDm9LGrh5dmZ72LXW9SRrMqIQgmSqrciAcKZF0UNSEGtre32buww63mNnfu3iPnzDB4co4F3hZH2t3dXba2tlgulywWi+LeSTn2FDlbAEJJmB75N4Lfi5RUsdVMuXZxhyvbFc63LO/f5KRd8ojE/kkrEtXbRyhjePnaFpUxWMSxUpo+0e9bp0ixqIMAirmc9x5bWVQZpYQQMEAOEZOFb9K1LctWcoa891itCUFGDkmL2kVT/D66nsEPxFyBEVmwUgZjHUkJv8KHUN6rONY29aQYuw3yWRjxoknFuM45R1YKZc3q3FVl/q2UFthfiVpEkWU0osRpFQUhRbGdz5rOR5KpSEqtogusdSKBDZKbElIq+TcS2hhjJA1jcdIkXwzmtEarJPvJGleVsQSKoZMgxaTUyl1XFQa1UmIMpY2gBymK1DbEIKPL8uMqRWUMmozTUBtBEJ2yNM4wcYrKZCa1hqrh4pblfiskWOO09CDRklMsKeGWGHyRMVuW8148YdSAcTXkRJUT17cbtmuDH8Q92WfDtKmxJTOpmQgSllOQJiJplJExXanf5XqyDrWPyjRpSmz53oYgkQZaG5wtAZJZrPt7L6GMdVVhtXBTRg+NkUUWY0AZLQ66/QCIcV5W0IfMu+/e4Cvfeo+jR0dsbFheeuVlXnz540ADOTG0R3zty79J6A+ZVIrptOGTP/wjmN/9PI+OH5BVwtqMUo4YQCuDz4nF/IQvfuE3eOrZS0xmW9x78Ab90KOUQ2U4PDih0pqnnnmW2wcDGA9GSMH37t/n6rVXmG5M+M6bN3jnvQeEpDA6sjFzLJdzFB5nHX3XM9mbUdWK45NjQfJiL9k/SkOOGON4cO+YgUjTbFFZIGsODw/Y3Z2QVc+kDbiqYjrbIvsDhv4AYkvbBZKr2JhskmJkOpkSQhQXbeXwsaAmxXdGxqbCy1IEUJacpaHOQE6K3ivapefSJcfT17a5e+uQZZtIypCzKLpGI7NxEZZKbU4r5czIVZF75IKCyqWr2AuUc2CcvpzaY6ytuQsaPdaiU+Tl8e27tQGr2rPiDzz57ytOFUIUf3x78mPP3pqgqDcFFf/eLfZ/oLN4xm01dzuPUGiZl44X0Q+UOeWzxJ7H/5zXCv9421k0ZtzWvVTW+Rrr457z+16/7/n/l3tBITvJyCSSxw9cpVPQZs2XZEQ4RufH8eQa0ZxQxiZVZZlMJlRNxWwmWRFVVeN9v3KCbZqG3d1dLl26xMHBQVkxy7gmo/FRLiw5tqjsZQyB5ELkDFYbNieOS9sbXGgamtCS7t5hsZyzbCM+Z/oMPmQClsM28frNfTLw3F7NVAWMioQUS2G3KDI6lwTlNb+VkbPhfSRngedTyign1vLWGKba0i7nDD7iXE1SohLyg8c5Q2UdOSaO50t834sRWMp0gzQ8KSqmTSUOt4jzqNaKPkjku/MDPmfiMKCtwVlN7z3GCkfBx4CxVrJqQgSUoBJJxlV1U4khGUjjqqW5EAm1KJd8DvQxE7Vj2XlOlkt8FEWWq1yxgB9QWlNXjqrcZgsKk1cNJsVtVgvxrnyfxMNDPj+R7GZMWf0rpaCcG6Z8L0Z+T5ZrEbYUaFKCGNFGkByrEGKrySgCtdNMnGFiNZNKUztFXVsa4/j4cxe48eAmvpfE6UUUsynnFD54QpZs15QSQy/Nh7MOrAS4EQMbJvL8pQ1UHuhDIGuHR7NhKyaTms3NmTRMVhG8kuToXIItkcBCo3SZJOdyjp0aEq5/T0eDwowqElYZ14zOzCL377DWMG2mVM4SfC8Ak9LE4CGJlDWmjKsqQgKrK/o48OBggVre5a13b2KTkKF/+DM/SjO7iAKiH/jd3/qnfP5f/CM0gRB6nnnmWV773B/lvVvv4pkTo3CEhkGx/+gePhxj7Da3b77PrVvv8slPfxytG/YuXBBn6JhJAabTDXLMzJdLppsbXJjC0Ncsjjx9gvnQkR495CvfeINlJ5BmUyeuXJzR9WNIZWS5DLjqQlGRddhK0S+GstgQBEtpzRA0rtmjdjXEJbVzBN/i/YKLlzY5PknEnLC2ZXOzorIzcmjRKJpalDfa9jz3/CWOHnkOHiUGXxQ1xkMOoCOVtXRdT4oe4xQkhU9i1JYLBBJ85OiwpbaRp67sUT+1y/t3DulQ9EMgFaKsxGgUnlIuwak5yni28JbOgx2CQMo1/BRvGCH5U0RmpdZcmwT8QduTPKrOIO7yh+9pX+NrHtuh9Vp6pi5+wGPTudfyvW4/0A3KafFnBXeB/F98Cyifp1ikj6qU9e080fUMj+hcY3Fa9B+X+473fyIfJPPYfc6/j3LvD3htT3jN+Umn6bkT5glJlSPiIWRZj3GyAnDOsbOzjTWS1huCJwa/8piomwrnjEDqK96EvA7nRE4nhPWKCGQjHICGxKVJzU6t0WHJycMbLNsOm4Q8qE2F8hGdPTonjEn0IbO/gOGdh/hum1ef26ZhSVXSM4fOC5qipEEaC0qMGT/0GCNjM2Nktmy1YYiRVObtOouFe+49ddMIApITzo52/lpIuDGRlMbVE5ppTdsuSMnQDz0xZ3acFU8HJwTZFBPZSaie1gZb1djKCWqBqHVkxZjYmE6IIQhrX4taaEQ4ct+X4i9uliiDsULoTFGRlSbhWHQDfTbMu8QQFdY1ohpQkqETkpA3CYrBiyGVKYTiEf2ytiryzVSkxhKw1vUDcfAoY8Qjwlj6wWMRRE2yTqToGqVKwzPm2AgZtzKVcKxUxpVGTeeE1RFnFLNJRWM0VsPUGRonxNi60qASr15reO/6lIdDxWxzylt3jskpUxnNctGSssbVUwbvCSmKk23ygubERJ0TL13b4dlr23TzExZzj1LyfrRV7O5uUddVGVeIWi5Q8k6iBEKmLCM2lC4jFE1IAZSQjVFZFG+IYkvXtaAqMRGCELAz0qCpKDLx2kqjnKLkW1VVJeNTlYi9WPfLKEkk2E41ZA2P5kuaqHA6sTl1PP/c07z6iU+hTUXsO77wm/+Uf/orfweVFrIqz4ndCxdJqcK6hsl0KinmIbFcdnzrO7+DczU/9Mk/xp3b77G9O+OFF15EKc3lK5e4/tQ17t66TVM5KmeoZ4aoWi5evcIsGIblCd21Lfww5+1b71E3M07alqwyk0Zx/douk6m4AMfUklWFomJr9yJ3H9wn5Y7ZVBFaCalESYOotKYyNcbUBaHQjDw6ycUaeOaZ6xyfHAphVwe2rjdcuvQMt9+fs5gntrYaXnn1afYubtK3jm/8/j3u3xtIIRBTS9cfgYqkZNDOsL2zjdaOg/05o2urKHYkAKdvM4u5Ybkx4Ay88OwWxhoeHZzQdpn5ItB7QSuz0mSTiLnEOhQZaRprxtikKFipgArKIKOfcUGaz9Wf0+v8mQy3J1aPJ2+r+qTU99jmjE/wB+E04+J6pFyoM8VvzMd70jThu20/0A3KCiFYQzOkcucPaAxz6VTX5jhrXeBIKjqdppw9Qc62BGnt9tP7az3ev3wYxdF1nSh7vqkZ5+nrfcvZJuaUnLh2y2kXPr4Hxi49l6Xs2S58/TCMuSnVRKLZrTPUTY0fRufBpqwABcaeTifFkRRW5ORySAyekcaetUOhqOuKnVnNrlNwfEB394B2OSfmEhCXZeyTtCKaXCSBAqenrFh2iWFIfOPGI5pZzUef3kYNxziFNAGDrKDGVcWYXorS4iOg5XhoJdZwsVz0szaSShsTrq7pBi9Qe1YQJQ/HVZYYxeLdWUfIgHaEqMQvQ7siyTX4IIZgbT9gtKHWws9QxhKThOpVZWQzEiONNfS9mJuJkZkqK9tcFEtalDopUTkrDWA53ORcbPYzPlkeHC15eNxzvBjQ2rG12WCN8BrQppjZjcdCC/tWQc5iLpdQ0rwlwU9Ge/+sNEMYyCHJKEQLGXjkWBij0UqJqVUJVYzF9r9ycs44TblfxhmFNVBpI/9aTeMMTmcmztA4Q20UzmQqLVyUpzYMH7m2wTfvR/ooq90QAygR1ptxRFZQDWuLMWNK1HHgmb2Gj794jc1GBo7LpeQOoaFyhqZ2GFPMt1QpIiXjSkB5jVnL+LGjQRviXyIFM67g+pwFwRNJcll4KJFIawW1s9ROcoZi8OIPY53wmZR46diYGfpQxnWyio9EprNNtHHMF3Ma59i6ts0nPvlpLl2+Djnz9hvf4p/8v36JNMyZTh137j1AWculy9eZbuww3dhGHVhSUvgholAcHh3wa7/6D7l385AbN27xIz/2GWabDe/e+AZvvfMdjtsHzDZrQu+ZLxbMtmbYCjIdYVjSLY64dnmX/aPIfJhzdHhItgGtBnLKHC8GTpZHLOZLYpax7BBbVGPoFy0f+shzdDnx6MGCg7sDR8eewWdspen6juODJVVt2KsMITnAo4zCOkUzcVTVNlpFVE7MNgxbmxdJSfP2mw/xyXP3wSM8EecmfPyHX+L1b97nnXfeIeYeZcS8rZlUTOpNrJlwcij8LbmEjxwTkRWHlDg8GQjxEdNGsbvhuHpplxeeusjW9g6Dj7x74xYHx0vmy44uKJKWoMvR3FMpGXSMV+S0UjeKyIAztUE/ft2Wi++Z+gOjp8k6AvMHb2r17ymWsyoP4/p2fTE9LnZXk6EnP1M+vcPpcylRlq4lDH7P2w90g3Jae892I0qxIp6e38pITT7MnM80DuNOz6MmpyqesyF5uTz36Zhm/XM5bUbkJOTMPs83NhTOzAdLjTMjIfFUYvwEfstoBqMgF0j68UYml1l5oKo2V+ORvNb2aK1p6orptCEDk0nz2GsbybxC2kwiSY2ZvY0Jlzdqat9yfOs2qesIwyDQJ7lIazO6sqhmSqUd3fEJqh8KZyKTs2bpE8sh8qXv3MWoxIeuTElhgUERjcCmIvmVY6eU8EgUuRRGKZAxS1Og9eiCqrBKii7KoK2lWy4xUWONwhVysDai7Fn2A4EFOSnmC7HA397eZvABRabrBnofqIxYn/uY6NoOxgIHjLksSomXUPQehcJZK3B3iNjKlJWvjNCc0bKCT/K5mGLStmwHThaeQM3hyRH7B0u6IeAqxXRKaRAkD8daQTtykoRhCpenHwLGSrPog6BZKWdMVeFL6jJKvFKSF1O2um5WsRPCryiXRwVVZck5YnQp5BmMLo2JVlROzMtqragrQ+UUVicaZ2mskaC9nKitQSWRcW9Yw6WZYnF0yENvCDQkpUkRqskUoxU5JMiFbOtkvJe7jstbmh/50FW2G0kk9j7RTKYSa9A4Nmc1kqyt8CFhjMizNVn4Cams+rQWZGYVylY4REmUL9YYrBFuUIYSliifVQgSdGmU7MsaGfEJIqNWo2edxck550hdS+5OHPK4AiN5jzUzaX6GiCIS08DO5SsYV7OcH/Pbv/VPqFSP3aw4PllycDhn59Ildi5cZrq5xc7uJfw7EnsQUyIkzxB6SI5f+tv/d5567hm2tiNvvvstlkPPoltyPD8gJM+yWzCdakIyuGaG9wOLowW577lweZfNrYavvP4dkgpsbBlsspAVx4uOIWYgMtmakXIkpIHb92+yOdFUrqKqDAQFviUqw+FhR9e3DEMnSFayhBAJSVyRjVWAnGci1fa89MKzYALOTphuVBwvTzicdxy2hnfev0si01SbDEtY9AtGn5Pt7V3A0LeKk7Zl6DKaqox2hOuRlRFvJ53pI9AqhgjzZctysFy8sMm9wxtsb9Q8/fQOn7r4CikbDo5aHj464vbdfY7nLUMvxFqVRCicoJixlWKU8to19Sx6fro4fnJNk+XHd1fsnHIZ1+Ui8tjxeXjstic905ORe6mhnNYeTqca67Xyex1PjdsPfoNSttNRz0hUKiTZVW+R1+6nVichKq+gN/n72X2uP24s3qdeJh88LlLqyR/lB3FRgBWZ8IwS6bG3fE6B9NgBOUWETp+vWNavITg+DISYVtyBMTgwZUkXAYq65BReleCz1Tkoq/oRutTiiHppo+H6xOAP7nBy+IjcD8Sc8VmKlraGbBSuaZju7hGqRsYEruJk/4GYs0XhdYSUidnw4Cjwzbf3ubw55cpsSswtKkVZzWot+SDoFQJmV8RZdYqiyItk6Hu0EkVQKjXgZL6k63qMVmzMJizbnhi9HI8YReLc9jRVRdaiypgvWqwWEodSisqJfFGVfKHBB7SxtP3AMOSV5DanzLJtcQXmz4xurYmchXuQSoaQsqa8R/HjWPYerQxDyAxZczBvOVlG+h6Mramqmq7vUbnMHLIYs8WYqFxFioGuHXBVRVbFLl0JvOyDqInS4EmI5X1MFH6PnEN+OB0TOWMoXmt4PwiRVUtCsTXiBeGMJFg7LaMblaGxmtppmtpilKhCjBYyt7HCU0EGbRgyT1/e5tUXMl988xGHiznLbAkZrLVMasNGY7FJkK+YAjkmNmvFqy9c5fK2I4cOP2RA+FYqJJpKUzsLqFWuUMqQQlid82hxIRYzOknDlpGkNLoYucbkIsMf3YeNdmXEI9J2QTXTSJGUfwti40eVkJFsGmdr8UNJgyQ1Z2nAx0f7IYgRIJl65rhw6SopZL71+7/L4cMbXLq4wZ39h/RDpqo32NraKcGMkY98+OP87pd/A09PyOJ11IeeSzs7XL26h1GJd959gxDnVJMJizbS9pH9gyMIiWU30PeRoY10/ZyHtx+wt7XD3oVd3r55k+l0i+XRA2nCnGWxGGj7QNJCju7jIGRUo3n/1i2uX9pl2fbU05rloufgcM7hUeDouC/kblmkjIpA7xNNI+eHqxQxyVh2HIlcunyZGDRb2z0xaLoOQs7U05q+7zkOR0QfUNlgbM10ukUODUMXCT6TA+J0nMuCTqcCc4gyLCoxUYtYQrZ4ArcOB+4fP0ITaOwRs0nk8uWH7O3s8fQzz/Lyy9dR2nJ01PHee7e4ffsBBwcnLLtB+HalWZHrqLxPUbkIeVrphEIWYCmPHimnV/qxExAQ+TSg72xpWudA5lIf17GWJzU9aq1eUB53tm3JY1O0trCXi5VcT84OkD64Tv5B2w92g1LgfUaZbhnxCPRcCLLASDDNuRTsDJSCOW7iRSCW8jmd7nP194KerCMo4+2w1viUD1SY4QJBy0JNmo8Rzyjor1hjj8gEMuNed6CVS1OJwlKsouxX3relz6IEIwoSN/qWjHNMkUaKs2YxkCpQvTWWHEe/h3XfGIHjlC7yt5zIWa8gSl08yweVsFnC0C5tb3K9SbB/h4P7DxlC8SxR4ElEZajqGRsXLqKbCQ9jpu081zcUF6aJS3rKnYeJRe9llpvkSxCCZv8k8vrNA9LVKRe3GqyK2Fxku0rcYo0zoOXClGIkxURdOawec2VAaUtVWTYmFWRpJNphlHkqIcL64iJvrYxcUhDeTgnyQyGmbJXFGsV0MsGbQRoUJY6Z2jop5tbRdx3tEKjrCmfEy0UpKajSPDiIShAZLb4iKXtyTviUsdahjGM572XlbhxBax4eH3N00pOzLXJKT0wweE4vMFHQGKUTRluGzhOzl8YujEF+auXfkVKWvBsvPJWqqtbOwYgAZVqkzzqfBkBqcYV1RmM0kCKVVWKzbzWVBqsMlYVpY3FGYdBonamsKeF6YhintcYr4fJMDXzulYtsbm7wa195n3ePAn1QtH2gb2F6eVOOl09UMTK1iY+9cJlnL2+iVaSqLNYkQi3RAoqaSVNRV3YFp0ogpZjm6cK3GdO6U46i7MkKCsrokyAvI7ieUxROSRLukUZGWM6ach7Lftu2Q2tR9hhrSV4k/c5AjB5talQW3smy94TsOO4UhyGzHGAy2eLWo0MqV5HbRBwUN998ky/+i39M6g9RdY1xG9x/eJOtrW1O5nO+8bUvc3S4YO/iZV5+8WN8+fd/g5QTMYsCZd6d4GYVd289ZHtng+29qfgN6YRzFc10SrscaIfI8dGco/uPCKHFJbhy7SkOlz2vv/s+9bShPe5QObE48fghEbxH20xURTljFJV1DG3i0cGCZlKh5wNDn5jPM+0y0i4lYFMCIaXZrYyBgFy7rBDMQwp07YJr13bQNqNypKoq9nb2uLhzheXSIvEVCUeP1h0bM00MBqNmKF8TenmcIZK0nO9KG8ilDmQhcgvoK69HAUZpxoT1lDWJmi5H7GRg+8pF3nrrDr//rfeYTDVXLmxz/dJlnr12gRefu0SIieOjEw6Plty6vc+jwyXHy5YQMyGDSqWFyInKBj7xiVdQSvHmm7c4POpIGHHIyQqFKaOhwkxfawxW/65Wkut1cx3JKLaajy32x7+XpmdlVTsOl9YM3DKMohH5TpzyY8bJwPePncj2g92gcIoojI3D2O1prVax7uvQ0hOJp6Xx0+Ph1QrOISDSlIyz5vURz9ltbFJk3HOWWJtW0EN50rzWDoxwrz475sllJq7WDNzG8ZRae9zoODjuI8a49vqlqz1tnhKhmFk5V51KT8+FJ47HVmlFTpCKfboqF+cRgs7A9qTiokss7tzh5GCfEGRuK1E6GlVP2Nraha0dHqVIaDuGIaO0I1GzubFJrT2zy5tk5tw7aWmVICnGWrqk+Pp7B9x+eMirL1zilWcuYzMMQyJbLTEYWmN0Jnu5qMQMiy6gyqjLOs1sVpN1pPed+O1Gz+bElouTyFZzQZGcMUUVaKEQWF3hdESdQWlRx3hPTJFKiWw1xVjgfL0y5zLayNjDGJy2sJJxj7C7NLUkQVsUsoJMKTH4SFIJtBFoOQQetfD27QW9T8xqRUgDjVZM6opYUJPx/BvVJSAIlpzPMgLsfY9VMqKQUZR89tYI0qVyXpF45XHF+C1GnHUF8dCk4DEqYY00bTpD4yxGWTRZ5OJGMW0cdWWFzJskZTakhMkWhci9c/aEGEqD6NieNPzwRy9jJht84Rvv8f6DE2I2bG1vMW8XdPMTNivFM5e2+NDzV3nq4iY6thgF09kGdVVJCkmW0Yvk5BhyGSfq0syZgliFHOScZVzQiOTcWk0M8n2IJHLShJAYBs8QDbMN4XNpwBlLyKmMyyQ8MuuMTx5rHV2Q5qSuKrZmM0I/0KVI5z3LNNAbw+2HLTfuHKK3L3Fz+Yhb9x6wXHiWeMxiyS/84t9mUlni4hCrB3Yvf4Qfe+2TvPve/5O2P+Kzn/os/8af+rO8f+s+/8Pf/L8R6Tg8aAnZ42LAT2oGY/DKc9wd0z4YcNVVNk1D6gImi6NxTuLdEb0iDDIO29ieosh89Stf58G9fXYv7mAxxFjGds7StonZ5gRXGw6ODkgxC5+JTNtFQupx1uE9+CCfvVyuhHljXcTWGtvIwkOuzRSEsiPhmc0q6kbjw0ClG6bThgsXLqKVoE8hRYyZiEpHa8xozoa4so5XutMakVc/SmW00hhlgVAQd49S4CoxP6wnmYuXdnjmmee5c/dN3CTy4keucPPGXebzBe/cvcsbNx+gck1TVVy8sMnlC1tcvrzNi89dweiGw+Mj7u8/5NHBMSfHQ/FpUkxnFR/76FUOT47Z2XuZr/7+e9y9Py+LhGLtgJMmZa2mqTUH8A8ipZ7lVz5ex84/blwkrxWH1QL58ceeHSHlUhBXlfcDpgNP2n7AG5R1TkYssBOnHBRgvTk5IzVWaz9ZMAm50+NHfNVkpFVNXhX7800MjM3Jk1/v+fuP9tfrr2+N8nL6HtZ5MZx9zPldP5njsravcqporRmGAe8HloslbdsWvgIYkzAaQqglcTUJ9JhW3hCyN6M0jTFc22yID25z8ugRQwCyJhFJrkJXM2a7e3jreLRoWcaE0RliQunI/WPPbJq4bis2J558cUr0A3cXkQgYC62PLHvFfMgctg94eDLw4ad2yKYmpU5m0nocT5mVI+4QpcDXVjgqMQykCC0iH22cZeIc0Xvq6YycAt1yzvb2Nn3flRweyTdqmrpIQ70QQ72ncqagS7nctyhlkljV9/2ikDg1tpZE3pDG/B6LNcLLMdahkxAzh85jbHGIVZqEZtF2DEkRsDw8Hnjn7pKDeaBuajBgHUwaR+Us0VjariPEuEJGRvmjtRZyFl+WlPA+gpW05lXuTLGzF8l2OnP+GC0BedZqpk0lF8oYGHzEIORWo0Alke5aLcELxlCSimU1lhFUQSuLUtD5hI5qRd5WSuMTuNowrSo2as2nX7rIhU3LW+/vs38y4HHc2e+oNho+9MwlXrq+x8XtCbVTxAA5J5rKUTdVUdpIOKUQ0iX1WhWp34h2ppxW38lxcTO+/xizXPyzQOUxRlI8XT3KaEg+dxUTPkkTE2PCmAq0qOd6H8hZmiOMYr4YSCFy2LXMfeSoD7xz95Df//ZtHp1Etq5Fbi965v2cfvD07QA68YUvfJ6Le5tc2dvmheef48f+0J+gjxPqyYzdC5tcuHyRutlF6WMePLjPW+++CToz2840U5htNUztBI8napg1DQ8eHDD0gcpZhrYldAMqZ/puoGsD/ZDZ3m5wruHu3YfcuHETnwKEyGd/+NPcv/+It996v1xLAkdHJ1y8vMv25g6HR4foLMnN2mqsE7v5PAS6bimcHYTobEymajKzWUVT1WIcWXg/4qId2dioaSYVVWULB8pT1XUJaFSkFGSBl4AktgcpSp0Qz6a4toBUgqqX21iLClmhAMpjbCLrjs2dmu29hudeuMwnP/kxcrb80i9+lZt3bvHMM09x+emaq6pCm4a2d9y/1XK4P+edG3d5771bTJxjUk/Y273AxnbN9asXeenZp0ErQhwwRnGyWPLw3n3ev/s+R8uWq09fZ9HPOTmO5CSmjuhU6sT6dzWx3gN8d+XM6aL0MdRkvYacG/Ccr2XjlEI94W/nLe7/1zPiWeNcADLKUIVsaopJEpxBNOR+p/CXWivqq72qU4gM5IshZmQleXLVoMhrWJdPjSe8dLhl1DKe5Guw2KqJODPDW72T1czw9GSR2wGRs+a8srv/IPDsDH9m7HbKatFakRM/eLDPYnHC/v4jDg4OGYYBcvl7qDFW0zSNPLRwKABimWeaDJdmDa6bc3i0jw+BnKyMgrTDzHaZXrzCcmh51LWEpDHI2ESZyPbOhOQ9B0EzUY6KyPMXZ1hjaN++L0FmiA9HSIrgNUHBV9894O7DOVf3Gp67ukllIgQx2jLWYgqa5pzCZwQN0IVzAAxhHGtYUkwyf+464X4UJQ3aSMJvLiviIh/OSgr+4CPLtmdne4PoB/IKhcqrGd56sVNK0fUdpISzhkldg7Wi+lHSrFpnUKaQV7OE6/U50vpMFxK9d9x7OOfm7SWLABt4ZrWhqhtsZen7AWMdzrmV828sP2PGj6B0pvwkBh/IQG0qUawUqFgpUfXkdIqeKMSKvnbCIUkxQozUTjOtHU1tyQX9qK0WHxAknVUXcnSMCAKRZYVKqSG5cHGg2ARkQ24qJsYxrQyTWmHzlJ3G8c7tRxwtA89cvM7e1pTtxrDdaCZVoq4d2s6IIZFjEh6Mtas+v++61Xdm9EtSprjoxlh4WadNfAihoFDgrMZYJBxQZSH1qgrjFMPQy6o9SlMdAixaccJtGnHdbbtQZPzC+6kq+VxCijw8XnDzwZz9Rc9bNx9wd38JbkajHabxoAdmGw1hENLofNFDjlij+Dc/9WO8/JFP8xuf/z129i6ibUvVzLi3f4e/+/d/kRu3bgiKkxT90LG5Y6mmCza3t2gmU5rGMdusGdrAzVt3uXThIpU2bDQTuj7g8bR9x9HxCcps0A49N27eI3pR1bzy8rN43/HWW29xeCTHYbJRs1guuXN/n0sXL2FcjQ8BEwzEyDB4yJrgReaulZCprTUYm5g2MKlqSBrhFWcqV5BSNBf2duXapAQBNRbqRrO5NeHenaUsKJMqsvqywlSChCpNSXRfs4wglGJ6ij7mEeXOCa0j2zsVH/rws1y5vsmV67ts726wvb3Be+/cI0bNwWHPxUuRT3zqY9QN3LvziPffO6SeJLb2HDtbe+QI77x5h4OTnpsP7qDMwKT+DjsbNZcubbO13VBZS86abgjkbFkulwzqBs++eInb78853I8kXOGrFbpCNiBCeVZ0hrXJwfeKXMh9P/CvpWY9YRLB+Xq2Nmb6QGXtd99+sBuUgjZofTozGw1h9Nh9rMmQlf7APQnkXPa5vqWUZbyR0upkPj8KWSe+jo3FmSbxXMO4ru7hzLzvdH+rk2tsLPLpazt9/JNUPGNztQbf5Vxq5qn8cWO2ATnT9R3LwnuJITP0nhiDGF3lSFU5WXGHQNZK1DhJViFGKSbOsK0jywf3GYYgqpMsPhx2sklz4QoP+4FuaBmy9PkqZpIKNDOYTnoGozg48VRVRWMCOwa2asW1zYa0GDjyUQibWRAGHzQhG5YPPfcOB/aPej787C5PXdhB+Y449FJEUOQopDrIDDmDL4m6xlK7hpQzXRxIUWTIjTVUznJ0siwrYosPo2oqMfiW2XQqAWNoeh+ZLzsqq5jNZuQYCb5HWbGxDrnDKE1dN4Qos2Nri/GbD4WobCT3iEQ7tMXETaTY/SANz7KPDF4xDIqHD3sW8wyVxlmL0ZoYAzFJmrNJ4pPgnKPv+3Leis+K1jLi8MXt1BhDCKmM+MSvo3KuIIaxPEZcT21dSVOq1MrTpAh2qKuKjdkEaxR962VswkjKg9GsLCaFcxU+eAbvhUNkLVXdiPHd2Lg7R0TT+cxGkpm/MdA4w8YkcWGrYdpEdjanKyTHGtBWoZ3FWStIio9nxqrGiGGfjC4l30gpQbGU1hjtVty1kfirnCUXk7wRiSFnKqdpmgnLtqMfIvPeswyZ1iu6sOToaM7R4TG7u9tsbmYODg8JIWKqipOTBctFT4yJelrTec+dB4c8eDQQleXR8QlRV6QQ2Nzd5FMf/xTHv/xr3Ls7xzqN71RRZkXQNU89/wpR19x/cJ+26zi494Cj49/g1//lb/Od11+n69sCFCv8oDg68FSzAT/Av/q5P8qVnXe4eeM9QljSbG6xf7hgdzajtg19v5BGwMCy6wkHmaPj+xwdLUlZ/Gy2d2Z86Utf4+h4SdYV1dQy225IxtN1meNFRwhF2RUE8R6Ksm9MY9+YGpqmZmtrhnOSJmxtxTB4vA/UlaiYgoo4O+Hq5cs0tYMkI26tFFUFV65NeffdBzCo1bU751BQkiwI3gr5Gm0g1gwwT5UVhdcopNWq1vzJP/mHefWTT+HqzGS6yYOHD9l/OGd/f07KjqOjY9597z6bWw2TacXtW4+4fesRIQZSHHAzxY98+rNMZxO+/Ds3yTFRTWumOxMmW1OOo+fm23fp2xO2Nif82Od+lPfu3aH1AdMFMve4cu0ydR24f3cJ3pbXm1GqBAmuQPLThfOTlKHf65ZXheQUYVFPmCCcewSsLQLGacf3g57AD3iDcpbjcdq8jSjKGXTkHCoy3u/87+u3pUJwO32e05P3MXTiCftbf43iLVIa3TX0ZDU9VKcf5koiPc6rTv8Z73zmfa+eawXXyap1vMN4P4UB5dFai3tsVRFjYDqbAYq+H3j4MND1sbDo88qQq+s6Yk4SfBZlpRFyZjadQX9M6Fp8SMSsyAaMm1BduMB+37LoenyS5kVlyQFSVWRjY0o3HJLShHmf2LSOhdHsD5Gu63nm4hZ9Oua47wi5jA6yfCYeA1rRAm/eGzhc7vOZVyc8tTtF54iJmRzlglgrGWkoZeiGnqH3OAfTRmDcWOzJY5KiHBIYLyFw1jliygzBU1eWvvco46krSWDuk2cInt3tDZyXQDyMpR8CCsMwBOrKsew7KWol70cbSQ3OKGKQzJWMNNjDMMhxxOBTRdsGTo46lvOIT5n5SUJrcI2mqSziFyaSW1Ma0kgsyivxdJFIecmNMZUj9IPYrRuDc3nV5CslAWwplsylKFiZtoamqnBWEb3HaXGR1UaRQsbq06ykMZPJWCc28NbgCzrRDgnnhCMzJiQ3RrO1sUEzmQh3SgFK44cgTWbKkumjDFEZtM1sbDY03rM3sygNAUXWGuWEW0LhguWCghFHBIeCgEkYoFaQlYwDtTIrpNIWG/9MEvRn5BPpEjWBImnoouckJG4/OGHuDY/mnndv3efh4QnHJ0v6PrCxMcNVjuOTI5TS2Komxkzb9mKYRyKpjA+ZGAzaBFGw4ck2sXNpyt7FKT/yoz/ErfcX/P7vfYvBz8lJiMk/8cf+BC+8/FGSMjx8eJ+vf/PrhDigNVQTK9/dGKnqCrkCVSign3v2ti7whz73r/ETr13gjbe/ytHxQ2Ksefs77/Bb/+Kf0h52DCGwc2GLvl/gTxaYtufwREaX2IQyTlQ4hwux8p84MgFnLXt7e8xPeuGv9BE3kQZQJNuJlAJVpXGVYWNWsbuzwfPPP8Xu3jZt2/Pg4QGHB4fkJONJbXqcU1y7coXNjQ2ctaQ4Jm0ntO546rkpL+5PeOM7j5gfOVTQ5FTyj1SGpFZrP9liuVafBpuORVau3QHIaJ25cv0ily9fkKB3pjx88D6/+Zv/gjt3H9IuI/3Qs//ogAf7uwy3E4t5z9GJZH1durzLtaf32NozfOwTz/P66zfZ2t7mox9/iWQU9+4f8Nbr73F4MMeogclWw/HyhECiD5GGmpPFwDDc4/KlSzTNFu+/Nyd4OZZSGkwh8J6lNYzv5bRGnXIlz2+P1bFV/cyPLbYf356ErJy7x/fRJ/1gNygrTkjp5PL6hyK+BhRnzdMP5Jzl77kPY12dI81JSY7NJZlyrQs8KytW527LK6RFKUEOclagTjvaccZ0+npHB1xBNM6AZ5mCmKzNBte65PNn2hm+zdp7EzgwlzGYxhjHjpFVSBgk92SxOC48AMgpEHxEF/twN6lR0wnD0EPo2agsuk+rL7xBEYxjcvkyQ+XIw0A9tRivGUIkD2JQtjFrSMkzX3TszDZ4Zm+DPec4frTPvfstWzlwbcfx1MVNDgZPv4zFVCzLsYyFhKsNRlc86jJf+vYd3pxGPvTsRa7ubKP9gPGe3LVYpfA5oVTCOgUq4aOsqpSxUpzUmBghpmaiFgAfwdpagv98IsyXTJoarSD4zDBEYEmYZSZ1hbOSrNx2S/reU1UNKAtKbK99TAQvPinTSYPGMF8sV6dw7z0S6a7olpHDR0u645bF0UAbPEOXUFajHYQ0kKPBZEdlHApkla60rCq1omkaUkol70TgdMr3RkzXxMMkhCDur0pBSmiUqKCsKd4mAYXwZrSGSVNJNpJ2K66JypI7pND0IUJWDJ04pgqC4Vh23cqXBm1JyuCzwmZQVozMBLVRxCHgfS8qIWPovaho6toyKY6zQjOQ740uzraQi1RdRnU5B4lGiBmlbJmpS6OirSHGACmjlVvxiLSSy6OxMq7TRjN4L9ycnAko5n3g4TLwzsMl79484u7+CcfLjkhiCJEhJB4+eCSkfS1utHkxYEvgYgzlu6gLB0ZRYgTE/6aaOuptw92DG3z41Y/ykQ9f4J033mO5HOj8QNNUfPKHfojpxiZDUBwePCLFnumsAqD3mcVywDjNdGbxXhyXQZP7jPaGyk7Y2brMpz71h8k5QHS89ume7BW/+It/i2Ho+X+T9x/PtmzZeS/2my4zl9n+2GvLGwCsAkD3aKDHkF5IoSeFGgpFKEIN/VNqqK+OFKGGgtJ7ahBU6JGEHkmABFgFU1W3qq49/my/TJrp1Bgzc6197rlAgb0bzKp9z97L5MqVOXPOMb7xje9bdRvqytI0FmM91UxhK8e29UQ0T59cMZsdoE3F/fsPePb8JbeXHfP5koPmgF53DK1n0cyZ1QbjNCFaXKVZLCsePTzh8KhmsXAcHtacnNQoFhyf1KzXS5xrMKqi7zfc3qzIsdgsJHBVjU4BH3synoPDhr//j7/B4XHNn/3JC67PHSlWwIgiGrnLVenemhZVIc4mmAQ2x4k2Z1EGfvH8gnfePWO1vuan/+kX/Mkf/5RNtwaVpFW80oQYubpec3V5S7f2qCyootNb7Hdq+qHl+N6SD79zwsNHjzB15slnT3nx/IrbmzXDMFBVifV24PyipeslWen6BAl81xHjMx49fMw3v3PIZ59c4jsh4QutwEzHfTcQ2QUnsEP7f5PtLjVzJBjv1pxdo8YuQLm7turpsb8NjvO1DlCmYsad2o0q0tzmji/Om5uUPhTSbjwaGY0nmmkCHyXBY+F87Opvbw9sZB+7x0akZCzJjCWWHbl1Vw4aW5Gn597goewTYsf97b71+N+7QdN+QKaUmmr8shM5f5WtOD46gQ8S8/mMzfqG9epWmPGVKMzOl3OODg84OTyhntVs2g2XL56Rr65ZP3nJ0A8iLGIMs8Uhy3v32JI5XpxhjWO97rhdrRi2PX7osc5gdeSkOeLd2SHNkLm9fM3F+RVX60BYVpzGxKKueO9kyXV7wwaFV+Vcp0gqAVTMmWQV50FxtYpcrF/xwYMlj47nvHvvmNn8gOR76LconfAxk7K0quYsKqOmKKw6rbGuwihBM9pWnIoX1hFSZoiZShuGKF0qWQuiE5MmZE3nhZSrlCURiVnjo2hdmKLcmguSk0tdOzpFOwjPKUZo20QKcj7bVeD6Yg1DJvYKH4JIptcGnUXsyRkthMBcUVU1OQ+CwhTzQedcUdfdoSQyud9FBCdieeE4OWOLOByiuIoS0bGpE6bozBjhbMQkwniz2QKlDW3bk5GAK8WEMZaKhHEVzWKOMUI0tnVDwtCHJA7ECpSo5RPLzdEFTxwMvhAfDUKyjUV0yyiD1QqrdveCscIXEtO/TPSlLKog+EgunVriiC1t9hROSkYVsXHhzIh2jmYImRCSOFqjOF+1PL/q+fzVip998pQhaJQG4wwxQUxS1tLGFdl7ceMeUVUfgiwg2gi3rMwBKQJWc3h6zNPXT7nPGT/+8Xdx3Ofe/Xu8Pr9GBTEeXMznomo8RLa3K2aVYXFQ0XWBi8sNKSmamWG+qNluYbvdYK3YNLx88YLLy1csFu+BWiCGeYqqNrzz7jc4Oj7h9euXhQxsUFiOTuY0CyXGwOqMvk1c32xZHB7yYOEkyXqpiD2s+o7Do5qqytRNBjWQtaNq5sx0hY8DMQVO753xwx98Gz9siHEovJLEfLGgbmYYU5GjZf2s5a/+6lPe/8YR3/+tbyBaKZbKWVCZGBMxdjin+PDbB9TVgv/xX3/KzdWWmDIaQ4oleS1lkXGulJEjQe9UwZgmeIX3in/9P/wHXjx/yatXL3n+7JyuVWg7w7iIq0Arj/eZy/Oem5uWMESMsri6ZrXy/Pxnn/Hs2ef8+Ec/5jvfe8zL52ue/foJF6+vuL5YEbyaOCV9B6t1P5UkddSlQ09MJZ+lp7zz+F3e//CMJ5/e4HvpSNstUXdg97f8+zcHKF9dktnRCCQIuhv83HmlmkQxyHuJ+2+yfc0DFKTKnfeDgbFMokeAYvoZN2kdHHX87p7MXXAy8k4gTlLWu5rK2wi2O6LsVyjZ5t3r8y4qmco5E3KidrooXzU8JCreU3ZVirE1+u7nvr1GmFPa7Twr6qri4YNH3Ds7xQ8d6/UNMXmWyzmnJ8ccnhxxdnLC2fEJh8dHaAPrq3P+zT//7/j3n3wkbpzakKylPjzk+OSU+8s59x/cZzafcXFxxdNnz7m+vqFtO7zvqaLl0XKOWa05f/6Cvg/gE0YprjcD57Mt33hQ8eHZgvObFZ+tEx0iulaTduQwJUhASJkAXKwz2MCnry/4Zm/41gcPeHB8xqy7JW2uCV1HN0S2vQQqQ/AoIs4ZlMls1lu0RgjDqNL5IuTklDIxZlKEoGHwZaHWDh+kXEQWefiMQdsKHxM6RHxORfSsKFQWHopPmW5IhKDpuszqxpMHCG1L7jJ5UOSk8V5KEU5nwpCoFpU4Aquiomo0xjlcSgzDwND1xAx1vTNRtFaIdZVzALRtVwKZooKahL+hi46Q1oqYhMxYzypsWdyNUbKo612SMPhAra2c096zbntCkPbomDImilCXcxWLg0MJRPoBWznQBm0cKOQ9UitjyAlCwhAZhk6GuVaTGJ3SxTe7kFa1VoKYlO4crbMkIAqylYk05YwqpNeUoO9L0GMFtYxJyk+hcLGsrehjIA+Jtg/cbDr6PDBkzWfPXvPLz17w2fNLhmxIRpRnhxiJSZERPs/Q79Q0R0uK0Sgyk/HBk9GixpwT1jh05agXc3w0nJ18i29/8/e4vhw4OTllNqsJMVNXNWenZ+Id5QN9u+XwYImtDefn1+ScWSxrmrmgXnXVMJt3WAfvPnqHlCJ/+C//Of/t//KA+/d/UJKoTNKJ09P7HB+esNncQtb4IbGOG2w9UM0PqKoGRUWKCWU7Xl1fcsyclDy60lRzKf8Zl5kvG5JeYG2FMUn4JdWcoYXXr2/4w3/xR1xebDg5PuLl82c0Tc3gt7hK1Is3m471ref81TkxwGzhSNlSVaVkpGoqa+nzlr7foI2haQzvvr/gH//Bh3z22WvW68jlRcvt9QCpJscdcp1zKgupEMSn/DUDxak8R8XL52suzn8uc3MSF+0YImHQ9F2gqmeonFld98Qga4FPidRB01iOju+hzZaXr58yn5/wxdNnXF0OrG4GYtIoLVpIxtQMPnF9c8HJ8YLLqwwkbCXeWYMf2KwTX3z+nPfe/Qbf+s4jPvnlc4ahLDT/GXyTv46qsP/8V7/mbnlnty5Ob5oqBr/p9rUOUO52ssB4YvQUoOjd41m6OPbezZ06497JF2JsETSLRWm21N+mOPGN8sm+SBuoyThtx1+Rz7vLkxnprDuBtF1wtTvWAtTt9lUe3e1zV1ZSI4ymxkAo3X1N3s8Wdt9HK2HPu1kDasnR8QHGwGLRsFwuaJqG5eEBy6NDjk+OOTycYx7e4y/+1b8heoHZQzlHzWLBvfsPODg75ez+PWaNo6kcve9AQWUMVZqxoMdfPOf64py+9SgsJmsqk7B1TY8iq8TCKT44nXPZruliloqxlsWpsgaTpbyQjaaPCmUNLZbZ8THPY8Vnv3zKu8czfuude7xzf0l9e41ercixo/dxylp3ULtkslUzk0A1htKdlDHGYqybhNtChBAjSvX0wyBGcFpg3n4YIMuElwoZNgfpmqF4U7RDROVICpp2E9hcd6yut+ChUoYKh5LqA2PIqkFaEGJCYaSTJotOTYoDSlECEoEhRBOH8t2k/DIhJkqJRoQxIu0fE6mI/o38IxDHaKM0xij8kNGmknZzIGmN0YYQA8O2px+CfEdtQRspWWVINmPrmmaxwNUV1jmqpp7utVAk95USU8eM8BuykoCBFHHWFPsAEVqLiMqrHce8RDBQVEhVFs8VY614NyHideIPKEKFKUVE1j8TUhiXJyENJ8gh0/aB1dazaT0fP3vNpy9v6EPidtPRh0y2DTlkMpqbTVsQK1O4PLJghCifr5UqpOQyR+iiKJqkBBRyQtWKw9MjNm3PojvmWx/8fXxfM/QtTTMXKwal6TrPkycvqBfvcH5+zWp1Q+U0wxCxrmJ+mDk7m+PDFudqlgcNi6MK5+DRg8dURvHv/90fcXN1ze/9/v+cx+98h6OjM9xIFs7SEj+ESM5I8AoQElevb6gXh1zf3DKfz3l97ck3W5QSUmvvRSG4vbzBrQ2HR0fM5oekuMbVmtmi4vzimtfnG4w2/NG/+XNImq7tqJwiqYhWBmMzTTOn3SZSgMrVfPLxBZ98fM53vvsettIiUa80ziZWfoWKmVlzRDVX/PCH9/nwmydcX0d+8bPX/OVPn9K3oj808jXkJwkjYMKmi0BmLth3VuRkCb7MF4AohhtScBAtfQrCy8qgspMOrRAJQ+TmuuPp03O+850HVFXNcjmj7TesNh0xGaqmIgHWOVI0bDa3XFxdsDisePz4AZdXwmGqqhnDMNC1HTFknjz5gseP3uXs/gEvnm4lyJzWI0CNGrN3t4nqMD4xrnNv/H5nnZveW9abgvLvFXbeAFHuwFD8bbevdYCyX1bbCZWJ7sP4A3r3XC7sfMZWUMhEYo6iNFq4LDmWfvucp1Zh+QymyHTsbthHTUbiqipkPF2i71wGepJK+Ze+hVJmmph37Z87Ndm7JaVMTkJSVaUdboplJunyMrkXv4oRKdqVheR1OScpcSWZJEdUxhRVT0wipszt7ZqLi2t4+Zq6dhws55wdLjiuG7reTwRFk5MsCCHg5g1ueUA1W2AqIeUeLA4IW88JmnB9zuWzT2lXN6QhCAdEGzCW09NjHr3/If78Oa5OqNzzztkRL28HtlcD26TwCbQROfRGZZzKUEm7YbSag/tH1IsZN23Lpo9sXm3wyfHeP/wxD+8/ZPvic26uLlm3LW1XJMVzICZBk1KO+BhLl0tGB+FkZKXpY6AyltB7gg9UtcVHkeZX6BK4tBgD1hr6kOmi8CYymhg0McIwCL8nbCOETGwjsY2obcYqI2Ji5fJrBZU1xOBRKWGcxtUOWynq2rKoLbUVNGXbB8gyAZMz2gq6Zq2dLAEUo8mewSjhrFS2KuUfgw+DiM9Zi9Mi9JZixichc2qTcc7KeUsBo2HTC2rQ++IIrYovEBFjNbOmoapFp0Na6oooXZZAL6YoZOgiBT8SvUVC30w3vDYieZ5zJhcOhyrlqJQz1hQPoaTwPoDSk8CXKOUYKlcX8bkSPGToeikXaqMwGmIO+M6TlOO2zTw/X3G9GvjzX73kfN1j9OjBI/f7EET4LkZJFFIobedak7Uo9ColJbMUIwoh84QsQn82KzTCydGzGV2OrC42fPDhDxn6hl/+8jPa7Zq2Ld0lObHarPnj//CnKH3Ci2cvuLm9ZLnQKO2IacX9Ryc0s0TwDU3doK2jckse3XuH0+UjVITzV5d89Itf8OrVJb/9W3/Ad7/zd+m2Lf/yD/97bta3KGVRZJyDxaziZFHz7v1HPD0/5+X5JVe3N7zXNKhUkQZF27dSPnMztFLcrm7oek/X3XBzvaWZae49mGGGlvOLa4YOtDG020y/7ahdCbp1JUl3GBiGlhgLWhKhu0n8v/+7f8c//YPf4e/86NssFzXGQMqWGBW+74mhRaM4XM6xOnB8NKfb9uSgi4ko05zLqM6qQJeyfyw6WbtrJ/P4yA4sBUOZQ8e1JaTSJTgj4lE54JwmWcUwBD7/9DU5euazb3F87Lh3dsTrVxuSCrh6zmJxSrsduN2IIFsI8MUXL/ne97+Bdpqu7anrmpRq0tEMYyyr25ZX5y85O34MWqNSFLXZsQwzlvj3V51xHWO8BdS0Nox8x8mEF1knNHsYyVvKA+IDqCcAZ+z0GRH+XSL+17TTvrF9vQMUpd6mqzYhKFpmj/Ji7i7m+1uWLDOEXf87UEi4I39DXjpO8OVtE1Jxd3fjhc7cRVD+euhsv7xz9wX7by1iUikW/5ZUlBGB8r13ka0ES8S7ZaVdR1IGIgo7PZ9SQhdPmLbdsl7dcH15xfX1NZtuS0gereFkMePdszPCaoWuTKm0jCW2zM3tJV0K9Ns1VTOj22zYbnsOVGT1+gsunz7ldrMhRlDRUNU1s6Mz3nnnHfTpATfrNQenZ/T9NdvbW2aN5hsPj2nDNV/ceIIyNEqXSb7A89Yys5aDR2csjmb4HMg91PWck1nNg+MDah1pKkN9dsLRwYzOD1xf37Babeg7cTnOydN1vZjr6VEFVqNKpq9MIYQmGVg5SIlFK8UweOE3pMB83oCu6L2n6xO684QhM2w9QxcY2kHIvn3CKqiVxaIlk554SLkY2Mm0aBUYwDlDJoiMuhL/E2tlzI4OvHVl8TFOLbLe92AsVWlzjpSgyopnjHUWpRTD0En3jdG4ylKNrsFI+SulTO87ZrMGoHTkiIdSLkaPPiTQiZQGaQUt4014NqXjwmoJ4pV0NaWCDiZ2dhVjSUcbjVVKCKzWyutTonbV7n7XmvGWl9ZwcZMWfaQdsjmkSGUdsZgmojU+KdZDIiTxJHLW0Q+atg+0vuP8puWjT5+yHTLXXaJPThCTJC34fWihlO2ErCvePlVd0Q892Yg2U46pWAqM8uS29JDoYrdhqec1WVkuL285Oj7g6OABT754CfqKGAf84KnrGu8Tm67nJz/5CY8ffpNnn31Ou91wsFxyfHzENkYOjhb44YbT4yPIhuXyHo/vf4vT5SOsmZFT5kc/bLi8fsmr1y/46Ge/5OLVDU+efI7VkXffPePVy8j6NnK4nPPg/pLKenLyGKV5/eKCpBT9VsZL17WEIJ5e80M3JVpKSdNB3wX6PqONWDxYYzFKJOiDTygD2mWyUWQVUCpROcOsOcDkGV0XaJoFvVc8e37FH/7hH/Py/Cl/8E//IWdnh4SwZbW6YHm4oO0vUVmxXFYMQ+blyytevrgV3orO6KQRNlNBT4rhqFK+rC13EYT9ufyODAQgk4Es6hlNCkpE+7JnuZhxeLzk5uaa29tbnj67IvMxXZ85PDrDmnO0gpOTI4ypOH99IwKKaHLWDIPn2fOnfPvb73NxcUnOok68XC5xdsbQBtrtLcp4jPZI5XB0f/rP3e4mtuQsc1JZQ6UktsdD2S2Ge+dl7CDN03mSc/lfCAdlnyS6/+hINv1r3rgXsEh0l5I4/KbRVRKmk7vfR55VEboqGZ7KEnkK3LervelpL3/dtneBJwRFf6nE8+Zu5LjU3vFRiH17Fz8rFMX8KqnShTZ+XtoLUIqyZ9ESSEnE2FJMdF3PZtPS9SLeRoR+22Kd5vS9d/n2976Lv73l45/8Ka2+pk8J7RSRzNnJMet24NWzZ7Te029bmtjR3V7x6vPPuL1eETBCaHaO5YN3+c6Pfo8HH3yIOThgvbklXL/g+V/8Ry5vO+abjof3zvjg3iF9WnHVSa02FOh8iJ65tZyennFwckZQge2mp7ENxycn/IPvf8h7Szh1PXnYoE3CzhzNwtE0inunB/gBNpstNzc3KDLGGnH6NQ6SKImmlIu/jccoI8TXmIg5ToiCj4naNfhc4XtN1ylW64DvBnzrCW0EDwZDZQymGDVmZYiI7wdZOCFiWCcTgkYx05ahyiSnUESc0jhlRFcOIUFbpfEZnHMYbemHDlvabXNO+ODxEYYQ8V50SOpKuCNaje7JQEHTYhlTKYoJnhjowe2qm7xrfBgYvC9Bsvig5Jxp5jOWixl916KNIJxyTkVQymiFLR09wtsZx3jelWTL5GaMZjZvilJvBqOLEHQp1xYCeCxtwCGKaq+1RuwECh+mGwKrrqMbPEmJd5OPim3vJ55RSBCi4mbd8urylsvVhtttT0Rzte7Z9tJFEvwg1ypTRLMMxipMCYiqqiFm6P1AzgGQAE2VDqLRnC5nhXKOZnnIgOLy+obFoubRgw85PnpYAqkMyYsnTBY7AoPlxdNnPPn813zy8S85PjqELOTZg8UBlbZoJyaEwcOD03c5PXiMjksRyyOxXNzn+rLj9vJzuuE1n3/2Kb//e/+Ab33rm/zpn/6P9G3HzdUNXbdlPjvl3tkhB0eHfPLkhaAF2pJj4vBwzrNnt6AszmpC8PJdlSblUVNHPG2GLuH7yA++9w1++dETrq8GsKBMZrbUgmynWDyeDMfHhxwtHnNxvqJtt1RNjW8r2h5+8cvPOTic84/+4Y9JaeDwcEnKCecUs2aBcRbjDKv1NX2X0Frk9iNJ0BIgpzG7v5tIvtkFOWa8uehr7UokibFblGSlgpt7Dk9mfONb75BVJLJF2yWrmzVPn1zQdYGHDx8LEmotB4cHPH96TtcNO0uFmLGVYrvdcnF1yfHJIa9eXtC10lHnNKxWa+l8QxAfpXS5f3dr2Qhr7JL0iazAVNRSb1IR9ukDo2LtGIvc5Zl81WIly+uXS0S/6fb1DlD2a2aj+h+yWOsCE3/pPUxVmul5rQxKxTLHjZ41d+tsY/AgjxVfk6K6mRHUZp9klEY0Quu3ICl7n7/PRXkjSNlFpHvxbB7VD/OXSnr7Aa0qELraG4jToPrSeRyVckcUBYx2LBeH1K7m5PCUrt1yc3PNZnvA6dkRv/+7P+Lv/PYPCNs1P/1X/19uXjxHGwjBc3N1zdnRGR9885SXz59z+eoFm9Ult08/4frVOet1j4+CAbq65p3v/YAf/Vf/lOW9B+hmhjE1B4tj4vKQJ7/6hPn9d5j5C5ZzOM2OszCnfXUjHR2AT5moFWHwmCFwr1rwrQ/fw6fIfDbn/bNTHlY99eY5tluj0yBliSIM1lSWoBTOyGS4mM9ou55uCKw3G9p2EGRAZ8IgwWwO4HXGF9RAkbC+iLeFROsTVkXWNyu6zUD0kdgnbBaFVJ3BGovKGlNKGTlBzKkEwabc3IKIZAU5lgWwZFCHTc2yMcxqgzMSMEvjWiiaMSKoZIqZYlXXpIQEdD6zbSPeR6wFpUqrceyhSNkLaVXeOwYeGSNifAlxkbaG7L1I5Bf0wBYOTF1XHBwsODo8QHFICB4fRXPGe481lYzQMfifFgC5B1KWwN8YMd4TjyIZ4kaP9+4OzdyVrDQxewhRgp4MQ0hkZRli5nLds9oG1u3Aatuy6QbaAGiLM4aLi0tuVlvmBydc3ay5ulmz7QPNck7ve9AWbUT1duQjGWR9SilDyiSVMGgur28K8ZWprGq0FdXa4kqpjcFUjnsPH3O16Xj64jVaJ5bLOe++8w2smZGyIqeIyfDo0WM+//TnhJBoqobNzZo/+jf/A9YkHtw/RuvIetUS+0ibA9tuw/X1FVbPWM4fc3b4AVqJKFnMGR8Tt7c3XFy+xMc1P/7R3+Uf/aP/mk3bofSMvo/EkOnx9L1nsbgHwLbdcnSwJKRI5TLNXIKzoRdz0n5oAWnZBlkvYxQp+W6bubpYs5jN+Pv/4Pv86X/4BVdXG0LJ1LVLEnAmhTIB60RluZk5fA6YSpHNjMFvULpiPltQuRofPCcnh1xfb+i3aw6WFdY6qjrw/ocP+exXHU+/2MpcrMeETubwqEcEeH9OVW/8fndhnxK+EiBLd5CsC1WtePf9B4TUcnF5Sdt13Lt3n5Ojezx/+pKL1x3DcEGMUDnHF5+/4Pz1dekysmilJGkmoU3m1esLjg6PAEPwkW0QoUOVFbPmgDAYciq+W3qPCLIXTKjp2Nn7bX/BKzSFQgdQ4zKzYxjcWTfePEdTAFeS9l0zCG9dA/+m7WseoNxd+JUqRoEjgqLuxsNygdTeIq6mf0VhMuypbt55J8BXEF/ZG+xMz+8jMF8+zt1+p+FeanRaq8kYULJqtT+exjHEGJ+8KS438mHuRK3q7iKQS1iVCvSmVMZQYPyilmutZV5ZcjMj9AONrbDacHh4wIOHZ9x7cJ/D42OWD+/zze99j1//7K/Q3qNzYlhtePLJZ/xXH36D1G25/fyXdE8+5ebpE9ZdoM8OVTmsq3jnuz/gx3/wP+Xw3gOUq8naYMiE7cBf/sUv0NWc3/nR7xJe/QIzrLl4+oKLGw8Kmtrgs7SRUjkO79/jnQ+/xaN3vsU7jz+gmTekfg23L9iGSypWEDu0KdcnBtFSSdL6OXpYGAuL5YxZkn/9EEg+srnd0N5syUNm64OUGbS0ynof8EMrHBUf6futtLUOWYKRrKmUE32Pkr/5GNBZSki7m3m8oceAVAKXlCONcxhtsClgLeIMXGt09vge7KzCaTC1w+qED+D7AT8EjLPkbEkKBt+zaQNtJ+WYEDIpe6wVe3djJMDt+iilmiQk08yATxo/SGacFKjBE0ISxMlZKOgKKmErR93U1LXDWQ2qofdR2pe1jNExwTDGyLSedv5U432ktbhlu2rXtTH6eyitJrTJOYutHD4k6qrCJ0F8eh/EKVZbtn3i9e3Ar59ccL3a0vae203P1WbA2EpE/oyULM+318SUCboCp7lZtfK5Sj5LkhexQegHj3EO3w2gNDkmsBrt6iIEKPfa2G2WUkZZh7KGg4MD7j14wLoPvLi4ICvFbN5w/959To4fIEyrNN3zJ6f3WCyPWW9anHMMg+f8/AXvv/+Ily9fMWsqqtpzu2nJLtH6NberFq0iP/nzn7Bar/mdH/yY5eIeioqL8xf8/Oc/oao0p0ePefTu+yhr0JUl2wofYXlwyHaz4uWrS87uHeDDwGy2xONZbW5IqadpFsxmjq7tRKmVOCVNYhKcJHBWmZwMm1XkyZPnLBeKf/SPf8i/+Vc/4XZbUBeXi8pvBpOwLokPDhu+/1vvMl9W/NXP/ooQI0eHFffu30NhyF4+1ymDHzxDNzC4DusUy0PF93/7XS4vPmboZN2OamwmVyhd2rrGtWFPUWxC0qdH9kocY1AzzcORrDzNQuHqzOvzK9brDSEpNtvA5esb1iuPVoarSxlTl+cbUsiEKMi3mrziEjlA38sa8+zpBfdOH3B98YJtt8VozaypGTq4uViTgpHOu5zYD0wAxgaK/W0yX9krxWhVHh0R+nEd2tv217E7a5pSu3Vt2nVZsP4zKk5f6wDlTQ5KKq2zo0Ha3yQKswsYxizNQaaISo2TpJp+Hxf9u+WVu1ojX/UZbwY0u+f26nFlkN857r0IdD/evRtAMQ2AHddlF5TsozjSOl1UPIuNvNkbaPtqioZiMmcyzonGRoVlPpsXsSPF4uCI7/7Wb/Ov/8W/oO0GVIroFLj84nNe/PIjPvvkl/z6J39G+/qlZGJJoU3Gzuacvfsh733/72AXR2AcCkXyni+ef8Env/wVyW/5rW+9x7Of/xlHaaDC0g/SFdIPCZM1x/fPOJ0fEtBlETYcLE9oqiU6eMLqBnX7AtQWrzuUFJaE4ByKMZiW9tZEIBFBiZ6AsZqkFFZZVGWpVEJtWvrVQDVEBjIxe2LMbNteFnsf6AfxvlHIwqqTQiP8or3LIxni1NqYQQtsbzUiiJJzQfd20tJKy2I+axQHC8fxQQOxJ4KceyMCbqmUAPpB1F29jwyhI6JZr3tW64HBy/6cMYScsCZjdMYUL6CcpYvHjh1BZdYJ5bzFXCD74nGUQiaogNawcPUbrfZyzutaMsMcPVC+r7UTMTaEQE6xICNKOmn0DlUcRdLkuVLSyZLBWmMYfCAkIawOPrHpPV2IDMmw2d5yuw18+nrFL56cc73qSVGx2g7cdJKlV0okz11lCxdFNJXqpsFoJ23kpTTjh4APEedE6VMZxRATugja+JDRWnROijkXKot6L9qgnePk/hmHB3NCjtysV1RNRWx7qspwenJCXc8kuNHl/kZhXMXR8RkvXj0npEDKEWsVOQduV2v6ruL4yLBd3+IWGlcr6nmN72Hdrvn1Jz8n5Z6/84N/gs4NP/3pn+BDx6PHH3D28AHzgyOSySin0VWFayr6QaO9Ydt7njy7IKbI7dpzvdlQ1RZjFYnAfFEXCfwkHV7FKHNMjJRR4sUVK1IC7wNt2/ONbzR8/wfv85OffkpWrpBkM8aI0aStHCGJH9Hh0QxjNQ8e3qOqPffOLI8enJGjEsVa3+OcJfqerttgnWW2mFE3loePG07vWV6/8OhYowhlXiydORpBbdSXf8Z5WI2BE2KguruhR8PZhDaB45MFIbRTqWroIs+evML3UuKLKTK0ErxKs6XMD4KCShBbABoy8tx5XOHMguPjY8Iw8P6773F4cMB/+JM/p2sj4EjZT+j8OK+/bS1Ud+b9uwn2nb+nNebu+98MUnYHO+EnUM5SVrvk62280a/avtYBiohejZWQPA2cqc34K8KT/RMrCzhURqGr0SRsFPwZg4dxP3p6v/zoaR9f+ow7r/sygrL7O5FLO6gqGZncKPou1ri335RGB+dxH6IkNTYt70vy3zlfaafjIU6sudSHRSpaFS7Obt/l5tQa5awEAFLpxPtI2w9Epfjej3/MyYN3Wd9s6WNHDh2/+os/4+lHf4HJsNmsGbxHqxkhR5rZAUfvvEd1dF8manHtImfFR3/5V/zH//Bv+e3f+W1+9MMf88Vf/YQvPvuC6t0jtLOcnJxSX7+izZ6oLM3RKWufuV1vcSgOFydCwFQZvb3F3L5kyZZaBXIMDNFDUlTWCBSfZRwlxAAxT5lQhiwuyFkJc7/SM9z9E27DNfl6S+o9wYNKmrlp6HzG+4CKiholDstq7JDKZFVImErjtEyIVkt93mkDOaGJWG2EhxICmiQiZEYW+IFAyIGmks6dWW2wqsbHjNVaymxZ3KJ9iFTOkrLGd4H1tqftM5vW0/ZCwlNK4UPCRXBW/G6c1aIFkiLWGHxIUzebBB3SbkwMEylUIWPHWuGULJcLDg4WwsuJATQ4pcRvp5xjY6RjakJGtCZGU7hg8nnONBNZ12ozdeiMt2UoY1VpQx8TMWs6H1n3kY1XvLjccL1u2QwZcNysBz5+fsunLzeEbEg+4aNh1UVi75lZQ105NhuP0RlrFM4pjLKlu090UpTRkumiScnivZR0FJZRnNQY4YVFhAStjMYKlEAk0swWNLOaqORe2nY9KXlOjxYcLiuaWT3J9jPOG0lhtOP09AFNUxFDT1Nb6sYSYi6mmpnVeoO1muOjhlZ1dEkxDEkEFXPg/OKcy6uXfPHJUzKJf/JP/hlKV2SVickQk7SzzmcNpsok3VEvLYrEph+4urzletPRR8+92RF9D2bbM1/MMPaKGBIxSIAaSWhTWpQ1EEA7VfhnipvbDU+ePON3fufb3NyuefLimoghq+LGrYS4/Or1a/phw7Mnz4FMVRuOlg3f+84jKmPptwmnFgyhJeE5OT3BVXMq16CpMNZxdt/yox+/w5/2T7m5BHCA+HMVeitpCkruzp8jyv3GbIwU+DQ5RyFHEzBGCdE+3NB3XvRJgiJGz2zWEEJg6CIhSGmUZBArkh2SOvIYE4ocFSEpuhh48uQpi8WcWV3xxRefslgsefz4ETfXT4mFvBzSXkAwfZEvoyBv/v22tWysBrxt+1KZJ+Upl87TPPr29/4m29c6QHlb5KeUKEhaY97QPXl7IDE+biyApsoGlRO+XMyx5LH/mfJZOwnhr7qwd471LVdp/9jH9mhdbgzpRhxhvr0yzz4KkuLeILuLqLytzpezZKixtMIJCiP7KIkDKSlSKl0GKUvgozTa2GJiF+gHz2q15vWrc7RS+NrxzR9+n1effsYw9IQY6GLAb8AmRVKKbCqScSwOzzh+9102AdIQMSisUuWzNPfPHvDP/uv/Ge+//y5h9ZrLF19wvVrx6ycDjTW0fcJow/Hxki4pbq5X2MURRlfkJB0SaEVIA3XecDQLzHzA5ETXe5IfyElUVCXzz+TUA5IVqyyKr6O7cMoiia2UwjiDOVqQU2YIkehblMoiXqYVfegxJQtTWaFzLhNWMaMbS2okVCHlqShttDkmjMqolLFZylxKKVxBWnQ5RX0OJJ2YOUNlADxV7agxEJMYNZZOnmw1LmkiGT1kYop0Q6TrxQ1XafFsyoBKmTik0qoppZFJeVZGqaBpiDeOQODCc8qpBMbJo5TlYLlgvphRV9WUPQv3AGzKKKMxWlE5i7VauD9WhNc0GqvspPPhKlv4JqUlWSmqqpJj7FoJsFMio4loNn3k4qbl9W3Hxarji+fndCHTR+i2A4GKlzcDF5tAJOKyQRmLbWZsNi0hBYJyaGXQMWKzyOhbLSRprTUJQxjSFDQQAzErceRFlUBzh3ea8dqnVDJwaRknJ5wzdGHDphfl3xwDlY4s5xXLxQJtHcUhg5wEDVMoZrMlzmnmc0t9tGTTtvhhIKXMthvEA2ghKsLZBroQaNeR4COxC5iHFa9ePuf66pLf//HfQ6uK1XaNrjS+7/FdDyrSbq5Yr6/wqUXpjLU1Xd9zfbOmi5CNYrPpCYPME4fHM+bzivW6I5duQDU5aIO1o52HiMrXswpjLTfXPefzl/z4x99i3f6Ey5sOlaWLJWfDy5ev2a4sYej5dfc5dQXaDHzw/u9w7/SMyjkq5airimbh2A5XNGqB0o66XpKzeDRZC9/7wTukYPhP//Ez1utI6jPWSqCZEqDjVJGQqbckj+UeEBJqlkk6j+UMxUgGzjIkuLnucbVIWPStIkbFrJkV7yyDp4hl5liS1HHOV+Ou5fPHElLOYjjqE/H2ho1S1Lai67ecnTikYTMTcjm2t6xCf1Od5cuk4LKVUurbt0LKTV9uIB7f8jetj1+1fe0DFNl2ENzbOmHeRuIZ378fKWsDLmvIDlQEpabW47ufN74/kfOoRPiWq7f/uXm/pLR3XCUqHxMlCU5GLsr+LvZgxpxLcJLe+JgxmNp9J+HXjCZoEtiMIlH73ytlWRx3z0dytru6pVZgxMDt9etbri4vePbsCQeHB7hGcXR6ysHBUnwpchEqUhaPEBpd7TAHJywePuL5as227Xnv4QztKqKW7FgZxcN3Hsu94Lf86md/wRe/+gX9MPD0eY/VGdtUPP7w2xw9ep/tMPDZ02fSoREjdeXQrpIJxPc4Bo7nCtdpYcZHgXOHoYhkWZG7NkoQFxW1rCGGHYwfg0iPo3BaY2rH/GSBSTBXt/Q3AzfrljZkZgYsGZ+RiXWsT+eMo7TNasSkT5U2RiUCaiolrFLS1ZPlxrTG4IqWSVbglSJqBQbqytBUBqPFX8goA0lJGa1A1pKNFfRDq1LWg1R8h7KSgCCVoEarLD5/RIwWYTkQ00SjxzbrPC28qZSxyKlok4ih4KxpqEr7r5RPzRRji0w+RdtECJTWlLbcKNbxWWt0Eg0ZYzRGa9p2SwwB5wRpSQU29zGT0YQoqrxX64GPPn3JdZe52HheXnluNp1wjQKstiue37a0UZGVIsRApRVRKaISuf7UB6xRWKWFfJ0kj81klIplmpcg1xbhuBg9OXjh4qhM5QyVE0l1rSUx0FZa0Y3RYDRaZeaNI/YWtGc+W3I4rzg5qFkuGhaLOUrbwrORIGdEq6pSQpvPLPPZDD8M9IM4kQ8eFKZ4KFVkE3EmMG80fh0xGJb1Ia+ev+QHP/htXr0+5+Nf/5LAgHU1B4cnPP3iM3xY8/LF5wydWFPMFg4VMreXa0GRSlt333kIlr5JhBhZLGesV92UCCSkVJNSQhuLU5bBJ9CZtutJIZPnlpfPL/neD+d86xsPufnpJ8QsZP0QEsF7Uso4V3OwWDCf93z7O+/wez/+IbO6ApWxtScR0A5qMyOkhA+BmELRFMqQMs5lfuvvPObwsOHP/uxjnj/dEANyrVQmj23pahS+HNuPdyg1kypImObnMS5IWRGDpt9aYhS/rBTFQmO5bCAHOgYqL1ynEFNJhJKgqra4bZcyc84JYwRxzCqQUkQh942xBucU1pVgbjquvzlp/pu38btyB0IZeY53XzmWgnalnf3Xj6/5225f6wBFFehzxCd2Q0fvSiywy3TkXZSHuHMBygWVjG8s0TDVJ3eCbXIBdu1Y+wjGCMqNAYKaftTUl74ftOTpnXmCwmQx0Ps3g6wCu+PJI4Kyx21RkrWPxzLyTSQKH28ypsf3/RBypnRM7PYnPBWpmaMosufiJ/L69SUXF69QKrM4mNEsGu5Zy8l7Dzi/PcfHBNmgtMOqjLZweO+Ubn7MR8+e42PgcNbQ1A5jLUlrgpL6P0qTVCZsbrh69gUEj1VGgobK8ug73+edb/82s6Mznr98zknvubi8IaskSrI+o1Om8gOmXxPSGhUHEThTuSx4cmblHGS0ykXWSAn5HcVIGB4RtJg9SYvfi3FKgpQhMcQNLiU2IeGMovWJIWeGkEhjFlM8j5ySIGVcuKXdVKYUZw0VsKgqYhhwWnxv6tIBERP0RJIBO3PMZzWNczgbJ+JtCVelTTyLYm0ovkM+SL085UQch1pByDJy/UWzQuwdlFKTMJtSimzFvkE6FcAWjYaUs3Q4qUQzqzk6OqCuLWZsa1FFdE2N4xqs0dSNo6oclZHJX5OxzhaX5zgRYY2WUsl8Pme92dD1HUu7lCB6RNiVImbF+e2Wjz4/56cfv+S6jQRl6Xxm1XraTjRn1l1g28XSFgxKSzmr68KERvuchMtQ5herZVwUt4BSegLtLL0XRDLnTO00dV0xqx2NMxJ0pUjwA3VlqJ0jhtI9Q2K2mONDoh+kS0YTWMwchwczlsuauhIhuJgzNss9KKGR4ezklNPjU/rukr4b0LokVYB1UgpSquH+vW+xDbd03Uui7ZjfW/Lw7AGr1Zp7p6f0fcef/8VPaPs1/bBFaYd5+YpPf/0LXJVx1rAdtrzz/jHHpxXr1Q32dE7fD9xuxdTQR08KiXwtXBnXaKwztK3wb1KSEkoO5TpbTdsNOOsYBjElNFGTU+bZ05c8eHDGrHmKJ9M0GmNmpOjoVeb9xx/SVIn3PrD8/t/7JkfHB8QwoEwg5ijdcgV5FvQl0XfiJqxNhdISzGjb8o3vHHH/wd/j3/7//orPPr3k/HVXCOljwvhlUuk4fY9Lj5oCgrSb0rMEOzlqwgAoBwSsiRJM2FrGvIE6KEIUrpXIYxhcVdN3QjCuG3EhtzbTNDXVTON9z+amZ97MWCwMJycHqDwTVB+DyrFwPu5uee8r3O0m3T27S1q/CjBRe+/RbyAuSHA3vXJca3MRSf0vLUAZB0X5n1Kidic1fMj6za6Zsu25Hu9KZAIpowW2lD53ICdCMZRKaReg7Lpkxs+++xkqK74El2WRN98vTemyRInzsiroifigTMhF+VSB+gTr3SfXyk0xvm78NonRm0e+ay5kw/LsXoCiis28tNLujleIbkWNFI3BYJTDmArnGmYLx/sfvMvy+ITGZI6XNauba5598oQ0JHTykhEYy/zgEG9qrKtYLBY8PrvHg7P7NHUFWQiYKScsEEPPi48/Yn3+iuC9lKCc5fG3v8eP/+C/gXrJ6npFUIaqOcCabSmBZJx11Dlg+jW5vaILK1LekmLhk6REZcvEX8oOMgYkEJOMpZwYrTBZU7wOyDmJGJlRUGnscY32Hqcydt1TWcuKQBsjQ04kJSaTo1mWKQu7LFyJgUxlNI1VGDIVUJEZijZGinEaC1kpksq0MTCfNTRN6XoJAulqlwlZSjwJCfS0NsToRVnTZwaf8V64VaKeWYLpMaQv5yEjgVlUI7dE9DJcOX9SVok7XyGkvffw+JDl0ZLKgq0EBk85krLCGYc1GmsydW1YzhuclXNBkszRWcPIC0QJ/2NEkrKxHB9byXBzELGzrElkhgSrIfHpq1v+9KOnvFp5grKEOEDORC8CfN0gqOjx4ZwhBFHyLa64s1pT5zKjqLGcIuUjo2QZMlI9LHwtxLk5yD0mpoqKYRiwWlAzXRauFKV7BSvzUkiZlDWunnO77fHJopXHVQmnNZUT9VNynPg1KpYxkWTOMMpwfHDEs/UlGcPtesUQWoyV4Gi7la6aR/e/SzVzvP/wmhB6rIKPfvEziJ6j5ZJf/OIXDL4tmjGaOPQsZwqrK1QybFY97TDQrTvuf+eU5cyzXgeUPcC+9qxWA9uuE6PMbeRadcwPLcZpbAr4QaGVlOk0iRwiUQ1CftUZrRJZBSIKHy03qw3Lo2O0shwfzrn/4JRhSJy/2kKOzBrHO+8ofvS773F6doy1DSH2hBgL0pm5vb0kxkgzW+KcQ1krmkWmIQQlNhkqQx44PTvjv/lf/F2eP7nhX/6LP+XJFzeEwtPbD1JG41k1zf3jz7iol0kjj/dSeS4YlKnl3okBPwxU9YLl4YxqELQ8hMQweLQWr6zZfMHl+YYYo3RM+Y6UWw4PKk7uzTk4mPHFJ8/QWXF04vjmN97nVz9fyzhEup/eJoX29gLPl8MQuQfeQEnyLlgbH99H6Xf/jjhKgWgz6GyK5EGZL97Cj/yq7WsdoEzbhEJJBCotw+atYm1vhb0m+KVA0lmLZOf4dIjkLETWN50Yx7eO9cLpM/a6f0Yn2anEk/eOY+K03NVbGUtUu/KRBC8UUut4HNNryr7eHG5TNFtKPTuX57jHpynwq9J7CMtYRtqVsLTWuKri5OSExaLh/Q/e4Ue/+zvce/gQpRT95QVmUPzR7f+Ly4tz+hgI2UJIXL94zemH38Pcf4BpKh4+eszJ2QNsPUPrCpU0yhhUitx+8Us++dmfcXNzKceBws4POX73mzRH9yb/nHboeXV5xdXtDdbCvIaTeWSWL1HbG6q8orFRynZ23723BIfjNWd33sUwT0TaDCI6Z9wYtYlcOgg4YBcil55zZqk0ZuuxWuMYCNlK90iMssAohUrS4aGRCbIxmtpaXHFHzykT1Sj/nnC2Eql9MtlIyck4WCzqUt6JJaumtAobYlSECMoIwuFjZNsnuj6yaXt83NWnZUwmyXq0lrbhLCcmIYHwKOsdU0KH0sqvxnKlKpLzcnKMMdRVPXUD5YK2aK1wTuO0RuuEc3ZX9lFgrMMYGfM6S/A2+dZY6e5SWko9pnCDtDb0vuf8ekunHB8/u+Lnn73ietshSp7SyeCDWEkPPhIjLJdz6rpmGDyx8AVyzgxeYbXB914IwoBzpWU6U2wz5N7og6KPmZxC0TgpHXFB4YwiBCn3OGtLB4cQsfvBY60h5iy8IC0qstYYctpy9uCMFHq22w5/XHyJkgQ4E0qqBZVp21suL8+Lwq4lpiQBV0i0Wc7xYtmwWFRUVcPBfElOkc8/+zWvX1+zmDV88smnDL4TLlaMYl4YRaNGl/miqit8bLg8b7m93vLu+0fUszUHx3MWR5Hnz1e8ehnpWkHe2nYgMuBqTVU5CbJi3qHYGTKB2axGGQ3KoZXcA83MMAwDV5drNuvExdUt262MqfNXV1ijWBx0/PC3v83J2UzGDFYQzpQZQo+1ipTg5YvXLA5atLYcHR1TH89RyDU2ShGTEFsho03gW995zD/e/C7/z3/+R/ThbtfL3TVj9/v+vH23o2VcGShJqZSd68rS9z2oxPHpgpODJU3j6IdAGMQhe3V7y+nJAdHD7e0KrTPNzDBbLKgrw/LA8I1vPuK9xw+4vnyFsQMPH5zysz+/ADxZaUGvR57Mm9teBWYs1YwBxy7p/XIJ584ulPry7+N3V2pC4ncvEoQ1T0Jw/4UoyaoRzZgeKShK8bNB7Ud9X8FQHqM/PdJ7CopR6qY5g8njhBynwbir7OQSXTIhKRkhR+6Ci79GnEbBDh7M02L5ZnubKsf6ZRb5uJtd7XFEP3bnSDathTTnfMT7MHVAaC2Lza6klaaf6bwpKXFZY6nrhtms4v79B7z3zns8fu8dlK0J73yDCsv5i6f88b/+/zC00qaqtaa7veXq8485fPSYxfKYxXyBrhqiFlt1kwMuDKxeP+PjP/t3XL54wuC9ZIzG8eD9D/nguz+AogIpgYUutfYZTeM4WFQcNIqlHTjWniYEKpWKwJiaukNSMY0zpdY7nptxPIzBWM6y6KpynbMQawrqEsFqOKjFMCNGbBdYOEt9ULPuvQStuZj4JblCWpWSTvHZsShUgkhEZQghirR8GFtoM330DCmj5orlYU1VQ0w9fhDTwapuCAH6wdMNAR/EjbaPibbPrLeBVevRpYibAAEAAElEQVQZQhm3hRAylRYZs/0yjvfuGVRplR5JJOX7jwRayu6MVqQo5zdrppKmBCgaaxR1JSqiozuV1tIVoo0W/6o8llkNOStiEEKwseU+TZGIlHaGmNkMiV+/vOJ8nfnzj57y+mZLNgiMjqJtB3wsYnooKmuZ1Q5NAB2oq7G9PNNuxcLBAykXsSslfiwyBpVwC5Ri7hz9bUfbB7SRM2eKsF5Wino2I4cePwrFpUDKmWZWU1mH32yIIXJ7fUNzcMDF1RVtt8GqTN1YDg/m3K43HG5b5ocBlazI4OcoQa4ytN2K+bJhoS1Pn54TvJex4CpROTaZR48OCfGSX//iKavbDdZaXr54zmxeEwMMfsA5Q1VZ7GAJUewzUonKvO+BiuXygJwjn392zre/912qGWy7gLKZbWsY+oar3DG0iRSh23pi0szmNXVlJodvlEIbh9YZ4+R6V87gjKGpDfOFEwG7pPHe0LaRp19cAIJynZ3UHB4bTs8OqZ2UhDCCVhMhhEEEFjuRe99uW/wQuby44rvfc8waDblGVzO0qkuCklAq0PUrzs4OqGqLWgcZvyrx5mL85WBlRNTHx+/O81IVzeSYScngB0GIjYH5/IiDwwX3G0fXCsqnzcDhcU3febbbNX3fo5Xn/oNjzs4OQA9oNfD48SkPH1RU1mLVKdttPyUEKb29A/TNw3s7IVZ/6YV/HZdl/7kJuy8BmioJzx6+NN1vv+n2tQ5QgGnhmM5vyYQl4Pjb17zGt2ijAFMClLyrt+d9/kYWhWO9V84Zob0Sqe4TaPfre/vw4Bjpvi0wmQ6rRPRjkLLPFRnh+ul8TCUkNf5fvpMWK/iqcviyWMeClmidS7uxZMlClh0JwuX4Ch/AWifaBMZhrcOZGm0bzKLhWz/6Pf7X/4f/I6/OX/LLn/6ENERUCigF7e05XbfiYLNibhtMs8RWFdYnKmD16gt++dM/5fLZZ6K1oZ2UFuqGb3//hxyenJEKhyNlsLZi3tSYfMDBomFewUFtaXSkMYk5CpuF04KWQkYsNeacdyUNrYVsNmWq3L1uSim50VRG50IoljoEyjjsyUKIrkNEtYm2H3Bk6jKeYhYUiLJYC5WtBJs5M3hRi6yqWrppohAxI3kKjrs4sDg+pXOeqiqlkqYSuFmJ980QEjGJp03XZ7Y+s+kz6y7SDpmYVclwZEtlQstZ2syNVqDNJEhYDk9m2bL4Zoq6ZCwdKUnQkbqppJwSpbUZtJikpYgtHTvzeSOLQhSCdy6iaOM9O2bZ1hZZeiVoQS5aGrqUXvsusO48qz6yShX/8ecfcX7taX1iMXcY61AqCZ+l9/ggba4qRWnLbSqc1jir6HvhQvRZNDmS1ihtRIdGaVLvZcwoVVr0IeAZiYshJhJKFGVJdCGQVx1GSVeWdQrnKnL2hBiwSjq2Uoi06zUhZc6OT9hsRfFW0BVp49+uVxz2W8ysmgQbZVwmBt/iw0DdGLZdS4gBPV67rDg+OCaFzC9/+Sv++E/+ZAr8FrMlv/1bv8/p8UN+/tFPuF1fk9ZpUsKuq4aUfAlCNbYydENLGDJZ9aSoObl3SL66YdtGDg41fefwYWCVEn0XpSV2gOgSy4OGEDTddoNSlqqusC5inSzuShsqY5nPKlLyxBCF61ZKiVlFRu7f4eEpWpfzFAXhI0vnkipjtG17Li9vubraMptVDN7TNBUpRWLqydEwq22Zcz0x9aAy223HX/7sU/qu2HrsMykmkuwuMN9v0BgTO5krxol4v5/FEH2mSwAzso34AdarLfceLHj46Ix2u0Vrx0lbYUzF6kZBSmzWHVontpuehw9PQWVub644XDge3LuH1QdcXziuLrZo5URiQcs4+nKQUiDLcW0Y1zBGfiPTfDCuTW+iQ/uP729jcLJfRxrXNZECybtSw99i+1oHKCNalacY7e4Cn9l1x8h6tI+2yLYLLN58gmlAWivSwxmJhkfS7HRZCqN9HNaKuxf5y4FSSV/3iExjWWcnSlVQIPxewLKD0/ZJv2PAM/FPRoRn/Ay1C35GFKWugviOeF8WC8hFKGgkh6ayWColAZvWlG4Ni3QzjEJ2eteRMmv44T/+A/63qxX/t//z/4knH/1MWpuzdEyoGLh88hnriwuq2ZLl8RHHRwc4PJvLl6wuXtH3A33UZGNRrubk0bvce/w+xlhUEtUSVQS+jg8qDo4MCwfzKnN/FlDhlnZY0VQKW1VQJrmgKUZmo2LpXlaUx7ba0jWTBfJUY7kty3VOWQirSYvBndobiK47IJ5vcDmxdBaFx/SeISaGmCdkQjRhxJhvbBXXZQHMWTxvtDNF4EjRzOdsYsYTpbZfBM/quiIhnSe9D7RDZPCJlCzdELnZDKzawKoLDElsITNl0S9DTxtx+85pvH9yacHWk7+ToEB51AqbggkA6wzz+YzlomK+mKGUaAhppUhjrb/U7OvKUTtL8NLEPwl45TQhLlP3ghaipTOGqjIoXVCMqHB1QxwC19uOjz5/xdVmIJTybkqatgvi5G2M2AYYi4oD2ikWixm1M0SvaNuWlEToTSlxsI5ohl60JHLOJMTHx4cwKdTGKCUgrYX4S9b03peSmMwxtdM01pJTwqfIrJGyXV0ZFA12iAzR061WOGu5f3bG9c0VPsTSzg/D0BP9FjM7BG3LQNOQIycnR9TV9/nks48xxhUUR4tLslHM50vOX694/uIjttsgAnm1JiXFJx9/ivlOI+JhQz8FgVoVVE80F6T0NfTSGTRElPKsbwYePj5m1tTMmp6qGlgsFSGIBEFMET8oVLaEIdG3PVUt2jKzecVs5qQUOCuyBTHhjMW5iqHz+BDohw4RCdSFMxepq5qzk0cYFsLPo7hTp5b1eoV20DQzYlixuu3ZrAObjaeqhETa95EQ1jTOCi8rt1QV9N1Au8385Z8/56f/6RP64c2FfTerv7nej4HJXXR8r4bCeJtolKqL83YmJk+3GWjrRPSCvj18dMYwtMwWM/yQaRqDHwLDIMj45fkW5845Oqo4mB+W62WZVWf87MlTtutEjEVYc1qD3lKKyeMx7pKw3eGPiduuOPS2IOWtCXRZgd5UYUtj9WBMlP+WmMHXOkABCtSvpkGlldrz4cl7CzTshyhfhq3UW/6URcsWC2ljNMnoaVHZDz7UnRrk/gBNpXyy68IZs9M3vsYUhIxdN2++aBd87VRJ97ksWf4hpR1KM5Yr9geZtYaqKo62k6y/bClnTB65KGWx2TNlGwO+fSG8MXo2ZAYyen7Ib/3Df8r/6uaa//7/+n/hi1//Ct92MAZxaSC212zaa7Y3z7gwBqcVKfiiMKrEZVdbTh8+5nf/yT9jefKQWDDDrIRU7AzcX2reaSKnVWJWQVX3WAQW9VnTx0wtYiLFAkEmhJHAOkX5CVnUFHsluh0xDgXKKFKQUowu8MJUMmkqzIlmaD1D36NSEmg/BkgiyBa1qEdibNG8EE0XpSUDDLm0kiKwdSLTDj3O1qjKEpQ8PwwDwSm2aiCkTD8kui7Sefl9GAa6kNh0UbpW+kAqE9dYZp7C2aJlknIsipWCIpkynkTHRbIynWURFKM7CQDqpmE2n3GwnFHXtoyPHVdlFKMTQqx0TFVOSmvSTpkKWTlNCKEx0rXljBWirBUBK6UVaE2IilU/8KsvXvLpk9fErNEqYVwxWUwwDFKP7/qBmDXGyT2wWm8IdUWMkWGIiDSXBB8ZBSGTfUKNrZ7IfTB4uefFCNCSlHQChSgE4pwStRMfokVtcUahc0IlqGpDCh5TO4xWHCxmWBvYtD29j7TrWzkvlbT1t9ueejknBM+LF094d34qCZC2kKQbr65rVqvMy5cXrG43pSyWmc0alI5c3V5ysDym63rE7bpBa8u27fD+nL/82Z+wWMwJXsTCvPdigpnAODMtKn3v8VHk+1PMXL5e8f0fnuGMRiOE3sXcklPDMHT0XRRXYqVROZF8BKeLIWUlSQAwn1eT7pCYHhr8kLBGOnu0STiMdJllxdnpfTFNbD3r1YZmNhfbgBAYhoHt7Q3vvfcBzi3YtpHLiw0xBU7PFhhT0bYBRc/i3gkx9bTdLSlXaA755OOn/PLnr+m3jpwNo6njfrAh8y6M3ZDjXfTlzHZ/K88pkaMQp2MFGNLguDnv+ehnr9huAt//4WPee/+YbbdhveqoqgpQRJ8JIfHi+Q05Q7et0CSaynF84LE58dEvPsP7MlOpXYL6VZWZr+LUvO277Dgm499f9dq9NS3v/bm3Jr6VE/M3bF/rACWPK3LZFECRw9Z6l5HB7kTvR4Rve3x/ky6a0sGSs5CrSkY9ml4p7l7wcREfP3sMSqSMso/YqBJQZN6MYtVea+YOKnyTm6LL63ZQomTHOyn78TuMn7GvDeOcJaUo7XuDL2aBUnONZEzaU7vd6+6RBUQymynQUsiCBaiiJKiaGT/4B/+Y5mDJH/4//u989Gd/Rnu7FR5BEj2SmCMkjQ4QtQZlCHLmyApsPePdb3+f+x98h2CbHX9EaYxSHBg4OzB8MPec2ITVmayF3Gu0wSKoRwxMnJIRIlcK7Oj6iZRvJCsWSfIxiwwhTOcsxogPRUMlC+yfx6ASRZo51NkhaQj0l2sGosiFR0EplDL4FCQDT6qQPmXffUxgjSx+IaJSRluNR7EJPb3LVBhsylhdEbOibz3tEBiGTPDQR2iHTDdk2iFyu5Wyx5A0FM4LpTaMkok/oso4AJvBKoN0KyVMFmXZ0VPNKLBWsqLKGdHFiRFlBIkxSlx8jVaTfknlNE0jbq0jgyoj7d4T2kzxuUIIws4odFXjik4NFKG74pGzGTwfP3nFn3/0GevtgKsrnJNup95HogefIKQo+idZo2K537RjtemlvGQtKYOPAdfUJB/QKVDNKjovaFnIYkbZB7DOsW4jq25gG4TvlqMEJk2jaZymUuCMcEVsSZQqI2JjOSU2mw0HiyUqSQmoMhCip9+scWrBweEhPnmCl6AthA7yqDdT5pKciGHg2fOXvH59yWazLUihlOD8IMHOze0atAjbGWPpuyglrWqgWRhuV7dstx1DMXtUykykZ1/KjhlFzkXlWIH3mRgCWmVR+DWaus7k3LDdBrZrT+zlHjNK7uU4RLGNiKKZslw6jFGopDBVhVVa0JM+cHb/jOvbvgSpwgOq6wM+/OC7VPaQob3l1asVxydzOVakhGa84fLyhhgtKlf0PtG3rcjiG8ezpy9YzCtOT+7RaCuCkl6zvu341c+vWa8qYgZyz5vbnVKv/rKax50uni9tsTwn6MYOdbeEwXD1MnJz/przV6/53/3v/ycsZwcMfca5TsjyWuY7PyT6LrNeRZ6lW+KQOD16QOxvePL0GXHUxVKaabJmN2e/bdutPW+SWr/8HUeV8/JO3kyep+BjVBUsmy6dhbvz85bW7b9m+1oHKBIEFASj/Gds01VK3zmF+10yf6tPUAp0ae1LGguTDknZ8Rsw2Jh5j59zN3i5s+0P/IKg7Eo9+u579o77q3gqeZ/c+sb32P9srRXGamyyVMWSXjqVUinzSJeBYYQxkUGv0t4x7r6asLNlmdZKkeIAOWGaOQ++9V3+6X/7v2HWLPnVT/6c9eUVbbshqYzKRhj+Sgvn1BlRs9WW5ckpP/oH/4j3f/Bjkq3YtZIbVFZYEke148QaDhvN0hiMVsTkiUoXd9kEWfx/pENlx9uR75EnFAitpKSdhY8hBRE51845EpmQ4tg5N/FzjLPiVZPAkzAHDU08IqRITGv6NqC0wvtIUiVw1FpY7eyqcBnwJWMX0cZEVhrvNK1N6ErhKs1s7pg10t2zGVrW20gImuAVbQhsPWy6QNtHtkNiSCLMxiSjnVB5Z8g38msSuiBvCrImxoTJWbqVrGjHCK9KFYuEhDWQkXKkUhlVfHys1Vgr6szGCIoyGiIaLeWk0RRzdPzW5R6zRfDN2J1AWVZFA0RpQoJ1P/D5ixvOrztQFq0t3nucM3I9tMVvW2IIJWMV/yBrxMcphNHJWpWurMzQtxOyE3IkKk0PrNqBfpBjJMiY8CljAWdgNq+Y1xanEpVRImmfxWslFxRs6o5Q8ljfe5TWWGNIOQivKQy0K+EjHT04pe96hvnA0Vkj3VYJlI6AeCQ9e/Y5n3z6iSA7KGISFCf6yGbdg2pZLBuUztS1lNXatiNnhUmGGNSENkn5u8w3yBiJiRLcyTVXBA5Olzhjub25RdmINZr5vMGYKNo9laFuHNEnYog0tcY58exKSdFtA8ZG5rWoHi9mc6KHru3oewncF7NjjKm4OTWs2gtyjpydPcSZusj8Nzx7cs7jx6ccnzooMghVNWO97ri67Lm8WtH3Hm3hvfffIQbPZrPh8LDBWOl4W91mbq9bPvnlK26uE+SKjC9l68xdHspu+lWqzHFpr7FhL9AeX7ND13feUUxnOJERafscNSnLOdhuO46bA4yRrjalIzl7Urknt5uBdttxdZnotp558zGPHmpubjdyHHqUCBiDkvyluf8uf2Z3PLvf97a9fYzB7x1tE3X3/OSxFJalVDy+d+LbyRshvbk6ffX2tQ9Q9v9VFMJjaWFE3Y1+v3Ivf+NzpdRjhRdgjMD1d8XO9gOgux0Ob25v1vPGr6D2Aqw3yzL733PyGtrb950q6FcEYvvlJZGd1iRncVFUMmNIk8+JtXbK2HalKdmPnN+S2WaZGJXZHRtEEQtKEZ8VeXHI8be/y6OkuHnxgtWrV6xuLkWaO4oXRQZ0pajnRzz64Pt898e/x6NvfAtUIQhmP00EUmIRMSIferJOuNrilCAeIZRrrmVizJRFUUlgMPGF9tAzKfcocrmmIQSZXgp0noo2idG21LgSOcp3D9GTFZPAGHPL7OERSWv617fkQRYYEReLwufQdirLjWRVMoQoZoV9TugsbceDSiyqClcZZk1N5Rzee/o+0geF78VnpfWZq25g6xM+ZCLiTxNyJCvpCjJaMpxQFjZjxg4dhcq5yLXLHBKLXL8IsWmyF9luo4SHZa3F2BpTZOqN1qUrxJQgQ03kyxhk0VaI1Dl6bwIlFTRQxldMCZ2TeC+UcZ8VpAjrduDiZsOz1zcMSYLD4MWDJ4bi6ZQ6wiDKsTFllE5FkTcKXyMb6rraoWMhUTlHDInei8Detg+0IdMn8FGORwPzxnDgalE11prKKiorXVmjuOIkIpelO0oUV/UU3PsQRczOKiqjCH1PGCIVGt92bFcbDk4OWG83zDYr7ucSWCpFSoF2e8ur8+cMfSdjGgmig5dooxs6Ysok1XN4tCBlxeADs0VD8APGavousFgcoPVACIMsPSPamjKD93I/KAUJnFE8eHCPGBM3l2t0FUjKopBux6bRzJqKps74tkOTmc0lsPVekaLGD5EYE9u25TQ3OOMYOkFv/NAjJN0FlTvj+999l9vVaz578iuuLtasr3/O6dE9Tg5ncH3NZw8czeIdYoK267m5vWW+OGa7XXF9s6Hvej781imP3rlHGDz37h9T1wbve3KY8+yLLV982jG0NWCJ9OJDVAxUpzVFjedlF5zIdRzFO+8GJ/tz8Igr5LznC6eKeOb0nIgR5py4Xd1weDwrCSQYp3avV5q+G9ebRBhuaLcdx8uW1c2AwoppZpbEKxeU46uaLcZ5b1fCYvrOu9Xk7tq5j6u8uX6N5ImRz0ceg5bxDi44898SIPhaByg7590S+U9iZJpdm+NddGK/5LHbzy6QeFvwMP5rjMLmTDKGZFJBLPYyJHl12dHun7fBaDnn6bm9V04/agxYFG88Li2Zu+OVyX36yL1jVuXvLw2KkhVpXWSSQxQi617EHWMiaWnlG/VDVN4N0mlgjk6cUq2f9h+DF/dWFElpWqW5UZmVc5x++7t8UFW0mw1d1+K9p24aTu/f4+E773J6/xuoWUMyBpW1ICFE4WVkCSIUAat6TuY1x0uLyZ0os6pIU2lSTMSsoHj0jOWhMag0SiB/paQjKKdMjGGnP2PUhI557wvYLcEpsaydZY2NOU2oABlUpYGKuTomWku/6kjrjtAOGAMqCdolLrwGY6UzKaZEslpaW5USr5jKUS9rXC0f1w8DYRCRsVWb2A6w7RKbNrDuPWufGLLIs2ekHdeHPCUtUlpRpChIWkgU+H5skR+NK6XVXuWESVBlTU5QVZo+ePQQqSuoK4cxMjYFFSkBDwmDpXKu8GY6cm6IMYrTbBEeGwnCMoLKQo4m+DSVEmOI+ATboHh60fLrZze8ut5gnKOZLWjbDgsMIQgSNSQZJ0rGZOUqnCrrDtId1A2eqqoJXoidofXi5RMNMWbxbSoLybxSzCpDXWuaylBpRY4RRaKyIo9OllbSXCTVjRUSdAxegu9x7kF4Xj6E4hWWcaX8NY7L7e2KpnHMlzP6wTMMHdVyjkB8kfPXz7i6OqfrerHiSND3Pc5arLI0TcWq3WBdQ1U1DEPk5mZD3RjOTg+xxqJUJQFxiFIeSHJMWktQXjUVMSd8kERjuWg4Xs65d7KkbS9pV1u0FYSormdYKy30pqBeKYWCziiGXuPcAYPvCDExDJntemBWRUxSNKZheXZAO/Q09RHbbUNla86O56xuW3718S/QumN1c81TozBmYOufMTuABw9O6YaOTz59ytGh53Y1sN1uUTrxrW9/m0eP3qPbbpk1DUpFjJ6zvjVcvdaofIyxhkiLUoPMDVmTp5lwb1YvyLgumkaSx+18umAs049B994yoEZERka5GsswJVlMBHKOYlfQbyEn8aiyFUoNhSicSHlUm5XzmmLFixdrvNeF8F8sTdTIodkpvY6J8/S9xjVJDulLQdab3YxqIt+OSd343N6SwhiU7MKSXevGG9HKb7h9rQOUST9k/M8UjOwt0EWq/Ssjt9EOmcybsBXcDVJyylhtyCaRrTivphwZu18onJSSJ5bPzXdKPgK/7YbvWHKYmM5qbGXbBShjp4OwwXPhf8CoKDuWZUQNMkKW7M6MYnVf+k4lgCuaFZU1RGNIofAjUHtaKGNEnBlrm0IiLQO+fO+8BwBqJJAYknj6qChttaSET4lNVBwe3OPR428Jf6CqqJuGuplhrUMpJxl/6S6SCqYpn5yAQKU8h03gzCXm0ZOTJ5TsXxVpcjHvMkTN5C8E4n2TKF8pCfw/XuNdMCrQ7EgO1lMQLKdBJ5HHR4uqZ5rKQ/KD1fgqYo8b9LxGLWrUekO/7WCI4lMSS5uqBpLC60y2JXDJoJ0Gm5nXQkaMPhGTaKO0fWLbwbpNXG+k5XYTRFXVl/dDnMo2KQnPIwRZRMbJTAAVRWQsOY3k1jxpmpgMystY0wi/YDGznB4umdcWq7IEXlpk7MVnR5RhjZbs3mqNDwPOCPkvRUEEVMnY1dg1lAX1IEt3jVYQvGfVBZ7fJv7yi1v+7U9/zWaQe+Z2vSWEQVSAEiSliVgCiqyhrmrhezgji61WxQfG0G9FS0YmX00XM9uQCxE6UxkJTJazGldUTysrJHllEfKpFW2XHDNRFVfxLJYBWmm0E8QtRlFLFpRNEVPAGQdBlGqHLEiXyoIzrc6vaKqK0CcG3+HKNX39/BmvXj3l5uaGGDN970EprFbMmwqVNXXl6LylqRuUMqxWa1CGECLD4JkdNqQAm82Wru9JhaRsdBbH5doWQTjh18QAh4cLVI4s50teXN6y9oDpxWMnqsLfCChi6QCE4MUMUWlFiFGuDxAidG1gu94wMxWNndHMZjy8/w4xNqRoSMRSAjYlMSoaON6gU+azz6744z/+Ob/7e9+DBCE6vnhyhR8yve948GDOhx98yHJ2TGPm+KEj54QfGj775IacDqhqhzaBkDw5SblFOrd2Wh278n2ZNwtSNi7Mwt1JZX7flX3GhVnlUR5iWqnIeVy4MxDRJjJfzFksFoTQkxJUlaVpZhjTE5SXbjSdhVtnilO61vQ+IErkMp9pStAzQs3TpD/9Z0pkS8o7rT13SkHsrZvjxKdEoVbf3al838KFTJOC+fg5pVNvRIxGaOU33L7WAcr0hWGKRnVRnByzFRkX+yTUNzY1RoVvF3K7+1qB9kSRNUntNe2izLEUMgYaqDy1Du92XRjdCLR9px6Yi/iY2kkrT2WksQaAKi3IRUg77W6nmGQCyimRrdT81dQK++XvNn6OMQbnrKAoRWwrhIgzSuTE9xCgMRKX07obiDtDurLQFwg0BhF/GlEmXSLxULgvKmas0qAtqZgM7jRkmFRXyaXVNQ243GPVwEEFi1pDDOQUyuJWSJ1je2tmKluNWZBA5cUUMQq6YKxhtCEYz7vROx6TMWbShtEjSqDVVF7WKhN8RhSHhaMypEAcxb4qQ3NyiJk3tO0ggV/IxQE4E704KwcSxlj5TgqyioRhwOMIWtN3Hp8N3ZC43QzcrAc2faJL0OUdp0Cuz/i7BNcqlYC38GdG7sso464YJ7nCHSl3l8lQqYRTCqehaizv3Tvh8b1D5nPNfFFRNZbKGUwJTOraTe7DzlrxFtKCNvXFvmDKKbUWikwxEAQhOqssJOF1D+cb+Pnn5/zJTz/m+esbjJujVKbzssCOi0ZIiZAV29aTs6KurJg+YsAaQkigDClJoNINiUAkAb1P6CxmjstFxbxxOAVWZ5zRGG0Kx8ZNicWk36JBaUvMO5G/OwisHQUAFVppgvclgdCE6NHIIl4ZS46RSOL68pIH80O67ZqDo8h2s+bzz3/Nq9cvULqi7TZSDlMSJI/GcqggQZXV9G1LCgFXiX7Iar1l8EJOH3yaZASMkXbqqq7QVtP2rQSkxuBqx6rbsBkO+OTzV/zq0yccndUcHFuqpUZpx9D1EkLkWOwWpDRWLxwGRd95Qu5BBbxXdL1nvb5lUBrLgsNoaZpjthuIWZOVIfnEdtuJ9lKVqeua+ewIsmazveGjv1izuvqUd9874/YW2jZwu7qhqjTf+8H7NDNIecDYjDHC/xp6aDcZ5xYYW/RNuuK/lkce3tsXi4l/p0YOivrKEs/dhzS7xWhEC8v0ZKR9/vj0kPnBAm0T3SBqs7O5wVWKYYCURC7eGoNRQpxtmiU3qSUT2RHQ2UNr3jyovEM5prVqF4hR3pvL/Kmmx9UYbt0BP/bn/4kCUNa/rzoTX4Km/obt6x2g7AceI3phdGkz3r1mf22+w8jeL5K9sd+3dfeoEgqPgmcmJFSIjEztqS21rOF3u2520NjbboAJbiuB0ptS9zlT2oHzxEHZTZKyj/E9IUS6ggpUSu3UUIHJu3uK61QJUBzeS41YYokd4TamhEl6h/zovWN+o2wlwm/Afr2xQFw57WT095GjN80Ly5GNe5V2xQwilqfQOVLbzL2m4rTRpPUGH/VkWJ5ykMlV6+l7yHfdGSZOXVjaCKF2nGymgFO4EKJ1vncttSKnHeIiMuH7pozjzZywzqJUJmXhs4QQGQLEWtxc+xTxeSxHGC7WLUMM3D87oK4dOksLq28zXSf8lU3v6VKmC3Dbir6JjxJIKjI65inDSSXay4ArGZEkebvgQCPEzrFtGmSBtjvLTSqjmCtNbcAoceB9dLjgYFZRzTS2sjhncKUDx1pDZaXl2FVWkBQFzmqR4C9S8qK3Ip0/WjtpciheU2ThwfhsuG7h41db/v1ffMrnr25IWFHdncS8shC9kZJVTILgpZhL+zD4QsLsB6F/pyzZp3B15N6rjGZRwbx2LGY1GtE1KebDkIKI/YUkmfTYFVdqxEYbgu/JWbqYRo5CjJlRTj7ljLLC30kpUTkxfcxdJ4B4SWpiCrTbLTdXVzx6rycMW64unvP82Resty1JabohoMiY0nllnSXiUSoyr8XrqO86JClK0rWUpL3ZmkqGgtGT55Nx0t6dcpAxW66HNqLB8/EXr9DZsu28tMRrIfC6ymEdaBORKDjvUGDjcXVFP8hzWsv5aFuPihanFA9Oj3H2lNtr8EmTbZ5EIT/44EPmC42t4P79exwenJGCYbtpub29wVqN31YkXxGHDXGIPHh8xOnJPYIfiHEgRU/KA01zwO1ao9Qca2tCDBRgt8y/6csL9jgbTff2joMic/ndub28eAr2ZVLZmwcLkiJJkiB1gLR550zTzGnbAPScnM5Z3QrPqG0HOcYUwEmzQAqmlLW1oM2F6SHlo/JhY4ChFKMekRxjSe+/MnPf36YDf+s2Bkbj173zzGS8mO6++DfcvtYBigyaXcABMkmMLcZ/3fv2/igiVV+NoNxlQReUxogdvI1mV6Lhy4HGbpdjoDRe7F3EKsuDngb//s8UBOx9T13aqMfafSpCcaaoMiYd8N4zDH5CDESxcy+1LudnDLakrlp4GoNI1Me9rqCU9xqex8w8j0HKiJDsQX65OAGPgOkeCrN/XqfqUd4FLUYXIDGPCJks4FFB1gZIWJXJ/Qofe/A9SiPdNlEV8qqUItJ+gJlLLqB2Y8Do4m0U45QRS0sspBAI3mOtJY7GfVphMWAyMTBlxbsBotEpo5RDp0xUooVBioSYYOwe8aI6uukDmy4wDIbVNjCETBc3nMwbiIE6Rc4qR2U1YRgYWk8fRZUyBlW8NzI5RekLyJRyVBkvjK3loqEykee0mrKukcKnKAFD2c8ocd9ow9xoah3JJlCZiKJHKYuxDabWwqPRiqqyUwlSmzHDlEw8l/M8jlkZfwZbSpGjAJeUoooSbFLcDvDzz17x8fMrQjY4K2JpMUk5yBhHQPQ3eh9p+4EQEsY6nBaV0xgyIUMXIMSAD6WZIENdKRpnOVxU1LoowOqIKsJrVivqatTISIQY8UMogX0pWaVI0zSEHCdLhRhjQZGKZYJ2O5VeBNkLuvCekLZdqw0xRZy1+Ji4vbxgfXPFweEJr18+5eb2Bh/HMpVoy4TkURhuN7ckIvP5gmWzZNN25JRomloQjTBgjClt3xXDIB1NsJtTfBgmFCHlJN1+FWgciZr1aqBrxZHZWtFGGcKGZqkhW5SSoEmVuUWbQrbNFH6LRalEipptmzloKkKKnJwd0fWGtA30MaOSuB4fLA44PvrtUj60GO1QlaGpDjk5fkCIkWEIxOjw3TWVgZvLK85f9dy/ZxiGAET6PtA0C0KYoZURI0w1Jk3CuSO/ySfcu63VGJjoEpwUN+/SEZin1t7xvhuneel427X+qmkdkIBHQ9Rs1x3nry8w+mwK5s9OD/B9wuobtpvCB2TAh455c0D0Wua7tFtT5P62e0GA2vv37VokU8fR3lw84TF7ZZ43u4H2/tgVj95Ab/bXxX30/TfdvtYBSspjeytlot1ltfsnMJfsfV8H5G/a/rrun3HBt85i4zgh7RbZnBL5DR2W8s5p30qNJFnKYNrXN1F3jnVa2PMotFbM1vTe/pAOGuecsOJLgDKWcIwZYcZRoGt3XGbUa6gkGAlRSjwp5knddL/EsyMmjyhIuvPYDvFJ5aYqwYecPKZ6Z/neb+6fwqQflVdRWuraMaKSx2RPrSNHlcZ4TyIK+qMLZooEMrl8vlGSuZPidBOaQmbMmWKVIIuILU7HOcadouoOjmPMSqwRZdBQHJG1UmSVRV+maIjkXloEZeEVfozw3XZcpRQ1g9est5HOQ0hwfRvo1xsqBQsyy5niZOGoqWQIRfHgycCQoTQRl/OvxtNa5keZXNQeoke5ptNj+2iaGjV/QOeMVYpGKxonBFm3nLE8nTE7qHAzi6lUWXgUlRPkUhf82hhbkoUSxAIjoXvkdI33xRigyxiQRTpbCCheXd7w7PUlURkypmT90HbiwouKpGwIWbqWhgRog4+JbtuJh07K+JwYQiaWOcMaWDaGudXUVlMRqKymqUQafdTbgdLCWVrilR5b8BPeD9hCnAwxTl1fY+A6lk9G5HCH2kpCAAHn3MTp8t6jNEQvSUcYer745NcoDM+ePcPHUclaDC0zgaxh47f4bcRay6Kaoxnoh1BQR8gqs1wsyzWXnxQjCrGuqCpHiIGQBH0UlEv4WVU22NpBNihniRvotgPdzAEJHwMhWpypMUiilGPEKkulEyEL8qatLYGs3M9GW9bbjt5/hs8tjx5/E2WPIcq9GVNCa0dOGqMtEjrv5vfxPBurcK6haQ7oe8+m7Xjyacu7jx1X59coPJttZmhhfS3EdK1z0XQREnZKvviXCeq6m7t3a4lW+k6AkqYus939k8uknqeEcodajM+hMjkVHliCnCLtxjO0Ed8PaAPLRcOsslSmxqrEzbVwCx88esx63aI55ud/eU5KY+NHgUdVnObAu8eV78QGX0JOcibnt61X0+RwB3V/+/a2x++uo+Oc85tuX+sA5W2llJ1j793Syl93YsbSzdu2twUq469Gl8zRaLFD34sW37ww4+PTAHhjsOyQkp3s/d0gaxcUmyI3P/JUxn2M6I5zIow1DEMJUiRAMcaUxWiHoOzXya21WJdwQdCEFCMxaIIN2GQYybi7Gy7f/WHXmTRaAaSpprsLppj2sH/85TtmVQKvkcQlJR4dI7pb4cIt87xiqVuO5o4mzhl6hep7+iQaBxmEcFl4KGocC2NXUi6ie+yCE0FORm5PEu2bkSs0fT/KYl/4BEZh0FDKCCP6ErJ0gOiiSyD+TVE6RoLUi50xOG0wRKwyaJWwRpWyjMQgsbQEm5xQw4DVmoUxJAs5Cl8ll3GoUcSY8SmRSmYmZcCx/MQEJxf+toyXvauBAi1wTzE0VNRaUevErHLMjyrq04rDewsWhw1VLVL0gtxJcGK0xhpdUCXhktjxOSNln5QSVhsh1CWZT0OU0qDRmpghasMQE+s+8OL1BZu2o541dJ2gg90QyEqLUq9xYCqGIbAdEigxh+z8UEiZmZh3sgBGQ1NpDhrLorZUKlFpyVpFMXUUvYJkjHS9aEuK0hI7CkGmJKq9yoCzDj8M+BSnBMM5x9gePPoO5YwQhLXZC1xiuVZlDht1kJQi+sjN5QUv6y9YrzekLFO2yl6cfI3G5zIWlMLqGu8TMbbEIIJrOYtwmy1lJzvOi3nszpB7NJbvJ/wxIWHGmIgxk2LCusRsbmlXow9XzXw+Z9veokzi5FCJC7dREMV/xukZxITRAWctxoqZXV07ZnVNTont9orr1QV9yDx88CNSbiRJUaZw/DQ5aSiInPjAKtFFsaJJY63GuYqqmtO2Sz779S2r65+waa+pm4qjgxMePTxh3jRo5YhZSiYhJsJocsno0zWSYNX0oyiI4l6AMiZ/+4nbbs5OjIjF3srBmCFJoC5pSk6OoY2EvgR5NmLR1PNDDmZLKhe5vZGx897779O1mp/95Us26xaFcPfG+VJ8s+9+6tu2KWgZ59+vfuX0gqmc+Z+xTfP+30IDBb7mAcoOLisLtNZUxqK1ISu18w9541rdHUiynzcv0ZuBxd3Hyt+lJc8Ygyfw5vYm6jBmUHKh7+5r3P8uSn8jSNmD2HZCbm8OQsnanHPUdV00QUQK2hqDqkumqve4MvufrZVwCaLFhwGfMj5FdCljTTfr3qGPULYuXQoTK/yN87Y7dxMY+OXzNSItWSTRJdOPkBNqWHMQrzmrtzRhxYEZsAS0kfZctJaSTB8IWeocSoFVSkinE8fl7mSitCpwsvi9pBxElE8bEqpA4HksHcsCuxeUaS0TZ0pJ/FvEjVC+uxY4ISkh+EaS8B32ykuNc3S9p7aGjGh36KzQFGEzlTCAzqLxYbRoZ7gYsURCGRdWjwx+hc9SWhtDRjmfarI7H6X6TUGrBGkpVzcnGmuotcHmTJUiB85RGagczJc1buYwtSmqrxpXyo2CSghZU4KTXPQipG06F+0Qbe3EQ9put9i6km4bpdAFWex8IijNzXbg8mYj3SZBM3hPiJmMxhhLtMJbGHziet3RRyFrhxTxxW9JNF3kPNZOs6gMMwPLytBYSgnHlAVLzpcxehqP3vup1Km1IYQg370kAtHHPeHG3TiOMYkeTEEoc9zNB4kkwWy5P4V874hJiKZGC5dOhO0Cq6tzlvMDzm9fk2OEFLFOkIYQpEw0X8xwVPR9L8EbFA8sj44yV/nBk4DFfCat9llKRM5UGO2EI5VEIyeVeSqGjNce5yzOKeoa5s2Mo7OHHBwekm4rUrhlGAZqp6mdYWg7NpvAcHJAzoYcezADdV2hNFQu8+DBnOVyyc11w7bdcLB4QM4liM09OVeMpZTMOP9oQXKK3AIoohbRQGehrmZU7oB2G/j00ytiHKgqRX4443DZUFdOOr6yJDPBB2L0hBz3gpO3dHPqHUFW7qXd/PwlUU2ZJctanieJgrs7LOWQkvRt14lff/SS45MlZ2cNWmlmTc28UZAPefRgiTYWZw9oq5oXT/+KFMs6UmxPcsEhp9k03w1EFDsU5U5SPKpP8ua6V0KzPV7OW8OePJJvv/zsfgK8W/t+8yDlax6g7LYx8zDWTpkwmUlr4G+73SXH7hGh2D2ui6S3tRZtxInzS6jCtEh/ef/llzvfYbwRxkmNaeyM5FnJ6Iwxe2/Pd/ajNVRVJSTAtmUoHQPGGExluBNojStv3u/ocYXPIcStkZ8xdS0wIn67gGLkoGQopaGCnEyHVSD+vSGexzReqWlf+2jM+P1CDFjf4oZrjqoOE69wCuIAfc6lBBSRLzNmg6B1FqM4X+r8egywdvo4lNLOeE1GpERN16Aoz4KUjNgFYXIeNUqliRAp51+sEFQJdHRh3RtjcFmEumCUew9CxCytqjopdCG8KgRWdtrgtIYcMFhqC30CmzIqgB4n7wyGnQmiXNbSrluOJSMCcylmJs5JuVdIgUop5lrhiNRKUVtFoxO1MViVqaymql0RadOiVVK++Fh6FIRhNySnYHBvfEuXgCF7g48ZneT9vpRM+xDZxszLq5brdU/vM/0g3JGQQaWIqSxZG7btwKqPtD6V55KooBaOs9bQGEWlFYtaUBNHpNI7QnE/BFLOWOOATIwStObSLizdLiWoo7QNo6cyZl05+T0GEetD+DUgGiVWC88s5SyIq5LATRsFxbIiA1VJLMotU5rREkO7xVYNmoiPAWMNs6bCpx5Fw3w+x1lLu93g3IxhSAS/Q89CjNzcrtCIg7MxhsODA/quZQgGrSJNU0GfhBrsIYUo92aK0kocA5WxnBwvWRycMD98QNQ184VmaCNDf4siUzcWaFgshXAfx1KplgVVFRKxqzRHxzMOj2aEYGjXx3SbGTkW9CgndA6lu09LK/DY5z/KOBiNzY5kM9GJKWHT1Gw2sgYMAbohs972bLY9BwdeFHyTaAHFJF2GZDUpSbO/qJfrPSWOY9CYMzqPKGW+s17sz/m5eF1lTFGInmYQcqH1kzMxVnzx+QrjPuUHv/UOZ/cOOTwUTtchhzRNg7Mzgq/5q5/+kovXPSntgmgp6eZS3tlVDX6TbeL5vaVasL99JUfzb9r/XsL6t12Jv9YBSh5V//ZO7MTPGBf3XPgeeZ+Ydzfi/euu45tQ2P77YOzokTbdUbhNqX2DwN1r30YSGksi0wS+t4DuSji7ATSWsXZdPrtjSqPhGrJIVFWF9x4/DAz9UMzX9rMPShA3foZkWc4m6qomRRiGYUJJRm4JKt/h3LD3PTNMwcm0QHH3PE8cG62nazQ6DGediy5GCdislVJAhplTzE2gmmmCD/gQUYnJ8n7M4DPy/rHUpJWeOAC7AEvEtvaPU4zgysJe1F2nY82grNTO4x5Mqbh7A07XGo3OBcHLI7++6LMIllwykkRW4tw6OsqaLJoHonugqawTZCFmbFHsrZRi7hwhBwaYuC4aQV306BQMyN4LRwtN0iJgprUWfg7imaGVolaKBsXcWhqlqGzGWU1dGWxlqSppH8ao8mOglFR3I1Xd4WKQd0REW7pGygUm5kzf9oUbsi2tvAYfEl3Q3LaRVZfYdoGuz0RliTFTG0UMgZAUrQ+su0hQWmzmxzGJJBFOK+Y6Ma8N88ZiVKJUc0Q3KJXrpRSqtJ6mKKRbFNiqkpJUaemNlLJD3rUUe3Frm4LdkZg8ejAppcsiZ0r3iCCWWlv84GWM5oKuKSWquCXVVxQUxHccLWZcxa34zxhNXc/L+FZ07ZaHj045WB7xq18+YRuF8CpcIAERE4qYFFc3t7zz4AHLeUMfModHBxydLDm/vGDTdUUgxzOEUN6TCb7HAUdHp7jmGJ8ssoRUuGpJGFoUAW0Ss+XeHBsV83mDtZamqYHAwXKGsw6F5uT0iL6fs7rKwqnQYynZQjblcpY5JSnyfqKBcNW0GQoXpaKuGppmxrZzaBVJybDZtKzW15yezNH1gpQ0ISRi9OzMX7mDVKOkLEwak1EzBeTj3LtLdgrpNo/6PqMQ5BikaEFS8ph0ZqDcB2RytmzbzMcfX+JT4DvfeUBdO85ODpkvDpg1RzjT8PpFz3/6j7+i7wwKaWpAjSEG010+JmrjWFRqV/i5U9p58ztzdz2SB37DSGc3I97Z193tv6ASz7gojRdHlyxVFd8PIc2OMNW4mEgmPEpPj1k0St09tSPmzd3IcZ+cJZ8ptUnRXpFseix9SJa0T7TcP9ovIygwFVHulHgkQpaRpNlTpZwCmhJJpxHxk+y8qgwhVMQYCCnhQ8CGQv5j18nB1Con3IzaKUiSXYRCHhs7emTIZIokDxEhHdpxIcqQkgiEpayIedRS2UX1shiY4q8ipTiRzI/kHESgCUtGo4oVvFLiDttuVtQzhbNOJpiSLTMuFsZg9WiAF0SrZMoO8qSXMekdlJ+YE0Qt/A2BUErr7d2QsqwfjGRmCVLvtoNTxmLWoBDHYmcSg1ICJadUygYwayxDsAweFEE0DrS0KlugVolaR4wSyN2UzLJRStRurZaOnlwgfYWUuIpBl1aaVGr3aixvAdkWZ2ek2wmdcVpxUDsWpcRDCFil0CajG0NzPGe2aLDOlMVVoY1Cl33JRG+l5BYkS4bSRq4U2HI/GAmSUpKFNcYMSlCTjBJ1VNdwsWn5+Mlrzm97+qiJORYvI4VPggTdDpmbbcQjyEoqiKIp96Y1mkrDzGpqBcSAdnoqA+XChzFW7uFUBP3Ge9xZU4LKXNr55QJLy/+IKJaOsZSwlcMYQwyBFOUaWGuJIUDplktZ7uMYR0ni8rsSR+8Ux7KbEGGVVhATfrPm5Pg+ISqUdcQ4EHxg6DyuaujSQAjCORENHyksWltL2aQQU7WJ9F3P+cUF904OODpYcHy0YDG3zNwZry5u2QwBW3luVitJvJR0DmkSIWcsqiQikRwVhjlWn5DzimxWuEqQyRQ0MWoU4nx9cLBgPoPT0yXPX55zfWVZLM64eOXxQwXaoFQUCrgqc/mEvoEyknxoPa7tmqxLsK0t1kJTN8xmc+p2QT9Ego/0fcvt6orV6gClKnIpW8cSOKe4j0TsL84SNE5cw1HJWytUUju0dAwCpnlOSxICU7Byd5Yf/x2bCxQpWvo28+mvrhjaSAo1tw8yD+8/IB8LOvQnf/ITXr/eEjNTh2LOZV6Dr/yUaQ7Lu3VQfh8F4zJ3Z7rdfCf/qrc8++XP2fuYr3jt3ybY+ZoHKONpBUqJx8gNOOLLeXfid4NuLDuMjPpyYcogmR6fMqC8uzh713BkbCsKMXAUT9sLOPZLIrsjHpGQ3bC4U7tUatI5mZAgSmResjxjjDDFUFC8OCiBRk6ZRMIYhbGGqrb4YBkGz+A91jmcMSgzQoHyXXfiaKIEWjlh9Xs/iG9L0TAZZdHH81BUQohJTO4or5EJOxejqz0USo1ks31eipApY/SSladEVBVoCVMoTp0xBkxt0Vr4GH4IE7JDgcxzKVfoJAt6RpWSinSahD29FeMsBNG2yIV7MN7MUyB4p+QkgeJ+qUg+Wk2tyKmcp5gVnQ94H0rAOfoUKSljpITRFmcssYa2jzg9FERJo5LC5sBSa+ZOU6OJCuF3xIypRIfHWEvlI55MVIqoIZgiHpZFy0SPpHEZYCVIkEDMaC0kyCzlnAOnqAGdIkWjEu0Mam6ZnS6pZg5VrqHTMlZM+VupYloXBOEZkatxsRdlWiXtwbmgPsbhfSekYqOJWeEzbNqBX39xzsefv+J61TN4QWFQCaUtQ4C+T1xvQjFEVIWWOC4wGaehsVAZRW01xooK56hbI/PFqFkSUNqQivJnSlF0XZydIP0U06S3Kx0cwnMKYWwn3qGHpFxIqWKqFxE+VS4csBEJjaULLO0hkRK4780ZWYJLkzIMPeTA6nZNTKE4RjeELC7Pnz15SdcycWkmFLEglq62eD8Qo/hNnZwcYkxiOaupDWjbkA4t2+cXLGpLXEQ26w0KUZTtVWTdbnD1KSaEKTBD1xCXhKHj6PSYehZYNA7vod0OeB85PppR1Zmjo4qDgwbr3gV1yOuXgdWqIuN2aMQ0pzMR/PWIYJgyf0NBShVGW4wRQTbrDLOmoalmdLYl+kAMA6vVitvbNXW1wJiKmMu5j0UgsqzeelIBV9PnGKNRe80Xei8hHfWWciGrip2WPLZLSUeEWfGm27A8Ls/HYMih4otPWs5f/Jq6+ZT5vGExbwB49vSadhC+jMwVI/NE7QUbhfy+n1gzzu/jsijfKzImv0yL6ZtcSzkn/3/y/izWsiw760d/YzZr7eZ0EZHRZFZmZTV2uarc+17+uN7uBQvfK7/hRwQI8WQZBFhCFhIP9CBeeAEkhBBvCIlXQALD/1roAsbGGGPjvqvG2URmRJxuN2vN7j6MOdfa+0RkuQr+SDfFTkWeiH12u9Zcc4zxje/7xss3ufv6B89p37vcfXwtqr/R28c6QTmEpqZEwR+0eF5++FHLZuobChNCMb1Yvd19nbtEKOpmaK3VCqzyFe4+p7REqL3mlMYev5cmJmZu4xyQYRuk3KDGV/c8Zd7oqpKg7ztSTLP82DtNdgx1nHd9HVOmKttYw8J2JJPYsVPIOwZSJxgMtigHwsWiM3fEVh5IJbbmBCkieYQ8IqhjJSJgWhJWj4/mNMoZSFodYbX9Qd2wslii7Sm2I4Rrhu2WMWatGEUmRAyqmrjC8RNMi1apIYYjBZSpa8Uwo2KTCe1B0GgbZ0r56Ljr5575Qc0YLqXEfr8nhURnu2l91ifq8e16nFhiJ1A2tfWjh8gZQ1cM675TFEMqKJITlIR3vvIZdFqsEzBGB4aprXipRNgqj5zKqAKik3RTqm6tJSPiWHht8Xi0rWCNoiNu0WG9kl+dd4gtdY06dVat1fphP77kTJJwsLZ1HYt1OjNHINZhfhlDLgYjDtd5lhY211vee/qcZzc3xNySy1naGYvwbBPZhmNrcuXzQGdg4QRvMq6W25lMTBwMfNONPRblnJiiLagm11dLcZmQ0Kn1ag2+ttD0OjxWchij6FlhNmSbOWzz9eqcTk9OKU7vAVWWnDLW6TXVOCnGQoo7vCtgAlYs3vWU2toadwHTd+yHzH4MZLSF1IqWruvUlTiovf+it5yf9aQwEPYBsuC6Bc+vN1xdb0imsL5YsTfbg30ikEomZUvJQs4jhYizPaZYtjvLzVduef0TKx4/vIeUyKXc4kxHv/BYl7i4OGO1OsV3Sy5fWG4uR3JeglHukojFGF8Tf5X+tz/ezcjyxBE0s3DAOYf3Ce89i2VPt1PScIg6zfny5ob1Sh2QU0rEqMXCYTtknufWWuh6TjvrDpRoadqLD32w9DUKrbjV+NC2+rsh++BWZ6MpH8aQY+H2pnBzHTASMXJbE1ndJ0UOY1E5DiXSWqscH6faTjr8DMphkY/4WHN8K6W8lFi8ikw831cmUOA4ZoJ8hNfMq24f7wSl3qRWes3HYmqp1ESgDafUY9lkrNQ7D17nzsGcX3+GwqbkJnNnUavkOBUzVTwwJycN/r+bdd7NMKVWnhPZsFbd+lamXrwOIy8nYQ0BMHU2kGb+Fuc8zgVCCqQUCTFgnW6yk8pJmoNGhSkNiDe43iJZ1QYhFXxStKgWCEgqlJQnl8xUYBsz25AIqXJyKNqqafn9ZAhSf5RSERptCVlRt1gRQyza8sB6htyxi8JZ56q7bKlzgwqlxMkMrJTKN6rIl3pY5AmWnfk0M4egQaTaP87TxtTWhBirlW+JBwRgM71Wascgt8oVfOe1z56rgZqJpBixYlhVLkeJevxyzEih8mQ0Meqs0FvlyujIgsqhEg3ExggmF7w0dn3CknGkWvVU4riROsjNKOHY1laDtcRccEUJuEtxdNZMPBkRA14wzmK9qxObVS6qtwIHuoGmcrDWTNVbaynFigCGjKJ+Wc+79Qa/XLDZjYRxxHdquCfG4boejE6gTnVjLmIJSXh+M7CJhViT8qb8cqg8euUN3oItmd7ZmftCwXUO5xRlUphceWS6j9QiwEjlbRw6ER/C6YpqWlFVUoF5OjJ67CbieJkdlEXsNAai3Zr8uCXDKWdCDPRWPUqo1vgIpDGwXp2xGRPGG/qu5/pmx7AvkIVF3ylKVhUpBnSIoNMRIFe3N4yjqoS6zrJcWLLtGUchBMsuBp4+u2SzjyAZ63Yse4+xGes9qRgW/TkpZUKphQdFFWJGyMVyfQObX7ni9qpw/35P5y3+xJJSwHeG1x69RQwLvvzlD7m+tOS8QsRXArVMCqaWcDReobOWNubjkH+XKRPhvu3FXedYLhcsl0uGYU9MgXEcub66Zr080WMaI+FAANDWsD0oAhu3SkRwfvaTssZOE+0POYOHiWpDWOdd/qMaH7r/5jomQ4dUNnTWovz/ureJNta/mdtxItHw4VpITp/vOJYcJjZ3k5OPIsvq79rrHSZCL7/2N3r7WCcoDXZviYJmtE43AJgGvB0ekMLBwZb2+/q7g+TkMPlouvhDyDQdWKC3F9NBTrUV8g3pvQ9Mz6Y2iCYhWp16ROy0ftpFMCtSDr5VTX7mKkyhNCtKsky+IwWtGFyIOqunoTR6RSCYOgG2tnxcwfQWF5XYl1Mhx0J2Cm1GSSQCuUTSUCssI5QQSONASbGaIBkyXr+voIiHafyfY6KzJv5KMJVc/UiMo7iOJCdsw3OGCL5bEIzOTokhElNk7v/KBFu28zVxgMS8dH+7gBtUa8RM3iJtneRSMGVmobfEC+bBio0T02R/rp6rnIrKsKmkTe/UAbIFoxCn+TiUiv6gihxSAmu1dQKVQNzWTa6yZv3M5KRonplyc5wRvKt25lJ0/oihmsUVYtEJth5LJ5q0ppzqsEYQcVhvwKIuw+06c7UIyFnPl52PlVA5lmaG6kHRkhKDIkh1/0q5sN3v2e4it9sB34+4ruNmX7CuYxwCKTt9LpDFcrkbuRoSCch1iKQVPV6+JnWutp7Ub0YRO+sMJUU6K5SKWlTvWl2bWZPYztfCoPKFGr9M9w4dl5BTnIjAMQ5QDeistXo+qXyhVEgx1qRLFS3Ne0cT21TJ7Mod8V7xq7Ym40ELs2S15OuMZdF3xBJ1WKlJxDyyWnhOz87Y7QZyDBgy3jsoGWfctO4VqFOCcs6J5WrBOI6kZPjKu+9xeb2l4LAGTBo5Pe8w3tEvz8m5J+dVNYzbV2K28uGKGIzz5OKIo/CV39ny/rs3fOLNc5brC4bNjuubwunvRrY3Gy4vPeQFYjzWtTlnavTWRpZYMyu/5tY7U1Gg11CqIypmbxLvPYu+Z7Ho1QhvMKSY2O12XF5dVuKwrUWFFiRazFXpfJWQz0hFRQ3rOjhGWV7+03xy5r35JcD8JTQ+l8QEdEJNcNWwL+U0JS0zEXaOf3Ni8HJ8+aiEQF/ro9AT5tc9sPOf73/Va85JyZyilAabTO2nV4EAH3X7WCcoujnOicTU+jCG44xRf77U2oGDADUvoKOTkeeKPKVEyrm2S+L0Ovq+DiOiEjbRLe8u9Hf3vefmlC626f1roqVo0MxDaZCdVqpzlXr42nMCpfdp5aEXnHUjIQQl8EUHLs/HSqGGqW2FGKwBb9XXIAclnqYcSNWrIIn2MHMYGfc79rdXlLhne3vFh++8xz5k6Nc60l3tlKqE1nCkcqo+JmpNXyfxlgw5IkY5D1k8NwPY0XDqCl2IZKvSTK0YFXU4hGgPj/dEbBZzlLA0Pw4xjRtjK8HSTK8npqp3kqI604TqwrQRpYbY1MceBqBSFGdwtTpLsckLdc1psKjfu55qa6ATauumDmGs7rhtSOFkMifKTSkcqsE0EXfWQlHOST2wmBooYyWsGgFfq+2SVLmimy9ghX7dY04WuN5hnCZ/UpESKzodWe9T5HBSMrTNeToXmohbESzUwZS6gSnMDgnDh88uuRoMEQcYhpBJxZAwXO/2PL8ZUad3M3//eqw6A723+h4tWWs7gAjWO1KKVSCjdvrtwAtKaKWo8ZcxlnEYaje2XcsGKxaZgpfQ9z27/R6dGFyt4+t6FjH4rp/2Cw0IeuKbn0ZQhjTOabtATevydF3Gapzo0CRo3N1ycX7CzW7g+mbLbhiAQucFUzQpcwaKKSwXThEir8eyVLShiDAEeHa54Vs+85Crqxd8+cu/y7ObW8BgJLPuhYcXC771C5/hjbc+x+++e81XvvYBu71Qytg2YahjKSSr6kawJDKCZx+Er3zthputcH52wdnZPb782wFre4QV4rRNKHXEgHKCDlV+Ml1HOWekWtK3dnWsyK2riLMYJbM6p9OcV6sV2+2WYdgTohrrXV/f4FxH3y9rYVNb9M7SeU/v3UEbuJlNVqK+sRV5a+IHM+0BhwnKcWw5lvC+OkDPIylKbu1w6vlXWbiihJbJXrHtT0duta9GLe7GiMnS/+uBOofx5VUZ1svPoLYPjvaylqpI+/mNAygf8wRFWtDWvrJCgW7yIWjHqG6989MOFtB8m4/oVMnCFJhSinUCb6bUBEWzajstZIUDNbAVOc4yX8o4W3A+fM/DlEUOq4b54033NwQCmS6ew8CYDzbw5sFhvSNEJZaGFHFZ2wqN4CiVYArUqlzwxlI6R46e/TAQ4ohPFpcMZoykzZbNe1/h+btfZrj5kLR5gcQt4/NLbnYZOX9C6i+wKeKK6OTi3HxS2rFQBY/aTRtycpos1USl1EpeujWpnHEbtyzTHlO0XTVtYCnja1+/tW+kEqanC7Me24mX0qDdTN28Fd0x1bMBNLnIHMufndNhdKmZb+lJ5ij1rOcuV/5PKeVg7g0qk03UQYhVJVIsUkSrXwt9V+cuoTyDUvPSmJI2WIzOWGoeE6aukVbl6byRatpWnVpjiAiVM4UqXlQQVJEWp8iIcQZ6g/QG09mpLWfbpGxRDk9DS6w1OCu1hXQHjawbs6lE75ITYlwlIY8YgdOzU8YijHnH5W7kK+8+Yx9gHHSoYhDh+WYkVCxD23ZUtAn1bPHqmCpkOm/pDPW9KgemyT+k6NTglOfgJtUdWvQ57Wxp8NHnp6wunylEjJsTbWssYtwU8EpFWEKa2z4FPcYla3uSrMZ1Meu5LCXjXAckxrouU1IreV2HAW+dIoUxk6MQxkKOgrHqfWRMwTswJrNcdHTe17Ul7MdhcnYWA/sx8/T5hk99yvLhiyuevXhBMtpGWfTC+Ynlc9/yJv/H7/8Sb3/m+/i3/+fP8NWvXlHyQDNQ08Q0U4ggVpO3enwzsZ6nBZvdgpOzC4y9h5GlBnZHXaOtqKybOaKv35Q1B5JZndOkBpTDMBBCBCss+wWLvlfECJlsFpaLFavVit1ux76S6ne7LVdXjtVKR4EYK1jb0XUdi66j824+ZyWTSyLn1n6v15lRpFukKXgUVb6boNxNSL4uejAhwDrzSTB1RIuec02Up6h/pwgvd/5+/DnuvNH0p0WcGYWRV+c2ryi0X/3a9ZPUuw+TtIakfDO3V5Fzv+Hb3/pbfwsR4c/+2T873bff7/nRH/1RHjx4wMnJCT/8wz/M+++/f/S8r3zlK/zQD/0Qq9WKR48e8ef//J+fzYm+yVuD/ZqxliIorzjCZQ440/PgaEE1TUqpGXJO6m+gc22iKmHGkSGGlybY6mvxEvTXXu8lJEV/UTPZQrNGNlVCp2PdDdYef2Zt8VQIX+b3P0A/gXlCcHtfW50vrbPEkhliYkyJmAs6TquQcySXEckD5B3kClUbi+86lVAKlLDD7G/g+imXv/kLfO1n/0+uf+M/sfvKzxPe/WXie7+Gvfwq3e07DO/+KuM7v0a/fcaSyMLo2PAUErEUCrNMcx533lCUGSUoIhTj2cuKWzllMGtSPZ/aXol1gFxhDJExxGmmUMrN0rqhX3eUJQ32zhX1qlU9pqitNvV6E6gTheoJUTVW65UbUISjnvO2ZzTiakpz77ghcloF6lpryQul4KTQV/TKCJXfo4EtxOrpIgbvVAnkRNsazlhFajCKVmWBYqj3kGPGFKOPKaq28aKTfClFTQARvHMqY+4s2Ss8Yb3VNVlVFq2Naaza2ztrWCwWnJys6Pv+qAqmGpFpG0wH94UCQ9QNuHPKsRlC4sXNwG9++V3ee7FVCXFSR9QXtyO7WNdzPSe2gBdY2GrGZlH1jrdcnCxZdcK6E3pbsKY2N0Rl7xnBOI/vqqdI11XEpSacparhrDm6/mLKuG6u7UIImnRVuWkzQDhsPbe94LDSbn8/9DXS9aBJzji2WU5OFV9epxHnWFi5NV/41m/nc5/7IsvFGsmFvneICYRxy3Kx5OFrDykFrm9v6+uNKNICi4Xy9Ta7wH/75d/gd373XVJF4KwUHtxb8a3f8ibf/V3fxWc/+x2cnz9htTrDGEspqSbRDsEDliIJCIjkybhP3bwtRTzWL/B9j+2V7+Os0baO1WuIIuTsyNkTYyGEkXGMDMPIbrdnu91xe7vh+uaGm5sbLi+vuLy84vr2lt12z1BVijHGCfm01rLoe05WJ6xXa/quQ0TdoW9vb7i5uSaEEe8t6/WS05MVJ+sVi8WCruum89LaRm09t4RktoKo3lJiudv2eVUb6HA/n+/LNcHJUyyY2zntT5uxk+/8qZvT9GdGWA7/zI8/RluOUJf2/gfDaQ/j23GceTm2KUXg+HY31so3kXb8DyMoP/MzP8M/+Af/gO/6ru86uv/P/bk/x7/4F/+Cf/bP/hnn5+f8qT/1p/jDf/gP8+///b8HVEnxQz/0Qzx58oT/8B/+A++++y5/7I/9Mbz3/I2/8Te+qc8wDTmjVbUO670a/TAngq/qmd1dLO2VNDAWUlZCYKzkxzjxKWp1jhLebHV1nVsKMxzYbi0QvmQQN5n7HJ/SOdmqvVgjdR3OC3LKnU2V9xaZXq+hE/MEXn18I5uFEAgpMcaI9UlRlAI5DkgaKDlAShSj9tcmR0xKdBLJMtKlkTMTuV8y/nJH2b7Al5Hdfo8x6GYx7Bm2gWL2JNnQmwWnThg97MPAbndLv1zirK89fgAzHb95enImi9Xk0jhGt+Q2n7DsIuc2E3Y37FPGO6/VZgizdHMaLTAf89xaYJVbcNi/VfIipJIqxF+heiPYoqZwGr7yEUwvbp5smvOMXqR0zDdo7QxV+9RKO6t8tbriq1wbVeUsnFHmTjWHK5RJPaBSepn5HqItCmuoa1RdPBuClFOpviDaihSjk3BtHU0tpkwGWUWgWEEWFrPuMIsOu/C4zqvRX05HQbX9UVv3FoBaEIYhBEJUR1DnvKpOKOxCYsiWmKpKJyaubkd+551nvPP0muvRscuaTGx3A7tBuQI6JqfUggA6CwtvWHWK3HROsCbTm4iYkUVv8Z0npMzNZk8xmiAhgreKVkmp2mdKleBrAmidoo4i2oYjK2o0X1tz+0pEpddS112qnJbDRCTH2pKYFDwJOVDktdcyxhyNVBBrGYMmpn0Hjsy3fPqzvG0cpUQ++OArnJwsiBmMLdze7tkNz9lt98QYWIwR59T4q+87Fv2Cy5sNm+2OzeYpOdXk1Gh75975irc++QnuvfYJFovXsH7BYtVDa+FVLo61riafiVKMksltDWTonmQN9J2a/XlnMTZjjNNrOicgKYqYIVL03znWgkHfL6Zc2+uRUNGTGOtE6X6ha60UYkW7lOgKfd+zXq8ZhoHdfs8YAjkHYgwMg6HrOrz3rJcruq7TligckJgLJbV2YEUEpGCyersYcYikgzaPrftJS1YbWqGJQWst3209awtE31MpArXQaTt9RU5kvuel2NU+L7RYcfi743j0zfBADl+3TC2bQ3VSve8VaMqUnGBQadtxN+P3uv0PJSi3t7f8kT/yR/iH//Af8tf+2l+b7r+6uuIf/aN/xD/5J/+EP/AH/gAA//gf/2O+8IUv8FM/9VN8//d/P//6X/9rfumXfol/82/+DY8fP+Z7vud7+Kt/9a/y4z/+4/ylv/SX6Lrum/48LVM9cpF99QMn1AE4CE4KnbVqurmFhipjbVV3q4Bbi6BxT9p7zmz/+S1naDJPAcxa+xKM9qrMun0fffCMhswtnsMMXBSGrJhEQwLa3JDJat174hh0EGAIZGsBB5IwcYcvA66MSA5IDPROyClSYlDpaI5YIufecE+EtL9iHLcMIbAbAiEzoRebMRByZpf3ZL9mYc/obdHHbjcsVqd03QIxFZZtszBgarUoqqLKpiJCMh07FmyCcN8I5+fnLIaBzXbLOIZ6zKlzSKpsODcoeU5W1NPlWBpKRSpCydr+am6hFsBOyWRBapDUAW0cnBfnoFTps7Fm8mBp16QRi7W6CbcEpeRqOViVLQZwBtYLjyl5VsBLTUarv4KxTpU/Jevknmq5P3kkoEz9XJRrApDQ1oUV0VZIikq6rZlOzhowixfsSY9d9ZhO+/Nmais2k0KFvDNlmvqbUiSGNlCt2s0nNQlMGcaQ2W0TxcA+GZ7fbPFWOFk4soF92HK9jdzuM2MpDBm2Q2AMGecEK3ZyizVkrMCicyw7ixNN9DqrCNT50nFv/YCzpWO97NmPkfeeXfHiZkuxHWLchAaVFNW062Cf9d4rqbW2SaUowVl5DxqM9FiYKSE9RC1L0SDd1p4qy/RcHkqP294uR/uTcnWKiM7SqvtB11lSDtxePePXf+0XuBojnbN8z3d8Lx++eM6v/NpvsR9GNWYMSnQ24tjtBu7dO2O58Jysl+QUSSlydXUNeFUGWkXOOptZLDwnZ+fsB0vIlt46lqvVxFkq6OwqY+tk7exrYm6xtkMk6HUngrdG223W4sUjuIqOpqmYSLkp4BRh0/3rrjBBHz+O4+zc611V2zTH2dael2nPWywWrNdr1jvl67TXiXEkhFEHHHpD3ylfJ+cZWcjFKqJaTS0nqe5BO8eIIctse3/ISandzbsdkmnfmf5d21pHbZdp49D9/yCq0JKc6dkHRVgpL8eg9hmOE5OG0kh93zIV+yKv7vTMyUU5+k6lgs4vmc7Wc9Ee+9EcnFff/ocSlB/90R/lh37oh/iBH/iBowTlZ3/2Zwkh8AM/8APTfZ///Of55Cc/yX/8j/+R7//+7+c//sf/yHd+53fy+PHj6TE/+IM/yI/8yI/w3//7f+d7v/d7X3q/YRgYhmH69/X1tf5FGvSqi8M7X6VoMp1epgv+Iw7K4UHOyklIlagWY3X8THPLBKgXhJlMg16Gvl79fooO6CIUjpGdw6xWK5M6O8dUA6hSWdD1jfQ7t79LXbNSD4khUTkpqSoyauXsTSFaCDFShkjOO0wUepvp8pali5i0J4c9C5dYWUchMoStbgwxYIwQx8zlbUFyACy7mNiPkX1MjKmw2w+EoFyXLB5nM86MLBzspLAdB7bbG5arpW56eKQIkjI+7nFph0gijBtSicTdhu3NNbebW9be0J8U3Budch5WC1KMOGsZhmGq3EPSEeUt4RFq+8zoULaJk8K8LYBa549RSa+5WsAL1S0VTWZ189IFlAvkNLeK2kXfirA6oBhjDZ0IpcTaQjj4QwWJjCqYFlZYWa2iOfAYMVZHztOSqsJUXTWDuLa1tM3A2ll23sivQqqTRUtNxFA/G2tJruBPOuz5gu5ihVt0OK/crlIKxrnq0MvUTlWZuFrEhxRJo07BDTEzjLWNhaGUSCqZIRW2I1xdb1j0DtetuR0zQ7YUo3LyTQhsQmET1GXV5oIpiWXvOF91hP0WSuFs5Vh1nnG/ZdFZHt0/5WxpeePBCQ/PFjx+cMqqd2z2gWePznjn6XN2obAPCWs9lEIYB7b7gZBBnGU/aJVuXVUJWa1dFX1L2uJJFakCxFjIEMaxqj/UkK/EXAsEvUYFTQZTHaRY6rkkqzfOhLRWA8b9btDWrLU4CzlHnPXkHHj+4bv48wve/vS38caTt7j82f+s15EUcq6TiQU678lFeP7skseP77NcLrl88YKzsxPc02fkUug7R2fhZGm4f77gk2+8TmfP2OwKISWsNaxXK7q+UyIxjkMHGkXelBPkjFXelug1ZIzBW4c1liYxz9V4MaZU0ZG6xxZ1oS4TSDmTzXPWRLcNb9RZUJXzQmuhFaJknOgUBqmqueVywcnJCfthIIbAkDMlZ8ZhzzgO1cmXCc2VGtFLKWRrpqnKpm61pgZx5V/J5Co789+aN44i2A15+PrBeV4PUtu9czpwEF9eYfQ230otTg6K3vpvagzJ9WH5MJuQxo37+mkJcjjR/u6jlfvVNht9VDlCTb5Z5OabTlD+6T/9p/yX//Jf+Jmf+ZmXfvfee+/RdR0XFxdH9z9+/Jj33ntvesxhctJ+3373qtvf/Jt/k7/8l//yS/eXiQgks369VkSmVYUUjog5ZSYpttCUs/b3U0VMQlXrxKgmSSXPFU9ru9jaQ1UGen2f6TVfzhKP0I72AQ6ULHdht9b3dM5PCZaGqsZFyNOiB1HfCiNIi0TiKJVETA5I3pFTwMWBZRnxjJgUcOOAHzPLLrEygT6NWIlApjeWTjxD3NMTsCbSOb2wSynEqH3ylEO10ld315BUhq3tMbCuwxuhODhbWNIQ6aRg8560v9WBXwR8HLFlR7ndcLO55dmHH7LbbXDsOOsTp4uOJZ5hV3Cr12r/WxEGb61KVztl34+jqgtSDkpwLdRpvtDmaqSc1OIaUVJo233QajhIHQYpTMgUtc5QhMQqUbYSj3MuFPXjpu7Ceo5EvUQcQIaSDKOzRJNBUrVXL5r45IylsHSWnkLJldiZdeCfwcwmcqnOX6qVGsZrOyhVhQGCjl5o3AKZNhdFPxpBt9LIpYAFe+LpXzvBX6zJFsRWVVDOiBViybhipyQb0SrdYMgFhqCeNzEWwpgoqN/KECMpRIr13I6Jy5s9292eIXpuYuFyl/nVLz/j6Yst21DYxcI+JqZlXoSlh9cveu6fdoR9xCL0vRYmse95cHHKSS/cXzveem3B6/dPuThdUEpi3TnOV+c8vrdmFwo3uz2bzR4xKg3eD3us9Ty/3fPh5ZZ9zOQSWfUWI+q5st3H2v5DPXViokghkjHWKdIkQjHqm9FQFREliKe2b5km883VW6Pa32dF5UpV4g3DwHq9QCqvpfNOCyYKOQacGC7uPeD951d87Z33SDlgmr9CPXAxDljT43zPZrvn2YvnbDZbTk7Pdaqxt+QUWRrDw4uez33LG7x2/x7DDsQrd0UoLBYq2+36nlwMKeu4Al18es5FwFZulghaHFWXwIwWDZJjRTB0nlZoPLDcRl6Upn+ohUAVKuSkrcJ0PCfrsM1WDp+XK+InSiA+PT1lGAbGmqSklEgxstls2G63LFcLjPOYoqMKijHYUijYqRAUhb9qO7WQmnqt5QLSiLEyJSdVpDjJjj86UanIZENIKFNYaaEsU4vScoy663szFUkNQT1qHdYHTSgwM7rSMqDpWjv8TNIaSzK/zkFqIi2dKnP7qe0L+njltIgcK5q+kds3laB89atf5c/8mT/DT/zET7BYLL6Zp/5P3f7CX/gL/NiP/dj07+vra956663jRSrC4fmaa+M5a2sQVKbajhfUp6Cy+WPS/mZs/47q/dFurbWiydDcg59uLZGYoLa7J6KdMZmvpvZ5W9uhPs4Yh/e9ki/FqjVPmQmhMWpwbQP3dHGpeogKQRprKHhKSuTdJXb3HJcGch7pvCWHAUdgmTOrVDjrDCVuSWGg6zwn3QkiiVQCOY2QE6UlHhnGOireVv6H8nYKIaRKVNV2g/PVKjplTozBr5Qfk1ykpFvsboC0IQ7vQ7zienfJB0+3bK4Hei88urfg/tmacdwjds3zD645Xy+4vLHEXpMTkEpQ1WOqM1sMKdZBhKj1ONUDRAP4QdumtiJoawNDTiBStCkiDZF42bxrnoacJlUQVHRBVDGxcB68YxyTTso1SoI2Uo3jUqnS14IzcNJ5rchSQhqnpL63mdb1PK0WmJKkJqWGPBP9pgq+OtpKHQNvTEVGEliDXXW48yWLszXZW/XCMBWxmdqJWoepQ626rXpfHTYrIqPQvNoCl1wQq5v9EIXdELjZRa43e0KG2xh59v41N8HxK195xtc+vGUTMkPU5MkiSC6cdMKT845P3PM8ebBkvTil9x2XV9dY5xDWnJ0s8RK5f9Lz6MGai5OOVW8RHGMIGCLduuPcWE62lmGtQenmdoOzp/iu58OrLZ2/5Pn1hs5Zzk6WnKxXvLje8PTFhtvdDiOZIgXfexLCEBPWeZ2GnAtjHQg4tX9DJE/XZDt3eUIAimHiVMScaxsjqeFY3+ljnU4UVhWJI0b1Gvrt3/gNnr645ukHTyGPyqER3UdaW3rtPQ9eu89+d83V1RW3tzuuLreVf9EjxXLaOd5+8wmPH75GyZEQdvg8Mo57APpFT+c7bXfVtoJpYwDQNWpEx42oDD9NyGTOpcqp90ihFn+KsqWSOZx/NO3XVQrbUKtYURRqy9eZypm5uw+jCUJV/murx3kWi8WcpIwju92OlBLb7ZbNdstpOKNf1IGh7ZoGncNU7aXVpO/w/WZPlIkvJDInaOW4OP2o4HzU7vk6j5uQ1+Nn19do/zo2Vjt8/TLFHTn63TFfpmVbheOezcufaUZ2DqDgg2Tm+HkzsvuN3r6pBOVnf/Znefr0Kd/3fd833ZdS4t/9u3/H3/27f5d/9a/+FeM4cnl5eYSivP/++zx58gSAJ0+e8NM//dNHr9tUPu0xd29939P3/Uv3380OJ1pTQadeTu6o9QRMZMx6UVWVRwiqAAnVVlqDvyYsFF3gCiPqhTmTVw2HGTMlHy1G/SzHZKiSs86LYSZOzhdlI+nW3qa1eN+pVwOGnPXCHkdVqfioKgOVdAqYTEF7t4ZMFqdtirRnnW85kUsIV1AiphY2985OyGEPcWRllpilY5CgbYg8UkrCS8IvPbe3kWKEmJQIu9uPGpCTKmdSFvajVkX7EIm5AIYxKjqSwkBMGd8vWa979rtnyP5d4vWG3eaaq8srQkgMQ2K9tDy6iFyse5wr/O6Ht/zWu7fE8iEeuDg/4ereAnDcP12QUyDmoN+/Hk8lZyqHBVTNY5tbpTSOScsVK9cAIUuhWPSx2dIw2lRml1hVC1R76oNzOJ9HrSpFlFBtjVEEh0Db1JxRNE0wmJwxRWfVLEzhvOspMShMnQvUJFVq9VSvAJ0PUytQW0u5hrVZq34guZZwbcZLq0qNmGpOlsgGigOzdLD0JAvSiMKNxFkDUpvObIwawTlr6jo0VdJsyCkyRm2hOGsgJw3k25Hr7cDNJnC7j9wMgZsh8/x25GtPN7zzfMPtkMEalctGKDmzsHDh4dvePOOzb15wsfZ4UZj6YnFOTGq2tlp09G7B+apj1VRnMWK9o3OGHFGOTYFuaRmcMITA8mKJd64qkmAcdqw7w2rZcbrsWC4XnC09q0XHZr/iZNUx7CO3m8BNyFxuBmIMlUh9WNTU6rLtFXVtSJ3dpAhLxDpXvTU08MeU6DrPatHXvSrSZkPF6scT91u2tzc8u9xxvdM2uHea4IpQCdKWTGGMiecvnmMILJcdF2fnXL3YkiUS9hvuny958vCMN19/RO97NvuRZHYYMmEcKaXQdz2+87qvVQ4XHPPg6peevqu2dFQNud+Puidk5SapxL61yZpDs+7delWk6brMtSUjZUbL1e+lts9M+wxVDl6qGeAUJwRvHavlkrPTU8IwkmJiP+wZx5HbiqKsV2t85xC0RdN4VqnUovdgf2/FcVOz3VXrtN8fFjPfLILQHj/Fk/b/j0BgytTinRGM6bdtj+JO8SxAbcfd/fxHycrh4w9MMQ/TmlelHofn5X8pgvIH/+Af5Bd+4ReO7vsTf+JP8PnPf54f//Ef56233sJ7z7/9t/+WH/7hHwbgV3/1V/nKV77Cl770JQC+9KUv8df/+l/n6dOnPHr0CICf+Imf4OzsjC9+8YvfzMehHY6cS+1ZatasLV3tt9l2olprpW4QTXYaQiSMgRQ1S9cNI02vOb1TzRKFNr24TuNVdmF9C10Y+jPz0q0oZN/O5vF5atBbq0Zmd9NmtwwwjoHtdsd2s8Naj7GO9mvN2HOFi4UkI0iiG59zsRhZlx153GKsWjULwrrLZGNIRrjZ3LBY9CSEcQx4P2JKUhTHecTsJ4UCaOshxkxMobZ1YAyFIWTG2lcuUgi7PUPU1sM+BFIx7PcBJ4n7JwZbblnKSH9qCNEREyzWS3KO7ENivy2898GG80Xh4YMlBUeWwu+88z7f8vbrLIaAJ9F1Vme6WCHEEVORkpymw88MUinKNGUo7cIpubY+MuLdQVWipE91AlWH0MOx69TZRoZy4DJcvWhkdq1t57KUOkeoMKEYgr730urkXSN2gus11WvnWAuDyctWsfTKKWmoop2m0LagJxRKrnwOa2YzOsA4CwtH8QKdIRstIk01zvKTzXepvhFmHslQg0MtBYghMYZEioWUAsaZaileEOswNrPZb9gMkRebkWc3A0+fb/jw2RZThKWDYiCMmVVnWHSOE19487WOtx8veHTq6Uxh1S+IMbHyPcOoyejFekEMAwvvNGEryvewRZGj5UKHZaaU6I1h6S27IMQq04VMWVreuLcmnBW6zrJa9rpMUgKWnK+Exw/OScnwztNrfvvdF9iKAmhgpu4jyhlqw50monLISG6k/LqmYsJYR84JirDsO/q+15af0TlFMYy1nWHIMVEsXL+45GqfMf0SVQ4lOmtwXhiGUdUyJHbbPbttYL20rBYdZKqUNrFeOu7fW/GZT73BYtHx4YdX/O7TD7h4+JizB5kclcuyWi3oO1/Rjrrv0oij1KS1cvPqsW9rdRxH9vs9vrRWZpX11+QEqitusZSspHkpSdUsU9/mMPBXg8w7o03UZbnGhakZIfVags4vWK/WjKcj4ziSS2YMge12y83NLaenZ3Tez9yqUqpQImiiXgFrI7N8/NDzRz+b7gczp/Dlqcfttdvv5xBRju4/RD4OUZuXQ0sNKgLH7JVX3Y5RkiPs6agNcYy0HOUq03cuR92KVyUoL9Md7Cse9erbN5WgnJ6e8h3f8R1H963Xax48eDDd/yf/5J/kx37sx7h//z5nZ2f86T/9p/nSl77E93//9wPwh/7QH+KLX/wif/SP/lH+9t/+27z33nv8xb/4F/nRH/3RV6IkX+9WmPuWmlDUfmUuNJ2qrRBfQyeOk5PEOAZiRVAOvUNKrZTnAKTPtaZa2rumff/6mu75hLcN/I5ufPp7g851+aQjz456fVaY9PZmw83NLWKsJg7Ts1EZpHaogchC9vj8DCd7CNfcP/VKNEuJYQxsN3pR7zZbAO27V/a8yMCq1xaTtsMq4TELGZUCpwJD8xoJhZggZgix1CQlE9MI7ClYLjc73n9+xXZMLCw8WhXefGB57cSw9A5bMs+3gWfXN8QipFDoDbxx33F/7Vj0hptgeH69xd4/58PLHZ01nHbqpuqd52R5SpEbwtUNY2ltMANFDctyvfBy0gpNWxjz5F0jBe/stGZiMwQTQYzyCgrV5C0lPfqim3WuqJtzlhhrm6No4NCstFUSpq5V9UhpiYKlcLrw9LZgiqqYphUm1ADWyOFMn7HxTpQ3qwlRc65VWWiF4zETSY7qhokpFCf4dY+sOmznlTMjOpMmpUjXuXpM1KvHTQ6sVWqKokoZQ0zKTSpFfS5ibFOMVb7fZtIMKXK1DVxt9txe73lt5Xj99XvEFLjaJjbbQIqJ1x+e8/jBkntreHJvzbo3mCyQMuuFBXHsnLrt9l4YCwjK7YmmYL0jZp3J0zmrRlwokXVMmUUs3O4GXQvWsPKF5cNTxDour2/ovOH6dochcn/VYYzjbGXJxXF76+idutfWNFbdhEUwRWpS2HwtVInSZkYZEYxz5Bxo6hNjlERqvSaYIQTE+yq7rcibc8SYdI6TiXTWcnVzS+cdQwgMw0gYlbOSWkEh0Pue1WrBvXv3uXp+ree0Ex4+OOXTb7/OxcWacYBf+fUvc7MfWT94Xa/nmDAiLJdL1uv11NYxZlapUBETQ0UVpJL0pRCTtoLHcVSyurFVeKC7XT5IUKgcFDW81ASOmuyoY3FtsztVlrVZPW022WHVr9d5Y0/op3POsVgsOT1NjCEQKlF3HHXa8c3NDX2nBncpp4r87HUkQa/3m1pItP1duSY6zbj9u/kj3XWYPUw0XoUm3E1KjmNI2+c/KgE5TCgq1/IVD5tN31rxfuc9Do/j9PxDZPjuZzpMal7xsQ7u/2baO/C/wEn27/ydv4Mxhh/+4R9mGAZ+8Ad/kL//9//+9HtrLf/8n/9zfuRHfoQvfelLrNdr/vgf/+P8lb/yV77p9zpsm+TS/Ep03kyp2bSxDfKuwHfOjDGpwiRocpJzqcjLge+AHC8CRRHngYStt9wedVe+pc9p0uO5DTN9kjIb2hxmzSWX6U+TOLbnZZTfsdlsuLm9xXqPdSrLNgipZu2GqGoHM3La73hjGTllwBpY9h3eOZ5fb0gps9nt5+F5OUPI1aZfeRcxZcw+Vsms8kxybU3FOm7diGFMgTEkQhLGmNmHpNbSVbo5DJHL61uudyObZNCxbplkHH55yu14jQmQsoDrWfue3hdOu8KJLVgyCZWdPr0c+GAbGLJjvxvY3V7xhU+/TskRa2AXbrjdblVtYSylwsApqcpEAQ8zzYppbpGFFsyPk0gxtiqmalswp7rxMz+2btItwFBaJad+GDk2bgiAVPJ1mZC+ggaszhROOqPtnqyVd1UfawWG+o0o4sN03pyzU+sG1PrbCOoMa5oDZpkQl0aSRSBZwINZWOyyw/dVuima4KtCTivjnNtAs1zHMdRhdlWmq2TpxBA0qJGhWyzIFT3bDyO7/cAQEzebgQ9e3FCK8C1vPeA7PvMG91aWVAJXQ+HF1YYXL67pveGsh4dn69q20WvbOoezBesc1hmGMeCq531KIyVbjNUhh7lGUv0uijp67/Epw37E7iFUeG3RGZZdh/cd5MiAJaRbUoqs+p6Ls1OMZHah4L1ltVqyioYYE9bCbhwpeAoGavJxdI2XrC2E1vqt5yTlmowWTQpDUE7KMOwRgb7vdEh4yuSUdAiod6SkQyN3Ya+JYNTfl2wmabMgFKeDRruux1rDMG5YOcvJiePexQknJyf81gdP2Qbh5Pwx/fKClOsEb2Mmue5k419agnIczKRJt7MaCyZTJgSltHbClKzrWqK2czSRU4SGNvS0rkF1X1HE0XmvifSkdGxpfIU4SpPB6odKpVpCiuB9x2q1YgwjYxhJKbEfBja3t1xeXuK952S1IobEbr9nt9tRANt5JkL6QWurFaqNBDr/vUyPO3z8ywjJccH6dbkqB7Hl6z1HqIIJagLZ3qZIdW8+Rk6OEZqjjzT/W44ff3g7bEHdTUFmTs43l5zA/wUJyk/+5E8e/XuxWPD3/t7f4+/9vb/3kc95++23+Zf/8l/+z751VZPMxNEgprq+jrhSFLbOUm3AVWsfUiYGtUjXCz1PKP/Ra5fGztaDa43Qd+rm6FwzyirzxX+wGET0ImoDcUppvcF2M9NC06xUV9CM3uhzjtxgK7QfU2S727LZqNHZZBsjRl0bKTgCXRk4WyUe9yOP+kjebfHWsXAdQTILPxLGqIS8oAPjBG0TtM+23Y+U3uucl1CPV9EquE0v1ocajKjLaBYgBVIu7GJiiGqp/eJqw/VmAPE60LFuUC82hV/68hU5DhgxLDs1J7s4hSennidnFl8CxXZsy4J33t/zW0/3XO4Lz262PLlYc7J4jPg1IezY7COxVDk0UmWGGrxTLuTaBjOZKn301cV4noVTqny7tdv0PNojgnJLHHOeyc3aOz9MOCsKV5qBXrXpDnWwYU0alOin3KGFCOvOYtp7F6ZEx9QFllJSjKwSYsVoshGSTnQWMycnahpYp+1mnV6q40Sqr4wVysJg1x4WFrtws2NstYx3zXzNaUuvJc8mKwoZYwKjyeV2Hxmq5LzvOl3DY2IYE9t9YrdPbPeB293A9W7kZhM5Wy/47JuP+ezr55wvCilHnl5vOOsWvLbS9tWi71l3HQvnMEZVAc7KxPGw1Su3t5alXyNoa9JZq4MDm9tttSBwzuK9OiQPY8BKIUum956Vtyz7DsTgvWUIhcVygZTCwqlLLViGFHBOxx5YU1j1hhgHeifsAlWJk+ZWX9HRGK2NXGprzBqjCa8peOsnZVZOhqagcN4r4bjuV5oIZ0gBLx2dNexjgKLcjBwiSNJzXZOHmAqb2y1Pn36AIdN1mXsXKx69ds69i3NSFi6v98TiEL8kJE/KRscq5ETfd5ycnOC9J+dR1+ShiiYnTFFZ+yEfqaRMDEHnGlX1o14X1CF/1YhRlNybi5oYmlL1LNWF2Ii2b513dZiftrgPUWyRWZ2m1yJMyPTUsxdc51mfrIkpVhfqNPEnnXOU6li83w/sh4BYwwpqUVOYkxN1QH6Jl1LfT4OyrW2fw+K3xZjDYugYZTlMsA4i051/HzVoqDqjg9ebnzMVNK9Ifg4/tz5DJmRkVul8HYCkfuZvLAX5qFd5+fbxnsVDC+TzhGElvQZSKdjsiNWvIWdNRppJT56Sm4+CyhRmNKbgjA6Raq6DU3JCy0LL0cJqc1GyqPgOPqo39/KiOUxOFDK0dxaZXkjb3Z6TcUSsqwujUESRAFMSndnzwCfOzBaXBzXbqi0ASTr7xjvtZTfXTzFoWynWCscaxpAxUWelaIWu3iC5zLJn3WQtY9HhXaADwXdD5HafuLzes9kHDaZFDZs1IA9kMdwMkTSCKZmbW51BkzGcLBOUgYevLfngOvOLv3PJlz8sDFH5EWN2bEbDPnk+vNmx8MJunxjHQWfYSMEWmRCinKmqLCHluqGaVk0YDQzoBdlkuqBW9TkxrRmRWR3RbproClLJ0odKH7UBUA5LjIrYNbM+QZTbUDIGw9rB2lus9tkwYojM6/QwEdagR904dB7MtCGXRsw9WJdiwOTJaTmagjtd4i4W2NMet/a4VY/tdCJ4QXkbi0VP33nEVv5WnR4bQgZGjDWKnCQYxkRM6jES0h7rPfsU2ewCN5uBF5uB7ZjYpsw+F7b7yOlSCPtbSlggi44QBnqT6daedWcJqWCweKdJBkXPGwScWWjLIyTEO6wUvNU2zsJbFtVW3VdpsLeCJdM79dDJqPPsyUonCnedZdV3eGeJGXpn2QwDq77jfNGx6ix9VydzAxcnC+6d7Igx4O8t6Lzh+dWGdz/csRsLuZJfJ7VOhkxEDMRyoAQzM+Kq7R8d8BliRM3PHLkkxhTwxiEV7QtxQJzQeYMZIRs978veY21CnGUIiTDqLhRiIoSRxw8vWPRLvuOLn+Kt1x9gRXhxPfDiekOxlmy0dZZTJFSfkK5fsF6f4JxjGMapGGvJVzYyTRWegpXodRFjZD/uKGJwvq/fVwsDTS0duaiXjBGnKEoeld+EcnCcsXTO0fkO5zp1oa6KoqlyL3OB1dxbp70VKqqgx1cTrpUi6Qdy4w+fPSPGzKJbKD8xRZztmEY31CxfE6NUERstuLTUbFwTW2uQPEWA41aPnpPjNv983zEqcviYFp+OW0W13pkedbcL0OLLq2530Q05vP/QW6nUjsSd3tFHoSNTQlbVjP9LSbL//3crUzCfRt4nrXCbp0AjKylseIhSVLLWXWjrTlvHVoda7z3eO6w7JEXNPJV2AqY5LsyLMTeos8zTFOYlMAeeWnNPj2+vYVorol56IQaVyoWA79XJsdl1OyNIHjlxgQdd4cTpposIKewZw05lrtaQimVMCtWnCqsW0dp9em8t4adeavvcuSj3BxElQ07HPzG2eSspc7vZs90HxXWyWrGbUpA4cP/E8NqZxxvHMARiKhhnOFk6Tjvh/PSEwVj+29cGfv2r1zy7zoylr62Hwpgtl9vA735wycVZx3phCUMipcA9v8aVOuXUGIZxmC60GCNirHJLiBNSZkyr2BrZrkxEVmMqYsGsyJrY+cxOiRyhcW1gH2Qp5KowslbhautsnaVjGEQdXM9XHocmT6QKd7TPVAcGilBt1PVdfOd1eJ1pyJwcXRuTPJ4CYmuCkkkGulWHOVlQVo7UKdJjtTODFdGkwCkiY42Ac4Q68gGgxIQkbeUNYyJmYYyJ7W6k6xySIcSR7S5xdTvwYjOyGXbsY2GzV07Chx9es3vcs9lucB3kbFkvTggxYq2acxXAoufLVSWWkYyVjCHhbGa17Ka1sVxYemfovHqHdE6DraqOHJ1t1WFh1XtN2KXQ97YOaHSMQ9D1g6IbvbM4U+hMwTs1Hsv0bDYL8rjn9SevaYJycYrlGV99es0+K76TYq6GeWVORHLW0Rxipnbp1Aou1GGUGWu9Jv6m4Du1iE8xYyThRAuhRW/pg/oC9b2nc0s2+y0PH73Gu+9/yG0KdV0bxBS6zvDg/opHDy5YLTtShBfPrwkhYzuHdTUJK4kY1TOk73vOzk61xUjzhgKRqrQpdfKl0b2wRUwtBBMxBGCvLdCuYN2e1VpYLpbEmNnvCjk7JbWXiLMB7z3L5QLnekIsOO/onKezHm8807T3KQk/3ntn9ISpZWpacSmGvl9wdqoW+jllbrYbdrutXmvLpBPEJ6TIVkfr44RCbf9bS8dUL6rZXHHaDQ5Ivhqoj9GP42Rl/h4TAfZOrGhF9O91K7U4OnzpKW7xqtZLe826308JWC3ISy3Njwrn5pfSUnf9292XbmTmb/T2sU5QDqtF5cXm6aJWSeacuerjDpOTdtLv9s5mVUaDX5V3Yuuk5Jm1XqMZ+mjd1KVC8VYgi5DqCTl+30ZzKtPn0u/Tll0b8d2SlErGFSW/aqthUKv6mBCjdYhBUQJfIm/fszw+GZBxzzgknHeseq00czHTRFBBfWCaZbvAhBBZUdJbqeTS1n4KManssSYsQ1H30CElhhjZjZn9EMlZiairvqOI4XaISt1N2uIYkyGEyBuvr+m7JZt95GZbWK5OiCnzn3/1KS+2sEkwRKEUddMsZMaxUKwljoHffvcFQ0pYSXTGsu61+n10sSLbokTiGAnjXtGPUiDPXgEGKCljjBJksygiEsuBQV+BtknMCi+ZSMwqN56E7jrWBTMhLaa2Yay1JAq2GLyzWBvxzuFMwKTMibOQIrGo6qPkemZFkw+1VE+0zakRL9vMnWbF3ZC4BsGXrL4dmTY/yEIHeWEoHpy3VXHSzJqKjs6QTEpBTa+SfkehJaiQk85MSQX2Y2QMaeIgbccEYkhFGEJhOwQ248jVdmQTYbMdsCXzxsMVD187x3cOK9D1Ho+iCrHkyeSqczr9uPNWkZBK1nXGIk3uLOCs2t9bA4vOK+/KGkQ81ohOzi6qjonVOKyzwsL39Zw4/U6NY2UK5ERnLaves/ROpwf7Du97tpsBWxLnq1rEWM8QDZfbQLwd1MKsugIr+lQVXVa0DWMEZ4WUpfLOQKwy/H39bjEHTKEOLpzBd22VFJzVmUQpw2q1JMdIZ+H+2ZIP3i8sfEdIhb7zrBcLrGTWiwVhHBhGx+XVyHYAbIctkX7psE4R0pgiKQW8t5ycrCaSLGXmj4igcniae2pDjDKFpLtjGjBmoLg9fW/41m97g7feus/bn/4k203h3/3kz/LBe9f0Xrg473n9yZucnT/g6Qe3hGh4cbnFOK+eN85W9LiWfK21PqEScztHL0ndw/Qz18unGJztWS414UsxEXNiNwxst+pSvFgscd5ri7P6CWWR6dhTPYS0rc+kpNN9+7DlU9AJ0HN7iBoJSvvwB23huxjDlLjUrzOLEWdVJQf3NeS0PbdUlPWoxVOOnjbtF+3d1RW2JWAH6ExLbOo+IPXzS5mjGsiRHUIrDktrG3yDt491gjKfTK3g27TXpoHXg3eYwbYFcLyI9Cd6Mg4WTzNjc5Ut3mzCp/Pako/6b9OySqPyZq1ypJIcD05MqShLaYMF62cBvaDz/Fh9z2psMFXGiRgiMYzklLC1d6uOqIm1LzzoI7ubDzAlcLJe0zvBSeZ2HwmavWngiqEyYqReuEomU3tqU42JALHVeVFJsc4qyTXWKiBWW/OYiv6Jkc4blWPmzBgS+zCyD5loDKk43r+M3N4mNsM1b75+wocf7Hj+IhNkTyiFfVD/zIyoPLVm7CklhXZzoYjlchfZ/O4l5MiTB/c5C9C/2LFcLCilENKuBiVFxLzvCTFNs3ooSn6tVmkkMsWiP6nzZrQEa6eNNqdHrf91Xkebkgya4Bi04kpFJ3Wrd46aU1FbMDo0boczwtoUVhacCEG0DSUlqUW4pq11jc7D5EDVM0baaPa2KVpKnfdDTU5U8owiKJ3Fny8wJz2lWrG3qirlrEMERYmcmoxUX4lSk6Sitvo5S23vZEJK7ENgHBNDyoxJE7UxJlI2bIeRkDRx2Q7gxLJyhcf3eu6dLjg7WbH0pg481ES8s2qoV4qpAxUFZwq9dzUhkYqSqa+M98o58U6HIfbe18fKxB3LyVSZtrYAGwFYRy5UBV3KOv/GGvreE4MmEZ0xOmDQq2PwkALLzvLo/hl9p22Am92W/X6Ls+BEnYYbjwJ0UGCTnOasAxtNTZYaV6rkqPtXkerLUWXn1OGDdccxRrSFmBN9ZylR6L1nM2x4cLFiYbMiiRU5MTbTdY447rCi06Vj8fSrU/bxHbLA6dmaexdr+oWGhzacj6IJjrPKwygY2jA/EaYhjiqprvvctDkmFku4OLc4Hzk5Mbz91hkhXmK44Nu/+O3kMPJbv/ZV3nj0Osu+48XVNV/92vu89/4tYtaYbqnFhtNzhSmzj1jJMKk1WwYyhYkaQCsdoO7FrQ1ijGO5WpLzGakk8hXs93u2uw2FzIk7nbhGYoDckIXZ22NORmYvq1eLLY65KmrFUKP/FJcOyNMt1kwx7ODVirz0u6ObzK+j+/sdcuzvCWS0x9b2dY1vpbS0Sqqj7YzvlPq+lBmHKbW4E+bY+o3ePuYJSks8FV7MyVQtfSYXMx+1b+DWNvf2mlIllm3AnvaQ24uVA5hqSivR6uFw4RucKWRTq9zfA447QllqDnOXvKRyWDU+apN7TeUVmJLpTMabTBFDoFPeie/oO0FyUFRgggjbBTPzK9r7O2sxtqJJzZSnbnJSwDqrcu4CUnSIm5WkQSwFyBFrhPXpCmfVQfV6F9mNexIVUSieIRaevhA+uLylZEvJPVEGMHXSR9HZL82XQChKFsToxl+VWiEqAfR2F0gBttstRYRPPLnH0hWkFLw4tZrPc2ICGrwVXdALPuaiRFmqyVqbwZELKSoqYI2lJB0Yp8dt5jSllCZTNNA1pGqbMq1X5RVYRMZp/PzSGDpnyTFW63n09WsCblR5qeqIA0i4IYh1dzhaR769d00yrLW6v3YOWS9I3lCcEMizd0VKSG2BFBEyhlRMTZQgBuUaxawVe6jJ3ZScZk2uYsrc7vZsdiNFHLshsI/aCnpxuSOGkU88POVzn3zCk/tnrBeOHIdahUq9/owmS3XN2IpEdQ3VFCXxemtwztB5hxP1bmkqpBhGUgRje6xRf5TmS1GKurVSwHmvKr9RHYG9t/S5sBvU+2VKdCpnK+VEDAPWFDrf0VVuyqp3SB7obOLiVKcGx1yILXDmQGc9uaBJfVFUUKRybBoqnHSKso5HyBirNvqKrlDnx2hwy3HEGU/vLJbExdmCi7MFDx5c4Nw7+GJUnbQyWFs4P1/z6PE9Fus1Yk+wZkkqGeeFNz/xmNffeIuULMOgydowVLO2vtcBn6gH1NTSFiVJC4pCqidQpe2XgncGvxIW54aTpcFJ4f13v8qih5sXZ9yeP+PxozXC63ztty/58u+84PnlNal4jF3Sdyus6fT8WasePaItv1ILgbvKloNNk1bMTtywg4TAGJXKL9crzkuu6GeZZsD1fT+hC4dtpHablTuKod9t7aRUyexTMfyKIF3mzzwZ4h/s01PTRRoacTe/mJObumSm+47R+5pgSHuFGUZpbSdNRMq0f1VItf04OsaHBf3Xux094n+fFs8x/ySbmWPScI1DUk6pR/i4rzcjKzAfO73I5CA50efyihNyKLECpkxRTYsKNlVNRvscCK86RYfchiYPnGz8y2zK1bgROrwv4nwPIljfYwxEZ3nv9pbXl2tOukBOgWGf2W83OttFlFmvPitpulantgBQSiIlJoOupjrJYkhEJCu6UArVZyTTJo4KOqCsiKorckqMw4jD0BvHNkSMi3hvkGSIouiNGLA+IdlNE5G9txWWr6TcCldO8t6siYyaKAn7MXNzs2PVW8KXn3K9j3zi0T08iZU3LL2Q4ogU9cfIRauAmHV4We8tvg5q9M4itTp0ovNKJBdinjePhjzo5pcmWTmVTCyGyQ+hrbnD9SPopmlFOO86VZxITSpEE6VSqIELsAWM08preo0GczffBYgx1HYAQJ6QP6hryqn8VhEVmUYmqPuyTMhJSAWxRaceleqoKZoghhgIqaq6ss5iylmftw86OHIfMwEdvrcfEiEVtkNmN0bun654+/UHvP34gpUrlBSqKqfa8VtFLF2dWGuNOtSWnPFOp8/6SrxzNSGREhGxrBZLvRbGgRjUdt4Hj7da4YuzmJLR7KBUpNToQMO6D5Qx4aSw7lWNtPBW14fXtgtBTdFOFiq1XnSWVOD+2Zq3n7yG8z3Pr3ecLh3Xt7s6o8iy3w8UkxiTJRlbZz02jkDGSCHlhJWKTmCrn8yIOFeTYl3/RoQUI7YNcrSWzmSevHGfi4sV5+f3leTpPafnSzqf6Bx88q0nWF8ICVb+nN1OW5vnF2u+8Plv5a1PfobnLza8+94zUtaJysZYlss1y+VyaiXSdj4pSHVOFvFYt8A6RykD1mbWJx7fjXzqU49YesPTd96hc5bXHz5m6c74xZ/7Fd754B2ubnZcPvdcX3Yk6bC+x7olWI+xHVInF1txk1FmkWbl0NQzxyh5C/bztPrjqdM2z0nKen2iV5QI19dXDOPAsNsSx9ODvV6OguyrAvRdpESDeRutcUywLxWdneKDNIn0ASdlKoBh5rncfddD5Kg9D1TWXepPDroKx8lJQzmYHnUQE2eo6uA9XvX+898bIvs/c/tYJyhwnB2WGiByTkhRx8WjQzbp7O+cRJigcZWpyQS/K/dknnB51D+cIDy9icg0uNHkNsWyTBX04Wdug8J0dLz2TFN1lTzkMjTCpjHqkqsmW2WSxeWoVZYOL+zwiwXiApcps07CosDCAiXS+SXFRIaYp9bVmHSqrQ4azJWbQc3424XdFqqZFne7vznwFjLGGTBCKBBx7PaB2/3Ize1W5ahJZ2d01ikSIxkkE5OQiiCStcoURyyAEfV6MaIk3uo8mVsi1QY/VihcEPZDwFpPKML1ALdfecqLF1se3j/l3mnP2cpqtW2FMWmC44xDrEdK0uBdyYzNA6RxkXRDdFA5KFIibdNo604TSju3ewp10m+uHIRmKpgrgVWmQLTuDFLbaBZF3hA3VVfCnEwrom2mNRKzkjBzAm/Vb0UHImryY6whkUklYYuFGMnDSHfiMQXclNJzQMqunz1polIkTPbsiI5iICdiipq85KKjGGJSL5RRE5jdGBlCYRcKV5uBD64HtkNmZfecdI61K3RGv0/MGe9cddctOIHOWRa9mpWV0tXjplJs7z2UVPk9eu12nZ88OIy1eDOPpUhZHyugv+uUa2IqcVjE0Hk1obMx0jttpZSsnJfOCZ1V51mDqoLWvacgLHqVc2Pg4fkKJHN22jFG4cXzWwoGv+gZU+Td9z/k+dWIs47toHJ/UCmtriNNOn1VD4YYSTHSdZ5YDRy9d4QwKk/JCqbonKeTpWfRWy4uzrm+3WKt5fRiwfn5kjhuePP1xzx6eEEk0i/PKWbFmHbYrufexZpv+ey38rlv/TzPrjYkfo0Pnj4jBN1nlqslq9VqKthEFF0yYvR6KLqXLk8W7PYLdpvEeml47Z7DuIBnz6o/5TOf+hRvvv4273ztA37+v/4cV7c3BDZc3H9EMSswHjEF6w22E1yvk+N1qrOrDtq2SvHz1Hp46VbBgNYOvbsPt0KAmuwZY1kulvVxmdtbmZCXQ47g4Z7ffjaEvCHth/Fi/tMItcdO482/qEztnRYX6u/rHCBhRnBeJtS2xKZdyS+bvs2FeH0dOUwijhEeaZSC6Tevvs1J1GHSevi5vjnlzuHt452glBYoa2Iid0mwh1XuwX0TNPXyoZ9aM84eJCdz4nI3IYGPvjCMFUoxOFcAOy02/SxZg1UNYo0/M0lTaYnCzENRlrR+5pTS1OJRjxbLcqEzQ6ztSDFzVSx5O5Bz4Z6H3qqgz4uAakrw3lGqGFqyIUueg9TUP52/Z5Nrz2hPopRIae61RoHd2yFwfTuw2ythVmfw6KuZ6hBWjCiCgUGSgIFQxgobqwdHSqlKd+fz5mrvNlcHM1fh5lxKJSBaRgqmOEISnt+OfHj5Do9eO+fh/RVnpwtKDJAzvXUsO50lY42OaS+uwuY5a+LWzrnUTVIKiYRkDYrqo6IbxDyaQOHSNqm4ISulKMdBUN6DM0q+EzILI5QcJ7OunDLZKEl22kJE1R2ztFAmZ9tcDpj0zeUTDfwzXCzEFDGjYJPDgXqIFG3PlLrotOps67XKz1OcLPZjTHWwpnIRUlFEbRoPVyBFnWhcxJLIXN7e8uHNyFA8RVTNtOwsy86y6q0qhEKsZFBByPTe0lm1u9dEgeoEra3cGINutMZgMhTTkljRtUCpKjyV45dctO9TD461BoOr69JoKW0KHa7ywaqypgbezqujrq0OrYvi8E6TQ2MgV++OB2dLUgl0nWGzCawfXaiRXGdx/ZqzteO3vvIhL24CuzHOFaxoG1XRkDpLq6BrqXLTGlJSSpkcsI0oiTiWwmqhypcXl7d88GzH/fv3WJ/2xHDLyjtKHMkpsDy5z/lrb4M9J5gFb779Gc5OVjx6+CZvvvVp7j8aeX654+Z6QwgjOdf5QKtlRQZVrWOdKuVyNOQU6Bee84s1nbd88P47rPrI64/PePjwETmN3D+9h5iO//Jzv8xv//a7hBTAJfplQpyeC+u1neVdV68Rwft6nbbW80EwLOVwX4ej4MxMGj98/PQ8dN9IMDmFaxKmpm7DMNSxAFYda6uM+HAW2xwPNIl4VfF698/dz645yd2EQr+Peh3N+8DdiNMeL21py8uPOXzsvKfVzzK/3fFrHtr4t17eK19Zjn60z33nt980ovKxTlBav78lKMUcQ3twjLC027xA2sLS+1twsU5nPKhj7EFPuID5pmCrxopW9KGU4z5oynk61YfIibRM2VTynjEvnWxFUAZyingnrJZLVosFy15NgbJZsBt3EC3nWR0nXRlV4hATOavFc5OP1rb/zPWosLPOkoVGlxJUhROCDlQElU47ipIKK3cnhsB+DIxZCBjoHEMdwCG54jDWkUETphzJ2VDEUcfN1daIog6uVfWtugDEGmKIdaROqSRKCONIv+iIIRDCSBhV7TTkS652I713LPqOOO7oDTy+f8Fq4eldIfcqT82IDqArLTmbg72axStaNAwD1ln196chbUzmgGShTWrV+3U9pJSnoWgOUQOy0gKiq1WxnZBV3fTytE4FRRuMCLHM0lVXybOmtp5MvT+jgVmMwXhLksLJ6RrjvQbsqoApomRvVXDNSekYgrYbjNF2TsrEbIhZlVulGMKEnhRS0eM3hkgxnv2g5mw324zpHN4IF2cLrCRyiVjrSUXRHkHbhM4IXZU4l5xa84U2CbgAY4hYEYoDaqoRKx/JO23NpuqmOzvwziaMuoDNvPnWE2hsoVvoTBY3xmn/8FZJtUWzwAlldK46rroOY6nO1kvd30MhZ0NvwXWWWCIPTpcMj+/h/YaYEpdbVUNpJ7XuOdTRElERI1c9j5xzDGOEet5boDTo+d/tdnj/hC9/7R22O8OTNx7Td4n9beb28hrKCbvdyKM33+TBw7dJ4ljdi7z28AGdsYQgbLYDMRec61mtTkipsN3tKBROz8548OABIQRyzvhOUZ6chBQHVgvL+ekZ48N7vPX6im/91jc4P+3Y3V7xu1/7Ku+/e837Hzzn/Q8v2YY94rVgs8VSisqunROsXeFtp47FRhWUtpm6kbVFWVvNc2viuAUxB/9y9O/DmJAbqlkKSZSkLkbouh5jLKtV5vTkhL5f0Fq6ejMcRvSX2ySvbvU0X5TGS2vJSdtoZgPM9tz5VV+FRhxSFErdvMtLv59R2MObtKdO6MydR5RWLH90zGty6YPcZD4b9VprAWzmv3xjt493gnK00HKV5s6S2MODdJhhHiYo0wKQGT2xzmK9w1Zjqmb0pVu3HIwzp76mHPiEHN8vBzLPlKuCgxkxaZ9vauvI/FxzsLjbomug21Q9knWY2rKj6xUWzTGQ00gnI/eXlqVVGNQ5R06hti4ULrUpUxx1GmwLxKpeMCj7vxTFWIQ25tySbMHmppRy5FjojGAlYkrGoq0Xa3VSb0iRXDIOVSKkXAhDwDvoOocpoj4oougICK5Kd40xahIWUw26mlSFpNBuqm2f3jtySvjOs1ws2O22QJUVG0OWnnc/2JJSVtvwONC7zO0QuX92wtmqY4iOpoLpnbDoDF7AaWaqSWPbJIpWzimVCZJve6FIG6Y2J6k5C8bUhncqEwohpXC6WFSuUX2NiraorLyAqJKnLRKFgOf2W5O5l4YiOZVwG28nWHiqIgX8eknxluwMUv8cbuwtWRcphBjxnbp2xpiqU2wiFB1rMIbCGEdtYcXMftCptVm0FbIZBkICMZ5FF0lp4HTpeHyxZNkJne8UKUhJJbNUtZWryXG9bqTOR1I0QxOl1u6TXFQWjZnMAhUQkTmM5FyTCj3OTGilTMG+Qd5FKopTbf9jSDNJt16n2Qpi1BzOWUNMmV1IpBjpLay8JSwWOHEMYyJlB1Y/9xAzjy5OSWNiu9mx248MqYD0Op+pJG011utfE1ajk4WrtDbVVpe1duJ/5ZIIu4G3PvEWuzHxH/7TLwCJT775GmeL++RhT9d7zu895vTeJ3CLMyWzlsKyP8FgeH654Rf/+6+CsWw2O07PzrDW8sEHz0kp8ejhI77ru76rercocXa9XpGyEPd7FrYQ97d88OFX+cTrb3N6fspXv/JVfvmXfoGb6+eU0hFSZkyJbKHvHcM4EoKw2xZytnjXY8VjRZMTKxZLkxUbSjEUpJLFmfZ82r9KVb1NgXuOFa+audYShZw18WnyfOc6nd+zXOOsn/b5yYyu/pynFs8Jyozo3EVO2mfmwE7iMEnhIDY1scVhkZqn155/Ml0b5QBdmu5vL36A4k/Fs2LmR0hQ48sdPQkO7s/MQ//KlNyUg+N9+F7/o7ePdYJy2LIpuVAkHWejU6Nk/vfh7TAp0Z/zrB3n2vyWNAXJUqr+XnKtdORokbTPNCdDoilqUdKh3nSmzGE755Doe3guhdlKWlrj/DBo5YCzsOwcvTdYq6Jcygjphtfchsd+z1lXWBr9nao6YBSdW+OcoaQ5yWrGdhblzkxZf85V/68yY2tstRpXqWKImU5g0RW8T7q5lzq7JugQuVTn+1Ck8jkSJWaGHGiqAFtNjzSj11AM85RqQSZpm7NN0qcX7xCCylD1KOD7XudoGFvtxGG3T+QiDHXUwWrh4CbxfPOC89WC+6c9+2GBdZ4zJe+QbKJzgncWM0HJmhIYo0mRnt65jTO7G6uix9SL2VqHMYlEJOdECgliYlEh+7aB6cZrEYkIKv1V0KYRJPO0fm11KJWcwSiRVSoaUMo8IyTVn951WN8RUsQmi/OmfrbW00f3OtFWgg5/M4j1jENiPxZu95ExwxC1hReS8jgoUIzTzZ7a3snqjWKsY+kD67Xhc28+4Ns/9Rr3l0JBJcp2QgGEvvN0nSelSIxFkahQLeBh8p9pUHLOpbquuoljQk1cvFfEBtrw0IMN2CjhsDkik4uSLq2AtZhcapHREiNBshoRNpRHjeMK1rrqdyKkGFj36sbqzcjQpSptF2IyFCJrhDdeO8dYSyqF9z+4IeSAs25KPHXNCX3Xsd9tWa6XxKRS+BgjvXNqaGeURGwQdruBzfUtbzx5xMnSs93csLnteesTD3n0+NsJOdGt79Ov7lNwGMkVcVNfnTEXnr24nQLfonIyLi+vKAVOT89Yr84qqpxwztL3mmSm3cDTr/4mv/nrP8eDh+e8/envpl/d53ZYcftzv8h2yKS8I4vO9UqlsDYevxSc8VjTgV2TpNNk0WYwWV2yBUydHl9ya0OWeV+cEHS9bx4ke9z6nxKRO6hKixAxA5UfJgaMU8fhYzRmTj7UA+lubHkV/+Q4SSmZYwRlCv4HtAJjamupxZo7MeIAUdEyXQ5ehwlQKlmg+rA0/6oJ8aWxTZiOx+99O/B0qa9FOxdw9Ip6XR34en0dNObu7WOdoLQKssH+MxoyZ37CIdwltPkIhwtARHRGhK3j463FGKvGO1GJZ+o9kLWCMrUmK8qjkFbtHlgaTxyS+jmlemhQg31DePIrLhaYF3gbUDgz1BOtye8MOElIHonDDYRCl/f0Zc/CJs79QFdGTIwM4w7rLfto1bdiHCek4vAINaKYwPHFnFV+l2Kd74IGNIMQiYg3qogwgkhVxxgLUerQMpWeqhU3uJLpvWCdJ6S2iWQcTN81JQ0OqQ6mszRFT03oSqqTTB15ajtkxpxhP1QPGsM4ZpaLjv0wqiEWKkvOImzGQq6D8S5vb7jd7Mk5s1ou6OxK1VzoQHhKBqdQc1Y5C40Yp07FRqe0Fk1qrVWidQpKJNU2X64onaOgk1IlRJx1lZCatLC3XlGFnCHXBOFgk5wh4wpzm0PqHqSYFemqbr+tLw66aUsImKQBWHfkuhZFeRnN9yQVDSIxJvKY2O4H9mNmHzL7qFb1Vze3YHRGSufVCyRRGILO3bm8GbjejOQMD8+WPDnv+fybD3jjYsnJwtaEohoDTolthGKnSi/XYDObXjFdJw1SllJ0PIDRY2XqehZmw72WbJdcj0tR9GuSWOeshMTGwTKCWD0WzQyPUmoKrHuKiJLMMQYnlvV6SRod3nfYIVBKwBbDdh/pxDGGzH4I9NbhTzqsP9eWYkg8vw6MNVh1XafGgSERx4Cg6y6mNuV8nsxdYGp3MEa+9uWv8NonHnJxtqTvV5yfnnOyXrE67dlHeP2tb8X1aw1oYjTJR8Aov0rXVrVWqME616TM+x5cK8gO3G/HwO/85i/y/L3fZrlc8OnPfjf3Hn2GKJ63v8XzPd/7Lj/70z/JZrjE94mFcdxcZ+IYeO3BCavlCacnj9mHE7a7cZp5VUzR3jqZnGNFLLX40+Cu+3HOqSKFteV5lJQc72eHSUvdlmuSMY8byLkVDCPOOXoXaJOaVdac7iDxkzvItDZbgTcreY4L2WYPMJXSUnF6kToIsSaeB9JlEabzwcF+Obd65gSgHY92aynCTD1on5vJ4O04DlGLR2Z08TCBOUBoSkNvyoyoHN6m734HKPh6t493gtIy0XpCNJC2k9TieIP55ODny6iKVCjeVvOnpuCgqk3KncXeFpNW8/UETa/X3DjV1r0OcqHkpIqXXC2hC1UR0nqgkIu6oBbkCKURAUvBl8jaFe6fdDx5ILy5uuV++DLdjbDuDAsTWXtY9x0rM2Bz0A9qLPsxM0Td1Maoc4sQ5QqUWqUbo7NKpiy/SuKOpXmlBoUaKEpDEOq3NwVvhYVXtkZIBcmCydWYKAeKAet6lZMiRK1Rqn+CmTZcavJZagsqpaKU0VIqIpOxbrrKp++TswY5U+eWpJgIo7phSs4Kzyf9zrfbHVAJrzeBlG9Ydp6z9YLOGkYKpTTHR3UgbRwimeBOKom9flehJrOWfX2sOVprKuF2TvCdpROLqcGxAKakeqFXgrRRpKEltrqp5IMEHcRItcJX4XFTEzTJsKkba04JcoQY6aqSqXY/ONxTCqKGgDkTs0773Y2R3W5kOyR2Aa42I8+vd8RUcF3Hg3uORafeI7sh8N7zWy53hdvNyMIVzInwqTfe5OH5inVvWPeq7MotcdI8oU7z1cRMTQMqR6C56BaA2rJhVt4JDabXc5YyuDoVF6izmJS/knLCOiXftltuXjVpPn4UprauFKE4p0EiNc6YqQfPVLlzwXXqI5SBGByuGr8VPBsCy0XHZjfiug5vM0/urYj7cxZuw3tXe8ZYiGOAg4o3oihZKRBCoKAJrZHWxNLgkWPg/Xff4+LBGZ95+3U228Rmc8PtNRTOePjJb2Nx8pjc2oZH5bNgq3KsEaCUo1YqSqEWDCU3xo+QiyKBX/vtX+Y3fv0X+OQn3+LTn/0C3fIBu1AQX+gWa77v9/8BXLfkV37tpxCzJaWBFJ/hnOXRk7f41NvfRt8/Zj84Li+veP78Bfv9oO9bdF+h2epncxB8C9Pch3bK2r5fUTRqQdP4JrlZBUyUgPoeWkXOSIUUSlD0K8SM922vT1BViM3mvvkUtfPQbkYM+WCgoH4+9TaaA3w1UZz2h+aUrEVzQ2ZTmvfmedDgAVpxcPXOyfTh36lr9g4Ps91falBr99W9pRx9pwoIINWWwEz/VmdbfXIpLSrq9Ug9Tt9My+djnaC0jZlWWU6rkzsnsd45ZbozmRHmVoYqOUzdyKvNu8z9xcPsWxfNXbTmIEmRqRM5uaE2Y6tMy+4rZ6Y0lRFarRwECRGhN5GHq8zpWcfD9ZLXzzsenXesO8FxA+MLJCcWe1j1HnaZvHd09++RcyJgiFmdXkNQnUVKClOnPBsT6TGdGhUTxMtBxS4lYYsmTyWV2stXI7Smmuid4WShtuQnWNZLx25I7IOw3esUVOt0PH2p8PLSOwqOUjK52oxbq8fd15aBqdm7MtptTfoKJafpog5RURR74CeizrOVU9DaHLaSS+vGkAWVHRfDi03g17/6AauFwz4+58RbpIx0TlgtOzpVoerxqrbp0+ykupkbW91l23gF6oYE+DphN4fIsnNYm7BZP0Qq2jaTVuGLq2upKXTmDaltANZZRYTqZ2ptCCkgTtsHihDMAS0b6DsduoY1FNs2popQoZWbHr+KhoyJXQhsdoHb7cD1LnK9y7y4CezHTIg7dqHw5MEJDhgCvNhknm914KazmfOTnoWH1cKq2qSrk5e18U/JOn5B79MNbTK/MyrBnTdZJmL0nBC28RSzqVYuCgVpFTrPERJrSDFTahKvbq7Kq+jw6EC4dq7rVdFUXWKVPt6imhgwFQkqjbAvWAonyx43BHqrxoSl91NLLOTCqnMsOoPlAcZ2XO0/4Gqvk9cbMtRCxna7wxjDou9JKeG9n1Rk7cOKCDc3G8Yh8vqjB3xwecOHH25IudD3Jzx89C1ks9D9cEr20ABSVH0mlCq/rdsZc6WtybAWEEaEFEZ+49d+nufPvsr3fN/38eT1T1PMkoSitYwDxlhOzu7zf//9f5DPf/ELDMMlv/Pbv0r83EgIiYeP3uThw7fx7gSK58GDDffvPWOzvWXYD2w2u2p4ptShnEqd1k1dt8ownvaJVrbmNppiRk+a8klb2tV6oj2j6I5dn1qvMX1OKgU3Hat2yEtNVBqyOe8N0rLtelwPb6mJJCZ053DP1/XvrJ3UZ42iaIytPMaGxswBv7l+H7W5FGLl4MxNce8YaTmoMA8e0wqi0oru+jrzEZMa4fRe01ZVRVPm2Ds/b15wv/ft45+glDQTjcoMTd05/hzCcIfJiqkqGetMdQwVjDk+ce3k5TJbJZsyk4xmaE3fWBpyIhCLTqKIxRCyJeSqqhB1sSyiVbipq1Tvz5gS8TmxyCNvn8Cj11Y8vt+xkC023uKlkPeZGAtDUK7D3ghh4YGCuThnPzH926wiqg+HOs0mDCGlWrlWGXMu00C65itBadLgMm2AzphaeeRq8lUwptA5y2gTp0udf+IXK3ZD4PJmx/NNIuVIiIUYtHetxWudjpyrOyaiF1WRaTBZaoqaMhNDl4teK8nKETLCnOyJoglK9tULbrlc4r1ltxsYx0jXOazvuNncamIWM0kKUQxXu8TvvH+F8R0PT5asnaJJzsXaO9bPXRQbhgbtFqlBNasvktEkyFlDCrm2TQpWLN44vKj024oqqUy7yKVWH6LHIjevmgpz6CagiJfuQRnrPGP1qyi1/UhLHGsSnm2hOIvpPXbRkStho+2lU0Ve85WUdOhjSIUQC/tB2zY3u8DNHq52kaeXQx1vkDHdHuc71n3H5SaxHzM5FsQWTjrLiRcuVh3r3rPwFikJEYMz4DtbZ2kl9XBJSjiloplts5zJ42UqLCZYvF7DLZhSGpFbidk5pWlrsAW9Bms7pxhVIgmZ7Cy2KHJXahIi1kzgTRHBOFuPb1HOCtpmMC1wZJ0UbrAUlzBZkUi3VP5P7z3DGLAmEYpldXKKv84knpNF5y/lktFBoHq9qG2Bm2Y85ZwZhgHv/XR/KYX9buC9d59y/7UzTk56rH2M7x2vf/LTnJw+JEprRbRI2zZNEGZ1oS4Mtdov0zq3FAJIZtjv+a1f/W88ffdX+OJ3fh+Pn7xNMQtScQg6aDGViBQVCjjrWS+f0Hf3+Py3PaTrq/EcjjGAterIu1ytWZ+s1c11HNhudzWZzOz2O25vbtludorwpVzPi37qVJFuA3Xfm7koTfWZqky9qKFRTSbm5kMrfvXyzhOa2xBdPQ7mKK7c5SM2lLNkU5GWGT2Z49SdYF3XunO+qkjt9JxWeLf2zlEi9NLNcDjjrf29PVQL9Ba3zMHHaO2ZlnsfEAAmtKf+Xw5+0b7z0Xr6n799rBOUo9vhST/I9Q6rrfZT/8yEWGNl4p40NOU4+dBbzjpKXlp/ulZok1a8ndSaoEQKsSg8nuoQw5zqYikZ9UYRICAS50y6JGy8ZR0/4PF6z+PX4MwkLDcM+w1h2HMbMjFqQA5Bx5bbzpE6R0pBh7ftA/2ip4iw2+/VOwKZ+tepohW5Zfl10UpNvkyhlqaaG9jq5ZJSoRhFJyKpffUaPGDhDaZYFp1FrKG3Hb2zSKe+LZutypRTUctyclCH0EINjrOxVs66WR56ACgnR9Gt1uDzzk2QeJtUbE21wI8ZayHGhPduIrBaU0h16GHOWUm3GR1uly2/9d41Ty9v+fST1/j043OenHvMEBlNrt5QinJYmm9MXX31oDa+hM5PKRU+axtNDWy5UM1NFT1oBGEp1em1Qqa1xdSqPJUu63aSitrOu1YpWkWEjG3+JHX4JIYk0K973HpJmlATkKyoT0MEcoYUEmOMDDGx2+vPfchsx8LNAC82kfdf7LiN6sA6pEi43LMbCytnuN2NCMLaF55c9HzhrXt88ZMXPL53wsIbnSicdUtzzqoKy0AyOsNHRNR2XwSpTrGlqIy9XcOmFDrrdf0yb9ZqZ65JayyRkFsASZp81WvbzN0dKAVvhJQghRFfnXhzSmBUhq0wSS1aWocktplapvJU9PM5W7BWGMeA4OiK7jPbIbDuDLsxgVey9bgLvHix5fL6dkK8Uk6IWLKoP0/XzbykhuJOKjcRQlCOhLGWmAspFnbjiOvg4uIU49esLz6BGD9X9wftAf0yh3toCzo1GFaisJRECoGr5x/yS//9PxHjhu/7vi9x/+FbIB0hwhhSNVZTRVYuiTBEhmFkv49QEsZ6UvYs+pWqoXwhlQQ24TuL7y9Yp6yOxWGcEJBht+P25oaryyu22z3DfmQYxknQQA3ezQwzlzZt/cCSomSa/H9KUDgsYOv3bsGaA67jYVxB+TuUtg/KcXAWmZIOyYdrs0yD/uakpqivzCTUcBP/Sj12uJPQzJzHV4k12s/DGHZYcB8s/Po7c+e+dhxehXloMaZt1vkppSE7dwCCw6Ttfx+SbL01sthRb0vKdGDn7FZ/1RIQU+e4WGtxNTNtf5r6pr7D/D5HBKt8dPbm968VLNrrTCnq1OEUsbX3qZJQgWxJJJJYch5g3NKnGxbxGWfLGx6sDAyX7G8vFequVWysMKWIKga8EUQ6dvtA5y23mx0hZk7LGdZZxqRSzTK1H2p7pFYYtDbAAbSn1UOhkeD0mKk0rgXJVjF2naeIpTBijXp6tEm2OSWcBW8y3s3BI2XYjyPOJEUSjNVqqgZv65StH6tKRm301QcihIBYTVoaJ6SNB1CljJ6jGCLeCH3XY61hs1FX27a5l5xVhWPsZIemh0PN3i73md9855IwBpx9yP21wRJqlVHq8DrBJOXdNLRGrNTjVCbY2RjlRBgnhDEQ4ogFOmsosSrDqppnrMdfxNQedpnChSZn1WujeaPYKq+tu2cuit7l0qYP1/PqHaXz4GxF0xImK/nSNhwZKjlZkbdUUbUxZm62I1ebkctt5J1nGz64DkjfkUUYC+y2iWHccbq0GJTEfXFq+ezjJd/z2df45KMLnAQ6qwgDJeuxN83W3mKlTOZls4osaQKFcoCcUb8f5RBkmvetSqxr+7Wdy9xQqyYHb5wBbfmUpOonnYisxERjdRwE7TPU12pJUDGiuUrO09wmaj+eug5bpetdVWhlWHhFhnIyZJfxVrdgPxZ2+x05Rc5WHWMIxBhJqArJNdNCedkHw3s/JSltzRcxOi4iw/52g3UDb37m03SrJ2QxaHZVQ4UctMfbGsPMLQ+TlYCM6FoZCz/1k/+O//bz/4EHj9f8P/7AD/Dg4dtk24M40jCw3w3ENLJcdnS9eplYKcQQuLx+QRwHnDMsl2vyWlisTzDWThwhiiZaznl815Hzghj1mPTesVr0nJ2esNvt2W31z36/Z7fb6QiQMVaejhaDyk1SDmBLZF4K3kd/a0ckT3yVtu9xgJzMN+VCFckoJ08mAnPbU6hcqMP3bYhgaxE3An1LUOa4UiYU5lgNVJh8SD4iOfm9ExTdGyAf/Pvlx8xr7/h7V2D9oHXE0ed41et8o7ePfYJyeMKPoTOmuSLtgMyTXo2Oaa+j2p211Sq79q7NsewKmmy0HPy9jkyHl86lEv7mAF9iptQBelIKpegGoZue3mfGPW58wSK+YJmesyo3XHgouz03tzfc3G7RZoASPqW2VKCoqZFYQgjY+v1z2ROiTpxdLJd6kVFAVFZpRNCRo3n6oq0yOOw/KmOeqZWg318lgs0Qq3rZ0TlDyo5SgkpEs7qJqmdLpMQRkpKErfGqEEkKxWolaSZYsfEWnXc10ct478mNS4BWtoImLqU6tqZceTGiwwSbu2oumTRGQlCOgSJl6ojqnGMfEohyDrTqUrQiFMPVPvK1D284P12DWbHq1Mis5DQlGL03ahdf0mSoRdFRAM2jJ5eMWENJpap61Ja+61wNtGoQF2LS5AHqedIA4ZoDKi3JnUlyrZ+tdZ+uQUXMMl6MJnPOIH1PluqhkSGGgqny0pJ1/U/vK+jnHbXtMoTEmIVNKDy/HbjaB6IRxiES40gBlp3BdJ6EULL6gTy6t+Bb3nzAJ+6vWPdCSQI5EkqtLIuuJVt9RgrazipNXdSSz6KIRN3tMWKmGqLU4JHI2FQrVZnDjK1SUCV9q5KsmIpmmTbaQtVyTWlVN42p4tZ1aSa4nRq4MDW1rQhDIztidICcGsShrrop461Qeo8YR0iJYYwsFh0XZ2t2AWIYOF2e8f7zGzZB2MdMDoWYAyIzv6ZV1yLqZtxGAIhYUgxcX13ywdPnvPHGBVjL4098FnFr8kRqLwf73IwJUK8fKabuGRrcJRWun13xC//1v/LTP/3/oV9lvu/3/T958vpnKUaTE0SnL/fRwl7q7CSLWIezjvVqxX7Y8/71JVf7HX1/y+50x8mwY7k6wTpfk8WCGPXzaa2txjUq1cBvueg5PztVP6EQ2e92bG63bDZbbm5uuLm5ZrcbCLkOkJ2Ky7nAbOG2VDSp8UhaDDlUfx3fDhCBw/YODenUjbRIuxqP49NRolDqM6pC1E8mobaiJ6Ump20fvoua3AFW2v5wUEwfvt83miAcf+9XHYO77zmv/eOE96OTld/r9rFPULRq0g3jrmRXajBuMq92UTcTqOYU20h1sznV9NJT26XJzkD5EMbUDUvZYhNE2BZhqvNaUsyK/hWjm7YAol4JOQXIG9xwyyresuYKX54Rh+eUcU82a3bbDft9JCVb4bOMNfrdQor1PsjkiRQaY2IMOh/F94XtblS7czQwS9XJtOc2dUlro2jipEmIJnizJM1atfnORQNKzsqFULRe0YRkLMUKIUVCyhrYqsmaSGHRd2yD6GRgQN1q9XOlhmpUCXH7XLrw1WEyJe3H74eAs5a+77m6viWXgrOuVkl5Oo/W6euqZM9WlMViO0/ZD5SKqMQm+AJyDGDVij8KXG4iv/LVD9iMZzy6WNM5wRnorbDqlSCpM1z0O7ZjY43RIZYpYqzRnnhMLLoOsR5DRx5v2adBZ9mkTE4VnjYGYq7mcE01xLSWgWpjz1Tpq+193QiF6p8jSIOKU8EXYNSKvFig8xTqCANncJ3XIAjaYjFaTY8xsdlHXmxGnm8Gghidjp1Uhtt7OO17DNoeMlZY9B2GzMmyY73sVSHm5MCxWKrXiui8mZoYNSIjzPwTawyLvpsk+631MDv16iY8xjjxkmIIpJzovcdZvd69Mw0onGuLVqSauubryiy5kGOckdiqvCi5Xutoq0VsRRysGuNNM61q0m2cRXLEZKPy4WxIeU9M0C86wj7x4GyFc46LlcX3S06Xlq+8f8nlTtgl5cd4P8tNNTdqLd76Ner+Y60l7Aa+9jtf47UH53zu27+Di3tPiCIY8VMaq9+y/V8RnzaED1SVkUbh6vKKX/7Fn+OXfvHnGYctX/iuz/Od3/PdPHn9Uxi3AtyE1lknrNYLnU00l9aIqJ/L/YsLUhh5//132W6uGYYN2+0Vp2cXnJ1fcLI6nSaIi27sUDIG6JzTgYkck1JTSsT1insX54xj4OrqmufPn3N7c8vl1TXXNzeYVBPw1JSZWlCUUveYup5MrToPQ+rdANvEFnfvU6DSTFlPbYIcFc5tnbaJ2tSEXIzUsQzKP2kk79bObNyyj/pM7dzPvloNhZ3f76jVInO8+uikpT1+vkyO/3LnmNTPMRP6/+duH/sERYuZ+t/RiSkzNeTgpFhjJulWQ0yMOTBEOzgTLSlRR9B6OU8GXK33ezAptiYzKRdiTuSgnJOUC0V0zH0uCVMyJo3IeI0dP6QbX7DONyzLlrC7ZXd7gzGW3ZAYAzjpsOyBTNc7hX4rikHR2RStpZXq8EAxjlJQB8wiiG0beKm+AnMlWoFBjmSVMjOxVX1SDha61DkZFQVSFXVNcGL1sNBeeUy6uVvryHmoRm0Jgw5lm5KhVJRQas1koQ8wjmFCTYY6d8U6V1Urep5j3msLxBgKVic1VzLkonOcnp+yvd0yDAHvvHKJYiSVzDgECoK1jpgiiFEbf8o0siWJpSA8u43sxuc8v9pWa3zDwsGDsxWvv3bGslhM45AYM1nFp9Jm9QiSCxZFW+J+YLzdkYZB++Sl6gemje5wjesm0fg3ADnpkLhWRRsRsM3jQNsWHG4sOSMxkbcjDjCdrSTCQDbgejcF7SPY2XmKSSQsm2HH0xcbbveZMav7bymwNHDaW5ZVnRVyRqywWq1YLoQwRE147by5W2voahKac6kTmPX7tWLgMPFIOSJFh0cama/FSalVibVTkZIL4zAourLISFew4hE0IaKUg8o2o7BdRQsqGpWLDktEmBJqQKXbSdcJfQ2mBwgXUgOIRqcpsTRGidJGNOGqzHB6J7x2tqSzcG95Ri6G1eINloslv/61F3yQR5VMOzclbm1/slaPuTF67VjrQHTdxf0ILHj9zc8hpqutMA2bMu0BLfBVBVkBIUNOXF9f8cu/+Iv86q/9MllGvvP/9h28/alPc//+G/TdukYuLRI16ctT4WO9O6js5wq+7ztee/CAkgPPPnzKGEdi3BPGW6SscVZbwTArtAqCmOrLQiNx6obbJMVm0dPR06WM6zz9sme33bN89hz/oWc37AkhcXu9YXO7bcFhGiypCr+ZMFqYWxcTQl+P3zz071g63D70VOPKHPxnpOqOnr9e24rsa4Jiq6GmtjEThwnEcYtnft/jBGUuqNtzDp97+LzDf0/I4cE50yVSY0D7Xg1pe+n2P5+UHN4+1gnKIRxXjjabmruVMrV1JvSkEWOb50klxrbfTxv6QWU2Z78ybQpzS6mdwJYgFTUMSwlyoqSqoBGnFTWZLm1gf4ncvocbn+JkT057nm1uCftAipWxzw1hiPXDRPrOkPJIyoEiRqeI1lk52rbRBa36eoU1xzDipY6in2BIg3inFUBp5Nh2IWoFebj+midAq8wOyauNEKVJnFaTKn3MOGvpnCqYtsOOGCOd95ycQNkFVYhE3RRiSviuSuqKoUTl2+imqe/XdT3DOJKCtm6c75R8N45TwAtjqrCooia+mofdpJtJNmitI2XtZ4tR+D8kRW2MQG4kTNSVNUcNeKFYtiGxGXc4s2XphZWD69sdne/orCUZHQSYUqrya3TzFqsqoZCJ25HhZk/e7JEhIwdtK9u8FGqLRyrErjb4ogTsA/TEGp0oLNVPplK7J1+QXDObEtWqXQZNzExIpM5QOkPxFlkYpHOVK6Ntl8bN2u9jVYAJVxudRByUe6yPA05WOm6BXL1cSiYl2G9uWD96jWVvyWPAOJ1S3Dk7KRRyigeJRq5ckxmmFmTyG8o5KZ/BGlIJU1ICCseHENjvx6mKHMeRNA6EZQ/rNe5krW2tJNNxyimRJ9fkGRLPB66dMSVIHBQmSuwVp3weTIP1a1usmowJTGvJWUGKqeqkkZRUUt15QyeWhc846bjdZcZYuOh63np0j/ef3fLseq9rMwWAur6b1LbQeSW+RsmI0SKppETaD4ic0C3uk3G6vkpVxNGir5kCkRI3M3Hc8Tu/9ev8p5/6/2Ik8j3f+9185nNfZLE6A3oMFgjKq0rUoFwm5AXRv5oyB7zGpbDWslyuePTaE0wx3NxegxV6v8AabW1oIaHtUd2zO0DR03k4pxZ8RSpHiLk48P2SU+tZrgL9asnZxTkhBHa7gXffeY9cnrLd7iipZgF5/nwHEeagSM3VnFH3pBl7MzROSrtVkXZ9BTWG1GarGiGWurcWkelPQ0maqnSe3dbUN69GONo1MicnHIxmqZ9GGmfmVa/QPvvd7z5/R5mSqjkxFmnfcA4UDbX9qNv/SJvnY5+gNEFMIzG1HuPUXGQmxR6qdO6qdqYsshbvx+O1marJ9qKtapvyYlF1TIzqX5CKViCSlVtQjJIGfRzpx2f04SmeZ+z3z9jv96RcGJOiH7bvSDmx2w+1LSGIdRhjcblgspnJj5XERdYetSbAyr9QroqiAqYma9ZaQgQxKsEVGimYuRo5WGRtzTWJ3nQUxGCkTcJQeLTxblzN/r1zjAlk0EFvfddhshBKoPPCPld4s5pxtevAOYfreg0uB3OQlqslmUKIgZKpEk39BItFzzDqQLuGeFlrSDnx4vKScYw460GMbnBSz7FoZVaCzigqaOBPMCE5zUOmxIxY2AWhd4YxQloIbpt4+mLDwlkenHQsvNUEMYPJhRh0PY5DoIRC2A6wHbFDRsY6NLAcVK8tyNH4NFJbcdrCsxVhEdGKWc+jBj7jLKXU4YpiVBVRNztToAwBQb1RiA6SHqPFck3nPDgzc3yyutrGmImpsNsHYgJxjjwkRUQyrJYe55WIHYeAdc1CO3PvfMnDe0vOVo7e5wpdM0HYKVYFV4XXGyJnDqvWUhMu1DjOCqSi5zHWKrHve0qBYdCJy/vdjmE/kLPOqnKi3I79rrbIEJzXZFuT6k7RVFtXtDU1mbXTXqDcpIwXj9TE1ZoMEfWRsdVUD2ml71GjoCGYgiYPysUSeueVVF3bmyl1YBJDiJyuey5Ol5R3X2hineK0Z0HzBZkRJGuFkJJyOFIkj8LT956z3WcWJ043OElqslYLK732NUilFHj63tf4uf/yn7h68QHf8e1f4DPf9h0s1xfadjFCKQFMpmB1PUimMGJwukblYL+svK5pKjSAZCyFxbLn3r17uk7JLJYrOt9jFN9DpPo01TajqaMY4sQjqVW/tWRgDDoPSpVMDm89xnqKcfSLJSUldrsBEXUK//DDZ9zcXBPGkVz3vzkBmQPwYXLQEJUWvmc0o6KWH4EgiFhE0sE6OOCEHKwPI3OyeLdl05RHdz252t9n9PBlufO8Xj6KJHuAStESogO05ei7HHB1pqRkVr3qU/6vQVI+/gnKtKBqkpJ0ym6pPhpTFiht1s7c3nmJc3Lwuoc/pcKM6netd8xIygy/xZqgxJQ0QSm5zoUpFAIuBbpwycn4AT4+J4ZrSg5st3tCFny/ACmqbBE1BZqMp0SQBp/Wj2KsKgbEUOWk2q5VREXI40hs3yElrO9UIl0rVaikxEJ1Z52/2xE5inrt5lJ9K7TCDbElLSqPk1TNgupCj0nnzeSix8WKgLP0XWE/aptqzJBjVIRnF1j0WjllpI4EiBW5ghBHnPfsR23LxJxQBagQY64k2Vzn1eRKZIX9mBgTYJIOK3S2GtZpcjJUKW2DVdsQOhqXBDRhQRTVESXo2mLYiVDGkbP1yMWJKpKM9Ky9w1LXQ1VfhaEasqEyUFF7VuXxAMXoXB1rqLbtapdPVYSpF41MG0MpuZJKdb03/x5pPiaANdXDwkpNaC3UHrwQlcjpHd6KFkk1eCdU6rvbRzb7yNVm5MPrLbshIXitXEth2RtWnR7vIWk76GS9II0bHp16ft/n3uCzT065WFgWC0/nZ0+N3MjD+sHUrK1WZ9Rzl6vyrLVXWzszhkhKigb1ndd2T3UsDkOElDhbOJausFo6nBFC2BO3O4x10+RhMRbjPF2XGULEe23/dD7hXTfNqLHiKBLmQFGN7KhtGmluf1mPtap8lOAtTWKOPtyIKooWTuXZxumfECydK/S+KHm2klP75RJrLftBJx477ypKWui8I8VMiFHHEdCOZ8GgQ+Y+fOcdnr3/Hm+dndfavlnkt31OZznFcccv/bef4ef+83/gE2+9yR/6f/2/uffoMWIW6NgBNQMU0cKIYnScRVGEUAGUec9soU1QfoUO+KtBXATjHIuTNSd1rlDX6QyskAtpDBijgTfEhMSEMQ5MJbxXFWLOdY3XwYqxDt90NQnRCd6ZTKIYWKxPePKJjsVqyfpkxbvvvcfV5SXjEIhjJFe5MFNwL8ytjiaOqEpGeCkJUGR5TnIOH1OmeHSIatT2WjlwyE4JSNN+lrLGtFRRnEOOSSvKG99kSmza7q2VzSQ6aOhNg/va55jl5YffqcqYpbarDxyXp3cQJpRR0EugxUjdpuYi46VW2Ddw+3gnKDRfiDLNoWgZd6nVcameBFOgP5AYH76S3mam8tz7booXUy/MunkyM7xbayTEym1IiZBiPU8dxRYkDbi0ZVmuOZEtw3jNi8tnpCIUaxljZH+7JaXAernA9x0ljIRhIBtTZdA6f6fBPJpta6WdUDVGkzWUXIg5ak4lulHlnBljonNgpj620QFcTYkAdxbUYTtL5820NmVu5USdD6R+IlPdofLYHBlj0s2iWv53rsM7vbhClfiWUtgPsbYwNMGy1tD1C0JQ9c1+vydV+/IQ87SJeN+p02MsWKNLOiU9BsXAGNUnxGRVtlCUSOz7rpqQ5cpfYf78tdLIRVsOhhos1c9e1TvOUYBkLFfbwAdXt6SoAas7P8FbQxIdThhiZL8bMUWlyENtJZisSqlUWn6Y6JzBW8FZp20iMYiBnBsZcibozZVqO+81UUUdaxsvS4ySmKV6e5SkSpbmlgxqZObETFOIx5zZxcyzmz1fef+S3/3gkl3uGWOuCJk6wnpTdIBdFsYUuck3XKwMn3pyj8+/9RpvPliT44gzaqLW9z3DsNelI3XdCPP2VwnapW3OlW8UrcFnN0nsS0mUXAgJOlfIsbC53TLu9vQ2c9pbLtaWk4XHGkOIOgG7iCUV4XY7sh9HfC94LyrDzwOd92QxpBKxYiqsk6dhfAplt4Va9406iVmMpVQuFfZA8RMTCl1KHSmgSJh3Vl2VS0Xsiiq7vBV6HFf7kd1+R997dkGv2WE/VgmuIdd9xopKo0OJirgWENTL6PbqQ37713+ZNz79KZxX1KyI0dIpZj744F3G/Zaf/68/xQfvf43/4/t/H1/49u/GdGuK8bVKnvc9bepV4jxV2o49DnIv7a3zb6TS8kUE7ztOTk8JQWeDhZTY7LeICKcnS5zz7IfAsNshInSLrs6K0j1gDBGJkUXf1+GOuTofB3IONeAHQkoUEdbLBeuTNYvVgq73WGfovefy8oqb6xtyqIToure1whaamqxKiPNsnX/03cRUF2jq84+L3cPHzoV1De7VmHCs12NLxJqXS0vWD51wW6FQHQ00GZR5P1DyLfM6fekMyXyaJkRn3ve19ZSn13717eC7TQnQywnP/5YtHmpF0P49tWbqWVffL5ns6+EOxHaUUZaXDuK8QLWybFlh20w0dzETPNs+j8K4kGo/3puBLl8j4bkO9isF5zrGMdYepKmVsPZZQyhITpjSaFnzgCxq0tFmSmRq1YyOhW/ZfEGPQwFNQMyhSqccXFw1g5+SlBnu0725yj3r31tiNh1LJb60s0JrtzV0aWbc688QtRe830VKmXuguaIune8m6aevhFhjLSHDGFQ6nWpCRCkzz4KG3GiV03V9bR0kDcbGgVhyGqvCIypSk/5/5P1brDVbltcH/sacMyLWWvv2Xc417xSGhOJiAy1XZRusloXByO0X88QD5sFPJdsPxpYsJCSDES6JF6SW4KElhF/aom2prXbbbuQC05IFVXZzadFVZaCqKMjKzHP9rvuyVkTMOUc/jDEjYn/fd06eLPrliMjcZ+9v73WJNS9jjvEf//EfjQRtRNsmphcsVEIidCFSayZUa0WwHxKg5iyJ8uLmjiQn9v0jxhK4O830h0TX90yTieQVKnfHye7DneleMFn06h2M1R0mFSRGdyzXOW/pruqIVlX1brvRDJxD/Yt+iHoVjKveqs+dcTcqoskifYlIsNSP5kJWZdLC9Wnm0xdHPn52x80kHGthzGYNz4bEfuip08w4ZzIJrSYgeLbfkVAOQ8eQInOxsmytwjxPNr8xIiW7MJkfgmqIY/VKMdVKUdeuIC7l1HPOrusj6J11sdZ5Yj7espNClyJd8HYHtSJS2HcmBmfiZyYvcJwqJSRCsO7YMTQNFU+becsFNg30zOHz6sFqjnKTMletBre5F29NBKN9tFIpZEKMdH1PyIpES3nhmjApBSR05FqgChc1ErXQBeVs33N9e7J5F6G0VG3ydI0r3eZaSBIXhe1aRv7+3/1f+O2/5/fw6N2voNIRSNQy8cmHH/L//H/837i7ecI777/FH/g3/hDvf+3HDF0imPT9Isa1HlBNBf81m/zZxvqNjxGRhW8yTifGKZOL2cPD2Z4+9TAVjuPE6XRkGHouLs4JIXl5caFMhrLGINRsvKO7cQSB/W5n6by+I3i1lbX2CMTYMQx7Dodz5tlS4nd3d+S5VYWtyIiwCuQtDsqSalqJ1u1jrpzIzTm1Qa3stXUZkVqrtd6Qyd87LCq423NtRU+276uLXViqc3ztiTvEy8Df8zGW02CZojX9s0U8ePWJS1D+BWb+teuLljnDl9xBafm4NnitWaC699s6AacQF+TESJ66mTibtftpjdcnShbEbq3iQZ2J742gYrDoANzbVBbPttOJq3SivHzCp08+JKDMVc0Y5RPTZBBtEC+xTEa0G5LnskMgYIqFplbZZOEt36pFmadMXdAAJXUdqe9Jfb8s3CXHiVmYRqzK1fkvjjIBhkBRN3p1LQet63g70hK9giAEky9fNiJq4lepMjjR6jQZspNCoBRxHoV4czW11uoqlFy9yZY5V2WerRNxMRewwc2EwDzPRkRTj2wRq9KZZnI1cDJ7lIvi0aci0bpWN36NlhU9apGN1oyERHInZUiGSGktZFFqMV2Uu0n4+MUdh2HHxZCYSyZ1g6XiMAejAFPO9F0iHQJ6O8KUqS6JrWoKv0UNVu1iR3R+wrLOVa1M3deWpZuM7BujWOqjFEMCXF9FcTK3I4oZKzGupdIHy+Gjxo3A01rjnLkdM09vTrw4Fm7nwKkKY650AQ5dQr2UfM4w1WL9joKyHzorKVZFa6GLFuW3FgDD0JuR8+KZ6DwwI0EaQTg3cqLavE6TKRBn7ylVHA2Z8mz9mPLIeVe5PB/Y9yYM2OS8ResS9weBjHLWm/NyzDMx7Bj6ZK0IipVcEys5W9BgJNBVpkD9c+XJ9mPsOvPgm6NeBSiudmzPp3cBw1CJVcGj31IrNRdCgM6bRu77hObK2dDxzuMrPvz0BdM8E0WNo1YqpWQ656aFoIzTZB+wVoLLKMzFuHBPPvwe/+jn/z/8xFvvQUxQK6fra37mr/63/JNf+fv89t/2W/lD/8b/kYtH71OC8TYoVnG0kE/fFAlv8f3VSLL8sh3YbL+rRY66Pi64+vPN7R0iidT1HMeJgnA8jVzf3fLi+Qu6Llka8byHEKlqrTM4WUoozxPH45Gb21vOzs94cPUAnMsy58Lp9pYoJsI3zYWpVAiB3WGHYohdyUezAXjKdaNibUj1NnXhSJ426fxWpOHB3fJ3+97OlnZStEo/9UBrnt2me3fyhpC+yjnZOkTqAVoLoLedihvara9MhFnQe00N7s/pJgC9P4PbP78yq7rV1dm+3OuB/xe9vtQOyupZWhTTIndQF17q6KKLsnnlTgjcI5m117Fza1NOG+LCuF/eD4P5i3Mv2u+6mPw9XHq6FubZIz1s8aY6cRZPjDJxBEMDivLy5pbjcTKIPBf6LlFVOY0nBoeQTUHVDS0e2auhOuCHc85MUyaIOWBazQEIMS4+8sLXaXCe80XwiNV5fa7Gvkbt6Kve/2qsTFra0xUSFi3CJoYXQl00NXCHse8hhhNdrBA6spqCKCp0QcjzjJbKsEukFAkhcXN38vSLzYmKuHjZqvJZSkNTLCUy5+xluyb5LtX0SGJ0A5ESU87ezdnOFvFKLhFzgNs+NCg90Ef7QpVcrZ2BHYBwjDDOlRcvb3j7LAH9MuatTXupjq+FgCah6ztiUaYyUfHyZLEupkFcin9xCr1NgTtPpTqXSMyxKjnTeoukmBjnpvTryJBH+0ECKQW6XYd2ltKJKSIpeJWBOT9zVk5ZOc7KVCJjUe6svwJDF+nE+DpZ1dX6jKcTu4jUmYuzPSWPpLQnanIOVfUmkMUcq7A26bR1Zb2O5uxE9wplVsY5M+bKNBUn7dp8z3mm1onAzMUgPH54wePzjp5sqAy6ONkNqdE6L5o/+87IttPNC+qU6foDFZMBKN7GIZRATJFEQCSbPo8Ei7prdt2YuBBjwdAtwEqPfdwJQug7RCpdxZCq2VM0XoI3zZUgyq7vqKFwnDOX+453Hl7w8vZT+i5ZL6tivaRS33k1CqYr7+ux1kzX9WQEaqFOR37h7/1dfsfv/t9z/nDH8eYZ//Pf+Kv80j/6+3zlG1/hX/59/yqXj76C0tnR6Ry1wroHWjDXUNbNsbf+/bXg+ItFy8FtdM6F6+trVALPrp9zefWAIKZRlPqemMyZzsXSOze3d7y8vmW/H7g4Oxha0nXs9wd2uwMSI7VkjndHnr18yfHuxMOrB5yfnZOGHbvdgWmczGZS6e/umE+Tcc02LRW2RFT1s+PNTsOKRiivIhw+ImI8pOZANCC7FV5YNU9ckJBWKdqQjKXHDi2lYwFZyxKs9nljs31uFpG3N8xB+5zID0M5/J1lJeM2UGD9+/qZ/lmuL7WDAiyoSAjtcLQywK5LDH0ymejYnJNw73C1ga2bQdwewNhENQYfznN5ZTG2xWGlj/YaodrBnCVbs7NS6WpBxxvGmxtOY+b6OJIV7sZMLlBdUyKEyjRZM8E0WL49qh1E1jjP0YS8Qn2tAZaqCUKFEIjdpjJJ1cmqAIKEhFRYGgDiB9SG17B2cN7mWM0haRUYy+WpMhEh1FY1pYgY3yMEK8ms2ZCMoUtcHDpU4JiFqRpHQzR4DxbY7XtAGY9HUt8bkTaI9QeiRQkWXc/eDr2qHa65FKJlx22OJSxKjIJF8qUqc53dkMBc8GjXnS41IqN46wN1XQERQ7Jyte6m1Z0DUqKKMI4TcjEw9B27YSCpQB0tPa9Kl5JXCJmDIwrnfccEzEVBm1hTRGtm6RfiCEhRz4WrLCk+BVMQlnY42QHV0n4mDuf/dmi51IKEjn4/EPqItLUbTUsGhblGTtOJu+O86J1UNf7N0AUoLh2ugbkWCoGhM1XcIIVHD87pO9OX6QdDBKIEkq+75gxG5yCpIyUhBrTOhs7MmWmaTNJ8ypaeKTYWec7UPNOnyuUh8e7DMx6c9/RRScGk1VtKdvbK2uhVNA1ZSdJxvkvcHCeefPoRM3vOLs7ousCgvSGCogxERLMJpVVTHbayZquSS7EQooKsZf+qakiKqB1qqhACIQkdppRby4nF2LtqM15O3sdIHwvnu8T7b13x4jhTXoxML0+Wrg1hWfcihuxUqksNZOYaqQQoQtTK048+4Ob5J3R9x9/8n3+GX/jFv81v/52/g5/4vb+Pr37jxygpWgXVQvZVCJ4mdPMonuq5h5NsDrb7V1u3m8O52QttcZI9KUpkt9vRdR3X19c8ef6C0AW+8c1vcXn5gBAih7Nz+q6jFOXl9TU317c8efKU59cvef/dd3n08NJeegZVk/p/8fKGPE/c3tzw7Pol85Q5P7+0hpbnF5ScmfMEVIpm9vsdZZwZT27/3ZFt6F6sDZLQBa2/Ry3w9aa8KkdxH2V49RwKYU3plFqdEyjcH1S5Z4/FI6n2OiEY6rra5vZ4XV5HNk5K+xxszomljHD58+sibp/FKRFwQU157bn/XCIoLZcek+UWm7ebusjQ9wz9QErhnnPScvPA4ui9OrDtCkGoi/dsrGqrEirLohSRhXsijl4kAiTjjGjO1HkmnTL1dGKerBvs7SlDGuh2O+5O1+Q5M/Q7lOKCYWqcUsthuEnw8mK1UkKt+D1VN1gt71m8p4VtBnNrovd5acJeFp46kGIMm8DipNwboFeu7WZbkSulSc3XRUXTNsg0jozHyTgKamJyZ2cdRSrzzUjRwGku1Gps//Od59TV++oQvMzUSgwNwNBFsr1ME82NxGHLtr1zqYv+SVbokngTMYPyJQSqd401VMY/tViVlEX7dXEGgo8xzvmwXiuBw24gkKFWri4O7D19kLP1AWntBYbOEKNpGjne3PEgJItZU6QLhl6ZurHidTbuRLkmi0PBJuyGp27MoWrEPkWoblhbmfaiqiyAVBKBsUzsunP6w0Bxxr45X3A7Fp7fznzwyTOO00Qlmk5MVZIIuz5xGHrqeCTfZuZinJHTqZACHPodX3vvLQ4HS+XMo4n09V3yyhh3kJ3Q2foW1VqYpxl0IlAQnQhkYqg2vlqsD0+pSMjsznuuzjoudsqDi0QXCimYPHr0NZ5zgRhc6di6Kmg1NCVIpRM43yXGuecHT6+Z68Rut2ecC8PQ03UdWk8MfSRKZ6nMtO6Dxv2REKxip50Hqit6QnU9HD90gpD6RC2JPBfago+hVa+ZkxMFLg4DWSMvRvjw+fco1Spa5mykyqHfmUOZTWZAqaQ+mfihl7+mkJiPt/zD/+/f5Tb/bX75V/4B3/m9/wq/51/+V+h2V1Z5JNUckiKegnEbsj2wXjfCNK7aciw2h+WzziRdH7delb7reHB1yQd9z8sXL5hr5nC4IMae/X4PKDe3t8uanqeZaZ5AlH7o6Hc9JWeOL4+8vL5jPI0eONr9nJ2dc/bOBRfn57a3a7TU4TyTayWkjsPZOcW1lOY8O+CstFxkXeGOJWjZHr5riqdN/xrILsT7V8axBcTiaRf112lVe69TD2xOt6mcJYXvu7hxzsD6TW0dnXtOyjZVI4tr4X7L647G69N/v6TZuz38MyMn7fpSOyjWXG4J4EFsUlOMdJ2lXFo5MawD3khOFlBuDAr3J7tlRBqasNS5+0SKrFVDdogJMWAG1OF8KzVMhFOh5Jn97kDqRxgha2S8Hbm+PZmCIFZOXGuxA5BAqbZ4i6cUWu6xldXiqoQxhiWHWrWV2Rm8XOaJqh2RRI3quQxTyTRBL6EGO+CK50njUo/vvI6NU7I2Wwz+N083tDI4xTdvXSDI4ERarcpuSKYZEaya4Om1pbhS6lDUDrs6+0ETrFOpR4otiquYA2c6FWWJxqbcyq3dSQqB6uXPIVgVy1ysaLgWXDHUShTtvv3zR4EQl2Z8tlIMyZpFSX0PCl2E8/1ABOqc6c879kMkio/FZL1/QnTlXa2EKkjXoQoRWcTXqlgKz4zfqnViysS6NEOuKr4W2n05suEk07a+gzTuiRH+mqql+O8MuWjooJWlIoExw9ObmV/5/hM+fHrH3SycHKWLCn30XkQu1hQF7/SLI2TmBAzR0DLqbHszpoWsHcD6x2RDBvM0Mk+j3UvOBGZSqHShmJXSaN20sdSlrcOeQ7/nbBD6MNOHgmgFonG/gid4SkFUKNEc14wS1LhOIgXEnK6HFzs0BJ69uOP6+Yl+OGM+23N2tocuMkgygcQQPL3ma7J6GX00si2lRcCWblOXPlea5o/3w4qBbuiMHD5tSknrmr4LYmrIhyp0va31GCOlCuNsrR5o9swDturnqSpozah6qfsx87P/8/+Lq7ff5ff/gT/Av/BbfidpOPfQp6nJKhpq8/aX1I0uNnFzGL/6/X7w7U999aCSzTPsUds0yn4/8PjxAx58fMGL61turm/o+2dMZyM3NzeM04kHDx5wfn5ulYES2OsZl5eXxBAZ84m72yNPnjzhdBy5uLjg0aOHDEPP7nBgNwx0XQfANI/eY2pinCaGYWDYH5hOI9M8kWteEI9XSa9NOXfrhNxP5fhYtse/+mWHjQcUtjcRQer9x2+7ureS5Iaobs8qaWcSuK4SNPXXNq/3Z0F8PbIk6u5laGR1Mj7POVm/twL2dv9t6tuLsX79CNeX20FpHUexqAG8nHgRX1sn+366w8mdxdfIa8hBe55NcHtNk5UGDetBXEthzgZDQwet4aBgyI4OSK3su46uC0wnKJo5zTM3p4lpnikqSBWmuSIJkjsHpSqUTOgst5xd36UGcQKhyVyH5i2LOxaoC0ll1B0JqkOS1eDm2k77GO3xxfLgjThcm4VaFqo5ItvxFBFQ7+HiOhRVLaJfmuMFMTXXIsynkRiF3TAw5WxOWagEzXQJJCi5Wqv25CWarVuyhOjkvwBzMXXXjZZAccZsjMHIsg6bSHDkyXO0LcAtjeLg3VNbQFHapnSUyvq+rAygIEY5VS0MXSBGtdYFaiTfw77n/LBjN3QEz1dLcNJiL4gYwXOuleTqo8U5JgX1Q1/dhzTtiOpGsKqhKq0TTdXWZsGl1t1iihtTa+GAp7qMu6Q1k7puId/N00iaEqFLliKQyNOX1/zj7z/ln370kmO1Zoljse7GorBL5jRPZaaqzVVXleiDeBgC3/rqO+yToPNsZfYeRBTXblCrAwcqZZqhjEgdCaj1HZLCWGbqPFOyUmfTNkkBDl1gvxuIYg6iMNt3160JVFfwZdHl8MTVesgEMe2UOiMxoSZdxoN9ZIjnPLs+cRxnbq8L4+nE2cXBnncI7Pc7W5s+D6Uo4zgDwkDvlORo3lrEOFq4IW/yBo6mWG+gRJ5det7nfVGMdD2lkmfubm/Xyr3qXclFOI4nalaGPllwA7ZfsN/N02hlxSEwnY787t/1u/gtv/13EboLR1OLp7KtJ5Plf+tG1GK1iV/kWg+2N/gnbM4obevCHeQAQ9fx+MED3n78mJwrJReeP3vG0ydPePnyJbvDwPvvv8/l5SXHowlcajap/+PxxOxdsHe7HbvDgYdXV1xenCNY6vfu7o79MDAMRj4/vzjwaHzE7c0tqUtMxzvytCc70XyaZguK7n0CKx9epki3FZEsgW0LFu4hUNtDX3AqoUB19CLo6hzSkO6wIP+rU7BmBO4hHdo0g8L6O0fR1rmw97ZmkCvHcvPx3uCc3F8L92dzg860oKnZzcXZasgPoG94z8+4vtQOSoppEczZMqdrzeScbfK2KR3AedO0Bn8xRoJ6tMOKoNzzht3wtk7H1EChLN6iSWrPNjm95aCbiFNU4ywIhUpmmk+M45FxzJxOWDQvln8uxxO1i+w6CGqaFNGbkFWMn6GlYoL5ax64OOyvrtkRQ0SqVS6E2lqlO+KjFS2C1rZxMmA9IFTVe3m0DWGvuSxWf7+FLOboSUoJDUrV2UiNtUUYxqfoq1Apnl+1TSQaTLK+KFqqI06FUhRJiawQ1NNnToI2FdiybDRVIxbHZGWglm4zR6X4vYVNvtXIsL7RGtTuEUZVI8k5ZWBxcKLgr2lz2qfIoROS2OYOag4KXh5+dnbGfr8jRENGUrLyWgmO2ImN3zxNRDXkYxRHqcQimwatazXNF0NOxIQA61p6qKouF99QQDOcQfHSSNPjaJwPgNj15rxIYJd6giTqXOlDYBh25Dgw1ms+fnHLi7FyzMopC7OLTO2SydSbCq/tuCSCdpZSiEEIWolakWpNJPuYiNjc5mXdVKJUqJkuKClU+j64w6vcZUv1TONMnm08hhA4P9tzfjYQg/V+thJmG7uqaqhbUKIaZ0yilZOa6nFLg/naBprKbnPgBoHYC+Fqx/Vd5tnNxOnOS5qL24doa3GarAlnm9M8G08qkbznlDiHRbx6zO0OwRaZWsotpkSIlj7zW7JDq7jImQTG05HrFy+gKnmeIVjn4GmelzYAWr3aTwIpdASqI1urM19zNlKtDJRarKJFkx8mG+TY0R82kfByWC2/++FOy5ucFHXUsL0WsjplgnJ2GHj04IqPPn3KaZzIc2aaZ+Z55qq7ILm67zRN3N7e8vL6ltPdkffeeYu+79jv9wz7HcNuxzAMTOORcZy4fnnkNB55/7132R8GUpcI8cDb8jaXF1eows3L59Q8kfPsabvRUo5V1/SdtjPhVQxp/YS2vjZo0+Y8acjnojp8b7zEkc4tmv/qGWZ/31IXFsqBr7O6cZC2iMu9+/H7fKPfsXncUtH4xsetztH6utz7Ha/9+3Pe8JXrS+2ghBhMZlrV91OACjVXaq5kKUjctE7HF42PU4zRS3YrbMpLl8e6wp+6AQgOj0fBOC9glQlOpC2aDb4vmYLpKYRqMu/9sGO33/FSlHFscL1D+WLRcArBZdUhqlCSkMR4MDUXW9AqvvighaVahehpCnWtCMEqQQqV5LL71hsorKW44llPsRSP8TtWxrgt+s2mknbP1Q9lHygnHgZRKxmtQg1Y11gvna0lU4fENBdHVhTRmX2C80GYZzipQkzmkFVl9Oql1lBuztm5A7KUem4/RyvFFdq92r/agY5NkxtzvATXSacCBe9ZpLoYFxHjrQxdoGul6i7DrWo5X5VK6HvKZE5BEsyYiZWFmxNj4lHTXBhzNsn2rMQUrIzZDYqtUVP2LBVyNq6Jic6uGiF2cPk+wIYhOkoRohAxh8rE8kzZOHkTsjlPhNQRgtCfDbCP7A4D+0PHERMxO47ZWhUo9uZuXLo+EJNF3dUP0K4L4P2EoigpKNc3t+RirnV0zZG5FPs8JROoBKlEsomViVBntYqaeeY0mcAfiqVro6X7zg49+yECzrPy8uHFyXDnK4aAivWniq6ia4ioLFwQkeaIN8kAsbSQKme90IVEF5WXdxPXdzc8KxOnnHkYEn2KaC50ndAPvaVpFDQXJAZCaZGtczlaFF7V0Ak22ycFut7K0o2r4pFxaPNdkKq8//iKZ9cnxhEmAvOYmUcjf6cumZBtKYQkqEYIkdM4EaP1oyreuPSjH3xInma6XbekaJfDiqaj4Z764uDL6ph81vmi7nzc++X2IF9/s3nK8hj1fdV1HZeX5wx94vb2FsQ4aH3fU4HnL15yGkfGceT6+iXPn71gHo88fHjB2fmBvh+se3mMZherldPncuL65TMuLvZcXJ6h6t3mEYb9nr5LxKBM4x3jaWaXG/fMuD4Vd7wdIagUc9IbEoK4Hk71IMwHrNrevt+JuA1GcMdsMy5hecEliIbVybFqnaZ/1FJAxc8qcyzFySBSVzvxqpPTZku0zTW2/mhW1L/UuIGvTfdGhE7dgd02+dwi7f/ckmRXz9QmxFIZjQBZ7ICqDR2hoVsYoXVjCDzfuLyeR4xLpBoCxOSIi+VpUzT9DnWyaQjBVWfVZLG1orWYtkLaM7NzxLazqL1OVoUh7T3w30MWS+kEV50UvN26OzFlg5hY1QNLKWlRV75wrQEJlh/MZQJMOVbEODrNOy7F9R7UDm/L+1sKxAIoXXRG1DkfsUEC+EEQBFwkLXqFBgK9CtpH+1wU5mrVGBcXB4TE5eUVw7NbPnp+y82Umee6dHoN0StmiiEnEqKpndZsm0F0cUxaV19g3SisaZvQDC+r3V0M7gIPuclU6KKw3yV2XaAXSGKGbuny60YpSGSaJ2ItkGekFFJISxpwzoVxNCJp8fHVudCHuIyXrU9zuuZsxN5clFK8O7bq0nem+aYBMX0PgRRkKU1OXjFinRlsjGJKRvqu1rAxDj2kgPSRuO9JfcKyAuJry5AfqjlX9jJKCoYQVnfAaq0mZuaVXVEqh32i3w10w+BlsSNTNofOELACasGDiDdVDDBNk2lVzDM5+xhHoe8ifdeZumoS47RQsbo9QdWCgOTpHXMCwtIJVzbRf8vr+6J24UFvpGiqjpayk+b0RXbDnq4LPL2eefLkGadcOTs7sOsSZwS6zoKdqZgzqi29qDgfRRbnfkFTGi8uBFCroospECdbi1Y+HogpUfKJlCJfe/cRknryP/o1Pn5ZmDAnqgZMebqaYrNqoWhhmit5nhj6DhEotYAGvv/d73J3/YKr3WExiIsD3yCNRZbdD5oFdWxEzubAv3LotsX5Bju9/Hvz/OV5ywY04bmLi3PeefyY29tbxilbQ0CF29s7PvroY/q+o+8TMQhvPX7I5eUl5+fn9H1PyYWbmztqrRwOBwskQuT8/AzVyjAMjnhVrq9vubm55vLygvOLA3DB6XjieBxBWnVN5XjXeIbeskOauagLqEIbp+W/7vTpBjF65VrKhLUlkleHrp1Py9qkOeK+NsOa+sFJ/hq8h1FZURNpERt67zWWUV8cp5Vvt/1SR3Xvk6Ubl0bv/XtF4P7/c32pHRRgSTMs/6ZVOrS+LKveieXkXVG1EXvMfvth3tQ210mU9fRYFqxd9rqpS+BCbevfjHhXi2X4ZhVu6dF0wfn5JednJ56fbi3qF5Y0FUtaBRrSPzvvJJmFIex6KJWYEnmel5K0WoshDW4cTYbZ02DVOBaSTAemCYdtCVjmABjnIYogoanaenpF14O+VpjnSo0YUc25JtH7bUSPVEWtMiBWIy7HYGhWnaBKZd/tgMYjUsYpczwVdn0ykTLvVqxeujzO1hO0qAnlKR5sbJDDVm4ewup4NWNivAEzCqW0nhrtbxDd0QoKQxIuDj1DF5yHYk5rDELyrMo8V0JyeHye2Efh0dnAxaGnj2Jt5NVKmE9T5TgavN+T6CRx3kVSUSitwaERJXOtCyG2VCgtxcgaeQcJJDH10+QtkJN4GtLnK2DjXjUwl4zW6o0clVIzXex9PQix6yF0TBO8uD2Rq5BzI88akhdcX6WUbPsmRnIRCB0VkxQf+sBh19N15kRmF+JDrGO1lpmgFSVTBEQq01goQRjn7FVg5gzt+55aKru+c/l2Z+A4d8U6PBtq0sVAjCyVL6khnGJjVbX6fa/k4BBMe8N6frZUpi79pEx0LhIqSDyjH5RPX9zy8volt8eR87MzkwtpyFESQurQktHYCCibtddQmuXgEOenuD5Q1zGnTBQTICMbMjn0HZdnMGtkrPD+u4+4nZ5ao74QmUomz7MFL0VNsGwamWYrqw4BkMapg9ubl3z68Uc8fPu9RVPn1WqM7b+3B9PnRcOvlpR+3vM+s1TVf7/f7Xj77bd4+vw5nz55yjjP3oPLEM/dbmC3G9jv91xdXfLWW2+x2+2Y55nnz5/z4QcfcjgcOJztXbww0Hc73nprz+XFhZdo33E8Hbm7u2V/GIgxcjg7UB4+ZJomruNLt+nmcJzujss8boPj5Qxyu91saiOLbq+GTMN2bMX/vzo3IIuExqrbZehMm5e4sd9s1lStddFXaefSliNzf64bVWDrlCx3y+qkvj5Hr15rYP/Zj/tRkZQvtYNiTd1acSnNGi1ENMWRlI0XuYWcmiJs69fTnA71HgvN4WiPDcEFyQLLa9pwRydytscHj6Kst0wNMDIQugsenl9ydfmSp3dHro9i+htOcqxFmbWSugDVIlnUDtzqGLERc+vSHKsi3vxPyXOhalkMs6U+fJwEOlV32Fb438iUW6IV1IZK6GYTIsuCr863MITH+gNFaZtBST7Otd1/CYiYymiXrInXPFdu704oleNYOI0ncNhdJFhKSo2fUkp1eWoz7irGMXHk0w/3NSpo/XZQ9ys3G3QhB7M8ZEXVqq2AXRLO9x1DBCkZcfizYoeWUggSTKuEQM2ZVJWvvH3gN379Xc52PUOAPM6UUpmK9bS5GzOpCt1UOWhA8mTRna7ci1aBga6Rf9wm7FuaMQZSDJvD2IzXYmKkOaJWxdJ6MaEG/xYqGjGOSt+Ruo6swrOXd3z46VNmxcTkijU/q9Wc8RgTmguTN4mcq5LLbJBzLQyhEiRxGKKTt+uCTAiFmiffs7Z+VKyLNzSHzJy15Nwa6z2VrSGclbdQtBKiiXsZR8vF7dwYpxh8nQWrkArClPMCl8fYkD+7bB/bZtZgLe9pRtwXyRAgHjpiOKM+u+WjF7cbhAsu9snE32rwZpmWarZgOy6tG1Yxt01gpXYsde4wKYEuNU2MTJcE6JBcORsi7z2+5DgK+cMXHJ9d0/U9N7d3TKKECv0QkJTY7QfqPFm5bBBCEqgwTyf+yT/+R/wLv/W3m6rs5vq8A+TXC9P/KFezzSlFHjy45PGjh7x4+ZLbuxPPnz1b+qwFN76tSCIE5wSJ8PL6muPxyMXVOamLzPPMnE2FuOsSRY03hcD5xRmXF+ecX5wxDL2tvWHnVZSwPztjt9vR9x0vnj9nPI1ml15xwlaUTjdOCKyeC4tdfq36RhpitaISYUFPWt+4Zt/WdWuFz/cdnledQPG1+Bqvst3d8s/X/2bn5etz1B5XqW943fvOzJvWzBY9+2HXl9pBWfoTaF15BvhkSENBVpLQyiR2JUtPE0QvS25w2aISq5uDzKPxIBlXtbL3at9lS/yK3rzOiQRRKDFyDDtC6Rh2PY/PB549P3GrukTxVfHyTZPijooxrZvhDKsS6Thl776r3rvFGm0JtrmtIicC4oauEHJGYkbwyDFnKkrX7ywNVO35hjJFl9/2ih9fqdlLK+28V+u6LGsZdxAjEYqYVHmoTd3QxEZbsVRVON7cElPwdIaR0qIk5rkweMfWFlEvZcCs/WckiGmRuK0PuPy/z3cITVOgxQZmlGp1EhksG7jxOHZJON/19EGp82zjmNqBZZ+/C+aApmR5/lIn3rno+fa33uFyF5BaOE2F0zhzPJ64vjlxGjOaK4yFrgRCttSGRWO2Jo1DgaUnaM6gOmpuazd6GiiIGS7vSbd4W40AC1bFZQH+Ri8hBKpUpAvQCaFPVnYZAmOBT18ceX4zMhVbV8UdbMWW/Wk6WZdmrYzjaYNAGTeLqrx1ec43v/oewxBI0VIdpRSiFquaUauuKnlelIxLaQ6kOSjW68ZQwS5GgrbD3lIVQYSYEp1XzMGKnEQBqcXjFTsAFiVpeyjVDXopmYaaFNc6krq2p2/VCF0wZJFBeHjWc3fKjGXm5u5I3/fmEEmxexXTyGkOkqWcfME1FeRmlxyeb8FAEmF2npUXiS+oUKQwxMr5LnB5ljg/dHz4SXYV60DXdUSClSMDEEmpM75XiEzTZO0GBD76/veYpxPd/vyerWs/vxr9bkmQ2+tNHIPPQlLehL5so/n2t7Zez8/2vPXoIR99/DEvX94QxBp/TtPEPGeCCPM0cn17y83NHQ8fPuTs7IwQEo/eeszV1UNCSJQyMY4jL57fGIk5Ba6urui6nmHYW3PWznLaOc/W9LVWJEYuL87ZDz3j1SVXl+e8eP6C6XRiPI2Mp4laM1K3pNimjVLuH9yydU48lm6B4cLlWJH75jC82vdsOz+q6sUAzYawed9lhO/dx+vzGF6b63VueOWxrzg64ZX1sPG5P+uyc/LN7/em60vtoMCKbqgWz9WwDKDZhRYem5Na28T7QReq5YhjbfCYV3X4Abz1XEWsS+5awtwewz3EJZfCVDJaJ6I0TZRA5py78DYPH2U6FT785IbryUpmi7ezDRGKmmnKhtwZqRRDFkqF6A5W6NYeEVWLVU3ExayZwyLRomAxtdaCdUK15/jClkh0Iiq6St6rbAJNXRGKtsGs26apm4oKySFJVUsL1GplutGjxxirKXkqBMyghmgH29l+z/XRD8ZsMLWNsSwRfAjR03aew3Znbs3itRu0+1VWeLNxwBTdopDmnATxqinTnEhBLJXQXqfBuogfPhCl0idhnk88OEt84ysPePfxgS5Yz49pLIxT5XScQK3yhRm6MtMZF9LQk9gcQFAMGeu9hT247ZKAqY8b8a+0ahFP7bSIvOWqW/qrRWatCimkRKYgXYQh0u0HNIIGOE4TL8fK9z98ws1dZpzF+714v44KqpXURaQofTD12aqVLhiBWGrh4SHw+HLHYQgksQ7Tbm/J02gbiJUbljdVeG0OQ1iNcOt9Ux2lAVn1j7DINXqZdgrBkipayaUYjUrE+wtFWuor5wnw6jP1buVgFWOi1hNJXDdHDJuKVAjWWiHGPYLwyYsTdyVzHCdCtEd1qRjfpxjialU/vtiCOLVDvIM0xplrjorrOIVqnY7tEBNiUFdHVjpRLvYdKRQO+8GI6CIMfcfQ7zgeJ8TlmOd5YkgBLfaZq6eLVSrXz55xd3vL1f4CS3eFJeBb5oPVAWk27rOuz3M+ftj1JgdGxNKTV1cXPLi64unT51xeXLDfV/rdgGCcpbu7W6oGrMt6Yhpn9vsDqYtM08zNzR13d3ccjyPH8cQ8Txwu9pydn9N1HYLxoqrvLa3C0Pe89dZbjBdnXJ2fM3SR6XRkv+sZ+o67uzuuX7y0MuTZq/88rY02J9vGstS62B0LMTylIk2ryIj25R4KETwgLvccuC2if+/3/mXT08qJX0Vy3uxkrmTW1+ejZRz8kZsv//c9Q/q683oPMHjFCf2i15faQTG+iC7y8ytExmKg23C0n+33PtQNfSmB6mTU9tjVQ62rNoEYEbQx3+9RvbQJmglZK0VHrJQ5EaodQrnsOMlDzuQZlcK+t+qQOWc7iNWjJ09LmXJopItiWikIOWeGLlER6/Ir1tDKS90JIaFY4YVIRee6RJuqkPMMtVjFgAjDbu+tyL2kWcX7nbnkuDp/xcettTpXqnc6bQvReuI0aLI4R6AZ3xg8HRECfRc5TSOilRQ7kMB+iOyHwvXdEfWSWt2oby5zgjdzww5sH3rbqDFSiqVfltLh5cvXi7BZE2uTOqmVIQldjH6I+v0HKLkszpGESOo6hk4ZkrAL8K2vPOBbX3nExb4nCIzHmXFWpgq1CruuoxsSQSfK9YjMMyJiHIIYULIhIikuNxZd96WhAFXEO2Pr0qG71GJISzDTVwGKV3u9wmcKwXg/c1AO5zu6h3vCvkdSpAZhKpmXtxMffPzUeusEoe86QoSoVqId1FIIjZy381RcqJmzfWTfJx7slLOu0GEVONlVUfM0UaaJTivaGrw58rlEatXQH3OA1QXRCuNUfK00JMSrKLSgxVKSttbqAtE15E/awlUvMJdtVUNlewCbyJkSuo4G14tYR2k7XawfT4pKeDgQRfj45cw4j9wdFTQt9whmHwIdIh0iGzqh31NDAXGifOvwnGum5kIphjb1XU8uI1Od2Q0dF1F4/PCKj6+f0/U9d+NM33dM42haJ7NpsjQdpTlPECND6n1dw/WLZ9y+vOby8buLLX312o7Nq0jJm1CWX4+T8ib0ZeFYxMDZ4cDjx4/46JNPyaWyk7iM2zTNjOMEkii5cDoasnF7e0eMkZubG/a7PS1tstsPnF0c6IfeKslEOJ1GptPE+fkZD66ukCh0h479fmAeR2JQqJmaAn3fcX5+7gi1BYchYAJyY/bKQOceunNRXSKhOShbxkd0+1pE7quR+J7ddk/eKqA3m7Zt3bKJI1l4Ldyvovls7sgy+vce05CcV1M9LWBXXn+9z5rvV9fRF72+1A4KsLgI4mH9mhPcDHT7voHI2ndl1fVoj9kOcNVVhEeJRnFxyXhzdLbeKKAw12yHh5HmAVu0OQuT7MnDFfvH79B98ITd3cgRtZoEj3al6CIwJv7CgQLJFDKT6yjkYqRB9eohkWC5UzXegBY1kbdGGM2Z7BF57Hr6YaBUT9G0w7+lzaLShbiot2ptsKGyXZct7ZQcdQpxu5LXebHHmnHvEibMJsGlkYU+wRC9144queZlPmr7bK3CpM0NrBIpjoi1A0+Clb7WamPRDqo1T6xtgi0tokofA0Gztbxv5XnBlIGLa3p0EYJmgprWxtsPdnz10YGLIVDzzJghz4VS7HAOMZKAMM3Um1vCNKHVKnRqhTpaHxAbJkPJpGn0NPTXYB7r4SO6OIuqlk5rDpitXXMVa0MNPKWWA5QE4TCQHh4I54N11+07KpW5VKYCxB5Jll4E40UltfWRc2FiZtdbKbiIskuRQYS3rg7se3jnsuedhxdWap8FDUIumTxOhJJRvLNriyxrQVz9WQOW/gFH2ezvKpsMSS3EYGXLQUyNtktiHb3ViN4pWYq1IYS1el8lN9oN5WvOc906wLWa8mwrKQ/WBNBkRMzwR1UOnfL4skdD5Mn1aK0AijDlwmmaCSJ0ca3oQdUDHT/cG8/Fq9WkKV5rIVZDEKOvHXyPzblCiISa2e16bm9uyaWSUs80mghi0QjeZBINSDJ0pXpxQCjm4Odx5Hi8fS0af5Wn8MOIjq+mcd50/aiR83o/0PeJxw8fcnFxzsvrG+Z5RmL0SkTrih27gb7vCUHIc+b25ppxmtjvD1xdXbHb7dgf9hzOzri4OGfYddZq4u6O6+sbTncnhv5r9N5HStVUyhPKPB0NcdNq1VAcTJV2GNj1HYfDnk8/jTx58tQUr0sxYcGGNomsqRA1tKXtdYAQymtjZ2b2PmH5TeO/fPevleYgwP05/CwOyoIrK0C49/j2t/b291NMC1B9733uz9+vv7y4XV9qB6UZ7wWm2niU95y7JWJ6M9y1OBPulYINcnEYqxav8Za1o+WrCn6werzW60WgCDUWM8qe06+iPJ0Sl/GK/eUjHuVrjqfZqiYcmUFAiomMibYGakLwlMVcq+lGqEfXpbLve5YUFeIy8hXx8k9t91bttdrjVGGe5+Wz52yaHEnjuhD9dUMbTDtZTD3W62JyVeNmqEWmpVRLKVX1g9cOnhhMN+Ow7xin4geJtXXvO7g8i8gEx6lYE0VxZUTxxuBqzufidAS7p6JqJEo8dcVmEy+ZnyaIJsv6aQ5mDFa504VghFKtxBRRsc8FeGM6pQ/K5dnAxaB8461LHh86BhQtlrwwEtFs0G1QdKrUuxFG0+4Ii/HxQ9otjJW7urNhd+8uqqe3WsSvigXp5ti2TxfEHFeiRW7revdeTfuOeLmnnvWEXUfBnMa5ZMa5MmVlnAop9cRaqCUbyuFYQEG4m6zJYoyVPln68vJix+WDC5JOPHx4yeX5BUhkmjMpCjlPBJ2JTF5V1eZgnQtwzoWnOdTJkCkagigCosXKqYOJz8VkXaqXXH1jGnmbh5xN4l5Vrc1CNJRlu8dbX61tJKqlUIuV+pdoUvwhNZ6QIVYBYeiEhwfjch2zO4TgWkaVGF0TpUaWcLvxi4LrFrmz4m2DiENP5917ZTZ6fIqJPildrNZ5WpTTaWScZ09FRWKN3nPGG3/ONqJRIHQBDYE8F0IwMvE03vH8+bPPNq4bO/nZkfdn/+3V67Mcnc9DZMCqBC8uzrm6vOS73/0e0zTTDT1gHKzdfiDEztJ/aqn+aRoX1d2u6+i6RC2m4DyOxjnSmkkxMAwDXUycne1IUUwuynlH1gIEqgjdrkeGnmnqTGhxP3DY9+z2g7/nRCkvmOd5qaBcgiFPj7JJ/Wwdhnvn0vLfN/N6ts9/bSztgYvX8Orz38QX2szQ587Zm+d5dYS2Z+EPS/X8KNeX2kG5b4TdBsgrbaddg+BNcOSSd2UlI225JI24Bq87N69urpUL42hDzdQCM56jdGEwauWmnFFq4PzxtxD9Li9u7pi0MI+FohCqkHNljsbTDlpImtA5k8SiyN7lypM39craHARPcVXX0pgLsUsLCTFKWHzrUoqx+51HUrzFenKOyuRqvMH1VHTjEOJ8DMEOw3nONBl+k0PZLkr7HkMkBZYUFSLc3Y5oKQSNHIaEPgzIjR1sx0k55UoumAy8v94C1zv3IAYHT7W6OBueF9Yl+lZZkYZlPbhD2EfhsEtejWSQbvTP0RRZA5WU4HwfOd9HLvc9X3l4zvsPz7gcTFsmuxCWloKWShcTs4g1dCtiTdicuNyJQDK+UnNSclPBzVaJ1Zo6hqY4qWtZdWnIUEtrhejOoVVRqcRFX0dCIOw60vkezgdyL+5kdNZwjpnjnDmOVtZuVd+m0ltUyShZAyXYZ5wKJNT4LCI8vztRPviYQy/k8Y7zBFfDBd3OXMlOK4GZoLOJmbHqOsSUfE0Vg82rIUAttZo6S+kIlS7Gpe+PYGKMkqKRjavSOTKSc7aWAFVdG2SNJ9d0jjuhRK9ucsdDZCFkI4Zc1DkTa1g6CKfBUkC9Gon24XkHt5kZ0z2qtZJLZS72vKTVSpXV78d7wRDWyj+K2QnNZUldWI8vOE1Ha22hpoUzTjO3t3fkUlwnqFiLh5IpKsRo6ZEo1jBRUeac7XMG55/Vwovnz76wA/JFuSSfla75LNj/Vbv6JjudUuLq8tJScOXktqh6h21FsrnpLbW23w+klEhdR+oCucxcX1/z9PlLLi/Pef/9d7i4OONsv3MkQKxkvGRKnmna3xKg2+0onaFzpgyd0KqUrnOCdnNym56RcjyO1JKNC+bjX6vZ/vvjsFHk/oyx/zyE6tV0yas/b7kkWyf8TWm49rgfdv0wTsurj/1RnNg3XV9uB2WpNTdiK3jawNENEwsz7oaqR6N+CJjStP3NJq7VmYuDBC3C1aXTsfpzGhmpITUNWjYnpRkSiztrMUKulcsqVEHDnkLi/BB48FWDifOvfpe5VMYsnssUTiglWLfVmC3yrgH6ZH0lWv17lEAuLFEBYFUEIsyTVcaUbEq1KQbvxWORRqiVUoVYlZgifZcMIs/Zy7gFEeub0oTo2nJcFqZrXJRaqF63b+NoLQTUdUTaBgkouxghwRStBFA9z9mJct4JkUSKFT1W5mLza+XFa1l5VCMTNmNSvGmneI5g0ZoSwWu1DVavTlZUZRC4HCKH3vRsKoUgFjWb4p+RFHdJuTzf8/Bi4OF5z9V+x4PDwKFPHt0rZKvcKqqcpowEpc6VfeiI9eSOmBpB0mGTZuRyVct3h0AM7iyqOiHUEYTouWg/cA39ykvUJI5INENZEUiCHDq6h2fIeU8dArVVN1VlniZUiin5ToWCpU3yVKjqKB1CcNQuB2Eu1i/n7GyHlMzLu4mcIy+j8Pxm5Or8mq+9dWAfZkKo7GJBRCkkCNXbFxRHg9yxrNVFpuxzGRnVOpWjXlaKeMq1EFzuPHqgEXCSsCNrUnVdc74ExLkqTRUziqVAal0r/YLzUMSduwaINWc2uJqzCoSo7CRQUbImrk/mnJa5UCSQ50pJgdI4KeLIXwqOsuEEWkFLZR4Lp9PEOGXmbBF/FSF2idNppGhmroHbEebaG4dJWysLMd2g2dIRfbSD1F7dOFZ9Sk6YNyfw5ZMnVgpuO8gQSGkpAnEUsqLaULrPv34Y96BxQdo6XdxG1eV915S5sm0x8uDqirfeesw0z0YsV+tmfBonVJVzhf3OeHQp9aRk6eYgkOeJaZo4nTJDJwxdssqdFM3piAEtmXHKUKqhLsPO9GO0UIswZ1uY7SxIXq48KJzlwslFBhFBnj3nRbmmlLw4v+1sWB1lFsfazhNx4OPNzsM6trLYgzde0riWNpfiaIyIqxLDUgYPGPdpeXLTU2nTsp6pTYV5vc9tifMyY+0dFiTIXut1p/OLXl9uB8UXPNIqMfz7gqBAg8saZG4jVxej1SavMfZDkHXz+I/tuXYoNMIltH4asKZ3zEFp+UA74xQWI6hYl+JM4BrL0T/6itBH5fvf/5AffHrkdmRxgoofCrUqEaUm68kzlUKKClLph4E8zYROrK18KUYgjUbmymqRU3X9lla6Ok8zsQq5CjLP7Ha2aVtfGFWrDgrYuJrgm3vjPpyGRHj/HS0+3K25YiV7f51lUYdgRFStdNEqecbZuq0KJpTWR9sMpRR2yQjCsVhHXZt3m5fQ1kAthqKIEH2eLN1RXRXVniRi0lnF10GKsE+BfQqEaodziK4GrOrpBLg6G7jcBd59dMnVWcfVrmMIgT4aZyBXLEIGUBOcuz1NJA0cUs8ATONMyC7Ljt2XoSIFBBcPE6oWQwliYK6BmFYtDzCHuzrCgRtLY/AXNMjSO0j8sK4xEPYdsktoAqIf0KrWT6qag5AzHEczspbSDMQ+0TkJPWGCg0UrQQt9sFSXhEgWMaXYYvyNp8+ec3O942HqzMBrIYgS0wDFDpQlVafqQnxx4X50KVk6J3k1U3PUcNlx39GWunRj2EqhMXTAnJzoe8+r2XzMgmxKK0XuGVpVlqoeK6f3MmkqUiHGtKAtiDkyuy5QaqCUwu2UISYj3idLq+SYLWUQvZIot6jZdVGCULI5m7kpOiO+h1u5vR0fd1PmOMPTFyemKRMidBLI2Rz3fuiJYmmktt9zzoY+xWipHpcl6GIwZzGYdbNWHur9qNxBcUd6eyJ+Ub7Jm6L2JT0Ly0mp7eflYFztdOsPdH5xxte/9lWOR2viOOXsgpEu3liKp4pdIDBnqzhzJyuKcHboGLoAZYZSmOfJRN+6DumTCRKmSNcFqyJ0u78EZiKWWowJkUCukDWQpkw37Dm7vDLkEuE0T0z++lr8jNj0xlFVT/msJP6GNrdx3I7zZ6FLb/rZZ6wt7+UfLaOg3itl8Yc2TkRz6NfnbJ3T1Y5vH7+kl9pjliffe+qv6/pSOyiIl81V+45XAOARtD3GkRBtJDm7FFYHRNqC2HisrAZr8WtaisAnagk22muqLjwPQ/S2CI+ngZbNJ2QG7kJHCIn3vzXw4LAnya/yvScnbkZDDcoMmuxDdSIEjX4f1Q8SI/llGw4/JBpByyD0WatrhJgEfuvrM5dK1kweM6lLpK63/icCXQj0vZMJa1k2TEuFyYI0tTPEHTLfZIuz5uNQvaqmCeeBl2b7mKuLmcQQ6PtEyMpcxNrbJ+HmmC314I5Ae6+WStLFAbEeLKW2Te9nubFxbR1USAHO+sjZkKwSxY16wF7DSo6Fi0Pi8cXAW1d7Hp71XO0GhhCQWmkN5qpaOoysTHPheDoxTTPTXOk75XTKMM1eDmuRjHhaioJV5eCHv0cwKlaCHLzm2wxLXf6tmFNjVUtOxallea0gpuuTzYszPklNSOsR5bwHFZw4bciJpbXs9VoTOmjkaU97RaFrlsOh7VwrQZR9Bw/2wuUu0kcbZ3Wekerp3npppFUr9zUtkMZ3it5/JQSxHlt4+wR15czYkCXbAw4JLQdpU011hqLZCe8M3bhKLc273b9LtLlwWrZ7u9h4RyuZEzceopUkyn4I1uG5jIZS1QEwh7LkSgxNawnqXGzDYutnLoYUlmLpoewKyKUWptn+fjcVPnl2ywdPR55fmxK1OKrUiL8t5dqi3e3V9m5sOS+tC04cpAUgq51s5k0XA/jZ1xchRS4pn+ZNtt8vTkur+mvrY3Vkh9Tx6NFDLi8uGOdniAip6zgcjIu0G3YIwjSdOB2PVC3ejsBaCPTdQBcjXYC76+ckvHmnKnLY0/cX9F1vTjGVWvJyNqgbkhijzXdrkxJNB4mYkG4gDYW9CpdVrV1DKRxvj2RP+9ka8pF1eYBXS7stlrpfH3OPdrAZtSVlvXoZazbAg/eGTEvrcs/mHGwGkrbPZXntNbh/baZfmfd2Bui9v35eaupH4aF8uR2UzQdt3mEIwYxvCGhoHiu2IGgDpqxQ+CrmdC8X58p+C/Hu3ts26Mo2WkvrtFLhN/JVaEayLgtfFLIKL+oZgyTeerfyG/ORwvf43vPM7ZhgmqlzYap2agRViCBdYJ4LEJExEwhG8MLQlxAitcGS2hRGrUy0la+CME3ZcrkSlkO9FDPOCewA2NTfbwachnJUV3u1zxWtJLbJt3t4W9XQlLYJDOkKS2QZckZ8LmIXMWpBMflyUeaxogl0hoJzZqq2NicGTrpmijUSXNuLt41vXYqtp86hFy52iajV7iUKaCaKVWn0MfLoYs/jy54HZ4nH5x1nXWTnPJVK9dyziUdpBZ3VYP25WkdxFabbE/n6yM61T9rQhdCthriIKaMi3pnaiZMixmNw8uVCAsfvWczRiC5Y1/RgmspmUwNe94f1dpEUUY8q7SBVUlV2u8EIoVNeUThXSW4OBGpk6T4lIpZWmJwz00vlwb7y1UcHznshScEKztW6dZe8iOwBS3IhFxNVi+2A80PB0lxh0TlRdZXhpV27O6VOwm7/Fuyzmm6MOHpSV7RvQ4y1dLDfz0ZluNZWstzSksFVnAvzXEEqKSRCSKb1gzJ0wq6r3J5GqkRK7iipVdsZ2b5WY1NVXV8/O5/CQRCrdgvWpTlXKFqYc+HF3cSn1yc+fX7H7XEil9Wp12prJTgqM+bZRf1Wu9ccBONyKD/43vcYxxN96humsdi55pTo9peL/Xzz9dncho1zsjiQrz/2TeTKqqsjebY/cH5+xqdPnqGlevuMRIxeBaZWml3KTIqBPgX6Tui7RBDv7FwmjrcvrVHpbkfXddSSoJqApTqiUfJsVVQpEbyZpYghctajslIQaohINxCHPSEb12h3pjx87E5JfcLtze1rgaovste0ZV49urf8xjZ2Wz2URm8wR0oW9M2CAFlm1bqcq9Py2zvVewjKko67dxOvk17tvVtl6zbo32I36/1/9or54deX2kFpsuBWjSIIERFTcgwSvcW4bwqJyyYVsdLVdrVILGwk8kWbkwLbHaqCQaDtNZSl2+w2vVO1rOW+zTnx/NwrZoBahKfTQOne4fJ95d1p5qgfw8vKMUOebSFPQdDqcLJDxJIhhsKQElnV0RtrPJjESotTDJ5PtYql1KptMI0PRZwXwCI3LgIxpE1Um722vxltW4wlGxlwKe/NmeBw95oOq65A61LuCjH2SJgJwbRHplDBtTO0Kl1KHHY9MtrJXg+JlIWQlOOsjNlIsHUz5JsDkAAAjIpJREFUQ0vU75uzoV5tyA2+h11nzknS4uiEGZ4UrZJnCMJbl3u+8vYFV2c950NgCNC7U6Binau1Vpzmj2YY50KZqwm5aSCpUm+OpFMlSGTKs5WuSjCuQq3MeWY3DPTBe9yIkfrKNNIPHTWv0asd9CZy1vLCKUZzItXGMTfSnVdYiXQMXUdMnaMOreQ6IMn4SFKFEgPDbo3e4qKCWlfCM877CUKXEmglpcQ4jogEuqB8851LvvrWgV2sSC1oUCQk5jr7gSdESX5IF0MWoh0i7rGhryKTRoRBtXgA0kqKvSxb8LLjNQgw8rSTix3qbFICLSCx31UnlcblkGyHwUI4V+s+rqrgzRslusMYKoFIDLbfz3YdRSvjXBjHcY1ih4hOs+2RpqviFmBJQ7p1qKpMc7bKtJhQKrkqt2Ph1z58ykdPj9yNuA2rpBAdwfIWG94cUkSIGpb0M2AHspdSP3/xlLublwxnF1R1gvDWNvk8vBqcNZv5w65X0xJb5+RVAu1rh6BgnnxDoYGh77i4uLAmp5PxCKtWbyxpDUb7lBjOzxiGxGG/Yxg6UrR2FEE9xVqEMgtzUIJU5lG4u7Vy7xjj/WaOMRCwsvrs9r3ZsrmAhkDsB/ZnFxSE2A90gyEx0VWFhSdcX79YqiXdKN5DTupmrb3qyL06NlttFEtfNuz3/hz5oK8uw2uOhgfrr8zZ/VzD/b9t57G5KO2lRJvDsn3N+yjkG+f6c64vtYNiVTasYxQM2rZcfVigQ1gjiAZ9Bie6bZ2F9XX9Rf37Fi42TkYDynTJU9fiZbz+vXoZri1Id0yWCXR0zU9NoTLlwDPtyN3bdO/8Nt4ue2r9CB1fcFMha3RU1uCXmq1kV7JtsuqHLUFMGhtsdkuBKCSsR4hUZ+Cs5zauKMI4noy5ngzKJJszEyKoBKoLp5nTZzDiXMum/h6mafbxtpxrg81rvc9hsfysHyKhOBJiESbOd6m1LI7WkKzMda6Vu7G4qNc6XVsott1PIw+uG8sqds72nWuMGLJkzqMpUfYJ3r4c+Ma7lzw637EPnnd2Q110TUsh0VSAJ+sce3uamE6ZUpROAnGciUXpJBIkEFNH8ahFXaI/dD0jldN4dJss1kUYS+HEztI4pcKYC0kM7i7Vy8LtRCOKScIGYdWucWejFIvwa61QoEvJRPicFx5CgBqoHpFLTC74ZkG+lbMHh+Zn9kNPEitvH08n68ItlX0nfO2dKx4eejqpm2ou4xGhRhrXOpNSNAfPd1KrPA6xoUV1QYxaPx8Rcy6SCwra3CutqXYIdkBX10IRWQFtBUf7ipfmhsXIa7uLECwV5qhrqWV5H/fRzPG21WKOjhrBtWhZbE2XIsdT5vY4sdMz70RtZeu7YUCqOdeWsbpfqVGdTN8c+ZKtXH+cJm6PJ05z4TgVjqORiq25ZEZYP0+VJrKoSxpQdU3j0MxeLYynk+2fIFCDBVHNqV9w1w34v3E4tvf9wyD9LVl2myr+zMNKWcaz3UlKgcvzM87O9twdT5xOJ6acvex88KBK6PuevXc7Tr7PY7Dy7BSsZUDJE5OYvVnTL5W+760CKJngZa3KOBvKbOKRJpCpAjSdGiJ6iKSup5bM8e4GXKytZEONqxZevnhBztnH1ys+m5OyGc82ZtvKUtms2fa4lvpRLYi019uO2P3x083488r73ft3M6ibOX/13uyeX31+CwZ47T3exKH5IteX2kEJYoe7ec8W9cXkeWtYGNfNLdjm1bYTZamJbSzeIG3vTSMOB4vpZbT3tYeYKFYp8+qHVEcPalMC9A3uxLPtOmgKoCKWFnipO4b0VR597QG7/XeJ3S9TPnkKYyVnc0JGRyu6LhhKVEwJFC1LxFBUOc12wEuxHDa+SGI1giqOAjWYe86ZejxxOOyxwp2KBiWo5+obx0dXUvDWMJnMenHIvuly2BNULVKspZC63rgX5MWRs6jcn1+VWfPy2iHYuEdZxdIMQLLGhUYsXPfUdrO3Qw2UPgrnu84l4l1xFaVLVqLbx55OJt56cOCti55dKAzRxLoUS8Ogis51SenUWZlPhdvTyM00L4qSl0TiXBhCpE+gNbsCaiPCCVJNkK4ZqlZHhtphexwnE1wTSwPMpXK2G5AYlz47qsp0mhi6ZD2fSrFyy2ClkjlnmCZi7pC+87VqRE7xqMt4DoW708nKjIvcG8OKkosuB0AUBT+QS3Enkso+KGepkMT+lkvx3WmOqa0f2yRNYbPFd7VWUhJPV1hKpPHK1hQsNA776rCwjF97NWuw1jgZLK0d2u5efm6RYFW/L/E0j6VIS1mrEJpeCsGCnjpXapkpkeUxjTQfo9B1ken2SDk5SV0CXYtOBZLLBGhVa17Y1oREQlDr+JyLVa0E66lzfnbB2dkt8vQE3qMLaZLpgb7vmfNs4+A8tMK8OGu1qiEJMbIbduScmceTo4uGxqBOcnTej8IbuXbb69XDa+uMvOn37W/b573mrDQDTrsB28fnZ2c8uLrkyZNnjNOJkgu7w46hiy43UIhSlzFEXXAvrjo7iqXUFnmEjSNWVRnM26XOmeCp/im7XQtpWX9BAhIDXRfo+8rpdOJ4vDPHfbRqrJg6rq6umOeR0/Fo/acWlM8+3lbxejtur6ENPjeNpqC0itI2B+vzam1o/X3nspFgm7PyWVjGmxzO7X2tiSlZ/SC5/9zt9WqK74teX2oHpeuUrlP6DuYOhkHoOiF1SoiFbYgtnpZo31/VRrBxc3KZ+lMtZEakebAszkbwpm3mlRQE7wWEqUAa0lA9teJzJ2s8Yv8VlEBpeYlqAm8jHYVzzt76Ft+6OOP8B/+Uj773A548fbn0vlHENCOkELWSopXcdqJIza6DYqXDM44sFPEqCT+YskfqRPKUKWM1MqZEsgb2vemcmMS7fR6z0avBVt2K21mFQHE9mK6zBmutQ62JsmEbP8QFao7BGnh1RShdcL5C9Q1oiFUMQheFPsK+CwRX0q1eTtwiTmsrzxIytIMrBbjYJfa91SNHd07QimgmCgwh8vhiz+W+Z4jCEJQUzBkt1TdlUaTYa9fista5emdbNSdyKlADl11PooI64S4YqmNcCEE0Ms3WQn5LLgZMMVaE6nlvEWHXRUIUE4OqlZotp3yaijW8TIGYeuZqzt1pHBkudjY+tUIxPkg39O5wGudlmgtzFo7HkVZGr7oxJLbgbSvVimhF1Zw2dUSpp/K1x3seXwx0gWWNa1UjXrpRN2ivoWMtmjaUD7WS0Pb76Lo+1RG7uKRxdIkeQzQOzdI0jRUp2JKxm/W8F5gEdwlVmWfrdixeMSduC5qtDa7Q3EpFW5PDLM5nwVALESGJsBsSXQpMcyamRC6ZlJIhJxJsnYgpDVOM6F/EHO627kutlJyZPM0Xg3DY7+hThwSrEAnR+EQ5mzPYkJOcM9EbKQ59Z/vJXxOxvlzEyjgeN0HTds51cRAaH6XJrX9WRN3G99WD6NXn3Of7vfkxK9qsy/1IgGFIXF5esNt17PoOGXrODwP7IZnz4WTtVnaeYqvQxFHdujpfxcZinGZL3VRlKoVuznTdQIwdaRi8GzogQhfwKh5Ps2LcMVXleHPNJ598zPPnz3n+9BnjOJowHpggXNdxpKUhV/7IZzkJ23HZjCZrtN2oA22Y3sBz8T9Jm6dXX+8V1KNxwD7rpmyZNOPanJPNvL3ifyzzrG/43Re4vtQOyltvXXL1YMfF5cB4PNKlnsePH/Pg4Rl936NeChicOLSQjMAXVxvUzYxsIlzr09P0RhxmDiviUKu6XkiglrDIxKPqVQu0cN7fxur31wn1yEYnVHoPBaN1ACahITKcD3zr8oJ3Hj/mn/zqP+GTT55wOlqPiKvzxIND4mKInPXW40Zi5Pbm1jovh8hpnDiOfo9eSTMVy5GjZtAo2bgo4tUdx4kixn6PfnBo9ThD7fDcOnfNcLVcamsPYAqaLdKz8S61oCUDeS2xq5Zq6VJy1VIbbyNJ2pqPmAJmEkM1AkoWYVbbpNnLMGtzSnwPBBESyvkuse8glMnmT5WmcBuYudgl3n848PaDAwd3rJY0gJgfWoui2dJ5U60IEWIwETk10by+KjErD/uOPUqRQknexFHVtXkMmg8V+tZDR1vEZBoyJhZWl5rqRhakGuHUoh+TSN8dOkQC4zwTAotablFlKplOBudkydJ7CB+rBlvnUrm9G11szqX41VKaRtQUR0/M2BdPj4VoXXzPIrz3cMeDQ0dgomql5IlarcpC1dIrsel+eP297SdL68Ro3JwYmligTf5SYRKCR5t1iRCrOy7StpmYg+U4h68FQ1QMudG1U3StGIF2bfEgMRAkLQdDLl5mBeu6dm6LxS8tTbXYefDS/F2fGI/FHBDfH80011qtqWA7FLyUtVXmRW8EWbUiGkgxkec7pFp6QsSqn4rzciS58CK21mJwF3HZD7aeLXVhYoBpWEuq33x5lOal8G9yPH7Y9SaI/1WWg61l/YxDca1UETG08/L8wMXFOcdxRIBdH4nB/m4tCkysrpVJi9vzgs8fns7DStDLODHOhW6upCkT4kTqRlI3sJsLXd+Tuo6+64hdMnTOiwDm6cTx7o7j3R0/+MEP+PCjD7m9vWOaJnKt9NF6VInc5znZF7zRoXgVvdg6FRsUo42PP9gLg+6/3uL4+essHBifB21Bmgiv69000u06F+BcuLq9D938/MYp/HVfP5KD8qf+1J/iT//pP33vd9/+9rf5B//gHwBwOp34j/6j/4i/8lf+CuM48gf/4B/kL/7Fv8i77767PP673/0uP/VTP8Xf+Bt/g/Pzc/7YH/tj/PRP//SiAvijXD/2Y1+n6yN5NkGcGCJ96um6Huuf0RwTaMhIixbu13c74WcZ4PVvpjS7kls99loeatGccyeWzVRRV2sIrzy+mU7zW7xCoFr0liXifH/Lm/qTIpn4zd/E+9/6jXz8K7/I7cff5bKHi33ibG8kSIvKZ1QLvDNQq3VDvjtlnry44dnLO8ainOaR42jVASEkyM3oerO9qVI4USTSdcnIh36gCOYkAKTUUUv2qLIuzonWFnkKp9NETNUPxbCMQ3YdCCOGOSylFvFYqicuOirDMFgPkrEwlxmphS5YeiSmYGhGNHSrVIwo3GYxJPZDT6+ZXVKiFmKw9ynFKxqkcr5LvPf4wPsPex5f7dlFk1I3IqwhU7ViZNJSmcvMWK2CKpAo4gdtKeyrcJ56Dikwy4juAqHfGQJRjVcxV6VkkKJo9lJR97BEBSlCRJBqJdOigSyVAnQhUrzsO1qHJtdQaSCHLDBwv+vZne2Q6N2qU4DO9kQpBSTRundLiMzVxN1a6gFHPWIwh6Xk6hotVhUTUkKoBCoPzyPvPtgzRDsQiqtrooE8W0fn4LbR0BHvayXWQLIdqFZFrYtBDR4QoMX1PMKiAF2dX6VYFZr6YRRbesBRjq3RXl7bd3StKxIoMSDE1bjjaEbOjkCu3JEGsldXAl6q/aRFqnC27xizHZQGrtYlfdU8KkNtGjQr5JqXMuNSTL106HvKVI17NI/EAH2XmAnkKXt1luucqI37MHSoWoqvKQ03JGmejYzdiTAMQwuCfc5l5W61UfoRnZLP4jiso44hIsswKOLIlHiaTFWdGucl3W55QxDOz894/OgBd8c7Ss7EUD0Nb+s1NeTcUeSFVO6HcHEH1pzwRiaPxLkSU0ZCInWZvq8mc9B1RLxCNARKztxe33B7fcvd3Q3Pnj7h9vqaFy9fcH1z43wVBYkUb4+SayGX+V5aHFxM8Q1juzgytSKeomxo8IL0b4Lu1VGQzRpfHVQb8nUP2NZYwszN3JiNXon4670qsiDVn+WsboPDdbpXWsOPev3IXsFv+22/jb/21/7a+gIbx+I//A//Q/77//6/57/+r/9rrq6u+Pf//X+ff/vf/rf5m3/zbwJmtP7Nf/Pf5L333uNv/a2/xQcffMC/8+/8O3Rdx3/+n//nP/LNv/PO2+z3u2XihLUsEFgMFLTB3EKIvhll4zxsnIh2vb7JmvG8/5uFEIuft8st3I9QVm/W3BhL8vi9EahiUZA1TXPuw3xkfPoD9vvE/uGAdlfsw0zqWk6x2gZfqoZsXxcVehH23YG3rgbmCk+f3/D05cSTa+soO2ugkrz6xaqAbmsh95EhR8IMQ2dRZwrJkQJbOFmEQvAGa5YGsQ7MdmwVrZTZ+suE4IZOnAVfLWqtWH7eolwhOcRoh6QZ7hhMcK7UTHFhuUglRGWuwpijR/nQ7fdcvPUOj9//Kr/p27+Fy93AX/2//l/IpxuMSBgo2ZrH9VF5eJb42jtnvHU1cHXoLX2k6toiZhyNJO1ICXag19ki4Io5RjVDnQr7pOx6iHsIfQ8pEPuOXKxjdVGLPkTtMwXv9URW5qmQp0o+znQaSRliEYYYiSTLgavJmAMEifQbVqxpwbQKrUoYIjIEpBe0A225fFgc+BRMbOo4jZzmSs6Cmt486vLriCcjk7UqCH6YKkrQwqO98O33Drz/YAeYojDO0RIwIyuRkCJaZgitEyvm6EQjvoqT0eNCLHGHTY0EHDbb2rJOG0K4iwRu97PtPSd+Nm4JcTELBtPXBQJH75Pq0UrQShN6C+BBj1ra03duS5uor+F2nHZSuRwCx9zQReseGkIyTg52AMXoe6UEShXmWbk9jdZBOnXGYaEQ+oR6pVaZzX6gJmMvzgoIAYJCF3tyzsaRAydat2g6gERCv2d3uPDqixUJMl6coc+yHY9Xrs8juX4Wcda3N2tpbDt4LRfuxYQ+98ts0FzCEMxhe3h1ybMnTxhHherp+2ViMcRuM8cSzNlsgne1qPX6IvhRoEjOyFwJqTIghDgzzTPxNBp6WhT0lrubG559+ilPP/mE0+nINJ2Y5tnUZMsqqtecuwrkOTNP2dUuGooituYXh9D5AJvPrC1gUEtdhto6fpuX3KQV1rW7OcxU17Gr5mAsv6aYIyoNJbN5X5yUNwFr2twpTz+/Ye4DRhxfF8J2Pdgj1lLnH379yA5KSon33nvvtd+/ePGCv/SX/hL/5X/5X/Kv/Wv/GgB/+S//ZX7rb/2t/NzP/Rw/+ZM/yf/4P/6P/OIv/iJ/7a/9Nd59913+pX/pX+LP/Jk/w3/yn/wn/Kk/9afo+/5HupfLq0vODoeleqcJIdkkFIe6102iaoZl6zmu+Wh3cBoi0gykGHrQILlGhFuMmkdM6uW9Nnlh4+2293l9o5rn7g6KKxDaInDXRUHGI9dPfsAn/+DnkOtPuOSW/TDRBa+IEYPPA/Z+raeO9SGxnimhgyF1TFXpwzkXh8rF+cSz64knt5m7EijSEfs95w8f8vCtt3nr3Xe5Oj/n+OJTjk++D+M1iZF919lBo8Wrldb3q6WuOh5i/IDJdVwkWjMzy60bx6RUD3SlmiiZj00QI80WMUOWoqUiUhD2faIQqNWIoLko/VwoKgyHPV/5Db+Zf/E7/yrf+Vf/Dxz2e/7P/6c/z3y6sW62HnkHUc73icfnVq3z3lt7dlHpYyJJcN7LhsIEznOpTIuIlqWs8jwzz5lSMhIq/RA4v9qRkkKHHe5R0CKLgJ5gmh8NXpeCyZ53kbCLhD5QZmW6M+RhpJCQtVO0ozqCoSe48VI3NiFFMsWaofUdOVmH7Rg6YxunphVkvII6F8aSrV2CGytxkq1qNORHq6nOAlQjDEuoHILy/tWOb717xcUQES1W0VIK1r/EUiSmd2LqvDFYtRGLQ9LeyxGFhkI44mSOZTPX9rfoxMcurvL4jbeyRJ9YqqTUxglbN+2676Pv21UvBNqerkv6sd1nVfW0jz1lScP7nm7oHZi57xLMmpbUp9N2/cBsB7Q9vtTKNLceM8ZHmeeZrIFZDXnTkMjVhi6lwLyyFU15eThQS2bOs8sCWLpsnGb7bP5Vsb4++/3ZOha+2BV/XEN+Puf6vIqQz+IatHNxiyqvr4enk2X9tS5hIQB913Fxdsb5YU+eR1TafKodxM1WY7wgVKBYv7IKZqMcDShNK0g8KIlKcpRknozfdLo7eQAsnI43vHj2jNPNNdPpaPcVrOqq+PtWP4hDiJa2rJVpnI0npHpvzj20WIKANX7eBLv3wtzmrLEEubTAyf/XeobaGbKeQWt6Zx2fxsdZybNrluC1eWOdh+YM6SuezGvPUjbPWMLn1177s64f2UH5pV/6Jb7yla+w2+34zne+w0//9E/zjW98g7/zd/4O8zzz+3//718e+1t+y2/hG9/4Bj/7sz/LT/7kT/KzP/uz/I7f8TvupXz+4B/8g/zUT/0Uv/ALv8Dv+l2/643vOY4j4zgu/3758iUAZ2cHzs/OnKWdSKnzPB9rJc0md6eqa6khLHlZy83GBTqePWUkvlHVuSj6ysBuy76WTsZOeNN51R6QEMwIv6JambFItRdBYqISTeXSocnp+hnf/d/+Ni9+9e+wv/2A807pdKQP6lG9QX8WIdi0l6l41Y2lCaZqXWFjCCRg1yVSEg6HjrcenPHWMTP3D3jw9W8zvPVV3v7at3j01tt0XUJVGG+e82u/8Pf44Jd+gfn2GUMQCEqerRlWJRq/pTaZf1Mc1SWv6Y3KcqbZHFVDd5TGAzHSbWlGTauVJZdK1tbI0OD+wSPIGuxI6VOyckFVimZymXlwdcXNs2f8zH/z3/D3/5e/ZT67H3BBCg8ven7D+4/4yiNTh+2jlyFiEXlqa6hkFKvyyDkzz8qYTTQLLGVRqxKjUiQzHCLnFwPd4KVTXnJS1R8f1u1rPAjcuajEJNZjJ5uBDETqeUedrZpjzgVpghm5WhkzgWy5JyKmWxJR+hjIAhrd5Ei0gz5ZpU/FVFWDE/8qQs4uKNYQGZ/Dks2xS8EJnhi3SUSRkjkbhG+9d86DiwGRujgdqmrUhejl8B7V0rDOYNoNotWcmRjcAbDHtAPOys4bj8nGS9XI36ueyesHpfE6zCAGsdJb9cCj2QPjebQkbHCbwPL+7XWtFNlTMbUsdsFI2qbW3CLdVlah1bg8cxY0BC/TN6TPSriTpSX985RqZOWSTTMnJUNLxtPMzSlzfZz54NNbnj6/pVRTHU4xMIQeVWUcrdpnnvNSAFDU5jOkCPNsiAo40mNI0lp23BxT8bn3/bmGYm+83oSgfJ5z8sOuRqD9vNcQEfb7PQ8ePOB4PDLNp8WRtP1qq6yIVy6V7IiuIxIArSy3AlTXzLPePOpBx3RrFTlTsQaOtRTm8UieTq4ejAVr1TRSSt4iPi1lHZhPI7e3t95Q9VWcw+/HhRAXkir2GVZUpaG36gjdgmXQijNaIN04Pavj3BxjXQ3wOlvLHbd3bN8XJ6aN69bVaE6grgE5sPT2Wd9BNp/1vqP5Ra4fyUH5iZ/4Cf6L/+K/4Nvf/jYffPABf/pP/2l+3+/7ffz8z/88H374IX3f8+DBg3vPeffdd/nwww8B+PDDD+85J+3v7W+fdf30T//0a9wXgGnMjGm2PHks/mWHi0FaLa+5pnJa3Xu7YutRoW7IPNe95uCbAqRDoE38CQfDvGLBoBSH0KpJf9cmDOWLrin7teiueoQiYmBxi4ClZuab53z0D/8eP/j5v8kjfc5VykTTUDXOQTW9l6bHQKgLR0CCEWI1KIMY2a7UTHLlW4kCWghRiftI3iXeenTg0Y99lQfvf439+UNbfEGol+cwT4ynkU+/+4/I9YaihYo5D0cXTNNSLBJ1D705LK3UtBR17oQR9WIK3j1ZFwfPIj71VIAhRNYZ1hZ1MqKC9dtRI8XNtVJCpWogdR1D3/Hs4w/4q//3/5YP/smvouOdlYfHCLWw7wJfe/uCb757weOzyBAFqut8tIg+mp5GbhvRD58pF46nyYinMdKFFg8XhkG4OBvY7QIasjlFztBfiJUiS4RntsIRvmAqj11zeJNXkiSQDkzfJFoeXAJlykhVQg1QrOS15IrmSh8M6SmixD5Q+0DaD4Shp7YD3flXjT+Vi/Ly5uiN14RWwisqrjFiaS+qO1KegtwFeO/BwPuPdvTJUiFaC5pdpyZEkkeGMVgljDR0s3h6MzjPS9QIx7OV9vfJ0ol5ng1tcpJxFZy7Evy5tufXSjKxteNmvJTm8PgWXc7bhpJ6SXzrS4Mu9iKkRIi+Pgse7CjJYWpRjEQe4mJfFp5LtbRgVWWcZ0Q6pFiUriiihdi5JdG6CMF1qTNHKATmcaZq4G4qfPjkmg8/ueaDj54wTlAlMY4T/a5jGkdHgYQpT8QuIsG4Xn03rAejWho2djYQw9BbM0ZvA9GCMbYR++c4Gl+Ej/J5z33VAfm8lNH2MSLCMPRcXl7y/MUz8vVo/b5gcTpELE1RHDkx07z2Y2rIt0hrTBlc6NFIzdM0czyNHI8jo6duqJau7iJEKnjfsloDuYgXIbTPVBeHfRpP3N3dGR+opWPbgd4O/eVzb9yXppDcviwhvqA5y1jW9TWaU7GCJet46ua/7afFEZH1t/fRLfvdVutKl1vczJ8stPT1dVoW4NfprMKP6KD8oT/0h5aff+fv/J38xE/8BN/85jf5r/6r/4r9fv/rvokfdv2JP/En+ON//I8v/3758iVf//rXef7sOdNpWhbtAt2KuiHUZYO9qbSt/T448xswtGSTF1y8Q20M8WbcHS01Vp9vDnXtE11KEpf3aE3oYFlE1SOWKVQkJFQi1MzNJ9/jg3/wd7j9tV/ksj7lwU7WiQoJVVfOXHKvdoBmNT2YlCI5V885w9BFJpdlt1gRRCJzcAcq3/Dx//b/5sn3/ynv/sbfzte+/S+ye/AuMuyoCpeP3ubdr32T62cfM70cOWY7HCuQi/XIsZRStfK+FoUCMXbmzPjjRAwS6brgRjQDbdy8VwgWIZpio3i6wdI+QZR+GBj6yOW+559++JSxRrruHGLi2Scf87f+p5/h1777faQUdn0ESYRa2XeB9x7u+eY7D3l41rFPleC8DRNS88oR9cgyRGZ3nnKpzLkwzjNzqQxdT9dZz54qhS517HeBFCspGALRGrhJUGJsUb2b/7qai1bpJyKIIwal8YmSrZkQLWoPYMRQz2XHkJBsDmIpqz5BKZUShLgPpF2kNoSmRcXqPJBgLSGOp2wqtERb836wh6XzrneOFjNCAeVin/jWuw95dIhErLS9zMVSM1iXbRqkHdwcupEzjo+sB4N4ZYt3MbZP56JyAB4dhmh7khYpespiQVtgHWO/LLhYu0I3I7ytqIC1jNaCGF20VFSdeK2NS+KBT2icoobyOL8Ic6CIyQ67nE32QPAeSX4wqY1pqxw0VCMs3DQU5qKcsnA3wdPrI3MVYteRZ2ttcHNzbdylrAzDQApCiIm5ZKZs8gNNcyPGRNXZ5qFaevBeccKaX4CW5tmcXp+FarxagfJFHY01pXcf/Vqrfbye32bRfhaTPAhRODvfc35+xu3tS2YKTaxOFePyVJOjz+1eFu0I9c7uhjQHUUSz8f4cgil5JE8nptOJu+Pokg2BQbzCT8yWtcquXAQVU962Sqq4dkk+3jGPJ2o1VWxtSMY9LMUsZkP4tuO8HZ91zQKvpG+W6XvjiNflL+u7hmXOGyeIRY1pO6ftSY7mbH0pv6/mmAhhOXfFldy3qE6958T88Oufqcz4wYMH/Obf/Jv55V/+Zf71f/1fZ5omnj9/fg9F+eijjxbOynvvvcf/+r/+r/de46OPPlr+9lnXMAwMw/Da7483N04y2gCRsgWV1us+FNwcGRaIaoG12G5SbKBpLyybuWvvqMtj1J+3Mg3W71vosl3NyZmYIXQokdP1p/zy3/4b6Mf/iLe45WqPVa34a0m0SDbF4BtLXbBMDc6tjcPhSqNNlbRa9BnV2KRdiKgayS/UiVhHpuff5eOff8GzD/4pj7/+bR5+/Texe/DYyp0fPKK/eovbl88op5P1sBHIeSJXcYPu4+ucglYCGRFiNRh7LplcJ3ItpGDld8WF1rzTnbWZVyPbZmfN9X1CS2HXJc73A1dnA+9cDkBg/PCWowZuXt5yvP3EaqiqOpkzEKQyhMLX37rim+9d8s7lwKEzJ08qJCc7qlgJ4oKWeWBZcmaaZk/fKSkmtFaSRA59oIZAitaFWcRQBDugff6DuPFpDH5ZeghZZOdrpVr+uGk5EC1PjpghNRKsEtPa0VhCMX0VMJVghSoBwZo/aheYyCQjnBiiU4xjk4Z+ISXeuhFWT6+JS58X14AxW2hdmCORGOB81/Ng37OL3iXanx9EaIyitsa1KLnMpGjVYbYLqwFIgnO4Cl1KdNFk/8WDgmZ8m65H4xtY/rt15A2LA9IcDRBydoTEUQ5gqbhrFRXb3ibLYSD+eXzdipjTXF05WYKVbeNpg/Y4K2FtXZTVOGJ+kDUOFFj/IFAXhGuKoYYgqkKeZ2q1Pk/jrDy9vuP6OFMlmSNalZQ8FVSF5NL2EsXLXwt5royhtbYwZzC5NgvbNIo7XuvBKM2Q0mCn1Xe5b1vvpdQ2dvbV8dxer6blXv19QzY2JnjzszvsITAMAxcXFzx//tRQoqqW/qrGr5lLNa6J7T5CVe+vEz3YAepMLrMJVzqaIGLIWJcifZcYJ+uebJWO5piIpw+rqtk/9TJ0tZMkOgFdp5l5OqFlJkijzmpra2WfrXEeHVFsnzOE+0G1yHZMVwLzArj42L3iPyyfa/2tf1W1zu40VCasvLtlj9mj6zLPvPJ9ff6991TWs7TdP7KosH/R65/JQbm5ueFXfuVX+KN/9I/ye37P76HrOv76X//r/OE//IcB+If/8B/y3e9+l+985zsAfOc73+HP/tk/y8cff8w777wDwM/8zM9weXnJj//4j//I7//06ROOx1tWKeywTJo0+cO2Gfw/obGfJWx+HzbM47YAWm7WNQ/cOVkH/c1Rxb0JEwfjZLP57EGAF88FIZGpWO+gF7/2j8mf/BoP8g3nQ6XTQFBIwfzPKEJMQvKaEiN7BayG3cTiVK1suGqlS8Jcqqm0em62i4FcTACtCJRoSqWxFo7jM+5+cMvdJx/w8Xd/iQdf/008+sZvhG7g8t2vM5+O3H78Pca7l4hOXhJpUWrXdagIk0nGmhiUmHFcvHZxbkmemUNdGsGBHyye1qlYNUkM1um2c2JuH4VdnxhSYEjC2w/O+e6H17x4+ZygJuaWMe0NO4gKQy88Puz42jvnfOOdc3apkpLn4YMaAVWEOXurAte+qc4HCpvDL8bgB1Ol7yIpVIjQdxDDWkK47Rzb1HLxXiBt9WzJiWYIXHU4NMfFyMNtDW2WqIkBKojYmjCZdjPspRZTzgwVS2FEW7dVlygyNU0GYK6VMatxJTIrSdGdKgnR/PDmwqsZ355C0hmR3g77DWKo7qgb2dh7QbFxIKo1mQyth0BDMqQJ+1VSG3dwbQ+b14aerGRYe06KYZPClaVEuTmcK0r6etS+8MV8LEUrtaVqvSy1eJNC9cOIaqRYEUMkRANI8Co1pSCMJVI0Wv8lxOXzzVnJZXKn1ORok7eYyLmiQTjlidM4c3sceXF95PrmjirmlBsvrqnmtvEwInqplWmyexCMCBqDNRcNMRpXJReGYecl6uakaamLZsjyQX8IEtKuz0NWPs9JedPvGwrSKnt0CSLb/Vjw0XcDZ2fnHA7n3N2dmEshK0zZWguUupbxWuBkZfopmHNcy0zNk9nL2BPFt0iIDL2lw+ec6UYTamsq4s3CV7yBpLKQbhUWVewUYKwTQmEYEl3vRRhuDW14LDhbG6v6mUJzqlnOsPuDy2tQibpkwMpz2Th67b7VbUtV1BsI2pQbqtMQye0b2f1s3Z7Nz/duzSpKF2dy8Zza2VfZVoZ9ketHclD+4//4P+bf+rf+Lb75zW/ygx/8gP/0P/1PiTHyR/7IH+Hq6op/99/9d/njf/yP8+jRIy4vL/kP/oP/gO985zv85E/+JAB/4A/8AX78x3+cP/pH/yh/7s/9OT788EP+5J/8k/x7/96/90aE5Iddv/i//UOGvqO1F7eNZodN+67raNmkR5codoejOR8ifnSoR7F4GWHwnHyLCMVX4cZAbh0QWOaa1a9kg9iwIi6Gc1tTuRDQ+Uj54Je5zNdchJnUnKNSkWpNzVJtyoV2GJai4IeYVQCZummK3cJ9SF62Ke176+yZAuNUmBX7/BXmMpG0UueJ8XtP+e5Hv8pH3/0W5+9+i253zqN3vkqKPS+ffMjxxcdURmJ0LsM8W+mx80m0bsq728JukLl3QM4ufhdDBIlLu/lGBIsuNd/FQAwd5/uBFG0op1IRCo/OAl1I1Ljje5+84E6tTNJk0zND1/PNr73NO4/29LHQx6a4CaBWvqy6NHykQfgipBCYpZg6pUCKFqHVkrm7eUncRQ5DsLQORmkzjod9gtZZWMXKYoM7BW6B3Q9uC8MciPYn0yfxL4TW0LFFYO0+VW19qLCo7gYRtGZ3TAK1CHgzzYr3fMlm0OdqarStyqSt2qAQEeZimi9alCjWabcLM/sOdkuPP10OOuNIFVYSdCOU23gbx8uqsizNhCGBG8djqThhrezBD65aqjtaFoSYwa2+tupShm0cJ0MUlAxiN6soISRitD411mHYD3tvE9EaUbbin6VCyg+6gvEbmg3BDzbFEMA5ZzIdd1kY50CXIBYT1ptLoc6zqcuGQOoCRQsxdqDKOM3MFeYCt2Pmw4+fchyzITNq5comX6+L/pPltQyFmudM35vgXJ5nL2NWj4RtXXddx/n52YIyllp9rTbjJcvn+uLHSTOhn/2Mz3NM2nPXnzeP3ZyLZneNrH3Yn3F2uORJeMGUM3OFydOdFhi5DYxCn4Qg1dsAWDPLIFaZOnQNzXWUxXlN8zwzTRHr1WW2PiCIJKoa+pvrJu3nFYi2By1A2O06UnfuvtWKlphz0vgijghukId1HFg+fONG3nvsxrHR2t6jLjZiOy/br4VXorq0hRGf+8UFaaKIVZb71w0io8LyGeyZb7gv3/fN+a1fHED50RyU733ve/yRP/JHePLkCW+//Ta/9/f+Xn7u536Ot99+G4A//+f/PCEE/vAf/sP3hNraFWPkv/vv/jt+6qd+iu985zucnZ3xx/7YH+M/+8/+sx/lNpbrV37ln4JYKV5xhvoC84pDeG7EpE2Aw2ahCbWJe+qyJR65pydhVY0M0QWVlMZbESeXreiILk6lffnruUPSHJoQGopjTovl3AvD9Jx3yhPe7e+cgKmoNa2x99RoZMhgnjtBKRQTIPOoLsZgFS+qLi4EWipdCCiWEw0iSDRWewhK1DY2AY3WcjyXyfre5MLpw1/iyac/oPZnlHigxJ6aetL+AqFAPhFFHE1xLQNtQnkr5yEGMbKhOw+lVkvh1ECJViFi1QxmVPou0nUdF4c9+yGRxKTnXYyUMVdSinzt3SumuXIzFp4+r8xZmCqU2QDePgZ2Q+/wrhkr8/Vt7itWtWU8OM/Xe+WVYtF71yUrkVaFUpFqMVRyIuUiMFWNUNnQPKnVHVbx8YCG7VpU5xGPG50W8QVthzatLMGjN2Xj6S4poFJb/xonYmoxvQ1sLo270YjYkIFCZdLANBcXrXLTJKtiq9tRqmZ3fhKiSh+UR5c95weT37cUggm4WQ8GJYmluWrJUIznJShEWdaGKXv6+aOtWou19Dd4esv3V6uSC67kDMEh95WM3BCURvi1g1lBV4TLRNN8zwbX4EAXYrtijQ5LtXg3hWjdvR2JacRu85jsYLeKD+uZVCWSa+CUoUhnK60YWXjKxR1Zm9+5zpRa6DqDyU65MlWYq/D8+o7ruyMvXt6y1amwlF9dAix8HacuIJ4GSimhvXWbnucJJNAPcWkj8fz5c46nE/vdwQ+W5nC94pRsDkC470wsD/kCSMtnoSxfhET5Kkrd5jmljrOzM7puRy53JgNQrfWBqCEtKQp9jKSglDxR8rwIQi5IYoXo/XxaeXDrD9V3kVrTslaj94eqrYGrtn3pFFbBhQeNEzgMiX5RafXRXZ7DovdyL43iNkLdmfGdszgo7fy/xz1xv8e6FDTu0fo+jZyv6PK81vz1TZkB2l/c6WmVXc2hae+55XFp3dT6LPfV8FgPTjdFKj/s+pEclL/yV/7K5/59t9vxF/7CX+Av/IW/8JmP+eY3v8n/8D/8Dz/K237mlUvidDpxc3PLNI2bxe6oBm0DrAu8CYKtC371Gu1aXfXmiMSY6Lqeru9IyQ7NvneC2bLedIGJtz0r1pyuIzhYSZqEQEJIEqkh0dWJbhq5SBN9zIgYghODuiNiRj3PZuQIRpBNnUCZ0Vqta26IUAopmLBUi4wMGFgPAwhQK7vU2YaulUkzRKgiJBJVhE4DsYyMt3dMt59SNDCHgWPt2O0OXFw9QqZryjxxHCemXNExb6A8741SLN1Tg0UviDPe1cTdrLwy0A87Yn+whmZ94mw/cLHvSVKQatUxSYyYaNSDyvlZzzSOSAhcnSXmO6ij9+LwcPfTT59ykAvO0hmpj9aMzQ1yKaaUOufCPFnVyND37px6ikIsgmoVX1oKu92OrouEYETfpjKZZ0uxmZBeWEpPtxwEcORDgpOy8VlphLJ2FPljqysaaxPCEx9DdYjYNU00u9NTKWWyMZZEqskanWkTWlvugtvbOy+dFgd/DI0DIUlApVC9Csrw7EqfhPfeecjZoSOIUjwgKNmitxQDfZ+gesVOQ0b8XZe0j67pMBFTPjWybCV41UWxEhpTDG7uvwcPzYDX6paZ1w+zZkSr1Ht/V+eUNFJuq2pa0gyN8I7Q9YEu2iElLkOPWg+fpm+Ra2WuUAhkhLtZOc6CdMHIs6WQgkX13UawTVWRmAzFy5WswmnOvLwbuRsLxIE47GDOhOrcGSfjmj/ppPJsVSbmwHhPnpLZ7Xeglvo7nkZyrsQucXN9zQ++/32+eX5lWj0tQt4cbhaNr2ulIdWrzbzvmOi9x/KKHWQZ/y0q0B7XXmAb5d9/7dcfn1LicHbJbn+GynNTa/X1gSgpBroYiaJozdQ8m7JxDNa1HZOxKCVziGf0fUd05FRjpE+JLkVyNtJt8OaDWo0HVurKXFzTkQIUcp7Qmi2wWM4fD2ppKVpZxvT+5zWnc3FQGnrY5sDHIDgq8TpqoVQ10r8qtFJk/PHNWWlk7Ff5Ivh7tR1baZyv7RywvH4LsmTzu/YYXR6vHmRs1YI+//pS9+I5HC6sl0i4tcjWoy5ZqhUAtWJcQzCCpTLEDw5HkTc+xIKuNPQkpY5+2LHbH9jtdvRDxzDs2A3WnyHcmxQvO3WmU5RgfkCwDSNArAJSqcHFpoiE0FGunxDGH7BnJjITUyAwE0vCfHFFguXsheJy3pWuS4w5Y4vO4W+1iD4E07cwLQnTjYhBkdgcKLX29rVCNhVX9T4gWRRxoaiIpzDUSKS9FvZE6nhk119y9fAKVJnmzLMXz7mLI3NxPRlMKEtC2nAUPJqIAVVjtqeu4/zR21w8eodH734NVWW6u+F83zMwc/PkA+p0QxIlYuWuMQQgU4tVNJRaSAIXfSRoYbjYUar1p7m7veP2EBnPe/pgGga1KnOxHkS5VKYpM46TGbRk1FmtiubCOE5cn2bGcSJROPTCkKAL1fV+bf0VrRQphjS0dM5SVeJIi6+R1iJhQfO2l8Ptlre187kWQwXqgrjYOVnb2hNLLGm1KhvUU2WavBuxEZM1KJVIUCPDljkTRemCGJkVJaQOzcYDKapoaETADJjRv7y4QBiNFCwbQ12h662CpeRs6Qht6SdDlkxBtTOd16VCx6L7kt35FEid8VVMaM6cxloyOSvSdb6PnSQumBOMOXQSVvK6OXC275M7nhaxBh+btSSyONk4xETCe2yVSqV4CXohOYG1qDBX01bKpTKrkNPA9QTXp2LBh0PtQdLCW7AUhBEbgucszQQVShGOY+Wjp3d89OyOj55ec5pdc0jzKnXQnDP/7H2XzBHJJo6nApXAnH2vA7u+gx7mXDm+fM4//uV/zMU73yQmQ78UK4FGlbpUdKzoL+BSDlvxPO+VZEZ2DQgNBLiXdt8GirU2kv+6f5pSQfGqQPCPKVY+3w67JqRpcxbp+sERbntPUzwODCESagGtSCikKKTYE52MbchXZsqZPnX0nSNlAW8hkExzJwRrMOpIe8HaahgxNiwHSWtoSp4o45GaJ6oWGu+pORwrSh83fsPGscbSQ60EvLpjsYTVet8ZXByMZVm4DaBNoS7v0dDjxXWQRltdg3alkRrcVNMcqPvOZvs8C7L7RgnadQ4FZZ7/OXFQDF73hm+uFBpjICRT+ZQgK0kvRvrO+vSklLwiYFMVIPa4GBMhpAXmQxKpSwzDnr7vF+Z81yW6rlvy/cEPIcEMWxAhggmKCajXNUQ3TCU0AxqQoowvToR6ZEhuHdWQ54Z0p3am00o0XcFVGtfDjIlpHVTChuiZkn2mqqaBMBcjY4bomhY4KkOi1tkaoLkBaMbcaoKN5BlLpg/KVGZun52opxt2uz0PHj5AODdy2Jg5BThOFtFXhFxnO0CqugCbfciuOzCcX3L++H2++hu+zY/9+O8gpp7rly+IdWZ6+Smn8US9zkg5mbx5jIgq8zSDmGGLIbDvEiVnLh7s2Z/tmLOJLu0i7PvBmP5GqaDWyjRnajEy5Dhmbu8mhqEjdQqdUuaJu+OR29sTp9HGtEuFXbczLgu6EF+LRwhtDa4kWHFRMWh5dW1N5tx43K/wanD7So6tVdFg7FmtTW20LBGK4sJhbv+MGGlORVA7dFNLd9RCSBFJkVCNYG2HhZdZY6iFVdAb4XYuZUEkY4wUrVzf3PLu0BnC4XNAhRA6tApzNWSpcxh9OX2agfP5l2rNE6vVWlsKs7roYesx41FikLD03anqBOGGdqhFrw1mbs6JeEBSK8TIgli1o8L0SpzX4LYCsA7HUe69DiLUbBUicy6MrVrE05szgVNRrk+VmWRlxKJGzBSP7DfE3dT6TmElxzmbYz/NyovrI598+oKPP37JXE2XBT94m+RB9N5MyyG3GV7bt6sj08iOKXUISgnCJ598wt//+V+k6xJFq2l+jEeohdjvSLFbOFDtPVNM5nQCpWRPryuxM6FMU/m1tdSnREpul0NrDWBoHRVHERXBuQ5qazYXQ7cs2GtIoSFF4uhrI5POufLy5bVXbJnCrpWnVzRnpmkiBiV1cRlvUzO2PTr0A3OemPNILR3V50yCkLrO7HycKJIN8fID3HhKLRQW57N4p/XpxDzeUcvsZ7afDsKKZtirgIYNogmNm0Jbc4vX4SndNyBJ2xJk2SIiy16TFe1vqImqRROb57c0YmOjvXo1pGe1bXUJzEXUpDJee177LPaMrWDlD7u+1A6K+mQLBlvvd3suLi4Y9juDqoPlwLvU0XU9fT+4k5FeEXcyL1w8RWKdT20BWsmrQfHRnRZbCIFaHW3xmveV/2Js/saDMbtt0YKhwy7PTTu0bgnjx1zEO3bRIl4rgYjMCB0r5NnoS62szWS3VygoiBAUSs0IwcTN/H1EjchXq8HRje0dWimkOPeCQJBCsepN6/QZIrEzguUslSkXk9GPkXy643Y8cvPyGbHrOD+/5LDbcRxn0t2J01wYpwkTGnIBNDHnMXYDD9/9Gu9969u8/xt+E9/6F77NxeO3ySQeKzz5+AM0dszpl1Es4okhmnhbni0yUTvAkwiPHpwz9CMhBvaHQNed2aFTK4ehZ5oKWiw3bN2qzSjOc+U0KrlEprvCVO64OAxIKUyzlbx2ooQEh52RdYdOSKEScSKm6lKeu0CjWpccs23ihozga0/ufW/y5G2TB+fqtFJEQ0wa8VMWrQ5TzGwRqAlElRAMBYgdEhOm6VNcj6daZOfVYyrWPVuCQs32GqKoI2A4+TQSKQo3d4UPP3nG168eEXDNH0coiyqnbFynGBPqgULVwlws5Seq5qS7wS/VEQX/5NZd2ITWBDtwSslMOtnh0kjOcr8Cp8HHweH2qqtxVFc5zmVFW1r8116jBKVvhN4i7szZoSwpUubCccqMuTBVQ6IqkUmFGWGm45SFSqTve2IU+j7Re1DUpdjo9iQvYw3B+5OokItpn9zcTUxTpcyVQzdwN85MRzvs1IyMO/fJekLVvNhFWz32WYX1QJFgXItxmlAiVQrf+/6vcUznxH5HUeXu7siLZ0/I88T+/IKzszMrYSa45hOL6rbWwt3xjpuba0QC5+fnDEOPYOJnIViqpEsmHKdezVZqXtKm4PpGwZ1AP/yNBFrcWbS0OBoctbKfs6t7qyolz1amHpNzS4KV3Usha2aaMoil6MGdTyzI7fuOro9LtV5L4Yq0YLSj63uqmlrs5GXMubbeQZ7SDZEUArWcGMcTZZpAGzdyi0b5WpeGiaznELDsg+1s2u+FLVryaprMl5X7IQ3/uM/3aHvGft54tQtCsn3r9kCWcd7+bUWD/H7M7V3fYPMSwOJc1X9eUjx2GTQbY+Ly4pJ333ufy8tLU0sNJmDddb1t5Ni+mnOi914HwuJcFIV5ngmnyaoO1MsUHbavpVDc0EsQ1yVhIcB6+OKv3eA2LzBzT1UQNI/M1x+TTh9zCHeEVv1R7UWs0qdRpMzI16xrNKcshrYJwYXQHBF/d23G32Bm609SljSD+tKKIkjyjsrFUamilGB3HqRFDYWI8yekmsNRbdvMZeb5OBK7gdgNPLg65zRl7o6RMXfcjZmQXf6+KlePH/O/+1d+H7/5d/9ezh+/z6kow+HA7WmmH/Z869Hb/JrA4eptbm+eovmWWjM6Z2qeSDEu7QyEysWh43xvhNb9LrnwVwANdFFAA7enI43sXIoyHmfu7iamap8vCNwcZ25vT+w7IdSJROWsN8LdYd+x64To1T0iglRPB9VqKFyLYpvDSl1y1BXWnzebvnGe2q9EZCnfXca+Vjc+Fo23SD6ESM7ra4XYUVQZp0KNM/vzwSMXXUyiLV9vhhewhmhULwhxEqYfRNEl8GOfkBitdw89RSOp7xEC4zi5M+8Oge8nrSAuirXYNN9HxXV6xMnZ1gVZrVy8VkJdmyOqCtOcrct2SKDWUiLG6MJZPq7aNHDux4Bbbs9yjHu0jhi3h1rJdbLXc3KuiCFIk/NNclHGgiEnCrMaGXYiMlZhroHY9wxDb6Ru136xFKsYquJOl/ihGNSqT4zDErk7jXz66ROm44hOhc4lAqrY1zQX06jJisqEBKHrDdFNMVpa1w+E1Loc18Z7iEhIZFWuXz5nf3dDL8kacRalSkIjFA1M2YX5gqLFPn/0tgSqanv7NJk+UD8sY16iV9GlSCmz309tiw5DHLyPVMAcY1gQlJiM20S19MiUTZ8nV58vvNqqFoS6VOMEAXKG1u4jBdh1TJONg+nGVGudosr+sCfEtIjWrXtw7a0Wk6HoOVfmPJNroWigydC3ADnFgFCZx5FpGq29h6NFLbW7/rxBS1m5k69erZqU7V83/eBedVKWMvGFUL9FW9bHNjSjnZ8rL2h19t/EA2pI3ZrQba8DW0T4/nu+/qm+6PWld1DUJyTFjrPDOY8ePOLqwQMnkYqpDoboxtmdAlb/YfXw6uKhSkNlzFdZITnfXA1exjdKjDi5LjZfl1YCKHVFeqBSA6aXgBLqzPTyI8qnv8oDvaPXDKVaCaRrMUSMy5L8K4PnnNecpiw9eWRxRBbvVj2aL06WzbPBsWLw5ZxnO5iW1wR1Ia+YIoj1G8nO/Kc6XJ0suTEVhVAW2HOaM3PJHE8jKoHd/px+t+ew64lzBCIpVe5OMFXYXTxkd/mQIonucMEw7Li9vWF/2NPvzui6xNnVIx68+1VuP/k++XSNzDPRvFKI0cXViqvYVmIKREn0Drcqk3VZng2CrAhTqVQC0wTPXpx48vQaJJC66N2DC6UTpBcudoF9HxgSxupP0MVqsLGAcT1YDFVo3AcnmiJt5bHAoc3ArAiK56NhRWNYkYQQk+WzsZYMSmsloCjRyMvFyiZjDBRkSaGp34OVc4dFHyRKNDWdOtN1QJ6RINRcqFWcvW8ORxTrvFxK5W6eIVTuJuE2R846pROLrFUtuC9ljeir669ECWTnUCimvyKbUvRSrM2ERblrpUytpopLgKBxMdghbHWPVoMam9O6pDeWGNFRrODV3SZkmNVVY91xqNVaBQSfL+MK6ZJ+KQXGqqgGcqmMBUaNnDRynK0aZNf1dCkxdLKgrm2uW6ReqlV5KS4sVqEg3B5PvHj5kvF4JGjmkAJVoKbo6qjGNxlrZa5WKp7NvKBdh4ayVIwphuh5RolWsZhbtVIemU9H6M9AOkLoODu78MM9OUKlnI4n5nlGVdnv90hvc9j1HWfn545gD65ds9qShlE1R96uFt3rgoBpa8DYRICKfU6/baa5Lr10rOIs0/p4WarLU/kUSztVJXTJOmWnSIqWruqTyS+cOJFLJueJrjNOTc4ZYiJJXbRwwJtZhgjBKh+nYvdVtB0gJtAXBOZp5Ob6mtPtHdRMI5tDQ1HsrGlnulVhreqrzVbcz5LU9jabcdugFM2uyCphIKvWhZ8Hr1fOLCmd1gOovRjrXK3k5Vf+/cbXYj0rP+MSWZumfpHry+2gbODxKIG+Myg1xWSVDA6hCeKk+3WWzXav+TAFF/ZqfIEVemuPr6W6NLWuvIDWy6PBkjR4uBrc796QBjWVR3+3iKLjNeXZP+Fy/pi9ji5SYA5ACDiCYVwC0zjIlttVJQWHKms24TZX32xr+37pl8tskzb5QkArXQzUAKFYJ2QthaCWulERkveXqHWzeVx1Mfu9WTmrl0+KUbAES1fc3d1yGkdi1yEhcegiXdcTd5fsH7/PN3/8d/Poq7+Bx++9z8WDS2romWarPulS4LDf8/Vv/RjPP/mA7/3qr5DHoxmMMjJNd8y5ErTSJyt3DRIJqHUlzpXQRVCzKLlkppK5mzJ3U+H53cTdWHn6/Iiqia6F08ghwUVvXVMv93tzUDpI0fprxGi5Y1mac5l8eYzR8+gubsZa9tvW2fYglUaco3q/GRN/Ks6fr3U1FJbqMBi5OJejVEtBKp6iw6ulAohGRBKxC6S+88O6ohKJfe8G1Q6R1hwxpUidKn3XkVUYTyMlF1KyVKaqGmk6CP+/9t40VrLrKht+1h7Oqbr39u3bc7fjtO1MOJPzJjExJiBevbEIIR+TEIqiICWEQQmOSKQIJYAg/AFHQkIChIyYEvQFYQEiIUAGTAZDeBOHGJvEGRw7dmzHdrvtbnffqeqcPazvx1p7n6rudjDw2e6hVnTjvlXnVp19zj57r/WsZz2LrMV9Dz2GQ2sN2v0Nll3GyBM4lpYFitKwgW8cCAkxxKoVMpdjZ1U/DUkVZSNM6wV1sMrtCaIZ0jTSHK8PUdQ+jYxdypMF7QEkmk55qNQqglqyuGdJa+UiKi+IqSmCjQwttZeNXtAHKZGPkdHFjEQWGUCIjMAA2wbeL6OjqA+8zEnvh2qjlBKYCNYORNJUnCNtlplYKm84Bowdg8YG0cn3MkctoSUEGPSZ0GeHacwISdPRmQDvkFVJmmERQ4QjgrdWKo5ygnUe4IwYO1iOsGSQjTbMJCcOtxFEIKaIra1NTCcTNE2DpfFI1iQAgEGzslSrZVi5b8I7EuTFKteuBnY8IGnlHpXA3zqrc1+ahEYt+4+snDuUzRggk1UOQLqDW8U0jDWCsqYIJglOrXEwNLQukHk001yPRZ8nR5Fs8F6eGQtGVvVZkPQtSiznVip+nRHiNWLC5skNnHzsJLrJlpCNweDqmJRUzoCmVwdlblvTtWJmj6vvQdeSsrfV97nKGci15AKnDHsY5itaBw9m2OfqbjjjEcmzejqRf2Bn6V+qsnn9dA08Zg+bTcM+ETu3HRS9RLZErbqJpyhlZGRJo35BHXLKCpEXQmzhlJQNNwFsdAEhaTpWfphR9CEAyCKmzkfkDKSA5IDkZgBkKhGrLHyZCaUxHHJAd/IImunDWMMmTI4KhQPGMIwzMDnBZD1eQ1NTt3+JxBycTElWZ8E6RCLEEAEWImzm4llnrXixSrTs0TSN5odJGrWxPDyWrJAWIYJacELky5BUQCqJBmuRtW9O6SDtjKZKtJlW30/RTycgchgvLWO8sox9B5+FF373NTj4nBdh5979cE0L5y3IOTTjJfRdj3Y0AoNh2hEOXPY87H3wQRxlgKYnwP0GgEcx3TyJxhI8ie6LRGsiXKWUVUlzaAQ8DRlHj53EY9sRj20kbEcgs4F3Bo3JaBhoWmD3Do8DayPsGBmMvIE3Ot+IpFkYKcE+Fw4E1cXOasXWMEPnHcZh+ipip++nqORNaVqkzg0plJ1VO0ahVdLeM7KfVqSlpP1yTLBeCJ9lYRLtHouYAOflvoVEUiqZSJE9jWghJcc1JaGNHq2F8mEM1ruE+x/dwtIIeMaqgzVZrwnDWYK3XhzVmGfSo1Q3pazCcyU6ExqLpLhiTEjegrJUnhXUsx6j3BgBW2TDYxaCembV14GijTAalCvPJM+A37o5UBaEqThYxalhTeNIOwYSpCoLjwokejsBBsaNYH0Ln6XU3DcOzlvZLFNSdVnR7YiZta6QpReUAbIxCL2kQogjECfYvWTAI4sYVBmWSxkyo88JXQS6RJh6g0kPTCMjxIA+JWQv3ZJFINAAlhD7AORSDh/EDbYR3gBt4zEN0tgu5YRMBk3j4QxU5MwiWYvWW+lhQ5K2LhU6zqr6LhKgPCch0nIN+JgBylSF8EqLEkDum8wJIXSnFJEgxOasCYUihmYIUsXnTK0Uk1JtkfI3XjoMpxSRUoRX/ZoQQkWyrLMYmZE4L0ULhVnaWoQOZMRJ0eoHWFNoAUaCCEWsjKaQLRG6yTY2Tq5ja3Nb9qDiHBdeRt06tB9PXQ90nzp9e6tOSkUKGRWdGhAZvYYzfzhfNkynOSsVLS+fi+Ezy3dx0XUBqejbf3aOsk6c9lpBcIH6/D9RO6cdFEKGs4R25OGJwBywPVkH2QxyKqwGIQ8WouFsXb61Fka7GRuyKrEtG1wRAoohIIY4pFUweIblczJlpAiEPg7VQQI3SBbCSFTCxkoHYY6I3RbSyYewljfgMRFUxohzZGyBy6gq9ZXvlEVOS9NUORZ5Jl2Q1IvVDcmQQUauD0uRwC8PB6E07BsIvV4F6UxxvmAk1WQ0uteJGghgEv0QQ4C3MrljZrQQfgQYcKpqyJQwnWyCY4Zd2QNOAavLS1gajxEZMMyIfYeUMpaWd+jmapCNgxvvxOHnXYGmabF55H7kzUdR8r0xTMBcFsTCtpNrNe0DtrZ7qbLICZM+Y3MSwGhhbUbYmKIdAa0BWsPY2RpctKvBwV0eyw0wbrJWUImasC2LM0G+qzYMk+tpjRVZfpSNfiiVnHVQShlmET/iUgJT5/Zs8CTlvgV9M0TI0DYBZIULkTXNxtr9mSDpL2PReF+rX6Q816BPFpkNpjHhkeOb2NoOmATZKAikRGKZc0Yjs0zSZoFjQsoJ02hw14PryDlgx3P3whuDkffSr0QX/hgCpjEggEEkcylq2igG5bikJMqyRVdIr0TMAMdUvcGcIZu7BgtSWi5N3Izeb9J0hlxPFbCzcv8SS7nxIMWmVWy6WOccwNrgUYT7ROwOJJVvSVNqMROmUUqvIzwieViywlUzBO9FAIzBdTMuawu02qdUDjZNI6XdOQmvpA8wscfeHR47XSupQbKYTHuklBGCIC19zNjuMrZDxlbP2LSMSSRMesZmyJiEHkEgCSnfzhJQFJ4FmCsqFvspWhIEeXvrJPqYMF5ZhSFxML0zWN2xjPG4wXg0wqhtAR6CEcGgMgBtXeCstlqgwoycS9dlRY0Ao6X5rPI60gpA+H8JrKTr2YoUq0gfUYbJIlcf+07S4W0DOC+VnWZIdxuyiCFhOp1Cevg0lZtWeF7WFg4KFAWKAGRfYCNri3Xi8NdmlUY4RY2z4BSwtbmByWRL/1YR/IK4l40aUo0k7S9K2bSpD30lrs6mcOaqfnTdUSTwNJeBiwZJ0UrR1zCPWg6Zg1JNWOQ1VC25OFAl1XPq99RVSt6trhZzPfXZcuQSwM3qhT0RO7cdFMNoWgdwq43ZAibTdRiXMVpZksUla7UCq+hSLihKAdgUytTyqAFhsfVipiR/W9JFhaBKWjZHWg1UopPq2ZosMCSkeRuMqI76PAVtn8BqWMdKk+GSTIjEuVZiAgA5D4pCyGULGAh0KZNLO8bamV4jOo+lgGloMAceHDM5dugYW8rSQFAynTxMKSVYZ+GNbAql7EwIp5LaSlmbxxkCFbyTJKqIkHOxAIxGtgkG0xCQ+y08et8duOlD/y+OP/wgrrj6f2PtokvBZhUAY+RbyANmheZDVh527zHasUv0EVZWsLF1HDt2dsjTExjZjEauGlIG+hgRk4h+9V2PLkwRmWHbJfhxi7AtnJI9OxyMSRj5Hmsjg72rLfatOuxoDbxJsDN5Xd2py62uNyprZThRqZpQLZoaSgwo55yTglIiKwdVThENEVBdMEjSlE7z4FKuysgxg7SQq6B8rBGUMQ6yCUDTFsDG1hQdAk5MM9Y3t0Fk8PBjW4gsUWWRjJdqBEWEdDHrspBorRI/Eyw2A+GhEz0efHQLS4d2gAyw1LYwWgJtjHQS5KxE3pSRkkgCiMMkG51VPRPnLPq+R47SP0pKjKGLusx6IdJqOtGJjokWq0l0NlOdAy1TlbJQId7K+k3lomkKJlfdDWslPRSiPL9MJCkU1elIBAQGcjZgOwLbBokc+hDBnLC0vCSbnREEMSSuKCZBzrE4qDH38I1Ug3TTDmE6RYOMA6tLMMsOOQWplOMWOUPK4rM4KJMuYnMScWI74uQk4+Q0Y2OSJT0cDbb6jL4PyJbhGi8OHydRi2aGEMUzQt/DGAvnM5q2AZtQJRWQRVfKNxZNO0gr5MgAi65OSRWWdXAIAlkdy6ywPlU17iI3ELTnUWZJ00UW8TMpHBPhOdLUSpGQd0Z4DJyFK9dYQghJghsHWOP1Ptr6k1JpDSIcFWO9pPFiRAgBo9Golh+TzkOjTo4oQ5NWcaqDgqQxAIEoo+sm2N5aR+ynOvNmKvfKTkMD18Oow19IrUzDWlF3Gn1tINgWTpupa88pOIn+l2uoUyt+II5LcZXAs39L9fwKHaIiH+VYwsynyghmv7k6P6wjmEkRCUKs+y/jAnJQckTjDSx5WJKNsmkt9uzbhb0HDqAdtUrYk/x3CAEhiNhWjIKMdH2n6pWh9uVImeecGREN0t0/z9wMY/SmmsHb1Bw2GQKbBHCEYYKBl42WI1qeYBROYm+7jYaEFJvjRAhmppTZMUBWuxfLeLk4V7o5loU1hyD/1ofeOgvKLH2DCPDeIehGUMl6BdLUfGCOsVYEGZKHh1NGCgHQKBwQgpol6bCcNcchG2fpfSSoiTXiGGUG2lEjIlYxymYXe9B0gvDwBv79H4/jvrvvwOWv+D94zouvxK59h+DtCKluuEqAVa2bpm2RlnagDwFuvIo83UDTLsHyFEgR1jqElNEnqRSKsRcOhWswjRFb/QQxJfRBJOhXx4ylBti5bLBreYTVcYNlT2g1zScdaQFruSqfAnrd1fFLKcFY0YCAdspl5ZHM5pOllmfGSdEFYbabbp3bJfKq91lSR0kbfGXV0ymkWAcR/xKuBcFYKynNGAGvG5KSDO+99wF882iHLgH79+7Ays5VbD62jRQTWHlODDusrhBRQcPSZsGRIEUhGkQmHN/q8c2H1rFv5xijthWHWueQc7JZwBJiDMJTMrZGebLYSj17zBmUVD9GeSk5MULOgJVSX9nspETUOK24S9KmwNqi2QMNLkonY+FICX8DNYhgYGYDkxuUYkIKvVTsJPHqMhP6LGmjxIzIVsqybQNqxjDkMY2M6VQ0RJY1NRlT1KgRMOQQUkDWDt8pidZMDAmm60EMdJMJuJ+ipYzlkYVNBsQO5K1yHgh9UNIxrKIoCTu2I1anGSvbEcdOTGC3ElikTJAZ6LNWelkCcoZo2wgKG6P07gExfOOxtrZTyLu+lTg9RamwYZaqIwJKyTmMhXW2pjtJU7uzHAPh6ZGsZSS90JK2jAgpISf9G5U+kHRa2dJzRbicPl+cEkLfgbJ0aW68XJ9gDUKQiktjSCt61DnNgLcOo1Er8gtKEk8pYTKZVPXitm3hvUOjTojMIU0J6nPY+AZtw0i5q3L5KXbY2jyp6ElCqRCUeVgCD6AQVU/P9OpaU/CUkk4GaWsWJb3CVvS6VC6eakVMreCtKJVbuvaAC39HPl+2NaMBDA2O+yz6YcRJKjyisgbW80fJ/mgQd4pJao5rNiDj9GMez85pB0UmCWCdEFOdc1jduYZnHr4EBw4dwmg0mlmsxItPqvqYUqwiXjEGxNij72WC930vTaJCQNd19Sd0HWIf0PcCtyoHClBFztmNJ+ttsNWDFSCUcgbzFDvNNkaYAjlKFRBJOkgDK1kkYo/GSNSRNFdtjUEOkkpiFS0aqgIKxF0mp5ItOUsFRYqVsGeIVfQImvNNKDuw0l1kgS6ic6SEtVzIWFAyKlSTgpD090JUJCvsd4lqWXrpkEWyHollQ0qT43j4q5/DI/fdha999hO44qrvwzNf9n3wO3bBNCPYppVUW2KQcbBO9Gxi08DtOoBJN8UIK+DJY0hpgj5mYGkFO3aNceLYgzBbx+BMRsgGRA266QQpJow9Y2wJqyPC3p0jrLQGo0Yksa2RKBmQdJm3UqJsSEXZctJ9WzbSIpxXJ4TukrNLSPm3wQziVqHvgaiHMqXONOENS8pDHUFnStSV0TQeSZulBU2QWxKHOkRNCYEwbi0uuWgPVpam2O4i9uzbh/uObeDBHGV+GiMdmhERs4ElCQQYEr1OY0RiIQyzEj+2InDvsR77H93Gnp0jJA7iODVeBPpYUlR9ZPR9lOaSGJy1mlIigI3wb8i6WonkDemGn2TzMNLEzVjhg5S0V0kdSTBooLkdcFKkSzk6RhVEy7Xu9Lm3ivBIKXECk6QYI0sFScxCco9w6GkE60aImcAkjTJzzhiNRlqNJGrHopHhdaNyYI61WaJ8NoA+ASEi9VOMTYJHjwYE64RoywDIOjATupJSBGHkDDwxWuexMmbsXPJYbYHmxAQ4KahNpIwQPWJKcMyqhJsRoWRL4+C9RYOIbBpgNBa8SdHXSNI+IcUA641yMUi7kBslwOqMZYDYiMZNSkP1kkx64WsxaqlwyqbyESSyVudaVbwNTNVHQQpgFuJrilEQc9OIs0EZo9bDO0GTLVkhk6eEvpe0jvcOTeOQ2Wp632m7AIO+i5i4qWiieA9m7WyeGdaqU0bi9Dhv0LZy/kaD4kk3wfbWJlKOtREewVQ04VScQ9pbaMJG6/0JgCmcHCr0AfUVMNM7bvbTirMCodyWtKZ8hK43pFw81h5SeXCS5HOhTmCpviq+ySnnzMN6xlTQYToFySkzIVf/ZtBKKQnqjMdZ3c5o57SDghw0JygPm3cW46URlleWsbK8jKYdoQpSAKjQG/NMyifpT1SeSknpJJ3gAX3oxUmZTjDZ2sbGxga2NrcwnXZIIerxsz9JvW7AaJmZOKnSddaECE89GptE9dASsq1dRgQlsVZ0SQBNuzCIpFFb8cpL7rREA0W0a05VEAMJU9I5sqlwHgTEgFO8/BL1k3Sz5fL3WRvR6TR0VvLjIUHlwQVlcJCcN4EQYpAzUBKv6FRYwEgE6TgDYYJw4gge3FzH+rGj2Pf1r+HwC1+Gy170cuy66DJJVRjRaSDr0YyWsDQaYXzxYaTpFQjrj2DzkW/hsUePYHm8jLW1NWwcO4Ljj9yvKqqMaddja9LDpIy1kcPIW+wcN1gdWyyPCA5ZdBcgN4E1beas0cZfWiEw07Cv8Hw4smp4ROFR6PVEhpI+S0oRFS3BzD2ZtVJ1UuuW68wVPQSjmjTWyiLpiIRYbXWzYakwKLgNMyPHDoD0kGnaEfbsXMLuXaswtgHZBo9tbcEiIZKUIFto5UzOoMYhS44GYBW/ypBWCCSVUQSD41PgziOb2LM2xiW7HJa1BUBIEYnFUU4gBNUPKbLoTlVUc2Jkbb0gC6KkAQyXZ4AQ+ggmJzwZS4hMIuvO0hhPMwd6D3lWPFPAT+UJ5ZhmKmtiXQtCEkcsg5B1kyypocCidxISo8uMSBnLIw9otU/OWYXpbK20yykrUiMpMVggJnkG5LQZzjipFOm30ZiEldbAZAJxFEKqs0Lu1I2lsVBnKQuCBAuiJCXYlmDtGK6x8C6AcweMR9i/51l4dGMDxx49AuSE1kn57SRE2NZjZecueOeQFTmQ6Dshk1TFpZhAVlIrzkkQI46J1cAoopSPZt0kjR1aikhhgRX9EOXx9DHPI8K61xkNuIwhTWlLT5sYA1qvImxeZfk5glWFtQRppI6ENE1NMykdVXllU9cyay2Wl1cg5O/h3qWY0Pc92laUxzMBlCDcEhaBvbbxgvCkHpPtbXTdtJLly8Qr624xWWOLU1HSN+W3wbEo7RtAQ5hTgx0aloW6erOWBFDZ4YAZD2FweJgF9a7rzJCGlq8r/MnZz591sIobQigh98xpyX0sRMaZMdcjVF/pgnFQrCXdJJVJ7g3axqNxVqWVqeBlFXIb8mPFBs0JqNx1KXub02FQjYbQ95hOp/LTTRH6ki7qa8poOtnGdDqRnHSOCmuJ42E5w04S2p5hVaYeRoSCOCVY7wa4jCDCV5Dma6zwsKnwoy6MDHEeNGqQBoeDs4KcNWebYZyrr0vZn+Z462ZZ4AAxQ5rz139XT9kYcbrICHQtIYHAwFkEtmLOYOdQdD1koRIinQXQkLyHLBBmDBNsPngP1h/5Fo7f9zXE9WP4X//n/4FZ2VeRqJikd00zXsaevXtw0cUHYXKHzccewfpjx0E54cSDd+Ebt38WeXISliN6vYetZexaarA8arHUOowbB19LhuWSD9AmS+djhViLc2JIxfM0EgIGAbLYJxGC0oV26HGhplHR7PWXz5lZNCBRT676CTIXbZnHSt4uaqxsCI41rw9Jw0h1i8DvIaoDzRGUeiAaOUdD8D7B2IR9a2MseQOwBWcVQIvyHIQsVSOUVfFTUz+hLxVEypfJwL1HOqTuIaTL9+JZ+8ZgE0AmIqoAGZMD+xGm005heItMRkjoWpqKJNGiNYSYIkLOGHFJMTps9tJPBWRglJNjCDXlRaqHISRJnXOkC78iKKGXDbXMaUDSDiFKzyprHcBRo/2EkAl9NtgKjK0uIDHB+gzXR1jfwM1wHIyRct7CDSP1NkOQ9gLWO1VAzYqIZ7jcAXkbrScsNyL9jyyprxiLlLignkySt7FEYMrIJsM7wHgPEwFjIoicqOCyQdyI2H94Hy5dvRxf//pdOPrAA+gnE2nfsdTi0CXPxq79h6QxqPdCNjUqy2CEz8XGI1mtelREY0hXEHKSh0c0LkmqBHkWLQEAGUtSDZGcuK4LrOuz9D6T3mNS9hvQ9x1C6EAARo2VNhRWtHpiDAihk35G3ivxVRtPcIZ3Ftk74TSlBLbyuV3Xw5iAphnBe4+VlRVJcXk/t67GmISHZB3IlOeV0TQWzBZhGrG1uYGtzXWkGOvGfWYctJBX9Qjdjma3IppZC4bXBken8DpOOQSlvLc4KJj53FJ4o3Fp1faRH6oIDan4Y6kSmj3vYqqEVcdA1RGbHffMadG8g4Z6n08dwOPbOe2g7FhdQeMVAgXgnMdoLHlEKTs+xVdjfYDUo6wbBHRPJgJqZ5Xhj8o1zqw6BTFoCVsW5CVFKbHNSdJGXYeu6zENAUiiaiGVixmIHY7d/VXQQ0cFvuSMPvSV4FqaGAJa7giRZTdWSiCNwtcpShlx5jzU98+Qj0oemEskB22uVxyTnAVqJu1fUieSTNKYpepFnJ6oTQ2t9oBBXexzFt2Uxkk1icRKsmlVrQSrr2g1T1akQqo8hK+SWTRdYuqQO8L6vV/BrdsbOHn0Aey57AVYOfBMUDKAahvErJ/HwMquvWhXdmLX/m189fM34ZabPobpsW/B5g5lJWi8xWhE2DFyWPGE1gOWgjiBtQqqBD8kJYvWiCgdc03jDP7/gMIVLgkgsLixJVc7qKrOOiH178BgNrVC7FSTxQQ1wpEqFXG8cxSntRCVOQu50xlImspqWwWSXiewUgoKTuAgKbccCcvjJRzasxvLzYOYToGu6H30STZdskis5e1aaptTUodOrgsYGDnZvLYmGd/81kns37GEtnHgIM+BIQDJYnsqUW9rPTJEiTR0nVybhhBY+CXeWXleOFZpd2Mc+j6iD1tC6rSEsQdGbVMXXlJn11oaYHRChciJNY2gyGDOWmGTWMaa5Fplskgxo8+MPhlsRcKJScJWL2vIyALUBfgsKWbZQFgl3rWIOGX0Sui1TqrpEmjgNOQM9D0cpmgpwBsLisJbkyeI0HhXuTCAOFTeqmYRADhJwRASGktAQ2B2SMsWEyZsWQbFY/BmGS++4oXYfs7lmHYBiRjtaIzx8goCG2SVdTdIsIB8Rs4wiRRJgaIcw7qSMmCNqHPnrCkEAEzSUyhG4QbFmKsOjVSWy9hkbpuqIQTIHA9B0jgpCi/QEKNpXJXEt8bAesAYqbIs/XwKkpxihHemIh0ivyDpy4J2hxAABpxv6nmnJGgckeixpMTo+gDvDTjJ4iDvGeRI2O62cfKx49je3hL5doEuhhViZk1F3aV0TZhxJIrzbMpFLn9VkexhzyIMacwB/Z4hJ9fvG/5TU8f636xl/qWsu4xrDrKd+ztIh+s6ivJvSfczcT2Zsi6AFHSdJdbq+ZkzrHWPZ+e0g/K8y79DSHmlhA/A7t170I6XQMYOi/7MjT6TUd1gzvhu9UbFkSH4gkKUTVeRAdl4FK1Q1j/xUL9PYFCcAieOYf3onaA8EUn+skGRtJsHEcgPHVprDrGo0+r3iAx5yReLVgNofkKWVFAlfSXRUyilsYWwKNUkGaAsqSRwFY4TiW6jTcmELCWpIyU0eofMWt9OUqXgrEGnWiykqZKchAhHJU2igk2snAlPDOeli+o0BkwfuR9f/vRR2M9/CrsPPw97L30+/M5DGO3ci2SA7e1txO1tYGkFK6MVrK+fwB1f+L+YHn0Aro8wtgEIGNsEB2ClabDcEEYG0p1ZF0ppaYd5BxakejVA6Z2RAa1YEIezcEckUjZzUtmn9puYvScDcqICTafAwLP/rRwN/bsQgyj8QkihmXOVHbdGy2YNFIrPWgaqkzdF5CRckwxCikBqI1aXdmDsPbrHtrGdHNiI48vE4KA8JhIHXaqahC/iCWiMiKWNnUFjGa0FtjZ7PHBkHUvtGlrnYCkDbNEHYHvS14XOGSFnywlK+oSy6FWMRx5NY5ETowsJTQsYdWoe29jGeDTG0rhRXRTZXEPfoQQU0z7qBijPla+k5yIkJ2qqNR2qgFXkjNAFMAxiNugSMAmE9UnAyUlEhIVz0vTTMYvaaAayqnUAQ3BQeDZynw2QoI04gdx1MKlHaxJa7jByWn1jSo8vuc5JmzSiPC9gSUkowoQsoo9EAFtBNEbOIY4Ya2BsUsKRzYeQRy12H9qFZmU3+uwQIY4sK8qTGVXbhPS66fRHmaLFSZa5ZyXosVopBiE/Rl2LQ8xKzBcuW9K1JmNG7qE4czQETJJKnyLFBO8dxq20DBAAMQtp18ozaJ00Y7SW0LQNLBlMtjuZB+xViBPwGsRCUzlt2yKEIHOcE8g6LaIQLpdzFtY3ivKog1UcXSOoPTtCTj36bgKow15cEMlinIonyDpS9xEaypCLfIXVuTrvmMj8KVmCQpitUhflAzH3j1N9DRRUqtzDwn1LBcnKpY0G1XMfOHFDIF+Xq+qHFc9k5kvLgQZASanpdWEUJP2J2TntoFz27OdiaTwG9GKLR+wxGi8JqQw0563VW1qv6eluyawPUx7K2b8f4udyM0rJnnZxZAY8UNgfheeRFZK3qcfefQex+XVfS64K6dQaEc9K2gDQWCMPl6aYiAxCDHBGVCwNVK8BQnhNEZpiGMiyrF49M0tZp0rel02ypIBqeieT6qbI2EuLAEAJuuVY1o0bQGnC1npbVRNDymi9Qx+jLrLCqYm6QIOFg8KsJXaQTVV6AAp/waQOnANi2MbRr57AsW/eAb92CIe+42XY+8znYNKIPkTsE0zaxL1fuQ0P3fU19NMOI9fA2ARvMjwyvLEYe4vWCqxunSBVMWYlHPMQSdRx88xCQ4o+zS4cGn2zoGPFQUmplBnPziWu90LKJtUJibm+P+eUULlnAq0aGMAYFaMjWK88H+t0k1EVWypOcyFQS6UGaw4rKyci9gEhdZhuTwC/IpscK0GUhOBnAJhaEstwEHzRe4OlxqIBpIEiAI8AQyJ5z5nwwNETWBoZXPaMFSy3BtZ4nOin1YkusJDzDsSuisgxKQeEWY41QoSddAEhCR8kJWBr2sN5uaeF9+CbRgjMxiB1ATFF2FJOiqSIiXDMSJEMcZ9zTTckAAkMshY9OWxOA9a3Omx1CYmsdk+X0uY+BEXe5Bmt8kVa3ZcRkU2BzQ1yTKpTlNFwRoMeO1vAxIy2aaozIilaJb6nIGsYyzPOWbRoQEbSZpm1e7BH6iMsM8atQ0g9Rg3gO+AZBw9i+eJnY5LG0ifImPrME4RAbzWqL9yrmERGoKSmYxRivnWNOEkaABbRshikPUDMGSlmDYBK7y5x4EojTCIDQ7aiiyH06KZThD4gxqi6TFIZOB6PMRo1MJSRQocYejhieC/k1dZLKrMoazvnEEKPlAJSkpRPqdKB9mErzWIBVJG2EAKm0ykAcYS9c4Iyyi3T517WY2utyCjkBGsE7ZPWaZpWJEWYSzAys4mU57KmOtTxqKXaRNqmoDgqXNP6BCjHqgQ48wHNafsVDaXts1YdhjwgXClFrZqbrbGZR9bnf68fdoqDNH9MXcd4SOldMGXGO1bXsLy0pNE49L4pA3yGjDjctNOh9FPz//MQG045FpgB1gBQ3bDkFaM5v6zIhxDOcplMkHK5pR0rgPNIvWh9iPstTQcpl8kr7colOleE18h3QB2b4sBmZjjvayVBgetY3wNKU8A8CNBFUVctbPaCspRqIEAcppLvFsE3QToqXE7aV0G1VjKppkHi2m+IIB1No+oWWN18pJlXyRmXyiNxlrxSKgIzkJP0xogThI0em1ub+MaJR/DIPbfjWS+9GgcO7MbGdAfi+iP44uc+jX7zGIAAtglNA/gcMbYMb4wowBqBpVkjiardkEWWGxkKJQ+ENrmlDGgPFwuqugBc5o6ERfrgzzsnJdqZXawG5O3URWaAT7OWMhd0TcJZiXYplzmrv2Mg3OacYZzcp6KaCjAya8sD44AcQSxaH/00ojWAy4DNqUZ6ToYES6LY6g1hZA3axqK1km4jTiq2yfBG0oUggy4RHjp2Evv3jLBjVwPEBIMoaSYq49fraaQ6RqpguSoTW+vQNo2SM73I7FuPpm2xvrGJ1husLa0gxAhnrUbKEq0778Ck/W6MQR9DddiDkjlZ+76wXkNmCSQyS3O67dBhfRIwmQ6S6ZzFScgkSIlogkgli/NWK+60QicLtdnqcyUdsTMcJziTsNwQbJ7AOnnmrTq4ufZN4RldCdFBIqtoDEvlHLOgGCEKgdPqWJ3NaGEwHi9h5dAhNPv24sFjGbmLYHXQcoy67pgC0ChfSZt5ssx5kHTFFu0aJ2kUdbZjSsI1SRG5aNUUZBQDomdmNi6nZH7hkAT03RTTyQSZE5y1GI8aWGsxblu0jcOokcaB2QB96HR+RO0QLdL4McaKXjZNg5zTTFNYiDMZE7xXhMSW7sXyvjgt2hAwJBAJoVdaKKAsvoqSq8PuPcZtC6tBZdmCNIGFkpYbcJPyvKOe6zwyguFZL84KNJA+BVkd/iufffpeNXRmPtVm1wnHgLMJKcm8K33ZdMUY/p5NXUfmP7IEbSWWOy3kr985W037RO2cdlCM5j8HO1OiZvAhz5TiOdMNfDw706FlgsyfAaEAvKSCaqwRY8oMNgaJCJGkI6dsAsXTzEMdv058ayQqNyS9MpIutKxORVInJiuyEUOUqMrZWlVEqpFSJlQqjPN6DQYlzjIc1t8F6s0iJJek8ijlLCWF0C7IZtAMcVaErThDK0KEO9M0DtM+wsEgBRHPM1ZEjzIrTmC0M606QwKcS0rCcIbpN4B+AxsbR/CVk49gNBrh+S+/GsfvvROP3H8XTNgCeCo6CdnBG6BxBt6QOiem6rVYY2okYawga1qZKjyPNBNtFEeUS3ms3HyiAoFCI6hcr1+dC1RfqDNygNB1sWApjyyktirrXRxths6jAsHL79IPydR0BWetaIGSqUkaHDKLFkRm4S9QjpAeRVKOfGh3g82tKdzJhD5lNN5g3Hp4p9wKEmKzY4A4w1AGUdKSQ4gKstEUgWGtomBsbPfYs8PDcIJvDJZGjZCns/AzvPeS+otRCLUhIoSItrFoGi+doZX8w8zo+ilG45EQaENAHyKILLa2t7G0NKoIlrHCnQmcITPMqggYS/+czLXtA4ygMIlZKo1ixjQmTAMjMMHYVvkJylBTdKykRcszwerkhJQQpp1u8IV8moDUoSXGsgNsCrC5h3AnnETNylkq87MIShKVaiJ5ljNnwLg6R0KICIkRszj1SeeNJXmWNtZPYO+BpC201BNRnRlmuWcFtUsa5JH1MJoSSCTchwxJhfUhayif0Efl2KWkqLIZ0CkuG6Vy6BTZE3G0HpPJthCkUxR9GCK03mM8HquOiaBNVPR+Gq/OgjgfTtf+ruuRUkTjvZQCOyFUiwOgzkeMmPYidV8qkQRp4YqojEYjfeZljKX8vG1HGtQU/lAGkcV4PMZ4eQyCVIGW1AVrwABmsD7ng3PClcQ962yYmWVCH+76XkGz5Xczt48NaO6Z9rh5B2W2anCu0pMKYgwMqPv8sZL6GcLz8vqpm+IsjbacT/Vx9PvTBdMssKImQx5vAEu4Qm7/XTsdXQEKcjI7D9QvwKlttMsZFUKenJLF8uoujFd2oX/4KAIY1pX8vjz3GYVzIix6o7F6DKpVwhIV5pS1MVZSDRSJmDOXdBEhBC0BzBGl51BWUiCZAS0RaFEFyAr0zawN8AT6zTO6K0ZDTmOM5tV5ZnJL86xsDShl5D6IOicn+Mai67M4ImAt7WWQJdFFSCpxpnokpFEtZ4ZJCSPSSR4iwpF78e8f/SAee/Bb2NECefIYHE8FAobDyI7gKYGUKFr0XEi1JCrJFFxLRMs4MPPwDaiG/F+aSdcUGXOJIORxyswq+VzI2BoRqapmTqyVQAUpKZVkPDfXCvIiDqY6KzlD8z66kWmfD7CIRuUsPUQAaDJcqxJYI2WRlqec4aCt5QGgSXjhpau4eJLQR3X0k5CoY4xSQqqN2wqQyIr2iVNlYIx0k5biV4bNhBMntvHI2GHHkqS1xuMW0z6iDyJaJs5BRiblJmiqpmlF2HDa9QAnLevUR56zKppKGpdZOnPL5iHOeFSBN9GESSoAJnyIPkuFyzTIxsiAbD4sKciYB00OSb9mGCeIZik3L1wWmFI1glqWHLOUAufE8F773qSAsYkYOUJLEd5kTWE5GCNOWNYKfyobGxESSXDDuaw9MtcKusbQ54MEESrBhqSDGByBMJ1i/+5diBbo+3UkOIRsYZxUBspDBpWWF9QHSKIOretFyqxoHCEk3czAM2T1Qn0FnHUwEIfNkPxkJoRe0iiTaSdzUkmprAhRaQa5NB6L4xp7pNAjGMC0TeX/kabanIoRppTRdUG+r5BtFSUrrUe8b8AkiG2p1gkhaDnxGG3bom1aQdfYQFZd0rJoWXel4QfVddw7D+9bpKZT8m8pM9b5oDNGfDVZg4pjW9I3JfAZXjvzHjT3ftnr1DkpSMzpNqRX6jp2hh/5SKNrGOvSV9ahgTMnnzH/Xll7qhOi/5t1UOTvqIqdXjBVPKWqQhZMLshYNelVM2+zuf5Trb5eofjyyA3w3OkQ1vDSrBtjykSt6I1AsmSAlZVdWFrdh/Wjd4u4T2IY1SbIOQA5ou8DXNPCkK3Qp36QRD/axAyKshQynpDRBq6I/FsmUiEGAuoQYdCG0L2wvl+uRSmfZObqOInirjgRBTUQP6e42Fyhy6ybYOJCKpbvc6Z477LQG2jenlmiLeOEPJtFqCuGiGxE1TMZB8qAiz36B7+BO04exdruVYxth7YhULIwxiHEDGuV+KXVAhKhMqCEQHHmFKWoqa3SPmB+zhRnrsLVpEhHFv2ODNZmixi4FDkDqtoIRS+0MbQ4jHYQo5q9bwUzZc6iyaHpCEDmUJnvXqXgG++rY5VUTRPqvBoSMb0UA0C2brJgaW+QOKPlhMYBrVWHKWekPiJlg94RcrYImVRgS6vSWFGanJVTkEX6O2dYdfC2tjscObYB63fBk0XKyi9wDpQNQkzoQ4D3XjYySmicgfUNEifEPujnWozaFpaLE50wahuNYLM0rQSjD6luun1iqVhh2ShSKiROAOSQjUMszemyVKUkMrXqDZyro1meYWlUKM8OlZy9YRhHAElrhqyl3YZV1RkMcMDIAjtagxGAOA2wTYOsGwNxrlonZQMqz6GAHhpJF6VpJTUWxENdCXkEFXEwqnC9trYLjz12DNtb0uwxhAzDI6laIkFTCwqbFNXLSQm0nNHFLOmqzAAcYoKmC5VPVSJ4RfWEpyOrZ1IF766bYjKZYNpNhUTvpF+RtUbL14UPMh6NMB6NpATdMgJlxBhEX8m2whkxsgZFvSfikAsJt6TIQpAKoLZttdeaUfl+p0FXqjyUGCOc9XBetkNpCSBBlNPnKsQI70tKiGpAJ4iNGwim0O2DBz2RXDd4rmvjsCcwDKsXdwYUZEA5ZhyUqieFqhnznzkoj/9T2Iyyss07M5J2r2gLeE4Mbva/Q1qo1PhU12U4zhY05QJxUJS1IAmU4qlBofCCg5+qeHUmk71DMI9cQkTJkYuksECcAyCP0z6z3OJTsZahfge1gZVxFn7XfkzcCkZhCy1nZOe0MR9LxM2kLeVl2vcqylWUG0slDidGSFll1uXYsrmKQ2SQslQ0xBTrWZF0dKvOi/gWg3PCLN11JT2g6QYIWsIEcE7QtUk2aJhhIutFMDqpBQGw4CQdkzllSc25Eu2EWkXgDKpKrzD0DXKKulkDZIzovkAWU4MeefMxnJycQL/UYGW5wbhtAI6AYcDZeo5sSKBkKxFSSKwbUXkAdf6wbFiGhms557AoH4eTwu01ihHIhxhgQyArSAZphCNOoaRKJDrLSkSUxUa0QiwYufb8yFkJfgU5Iy/piBjFCTY6vjSgHN46gEtELgiFLMpRojgniqYScjJscQ4zwzcDJyg5IzoWWc4tZ0IfI/ppVyuY5JycPGe6YJKVSLz8b9olHD2+jVFj4WyGKO4mqezqIigzvCp2Zsg5hRRFr4QTGkfo+4S2BdrWow+9zv+MPkrk3GsVmwigFWeSsN3l6lAnVZdlkqq0UoKdmBGzOvckqrfMMl9qsEjCUbKmzG1dd1DSRhlsVEGXAMvSksDGBIseSzZhxRBs7GG9hR23GgeJEwlI08M+Zk2XoEqy5ywS/CEGwBaNEaluAomeTEGWjFb0ETmEBGzFhLC+ha995pPYfdHF2H3wMOJkCmN2Y7s3iCB0BTBUXhqDETmBk/T36lgpWLDSyYEccg7S1dhog06UyhBUjZIYAyaTicrJB6Qoz96oaeGcg2+Kdol0IXYkpcHS0T1r7x8S5Vh1BrwXDkwXewARTdNg1Di0vpBexRENxAg5gAPDQ2TynbEiiqdE0Ma3QCb0IYlTkghdZHRdhHUiq2AtaUVeqQLTVYIA3zSSbgzbmrIuyBJVHIGoCFcU52VAFghAVZUouV06pbpH9zWjH1b4SYYkrW4V0S7E7LpGVZR3QE6G8mJ5NgqfpjrBPHyE/E51jjKxqMmeImVftFSYy947gAJz6SUaXstnkMN/PDunHZTB5p2FygkAABi96Kd7p+X3WUiqIidUon2DM9ksEjP7idVP5uI4zQBhzBKVWYtDhy/FQ1/fif74o0iG0UeGNRmOdEJAuCScc1W9JBIJdqOwbyG+SrEDa/QkqEksKpbag0cgSFJuxZBWKLyTAtEOzQclsrI6cQfSsXrLBeorJN5ybXVSSnPFXFucM6ApAiHyee90gxFI3oAU5mYAAuGXTb1PA5wpAI1EtrBCWCUld22u9+imFqsrLXYsjcSlZItJ12PcGFiF0HN5mMpGxHJNyzWRkHb4nRRuBw+EU4liBJf33ivc67XBnTiGxtk5mHm41rKBxpjQJUlDpCQ9jXISFEDK02PlFTkn5bzOWJAlMIKmmjRuIwI5BhABUzrAmkp0JLIQvoNUgJE1SCEKgTkKTB6zamBkvd8k7RfYCOm5DxEjT9oO2Ojn6+SeceAyk4h7ZSCzwfrJiIeOnUTjHfbsbLBn1xjGiIih8UISjzp+cSJVKVfLH513iFnUR41ljdoNJtMA57wgdFFVQ6M8L2DhRUi4L+kO6zzIeEnLsCBoITGccpwEuVBBQy1j4jws2oaKtox0HLdGNj1vrTolEZQSnAG8sWgbA4cEkwJWLKGFpNaEc2I1dSKlroVzkmLJ85RHiQFWci5J8ixx1pYBFtZ57ZSc9fzlOQosQ9+YdtgRMw5ffAijnR4XP6PFqNnC8rLHN+7rsb0uzlnMXPo7IBRxSWaYbBByAhlJx5Jx0qnYCZJkjMzZlAJCH9H3ETlLuXDfT6WcVx3kdtSibdt6v2IMMLZF4xs0rZOUSE5IsUfrGh2fkfROLX6QDTlEhxgDCFQRjNKQ0DqPZjRGwrC+WXXkhYdiqyCca7zweaDpcUh7hRwinJO4gKw4R0bT6iEEaVxoLZpWnC1OYdjkURyQ0zfiOXQEwv2ou0g53Jq5YwmFozI0Di3vWzMUhfDMZ89zTzC/zvOw3oPEoS3pxTrn5s+yBhxnslN5L2fGcmZ8MHPmPfVMds47KI+XrjnlqMd9p1Zg6L8HJotEWwA0uh8u/SzB6PHOYcbl0TPgYRM3Fjv37MeOPQex8dj9CCBwzCIeZnQysiAizAU2E7JpzAIFD9AZ1dLinAYEJqUsZDACwEblqCUaiyoB7b0XFCoVDgUX/0wVOeehRgCwCpuUBUweGiMQe8pIpc8Iq84Kiex1jEnIvyibp0YyaXZBli933lbkQJwHg6QRpjFOWrFzgle5/KJ+SCyEuRMxwMIgOYfN9Qm8y+DcgBuL1qvQWREcA5TrIwQ+ZhZyoZHIVpwY1ItC6pwAgGsslhrJX7tSwmhU1M0UoTVxYMRpjFoNRdoPymIaEiZ9RGYLkEXXJawnkRnPUTbllDPQBxAkJVOg4TJfhV+ZVT2YwFFSC9L0UZziwk0Cc00LWOcBlRPPDHFeCgpijBK3k8wrRQZgUKFuIicpExjkKItcykAmhy4A25OI7S5gczsiRIZ3ESfXe8TksGfvGMQTWFLnaDpFSiI2x8xompLPN6I94h36TAjbU9kgfYsUIja2pfwVOSPFUHsnEYuz1TYGzo0QMhBZOkGTLWkcD6QOHBkNCNkoMqawtxSwiJdC6rwbK89jhmwW3jm0XvoXWUR4J3o+jc0YeweLDGOBxmZxYMygR5RyKb2F9uYZrn3ll2jVkKwhwtFiQLlGDYwRnk7KwwYAS5h2AYE9nB+DjMeJEyexe5TwzXu+hH37duOig4SHvvUYlskBmdAlQkoWbCQlFUnJ7YbgyNXImKw4Z9KzKGLaBUwnASF26LsOIfSABiY5i6q1cw5NI85J0zQAGB13iDEAEKRkaTyGJSDFrmqzkFHxQV1byjpkjMF4PEbfG3jn0Pim9k/LYEVnGi3XhToXoiAcYg/mBGMlNSPtGxKQSTg4hkDOIEx7xJzQeKdk7aH7e9/3sNZgZLxosdgG0fRA4Vjo3RqWzzNzIQsloZRel0CvquLV95R6PPxBfa84KLVx7RlQlLJf1eayWrWZWZFVKt7JbGqnIOnDflYCodmhzG9988Idc9WLGPZKoguFJPsE7bQc3mkHCOpSJwjU68Tw1JfMz7fzh4ZJKCs5V/Emvb3MSqC3cOMVXPyc5+NrD9yJra2jGBtpLuZYYNUyR2PSPLiEqaLqiIKGyENTVGWrGFtBMRi1/C0l6QxaSZGQRSbreVst/8xgLYuEltoO3UnlQaDhydLhFtJTVNKb9x5dL8hN0XDIaei7wQBSDJrKYnUYGG3jESKqiBwpWiR6MA1CLBspYJmQlPkPjeKkMZbIjh8/volW1U2d1UoqZnAmpEwwYG0fMIjHlXsn0Si0yqGgQ6IfIdGUbJht49G0TqNxEYzy1qDxVkWwRP668bLI9L04kMZYGC/qm54EpcqQzdATA+wQ2aBPgA0RXR8Ro0FICV1MyKmX2apRlaXSl0ke6MhZ9VIE4fLa9oBglGOr0C2syIAzSwM9nQs1kLMWMXB1OAkiQGeN1c7ZQMpCCu2jx3YXsT0JyMiYdglbE4HOhR9FcNZhu0u498HHsL61jdGIsbIs1SIVOQgBzIwuBpQWAyEmxHGLxjtxQgxh5BuknBH6HgZaqUWM1jl4Em5OU9SAncUkSsVJZCEdO5LxORC2OUn1ThZZf9Yo1VQlYQAsqIqomzBIcRdwBLKBJcbIAWPDaC2jtRmtSzoHolSz5aSlvEnVVkWF2hoCZtaoCsfr/UiRRZ8GojtSUtsxSy8YLpsACUm0Swl9SkjUYnVtDd/45v1YXlvGvoNr2LVjjMZ49JMJdo0T7r3jDvQYo88NYm6wsnMPvLUILA6boQxL0qgws5xv7jNit4X1zU10U8ZkIptdQVVEZVsak3rv0TSNOigjcRYsYTQaqfNusTQeY9w2UoKePXIKMlKjKR9IJ+ycM8bjsaY/ZV11qmuSs6T7UipN/gy8b2EMKYIJEEkH6K4PCCnDOAlUuj4iJMB6CbSMtSAnxDBSNEN0YAbtFEEYJYi12jk5oVTUlB1hCGhniaEl4BlKjAeHo7YTOSXFY8vcOOW9b+eglO/OlZeYKtBZAjooqVyc5AKEVkwcEvAOAWoNYmfGp9+E4qDMBu6SAlJqAw1HPVE7Jx2UcgEmk4ncYHx7xwHA3CQ4/U1xRooMln4LEgN9kOjGu6Hvz6lE2/LPspnJ2RkFjlnRu8Hz1EAUy7v2w63sxoljDyF7yfsmp8JXVsLRPqQaWbWOpC9Khec0PcGoaEDpwZMzgUtX1pJjNgY5DORZZMw4H1DCmpKPiZQgK5FS00iVBiu7MiV1tjjpBi+wLYwFImO7iwBZgUt17InFKWKFUTVDBE6CMvQpa17dSEVPjJVwB2SR0udSJSGfJ9+bZeMp6AAsQkyYdEHIdw7oEmNH77Ayshi3DoYAZ4rsNES7hESPoDTRKq0DyEkXV3INmqaB8QZsCIEg11PTXI214MYiUwJxFDifSH4HaV8VIRg6IxBzH6Xvh/QvkfPxjQcH4TA4a9FRQmTGJGjag42mhHLNc8s8lC6vjTUgiuo4AaNG3GWnsV2CNsRkWXhhDIwRRdchqhd9jRQyui5KSgJyrxKEw9SFiC4kbEwSTmwRtvuMEBVtNJJiMAQ4vYeJGR0Dqc+YHNuGd0DrO4wcwTcG41GLnKNwPaIsjuWztvuMptE+Qcxovaa2mCWt5j2cI3EeUoazDiGLU544SIWLzusS2acUAWvgPInaaRKHShghDEoRlhiNM2iLCF+WKh9SHlPqk9wHK8Xw3gKtlbFO+h5ISaqmICRz663whVjSGcilJbqsDIW/UDg0EiBoK4iUESGpQRCBbNHfkI2WiJBDRMyMSSBsp4RtSlhZ24XECQ89cAwrq5cixizPsiXYljFdP4GtCWFlZS/69UcgqFqGb0YYj1fgxmOwdmYu8wK0gkeP9bj7noewvdnB2Aa+GcE4VzljUhln4J0fugJDkD/vpOcRMRC6DpQTRo0Th9JaIWOW4IgZ06mki5iB0ahFZmnoF4gQbaxpbElXBiHDOnGi+67T1EgpWxedHe57pBCxubWNPmQ0owTXNOhTL2u0yuP3oUeO2mcrQ9cFEqXcmBBzqp3ecx54fGVzn/193njeEVGF2IJMl1QIqddTk0Yzf0OKeBBbFc+b/46S3hnQlBJ4DYhqnlmLS3Va0UAp6F1Bzefgk2EHlGNJREdPdVDkPAbtk4KGnQlVOu2T+YkcdZbZ3XffjWc/+9lP92ksbGELW9jCFraw/4bdf//9uPjii7/tMeckgrJ7924AwH333YedO3c+zWfz1Nn6+jqe+cxn4v7778fq6urTfTpPmS3GvRj3hWCLcS/GfSEYM2NjYwMXXXTRf3rsOemglIqSnTt3XlA3ttjq6upi3BeQLcZ9Ydli3BeWXYjjfqLAwhOv91nYwha2sIUtbGELe4ps4aAsbGELW9jCFraws87OSQelbVu85z3vQdu2T/epPKW2GPdi3BeCLca9GPeFYBfquP8rdk5W8SxsYQtb2MIWtrDz285JBGVhC1vYwha2sIWd37ZwUBa2sIUtbGELW9hZZwsHZWELW9jCFrawhZ11tnBQFrawhS1sYQtb2Fln56SD8vu///u49NJLMRqNcNVVV+Hzn//8031K/yP753/+Z/zQD/0QLrroIhARPvShD829z8z4tV/7NRw6dAjj8RjXXHMN7rzzzrljjh8/jje84Q1YXV3F2toafvqnfxqbm5tP4Sj+a3bdddfhO7/zO7Fjxw7s378fP/qjP4o77rhj7pjpdIprr70We/bswcrKCn78x38cDz/88Nwx9913H1772tdiaWkJ+/fvxy/+4i9Kf5mz1K6//npcccUVVZzp6quvxkc/+tH6/vk45jPZe9/7XhAR3vGOd9TXzsex//qv//rQN0V/Lr/88vr++TjmYg888AB+8id/Env27MF4PMaLX/xifOELX6jvn4/r2qWXXnra/SYiXHvttQDO7/v9pBifY3bDDTdw0zT8p3/6p/zlL3+Zf/Znf5bX1tb44YcffrpP7b9tH/nIR/hXfuVX+G/+5m8YAH/wgx+ce/+9730v79y5kz/0oQ/xf/zHf/AP//AP82WXXcaTyaQe8wM/8AP8kpe8hD/3uc/xv/zLv/BznvMcfv3rX/8Uj+SJ26tf/Wp+3/vex7fffjvfdttt/IM/+IN8+PBh3tzcrMe85S1v4Wc+85n8iU98gr/whS/wd33Xd/F3f/d31/djjPyiF72Ir7nmGr711lv5Ix/5CO/du5d/6Zd+6ekY0hOyD3/4w/wP//AP/PWvf53vuOMO/uVf/mX23vPtt9/OzOfnmE+1z3/+83zppZfyFVdcwW9/+9vr6+fj2N/znvfwC1/4Qn7ooYfqzyOPPFLfPx/HzMx8/PhxvuSSS/hNb3oT33zzzXz33Xfzxz/+cb7rrrvqMefjunb06NG5e33jjTcyAP7Upz7FzOfv/X6y7JxzUF7xilfwtddeW39PKfFFF13E11133dN4Vv//2akOSs6ZDx48yL/1W79VXztx4gS3bct/8Rd/wczMX/nKVxgA/9u//Vs95qMf/SgTET/wwANP2bn/T+zo0aMMgG+66SZmljF67/mv/uqv6jFf/epXGQB/9rOfZWZx7IwxfOTIkXrM9ddfz6urq9x13VM7gP+B7dq1i//4j//4ghjzxsYGP/e5z+Ubb7yRv+/7vq86KOfr2N/znvfwS17ykjO+d76OmZn5Xe96F3/P93zP475/oaxrb3/72/nZz34255zP6/v9ZNk5leLp+x633HILrrnmmvqaMQbXXHMNPvvZzz6NZ/bk2T333IMjR47MjXnnzp246qqr6pg/+9nPYm1tDVdeeWU95pprroExBjfffPNTfs7/HTt58iSAoRHkLbfcghDC3Lgvv/xyHD58eG7cL37xi3HgwIF6zKtf/Wqsr6/jy1/+8lN49v89SynhhhtuwNbWFq6++uoLYszXXnstXvva186NETi/7/edd96Jiy66CM961rPwhje8Affddx+A83vMH/7wh3HllVfiJ37iJ7B//3689KUvxR/90R/V9y+Eda3ve3zgAx/Am9/8ZhDReX2/nyw7pxyURx99FCmluZsHAAcOHMCRI0eeprN6cq2M69uN+ciRI9i/f//c+8457N69+5y4LjlnvOMd78ArX/lKvOhFLwIgY2qaBmtra3PHnjruM12X8t7Zal/60pewsrKCtm3xlre8BR/84Afxghe84LweMwDccMMN+Pd//3dcd911p713vo79qquuwvvf/3587GMfw/XXX4977rkH3/u934uNjY3zdswAcPfdd+P666/Hc5/7XHz84x/HW9/6VvzCL/wC/uzP/gzAhbGufehDH8KJEyfwpje9CcD5O8efTDsnuxkv7Pyya6+9Frfffjs+85nPPN2n8pTYd3zHd+C2227DyZMn8dd//dd44xvfiJtuuunpPq0n1e6//368/e1vx4033ojRaPR0n85TZq95zWvqv6+44gpcddVVuOSSS/CXf/mXGI/HT+OZPbmWc8aVV16J3/zN3wQAvPSlL8Xtt9+OP/iDP8Ab3/jGp/nsnhr7kz/5E7zmNa/BRRdd9HSfyjlr5xSCsnfvXlhrT2M9P/zwwzh48ODTdFZPrpVxfbsxHzx4EEePHp17P8aI48ePn/XX5W1vexv+/u//Hp/61Kdw8cUX19cPHjyIvu9x4sSJueNPHfeZrkt572y1pmnwnOc8By9/+ctx3XXX4SUveQl+53d+57we8y233IKjR4/iZS97GZxzcM7hpptuwu/+7u/COYcDBw6ct2OftbW1NTzvec/DXXfddV7f70OHDuEFL3jB3GvPf/7za3rrfF/X7r33XvzTP/0TfuZnfqa+dj7f7yfLzikHpWkavPzlL8cnPvGJ+lrOGZ/4xCdw9dVXP41n9uTZZZddhoMHD86NeX19HTfffHMd89VXX40TJ07glltuqcd88pOfRM4ZV1111VN+zk/EmBlve9vb8MEPfhCf/OQncdlll829//KXvxze+7lx33HHHbjvvvvmxv2lL31pbhG78cYbsbq6etrieDZbzhld153XY37Vq16FL33pS7jtttvqz5VXXok3vOEN9d/n69hnbXNzE9/4xjdw6NCh8/p+v/KVrzxNNuDrX/86LrnkEgDn77pW7H3vex/279+P1772tfW18/l+P2n2dLN0/6t2ww03cNu2/P73v5+/8pWv8M/93M/x2traHOv5XLONjQ2+9dZb+dZbb2UA/Nu//dt866238r333svMUo63trbGf/u3f8tf/OIX+Ud+5EfOWI730pe+lG+++Wb+zGc+w8997nPP6nK8t771rbxz507+9Kc/PVeWt729XY95y1vewocPH+ZPfvKT/IUvfIGvvvpqvvrqq+v7pSTv+7//+/m2227jj33sY7xv376zuiTv3e9+N9900018zz338Be/+EV+97vfzUTE//iP/8jM5+eYH89mq3iYz8+xv/Od7+RPf/rTfM899/C//uu/8jXXXMN79+7lo0ePMvP5OWZmKSV3zvFv/MZv8J133sl//ud/zktLS/yBD3ygHnM+rmvMUll6+PBhfte73nXae+fr/X6y7JxzUJiZf+/3fo8PHz7MTdPwK17xCv7c5z73dJ/S/8g+9alPMYDTft74xjcys5Tk/eqv/iofOHCA27blV73qVXzHHXfMfcaxY8f49a9/Pa+srPDq6ir/1E/9FG9sbDwNo3lidqbxAuD3ve999ZjJZMI///M/z7t27eKlpSX+sR/7MX7ooYfmPueb3/wmv+Y1r+HxeMx79+7ld77znRxCeIpH88TtzW9+M19yySXcNA3v27ePX/WqV1XnhPn8HPPj2akOyvk49te97nV86NAhbpqGn/GMZ/DrXve6OS2Q83HMxf7u7/6OX/SiF3Hbtnz55ZfzH/7hH869fz6ua8zMH//4xxnAaWNhPr/v95NhxMz8tEA3C1vYwha2sIUtbGGPY+cUB2VhC1vYwha2sIVdGLZwUBa2sIUtbGELW9hZZwsHZWELW9jCFrawhZ11tnBQFrawhS1sYQtb2FlnCwdlYQtb2MIWtrCFnXW2cFAWtrCFLWxhC1vYWWcLB2VhC1vYwha2sIWddbZwUBa2sIUtbGELW9hZZwsHZWELW9jCFrawhZ11tnBQFrawhS1sYQtb2FlnCwdlYQtb2MIWtrCFnXW2cFAWtrCFLWxhC1vYWWf/H5ptlRtoTq+RAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/mattors/gca/baseline_r34_4x10_200k_comp1k_SAD-34.61_20220620-96f85d56.pth\n", "The model and loaded state dict do not match exactly\n", "\n", "unexpected key in source state_dict: data_preprocessor.mean, data_preprocessor.std\n", "\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "img = '../resources/input/matting/GT05.jpg'\n", "trimap = '../resources/input/matting/GT05_trimap.jpg'\n", "\n", "# show input image and mask\n", "input_img = mmcv.imread(img)\n", "plt.imshow(mmcv.bgr2rgb(input_img))\n", "plt.show()\n", "input_trimap = mmcv.imread(trimap)\n", "plt.imshow(mmcv.bgr2rgb(input_trimap))\n", "plt.show()\n", "\n", "# Create a MMagicInferencer instance and infer\n", "result_out_dir = '../resources/output/matting/tutorial_matting_gca_res.png'\n", "editor = MMagicInferencer('gca')\n", "results = editor.infer(img=img, trimap=trimap, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.4 Inference of image super resolution models\n", "\n", "Image super resolution models take a image as input, and output a high resolution image. We take 'esrgan' as an example." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth\n" ] }, { "data": { "image/png": "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vueyyy6T5zznOfKZz3xG/vVf/1XOP/98ecUrXrF8/eTJk3Lw4EG5/PLL5aabbpL3v//9MplM5C//8i8fqWWegoda8ytf+Uq57LLLTjnnx48fP+U9p9uaL730Unnve98rN910k9xwww3y0z/903L22WfLzs7O8j0Px7X8X//1XzKdTuW3fuu35Ctf+Yq8613vEuecfOxjH3vMrff//b//J6961atOOc8nT548LdcrIvIP//AP8k//9E/yn//5n3LzzTfL2972NgkhyE033SQie+v8LvBQa95r5/hb8bnPfU6e8pSnyIUXXiivf/3rlz9/LJ3nPVfgvOAFL5Arrrhi+f9TSnLWWWfJO97xjkfxqL53vP3tb5fnPOc5D/jaiRMnJIQgf/d3f7f82Ve/+lUB5NprrxURfZhaa+Xo0aPL97znPe+R9fV16bruB3rs3y2+/WGfc5ZDhw7Jn/zJnyx/duLECanrWt7//veLiMhXvvIVAeTzn//88j0f/ehHxRgj3/zmN0VE5C/+4i9k3759p6z3zW9+s1xwwQU/4BU9NB6swHnZy172oH/ndF+ziMhdd90lgFxzzTUi8vBdy7/zO78jz3zmM0/5t17+8pfLpZde+oNe0nfEt69XRB9+3/pg+HaczutdYN++ffJXf/VXe/78fisWaxbZu+d4e3tbnva0p8lVV111yhofa+d5T42o+r7nuuuu45JLLln+zFrLJZdcwrXXXvsoHtn3h6997WucddZZnHfeeVx++eXcfvvtAFx33XUMw3DKep/+9Kdz9tlnL9d77bXX8uxnP5uDBw8u33PppZeytbXFl7/85Ud2Id8lbrvtNo4ePXrK+jY2NrjoootOWd/m5ibPf/7zl++55JJLsNby2c9+dvmeF73oRVRVtXzPpZdeys0338y99977CK3mu8PVV1/NmWeeyQUXXMBrX/tajh07tnxtL6z55MmTAOzfvx94+K7la6+99pTfsXjPo/39//b1LvA3f/M3HDhwgGc961m89a1vZTabLV87ndebUuLKK69kd3eXI0eO7PnzC/df8wJ78RxfccUVvPSlL73fcT3WzvOeShO/5557SCmd8sEBHDx4kP/4j/94lI7q+8NFF13E+973Pi644ALuuOMO/vAP/5AXvvCF3HTTTRw9epSqqtjc3Dzl7xw8eJCjR48CcPTo0Qf8PBavPZaxOL4HOv5vXd+ZZ555yuvee/bv33/Ke84999z7/Y7Fa/v27fuBHP/3issuu4xf+IVf4Nxzz+XWW2/lbW97Gy95yUu49tprcc6d9mvOOfOGN7yBn/iJn+BZz3rW8pgejmv5wd6ztbXFfD5nMpn8IJb0HfFA6wX45V/+Zc455xzOOussbrzxRt785jdz880384EPfAA4Pdf7pS99iSNHjtC2Laurq3zwgx/kGc94BjfccMOePb8PtmbYm+f4yiuv5N///d/5/Oc/f7/XHmvf4z1V4OxFvOQlL1n+94UXXshFF13EOeecw9/+7d8+Kl/mET94/NIv/dLyv5/97Gdz4YUX8tSnPpWrr76aiy+++FE8socHV1xxBTfddBOf/vSnH+1DeUTwYOt99atfvfzvZz/72Rw+fJiLL76YW2+9lac+9amP9GE+LLjgggu44YYbOHnyJH//93/PK1/5Sq655ppH+7B+oHiwNT/jGc/Yc+f4G9/4Bq9//eu56qqraJrm0T6ch8SeGlEdOHAA59z9GNt33nknhw4depSO6uHF5uYmP/RDP8Qtt9zCoUOH6PueEydOnPKeb13voUOHHvDzWLz2WMbi+L7T+Tx06BB33XXXKa/HGDl+/Pie+AwAzjvvPA4cOMAtt9wCnN5rft3rXsc//uM/8slPfpInPelJy58/XNfyg71nfX39UdkQPNh6HwgXXXQRwCnn+XRbb1VVnH/++Tzvec/jHe94B895znP4sz/7sz17fuHB1/xAON3P8XXXXcddd93Fc5/7XLz3eO+55ppr+PM//3O89xw8ePAxdZ73VIFTVRXPe97z+PjHP778Wc6Zj3/846fMRE9n7OzscOutt3L48GGe97znEUI4Zb0333wzt99++3K9R44c4Utf+tIpD8SrrrqK9fX1ZRv1sYpzzz2XQ4cOnbK+ra0tPvvZz56yvhMnTnDdddct3/OJT3yCnPPyZnLkyBE+9alPMQzD8j1XXXUVF1xwwWNuPPVA+J//+R+OHTvG4cOHgdNzzSLC6173Oj74wQ/yiU984n7js4frWj5y5Mgpv2Pxnkf6+/9Q630g3HDDDQCnnOfTZb0PhpwzXdftufP7nbBY8wPhdD/HF198MV/60pe44YYbln+e//znc/nlly//+zF1nr97/vRjG1deeaXUdS3ve9/75Ctf+Yq8+tWvls3NzVMY26cT3vjGN8rVV18tt912m/zbv/2bXHLJJXLgwAG56667REQleWeffbZ84hOfkC984Qty5MgROXLkyPLvLyR5L37xi+WGG26Qj33sY3LGGWc8ZmTi29vbcv3118v1118vgPzpn/6pXH/99fL1r39dRFQmvrm5KR/+8IflxhtvlJe97GUPKBP/kR/5EfnsZz8rn/70p+VpT3vaKZLpEydOyMGDB+VXfuVX5KabbpIrr7xSptPpoyaZ/k5r3t7elt/+7d+Wa6+9Vm677Tb5l3/5F3nuc58rT3va06Rt2+XvON3W/NrXvlY2Njbk6quvPkUyO5vNlu95OK7lhbz0TW96k3z1q1+Vd7/73Y+KpPah1nvLLbfIH/3RH8kXvvAFue222+TDH/6wnHfeefKiF73otFyviMhb3vIWueaaa+S2226TG2+8Ud7ylreIMUb++Z//WUT21vld4DuteS+e4wfCtyvFHkvnec8VOCIi73rXu+Tss8+WqqrkBS94gXzmM595tA/pe8bLX/5yOXz4sFRVJU984hPl5S9/udxyyy3L1+fzufzmb/6m7Nu3T6bTqfz8z/+83HHHHaf8jv/+7/+Wl7zkJTKZTOTAgQPyxje+UYZheKSX8oD45Cc/KcD9/rzyla8UEZWK/97v/Z4cPHhQ6rqWiy++WG6++eZTfsexY8fkFa94hayursr6+rr82q/9mmxvb5/yni9+8Yvykz/5k1LXtTzxiU+Ud77znY/UEu+H77Tm2WwmL37xi+WMM86QEIKcc8458qpXvep+BfrptuYHWi8g733ve5fvebiu5U9+8pPywz/8w1JVlZx33nmn/BuPFB5qvbfffru86EUvkv3790td13L++efLm970plM8UkROn/WKiPz6r/+6nHPOOVJVlZxxxhly8cUXL4sbkb11fhf4Tmvei+f4gfDtBc5j6TwbEZHvruczYsSIESNGjBjx2Mae4uCMGDFixIgRI0bAWOCMGDFixIgRI/YgxgJnxIgRI0aMGLHnMBY4I0aMGDFixIg9h7HAGTFixIgRI0bsOYwFzogRI0aMGDFiz2EscEaMGDFixIgRew5jgTNixIgRI0aM2HMYC5wRI0aMGDFixJ7DWOCMGDFixIgRI/YcxgJnxIgRI0aMGLHn8P8B+ZApPFfehXsAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "# Create a MMagicInferencer instance and infer\n", "img = '../resources/input/restoration/0901x2.png'\n", "result_out_dir = '../resources/output/restoration/tutorial_restoration_esrgan_res.png'\n", "editor = MMagicInferencer('esrgan')\n", "results = editor.infer(img=img, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.5 Inference of image translation models\n", "\n", "Image translation models take a image as input, and output a translated image. We take 'pix2pix' as an example." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/pix2pix/refactor/pix2pix_vanilla_unet_bn_1x1_80k_facades_20210902_170442-c0958d50.pth\n" ] }, { "data": { "image/png": "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t7zlLTzyyCMAfPKTnySldNlYfeu3fisve9nLXrRj9fDDD3Pu3LnLxuTo0aPccsst6zG577772N3d5a/+1b+6fs3tt9+OtZZPfOITL/g1X4m45557OHnyJK961au48847OX/+/Pq5F9P47O3tAXD8+HHga7un7rvvPm6++WZOnTq1fs0b3vAG9vf3+dznPvcCXv0LE396jFbxa7/2a5w4cYKbbrqJd73rXSwWi/VzX48xuqpEdp944glKKZe9YYBTp07x+c9//gpd1ZWLW265hfe+97286lWv4uzZs/zCL/wCf+2v/TU++9nPcu7cObquY3d397KfOXXqFOfOnbsyF3yFY/W+n27+rJ47d+4cJ0+evOx57z3Hjx9/UYzbG9/4Rr7/+7+fG2+8kYceeoif/umf5k1vehP33XcfzrkXzfjUWvmxH/sxvvu7v5ubbroJ4Gu6p86dO/e082v13DdTPN0YAfzwD/8wN9xwA9dddx2f+cxneOc738kDDzzA+973PuDrM0ZX1ca1icvjTW960/r717zmNdxyyy3ccMMN/OZv/ibT6fQKXtkmrtb4W3/rb62/v/nmm3nNa17DK17xCu655x5e//rXX8Ere2Hjrrvu4rOf/exlPeNNXB5/1hg9td958803c+bMGV7/+tfz0EMP8YpXvOLr8revqlLhiRMncM59FYrn0Ucf5fTp01foqv7fid3dXf7iX/yLPPjgg5w+fZoYI5cuXbrsNS/msVq972eaP6dPn/4qoE/OmQsXLrwox+3lL385J06c4MEHHwReHOPzjne8gw9+8IN89KMfvczg8Gu5p06fPv2082v13DdL/Flj9HRxyy23AFw2h/68Y3RVbVxd1/Ht3/7t/O7v/u76sVorv/u7v8utt956Ba/s/404PDzkoYce4syZM3z7t387IYTLxuqBBx7gkUceedGO1Y033sjp06cvG5P9/X0+8YlPrMfk1ltv5dKlS3zyk59cv+YjH/kItdb1Dfhiii996UucP3+eM2fOAN/c4yMivOMd7+D9738/H/nIR7jxxhsve/5ruaduvfVW/viP//iyzf1DH/oQOzs7vPrVr35h3sg3MJ5tjJ4uPv3pTwNcNof+3GP0PMEkVyz+w3/4D9L3vbz3ve+V+++/X97+9rfL7u7uZQiVF0v85E/+pNxzzz3y8MMPy3//7/9dbr/9djlx4oQ89thjIiLyoz/6o/Kyl71MPvKRj8gf/uEfyq233iq33nrrFb7qb2wcHBzIpz71KfnUpz4lgPyrf/Wv5FOf+pT8yZ/8iYiI/PN//s9ld3dXPvCBD8hnPvMZ+b7v+z658cYbZblcrn/HG9/4Rvm2b/s2+cQnPiEf+9jH5JWvfKX80A/90JV6S1/XeKbxOTg4kH/8j/+x3HffffLwww/Lhz/8Yfkrf+WvyCtf+UoZhmH9O75Zx+fOO++Uo0ePyj333CNnz55dfy0Wi/Vrnu2eyjnLTTfdJHfccYd8+tOflt/5nd+Ra6+9Vt71rnddibf0dY9nG6MHH3xQfvEXf1H+8A//UB5++GH5wAc+IC9/+cvltttuW/+Or8cYXXUbl4jIv/23/1Ze9rKXSdd18p3f+Z3y+7//+1f6kq5I/OAP/qCcOXNGuq6Tl7zkJfKDP/iD8uCDD66fXy6X8g/+wT+QY8eOyWw2k7/5N/+mnD179gpe8Tc+PvrRjwrwVV9vfetbRUQh8T/7sz8rp06dkr7v5fWvf7088MADl/2O8+fPyw/90A/J9va27OzsyN/9u39XDg4OrsC7+frHM43PYrGQO+64Q6699loJIcgNN9wgb3vb274qKfxmHZ+nGxdAfvVXf3X9mq/lnvq///f/ypve9CaZTqdy4sQJ+cmf/ElJKb3A7+YbE882Ro888ojcdtttcvz4cen7Xv7CX/gL8lM/9VOyt7d32e/5847RxtZkE5vYxCY2cVXFVdXj2sQmNrGJTWxis3FtYhOb2MQmrqrYbFyb2MQmNrGJqyo2G9cmNrGJTWziqorNxrWJTWxiE5u4qmKzcW1iE5vYxCauqthsXJvYxCY2sYmrKjYb1yY2sYlNbOKqis3GtYlNbGITm7iqYrNxbWITm9jEJq6q2Gxcm9jEJjaxiasqNhvXJjaxiU1s4qqK/x8ypveH+FnSkAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "img = '../resources/input/translation/gt_mask_0.png'\n", "\n", "# show input image and mask\n", "input_img = mmcv.imread(img)\n", "plt.imshow(mmcv.bgr2rgb(input_img))\n", "plt.show()\n", "\n", "# Create a MMagicInferencer instance and infer\n", "result_out_dir = '../resources/output/translation/tutorial_translation_pix2pix_res.png'\n", "editor = MMagicInferencer('pix2pix')\n", "results = editor.infer(img=img, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.6 Inference of unconditional GAN models\n", "\n", "Unconditional GAN models do not need input, and output a image. We take 'styleganv1' as an example." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/styleganv1/styleganv1_ffhq_256_g8_25Mimg_20210407_161748-0094da86.pth\n", "Switch to evaluation style mode: single\n", "Switch to evaluation style mode: single\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "# Create a MMagicInferencer instance and infer\n", "result_out_dir = '../resources/output/unconditional/tutorial_unconditional_styleganv1_res.png'\n", "editor = MMagicInferencer('styleganv1')\n", "results = editor.infer(result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.7 Inference of video interpolation models\n", "\n", "Video interpolation models take a video as input, and output a interpolated video. We take 'flavr' as an example." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/video_interpolators/flavr/flavr_in4out1_g8b4_vimeo90k_septuplet_20220509-c2468995.pth\n", "[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] 22/22, 0.1 task/s, elapsed: 245s, ETA: 0s11/21 00:31:46 - mmengine - \u001b[4m\u001b[37mINFO\u001b[0m - Output video is save at ../resources/output/video_interpolation/tutorial_video_interpolation_flavr_res.mp4.\n", "11/21 00:31:46 - mmengine - \u001b[4m\u001b[37mINFO\u001b[0m - Visualization is implemented in forward process.\n", "11/21 00:31:46 - mmengine - \u001b[4m\u001b[37mINFO\u001b[0m - Postprocess is implemented in forward process.\n" ] } ], "source": [ "import os\n", "from mmagic.apis import MMagicInferencer\n", "from mmengine import mkdir_or_exist\n", "\n", "# Create a MMagicInferencer instance and infer\n", "video = '../resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4'\n", "result_out_dir = '../resources/output/video_interpolation/tutorial_video_interpolation_flavr_res.mp4'\n", "mkdir_or_exist(os.path.dirname(result_out_dir))\n", "editor = MMagicInferencer('flavr')\n", "results = editor.infer(video=video, result_out_dir=result_out_dir)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Please check the result video in the output directory." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.8 Inference of video restoration models\n", "\n", "Video restoration models take a video as input, and output a restorated video. We take 'basicvsr' as an example.." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http loads checkpoint from path: https://download.openmmlab.com/mmediting/restorers/edvr/edvrm_wotsa_x4_8x4_600k_reds_20200522-0570e567.pth\n", "11/20 18:13:55 - mmengine - \u001b[4m\u001b[37mINFO\u001b[0m - Output video is save at ../resources/output/video_restoration/tutorial_video_restoration_edvr_res.mp4.\n", "11/20 18:13:55 - mmengine - \u001b[4m\u001b[37mINFO\u001b[0m - Postprocess is implemented in visualize process.\n" ] } ], "source": [ "import os\n", "from mmagic.apis import MMagicInferencer\n", "from mmengine import mkdir_or_exist\n", "\n", "# Create a MMagicInferencer instance and infer\n", "video = '../resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4'\n", "result_out_dir = '../resources/output/video_restoration/tutorial_video_restoration_edvr_res.mp4'\n", "mkdir_or_exist(os.path.dirname(result_out_dir))\n", "editor = MMagicInferencer('edvr', extra_parameters={'window_size':5})\n", "results = editor.infer(video=video, result_out_dir=result_out_dir)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Please check the result video in the output directory." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### 4.9 Inference of text-to-image models\n", "\n", "Text-to-image models take text as input, and output a image. We take 'stable_diffusion' as an example." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Cannot initialize model with low cpu memory usage because `accelerate` was not found in the environment. Defaulting to `low_cpu_mem_usage=False`. It is strongly recommended to install `accelerate` for faster and less memory-intense model loading. You can do so with: \n", "```\n", "pip install accelerate\n", "```\n", ".\n", "Cannot initialize model with low cpu memory usage because `accelerate` was not found in the environment. Defaulting to `low_cpu_mem_usage=False`. It is strongly recommended to install `accelerate` for faster and less memory-intense model loading. You can do so with: \n", "```\n", "pip install accelerate\n", "```\n", ".\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "04/24 20:24:33 - mmengine - INFO - Creating ../resources/stable-diffusion-v1-5 by 'HuggingFace'\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "88258b641d97420bbb07a7970929b7da", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/50 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmagic.apis import MMagicInferencer\n", "\n", "# Create a MMagicInferencer instance and infer\n", "editor = MMagicInferencer(model_name='stable_diffusion')\n", "text_prompts = 'A panda is having dinner at KFC'\n", "result_out_dir = '../resources/output/text2image/tutorial_text2image_sd_res.png'\n", "editor.infer(text=text_prompts, result_out_dir=result_out_dir)\n", "\n", "# plot the result image\n", "img = mmcv.imread(result_out_dir)\n", "plt.imshow(mmcv.bgr2rgb(img))\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "mmagic", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.15" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "2396e09a98edfab6266f814c68e2f319a2f52e823b3715487b27762471d9be4e" } } }, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: demo/singan_demo.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import sys import mmcv import torch from mmengine import Config, print_log from mmengine.logging import MMLogger from mmengine.runner import load_checkpoint, set_random_seed # yapf: disable sys.path.append(os.path.abspath(os.path.join(__file__, '../..'))) # isort:skip # noqa from mmagic.engine import * # isort:skip # noqa: F401,F403,E402 from mmagic.datasets import * # isort:skip # noqa: F401,F403,E402 from mmagic.models import * # isort:skip # noqa: F401,F403,E402 from mmagic.registry import MODELS # isort:skip # noqa # yapf: enable def parse_args(): parser = argparse.ArgumentParser(description='Evaluate a GAN model') parser.add_argument('config', help='evaluation config file path') parser.add_argument('checkpoint', help='checkpoint file') parser.add_argument('--seed', type=int, default=2021, help='random seed') parser.add_argument( '--deterministic', action='store_true', help='whether to set deterministic options for CUDNN backend.') parser.add_argument( '--samples-path', type=str, default='./', help='path to store images. If not given, remove it after evaluation\ finished') parser.add_argument( '--save-prev-res', action='store_true', help='whether to store the results from previous stages') parser.add_argument( '--num-samples', type=int, default=10, help='the number of synthesized samples') args = parser.parse_args() return args def _tensor2img(img): img = img.permute(1, 2, 0) img = img.clamp(0, 255).to(torch.uint8) return img.cpu().numpy() @torch.no_grad() def main(): MMLogger.get_instance('mmagic') args = parse_args() cfg = Config.fromfile(args.config) # set cudnn_benchmark if cfg.get('cudnn_benchmark', False): torch.backends.cudnn.benchmark = True # set random seeds if args.seed is not None: set_random_seed(args.seed, deterministic=args.deterministic) # set scope manually cfg.model['_scope_'] = 'mmagic' # build the model and load checkpoint model = MODELS.build(cfg.model) model.eval() # load ckpt print_log(f'Loading ckpt from {args.checkpoint}') _ = load_checkpoint(model, args.checkpoint, map_location='cpu') # add dp wrapper if torch.cuda.is_available(): model = model.cuda() for sample_iter in range(args.num_samples): outputs = model.test_step( dict(inputs=dict(num_batches=1, get_prev_res=args.save_prev_res))) # store results from previous stages if args.save_prev_res: fake_img = outputs[0].fake_img.data prev_res_list = outputs[0].prev_res_list prev_res_list.append(fake_img) for i, img in enumerate(prev_res_list): img = _tensor2img(img) mmcv.imwrite( img, os.path.join(args.samples_path, f'stage{i}', f'rand_sample_{sample_iter}.png')) # just store the final result else: img = _tensor2img(outputs[0].fake_img.data) mmcv.imwrite( img, os.path.join(args.samples_path, f'rand_sample_{sample_iter}.png')) if __name__ == '__main__': main() ================================================ FILE: demo/utils/gradio_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # yapf: disable import gradio as gr import numpy as np from PIL import Image, ImageDraw class EasyDict(dict): """Convenience class that behaves like a dict but allows access with the attribute syntax.""" def __getattr__(self, name: str): try: return self[name] except KeyError: raise AttributeError(name) def __setattr__(self, name: str, value) -> None: self[name] = value def __delattr__(self, name: str) -> None: del self[name] class ImageMask(gr.components.Image): """ Sets: source="canvas", tool="sketch" """ is_template = True def __init__(self, **kwargs): super().__init__( source='upload', tool='sketch', interactive=False, **kwargs) def preprocess(self, x): if x is None: return x if self.tool == 'sketch' and self.source in ['upload', 'webcam' ] and type(x) != dict: decode_image = gr.processing_utils.decode_base64_to_image(x) width, height = decode_image.size mask = np.ones((height, width, 4), dtype=np.uint8) mask[..., -1] = 255 mask = self.postprocess(mask) x = {'image': x, 'mask': mask} return super().preprocess(x) def get_valid_mask(mask: np.ndarray): """Convert mask from gr.Image(0 to 255, RGBA) to binary mask.""" if mask.ndim == 3: mask_pil = Image.fromarray(mask).convert('L') mask = np.array(mask_pil) if mask.max() == 255: mask = mask / 255 return mask def draw_points_on_image(image, points, curr_point=None, highlight_all=True, radius_scale=0.01): overlay_rgba = Image.new('RGBA', image.size, 0) overlay_draw = ImageDraw.Draw(overlay_rgba) for point_key, point in points.items(): if ((curr_point is not None and curr_point == point_key) or highlight_all): p_color = (255, 0, 0) t_color = (0, 0, 255) else: p_color = (255, 0, 0, 35) t_color = (0, 0, 255, 35) rad_draw = int(image.size[0] * radius_scale) p_start = point.get('start_temp', point['start']) p_target = point['target'] if p_start is not None and p_target is not None: p_draw = int(p_start[0]), int(p_start[1]) t_draw = int(p_target[0]), int(p_target[1]) overlay_draw.line( (p_draw[0], p_draw[1], t_draw[0], t_draw[1]), fill=(255, 255, 0), width=2, ) if p_start is not None: p_draw = int(p_start[0]), int(p_start[1]) overlay_draw.ellipse( ( p_draw[0] - rad_draw, p_draw[1] - rad_draw, p_draw[0] + rad_draw, p_draw[1] + rad_draw, ), fill=p_color, ) if curr_point is not None and curr_point == point_key: overlay_draw.text(p_draw, 'p', align='center', fill=(0, 0, 0)) if p_target is not None: t_draw = int(p_target[0]), int(p_target[1]) overlay_draw.ellipse( ( t_draw[0] - rad_draw, t_draw[1] - rad_draw, t_draw[0] + rad_draw, t_draw[1] + rad_draw, ), fill=t_color, ) if curr_point is not None and curr_point == point_key: overlay_draw.text(t_draw, 't', align='center', fill=(0, 0, 0)) return Image.alpha_composite(image.convert('RGBA'), overlay_rgba).convert('RGB') def draw_mask_on_image(image, mask): im_mask = np.uint8(mask * 255) im_mask_rgba = np.concatenate( ( np.tile(im_mask[..., None], [1, 1, 3]), 45 * np.ones( (im_mask.shape[0], im_mask.shape[1], 1), dtype=np.uint8), ), axis=-1, ) im_mask_rgba = Image.fromarray(im_mask_rgba).convert('RGBA') return Image.alpha_composite(image.convert('RGBA'), im_mask_rgba).convert('RGB') def on_change_single_global_state(keys, value, global_state, map_transform=None): if map_transform is not None: value = map_transform(value) curr_state = global_state if isinstance(keys, str): last_key = keys else: for k in keys[:-1]: curr_state = curr_state[k] last_key = keys[-1] curr_state[last_key] = value return global_state def get_latest_points_pair(points_dict): if not points_dict: return None point_idx = list(points_dict.keys()) latest_point_idx = max(point_idx) return latest_point_idx ================================================ FILE: demo/utils/renderer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # # NVIDIA CORPORATION and its licensors retain all intellectual property # and proprietary rights in and to this software, related documentation # and any modifications thereto. Any use, reproduction, disclosure or # distribution of this software and related documentation without an express # license agreement from NVIDIA CORPORATION is strictly prohibited. import sys import traceback import matplotlib.cm import matplotlib.font_manager import numpy as np import torch import torch.fft import torch.nn.functional as F from PIL import Image, ImageDraw, ImageFont from demo.utils.gradio_utils import EasyDict from mmagic.apis import MMagicInferencer class CapturedException(Exception): def __init__(self, msg=None): if msg is None: _type, value, _traceback = sys.exc_info() assert value is not None if isinstance(value, CapturedException): msg = str(value) else: msg = traceback.format_exc() assert isinstance(msg, str) super().__init__(msg) ''' ---------------------------------------------------------------------------- ''' class CaptureSuccess(Exception): def __init__(self, out): super().__init__() self.out = out ''' ---------------------------------------------------------------------------- ''' def add_watermark_np(input_image_array, watermark_text='AI Generated'): image = Image.fromarray(np.uint8(input_image_array)).convert('RGBA') # Initialize text image txt = Image.new('RGBA', image.size, (255, 255, 255, 0)) ttf_pth = matplotlib.font_manager.findSystemFonts( fontpaths=None, fontext='ttf')[-1] font = ImageFont.truetype(ttf_pth, round(25 / 512 * image.size[0])) d = ImageDraw.Draw(txt) text_width, text_height = font.getsize(watermark_text) text_position = (image.size[0] - text_width - 10, image.size[1] - text_height - 10) text_color = ( 255, 255, 255, 128 ) # white color with the alpha channel set to semi-transparent # Draw the text onto the text canvas d.text(text_position, watermark_text, font=font, fill=text_color) # Combine the image with the watermark watermarked = Image.alpha_composite(image, txt) watermarked_array = np.array(watermarked) return watermarked_array class Renderer: def __init__(self, disable_timing=False): self._device = torch.device('cuda' if torch.cuda.is_available( ) else 'mps' if torch.backends.mps.is_available() else 'cpu') self._dtype = torch.float32 \ if self._device.type == 'mps' else torch.float64 self._pkl_data = dict() # {pkl: dict | CapturedException, ...} self._networks = dict() # {cache_key: torch.nn.Module, ...} self._pinned_bufs = dict() # {(shape, dtype): torch.Tensor, ...} self._cmaps = dict() # {name: torch.Tensor, ...} self._is_timing = False if not disable_timing: self._start_event = torch.cuda.Event(enable_timing=True) self._end_event = torch.cuda.Event(enable_timing=True) self._disable_timing = disable_timing self._net_layers = dict() # {cache_key: [dnnlib.EasyDict, ...], ...} def render(self, **args): if self._disable_timing: self._is_timing = False else: self._start_event.record(torch.cuda.current_stream(self._device)) self._is_timing = True res = EasyDict() try: init_net = False if not hasattr(self, 'G'): init_net = True if hasattr(self, 'pkl'): if self.pkl != args['pkl']: init_net = True if hasattr(self, 'w_load'): if self.w_load is not args['w_load']: init_net = True if hasattr(self, 'w0_seed'): if self.w0_seed != args['w0_seed']: init_net = True if hasattr(self, 'w_plus'): if self.w_plus != args['w_plus']: init_net = True if args['reset_w']: init_net = True res.init_net = init_net if init_net: self.init_network(res, **args) self._render_drag_impl(res, **args) except CapturedException: res.error = CapturedException() if not self._disable_timing: self._end_event.record(torch.cuda.current_stream(self._device)) if 'image' in res: res.image = self.to_cpu(res.image).detach().numpy() res.image = add_watermark_np(res.image, 'AI Generated') if 'stats' in res: res.stats = self.to_cpu(res.stats).detach().numpy() if 'error' in res: res.error = str(res.error) # if 'stop' in res and res.stop: if self._is_timing and not self._disable_timing: self._end_event.synchronize() res.render_time = self._start_event.elapsed_time( self._end_event) * 1e-3 self._is_timing = False return res def get_network(self, pkl, key, **tweak_kwargs): data = self._pkl_data.get(pkl, None) if data is None: print(f'Loading "{pkl}"... ', end='', flush=True) try: print('Done.') except CapturedException: data = CapturedException() print('Failed!') self._pkl_data[pkl] = data self._ignore_timing() if isinstance(data, CapturedException): raise data orig_net = data[key] cache_key = (orig_net, self._device, tuple(sorted(tweak_kwargs.items()))) net = self._networks.get(cache_key, None) if net is None: try: if 'stylegan2' in pkl: from training.networks_stylegan2 import Generator else: raise NameError('Cannot infer model type from pkl name!') print(data[key].init_args) print(data[key].init_kwargs) if 'stylegan_human' in pkl: net = Generator( *data[key].init_args, **data[key].init_kwargs, square=False, padding=True) else: net = Generator(*data[key].init_args, **data[key].init_kwargs) net.load_state_dict(data[key].state_dict()) net.to(self._device) except CapturedException: net = CapturedException() self._networks[cache_key] = net self._ignore_timing() if isinstance(net, CapturedException): raise net return net def _get_pinned_buf(self, ref): key = (tuple(ref.shape), ref.dtype) buf = self._pinned_bufs.get(key, None) if buf is None: buf = torch.empty(ref.shape, dtype=ref.dtype).pin_memory() self._pinned_bufs[key] = buf return buf def to_device(self, buf): return self._get_pinned_buf(buf).copy_(buf).to(self._device) def to_cpu(self, buf): return self._get_pinned_buf(buf).copy_(buf).clone() def _ignore_timing(self): self._is_timing = False def _apply_cmap(self, x, name='viridis'): cmap = self._cmaps.get(name, None) if cmap is None: cmap = matplotlib.cm.get_cmap(name) cmap = cmap(np.linspace(0, 1, num=1024), bytes=True)[:, :3] cmap = self.to_device(torch.from_numpy(cmap)) self._cmaps[name] = cmap hi = cmap.shape[0] - 1 x = (x * hi + 0.5).clamp(0, hi).to(torch.int64) x = torch.nn.functional.embedding(x, cmap) return x def init_network(self, res, ckpt_pth=None, w0_seed=0, w_load=None, w_plus=True, noise_mode='const', trunc_psi=0.7, trunc_cutoff=None, input_transform=None, lr=0.001, **kwargs): # Dig up network details. if '256' in ckpt_pth: editor = MMagicInferencer( 'draggan', model_setting=1, model_ckpt=ckpt_pth, ) elif '512' in ckpt_pth: editor = MMagicInferencer( 'draggan', model_setting=0, model_ckpt=ckpt_pth, ) elif '1024' in ckpt_pth: editor = MMagicInferencer( 'draggan', model_setting=2, model_ckpt=ckpt_pth, ) else: raise NotImplementedError self.editor = editor # Generate random latents. self.w0_seed = w0_seed self.w_load = w_load if self.w_load is None: # Generate random latents. z = torch.from_numpy(np.random.RandomState(w0_seed).randn( 1, 512)).to(torch.float32).requires_grad_(True) # Run mapping network. sample_kwargs = { 'truncation': trunc_psi, 'return_noise': True, 'return_features': True } extra_parameters = { 'sample_kwargs': sample_kwargs, 'num_batches': 1, 'noise': z, 'sample_model': 'ema', 'infer_with_grad': True } results = self.editor.infer(extra_parameters=extra_parameters) w = results[0]['latent'].unsqueeze(0) # [1, 16, n_dim] else: w = self.w_load.clone().to(self._device) self.w0 = w.detach().clone() self.w_plus = w_plus if w_plus: self.w = w.detach() else: self.w = w[:, 0, :].detach() self.w.requires_grad = True self.w_optim = torch.optim.Adam([self.w], lr=lr) self.feat_refs = None self.points0_pt = None def update_lr(self, lr): del self.w_optim self.w_optim = torch.optim.Adam([self.w], lr=lr) print(f'Rebuild optimizer with lr: {lr}') print(' Remain feat_refs and points0_pt') def _render_drag_impl(self, res, points=[], targets=[], mask=None, lambda_mask=10, reg=0, feature_idx=5, r1=3, r2=12, random_seed=0, noise_mode='const', trunc_psi=0.7, force_fp32=False, layer_name=None, sel_channels=3, base_channel=0, img_scale_db=0, img_normalize=False, untransform=False, is_drag=False, reset=False, to_pil=False, **kwargs): ws = self.w if ws.dim() == 2: ws = ws.unsqueeze(1).repeat(1, 6, 1) ws = torch.cat([ws[:, :6, :], self.w0[:, 6:, :]], dim=1) # [1, 16, n_dim] if hasattr(self, 'points'): if len(points) != len(self.points): reset = True if reset: self.feat_refs = None self.points0_pt = None self.points = points # Run synthesis network. sample_kwargs = { 'truncation': 1, 'return_noise': True, 'return_features': True, 'input_is_latent': True } extra_parameters = { 'sample_kwargs': sample_kwargs, 'num_batches': 1, 'noise': ws[0][:1], 'sample_model': 'ema', 'infer_with_grad': True } results = self.editor.infer(extra_parameters=extra_parameters) img = results[0]['fake_img'].unsqueeze( 0) / 127.5 - 1. # requires_grad==True feat_5 = results[0]['feats'].unsqueeze(0) # requires_grad==True h, w = img.shape[-1], img.shape[-2] if is_drag: X = torch.linspace(0, h, h) Y = torch.linspace(0, w, w) xx, yy = torch.meshgrid(X, Y) feat_resize = F.interpolate(feat_5, [h, w], mode='bilinear') if self.feat_refs is None: self.feat0_resize = F.interpolate( feat_5.detach(), [h, w], mode='bilinear') self.feat_refs = [] for point in points: py, px = round(point[0]), round(point[1]) self.feat_refs.append(self.feat0_resize[:, :, py, px]) self.points0_pt = torch.Tensor(points).unsqueeze(0).to( self._device) # 1, N, 2 # Point tracking with feature matching with torch.no_grad(): for j, point in enumerate(points): r = round(r2 / 512 * h) up = max(point[0] - r, 0) down = min(point[0] + r + 1, h) left = max(point[1] - r, 0) right = min(point[1] + r + 1, w) feat_patch = feat_resize[:, :, up:down, left:right] L2 = torch.linalg.norm( feat_patch - self.feat_refs[j].reshape(1, -1, 1, 1), dim=1) _, idx = torch.min(L2.view(1, -1), -1) width = right - left point = [ idx.item() // width + up, idx.item() % width + left ] points[j] = point res.points = [[point[0], point[1]] for point in points] # Motion supervision loss_motion = 0 res.stop = True for j, point in enumerate(points): direction = torch.Tensor( [targets[j][1] - point[1], targets[j][0] - point[0]]) if torch.linalg.norm(direction) > max(2 / 512 * h, 2): res.stop = False if torch.linalg.norm(direction) > 1: distance = ((xx.to(self._device) - point[0])**2 + (yy.to(self._device) - point[1])**2)**0.5 relis, reljs = torch.where(distance < round(r1 / 512 * h)) direction = direction / ( torch.linalg.norm(direction) + 1e-7) gridh = (relis - direction[1]) / (h - 1) * 2 - 1 gridw = (reljs - direction[0]) / (w - 1) * 2 - 1 grid = torch.stack([gridw, gridh], dim=-1).unsqueeze(0).unsqueeze(0) target = F.grid_sample( feat_resize.float(), grid, align_corners=True).squeeze(2) loss_motion += F.l1_loss(feat_resize[:, :, relis, reljs], target.detach()) loss = loss_motion if mask is not None: if mask.min() == 0 and mask.max() == 1: mask_usq = mask.to(self._device).unsqueeze(0).unsqueeze(0) loss_fix = F.l1_loss(feat_resize * mask_usq, self.feat0_resize * mask_usq) loss += lambda_mask * loss_fix loss += reg * F.l1_loss(ws, self.w0) # latent code regularization if not res.stop: self.w_optim.zero_grad() print(loss) loss.backward() self.w_optim.step() # Scale and convert to uint8. img = img[0] if img_normalize: img = img / img.norm( float('inf'), dim=[1, 2], keepdim=True).clip(1e-8, 1e8) img = img * (10**(img_scale_db / 20)) img = (img * 127.5 + 128).clamp(0, 255).to(torch.uint8).permute(1, 2, 0) if to_pil: from PIL import Image img = img.cpu().numpy() img = Image.fromarray(img) res.image = img res.w = ws.detach().cpu().numpy() ================================================ FILE: docker/Dockerfile ================================================ ARG PYTORCH="1.6.0" ARG CUDA="10.1" ARG CUDA_ALIAS="101" ARG CUDNN="7" ARG MMCV="2.0.0rc1" ARG Usrname="xxx" ARG token="xxx" FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel ENV TORCH_CUDA_ARCH_LIST="6.0 6.1 7.0+PTX" ENV TORCH_NVCC_FLAGS="-Xfatbin -compress-all" ENV CMAKE_PREFIX_PATH="$(dirname $(which conda))/../" RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A4B469963BF863CC RUN apt-get update && apt-get install -y git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Install mmagic RUN conda clean --all RUN git clone https://${Usrname}:${token}@github.com/open-mmlab/mmagic.git /mmagic WORKDIR /mmagic ENV FORCE_CUDA="1" RUN pip install openmim RUN mim install mmcv==${MMCV} RUN pip install -r requirements.txt RUN pip install --no-cache-dir -e . ================================================ FILE: docker/README.md ================================================ # Docker Image We provide a [Dockerfile](Dockerfile) to build an image. ```shell # build an image with PyTorch 1.6, CUDA 10.1 docker build -t mmagic docker/ ``` Run it with ```shell docker run --gpus all --shm-size=8g -it -v {DATA_DIR}:/mmagic/data mmagic ``` **Note**: Versions defined in this [Dockerfile](Dockerfile) is not up-to-date. If you use this Dockerfile in your project, you probably want to make some updates. Feel free to submit an issue or PR for the update. ================================================ FILE: docs/en/.dev_scripts/update_dataset_zoo.py ================================================ import os from tqdm import tqdm def update_dataset_zoo(): target_dir = 'dataset_zoo' source_dir = '../../tools/dataset_converters' os.makedirs(target_dir, exist_ok=True) # generate overview overviewmsg = """ # Overview """ # generate index.rst rstmsg = """ .. toctree:: :maxdepth: 1 :caption: Dataset Zoo overview.md """ subfolders = os.listdir(source_dir) for subf in tqdm(subfolders, desc='update dataset zoo'): target_subf = subf.replace('-', '_').lower() target_readme = os.path.join(target_dir, target_subf + '.md') source_readme = os.path.join(source_dir, subf, 'README.md') if not os.path.exists(source_readme): continue overviewmsg += f'\n- [{subf}]({target_subf}.md)' rstmsg += f'\n {target_subf}.md' # generate all tasks dataset_zoo command = f'cat {source_readme} > {target_readme}' os.popen(command) with open(os.path.join(target_dir, 'overview.md'), 'w') as f: f.write(overviewmsg) with open(os.path.join(target_dir, 'index.rst'), 'w') as f: f.write(rstmsg) if __name__ == '__main__': update_dataset_zoo() ================================================ FILE: docs/en/.dev_scripts/update_model_zoo.py ================================================ #!/usr/bin/env python import os from glob import glob from os import path as osp from pathlib import Path from modelindex.load_model_index import load from tqdm import tqdm MMAGIC_ROOT = Path(__file__).absolute().parents[3] TARGET_ROOT = Path(__file__).absolute().parents[1] / 'model_zoo' def write_file(file, content): os.makedirs(osp.dirname(file), exist_ok=True) with open(file, 'w', encoding='utf-8') as f: f.write(content) def update_model_zoo(): """load collections and models from model index, return summary, collections and models.""" model_index_file = MMAGIC_ROOT / 'model-index.yml' model_index = load(str(model_index_file)) model_index.build_models_with_collections() # parse model_index according to task tasks = {} full_models = set() for model in model_index.models: full_models.add(model.full_model) for r in model.results: _task = r.task.lower().split(', ') for t in _task: if t not in tasks: tasks[t] = set() tasks[t].add(model.full_model) # assert the number of configs with the number of files collections = set([m.in_collection for m in full_models]) assert len(collections) == len(os.listdir(MMAGIC_ROOT / 'configs')) - 1 configs = set([str(MMAGIC_ROOT / m.config) for m in full_models]) base_configs = glob( str(MMAGIC_ROOT / 'configs/_base_/**/*.py'), recursive=True) all_configs = glob(str(MMAGIC_ROOT / 'configs/**/*.py'), recursive=True) valid_configs = set(all_configs) - set(base_configs) untrackable_configs = valid_configs - configs assert len(untrackable_configs) == 0, '/n'.join( list(untrackable_configs)) + ' are not trackable.' # write for overview.md papers = set() checkpoints = set() for m in full_models: papers.add(m.paper['Title']) if m.weights is not None and m.weights.startswith('https:'): checkpoints.add(m.weights) task_desc = '\n'.join([ f" - [{t}]({t.replace('-', '_').replace(' ', '_')}.md)" for t in list(tasks.keys()) ]) # write overview.md overview = (f'# Overview\n\n' f'* Number of checkpoints: {len(checkpoints)}\n' f'* Number of configs: {len(configs)}\n' f'* Number of papers: {len(papers)}\n' f' - ALGORITHM: {len(collections)}\n\n' f'* Tasks:\n{task_desc}') write_file(TARGET_ROOT / 'overview.md', overview) # write for index.rst task_desc = '\n'.join([ f" {t.replace('-', '_').replace(' ', '_')}.md" for t in list(tasks.keys()) ]) overview = (f'.. toctree::\n' f' :maxdepth: 1\n' f' :caption: Model Zoo\n\n' f' overview.md\n' f'{task_desc}') write_file(TARGET_ROOT / 'index.rst', overview) # write for all the tasks for task, models in tqdm(tasks.items(), desc='create markdown files'): target_md = f"{task.replace('-', '_').replace(' ', '_')}.md" target_md = TARGET_ROOT / target_md models = sorted(models, key=lambda x: -x.data['Year']) checkpoints = set() for m in models: if m.weights is not None and m.weights.startswith('https:'): checkpoints.add(m.weights) collections = set([m.in_collection for m in models]) papers = set() for m in models: papers.add(m.paper['Title']) content = '' readme = set() for m in models: if m.readme not in readme: readme.add(m.readme) with open(MMAGIC_ROOT / m.readme, 'r', encoding='utf-8') as f: c = f.read() content += c.replace('# ', '## ') overview = (f'# {task}\n\n' f'## Summary\n' f'* Number of checkpoints: {len(checkpoints)}\n' f'* Number of configs: {len(models)}\n' f'* Number of papers: {len(papers)}\n' f' - ALGORITHM: {len(collections)}\n\n' f'{content}') write_file(target_md, overview) if __name__ == '__main__': update_model_zoo() ================================================ FILE: docs/en/.gitignore ================================================ model_zoo dataset_zoo autoapi ================================================ FILE: docs/en/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile rm -rf _build rm -rf model_zoo rm -rf dataset_zoo @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ================================================ FILE: docs/en/_static/css/readthedocs.css ================================================ .header-logo { background-image: url("../image/mmagic-logo.png"); background-size: 142px 46px; height: 46px; width: 142px; } table.colwidths-auto td { width: 50% } ================================================ FILE: docs/en/_templates/404.html ================================================ {% extends "layout.html" %} {% block body %}

Page Not Found

Oops! The page you are looking for cannot be found.

This is likely to happen when you are switching document versions and the page you are reading is moved to another location in the new version. You can look for it in the content table left, or go to the homepage.

If you cannot find documentation you want, please open an issue to tell us!

{% endblock %} ================================================ FILE: docs/en/_templates/python/attribute.rst ================================================ {% extends "python/data.rst" %} ================================================ FILE: docs/en/_templates/python/class.rst ================================================ {% if obj.display %} .. py:{{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %} {% for (args, return_annotation) in obj.overloads %} {{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %} {% endfor %} {% if obj.bases %} {% if "show-inheritance" in autoapi_options %} Bases: {% for base in obj.bases %}{{ base|link_objs }}{% if not loop.last %}, {% endif %}{% endfor %} {% endif %} {% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %} .. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }} :parts: 1 {% if "private-members" in autoapi_options %} :private-bases: {% endif %} {% endif %} {% endif %} {% if obj.docstring %} {{ obj.docstring|indent(3) }} {% endif %} {% if "inherited-members" in autoapi_options %} {% set visible_classes = obj.classes|selectattr("display")|list %} {% else %} {% set visible_classes = obj.classes|rejectattr("inherited")|selectattr("display")|list %} {% endif %} {% for klass in visible_classes %} {{ klass.render()|indent(3) }} {% endfor %} {% if "inherited-members" in autoapi_options %} {% set visible_properties = obj.properties|selectattr("display")|list %} {% else %} {% set visible_properties = obj.properties|rejectattr("inherited")|selectattr("display")|list %} {% endif %} {% for property in visible_properties %} {{ property.render()|indent(3) }} {% endfor %} {% if "inherited-members" in autoapi_options %} {% set visible_attributes = obj.attributes|selectattr("display")|list %} {% else %} {% set visible_attributes = obj.attributes|rejectattr("inherited")|selectattr("display")|list %} {% endif %} {% for attribute in visible_attributes %} {{ attribute.render()|indent(3) }} {% endfor %} {% if "inherited-members" in autoapi_options %} {% set visible_methods = obj.methods|selectattr("display")|list %} {% else %} {% set visible_methods = obj.methods|rejectattr("inherited")|selectattr("display")|list %} {% endif %} {% for method in visible_methods %} {{ method.render()|indent(3) }} {% endfor %} {% endif %} ================================================ FILE: docs/en/_templates/python/data.rst ================================================ {% if obj.display %} .. py:{{ obj.type }}:: {{ obj.name }} {%+ if obj.value is not none or obj.annotation is not none -%} :annotation: {%- if obj.annotation %} :{{ obj.annotation }} {%- endif %} {%- if obj.value is not none %} = {% if obj.value is string and obj.value.splitlines()|count > 1 -%} Multiline-String .. raw:: html
Show Value .. code-block:: text :linenos: {{ obj.value|indent(width=8) }} .. raw:: html
{%- else -%} {{ obj.value|string|truncate(100) }} {%- endif %} {%- endif %} {% endif %} {{ obj.docstring|indent(3) }} {% endif %} ================================================ FILE: docs/en/_templates/python/exception.rst ================================================ {% extends "python/class.rst" %} ================================================ FILE: docs/en/_templates/python/function.rst ================================================ {% if obj.display %} .. py:function:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %} {% for (args, return_annotation) in obj.overloads %} {{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %} {% endfor %} {% for property in obj.properties %} :{{ property }}: {% endfor %} {% if obj.docstring %} {{ obj.docstring|indent(3) }} {% endif %} {% endif %} ================================================ FILE: docs/en/_templates/python/method.rst ================================================ {%- if obj.display %} .. py:method:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %} {% for (args, return_annotation) in obj.overloads %} {{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %} {% endfor %} {% if obj.properties %} {% for property in obj.properties %} :{{ property }}: {% endfor %} {% else %} {% endif %} {% if obj.docstring %} {{ obj.docstring|indent(3) }} {% endif %} {% endif %} ================================================ FILE: docs/en/_templates/python/module.rst ================================================ {% if not obj.display %} :orphan: {% endif %} :py:mod:`{{ obj.name }}` =========={{ "=" * obj.name|length }} .. py:module:: {{ obj.name }} {% if obj.docstring %} .. autoapi-nested-parse:: {{ obj.docstring|indent(3) }} {% endif %} {% block subpackages %} {% set visible_subpackages = obj.subpackages|selectattr("display")|list %} {% if visible_subpackages %} Subpackages ----------- .. toctree:: :titlesonly: :maxdepth: 3 {% for subpackage in visible_subpackages %} {{ subpackage.short_name }}/index.rst {% endfor %} {% endif %} {% endblock %} {% block submodules %} {% set visible_submodules = obj.submodules|selectattr("display")|list %} {% if visible_submodules %} Submodules ---------- .. toctree:: :titlesonly: :maxdepth: 1 {% for submodule in visible_submodules %} {{ submodule.short_name }}/index.rst {% endfor %} {% endif %} {% endblock %} {% block content %} {% if obj.all is not none %} {% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %} {% elif obj.type is equalto("package") %} {% set visible_children = obj.children|selectattr("display")|list %} {% else %} {% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %} {% endif %} {% if visible_children %} {{ obj.type|title }} Contents {{ "-" * obj.type|length }}--------- {% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %} {% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %} {% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %} {% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %} {% block classes scoped %} {% if visible_classes %} Classes ~~~~~~~ .. autoapisummary:: {% for klass in visible_classes %} {{ klass.id }} {% endfor %} {% endif %} {% endblock %} {% block functions scoped %} {% if visible_functions %} Functions ~~~~~~~~~ .. autoapisummary:: {% for function in visible_functions %} {{ function.id }} {% endfor %} {% endif %} {% endblock %} {% block attributes scoped %} {% if visible_attributes %} Attributes ~~~~~~~~~~ .. autoapisummary:: {% for attribute in visible_attributes %} {{ attribute.id }} {% endfor %} {% endif %} {% endblock %} {% endif %} {% for obj_item in visible_children %} {{ obj_item.render()|indent(0) }} {% endfor %} {% endif %} {% endblock %} ================================================ FILE: docs/en/_templates/python/package.rst ================================================ {% extends "python/module.rst" %} ================================================ FILE: docs/en/_templates/python/property.rst ================================================ {%- if obj.display %} .. py:property:: {{ obj.short_name }} {% if obj.annotation %} :type: {{ obj.annotation }} {% endif %} {% if obj.properties %} {% for property in obj.properties %} :{{ property }}: {% endfor %} {% endif %} {% if obj.docstring %} {{ obj.docstring|indent(3) }} {% endif %} {% endif %} ================================================ FILE: docs/en/advanced_guides/data_flow.md ================================================ # Data flow - [Data Flow](#data-flow) - [Overview of dataflow](#overview-of-data-flow) - [Data flow between dataset and model](#data-flow-between-dataset-and-model) - [Data from dataloader](#data-from-dataloader) - [Data from data preprocessor](#data-from-data-preprocessor) - [Data flow between model output and visualizer](#data-flow-between-model-output-and-visualizer) ## Overview of dataflow The [Runner](https://github.com/open-mmlab/mmengine/blob/main/docs/en/design/runner.md) is an "integrator" in MMEngine. It covers all aspects of the framework and shoulders the responsibility of organizing and scheduling nearly all modules, that means the dataflow between all modules also controlled by the `Runner`. As illustrated in the [Runner document of MMEngine](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html), the following diagram shows the basic dataflow. In this chapter, we will introduce the dataflow and data format convention between the internal modules managed by the [Runner](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html).
In the above diagram, at each training iteration, dataloader loads images from storage and transfer to data preprocessor, data preprocessor would put images to the specific device and stack data to batch, then model accepts the batch data as inputs, finally the outputs of the model would be compute the loss. Since model parameters are freezed when doing evaluation, the model output would be transferred to [Evaluator](./evaluation.md#ioumetric) to compute metrics or seed the data to visualize in [Visualizer](../user_guides/visualization.md). ## Data flow between dataset and model In this section, we will introduce the data flow passing in the dataset in MMagic. About [dataset](https://mmagic.readthedocs.io/en/latest/howto/dataset.html) and \[transforms\] pipeline (https://mmagic.readthedocs.io/en/latest/howto/transforms.html) related tutorials can be found in the development of guidelines.The data flow between dataloader and model can be generally split into four parts: 1. Read the original information of `XXDataset` collected datasets, and carry out data conversion processing through data transform pipeline; 2. use `PackInputs` to pack data from previous transformations into a dictionar; 3. use `collate_fn` to stack a list of tensors into a batched tensor; 4. use `data preprocessor` to move all these data to target device, e.g. GPUS, and unzip the dictionary from the dataloader into a tuple, containing the input images and meta info (`DataSample`). ### Data from transform pipeline In MMagic, different types of 'XXDataset' load the data (LQ) and label (GT), and perform data transformation in different data preprocessing pipelines, and finally package the processed data into a dictionary through `PackInputs`, which contains all the data required for training and testing iterations.
base_edit_model.py base_conditional_gan.py
```python @MODELS.register_module() class BaseEditModel(BaseModel): """Base model for image and video editing. """ def forward(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs) -> Union[torch.Tensor, List[DataSample], dict]: if isinstance(inputs, dict): inputs = inputs['img'] if mode == 'tensor': return self.forward_tensor(inputs, data_samples, **kwargs) elif mode == 'predict': predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'loss': return self.forward_train(inputs, data_samples, **kwargs) ``` ```python @MODELS.register_module() class BaseConditionalGAN(BaseGAN): """Base class for Conditional GAM models. """ def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: if isinstance(inputs, Tensor): noise = inputs sample_kwargs = {} else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) sample_kwargs = inputs.get('sample_kwargs', dict()) num_batches = noise.shape[0] pass ... ```
For example, in the `BaseEditModel` and `BaseConditionalGAN` models, key input including `img` and `noise` are required. At the same time, the corresponding fields should also be exposed in the configuration file,[cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py](../../../configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py) as an example, ### Data from dataloader After receiving a list of dictionary from dataset, `collect_fn` in dataloader will gather `inputs` in each dict and stack them into a batched tensor. In addition, `data_sample` in each dict will be also collected in a list. Then, it will output a dict, containing the same keys with those of the dict in the received list. Finally, dataloader will output the dict from the `collect_fn`. Detailed documentation can be reference [DATASET AND DATALOADER](https://mmengine.readthedocs.io/en/latest/tutorials/dataset.html)。 ### Data from data preprocessor Data preprocessor is the last step to process the data before feeding into the model. It will apply image normalization, convert BGR to RGB and move all data to the target device, e.g. GPUs. After above steps, it will output a tuple, containing a list of batched images, and a list of data samples. Detailed documentation can be reference [data_preprocessor](./data_preprocessor.md)。 ## Data flow between model output and visualizer MMEngine agreed [Abstract Data Element](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/data_element.md) for data transfer Where [data sample](./structures.md) as a more advanced encapsulation can hold more categories of label data. In MMagic, `ConcatImageVisualizer` for visual comparison also controls the visual content through the `add_datasample` function. The specific configuration is as follows. ```python visualizer = dict( type='ConcatImageVisualizer', vis_backends=[dict(type='LocalVisBackend')], fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) ``` ================================================ FILE: docs/en/advanced_guides/data_preprocessor.md ================================================ # Data pre-processor ## The position of the data preprocessor in the training pipeline. During the model training process, image data undergoes data augmentation using the transforms provided by mmcv. The augmented data is then loaded into a dataloader. Subsequently, a preprocessor is used to move the data from the CPU to CUDA (GPU), perform padding, and normalize the data. Below is an example of the `train_pipeline` in the complete configuration file using `configs/_base_/datasets/unpaired_imgs_256x256.py`. The train_pipeline typically defines a sequence of transformations applied to training images using the mmcv library. This pipeline is designed to prevent redundancy in the transformation functions across different downstream algorithm libraries. ```python ... train_pipeline = [ dict(color_type='color', key='img_A', type='LoadImageFromFile'), dict(color_type='color', key='img_B', type='LoadImageFromFile'), dict(auto_remap=True, mapping=dict(img=['img_A', 'img_B',]), share_random_params=True, transforms=[dict(interpolation='bicubic', scale=(286, 286,), type='Resize'), dict(crop_size=(256, 256,), keys=['img',], random_crop=True, type='Crop'),], type='TransformBroadcaster'), dict(direction='horizontal', keys=['img_A', ], type='Flip'), dict(direction='horizontal', keys=['img_B', ], type='Flip'), dict(mapping=dict(img_mask='img_B', img_photo='img_A'), remapping=dict(img_mask='img_mask', img_photo='img_photo'), type='KeyMapper'), dict(data_keys=['img_photo', 'img_mask',], keys=['img_photo', 'img_mask',], type='PackInputs'), ] ... ``` In the `train_step` function in the `mmagic/models/editors/cyclegan/cyclegan.py` script, the data preprocessing steps involve moving, concatenating, and normalizing the transformed data before feeding it into the neural network. Below is an example of the relevant code logic: ```python ... message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper = optim_wrapper['discriminators'] inputs_dict = data['inputs'] outputs, log_vars = dict(), dict() ... ``` In mmagic, the code implementation for the data processor is located at `mmagic/models/data_preprocessors/data_preprocessor.py`. The data processing workflow is as follows: ![image](https://github.com/jinxianwei/CloudImg/assets/81373517/f52a92ab-f86d-486d-86ac-a2f388a83ced) ================================================ FILE: docs/en/advanced_guides/evaluator.md ================================================ # Evaluator ## Evaluation Metrics and Evaluators In model validation and testing, it is usually necessary to quantitatively evaluate the accuracy of the model. In mmagic, the evaluation metrics and evaluators are implemented to accomplish this functionality. - Evaluation metrics are used to calculate specific model accuracy indicators based on test data and model prediction results. mmagic provides a variety of built-in metrics, which can be found in the metrics documentation. Additionally, metrics are decoupled from datasets and can be used for multiple datasets. - The evaluator is the top-level module for evaluation metrics and usually contains one or more metrics. The purpose of the evaluator is to perform necessary data format conversion and call evaluation metrics to calculate the model accuracy during model evaluation. The evaluator is typically built by a `Runner` or a testing script, which are used for online evaluation and offline evaluation, respectively. The evaluator in MMagic inherits from that in MMEngine and has a similar basic usage. For specific information, you can refer to [Model Accuracy Evaluation](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html). However, different from other high-level vision tasks, the evaluation metrics for generative models often have multiple inputs. For example, the input for the Inception Score (IS) metric is only fake images and any number of real images, while the Perceptual Path Length (PPL) requires sampling from the latent space. To accommodate different evaluation metrics, mmagic introduces two important methods, `prepare_metrics` and `prepare_samplers` to meet the above requirements. ## prepare_metrics ```python class Evaluator(Evaluator): ... def prepare_metrics(self, module: BaseModel, dataloader: DataLoader): """Prepare for metrics before evaluation starts. Some metrics use pretrained model to extract feature. Some metrics use pretrained model to extract feature and input channel order may vary among those models. Therefore, we first parse the output color order from data preprocessor and set the color order for each metric. Then we pass the dataloader to each metrics to prepare pre-calculated items. (e.g. inception feature of the real images). If metric has no pre-calculated items, :meth:`metric.prepare` will be ignored. Once the function has been called, :attr:`self.is_ready` will be set as `True`. If :attr:`self.is_ready` is `True`, this function will directly return to avoid duplicate computation. Args: module (BaseModel): Model to evaluate. dataloader (DataLoader): The dataloader for real images. """ if self.metrics is None: self.is_ready = True return if self.is_ready: return # prepare metrics for metric in self.metrics: metric.prepare(module, dataloader) self.is_ready = True ``` The `prepare_metrics` method needs to be called before the evaluation starts. It is used to preprocess before evaluating each metric, and will sequentially call the prepare method of each metric in the evaluator to prepare any pre-calculated elements needed for that metric (such as features from hidden layers). Additionally, to avoid repeated calls, the `evaluator.is_ready` flag will be set to True after preprocessing for all metrics is completed. ```python class GenMetric(BaseMetric): ... def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: """Prepare for the pre-calculating items of the metric. Defaults to do nothing. Args: module (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for the real images. """ if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor ``` ## prepare_samplers Different metrics require different inputs for generative models. For example, FID, KID, and IS only need the generated fake images, while PPL requires vectors from the latent space. Therefore, mmagic groups different evaluation metrics based on the type of input. One or more evaluation metrics in the same group share a data sampler. The sampler mode for each evaluation metric is determined by the `SAMPLER_MODE` attribute of that metric. ```python class GenMetric(BaseMetric): ... SAMPLER_MODE = 'normal' class GenerativeMetric(GenMetric): ... SAMPLER_MODE = 'Generative' ``` The `prepare_samplers` method of the evaluator is responsible for preparing the data samplers based on the sampler mode of all evaluation metrics. ```python class Evaluator(Evaluator): ... def prepare_samplers(self, module: BaseModel, dataloader: DataLoader ) -> List[Tuple[List[BaseMetric], Iterator]]: """Prepare for the sampler for metrics whose sampling mode are different. For generative models, different metric need image generated with different inputs. For example, FID, KID and IS need images generated with random noise, and PPL need paired images on the specific noise interpolation path. Therefore, we first group metrics with respect to their sampler's mode (refers to :attr:~`GenMetrics.SAMPLER_MODE`), and build a shared sampler for each metric group. To be noted that, the length of the shared sampler depends on the metric of the most images required in each group. Args: module (BaseModel): Model to evaluate. Some metrics (e.g. PPL) require `module` in their sampler. dataloader (DataLoader): The dataloader for real image. Returns: List[Tuple[List[BaseMetric], Iterator]]: A list of "metrics-shared sampler" pair. """ if self.metrics is None: return [[[None], []]] # grouping metrics based on `SAMPLER_MODE` and `sample_mode` metric_mode_dict = defaultdict(list) for metric in self.metrics: # Specify a sampler group for each metric. metric_md5 = self._cal_metric_hash(metric) metric_mode_dict[metric_md5].append(metric) metrics_sampler_list = [] for metrics in metric_mode_dict.values(): # Generate a sampler for each group. first_metric = metrics[0] metrics_sampler_list.append([ metrics, first_metric.get_metric_sampler(module, dataloader, metrics) ]) return metrics_sampler_list ``` The method will first check if it has any evaluation metrics to calculate: if not, it will return directly. If there are metrics to calculate, it will iterate through all the evaluation metrics and group them based on the sampler_mode and sample_model. The specific implementation is as follows: it calculates a hash code based on the sampler_mode and sample_model, and puts the evaluation metrics with the same hash code into the same list. ```python class Evaluator(Evaluator): ... @staticmethod def _cal_metric_hash(metric: GenMetric): """Calculate a unique hash value based on the `SAMPLER_MODE` and `sample_model`.""" sampler_mode = metric.SAMPLER_MODE sample_model = metric.sample_model metric_dict = { 'SAMPLER_MODE': sampler_mode, 'sample_model': sample_model } if hasattr(metric, 'need_cond_input'): metric_dict['need_cond_input'] = metric.need_cond_input md5 = hashlib.md5(repr(metric_dict).encode('utf-8')).hexdigest() return md5 ``` Finally, this method will generate a sampler for each evaluation metric group and add it to a list to return. ## Evaluation process of an evaluator The implementation of evaluation process can be found in `mmagic.engine.runner.MultiValLoop.run` and `mmagic.engine.runner.MultiTestLoop.run`. Here we take `mmagic.engine.runner.MultiValLoop.run` as example. ```python class MultiValLoop(BaseLoop): ... def run(self): ... # 1. prepare all metrics and get the total length metrics_sampler_lists = [] meta_info_list = [] dataset_name_list = [] for evaluator, dataloader in zip(self.evaluators, self.dataloaders): # 1.1 prepare for metrics evaluator.prepare_metrics(module, dataloader) # 1.2 prepare for metric-sampler pair metrics_sampler_list = evaluator.prepare_samplers( module, dataloader) metrics_sampler_lists.append(metrics_sampler_list) # 1.3 update total length self._total_length += sum([ len(metrics_sampler[1]) for metrics_sampler in metrics_sampler_list ]) # 1.4 save metainfo and dataset's name meta_info_list.append( getattr(dataloader.dataset, 'metainfo', None)) dataset_name_list.append(dataloader.dataset.__class__.__name__) ``` First, the runner will perform preprocessing and obtain the necessary data samplers for evaluation using the `evaluator.prepare_metric` and `evaluator.prepare_samplers` methods. It will also update the total length of samples obtained using the samplers. As the evaluation metrics and dataset in mmagic are separated, some meta_info required for evaluation also needs to be saved and passed to the evaluator. ```python class MultiValLoop(BaseLoop): ... def run(self): ... # 2. run evaluation for idx in range(len(self.evaluators)): # 2.1 set self.evaluator for run_iter self.evaluator = self.evaluators[idx] self.dataloader = self.dataloaders[idx] # 2.2 update metainfo for evaluator and visualizer meta_info = meta_info_list[idx] dataset_name = dataset_name_list[idx] if meta_info: self.evaluator.dataset_meta = meta_info self._runner.visualizer.dataset_meta = meta_info else: warnings.warn( f'Dataset {dataset_name} has no metainfo. `dataset_meta` ' 'in evaluator, metric and visualizer will be None.') # 2.3 generate images metrics_sampler_list = metrics_sampler_lists[idx] for metrics, sampler in metrics_sampler_list: for data in sampler: self.run_iter(idx_counter, data, metrics) idx_counter += 1 # 2.4 evaluate metrics and update multi_metric metrics = self.evaluator.evaluate() if multi_metric and metrics.keys() & multi_metric.keys(): raise ValueError('Please set different prefix for different' ' datasets in `val_evaluator`') else: multi_metric.update(metrics) # 3. finish evaluation and call hooks self._runner.call_hook('after_val_epoch', metrics=multi_metric) self._runner.call_hook('after_val') ``` After the preparation for evaluation is completed, the runner will iterate through all the evaluators and perform the evaluation one by one. Each evaluator needs to correspond to a data loader to complete the evaluation work for a dataset. Specifically, during the evaluation process for each evaluator, it is necessary to pass the required meta_info to the evaluator, then iterate through all the metrics_samplers of this evaluator to generate the images needed for evaluation, and finally complete the evaluation. ================================================ FILE: docs/en/advanced_guides/structures.md ================================================ # Data Structure `DataSample` , the data structure interface of MMagic, inherits from [` BaseDataElement`](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/data_element.html). The base class has implemented basic add/delete/update/check functions and supports data migration between different devices, as well as dictionary-like and tensor-like operations, which also allows the interfaces of different algorithms to be unified. Specifically, an instance of BaseDataElement consists of two components: - `metainfo`, which contains some meta information, e.g., `img_shape`, `img_id`, `color_order`, etc. - `data`, which contains the data used in the loop. Thanks to ` DataSample` , the data flow between each module in the algorithm libraries, such as [`visualizer`](https://mmagic.readthedocs.io/en/latest/user_guides/visualization.html), [`evaluator`](https://mmagic.readthedocs.io/en/latest/advanced_guides/evaluator.html), [`model`](https://mmagic.readthedocs.io/en/latest/howto/models.html), is greatly simplified. The attributes in `DataSample` are divided into several parts: ```python - ``gt_img``: Ground truth image(s). - ``pred_img``: Image(s) of model predictions. - ``ref_img``: Reference image(s). - ``mask``: Mask in Inpainting. - ``trimap``: Trimap in Matting. - ``gt_alpha``: Ground truth alpha image in Matting. - ``pred_alpha``: Predicted alpha image in Matting. - ``gt_fg``: Ground truth foreground image in Matting. - ``pred_fg``: Predicted foreground image in Matting. - ``gt_bg``: Ground truth background image in Matting. - ``pred_bg``: Predicted background image in Matting. - ``gt_merged``: Ground truth merged image in Matting. ``` The following sample code demonstrates the components of `DataSample`: ```python >>> import torch >>> import numpy as np >>> from mmagic.structures import DataSample >>> img_meta = dict(img_shape=(800, 1196, 3)) >>> img = torch.rand((3, 800, 1196)) >>> data_sample = DataSample(gt_img=img, metainfo=img_meta) >>> assert 'img_shape' in data_sample.metainfo_keys() >>> data_sample >>># metainfo and data of DataSample ``` We also support `stack` and `split` operation to handle a batch of data samples. 1. Stack Stack a list of data samples to one. All tensor fields will be stacked at first dimension. Otherwise the values will be saved in a list. ``` Args: data_samples (Sequence['DataSample']): A sequence of `DataSample` to stack. Returns: DataSample: The stacked data sample. ``` 2. Split Split a sequence of data sample in the first dimension. ``` Args: allow_nonseq_value (bool): Whether allow non-sequential data in split operation. If True, non-sequential data will be copied for all split data samples. Otherwise, an error will be raised. Defaults to False. Returns: Sequence[DataSample]: The list of data samples after splitting. ``` The following sample code demonstrates the use of `stack` and ` split`: ```py import torch import numpy as np from mmagic.structures import DataSample img_meta1 = img_meta2 = dict(img_shape=(800, 1196, 3)) img1 = torch.rand((3, 800, 1196)) img2 = torch.rand((3, 800, 1196)) data_sample1 = DataSample(gt_img=img1, metainfo=img_meta1) data_sample2 = DataSample(gt_img=img2, metainfo=img_meta1) ``` ```py # stack them and then use as batched-tensor! data_sample = DataSample.stack([data_sample1, data_sample2]) print(data_sample.gt_img.shape) torch.Size([2, 3, 800, 1196]) print(data_sample.metainfo) {'img_shape': [(800, 1196, 3), (800, 1196, 3)]} # split them if you want data_sample1_, data_sample2_ = data_sample.split() assert (data_sample1_.gt_img == img1).all() assert (data_sample2_.gt_img == img2).all() ``` ================================================ FILE: docs/en/changelog.md ================================================ # Changelog **Highlights** - An advanced and powerful inpainting algorithm named PowerPaint is released in our repository. [Click to View](https://github.com/open-mmlab/mmagic/tree/main/projects/powerpaint)
**New Features & Improvements** - \[Release\] Post release for v1.1.0 by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2043 - \[CodeCamp2023-645\]Add dreambooth new cfg by @YanxingLiu in https://github.com/open-mmlab/mmagic/pull/2042 - \[Enhance\] add new config for _base_ dir by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2053 - \[Enhance\] support using from_pretrained for instance_crop by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2066 - \[Enhance\] update support for latest diffusers with lora by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2067 - \[Feature\] PowerPaint by @zhuang2002 in https://github.com/open-mmlab/mmagic/pull/2076 - \[Enhance\] powerpaint improvement by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2078 - \[Enhance\] Improve powerpaint by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2080 - \[Enhance\] add outpainting to gradio_PowerPaint.py by @zhuang2002 in https://github.com/open-mmlab/mmagic/pull/2084 - \[MMSIG\] Add new configuration files for StyleGAN2 by @xiaomile in https://github.com/open-mmlab/mmagic/pull/2057 - \[MMSIG\] \[Doc\] Update data_preprocessor.md by @jinxianwei in https://github.com/open-mmlab/mmagic/pull/2055 - \[Enhance\] Enhance PowerPaint by @zhuang2002 in https://github.com/open-mmlab/mmagic/pull/2093 **Bug Fixes** - \[Fix\] Update README.md by @eze1376 in https://github.com/open-mmlab/mmagic/pull/2048 - \[Fix\] Fix test tokenizer by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2050 - \[Fix\] fix readthedocs building by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2052 - \[Fix\] --local-rank for PyTorch >= 2.0.0 by @youqingxiaozhua in https://github.com/open-mmlab/mmagic/pull/2051 - \[Fix\] animatediff download from openxlab by @JianxinDong in https://github.com/open-mmlab/mmagic/pull/2061 - \[Fix\] fix best practice by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2063 - \[Fix\] try import expand mask from transformers by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2064 - \[Fix\] Update diffusers to v0.23.0 by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2069 - \[Fix\] add openxlab link to powerpaint by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2082 - \[Fix\] Update swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py, use MultiValLoop. by @ashutoshsingh0223 in https://github.com/open-mmlab/mmagic/pull/2085 - \[Fix\] Fix a test expression that has a logical short circuit. by @munahaf in https://github.com/open-mmlab/mmagic/pull/2046 - \[Fix\] Powerpaint to load safetensors by @sdbds in https://github.com/open-mmlab/mmagic/pull/2088 **New Contributors** - @eze1376 made their first contribution in https://github.com/open-mmlab/mmagic/pull/2048 - @youqingxiaozhua made their first contribution in https://github.com/open-mmlab/mmagic/pull/2051 - @JianxinDong made their first contribution in https://github.com/open-mmlab/mmagic/pull/2061 - @zhuang2002 made their first contribution in https://github.com/open-mmlab/mmagic/pull/2076 - @ashutoshsingh0223 made their first contribution in https://github.com/open-mmlab/mmagic/pull/2085 - @jinxianwei made their first contribution in https://github.com/open-mmlab/mmagic/pull/2055 - @munahaf made their first contribution in https://github.com/open-mmlab/mmagic/pull/2046 - @sdbds made their first contribution in https://github.com/open-mmlab/mmagic/pull/2088 **Full Changelog**: https://github.com/open-mmlab/mmagic/compare/v1.1.0...v1.2.0 ## v1.1.0 (22/09/2023) **Highlights** In this new version of MMagic, we have added support for the following five new algorithms. - Support ViCo, a new SD personalization method. [Click to View](https://github.com/open-mmlab/mmagic/blob/main/configs/vico/README.md)

- Support AnimateDiff, a popular text2animation method. [Click to View](https://github.com/open-mmlab/mmagic/blob/main/configs/animatediff/README.md) ![512](https://github.com/ElliotQi/mmagic/assets/46469021/54d92aca-dfa9-4eeb-ba38-3f6c981e5399) - Support SDXL. [Click to View](https://github.com/open-mmlab/mmagic/blob/main/configs/stable_diffusion_xl/README.md)
- Support DragGAN implementation with MMagic. [Click to View](https://github.com/open-mmlab/mmagic/blob/main/configs/draggan/README.md)
- Support for FastComposer. [Click to View](https://github.com/open-mmlab/mmagic/blob/main/configs/fastcomposer/README.md)
**New Features & Improvements** - \[Feature\] Support inference with diffusers pipeline, sd_xl first. by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2023 - \[Enhance\] add negative prompt for sd inferencer by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2021 - \[Enhance\] Update flake8 checking config in setup.cfg by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/2007 - \[Enhance\] Add ‘config_name' as a supplement to the 'model_setting' by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2027 - \[Enhance\] faster test by @okotaku in https://github.com/open-mmlab/mmagic/pull/2034 - \[Enhance\] Add OpenXLab Badge by @ZhaoQiiii in https://github.com/open-mmlab/mmagic/pull/2037 **CodeCamp Contributions** - \[CodeCamp2023-643\] Add new configs of BigGAN by @limafang in https://github.com/open-mmlab/mmagic/pull/2003 - \[CodeCamp2023-648\] MMagic new config GuidedDiffusion by @ooooo-create in https://github.com/open-mmlab/mmagic/pull/2005 - \[CodeCamp2023-649\] MMagic new config Instance Colorization by @ooooo-create in https://github.com/open-mmlab/mmagic/pull/2010 - \[CodeCamp2023-652\] MMagic new config StyleGAN3 by @hhy150 in https://github.com/open-mmlab/mmagic/pull/2018 - \[CodeCamp2023-653\] Add new configs of Real BasicVSR by @RangeKing in https://github.com/open-mmlab/mmagic/pull/2030 **Bug Fixes** - \[Fix\] Fix best practice and back to contents on mainpage, add new models to model zoo by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2001 - \[Fix\] Check CI error and remove main stream gpu test by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2013 - \[Fix\] Check circle ci memory by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2016 - \[Fix\] remove code and fix clip loss ut test by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2017 - \[Fix\] mock infer in diffusers pipeline inferencer ut. by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2026 - \[Fix\] Fix bug caused by merging draggan by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2029 - \[Fix\] Update QRcode by @crazysteeaam in https://github.com/open-mmlab/mmagic/pull/2009 - \[Fix\] Replace the download links in README with OpenXLab version by @FerryHuang in https://github.com/open-mmlab/mmagic/pull/2038 - \[Fix\] Increase docstring coverage by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2039 **New Contributors** - @limafang made their first contribution in https://github.com/open-mmlab/mmagic/pull/2003 - @ooooo-create made their first contribution in https://github.com/open-mmlab/mmagic/pull/2005 - @hhy150 made their first contribution in https://github.com/open-mmlab/mmagic/pull/2018 - @ZhaoQiiii made their first contribution in https://github.com/open-mmlab/mmagic/pull/2037 - @ElliotQi made their first contribution in https://github.com/open-mmlab/mmagic/pull/1980 - @Beaconsyh08 made their first contribution in https://github.com/open-mmlab/mmagic/pull/2012 **Full Changelog**: https://github.com/open-mmlab/mmagic/compare/v1.0.2...v1.0.3 ## v1.0.2 (24/08/2023) **Highlights** **1. More detailed documentation** Thank you to the community contributors for helping us improve the documentation. We have improved many documents, including both Chinese and English versions. Please refer to the [documentation](https://mmagic.readthedocs.io/en/latest/) for more details. **2. New algorithms** - Support Prompt-to-prompt, DDIM Inversion and Null-text Inversion. [Click to View.](https://github.com/open-mmlab/mmagic/blob/main/projects/prompt_to_prompt/README.md) From right to left: origin image, DDIM inversion, Null-text inversion
Prompt-to-prompt Editing
cat -> dog
spider man -> iron man(attention replace)
Effel tower -> Effel tower at night (attention refine)
blossom sakura tree -> blossom(-3) sakura tree (attention reweight)
- Support Textual Inversion. [Click to view.](https://github.com/open-mmlab/mmagic/blob/main/configs/textual_inversion/README.md)
- Support Attention Injection for more stable video generation with controlnet. [Click to view.](https://github.com/open-mmlab/mmagic/blob/main/configs/controlnet_animation/README.md) - Support Stable Diffusion Inpainting. [Click to view.](https://github.com/open-mmlab/mmagic/blob/main/configs/stable_diffusion/README.md) **New Features & Improvements** - \[Enhancement\] Support noise offset in stable diffusion training by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1880 - \[Community\] Support Glide Upsampler by @Taited in https://github.com/open-mmlab/mmagic/pull/1663 - \[Enhance\] support controlnet inferencer by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1891 - \[Feature\] support Albumentations augmentation transformations and pipeline by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1894 - \[Feature\] Add Attention Injection for unet by @liuwenran in https://github.com/open-mmlab/mmagic/pull/1895 - \[Enhance\] update benchmark scripts by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1907 - \[Enhancement\] update mmagic docs by @crazysteeaam in https://github.com/open-mmlab/mmagic/pull/1920 - \[Enhancement\] Support Prompt-to-prompt, ddim inversion and null-text inversion by @FerryHuang in https://github.com/open-mmlab/mmagic/pull/1908 - \[CodeCamp2023-302\] Support MMagic visualization and write a user guide by @aptsunny in https://github.com/open-mmlab/mmagic/pull/1939 - \[Feature\] Support Textual Inversion by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1822 - \[Feature\] Support stable diffusion inpaint by @Taited in https://github.com/open-mmlab/mmagic/pull/1976 - \[Enhancement\] Adopt `BaseModule` for some models by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1543 - \[MMSIG\]支持 DeblurGANv2 inference by @xiaomile in https://github.com/open-mmlab/mmagic/pull/1955 - \[CodeCamp2023-647\] Add new configs of EG3D by @RangeKing in https://github.com/open-mmlab/mmagic/pull/1985 **Bug Fixes** - Fix dtype error in StableDiffusion and DreamBooth training by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1879 - Fix gui VideoSlider bug by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1885 - Fix init_model and glide demo by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1888 - Fix InstColorization bug when dim=3 by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1901 - Fix sd and controlnet fp16 bugs by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1914 - Fix num_images_per_prompt in controlnet by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1936 - Revise metafile for sd-inpainting to fix inferencer init by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1995 **New Contributors** - @wyyang23 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1886 - @yehuixie made their first contribution in https://github.com/open-mmlab/mmagic/pull/1912 - @crazysteeaam made their first contribution in https://github.com/open-mmlab/mmagic/pull/1920 - @BUPT-NingXinyu made their first contribution in https://github.com/open-mmlab/mmagic/pull/1921 - @zhjunqin made their first contribution in https://github.com/open-mmlab/mmagic/pull/1918 - @xuesheng1031 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1923 - @wslgqq277g made their first contribution in https://github.com/open-mmlab/mmagic/pull/1934 - @LYMDLUT made their first contribution in https://github.com/open-mmlab/mmagic/pull/1933 - @RangeKing made their first contribution in https://github.com/open-mmlab/mmagic/pull/1930 - @xin-li-67 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1932 - @chg0901 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1931 - @aptsunny made their first contribution in https://github.com/open-mmlab/mmagic/pull/1939 - @YanxingLiu made their first contribution in https://github.com/open-mmlab/mmagic/pull/1943 - @tackhwa made their first contribution in https://github.com/open-mmlab/mmagic/pull/1937 - @Geo-Chou made their first contribution in https://github.com/open-mmlab/mmagic/pull/1940 - @qsun1 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1956 - @ththth888 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1961 - @sijiua made their first contribution in https://github.com/open-mmlab/mmagic/pull/1967 - @MING-ZCH made their first contribution in https://github.com/open-mmlab/mmagic/pull/1982 - @AllYoung made their first contribution in https://github.com/open-mmlab/mmagic/pull/1996 ## v1.0.1 (26/05/2023) **New Features & Improvements** - Support tomesd for StableDiffusion speed-up. [#1801](https://github.com/open-mmlab/mmagic/pull/1801) - Support all inpainting/matting/image restoration models inferencer. [#1833](https://github.com/open-mmlab/mmagic/pull/1833), [#1873](https://github.com/open-mmlab/mmagic/pull/1873) - Support animated drawings at projects. [#1837](https://github.com/open-mmlab/mmagic/pull/1837) - Support Style-Based Global Appearance Flow for Virtual Try-On at projects. [#1786](https://github.com/open-mmlab/mmagic/pull/1786) - Support tokenizer wrapper and support EmbeddingLayerWithFixe. [#1846](https://github.com/open-mmlab/mmagic/pull/1846) **Bug Fixes** - Fix install requirements. [#1819](https://github.com/open-mmlab/mmagic/pull/1819) - Fix inst-colorization PackInputs. [#1828](https://github.com/open-mmlab/mmagic/pull/1828), [#1827](https://github.com/open-mmlab/mmagic/pull/1827) - Fix inferencer in pip-install. [#1875](https://github.com/open-mmlab/mmagic/pull/1875) **New Contributors** - @XDUWQ made their first contribution in https://github.com/open-mmlab/mmagic/pull/1830 - @FerryHuang made their first contribution in https://github.com/open-mmlab/mmagic/pull/1786 - @bobo0810 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1851 - @jercylew made their first contribution in https://github.com/open-mmlab/mmagic/pull/1874 ## v1.0.0 (25/04/2023) We are excited to announce the release of MMagic v1.0.0 that inherits from [MMEditing](https://github.com/open-mmlab/mmediting) and [MMGeneration](https://github.com/open-mmlab/mmgeneration). ![mmagic-log](https://user-images.githubusercontent.com/49083766/233557648-9034f5a0-c85d-4092-b700-3a28072251b6.png) Since its inception, MMEditing has been the preferred algorithm library for many super-resolution, editing, and generation tasks, helping research teams win more than 10 top international competitions and supporting over 100 GitHub ecosystem projects. After iterative updates with OpenMMLab 2.0 framework and merged with MMGeneration, MMEditing has become a powerful tool that supports low-level algorithms based on both GAN and CNN. Today, MMEditing embraces Generative AI and transforms into a more advanced and comprehensive AIGC toolkit: **MMagic** (**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation). In MMagic, we have supported 53+ models in multiple tasks such as fine-tuning for stable diffusion, text-to-image, image and video restoration, super-resolution, editing and generation. With excellent training and experiment management support from [MMEngine](https://github.com/open-mmlab/mmengine), MMagic will provide more agile and flexible experimental support for researchers and AIGC enthusiasts, and help you on your AIGC exploration journey. With MMagic, experience more magic in generation! Let's open a new era beyond editing together. More than Editing, Unlock the Magic! **Highlights** **1. New Models** We support 11 new models in 4 new tasks. - Text2Image / Diffusion - ControlNet - DreamBooth - Stable Diffusion - Disco Diffusion - GLIDE - Guided Diffusion - 3D-aware Generation - EG3D - Image Restoration - NAFNet - Restormer - SwinIR - Image Colorization - InstColorization https://user-images.githubusercontent.com/49083766/233564593-7d3d48ed-e843-4432-b610-35e3d257765c.mp4 **2. Magic Diffusion Model** For the Diffusion Model, we provide the following "magic" : - Support image generation based on Stable Diffusion and Disco Diffusion. - Support Finetune methods such as Dreambooth and DreamBooth LoRA. - Support controllability in text-to-image generation using ControlNet. ![de87f16f-bf6d-4a61-8406-5ecdbb9167b6](https://user-images.githubusercontent.com/49083766/233558077-2005e603-c5a8-49af-930f-e7a465ca818b.png) - Support acceleration and optimization strategies based on xFormers to improve training and inference efficiency. - Support video generation based on MultiFrame Render. MMagic supports the generation of long videos in various styles through ControlNet and MultiFrame Render. prompt keywords: a handsome man, silver hair, smiling, play basketball https://user-images.githubusercontent.com/12782558/227149757-fd054d32-554f-45d5-9f09-319184866d85.mp4 prompt keywords: a girl, black hair, white pants, smiling, play basketball https://user-images.githubusercontent.com/49083766/233559964-bd5127bd-52f6-44b6-a089-9d7adfbc2430.mp4 prompt keywords: a handsome man https://user-images.githubusercontent.com/12782558/227152129-d70d5f76-a6fc-4d23-97d1-a94abd08f95a.mp4 - Support calling basic models and sampling strategies through DiffuserWrapper. - SAM + MMagic = Generate Anything! SAM (Segment Anything Model) is a popular model these days and can also provide more support for MMagic! If you want to create your own animation, you can go to [OpenMMLab PlayGround](https://github.com/open-mmlab/playground/blob/main/mmediting_sam/README.md). https://user-images.githubusercontent.com/49083766/233562228-f39fc675-326c-4ae8-986a-c942059effd0.mp4 **3. Upgraded Framework** To improve your "spellcasting" efficiency, we have made the following adjustments to the "magic circuit": - By using MMEngine and MMCV of OpenMMLab 2.0 framework, We decompose the editing framework into different modules and one can easily construct a customized editor framework by combining different modules. We can define the training process just like playing with Legos and provide rich components and strategies. In MMagic, you can complete controls on the training process with different levels of APIs. - Support for 33+ algorithms accelerated by Pytorch 2.0. - Refactor DataSample to support the combination and splitting of batch dimensions. - Refactor DataPreprocessor and unify the data format for various tasks during training and inference. - Refactor MultiValLoop and MultiTestLoop, supporting the evaluation of both generation-type metrics (e.g. FID) and reconstruction-type metrics (e.g. SSIM), and supporting the evaluation of multiple datasets at once. - Support visualization on local files or using tensorboard and wandb. **New Features & Improvements** - Support 53+ algorithms, 232+ configs, 213+ checkpoints, 26+ loss functions, and 20+ metrics. - Support controlnet animation and Gradio gui. [Click to view.](https://github.com/open-mmlab/mmagic/tree/main/configs/controlnet_animation) - Support Inferencer and Demo using High-level Inference APIs. [Click to view.](https://github.com/open-mmlab/mmagic/tree/main/demo) - Support Gradio gui of Inpainting inference. [Click to view.](https://github.com/open-mmlab/mmagic/blob/main/demo/gradio-demo.py) - Support qualitative comparison tools. [Click to view.](https://github.com/open-mmlab/mmagic/tree/main/tools/gui) - Enable projects. [Click to view.](https://github.com/open-mmlab/mmagic/tree/main/projects) - Improve converters scripts and documents for datasets. [Click to view.](https://github.com/open-mmlab/mmagic/tree/main/tools/dataset_converters) ## v1.0.0rc7 (07/04/2023) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc7. This release supports 51+ models, 226+ configs and 212+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - Support DiffuserWrapper - Support ControlNet (training and inference). - Support PyTorch 2.0. **New Features & Improvements** - Support DiffuserWrapper. [#1692](https://github.com/open-mmlab/mmagic/pull/1692) - Support ControlNet (training and inference). [#1744](https://github.com/open-mmlab/mmagic/pull/1744) - Support PyTorch 2.0 (successfully compile 33+ models on 'inductor' backend). [#1742](https://github.com/open-mmlab/mmagic/pull/1742) - Support Image Super-Resolution and Video Super-Resolution models inferencer. [#1662](https://github.com/open-mmlab/mmagic/pull/1662), [#1720](https://github.com/open-mmlab/mmagic/pull/1720) - Refactor tools/get_flops script. [#1675](https://github.com/open-mmlab/mmagic/pull/1675) - Refactor dataset_converters and documents for datasets. [#1690](https://github.com/open-mmlab/mmagic/pull/1690) - Move stylegan ops to MMCV. [#1383](https://github.com/open-mmlab/mmagic/pull/1383) **Bug Fixes** - Fix disco inferencer. [#1673](https://github.com/open-mmlab/mmagic/pull/1673) - Fix nafnet optimizer config. [#1716](https://github.com/open-mmlab/mmagic/pull/1716) - Fix tof typo. [#1711](https://github.com/open-mmlab/mmagic/pull/1711) **Contributors** A total of 8 developers contributed to this release. Thanks @LeoXing1996, @Z-Fran, @plyfager, @zengyh1900, @liuwenran, @ryanxingql, @HAOCHENYE, @VongolaWu **New Contributors** - @HAOCHENYE made their first contribution in https://github.com/open-mmlab/mmagic/pull/1712 ## v1.0.0rc6 (02/03/2023) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc6. This release supports 50+ models, 222+ configs and 209+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - Support Gradio gui of Inpainting inference. - Support Colorization, Translationin and GAN models inferencer. **New Features & Improvements** - Refactor FileIO. [#1572](https://github.com/open-mmlab/mmagic/pull/1572) - Refactor registry. [#1621](https://github.com/open-mmlab/mmagic/pull/1621) - Refactor Random degradations. [#1583](https://github.com/open-mmlab/mmagic/pull/1583) - Refactor DataSample, DataPreprocessor, Metric and Loop. [#1656](https://github.com/open-mmlab/mmagic/pull/1656) - Use mmengine.basemodule instead of nn.module. [#1491](https://github.com/open-mmlab/mmagic/pull/1491) - Refactor Main Page. [#1609](https://github.com/open-mmlab/mmagic/pull/1609) - Support Gradio gui of Inpainting inference. [#1601](https://github.com/open-mmlab/mmagic/pull/1601) - Support Colorization inferencer. [#1588](https://github.com/open-mmlab/mmagic/pull/1588) - Support Translation models inferencer. [#1650](https://github.com/open-mmlab/mmagic/pull/1650) - Support GAN models inferencer. [#1653](https://github.com/open-mmlab/mmagic/pull/1653), [#1659](https://github.com/open-mmlab/mmagic/pull/1659) - Print config tool. [#1590](https://github.com/open-mmlab/mmagic/pull/1590) - Improve type hints. [#1604](https://github.com/open-mmlab/mmagic/pull/1604) - Update Chinese documents of metrics and datasets. [#1568](https://github.com/open-mmlab/mmagic/pull/1568), [#1638](https://github.com/open-mmlab/mmagic/pull/1638) - Update Chinese documents of BigGAN and Disco-Diffusion. [#1620](https://github.com/open-mmlab/mmagic/pull/1620) - Update Evaluation and README of Guided-Diffusion. [#1547](https://github.com/open-mmlab/mmagic/pull/1547) **Bug Fixes** - Fix the meaning of `momentum` in EMA. [#1581](https://github.com/open-mmlab/mmagic/pull/1581) - Fix output dtype of RandomNoise. [#1585](https://github.com/open-mmlab/mmagic/pull/1585) - Fix pytorch2onnx tool. [#1629](https://github.com/open-mmlab/mmagic/pull/1629) - Fix API documents. [#1641](https://github.com/open-mmlab/mmagic/pull/1641), [#1642](https://github.com/open-mmlab/mmagic/pull/1642) - Fix loading RealESRGAN EMA weights. [#1647](https://github.com/open-mmlab/mmagic/pull/1647) - Fix arg passing bug of dataset_converters scripts. [#1648](https://github.com/open-mmlab/mmagic/pull/1648) **Contributors** A total of 17 developers contributed to this release. Thanks @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @liuwenran, @austinmw, @dienachtderwelt, @liangzelong, @i-aki-y, @xiaomile, @Li-Qingyun, @vansin, @Luo-Yihang, @ydengbi, @ruoningYu, @triple-Mu **New Contributors** - @dienachtderwelt made their first contribution in https://github.com/open-mmlab/mmagic/pull/1578 - @i-aki-y made their first contribution in https://github.com/open-mmlab/mmagic/pull/1590 - @triple-Mu made their first contribution in https://github.com/open-mmlab/mmagic/pull/1618 - @Li-Qingyun made their first contribution in https://github.com/open-mmlab/mmagic/pull/1640 - @Luo-Yihang made their first contribution in https://github.com/open-mmlab/mmagic/pull/1648 - @ydengbi made their first contribution in https://github.com/open-mmlab/mmagic/pull/1557 ## v1.0.0rc5 (04/01/2023) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc5. This release supports 49+ models, 180+ configs and 177+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - Support Restormer. - Support GLIDE. - Support SwinIR. - Support Stable Diffusion. **New Features & Improvements** - Disco notebook. (#1507) - Revise test requirements and CI. (#1514) - Recursive generate summary and docstring. (#1517) - Enable projects. (#1526) - Support mscoco dataset. (#1520) - Improve Chinese documents. (#1532) - Type hints. (#1481) - Update download link of checkpoints. (#1554) - Update deployment guide. (#1551) **Bug Fixes** - Fix documentation link checker. (#1522) - Fix ssim first channel bug. (#1515) - Fix extract_gt_data of realesrgan. (#1542) - Fix model index. (#1559) - Fix config path in disco-diffusion. (#1553) - Fix text2image inferencer. (#1523) **Contributors** A total of 16 developers contributed to this release. Thanks @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @liuwenran, @AlexZou14, @lvhan028, @xiaomile, @ldr426, @austin273, @whu-lee, @willaty, @curiosity654, @Zdafeng, @Taited **New Contributors** - @xiaomile made their first contribution in https://github.com/open-mmlab/mmagic/pull/1481 - @ldr426 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1542 - @austin273 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1553 - @whu-lee made their first contribution in https://github.com/open-mmlab/mmagic/pull/1539 - @willaty made their first contribution in https://github.com/open-mmlab/mmagic/pull/1541 - @curiosity654 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1556 - @Zdafeng made their first contribution in https://github.com/open-mmlab/mmagic/pull/1476 - @Taited made their first contribution in https://github.com/open-mmlab/mmagic/pull/1534 ## v1.0.0rc4 (05/12/2022) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc4. This release supports 45+ models, 176+ configs and 175+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - Support High-level APIs. - Support diffusion models. - Support Text2Image Task. - Support 3D-Aware Generation. **New Features & Improvements** - Refactor High-level APIs. (#1410) - Support disco-diffusion text-2-image. (#1234, #1504) - Support EG3D. (#1482, #1493, #1494, #1499) - Support NAFNet model. (#1369) **Bug Fixes** - fix srgan train config. (#1441) - fix cain config. (#1404) - fix rdn and srcnn train configs. (#1392) **Contributors** A total of 14 developers contributed to this release. Thanks @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @gaoyang07, @ChangjianZhao, @zxczrx123, @jackghosts, @liuwenran, @CCODING04, @RoseZhao929, @shaocongliu, @liangzelong. **New Contributors** - @gaoyang07 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1372 - @ChangjianZhao made their first contribution in https://github.com/open-mmlab/mmagic/pull/1461 - @zxczrx123 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1462 - @jackghosts made their first contribution in https://github.com/open-mmlab/mmagic/pull/1463 - @liuwenran made their first contribution in https://github.com/open-mmlab/mmagic/pull/1410 - @CCODING04 made their first contribution in https://github.com/open-mmlab/mmagic/pull/783 - @RoseZhao929 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1474 - @shaocongliu made their first contribution in https://github.com/open-mmlab/mmagic/pull/1470 - @liangzelong made their first contribution in https://github.com/open-mmlab/mmagic/pull/1488 ## v1.0.0rc3 (10/11/2022) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc3. This release supports 43+ models, 170+ configs and 169+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - convert `mmdet` and `clip` to optional requirements. **New Features & Improvements** - Support `try_import` for `mmdet`. (#1408) - Support `try_import` for `flip`. (#1420) - Update `.gitignore`. ($1416) - Set `real_feat` to cpu in `inception_utils`. (#1415) - Modify README and configs of StyleGAN2 and PEGAN (#1418) - Improve the rendering of Docs-API (#1373) **Bug Fixes** - Revise config and pretrain model loading in ESRGAN (#1407) - Revise config of LSGAN (#1409) - Revise config of CAIN (#1404) **Contributors** A total of 5 developers contributed to this release. @Z-Fran, @zengyh1900, @plyfager, @LeoXing1996, @ruoningYu. ## v1.0.0rc2 (02/11/2022) **Highlights** We are excited to announce the release of MMEditing 1.0.0rc2. This release supports 43+ models, 170+ configs and 169+ checkpoints in MMGeneration and MMEditing. We highlight the following new features - patch-based and slider-based image and video comparison viewer. - image colorization. **New Features & Improvements** - Support qualitative comparison tools. (#1303) - Support instance aware colorization. (#1370) - Support multi-metrics with different sample-model. (#1171) - Improve the implementation - refactoring evaluation metrics. (#1164) - Save gt images in PGGAN's `forward`. (#1332) - Improve type and change default number of `preprocess_div2k_dataset.py`. (#1380) - Support pixel value clip in visualizer. (#1365) - Support SinGAN Dataset and SinGAN demo. (#1363) - Avoid cast int and float in GenDataPreprocessor. (#1385) - Improve the documentation - Update a menu switcher. (#1162) - Fix TTSR's README. (#1325) **Bug Fixes** - Fix PPL bug. (#1172) - Fix RDN number of channels. (#1328) - Fix types of exceptions in demos. (#1372) - Fix realesrgan ema. (#1341) - Improve the assertion to ensuer `GenerateFacialHeatmap` as `np.float32`. (#1310) - Fix sampling behavior of `unpaired_dataset.py` and urls in cyclegan's README. (#1308) - Fix vsr models in pytorch2onnx. (#1300) - Fix incorrect settings in configs. (#1167,#1200,#1236,#1293,#1302,#1304,#1319,#1331,#1336,#1349,#1352,#1353,#1358,#1364,#1367,#1384,#1386,#1391,#1392,#1393) **New Contributors** - @gaoyang07 made their first contribution in https://github.com/open-mmlab/mmagic/pull/1372 **Contributors** A total of 7 developers contributed to this release. Thanks @LeoXing1996, @Z-Fran, @zengyh1900, @plyfager, @ryanxingql, @ruoningYu, @gaoyang07. ## v1.0.0rc1(23/9/2022) MMEditing 1.0.0rc1 has merged MMGeneration 1.x. - Support 42+ algorithms, 169+ configs and 168+ checkpoints. - Support 26+ loss functions, 20+ metrics. - Support tensorboard, wandb. - Support unconditional GANs, conditional GANs, image2image translation and internal learning. ## v1.0.0rc0(31/8/2022) MMEditing 1.0.0rc0 is the first version of MMEditing 1.x, a part of the OpenMMLab 2.0 projects. Built upon the new [training engine](https://github.com/open-mmlab/mmengine), MMEditing 1.x unifies the interfaces of dataset, models, evaluation, and visualization. And there are some BC-breaking changes. Please check [the migration tutorial](https://mmagic.readthedocs.io/en/latest/migration/overview.html) for more details. ================================================ FILE: docs/en/community/contributing.md ================================================ # Contributing guidance Welcome to the MMagic community, we are committed to building a Multimodal Advanced, Generative, and Intelligent Creation Toolbox. This section introduces following contents: - [Contributing guidance](#contributing-guidance) - [Pull Request Workflow](#pull-request-workflow) - [1. Fork and clone](#1-fork-and-clone) - [2. Configure pre-commit](#2-configure-pre-commit) - [3. Create a development branch](#3-create-a-development-branch) - [4. Commit the code and pass the unit test](#4-commit-the-code-and-pass-the-unit-test) - [5. Push the code to remote](#5-push-the-code-to-remote) - [6. Create a Pull Request](#6-create-a-pull-request) - [7. Resolve conflicts](#7-resolve-conflicts) - [Guidance](#guidance) - [Unit test](#unit-test) - [Document rendering](#document-rendering) - [Code style](#code-style) - [Python](#python) - [C++ and CUDA](#c-and-cuda) - [PR Specs](#pr-specs) All kinds of contributions are welcomed, including but not limited to **Fix bug** You can directly post a Pull Request to fix typo in code or documents The steps to fix the bug of code implementation are as follows. 1. If the modification involve significant changes, you should create an issue first and describe the error information and how to trigger the bug. Other developers will discuss with you and propose an proper solution. 2. Posting a pull request after fixing the bug and adding corresponding unit test. **New Feature or Enhancement** 1. If the modification involve significant changes, you should create an issue to discuss with our developers to propose an proper design. 2. Post a Pull Request after implementing the new feature or enhancement and add corresponding unit test. **Document** You can directly post a pull request to fix documents. If you want to add a document, you should first create an issue to check if it is reasonable. ### Pull Request Workflow If you're not familiar with Pull Request, don't worry! The following guidance will tell you how to create a Pull Request step by step. If you want to dive into the develop mode of Pull Request, you can refer to the [official documents](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) #### 1. Fork and clone If you are posting a pull request for the first time, you should fork the OpenMMLab repositories by clicking the **Fork** button in the top right corner of the GitHub page, and the forked repositories will appear under your GitHub profile. Then, you can clone the repositories to local: ```shell git clone git@github.com:{username}/mmagic.git ``` After that, you should ddd official repository as the upstream repository ```bash git remote add upstream git@github.com:open-mmlab/mmagic ``` Check whether remote repository has been added successfully by `git remote -v` ```bash origin git@github.com:{username}/mmagic.git (fetch) origin git@github.com:{username}/mmagic.git (push) upstream git@github.com:open-mmlab/mmagic (fetch) upstream git@github.com:open-mmlab/mmagic (push) ``` ```{note} Here's a brief introduction to origin and upstream. When we use "git clone", we create an "origin" remote by default, which points to the repository cloned from. As for "upstream", we add it ourselves to point to the target repository. Of course, if you don't like the name "upstream", you could name it as you wish. Usually, we'll push the code to "origin". If the pushed code conflicts with the latest code in official("upstream"), we should pull the latest code from upstream to resolve the conflicts, and then push to "origin" again. The posted Pull Request will be updated automatically. ``` #### 2. Configure pre-commit You should configure [pre-commit](https://pre-commit.com/#intro) in the local development environment to make sure the code style matches that of OpenMMLab. **Note**: The following code should be executed under the mmagic directory. ```shell pip install -U pre-commit pre-commit install ``` Check that pre-commit is configured successfully, and install the hooks defined in `.pre-commit-config.yaml`. ```shell pre-commit run --all-files ``` ```{note} Chinese users may fail to download the pre-commit hooks due to the network issue. In this case, you could download these hooks from gitee by setting the .pre-commit-config-zh-cn.yaml pre-commit install -c .pre-commit-config-zh-cn.yaml pre-commit run --all-files -c .pre-commit-config-zh-cn.yaml ``` If the installation process is interrupted, you can repeatedly run `pre-commit run ... ` to continue the installation. If the code does not conform to the code style specification, pre-commit will raise a warning and fixes some of the errors automatically. If we want to commit our code bypassing the pre-commit hook, we can use the `--no-verify` option(**only for temporarily commit**. ```shell git commit -m "xxx" --no-verify ``` #### 3. Create a development branch After configuring the pre-commit, we should create a branch based on the main branch to develop the new feature or fix the bug. The proposed branch name is `username/pr_name` ```shell git checkout -b yhc/refactor_contributing_doc ``` In subsequent development, if the main branch of the local repository is behind the main branch of "upstream", we need to pull the upstream for synchronization, and then execute the above command: ```shell git pull upstream main ``` #### 4. Commit the code and pass the unit test - mmagic introduces mypy to do static type checking to increase the robustness of the code. Therefore, we need to add Type Hints to our code and pass the mypy check. If you are not familiar with Type Hints, you can refer to [this tutorial](https://docs.python.org/3/library/typing.html). - The committed code should pass through the unit test ```shell # Pass all unit tests pytest tests # Pass the unit test of runner pytest tests/test_runner/test_runner.py ``` If the unit test fails for lack of dependencies, you can install the dependencies referring to the [guidance](#unit-test) - If the documents are modified/added, we should check the rendering result referring to [guidance](#document-rendering) #### 5. Push the code to remote We could push the local commits to remote after passing through the check of unit test and pre-commit. You can associate the local branch with remote branch by adding `-u` option. ```shell git push -u origin {branch_name} ``` This will allow you to use the `git push` command to push code directly next time, without having to specify a branch or the remote repository. #### 6. Create a Pull Request (1) Create a pull request in GitHub's Pull request interface (2) Modify the PR description according to the guidelines so that other developers can better understand your changes Find more details about Pull Request description in [pull request guidelines](#pr-specs). **note** (a) The Pull Request description should contain the reason for the change, the content of the change, and the impact of the change, and be associated with the relevant Issue (see [documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) (b) If it is your first contribution, please sign the CLA (c) Check whether the Pull Request pass through the CI mmagic will run unit test for the posted Pull Request on different platforms (Linux, Window, Mac), based on different versions of Python, PyTorch, CUDA to make sure the code is correct. We can see the specific test information by clicking `Details` in the above image so that we can modify the code. (3) If the Pull Request passes the CI, then you can wait for the review from other developers. You'll modify the code based on the reviewer's comments, and repeat the steps [4](#4-commit-the-code-and-pass-the-unit-test)-[5](#5-push-the-code-to-remote) until all reviewers approve it. Then, we will merge it ASAP. #### 7. Resolve conflicts If your local branch conflicts with the latest main branch of "upstream", you'll need to resolove them. There are two ways to do this: ```shell git fetch --all --prune git rebase upstream/main ``` or ```shell git fetch --all --prune git merge upstream/main ``` If you are very good at handling conflicts, then you can use rebase to resolve conflicts, as this will keep your commit logs tidy. If you are not familiar with `rebase`, then you can use `merge` to resolve conflicts. ### Guidance #### Unit test We should make sure the committed code will not decrease the coverage of unit test, we could run the following command to check the coverage of unit test: ```shell python -m coverage run -m pytest /path/to/test_file python -m coverage html # check file in htmlcov/index.html ``` #### Document rendering If the documents are modified/added, we should check the rendering result. We could install the dependencies and run the following command to render the documents and check the results: ```shell pip install -r requirements/docs.txt cd docs/zh_cn/ # or docs/en make html # check file in ./docs/zh_cn/_build/html/index.html ``` ### Code style #### Python We adopt [PEP8](https://www.python.org/dev/peps/pep-0008/) as the preferred code style. We use the following tools for linting and formatting: - [flake8](https://github.com/PyCQA/flake8): A wrapper around some linter tools. - [isort](https://github.com/timothycrosley/isort): A Python utility to sort imports. - [yapf](https://github.com/google/yapf): A formatter for Python files. - [codespell](https://github.com/codespell-project/codespell): A Python utility to fix common misspellings in text files. - [mdformat](https://github.com/executablebooks/mdformat): Mdformat is an opinionated Markdown formatter that can be used to enforce a consistent style in Markdown files. - [docformatter](https://github.com/myint/docformatter): A formatter to format docstring. Style configurations of yapf and isort can be found in [setup.cfg](../../../setup.cfg). We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. The config for a pre-commit hook is stored in [.pre-commit-config](../../../.pre-commit-config.yaml). #### C++ and CUDA We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). ### PR Specs 1. Use [pre-commit](https://pre-commit.com) hook to avoid issues of code style 2. One short-time branch should be matched with only one PR 3. Accomplish a detailed change in one PR. Avoid large PR - Bad: Support Faster R-CNN - Acceptable: Add a box head to Faster R-CNN - Good: Add a parameter to box head to support custom conv-layer number 4. Provide clear and significant commit message 5. Provide clear and meaningful PR description - Task name should be clarified in title. The general format is: \[Prefix\] Short description of the PR (Suffix) - Prefix: add new feature \[Feature\], fix bug \[Fix\], related to documents \[Docs\], in developing \[WIP\] (which will not be reviewed temporarily) - Introduce main changes, results and influences on other modules in short description - Associate related issues and pull requests with a milestone ================================================ FILE: docs/en/community/projects.md ================================================ # MMagic projects Welcome to the MMagic community! The MMagic ecosystem consists of tutorials, libraries, and projects from a broad set of researchers in academia and industry, ML and application engineers. The goal of this ecosystem is to support, accelerate, and aid in your exploration with MMagic for AIGC such as image, video, 3D content generation, editing and processing. Here are a few projects that are built upon MMagic. They are examples of how to use MMagic as a library, to make your projects more maintainable. Please find more projects in [MMagic Ecosystem](https://openmmlab.com/ecosystem). ## Show your projects on OpenMMLab Ecosystem You can submit your project so that it can be shown on the homepage of [OpenMMLab](https://openmmlab.com/ecosystem). ## Add example projects to MMagic Here is an [example project](../../../projects/example_project) about how to add your projects to MMagic. You can copy and create your own project from the [example project](../../../projects/example_project). We also provide some documentation listed below for your reference: - [Contribution Guide](https://mmagic.readthedocs.io/en/latest/community/contributing.html) The guides for new contributors about how to add your projects to MMagic. - [New Model Guide](https://mmagic.readthedocs.io/en/latest/howto/models.html) The documentation of adding new models. - [Discussions](https://github.com/open-mmlab/mmagic/discussions) Welcome to start a discussion! ## Projects of libraries and toolboxes - [PowerVQE](https://github.com/ryanxingql/powervqe): Open framework for quality enhancement of compressed videos based on PyTorch and MMagic. - [VR-Baseline](https://github.com/linjing7/VR-Baseline): Video Restoration Toolbox. - [Derain-Toolbox](https://github.com/biubiubiiu/derain-toolbox): Single Image Deraining Toolbox and Benchmark ## Projects of research papers - [Towards Interpretable Video Super-Resolution via Alternating Optimization, ECCV 2022](https://arxiv.org/abs/2207.10765)[\[github\]](https://github.com/caojiezhang/DAVSR) - [SepLUT:Separable Image-adaptive Lookup Tables for Real-time Image Enhancement, ECCV 2022](https://arxiv.org/abs/2207.08351)[\[github\]](https://github.com/ImCharlesY/SepLUT) - [TTVSR: Learning Trajectory-Aware Transformer for Video Super-Resolution, CVPR 2022](https://arxiv.org/abs/2204.04216)[\[github\]](https://github.com/researchmm/TTVSR) - [Arbitrary-Scale Image Synthesis, CVPR 2022](https://arxiv.org/pdf/2204.02273.pdf)[\[github\]](https://github.com/vglsd/ScaleParty) - [Investigating Tradeoffs in Real-World Video Super-Resolution(RealBasicVSR), CVPR 2022](https://arxiv.org/abs/2111.12704)[\[github\]](https://github.com/ckkelvinchan/RealBasicVSR) - [BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment, CVPR 2022](https://arxiv.org/abs/2104.13371)[\[github\]](https://github.com/ckkelvinchan/BasicVSR_PlusPlus) - [Multi-Scale Memory-Based Video Deblurring, CVPR 2022](https://arxiv.org/abs/2204.02977)[\[github\]](https://github.com/jibo27/MemDeblur) - [AdaInt:Learning Adaptive Intervals for 3D Lookup Tables on Real-time Image Enhancement, CVPR 2022](https://arxiv.org/abs/2204.13983)[\[github\]](https://github.com/ImCharlesY/AdaInt) - [A New Dataset and Transformer for Stereoscopic Video Super-Resolution, CVPRW 2022](https://openaccess.thecvf.com/content/CVPR2022W/NTIRE/papers/Imani_A_New_Dataset_and_Transformer_for_Stereoscopic_Video_Super-Resolution_CVPRW_2022_paper.pdf)[\[github\]](https://github.com/H-deep/Trans-SVSR) - [Liquid warping GAN with attention: A unified framework for human image synthesis, TPAMI 2021](https://arxiv.org/pdf/2011.09055.pdf)[\[github\]](https://github.com/iPERDance/iPERCore) - [BasicVSR:The Search for Essential Components in Video Super-Resolution and Beyond, CVPR 2021](https://arxiv.org/abs/2012.02181)[\[github\]](https://github.com/ckkelvinchan/BasicVSR-IconVSR) - [GLEAN:Generative Latent Bank for Large-Factor Image Super-Resolution, CVPR 2021](https://arxiv.org/abs/2012.00739)[\[github\]](https://github.com/ckkelvinchan/GLEAN) - [DAN:Unfolding the Alternating Optimization for Blind Super Resolution, NeurIPS 2020](https://arxiv.org/abs/2010.02631v4)[\[github\]](https://github.com/AlexZou14/DAN-Basd-on-Openmmlab) ================================================ FILE: docs/en/conf.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import subprocess import sys import pytorch_sphinx_theme sys.path.insert(0, os.path.abspath('../..')) # -- Project information ----------------------------------------------------- project = 'MMagic' copyright = '2023, MMagic Authors' author = 'MMagic Authors' # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', 'sphinx.ext.autosectionlabel', 'sphinx_markdown_tables', 'sphinx_copybutton', 'sphinx_tabs.tabs', 'myst_parser', ] extensions.append('notfound.extension') # enable customizing not-found page extensions.append('autoapi.extension') autoapi_type = 'python' autoapi_dirs = ['../../mmagic'] autoapi_add_toctree_entry = False autoapi_template_dir = '_templates' # autoapi_options = ['members', 'undoc-members', 'show-module-summary'] # # Core library for html generation from docstrings # extensions.append('sphinx.ext.autodoc') # extensions.append('sphinx.ext.autodoc.typehints') # # Enable 'expensive' imports for sphinx_autodoc_typehints # set_type_checking_flag = True # # Sphinx-native method. Not as good as sphinx_autodoc_typehints # autodoc_typehints = "description" # extensions.append('sphinx.ext.autosummary') # Create neat summary tables # autosummary_generate = True # Turn on sphinx.ext.autosummary # # Add __init__ doc (ie. params) to class summaries # autoclass_content = 'both' # autodoc_skip_member = [] # # If no docstring, inherit from base class # autodoc_inherit_docstrings = True autodoc_mock_imports = [ 'mmagic.version', 'mmcv._ext', 'mmcv.ops.ModulatedDeformConv2d', 'mmcv.ops.modulated_deform_conv2d', 'clip', 'resize_right', 'pandas' ] source_suffix = { '.rst': 'restructuredtext', '.md': 'markdown', } # # Remove 'view source code' from top of page (for html, not python) # html_show_sourcelink = False # nbsphinx_allow_errors = True # Continue through Jupyter errors # add_module_names = False # Remove namespaces from class/method signatures # Ignore >>> when copying code copybutton_prompt_text = r'>>> |\.\.\. ' copybutton_prompt_is_regexp = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # html_theme = 'sphinx_rtd_theme' html_theme = 'pytorch_sphinx_theme' html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()] html_theme_options = { 'menu': [ { 'name': 'GitHub', 'url': 'https://github.com/open-mmlab/mmagic', }, { 'name': 'Version', 'children': [ { 'name': 'MMagic 1.x', 'url': 'https://mmagic.readthedocs.io/en/latest/', 'description': 'Main branch' }, { 'name': 'MMEditing 0.x', 'url': 'https://mmagic.readthedocs.io/en/0.x/', 'description': '0.x branch', }, ], 'active': True, }, ], 'menu_lang': 'en', } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_css_files = ['css/readthedocs.css'] myst_enable_extensions = ['colon_fence'] myst_heading_anchors = 3 language = 'en' # The master toctree document. root_doc = 'index' notfound_template = '404.html' def builder_inited_handler(app): subprocess.run(['python', './.dev_scripts/update_model_zoo.py']) subprocess.run(['python', './.dev_scripts/update_dataset_zoo.py']) def skip_member(app, what, name, obj, skip, options): if what == 'package' or what == 'module': skip = True return skip def viewcode_follow_imported(app, modname, attribute): fullname = f'{modname}.{attribute}' all_objects = app.env.autoapi_all_objects if fullname not in all_objects: return None if all_objects[fullname].obj.get('type') == 'method': fullname = fullname[:fullname.rfind('.')] attribute = attribute[:attribute.rfind('.')] while all_objects[fullname].obj.get('original_path', '') != '': fullname = all_objects[fullname].obj.get('original_path') orig_path = fullname if orig_path.endswith(attribute): return orig_path[:-len(attribute) - 1] return modname def setup(app): app.connect('builder-inited', builder_inited_handler) app.connect('autoapi-skip-member', skip_member) if 'viewcode-follow-imported' in app.events.events: app.connect( 'viewcode-follow-imported', viewcode_follow_imported, priority=0) ================================================ FILE: docs/en/device/npu.md ================================================ # NPU (HUAWEI Ascend) ## Usage Please refer to the [building documentation of MMCV](https://mmcv.readthedocs.io/en/latest/get_started/build.html#build-mmcv-full-on-ascend-npu-machine) to install MMCV and [mmengine](https://mmengine.readthedocs.io/en/latest/get_started/installation.html#build-from-source) on NPU devices. Here we use 8 NPUs on your computer to train the model with the following command: ```shell bash tools/dist_train.sh configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py 8 ``` Also, you can use only one NPU to train the model with the following command: ```shell python tools/train.py configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py ``` ## Models Results | Model | Dataset | PSNR | SSIM | Download | | :----------------------------------------------------------------------------------------: | ------- | :---: | :--- | :--------------------------------------------------------------------------------------------- | | [edsr_x2c64b16_1x16_300k_div2k](https://github.com/open-mmlab/mmagic/blob/main/configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py) | DIV2K | 35.83 | 0.94 | [log](https://download.openmmlab.com/mmediting/device/npu/edsr/edsr_x2c64b16_1xb16-300k_div2k.log) | **Notes:** - If not specially marked, the results on NPU with amp are the basically same as those on the GPU with FP32. **All above models are provided by Huawei Ascend group.** ================================================ FILE: docs/en/docutils.conf ================================================ [html writers] table_style: colwidths-auto ================================================ FILE: docs/en/faq.md ================================================ # Frequently asked questions We list some common troubles faced by many users and their corresponding solutions here. Feel free to enrich the list if you find any frequent issues and have ways to help others to solve them. If the contents here do not cover your issue, please create an issue using the [provided templates](https://github.com/open-mmlab/mmagic/issues/new/choose) and make sure you fill in all required information in the template. ## FAQ **Q1**: “xxx: ‘yyy is not in the zzz registry’”. **A1**: The registry mechanism will be triggered only when the file of the module is imported. So you need to import that file somewhere. **Q2**: What's the folder structure of xxx dataset? **A2**: You can make sure the folder structure is correct following tutorials of [dataset preparation](user_guides/dataset_prepare.md). **Q3**: How to use LMDB data to train the model? **A3**: You can use scripts in `tools/data` to make LMDB files. More details are shown in tutorials of [dataset preparation](user_guides/dataset_prepare.md). **Q4**: Why `MMCV==xxx is used but incompatible` is raised when import I try to import `mmgen`? **A4**: This is because the version of MMCV and MMGeneration are incompatible. Compatible MMGeneration and MMCV versions are shown as below. Please choose the correct version of MMCV to avoid installation issues. | MMGeneration version | MMCV version | | :------------------: | :--------------: | | master | mmcv-full>=2.0.0 | Note: You need to run `pip uninstall mmcv` first if you have mmcv installed. If mmcv and mmcv-full are both installed, there will be `ModuleNotFoundError`. **Q5**: How can I ignore some fields in the base configs? **A5**: Sometimes, you may set `_delete_=True` to ignore some of fields in base configs. You may refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md#delete-key-in-dict) for simple illustration. You may have a careful look at [this tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md) for better understanding of this feature. **Q6**:: How can I use intermediate variables in configs? **A6**: Some intermediate variables are used in the config files, like `train_pipeline`/`test_pipeline` in datasets. It's worth noting that when modifying intermediate variables in the children configs, users need to pass the intermediate variables into corresponding fields again. ================================================ FILE: docs/en/get_started/install.md ================================================ # Installation In this section, you will know about: - [Installation](#installation) - [Installation](#installation-1) - [Prerequisites](#prerequisites) - [Best practices](#best-practices) - [Customize installation](#customize-installation) - [CUDA Version](#cuda-version) - [Install MMCV without MIM](#install-mmcv-without-mim) - [Using MMagic with Docker](#using-mmagic-with-docker) - [Trouble shooting](#trouble-shooting) - [Developing with multiple MMagic versions](#developing-with-multiple-mmagic-versions) ## Installation We recommend that users follow our [Best practices](#best-practices) to install MMagic. However, the whole process is highly customizable. See [Customize installation](#customize-installation) section for more information. ### Prerequisites In this section, we demonstrate how to prepare an environment with PyTorch. MMagic works on Linux, Windows, and macOS. It requires: - Python >= 3.7 - [PyTorch](https://pytorch.org/) >= 1.8 - [MMCV](https://github.com/open-mmlab/mmcv) >= 2.0.0 > If you are experienced with PyTorch and have already installed it, just skip this part and jump to the [next section](#best-practices). Otherwise, you can follow these steps for the preparation. **Step 0.** Download and install Miniconda from [official website](https://docs.conda.io/en/latest/miniconda.html). **Step 1.** Create a [conda environment](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html#) and activate it ```shell conda create --name mmagic python=3.8 -y conda activate mmagic ``` **Step 2.** Install PyTorch following [official instructions](https://pytorch.org/get-started/locally/), e.g. - On GPU platforms: ```shell conda install pytorch torchvision cudatoolkit=11.3 -c pytorch ``` - On CPU platforms: ```shell conda install pytorch=1.10 torchvision cpuonly -c pytorch ``` ### Best practices **Step 0.** Install [MMCV](https://github.com/open-mmlab/mmcv) using [MIM](https://github.com/open-mmlab/mim). ```shell pip install -U openmim mim install 'mmcv>=2.0.0' ``` **Step 1.** Install [MMEngine](https://github.com/open-mmlab/mmengine). ```shell mim install 'mmengine' ``` Or ```shell pip install mmengine ``` Or ```shell pip install git+https://github.com/open-mmlab/mmengine.git ``` **Step 2.** Install MMagic. ```shell mim install 'mmagic' ``` Or ```shell pip install mmagic ``` Or install [MMagic](https://github.com/open-mmlab/mmagic) from the source code. ```shell git clone https://github.com/open-mmlab/mmagic.git cd mmagic pip3 install -e . -v ``` **Step 5.** Verify MMagic has been successfully installed. ```shell cd ~ python -c "import mmagic; print(mmagic.__version__)" # Example output: 1.0.0 ``` The installation is successful if the version number is output correctly. ```{note} You may be curious about what `-e .` means when supplied with `pip install`. Here is the description: - `-e` means [editable mode](https://pip.pypa.io/en/latest/cli/pip_install/#cmdoption-e). When `import mmagic`, modules under the cloned directory are imported. If `pip install` without `-e`, pip will copy cloned codes to somewhere like `lib/python/site-package`. Consequently, modified code under the cloned directory takes no effect unless `pip install` again. Thus, `pip install` with `-e` is particularly convenient for developers. If some codes are modified, new codes will be imported next time without reinstallation. - `.` means code in this directory You can also use `pip install -e .[all]`, which will install more dependencies, especially for pre-commit hooks and unittests. ``` ### Customize installation #### CUDA Version When installing PyTorch, you need to specify the version of CUDA. If you are not clear on which to choose, follow our recommendations: - For Ampere-based NVIDIA GPUs, such as GeForce 30 series and NVIDIA A100, CUDA 11 is a must. - For older NVIDIA GPUs, CUDA 11 is backward compatible, but CUDA 10.2 offers better compatibility and is more lightweight. Please make sure the GPU driver satisfies the minimum version requirements. See [this table](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-major-component-versions__table-cuda-toolkit-driver-versions) for more information. **note** Installing CUDA runtime libraries is enough if you follow our best practices, because no CUDA code will be compiled locally. However, if you hope to compile MMCV from source or develop other CUDA operators, you need to install the complete CUDA toolkit from NVIDIA's [website](https://developer.nvidia.com/cuda-downloads), and its version should match the CUDA version of PyTorch. i.e., the specified version of cudatoolkit in `conda install` command. #### Install MMCV without MIM MMCV contains C++ and CUDA extensions, thus depending on PyTorch in a complex way. MIM solves such dependencies automatically and makes the installation easier. However, it is not a must. To install MMCV with pip instead of MIM, please follow [MMCV installation guides](https://mmcv.readthedocs.io/en/latest/get_started/installation.html). This requires manually specifying a find-url based on PyTorch version and its CUDA version. For example, the following command install mmcv-full built for PyTorch 1.10.x and CUDA 11.3. ```shell pip install 'mmcv>=2.0.0' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html ``` #### Using MMagic with Docker We provide a [Dockerfile](https://github.com/open-mmlab/mmagic/blob/main/docker/Dockerfile) to build an image. Ensure that your [docker version](https://docs.docker.com/engine/install/) >=19.03. ```shell # build an image with PyTorch 1.8, CUDA 11.1 # If you prefer other versions, just modified the Dockerfile docker build -t mmagic docker/ ``` Run it with ```shell docker run --gpus all --shm-size=8g -it -v {DATA_DIR}:/mmagic/data mmagic ``` #### Trouble shooting If you have some issues during the installation, please first view the [FAQ](../faq.md) page. You may [open an issue](https://github.com/open-mmlab/mmagic/issues/new/choose) on GitHub if no solution is found. ### Developing with multiple MMagic versions The train and test scripts already modify the `PYTHONPATH` to ensure the script uses the `MMagic` in the current directory. To use the default MMagic installed in the environment rather than that you are working with, you can remove the following line in those scripts ```shell PYTHONPATH="$(dirname $0)/..":$PYTHONPATH ``` ================================================ FILE: docs/en/get_started/overview.md ================================================ # Overview Welcome to MMagic! In this section, you will know about - [Overview](#overview) - [What is MMagic?](#what-is-mmagic) - [Why should I use MMagic?](#why-should-i-use-mmagic) - [Get started](#get-started) - [User guides](#user-guides) - [Advanced guides](#advanced-guides) - [How to](#how-to) ## What is MMagic? MMagic (**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation) is an open-source AIGC toolbox for professional AI researchers and machine learning engineers to explore image and video processing, editing and generation. MMagic allows researchers and engineers to use pre-trained state-of-the-art models, train and develop new customized models easily. MMagic supports various foundamental generative models, including: - Unconditional Generative Adversarial Networks (GANs) - Conditional Generative Adversarial Networks (GANs) - Internal Learning - Diffusion Models - And many other generative models are coming soon! MMagic supports various applications, including: - Text-to-Image - Image-to-image translation - 3D-aware generation - Image super-resolution - Video super-resolution - Video frame interpolation - Image inpainting - Image matting - Image restoration - Image colorization - Image generation - And many other applications are coming soon!

## Why should I use MMagic? - **State of the Art Models** MMagic provides state-of-the-art generative models to process, edit and synthesize images and videos. - **Powerful and Popular Applications** MMagic supports popular and contemporary image restoration, text-to-image, 3D-aware generation, inpainting, matting, super-resolution and generation applications. Specifically, MMagic supports fine-tuning for stable diffusion and many exciting diffusion's application such as ControlNet Animation with SAM. MMagic also supports GAN interpolation, GAN projection, GAN manipulations and many other popular GAN’s applications. It’s time to begin your AIGC exploration journey! - **Efficient Framework** By using MMEngine and MMCV of OpenMMLab 2.0 framework, MMagic decompose the editing framework into different modules and one can easily construct a customized editor framework by combining different modules. We can define the training process just like playing with Legos and provide rich components and strategies. In MMagic, you can complete controls on the training process with different levels of APIs. With the support of [MMSeparateDistributedDataParallel](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/wrappers/seperate_distributed.py), distributed training for dynamic architectures can be easily implemented. ## Get started For installation instructions, please see [Installation](install.md). ## User guides For beginners, we suggest learning the basic usage of MMagic from [user_guides](../user_guides/config.md). ### Advanced guides For users who are familiar with MMagic, you may want to learn the design of MMagic, as well as how to extend the repo, how to use multiple repos and other advanced usages, please refer to [advanced_guides](../advanced_guides/evaluator.md). ### How to For users who want to use MMagic to do something, please refer to [How to](../howto/models.md). ================================================ FILE: docs/en/get_started/quick_run.md ================================================ # Quick run After installing MMagic successfully, now you are able to play with MMagic! To generate an image from text, you only need several lines of codes by MMagic! ```python from mmagic.apis import MMagicInferencer sd_inferencer = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = 'output/sd_res.png' sd_inferencer.infer(text=text_prompts, result_out_dir=result_out_dir) ``` Or you can just run the following command. ```bash python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir ./output/sd_res.png ``` You will see a new image `sd_res.png` in folder `output/`, which contained generated samples. What's more, if you want to make these photos much more clear, you only need several lines of codes for image super-resolution by MMagic! ```python from mmagic.apis import MMagicInferencer config = 'configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py' checkpoint = 'https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth' img_path = 'tests/data/image/lq/baboon_x4.png' editor = MMagicInferencer('esrgan', model_config=config, model_ckpt=checkpoint) output = editor.infer(img=img_path,result_out_dir='output.png') ``` Now, you can check your fancy photos in `output.png`. ================================================ FILE: docs/en/howto/dataset.md ================================================ # How to prepare your own datasets In this document, we will introduce the design of each datasets in MMagic and how users can design their own dataset. - [How to prepare your own datasets](#how-to-prepare-your-own-datasets) - [Supported Data Format](#supported-data-format) - [BasicImageDataset](#basicimagedataset) - [BasicFramesDataset](#basicframesdataset) - [BasicConditonalDataset](#basicconditonaldataset) - [1. Annotation file read by line (e.g., txt)](#1-annotation-file-read-by-line-eg-txt) - [2. Dict-based annotation file (e.g., json):](#2-dict-based-annotation-file-eg-json) - [3. Folder-based annotation (no annotation file need):](#3-folder-based-annotation-no-annotation-file-need) - [ImageNet Dataset and CIFAR10 Dataset](#imagenet-dataset-and-cifar10-dataset) - [AdobeComp1kDataset](#adobecomp1kdataset) - [GrowScaleImgDataset](#growscaleimgdataset) - [SinGANDataset](#singandataset) - [PairedImageDataset](#pairedimagedataset) - [UnpairedImageDataset](#unpairedimagedataset) - [Design a new dataset](#design-a-new-dataset) - [Repeat dataset](#repeat-dataset) ## Supported Data Format In MMagic, all datasets are inherited from `BaseDataset`. Each dataset load the list of data info (e.g., data path) by `load_data_list`. In `__getitem__`, `prepare_data` is called to get the preprocessed data. In `prepare_data`, data loading pipeline consists of the following steps: 1. fetch the data info by passed index, implemented by `get_data_info` 2. apply data transforms to the data, implemented by `pipeline` ### BasicImageDataset **BasicImageDataset** `mmagic.datasets.BasicImageDataset` General image dataset designed for low-level vision tasks with image, such as image super-resolution, inpainting and unconditional image generation. The annotation file is optional. If use annotation file, the annotation format can be shown as follows. ```bash Case 1 (CelebA-HQ): 000001.png 000002.png Case 2 (DIV2K): 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) 0001_s003.png (480,480,3) 0002_s001.png (480,480,3) 0002_s002.png (480,480,3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) ``` Here we give several examples showing how to use `BasicImageDataset`. Assume the file structure as the following: ```md mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ │ ├── image.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ │ │ ├── image_x4.png │ │ ├── DIV2K_valid_HR │ │ ├── DIV2K_valid_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ ├── places │ │ ├── test_set │ │ ├── train_set | | ├── meta | | | ├── Places365_train.txt | | | ├── Places365_val.txt | ├── celebahq │ │ ├── imgs_1024 ``` Case 1: Loading DIV2K dataset for training a SISR model. ```python dataset = BasicImageDataset( ann_file='', metainfo=dict( dataset_type='div2k', task_name='sisr'), data_root='data/DIV2K', data_prefix=dict( gt='DIV2K_train_HR', img='DIV2K_train_LR_bicubic/X4'), filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=[]) ``` Case 2: Loading places dataset for training an inpainting model. ```python dataset = BasicImageDataset( ann_file='meta/Places365_train.txt', metainfo=dict( dataset_type='places365', task_name='inpainting'), data_root='data/places', data_prefix=dict(gt='train_set'), pipeline=[]) ``` Case 3: Loading CelebA-HQ dataset for training an PGGAN. ```python dataset = BasicImageDataset( pipeline=[], data_root='./data/celebahq/imgs_1024') ``` ### BasicFramesDataset **BasicFramesDataset** `mmagic.datasets.BasicFramesDataset` General frames dataset designed for low-level vision tasks with frames, such as video super-resolution and video frame interpolation. The annotation file is optional. If use annotation file, the annotation format can be shown as follows. ```bash Case 1 (Vid4): calendar 41 city 34 foliage 49 walk 47 Case 2 (REDS): 000/00000000.png (720, 1280, 3) 000/00000001.png (720, 1280, 3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) ``` Assume the file structure as the following: ```bash mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── Vid4 │ │ ├── BIx4 │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── GT │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── meta_info_Vid4_GT.txt │ ├── vimeo-triplet │ │ ├── sequences | | | ├── 00001 │ │ │ │ ├── 0389 │ │ │ │ │ ├── img1.png │ │ │ │ │ ├── img2.png │ │ │ │ │ ├── img3.png │ │ ├── tri_trainlist.txt ``` Case 1: Loading Vid4 dataset for training a VSR model. ```python dataset = BasicFramesDataset( ann_file='meta_info_Vid4_GT.txt', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root='data/Vid4', data_prefix=dict(img='BIx4', gt='GT'), pipeline=[], depth=2, num_input_frames=5) ``` Case 2: Loading Vimeo90k dataset for training a VFI model. ```python dataset = BasicFramesDataset( ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root='data/vimeo-triplet', data_prefix=dict(img='sequences', gt='sequences'), pipeline=[], depth=2, load_frames_list=dict( img=['img1.png', 'img3.png'], gt=['img2.png'])) ``` ### BasicConditonalDataset **BasicConditonalDataset** `mmagic.datasets.BasicConditonalDataset` is designed for conditional GANs (e.g., SAGAN, BigGAN). This dataset support load label for the annotation file. `BasicConditonalDataset` support three kinds of annotation as follow: #### 1. Annotation file read by line (e.g., txt) Sample files structure: ``` data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... ``` Sample annotation file (the first column is the image path and the second column is the index of category): ``` folder_1/xxx.png 0 folder_1/xxy.png 1 folder_2/123.png 5 folder_2/nsdf3.png 3 ... ``` Config example for ImageNet dataset: ```python dataset=dict( type='BasicConditionalDataset, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), ``` #### 2. Dict-based annotation file (e.g., json): Sample files structure: ``` data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... ``` Sample annotation file (the key is the image path and the value column is the label): ``` { "folder_1/xxx.png": [1, 2, 3, 4], "folder_1/xxy.png": [2, 4, 1, 0], "folder_2/123.png": [0, 9, 8, 1], "folder_2/nsdf3.png", [1, 0, 0, 2], ... } ``` Config example for EG3D (shapenet-car) dataset: ```python dataset = dict( type='BasicConditionalDataset', data_root='./data/eg3d/shapenet-car', ann_file='annotation.json', pipeline=train_pipeline) ``` In this kind of annotation, labels can be any type and not restricted to an index. #### 3. Folder-based annotation (no annotation file need): Sample files structure: ``` data_prefix/ ├── class_x │ ├── xxx.png │ ├── xxy.png │ └── ... │ └── xxz.png └── class_y ├── 123.png ├── nsdf3.png ├── ... └── asd932_.png ``` If the annotation file is specified, the dataset will be generated by the first two ways, otherwise, try the third way. ### ImageNet Dataset and CIFAR10 Dataset **ImageNet Dataset** `mmagic.datasets.ImageNet` and **CIFAR10 Dataset**`mmagic.datasets.CIFAR10` are datasets specific designed for ImageNet and CIFAR10 datasets. Both two datasets are encapsulation of `BasicConditionalDataset`. You can used them to load data from ImageNet dataset and CIFAR10 dataset easily. Config example for ImageNet: ```python pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='RandomCropLongEdge', keys=['img']), dict(type='Resize', scale=(128, 128), keys=['img'], backend='pillow'), dict(type='Flip', keys=['img'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] dataset=dict( type='ImageNet', data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=pipeline), ``` Config example for CIFAR10: ```python pipeline = [dict(type='PackInputs')] dataset = dict( type='CIFAR10', data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=pipeline) ``` ### AdobeComp1kDataset **AdobeComp1kDataset** `mmagic.datasets.AdobeComp1kDataset` Adobe composition-1k dataset. The dataset loads (alpha, fg, bg) data and apply specified transforms to the data. You could specify whether composite merged image online or load composited merged image in pipeline. Example for online comp-1k dataset: ```md [ { "alpha": 'alpha/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] ``` Example for offline comp-1k dataset: ```md [ { "alpha": 'alpha/000.png', "merged": 'merged/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "merged": 'merged/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] ``` ### GrowScaleImgDataset `GrowScaleImgDataset` is designed for dynamic GAN models (e.g., PGGAN and StyleGANv1). In this dataset, we support switching the data root during training to load training images of different resolutions. This procedure is implemented by `GrowScaleImgDataset.update_annotations` and is called by `PGGANFetchDataHook.before_train_iter` in the training process. ```python def update_annotations(self, curr_scale): # determine if the data root needs to be updated if curr_scale == self._actual_curr_scale: return False # fetch new data root by resolution (scale) for scale in self._img_scales: if curr_scale <= scale: self._curr_scale = scale break if scale == self._img_scales[-1]: assert RuntimeError( f'Cannot find a suitable scale for {curr_scale}') self._actual_curr_scale = curr_scale self.data_root = self.data_roots[str(self._curr_scale)] # reload the data list with new data root self.load_data_list() # print basic dataset information to check the validity print_log('Update Dataset: ' + repr(self), 'current') return True ``` ### SinGANDataset `SinGANDataset` is designed for SinGAN's training. In SinGAN's training, we do not iterate the images in the dataset but return a consistent preprocessed image dict. Therefore, we bypass the default data loading logic of `BaseDataset` because we do not need to load the corresponding image data based on the given index. ```python def load_data_list(self, min_size, max_size, scale_factor_init): # load single image real = mmcv.imread(self.data_root) self.reals, self.scale_factor, self.stop_scale = create_real_pyramid( real, min_size, max_size, scale_factor_init) self.data_dict = {} # generate multi scale image for i, real in enumerate(self.reals): self.data_dict[f'real_scale{i}'] = real self.data_dict['input_sample'] = np.zeros_like( self.data_dict['real_scale0']).astype(np.float32) def __getitem__(self, index): # directly return the transformed data dict return self.pipeline(self.data_dict) ``` ### PairedImageDataset `PairedImageDataset` is designed for translation models that needs paired training data (e.g., Pix2Pix). The directory structure is shown below. Each image files are the concatenation of the image pair. ``` ./data/dataset_name/ ├── test │ └── XXX.jpg └── train └── XXX.jpg ``` In `PairedImageDataset`, we scan the file list in `load_data_list` and save path in `pair_path` field to fit the `LoadPairedImageFromFile` transformation. ```python def load_data_list(self): data_infos = [] pair_paths = sorted(self.scan_folder(self.data_root)) for pair_path in pair_paths: # save path in the specific field data_infos.append(dict(pair_path=pair_path)) return data_infos ``` ### UnpairedImageDataset `UnpairedImageDataset` is designed for translation models that do not need paired data (e.g., CycleGAN). The directory structure is shown below. ``` ./data/dataset_name/ ├── testA │ └── XXX.jpg ├── testB │ └── XXX.jpg ├── trainA │ └── XXX.jpg └── trainB └── XXX.jpg ``` In this dataset, we overwrite `__getitem__` function to load random image pair in the training process. ```python def __getitem__(self, idx): if not self.test_mode: return self.prepare_train_data(idx) return self.prepare_test_data(idx) def prepare_train_data(self, idx): img_a_path = self.data_infos_a[idx % self.len_a]['path'] idx_b = np.random.randint(0, self.len_b) img_b_path = self.data_infos_b[idx_b]['path'] results = dict() results[f'img_{self.domain_a}_path'] = img_a_path results[f'img_{self.domain_b}_path'] = img_b_path return self.pipeline(results) def prepare_test_data(self, idx): img_a_path = self.data_infos_a[idx % self.len_a]['path'] img_b_path = self.data_infos_b[idx % self.len_b]['path'] results = dict() results[f'img_{self.domain_a}_path'] = img_a_path results[f'img_{self.domain_b}_path'] = img_b_path return self.pipeline(results) ``` ## Design a new dataset If you want to create a dataset for a new low level CV task (e.g. denoise, derain, defog, and de-reflection) or existing dataset format doesn't meet your need, you can reorganize new data formats to existing format. Or create a new dataset in `mmagic/datasets` to load the data. Inheriting from the base class of datasets such as `BasicImageDataset` and `BasicFramesDataset` will make it easier to create a new dataset. And you can create a new dataset inherited from [BaseDataset](https://github.com/open-mmlab/mmengine/blob/main/mmengine/dataset/base_dataset.py) which is the base class of datasets in [MMEngine](https://github.com/open-mmlab/mmengine). Here is an example of creating a dataset for video frame interpolation: ```python from .basic_frames_dataset import BasicFramesDataset from mmagic.registry import DATASETS @DATASETS.register_module() class NewVFIDataset(BasicFramesDataset): """Introduce the dataset Examples of file structure. Args: pipeline (list[dict | callable]): A sequence of data transformations. folder (str | :obj:`Path`): Path to the folder. ann_file (str | :obj:`Path`): Path to the annotation file. test_mode (bool): Store `True` when building test dataset. Default: `False`. """ def __init__(self, ann_file, metainfo, data_root, data_prefix, pipeline, test_mode=False): super().__init__(ann_file, metainfo, data_root, data_prefix, pipeline, test_mode) self.data_infos = self.load_annotations() def load_annotations(self): """Load annoations for the dataset. Returns: list[dict]: A list of dicts for paired paths and other information. """ data_infos = [] ... return data_infos ``` Welcome to [submit new dataset classes to MMagic](https://github.com/open-mmlab/mmagic/compare). ### Repeat dataset We use [RepeatDataset](https://github.com/open-mmlab/mmengine/blob/main/mmengine/dataset/dataset_wrapper.py) as wrapper to repeat the dataset. For example, suppose the original dataset is Dataset_A, to repeat it, the config looks like the following ```python dataset_A_train = dict( type='RepeatDataset', times=N, dataset=dict( # This is the original config of Dataset_A type='Dataset_A', ... pipeline=train_pipeline ) ) ``` You may refer to [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/basedataset.md). ================================================ FILE: docs/en/howto/losses.md ================================================ # How to design your own loss functions `losses` are registered as `LOSSES` in `MMagic`. Customizing losses is similar to customizing any other model. This section is mainly for clarifying the design of loss modules in MMagic. Importantly, when writing your own loss modules, you should follow the same design, so that the new loss module can be adopted in our framework without extra effort. This guides includes: - [How to design your own loss functions](#how-to-design-your-own-loss-functions) - [Introduction to supported losses](#introduction-to-supported-losses) - [Design a new loss function](#design-a-new-loss-function) - [An example of MSELoss](#an-example-of-mseloss) - [An example of DiscShiftLoss](#an-example-of-discshiftloss) - [An example of GANWithCustomizedLoss](#an-example-of-ganwithcustomizedloss) - [Available losses](#available-losses) - [regular losses](#regular-losses) - [losses components](#losses-components) ## Introduction to supported losses For convenient usage, you can directly use default loss calculation process we set for concrete algorithms like lsgan, biggan, styleganv2 etc. Take `stylegan2` as an example, we use R1 gradient penalty and generator path length regularization as configurable losses, and users can adjust related arguments like `r1_loss_weight` and `g_reg_weight`. ```python # stylegan2_base.py loss_config = dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2) model = dict( type='StyleGAN2', xxx, loss_config=loss_config) ``` ## Design a new loss function ### An example of MSELoss In general, to implement a loss module, we will write a function implementation and then wrap it with a class implementation. Take the MSELoss as an example: ```python @masked_loss def mse_loss(pred, target): return F.mse_loss(pred, target, reduction='none') @LOSSES.register_module() class MSELoss(nn.Module): def __init__(self, loss_weight=1.0, reduction='mean', sample_wise=False): # codes can be found in ``mmagic/models/losses/pixelwise_loss.py`` def forward(self, pred, target, weight=None, **kwargs): # codes can be found in ``mmagic/models/losses/pixelwise_loss.py`` ``` Given the definition of the loss, we can now use the loss by simply defining it in the configuration file: ```python pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean') ``` Note that `pixel_loss` above must be defined in the model. Please refer to `customize_models` for more details. Similar to model customization, in order to use your customized loss, you need to import the loss in `mmagic/models/losses/__init__.py` after writing it. ### An example of DiscShiftLoss In general, to implement a loss module, we will write a function implementation and then wrap it with a class implementation. However, in `MMagic`, we provide another unified interface `data_info` for users to define the mapping between the input argument and data items. ```python @weighted_loss def disc_shift_loss(pred): return pred**2 @MODULES.register_module() class DiscShiftLoss(nn.Module): def __init__(self, loss_weight=1.0, data_info=None): super(DiscShiftLoss, self).__init__() # codes can be found in ``mmagic/models/losses/disc_auxiliary_loss.py`` def forward(self, *args, **kwargs): # codes can be found in ``mmagic/models/losses/disc_auxiliary_loss.py`` ``` The goal of this design for loss modules is to allow for using it automatically in the generative models (`MODELS`), without other complex codes to define the mapping between data and keyword arguments. Thus, different from other frameworks in `OpenMMLab`, our loss modules contain a special keyword, `data_info`, which is a dictionary defining the mapping between the input arguments and data from the generative models. Taking the `DiscShiftLoss` as an example, when writing the config file, users may use this loss as follows: ```python dict(type='DiscShiftLoss', loss_weight=0.001 * 0.5, data_info=dict(pred='disc_pred_real') ``` The information in `data_info` tells the module to use the `disc_pred_real` data as the input tensor for `pred` arguments. Once the `data_info` is not `None`, our loss module will automatically build up the computational graph. ```python @MODULES.register_module() class DiscShiftLoss(nn.Module): def __init__(self, loss_weight=1.0, data_info=None): super(DiscShiftLoss, self).__init__() self.loss_weight = loss_weight self.data_info = data_info def forward(self, *args, **kwargs): # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) kwargs.update(dict(weight=self.loss_weight)) return disc_shift_loss(**kwargs) else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. return disc_shift_loss(*args, weight=self.loss_weight, **kwargs) @staticmethod def loss_name(): return 'loss_disc_shift' ``` As shown in this part of codes, once users set the `data_info`, the loss module will receive a dictionary containing all of the necessary data and modules, which is provided by the `MODELS` in the training procedure. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using a keyword argument, please name it as `outputs_dict`. ### An example of GANWithCustomizedLoss To build the computational graph, the generative models have to provide a dictionary containing all kinds of data. Having a close look at any generative model, you will find that we collect all kinds of features and modules into a dictionary. We provide a customized `GANWithCustomizedLoss` here to show the process. ```python class GANWithCustomizedLoss(BaseModel): def __init__(self, gan_loss, disc_auxiliary_loss, gen_auxiliary_loss, *args, **kwargs): # ... if gan_loss is not None: self.gan_loss = MODULES.build(gan_loss) else: self.gan_loss = None if disc_auxiliary_loss: self.disc_auxiliary_losses = MODULES.build(disc_auxiliary_loss) if not isinstance(self.disc_auxiliary_losses, nn.ModuleList): self.disc_auxiliary_losses = nn.ModuleList( [self.disc_auxiliary_losses]) else: self.disc_auxiliary_loss = None if gen_auxiliary_loss: self.gen_auxiliary_losses = MODULES.build(gen_auxiliary_loss) if not isinstance(self.gen_auxiliary_losses, nn.ModuleList): self.gen_auxiliary_losses = nn.ModuleList( [self.gen_auxiliary_losses]) else: self.gen_auxiliary_losses = None def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: # ... # get data dict to compute losses for disc data_dict_ = dict( iteration=curr_iter, gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs) loss_disc, log_vars_disc = self._get_disc_loss(data_dict_) # ... def _get_disc_loss(self, outputs_dict): # Construct losses dict. If you hope some items to be included in the # computational graph, you have to add 'loss' in its name. Otherwise, # items without 'loss' in their name will just be used to print # information. losses_dict = {} # gan loss losses_dict['loss_disc_fake'] = self.gan_loss( outputs_dict['disc_pred_fake'], target_is_real=False, is_disc=True) losses_dict['loss_disc_real'] = self.gan_loss( outputs_dict['disc_pred_real'], target_is_real=True, is_disc=True) # disc auxiliary loss if self.with_disc_auxiliary_loss: for loss_module in self.disc_auxiliary_losses: loss_ = loss_module(outputs_dict) if loss_ is None: continue # the `loss_name()` function return name as 'loss_xxx' if loss_module.loss_name() in losses_dict: losses_dict[loss_module.loss_name( )] = losses_dict[loss_module.loss_name()] + loss_ else: losses_dict[loss_module.loss_name()] = loss_ loss, log_var = self.parse_losses(losses_dict) return loss, log_var ``` Here, the `_get_disc_loss` will help to combine all kinds of losses automatically. Therefore, as long as users design the loss module with the same rules, any kind of loss can be inserted in the training of generative models, without other modifications in the code of models. What you only need to do is just defining the `data_info` in the config files. ## Available losses We list available losses with examples in configs as follows. ### regular losses
Method class Example
vanilla gan loss mmagic.models.GANLoss ```python # dic gan loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ) ```
lsgan loss mmagic.models.GANLoss
wgan loss mmagic.models.GANLoss ```python # deepfillv1 loss_gan=dict( type='GANLoss', gan_type='wgan', loss_weight=0.0001, ) ```
hinge loss mmagic.models.GANLoss ```python # deepfillv2 loss_gan=dict( type='GANLoss', gan_type='hinge', loss_weight=0.1, ) ```
smgan loss mmagic.models.GANLoss ```python # aot-gan loss_gan=dict( type='GANLoss', gan_type='smgan', loss_weight=0.01, ) ```
gradient penalty mmagic.models.GradientPenaltyLoss ```python # deepfillv1 loss_gp=dict(type='GradientPenaltyLoss', loss_weight=10.) ```
discriminator shift loss mmagic.models.DiscShiftLoss ```python # deepfillv1 loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001) ```
clip loss mmagic.models.CLIPLoss
L1 composition loss mmagic.models.L1CompositionLoss
MSE composition loss mmagic.models.MSECompositionLoss
charbonnier composition loss mmagic.models.CharbonnierCompLoss ```python # dim loss_comp=dict(type='CharbonnierCompLoss', loss_weight=0.5) ```
face id Loss mmagic.models.FaceIdLoss
light cnn feature loss mmagic.models.LightCNNFeatureLoss ```python # dic gan feature_loss=dict( type='LightCNNFeatureLoss', pretrained=pretrained_light_cnn, loss_weight=0.1, criterion='l1') ```
gradient loss mmagic.models.GradientLoss
l1 Loss mmagic.models.L1Loss ```python # dic gan pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') ```
mse loss mmagic.models.MSELoss ```python # dic gan align_loss=dict(type='MSELoss', loss_weight=0.1, reduction='mean') ```
charbonnier loss mmagic.models.CharbonnierLoss ```python # dim loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5) ```
masked total variation loss mmagic.models.MaskedTVLoss ```python # partial conv loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1 ) ```
perceptual loss mmagic.models.PerceptualLoss ```python # real_basicvsr perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False) ```
transferal perceptual loss mmagic.models.TransferalPerceptualLoss ```python # ttsr transferal_perceptual_loss=dict( type='TransferalPerceptualLoss', loss_weight=1e-2, use_attention=False, criterion='mse') ```
### losses components For `GANWithCustomizedLoss`, we provide several components to build customized loss. | Method | class | | ------------------------------------ | ------------------------------------------- | | clip loss component | mmagic.models.CLIPLossComps | | discriminator shift loss component | mmagic.models. DiscShiftLossComps | | gradient penalty loss component | mmagic.models. GradientPenaltyLossComps | | r1 gradient penalty component | mmagic.models. R1GradientPenaltyComps | | face Id loss component | mmagic.models. FaceIdLossComps | | gan loss component | mmagic.models. GANLossComps | | generator path regularizer component | mmagic.models.GeneratorPathRegularizerComps | ================================================ FILE: docs/en/howto/models.md ================================================ # How to design your own models MMagic is built upon MMEngine and MMCV, which enables users to design new models quickly, train and evaluate them easily. In this section, you will learn how to design your own models. The structure of this guide are as follows: - [How to design your own models](#how-to-design-your-own-models) - [Overview of models in MMagic](#overview-of-models-in-mmagic) - [An example of SRCNN](#an-example-of-srcnn) - [Step 1: Define the network of SRCNN](#step-1-define-the-network-of-srcnn) - [Step 2: Define the model of SRCNN](#step-2-define-the-model-of-srcnn) - [Step 3: Start training SRCNN](#step-3-start-training-srcnn) - [An example of DCGAN](#an-example-of-dcgan) - [Step 1: Define the network of DCGAN](#step-1-define-the-network-of-dcgan) - [Step 2: Design the model of DCGAN](#step-2-design-the-model-of-dcgan) - [Step 3: Start training DCGAN](#step-3-start-training-dcgan) - [References](#references) ## Overview of models in MMagic In MMagic, one algorithm can be splited two compents: **Model** and **Module**. - **Model** are topmost wrappers and always inherint from `BaseModel` provided in MMEngine. **Model** is responsible to network forward, loss calculation and backward, parameters updating, etc. In MMagic, **Model** should be registered as `MODELS`. - **Module** includes the neural network **architectures** to train or inference, pre-defined **loss classes**, and **data preprocessors** to preprocess the input data batch. **Module** always present as elements of **Model**. In MMagic, **Module** should be registered as **MODULES**. Take DCGAN model as an example, [generator](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_generator.py) and [discriminator](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_discriminator.py) are the **Module**, which generate images and discriminate real or fake images. [`DCGAN`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan.py) is the **Model**, which take data from dataloader and train generator and discriminator alternatively. You can find the implementation of **Model** and **Module** by the following link. - **Model**: - [Editors](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/editors) - **Module**: - [Layers](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/layers) - [Losses](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/losses) - [Data Preprocessor](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/data_preprocessors) ## An example of SRCNN Here, we take the implementation of the classical image super-resolution model, SRCNN \[1\], as an example. ### Step 1: Define the network of SRCNN SRCNN is the first deep learning method for single image super-resolution \[1\]. To implement the network architecture of SRCNN, we need to create a new file `mmagic/models/editors/srgan/sr_resnet.py` and implement `class MSRResNet`. In this step, we implement `class MSRResNet` by inheriting from `mmengine.models.BaseModule` and define the network architecture in `__init__` function. In particular, we need to use `@MODELS.register_module()` to add the implementation of `class MSRResNet` into the registration of MMagic. ```python import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from mmagic.models.utils import (PixelShufflePack, ResidualBlockNoBN, default_init_weights, make_layer) @MODELS.register_module() class MSRResNet(BaseModule): """Modified SRResNet. A compacted version modified from SRResNet in "Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network". It uses residual blocks without BN, similar to EDSR. Currently, it supports x2, x3 and x4 upsampling scale factor. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_blocks (int): Block number in the trunk network. Default: 16. upscale_factor (int): Upsampling factor. Support x2, x3 and x4. Default: 4. """ _supported_upscale_factors = [2, 3, 4] def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=16, upscale_factor=4): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.mid_channels = mid_channels self.num_blocks = num_blocks self.upscale_factor = upscale_factor self.conv_first = nn.Conv2d( in_channels, mid_channels, 3, 1, 1, bias=True) self.trunk_net = make_layer( ResidualBlockNoBN, num_blocks, mid_channels=mid_channels) # upsampling if self.upscale_factor in [2, 3]: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, self.upscale_factor, upsample_kernel=3) elif self.upscale_factor == 4: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) else: raise ValueError( f'Unsupported scale factor {self.upscale_factor}. ' f'Currently supported ones are ' f'{self._supported_upscale_factors}.') self.conv_hr = nn.Conv2d( mid_channels, mid_channels, 3, 1, 1, bias=True) self.conv_last = nn.Conv2d( mid_channels, out_channels, 3, 1, 1, bias=True) self.img_upsampler = nn.Upsample( scale_factor=self.upscale_factor, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self.init_weights() def init_weights(self): """Init weights for models. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. strict (boo, optional): Whether strictly load the pretrained model. Defaults to True. """ for m in [self.conv_first, self.conv_hr, self.conv_last]: default_init_weights(m, 0.1) ``` Then, we implement the `forward` function of `class MSRResNet`, which takes as input tensor and then returns the results from `MSRResNet`. ```python def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ feat = self.lrelu(self.conv_first(x)) out = self.trunk_net(feat) if self.upscale_factor in [2, 3]: out = self.upsample1(out) elif self.upscale_factor == 4: out = self.upsample1(out) out = self.upsample2(out) out = self.conv_last(self.lrelu(self.conv_hr(out))) upsampled_img = self.img_upsampler(x) out += upsampled_img return out ``` After the implementation of `class MSRResNet`, we need to update the model list in `mmagic/models/editors/__init__.py`, so that we can import and use `class MSRResNet` by `mmagic.models.editors`. ```python from .srgan.sr_resnet import MSRResNet ``` ### Step 2: Define the model of SRCNN After the implementation of the network architecture, we need to define our model `class BaseEditModel` and implement the forward loop of `class BaseEditModel`. To implement `class BaseEditModel`, we create a new file `mmagic/models/base_models/base_edit_model.py`. Specifically, `class BaseEditModel` inherits from `mmengine.model.BaseModel`. In the `__init__` function, we define the loss functions, training and testing configurations, networks of `class BaseEditModel`. ```python from typing import List, Optional import torch from mmengine.model import BaseModel from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class BaseEditModel(BaseModel): """Base model for image and video editing. It must contain a generator that takes frames as inputs and outputs an interpolated frame. It also has a pixel-wise loss for training. Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. Default: None. """ def __init__(self, generator, pixel_loss, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.train_cfg = train_cfg self.test_cfg = test_cfg # generator self.generator = MODELS.build(generator) # loss self.pixel_loss = MODELS.build(pixel_loss) ``` Since `mmengine.model.BaseModel` provides the basic functions of the algorithmic model, such as weights initialize, batch inputs preprocess, parse losses, and update model parameters. Therefore, the subclasses inherit from BaseModel, i.e., `class BaseEditModel` in this example, only need to implement the forward method, which implements the logic to calculate loss and predictions. Specifically, the implemented `forward` function of `class BaseEditModel` takes as input `batch_inputs` and `data_samples` and return results according to mode arguments. ```python def forward(self, batch_inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs): """Returns losses or predictions of training, validation, testing, and simple inference process. ``forward`` method of BaseModel is an abstract method, its subclasses must implement this method. Accepts ``batch_inputs`` and ``data_samples`` processed by :attr:`data_preprocessor`, and returns results according to mode arguments. During non-distributed training, validation, and testing process, ``forward`` will be called by ``BaseModel.train_step``, ``BaseModel.val_step`` and ``BaseModel.val_step`` directly. During distributed data parallel training process, ``MMSeparateDistributedDataParallel.train_step`` will first call ``DistributedDataParallel.forward`` to enable automatic gradient synchronization, and then call ``forward`` to get training loss. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor`` - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict or tensor for custom use. """ if mode == 'tensor': return self.forward_tensor(batch_inputs, data_samples, **kwargs) elif mode == 'predict': return self.forward_inference(batch_inputs, data_samples, **kwargs) elif mode == 'loss': return self.forward_train(batch_inputs, data_samples, **kwargs) ``` Specifically, in `forward_tensor`, `class BaseEditModel` returns the forward tensors of the network directly. ```python def forward_tensor(self, batch_inputs, data_samples=None, **kwargs): """Forward tensor. Returns result of simple forward. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: result of simple forward. """ feats = self.generator(batch_inputs, **kwargs) return feats ``` In `forward_inference` function, `class BaseEditModel` first converts the forward tensors to images and then returns the images as output. ```python def forward_inference(self, batch_inputs, data_samples=None, **kwargs): """Forward inference. Returns predictions of validation, testing, and simple inference. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: List[DataSample]: predictions. """ feats = self.forward_tensor(batch_inputs, data_samples, **kwargs) feats = self.data_preprocessor.destructor(feats) predictions = [] for idx in range(feats.shape[0]): predictions.append( DataSample( pred_img=feats[idx].to('cpu'), metainfo=data_samples[idx].metainfo)) return predictions ``` In `forward_train`, `class BaseEditModel` calculate the loss function and returns a dictionary contains the losses as output. ```python def forward_train(self, batch_inputs, data_samples=None, **kwargs): """Forward training. Returns dict of losses of training. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ feats = self.forward_tensor(batch_inputs, data_samples, **kwargs) gt_imgs = [data_sample.gt_img.data for data_sample in data_samples] batch_gt_data = torch.stack(gt_imgs) loss = self.pixel_loss(feats, batch_gt_data) return dict(loss=loss) ``` After the implementation of `class BaseEditModel`, we need to update the model list in `mmagic/models/__init__.py`, so that we can import and use `class BaseEditModel` by `mmagic.models`. ```python from .base_models.base_edit_model import BaseEditModel ``` ### Step 3: Start training SRCNN After implementing the network architecture and the forward loop of SRCNN, now we can create a new file `configs/srcnn/srcnn_x4k915_g1_1000k_div2k.py` to set the configurations needed by training SRCNN. In the configuration file, we need to specify the parameters of our model, `class BaseEditModel`, including the generator network architecture, loss function, additional training and testing configuration, and data preprocessor of input tensors. Please refer to the [Introduction to the loss in MMagic](./losses.md) for more details of losses in MMagic. ```python # model settings model = dict( type='BaseEditModel', generator=dict( type='SRCNNNet', channels=(3, 64, 32, 3), kernel_sizes=(9, 1, 5), upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ``` We also need to specify the training dataloader and testing dataloader according to create your own dataloader. Finally we can start training our own model by: ```python python tools/train.py configs/srcnn/srcnn_x4k915_g1_1000k_div2k.py ``` ## An example of DCGAN Here, we take the implementation of the classical gan model, DCGAN \[2\], as an example. ### Step 1: Define the network of DCGAN DCGAN is a classical image generative adversarial network \[2\]. To implement the network architecture of DCGAN, we need to create tow new files `mmagic/models/editors/dcgan/dcgan_generator.py` and `mmagic/models/editors/dcgan/dcgan_discriminator.py`, and implement generator (`class DCGANGenerator`) and discriminator (`class DCGANDiscriminator`). In this step, we implement `class DCGANGenerator`, `class DCGANDiscriminator` and define the network architecture in `__init__` function. In particular, we need to use `@MODULES.register_module()` to add the generator and discriminator into the registration of MMagic. Take the following code as example: ```python import torch.nn as nn from mmcv.cnn import ConvModule from mmcv.runner import load_checkpoint from mmcv.utils.parrots_wrapper import _BatchNorm from mmengine.logging import MMLogger from mmengine.model.utils import normal_init from mmagic.models.builder import MODULES from ..common import get_module_device @MODULES.register_module() class DCGANGenerator(nn.Module): def __init__(self, output_scale, out_channels=3, base_channels=1024, input_scale=4, noise_size=100, default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='ReLU'), out_act_cfg=dict(type='Tanh'), pretrained=None): super().__init__() self.output_scale = output_scale self.base_channels = base_channels self.input_scale = input_scale self.noise_size = noise_size # the number of times for upsampling self.num_upsamples = int(np.log2(output_scale // input_scale)) # output 4x4 feature map self.noise2feat = ConvModule( noise_size, base_channels, kernel_size=4, stride=1, padding=0, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg) # build up upsampling backbone (excluding the output layer) upsampling = [] curr_channel = base_channels for _ in range(self.num_upsamples - 1): upsampling.append( ConvModule( curr_channel, curr_channel // 2, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) curr_channel //= 2 self.upsampling = nn.Sequential(*upsampling) # output layer self.output_layer = ConvModule( curr_channel, out_channels, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=None, act_cfg=out_act_cfg) ``` Then, we implement the `forward` function of `DCGANGenerator`, which takes as `noise` tensor or `num_batches` and then returns the results from `DCGANGenerator`. ```python def forward(self, noise, num_batches=0, return_noise=False): noise_batch = noise_batch.to(get_module_device(self)) x = self.noise2feat(noise_batch) x = self.upsampling(x) x = self.output_layer(x) return x ``` If you want to implement specific weights initialization method for you network, you need add `init_weights` function by yourself. ```python def init_weights(self, pretrained=None): if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): normal_init(m, 0, 0.02) elif isinstance(m, _BatchNorm): nn.init.normal_(m.weight.data) nn.init.constant_(m.bias.data, 0) else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') ``` After the implementation of class `DCGANGenerator`, we need to update the model list in `mmagic/models/editors/__init__.py`, so that we can import and use class `DCGANGenerator` by `mmagic.models.editors`. Implementation of Class `DCGANDiscriminator` follows the similar logic, and you can find the implementation [here](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_discriminator.py). ### Step 2: Design the model of DCGAN After the implementation of the network **Module**, we need to define our **Model** class `DCGAN`. Your **Model** should inherit from [`BaseModel`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/base_model/base_model.py#L16) provided by MMEngine and implement three functions, `train_step`, `val_step` and `test_step`. - `train_step`: This function is responsible to update the parameters of the network and called by MMEngine's Loop ([`IterBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L183) or [`EpochBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L18)). `train_step` take data batch and [`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md) as input and return a dict of log. - `val_step`: This function is responsible for getting output for validation during the training process. and is called by [`MultiValLoop`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/engine/runner/multi_loops.py#L19). - `test_step`: This function is responsible for getting output in test process and is called by [`MultiTestLoop`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/engine/runner/multi_loops.py#L274). > Note that, in `train_step`, `val_step` and `test_step`, `DataPreprocessor` is called to preprocess the input data batch before feed them to the neural network. To know more about `DataPreprocessor` please refer to this [file](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/data_preprocessors/gen_preprocessor.py) and this [tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/tutorials/model.md#%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E5%99%A8datapreprocessor). For simplify using, we provide [`BaseGAN`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/base_models/base_gan.py) class in MMagic, which implements generic `train_step`, `val_step` and `test_step` function for GAN models. With `BaseGAN` as base class, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. In `train_step`, we support data preprocessing, gradient accumulation (realized by [`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md)) and expontial moving averate (EMA) realized by [(`ExponentialMovingAverage`)](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/base_models/average_model.py#L19). With `BaseGAN.train_step`, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. ```python def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts # train discriminator, use context manager provided by MMEngine with disc_optimizer_wrapper.optim_context(self.discriminator): # train_discriminator should be implemented! log_vars = self.train_discriminator( **data, optimizer_wrapper=disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) # update generator, use context manager provided by MMEngine for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): # train_generator should be implemented! log_vars_gen = self.train_generator( **data, optimizer_wrapper=gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) # return the log dict return log_vars ``` In `val_step` and `test_step`, we call data preprocessing and `BaseGAN.forward` progressively. ```python def val_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) # call `forward` outputs = self(**data) return outputs def test_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) # call `orward` outputs = self(**data) return outputs ``` Then, we implement `train_generator` and `train_discriminator` in `DCGAN` class. ```python from typing import Dict, Tuple import torch import torch.nn.functional as F from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from .base_gan import BaseGAN @MODELS.register_module() class DCGAN(BaseGAN): def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: losses_dict = dict() losses_dict['loss_disc_fake'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 0. * torch.ones_like(disc_pred_fake)) losses_dict['loss_disc_real'] = F.binary_cross_entropy_with_logits( disc_pred_real, 1. * torch.ones_like(disc_pred_real)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple: losses_dict = dict() losses_dict['loss_gen'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 1. * torch.ones_like(disc_pred_fake)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator( self, inputs, data_sample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: real_imgs = inputs['img'] num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs, data_sample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: num_batches = inputs['img'].shape[0] noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ``` After the implementation of `class DCGAN`, we need to update the model list in `mmagic/models/__init__.py`, so that we can import and use `class DCGAN` by `mmagic.models`. ### Step 3: Start training DCGAN After implementing the network **Module** and the **Model** of DCGAN, now we can create a new file `configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py` to set the configurations needed by training DCGAN. In the configuration file, we need to specify the parameters of our model, `class DCGAN`, including the generator network architecture and data preprocessor of input tensors. ```python # model settings model = dict( type='DCGAN', noise_size=100, data_preprocessor=dict(type='GANDataPreprocessor'), generator=dict(type='DCGANGenerator', output_scale=64, base_channels=1024), discriminator=dict( type='DCGANDiscriminator', input_scale=64, output_scale=4, out_channels=1)) ``` We also need to specify the training dataloader and testing dataloader according to [create your own dataloader](dataset.md). Finally we can start training our own model by: ```python python tools/train.py configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py ``` ## References 1. Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou. Image Super-Resolution Using Deep Convolutional Networks\[J\]. IEEE transactions on pattern analysis and machine intelligence, 2015. 2. Radford, Alec, Luke Metz, and Soumith Chintala. "Unsupervised representation learning with deep convolutional generative adversarial networks." arXiv preprint arXiv:1511.06434 (2015). ================================================ FILE: docs/en/howto/transforms.md ================================================ # How to design your own data transforms In this tutorial, we introduce the design of transforms pipeline in MMagic. The structure of this guide are as follows: - [How to design your own data transforms](#how-to-design-your-own-data-transforms) - [Data pipelines in MMagic](#data-pipelines-in-mmagic) - [A simple example of data transform](#a-simple-example-of-data-transform) - [An example of BasicVSR](#an-example-of-basicvsr) - [An example of Pix2Pix](#an-example-of-pix2pix) - [Supported transforms in MMagic](#supported-transforms-in-mmagic) - [Data loading](#data-loading) - [Pre-processing](#pre-processing) - [Formatting](#formatting) - [Extend and use custom pipelines](#extend-and-use-custom-pipelines) - [A simple example of MyTransform](#a-simple-example-of-mytransform) - [An example of flipping](#an-example-of-flipping) ## Data pipelines in MMagic Following typical conventions, we use `Dataset` and `DataLoader` for data loading with multiple workers. `Dataset` returns a dict of data items corresponding the arguments of models' forward method. The data preparation pipeline and the dataset is decomposed. Usually a dataset defines how to process the annotations and a data pipeline defines all the steps to prepare a data dict. A pipeline consists of a sequence of operations. Each operation takes a dict as input and also output a dict for the next transform. The operations are categorized into data loading, pre-processing, and formatting In MMagic, all data transformations are inherited from `BaseTransform`. The input and output types of transformations are both dict. ### A simple example of data transform ```python >>> from mmagic.transforms import LoadPairedImageFromFile >>> transforms = LoadPairedImageFromFile( >>> key='pair', >>> domain_a='horse', >>> domain_b='zebra', >>> flag='color'), >>> data_dict = {'pair_path': './data/pix2pix/facades/train/1.png'} >>> data_dict = transforms(data_dict) >>> print(data_dict.keys()) dict_keys(['pair_path', 'pair', 'pair_ori_shape', 'img_mask', 'img_photo', 'img_mask_path', 'img_photo_path', 'img_mask_ori_shape', 'img_photo_ori_shape']) ``` Generally, the last step of the transforms pipeline must be `PackInputs`. `PackInputs` will pack the processed data into a dict containing two fields: `inputs` and `data_samples`. `inputs` is the variable you want to use as the model's input, which can be the type of `torch.Tensor`, dict of `torch.Tensor`, or any type you want. `data_samples` is a list of `DataSample`. Each `DataSample` contains groundtruth and necessary information for corresponding input. ### An example of BasicVSR Here is a pipeline example for BasicVSR. ```python train_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=256), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='MirrorSequence', keys=['img', 'gt']), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='MirrorSequence', keys=['img']), dict(type='PackInputs') ] ``` For each operation, we list the related dict fields that are added/updated/removed, the dict fields marked by '\*' are optional. ### An example of Pix2Pix Here is a pipeline example for Pix2Pix training on aerial2maps dataset. ```python source_domain = 'aerial' target_domain = 'map' pipeline = [ dict( type='LoadPairedImageFromFile', io_backend='disk', key='pair', domain_a=domain_a, domain_b=domain_b, flag='color'), dict( type='TransformBroadcaster', mapping={'img': [f'img_{domain_a}', f'img_{domain_b}']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='mmagic.Resize', scale=(286, 286), interpolation='bicubic'), dict(type='mmagic.FixedCrop', crop_size=(256, 256)) ]), dict( type='Flip', keys=[f'img_{domain_a}', f'img_{domain_b}'], direction='horizontal'), dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}', 'pair']) ``` ## Supported transforms in MMagic ### Data loading
Transform Modification of Results' keys
LoadImageFromFile - add: img, img_path, img_ori_shape, \*ori_img
RandomLoadResizeBg - add: bg
LoadMask - add: mask
GetSpatialDiscountMask - add: discount_mask
### Pre-processing
Transform Modification of Results' keys
Resize - add: scale_factor, keep_ratio, interpolation, backend - update: specified by keys
MATLABLikeResize - add: scale, output_shape - update: specified by keys
RandomRotation - add: degrees - update: specified by keys
Flip - add: flip, flip_direction - update: specified by keys
RandomAffine - update: specified by keys
RandomJitter - update: fg (img)
ColorJitter - update: specified by keys
BinarizeImage - update: specified by keys
RandomMaskDilation - add: img_dilate_kernel_size
RandomTransposeHW - add: transpose
RandomDownSampling - update: scale, gt (img), lq (img)
RandomBlur - update: specified by keys
RandomResize - update: specified by keys
RandomNoise - update: specified by keys
RandomJPEGCompression - update: specified by keys
RandomVideoCompression - update: specified by keys
DegradationsWithShuffle - update: specified by keys
GenerateFrameIndices - update: img_path (gt_path, lq_path)
GenerateFrameIndiceswithPadding - update: img_path (gt_path, lq_path)
TemporalReverse - add: reverse - update: specified by keys
GenerateSegmentIndices - add: interval - update: img_path (gt_path, lq_path)
MirrorSequence - update: specified by keys
CopyValues - add: specified by dst_key
UnsharpMasking - add: img_unsharp
Crop - add: img_crop_bbox, crop_size - update: specified by keys
RandomResizedCrop - add: img_crop_bbox - update: specified by keys
FixedCrop - add: crop_size, crop_pos - update: specified by keys
PairedRandomCrop - update: gt (img), lq (img)
CropAroundCenter - add: crop_bbox - update: fg (img), alpha (img), trimap (img), bg (img)
CropAroundUnknown - add: crop_bbox - update: specified by keys
CropAroundFg - add: crop_bbox - update: specified by keys
ModCrop - update: gt (img)
CropLike - update: specified by target_key
GetMaskedImage - add: masked_img
GenerateFacialHeatmap - add: heatmap
GenerateCoordinateAndCell - add: coord, cell - update: gt (img)
Normalize - add: img_norm_cfg - update: specified by keys
RescaleToZeroOne - update: specified by keys
### Formatting
Transform Modification of Results' keys
ToTensor update: specified by keys.
FormatTrimap - update: trimap
PackInputs - add: inputs, data_sample - remove: all other keys
### Albumentations MMagic support adding custom transformations from [Albumentations](https://github.com/albumentations-team/albumentations) library. Please visit https://albumentations.ai/docs/getting_started/transforms_and_targets to get more information. An example of Albumentations's `transforms` is as followed: ```python albu_transforms = [ dict( type='Resize', height=100, width=100, ), dict( type='RandomFog', p=0.5, ), dict( type='RandomRain', p=0.5 ), dict( type='RandomSnow', p=0.5, ), ] pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Albumentations', keys=['img'], transforms=albu_transforms), dict(type='PackInputs') ] ``` ## Extend and use custom pipelines ### A simple example of MyTransform 1. Write a new pipeline in a file, e.g., in `my_pipeline.py`. It takes a dict as input and returns a dict. ```python import random from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class MyTransform(BaseTransform): """Add your transform Args: p (float): Probability of shifts. Default 0.5. """ def __init__(self, p=0.5): self.p = p def transform(self, results): if random.random() > self.p: results['dummy'] = True return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(p={self.p})') return repr_str ``` 2. Import and use the pipeline in your config file. Make sure the import is relative to where your train script is located. ```python train_pipeline = [ ... dict(type='MyTransform', p=0.2), ... ] ``` ### An example of flipping Here we use a simple flipping transformation as example: ```python import random import mmcv from mmcv.transforms import BaseTransform, TRANSFORMS @TRANSFORMS.register_module() class MyFlip(BaseTransform): def __init__(self, direction: str): super().__init__() self.direction = direction def transform(self, results: dict) -> dict: img = results['img'] results['img'] = mmcv.imflip(img, direction=self.direction) return results ``` Thus, we can instantiate a `MyFlip` object and use it to process the data dict. ```python import numpy as np transform = MyFlip(direction='horizontal') data_dict = {'img': np.random.rand(224, 224, 3)} data_dict = transform(data_dict) processed_img = data_dict['img'] ``` Or, we can use `MyFlip` transformation in data pipeline in our config file. ```python pipeline = [ ... dict(type='MyFlip', direction='horizontal'), ... ] ``` Note that if you want to use `MyFlip` in config, you must ensure the file containing `MyFlip` is imported during the program run. ================================================ FILE: docs/en/index.rst ================================================ Welcome to MMagic's documentation! ===================================== Languages: `English `_ | `简体中文 `_ MMagic (**M**\ultimodal **A**\dvanced, **G**\enerative, and **I**\ntelligent **C**\reation) is an open-source AIGC toolbox for professional AI researchers and machine learning engineers to explore image and video processing, editing and generation. MMagic supports various foundamental generative models, including: * Unconditional Generative Adversarial Networks (GANs) * Conditional Generative Adversarial Networks (GANs) * Internal Learning * Diffusion Models * And many other generative models are coming soon! MMagic supports various applications, including: - Text-to-Image - Image-to-image translation - 3D-aware generation - Image super-resolution - Video super-resolution - Video frame interpolation - Image inpainting - Image matting - Image restoration - Image colorization - Image generation - And many other applications are coming soon! MMagic is based on `PyTorch `_ and is a part of the `OpenMMLab project `_. Codes are available on `GitHub `_. Documentation ============= .. toctree:: :maxdepth: 1 :caption: Community community/contributing.md community/projects.md .. toctree:: :maxdepth: 1 :caption: Get Started get_started/overview.md get_started/install.md get_started/quick_run.md .. toctree:: :maxdepth: 1 :caption: User Guides user_guides/config.md user_guides/dataset_prepare.md user_guides/inference.md user_guides/train_test.md user_guides/metrics.md user_guides/visualization.md user_guides/useful_tools.md user_guides/deploy.md .. toctree:: :maxdepth: 2 :caption: Advanced Guides advanced_guides/models.md advanced_guides/dataset.md advanced_guides/transforms.md advanced_guides/losses.md advanced_guides/evaluator.md advanced_guides/structures.md advanced_guides/data_preprocessor.md advanced_guides/data_flow.md .. toctree:: :maxdepth: 2 :caption: How To howto/models.md howto/dataset.md howto/transforms.md howto/losses.md .. toctree:: :maxdepth: 1 :caption: FAQ faq.md .. toctree:: :maxdepth: 2 :caption: Model Zoo model_zoo/index.rst .. toctree:: :maxdepth: 1 :caption: Dataset Zoo dataset_zoo/index.rst .. toctree:: :maxdepth: 1 :caption: Changelog changelog.md .. toctree:: :maxdepth: 2 :caption: API Reference mmagic.apis.inferencers mmagic.structures mmagic.datasets mmagic.datasets.transforms mmagic.evaluation mmagic.visualization mmagic.engine.hooks mmagic.engine.logging mmagic.engine.optimizers mmagic.engine.runner mmagic.engine.schedulers mmagic.models.archs mmagic.models.base_models mmagic.models.losses mmagic.models.data_preprocessors mmagic.models.utils mmagic.models.editors mmagic.utils .. toctree:: :maxdepth: 1 :caption: Migration from MMEdit 0.x migration/overview.md migration/runtime.md migration/models.md migration/eval_test.md migration/schedule.md migration/data.md migration/distributed_train.md migration/optimizers.md migration/visualization.md migration/amp.md .. toctree:: :maxdepth: 1 :caption: Device Support device/npu.md .. toctree:: :caption: Switch Language switch_language.md Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: docs/en/make.bat ================================================ @ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd ================================================ FILE: docs/en/migration/amp.md ================================================ # Migration of AMP Training In 0.x, MMEditing do not support AMP training for the entire forward process. Instead, users must use `auto_fp16` decorator to warp the specific submodule and convert the parameter of submodule to fp16. This allows for fine-grained control of the model parameters, but is more cumbersome to use. In addition, users need to handle operations such as scaling of the loss function during the training process by themselves. MMagic 1.x use `AmpOptimWrapper` provided by MMEngine. In `AmpOptimWrapper.update_params`, gradient scaling and `GradScaler` updating is automatically performed. And in `optim_context` context manager, `auto_cast` is applied to the entire forward process. Specifically, the difference between the 0.x and 1.x is as follows:
0.x version 1.x Version
```python # config runner = dict(fp16_loss_scaler=dict(init_scale=512)) ``` ```python # code import torch.nn as nn from mmedit.models.builder import build_model from mmedit.core.runners.fp16_utils import auto_fp16 class DemoModule(nn.Module): def __init__(self, cfg): self.net = build_model(cfg) @auto_fp16 def forward(self, x): return self.net(x) class DemoModel(nn.Module): def __init__(self, cfg): super().__init__(self) self.demo_network = DemoModule(cfg) def train_step(self, data_batch, optimizer, ddp_reducer=None, loss_scaler=None, use_apex_amp=False, running_status=None): # get data from data_batch inputs = data_batch['img'] output = self.demo_network(inputs) optimizer.zero_grad() loss, log_vars = self.get_loss(data_dict_) if ddp_reducer is not None: ddp_reducer.prepare_for_backward(_find_tensors(loss_disc)) if loss_scaler: # add support for fp16 loss_scaler.scale(loss_disc).backward() elif use_apex_amp: from apex import amp with amp.scale_loss(loss_disc, optimizer, loss_id=0) as scaled_loss_disc: scaled_loss_disc.backward() else: loss_disc.backward() if loss_scaler: loss_scaler.unscale_(optimizer) loss_scaler.step(optimizer) else: optimizer.step() ``` ```python # config optim_wrapper = dict( constructor='OptimWrapperConstructor', generator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-06), type='AmpOptimWrapper', # use amp wrapper loss_scale='dynamic'), discriminator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-06), type='AmpOptimWrapper', # use amp wrapper loss_scale='dynamic')) ``` ```python # code import torch.nn as nn from mmagic.registry import MODULES from mmengine.model import BaseModel class DemoModule(nn.Module): def __init__(self, cfg): self.net = MODULES.build(cfg) def forward(self, x): return self.net(x) class DemoModel(BaseModel): def __init__(self, cfg): super().__init__(self) self.demo_network = DemoModule(cfg) def train_step(self, data, optim_wrapper): # get data from data_batch data = self.data_preprocessor(data, True) inputs = data['inputs'] with optim_wrapper.optim_context(self.discriminator): output = self.demo_network(inputs) loss_dict = self.get_loss(output) # use parse_loss provide by `BaseModel` loss, log_vars = self.parse_loss(loss_dict) optimizer_wrapper.update_params(loss) return log_vars ```
To avoid user modifications to the configuration file, MMagic provides the `--amp` option in `train.py`, which allows the user to start AMP training without modifying the configuration file. Users can start AMP training by following command: ```bash bash tools/dist_train.sh CONFIG GPUS --amp # for slurm users bash tools/slurm_train.sh PARTITION JOB_NAME CONFIG WORK_DIR --amp ``` ================================================ FILE: docs/en/migration/data.md ================================================ # Migration of Data Settings This section introduces the migration of data settings: - [Migration of Data Settings](#migration-of-data-settings) - [Data pipelines](#data-pipelines) - [Dataloader](#dataloader) ## Data pipelines We update data pipelines settings in MMagic 1.x. Important modifications are as following. - Remove normalization and color space transforms operations. They are moved from datasets transforms pipelines to data_preprocessor. - The original formatting transforms pipelines `Collect` and `ToTensor` are combined as `PackInputs`. More details of data pipelines are shown in [transform guides](../howto/transforms.md).
Original New
```python train_pipeline = [ # Training data processing pipeline dict(type='LoadImageFromFile', # Load images from files io_backend='disk', # io backend key='lq', # Keys in results to find corresponding path flag='unchanged'), # flag for reading images dict(type='LoadImageFromFile', # Load images from files io_backend='disk', # io backend key='gt', # Keys in results to find corresponding path flag='unchanged'), # flag for reading images dict(type='RescaleToZeroOne', keys=['lq', 'gt']), # Rescale images from [0, 255] to [0, 1] dict(type='Normalize', # Augmentation pipeline that normalize the input images keys=['lq', 'gt'], # Images to be normalized mean=[0, 0, 0], # Mean values std=[1, 1, 1], # Standard variance to_rgb=True), # Change to RGB channel dict(type='PairedRandomCrop', gt_patch_size=96), # Paired random crop dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='horizontal'), # Flip direction dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip direction dict(type='RandomTransposeHW', # Random transpose h and w for images keys=['lq', 'gt'], # Images to be transposed transpose_ratio=0.5 # Transpose ratio ), dict(type='Collect', # Pipeline that decides which keys in the data should be passed to the model keys=['lq', 'gt'], # Keys to pass to the model meta_keys=['lq_path', 'gt_path']), # Meta information keys. In training, meta information is not needed dict(type='ToTensor', # Convert images to tensor keys=['lq', 'gt']) # Images to be converted to Tensor ] test_pipeline = [ # Test pipeline dict( type='LoadImageFromFile', # Load images from files io_backend='disk', # io backend key='lq', # Keys in results to find corresponding path flag='unchanged'), # flag for reading images dict( type='LoadImageFromFile', # Load images from files io_backend='disk', # io backend key='gt', # Keys in results to find corresponding path flag='unchanged'), # flag for reading images dict(type='RescaleToZeroOne', keys=['lq', 'gt']), # Rescale images from [0, 255] to [0, 1] dict( type='Normalize', # Augmentation pipeline that normalize the input images keys=['lq', 'gt'], # Images to be normalized mean=[0, 0, 0], # Mean values std=[1, 1, 1], # Standard variance to_rgb=True), # Change to RGB channel dict(type='Collect', # Pipeline that decides which keys in the data should be passed to the model keys=['lq', 'gt'], # Keys to pass to the model meta_keys=['lq_path', 'gt_path']), # Meta information keys dict(type='ToTensor', # Convert images to tensor keys=['lq', 'gt']) # Images to be converted to Tensor ] ``` ```python train_pipeline = [ # Training data processing pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='SetValues', dictionary=dict(scale=scale)), # Set value to destination keys dict(type='PairedRandomCrop', gt_patch_size=96), # Paired random crop dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='horizontal'), # Flip direction dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip direction dict(type='RandomTransposeHW', # Random transpose h and w for images keys=['lq', 'gt'], # Images to be transposed transpose_ratio=0.5 # Transpose ratio ), dict(type='PackInputs') # The config of collecting data from current pipeline ] test_pipeline = [ # Test pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='PackInputs') # The config of collecting data from current pipeline ] ```
## Dataloader We update dataloader settings in MMagic 1.x. Important modifications are as following. - The original `data` field is split to `train_dataloader`, `val_dataloader` and `test_dataloader`. This allows us to configure them in fine-grained. For example, you can specify different sampler and batch size during training and test. - The `samples_per_gpu` is renamed to `batch_size`. - The `workers_per_gpu` is renamed to `num_workers`.
Original New
```python data = dict( # train samples_per_gpu=16, # Batch size of a single GPU workers_per_gpu=4, # Worker to pre-fetch data for each single GPU drop_last=True, # Use drop_last in data_loader train=dict( # Train dataset config type='RepeatDataset', # Repeated dataset for iter-based model times=1000, # Repeated times for RepeatDataset dataset=dict( type=train_dataset_type, # Type of dataset lq_folder='data/DIV2K/DIV2K_train_LR_bicubic/X2_sub', # Path for lq folder gt_folder='data/DIV2K/DIV2K_train_HR_sub', # Path for gt folder ann_file='data/DIV2K/meta_info_DIV2K800sub_GT.txt', # Path for annotation file pipeline=train_pipeline, # See above for train_pipeline scale=scale)), # Scale factor for upsampling # val val_samples_per_gpu=1, # Batch size of a single GPU for validation val_workers_per_gpu=4, # Worker to pre-fetch data for each single GPU for validation val=dict( type=val_dataset_type, # Type of dataset lq_folder='data/val_set5/Set5_bicLRx2', # Path for lq folder gt_folder='data/val_set5/Set5_mod12', # Path for gt folder pipeline=test_pipeline, # See above for test_pipeline scale=scale, # Scale factor for upsampling filename_tmpl='{}'), # filename template # test test=dict( type=val_dataset_type, # Type of dataset lq_folder='data/val_set5/Set5_bicLRx2', # Path for lq folder gt_folder='data/val_set5/Set5_mod12', # Path for gt folder pipeline=test_pipeline, # See above for test_pipeline scale=scale, # Scale factor for upsampling filename_tmpl='{}')) # filename template ``` ```python dataset_type = 'BasicImageDataset' # The type of dataset data_root = 'data' # Root path of data train_dataloader = dict( batch_size=16, num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive sampler=dict(type='InfiniteSampler', shuffle=True), # The type of data sampler dataset=dict( # Train dataset config type=dataset_type, # Type of dataset ann_file='meta_info_DIV2K800sub_GT.txt', # Path of annotation file metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # Root path of data data_prefix=dict( # Prefix of image path img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # Filename template pipeline=train_pipeline)) val_dataloader = dict( batch_size=1, num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive drop_last=False, # Whether drop the last incomplete batch sampler=dict(type='DefaultSampler', shuffle=False), # The type of data sampler dataset=dict( # Validation dataset config type=dataset_type, # Type of dataset metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # Root path of data data_prefix=dict(img='LRbicx2', gt='GTmod12'), # Prefix of image path pipeline=test_pipeline)) test_dataloader = val_dataloader ```
================================================ FILE: docs/en/migration/distributed_train.md ================================================ # Migration of Distributed Training Settings We have merged [MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x) into MMagic. Here is migration of Distributed Training Settings about MMGeneration. In 0.x version, MMGeneration uses `DDPWrapper` and `DynamicRunner` to train static and dynamic model (e.g., PGGAN and StyleGANv2) respectively. In 1.x version, we use `MMSeparateDistributedDataParallel` provided by MMEngine to implement distributed training. The configuration differences are shown below:
Static Model in 0.x Version Static Model in 1.x Version
```python # Use DDPWrapper use_ddp_wrapper = True find_unused_parameters = False runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=False) ``` ```python model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=False) ```
Dynamic Model in 0.x Version Dynamic Model in 1.x Version
```python use_ddp_wrapper = False find_unused_parameters = False # Use DynamicRunner runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=True) ``` ```python model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=True) # set `find_unused_parameters` for dynamic models ```
================================================ FILE: docs/en/migration/eval_test.md ================================================ # Migration of Evaluation and Testing Settings We update evaluation settings in MMagic 1.x. Important modifications are as following. - The evaluation field is split to `val_evaluator` and `test_evaluator`. The `interval` is moved to `train_cfg.val_interval`. - The metrics to evaluation are moved from `test_cfg` to `val_evaluator` and `test_evaluator`.
Original New
```python train_cfg = None # Training config test_cfg = dict( # Test config metrics=['PSNR'], # Metrics used during testing crop_border=scale) # Crop border during evaluation evaluation = dict( # The config to build the evaluation hook interval=5000, # Evaluation interval save_image=True, # Save images during evaluation gpu_collect=True) # Use gpu collect ``` ```python val_evaluator = [ dict(type='PSNR', crop_border=scale), # The name of metrics to evaluate ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # Config of train loop type val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type ```
We have merged [MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x) into MMagic. Here is migration of Evaluation and Testing Settings about MMGeneration. The evaluation field is splited to `val_evaluator` and `test_evaluator`. And it won't support `interval` and `save_best` arguments. The `interval` is moved to `train_cfg.val_interval`, see [the schedule settings](./schedule.md) and the `save_best` is moved to `default_hooks.checkpoint.save_best`.
0.x Version 1.x Version
```python evaluation = dict( type='GenerativeEvalHook', interval=10000, metrics=[ dict( type='FID', num_images=50000, bgr2rgb=True, inception_args=dict(type='StyleGAN')), dict(type='IS', num_images=50000) ], best_metric=['fid', 'is'], sample_kwargs=dict(sample_model='ema')) ``` ```python val_evaluator = dict( type='Evaluator', metrics=[ dict( type='FID', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig') dict( type='IS', prefix='IS-50k', fake_nums=50000)]) # set best config default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, less_keys=['FID-Full-50k/fid'], greater_keys=['IS-50k/is'], save_optimizer=True, save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) test_evaluator = val_evaluator ```
To evaluate and test the model correctly, we need to set specific loop in `val_cfg` and `test_cfg`.
Static Model in 0.x Version Static Model in 1.x Version
```python total_iters = 1000000 runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=False, pass_training_status=True) ``` ```python train_cfg = dict( by_epoch=False, # use iteration based training max_iters=1000000, # max training iteration val_begin=1, val_interval=10000) # evaluation interval val_cfg = dict(type='MultiValLoop') # specific loop in validation test_cfg = dict(type='MultiTestLoop') # specific loop in testing ```
================================================ FILE: docs/en/migration/models.md ================================================ # Migration of Model Settings We update model settings in MMagic 1.x. Important modifications are as following. - Remove `pretrained` fields. - Add `train_cfg` and `test_cfg` fields in model settings. - Add `data_preprocessor` fields. Normalization and color space transforms operations are moved from datasets transforms pipelines to data_preprocessor. We will introduce data_preprocessor later.
Original New
```python model = dict( type='BasicRestorer', # Name of the model generator=dict( # Config of the generator type='EDSR', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pretrained=None, pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean')) # Config for pixel loss model training and testing settings ``` ```python model = dict( type='BaseEditModel', # Name of the model generator=dict( # Config of the generator type='EDSRNet', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') # Config for pixel loss train_cfg=dict(), # Config of training model. test_cfg=dict(), # Config of testing model. data_preprocessor=dict( # The Config to build data preprocessor type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) ```
We refactor models in MMagic 1.x. Important modifications are as following. - The `models` in MMagic 1.x is refactored to six parts: `archs`, `base_models`, `data_preprocessors`, `editors`, `diffusion_schedulers` and `losses`. - Add `data_preprocessor` module in `models`. Normalization and color space transforms operations are moved from datasets transforms pipelines to data_preprocessor. The data out from the data pipeline is transformed by this module and then fed into the model. More details of models are shown in [model guides](../howto/models.md). ================================================ FILE: docs/en/migration/optimizers.md ================================================ # Migration of Optimizers We have merged [MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x) into MMagic. Here is migration of Optimizers about MMGeneration. In version 0.x, MMGeneration uses PyTorch's native Optimizer, which only provides general parameter optimization. In version 1.x, we use `OptimizerWrapper` provided by MMEngine. Compared to PyTorch's `Optimizer`, `OptimizerWrapper` supports the following features: - `OptimizerWrapper.update_params` implement `zero_grad`, `backward` and `step` in a single function. - Support gradient accumulation automatically. - Provide a context manager named `OptimizerWrapper.optim_context` to warp the forward process. `optim_context` can automatically call `torch.no_sync` according to current number of updating iteration. In AMP (auto mixed precision) training, `autocast` is called in `optim_context` as well. For GAN models, generator and discriminator use different optimizer and training schedule. To ensure that the GAN model's function signature of `train_step` is consistent with other models, we use `OptimWrapperDict`, inherited from `OptimizerWrapper`, to wrap the optimizer of the generator and discriminator. To automate this process MMagic implement `MultiOptimWrapperContructor`. And you should specify this constructor in your config is you want to train GAN model. The config for the 0.x and 1.x versions are shown below:
0.x Version 1.x Version
```python optimizer = dict( generator=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6), discriminator=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6)) ``` ```python optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) ```
> Note that, in the 1.x, MMGeneration uses `OptimWrapper` to realize gradient accumulation. This make the config of `discriminator_steps` (training trick for updating the generator once after multiple updates of the discriminator) and gradient accumulation different between 0.x and 1.x version. - In 0.x version, we use `disc_steps`, `gen_steps` and `batch_accumulation_steps` in configs. `disc_steps` and `batch_accumulation_steps` are counted by the number of calls of `train_step` (is also the number of data reads from the dataloader). Therefore the number of consecutive updates of the discriminator is `disc_steps // batch_accumulation_steps`. And for generators, `gen_steps` is the number of times the generator actually updates continuously. - In 1.x version, we use `discriminator_steps`, `generator_steps` and `accumulative_counts` in configs. `discriminator_steps` and `generator_steps` are the number of consecutive updates to itself before updating other modules. Take config of BigGAN-128 as example.
0.x Version 1.x Version
```python model = dict( type='BasiccGAN', generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True), gan_loss=dict(type='GANLoss', gan_type='hinge')) # continuous update discriminator for `disc_steps // batch_accumulation_steps = 8 // 8 = 1` times # continuous update generator for `gen_steps = 1` times # generators and discriminators perform `batch_accumulation_steps = 8` times gradient accumulations before each update train_cfg = dict( disc_steps=8, gen_steps=1, batch_accumulation_steps=8, use_ema=True) ``` ```python model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True), # continuous update discriminator for `discriminator_steps = 1` times # continuous update generator for `generator_steps = 1` times generator_steps=1, discriminator_steps=1) optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( # generator perform `accumulative_counts = 8` times gradient accumulations before each update accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( # discriminator perform `accumulative_counts = 8` times gradient accumulations before each update accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) ```
================================================ FILE: docs/en/migration/overview.md ================================================ # Overview This section introduces the following contents in terms of migration from MMEditing 0.x - [Overview](#overview) - [New dependencies](#new-dependencies) - [Overall structures](#overall-structures) - [Other config settings](#other-config-settings) ## New dependencies MMagic 1.x depends on some new packages, you can prepare a new clean environment and install it again according to the [install tutorial](../get_started/install.md). ## Overall structures We refactor overall structures in MMagic 1.x as follows. - The `core` in the old versions of MMEdit is split into `engine`, `evaluation`, `structures`, and `visualization` - The `pipelines` of `datasets` in the old versions of MMEdit is refactored to `transforms` - The `models` in MMagic 1.x is refactored to six parts: `archs`, `base_models`, `data_preprocessors`, `editors`, `diffusion_schedulers`, and `losses`. ## Other config settings We rename the config file to the new template: `{model_settings}_{module_setting}_{training_setting}_{datasets_info}`. More details of config are shown in [config guides](../user_guides/config.md). ================================================ FILE: docs/en/migration/runtime.md ================================================ # Migration of Runtime Settings We update runtime settings in MMagic 1.x. Important modifications are as following. - The `checkpoint_config` is moved to `default_hooks.checkpoint` and the `log_config` is moved to `default_hooks.logger`. And we move many hooks settings from the script code to the `default_hooks` field in the runtime configuration. - The `resume_from` is removed. And we use `resume` to replace it. - If resume=True and load_from is not None, resume training from the checkpoint in load_from. - If resume=True and load_from is None, try to resume from the latest checkpoint in the work directory. - If resume=False and load_from is not None, only load the checkpoint, not resume training. - If resume=False and load_from is None, do not load nor resume. - The `dist_params` field is a sub field of `env_cfg` now. And there are some new configurations in the `env_cfg`. - The `workflow` related functionalities are removed. - New field `visualizer`: The visualizer is a new design. We use a visualizer instance in the runner to handle results & log visualization and save to different backends, like Local, TensorBoard and Wandb. - New field `default_scope`: The start point to search module for all registries.
Original New
```python checkpoint_config = dict( # Config to set the checkpoint hook, Refer to https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py for implementation. interval=5000, # The save interval is 5000 iterations save_optimizer=True, # Also save optimizers by_epoch=False) # Count by iterations log_config = dict( # Config to register logger hook interval=100, # Interval to print the log hooks=[ dict(type='TextLoggerHook', by_epoch=False), # The logger used to record the training process dict(type='TensorboardLoggerHook'), # The Tensorboard logger is also supported ]) visual_config = None # Visual config, we do not use it. # runtime settings dist_params = dict(backend='nccl') # Parameters to setup distributed training, the port can also be set log_level = 'INFO' # The level of logging load_from = None # load models as a pre-trained model from a given path. This will not resume training resume_from = None # Resume checkpoints from a given path, the training will be resumed from the iteration when the checkpoint's is saved workflow = [('train', 1)] # Workflow for runner. [('train', 1)] means there is only one workflow and the workflow named 'train' is executed once. Keep this unchanged when training current matting models ``` ```python default_hooks = dict( # Used to build default hooks checkpoint=dict( # Config to set the checkpoint hook type='CheckpointHook', interval=5000, # The save interval is 5000 iterations save_optimizer=True, by_epoch=False, # Count by iterations out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # Config to register logger hook param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) default_scope = 'mmedit' # Used to set registries location env_cfg = dict( # Parameters to setup distributed training, the port can also be set cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # The level of logging log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # Used to build log processor load_from = None # load models as a pre-trained model from a given path. This will not resume training. resume = False # Resume checkpoints from a given path, the training will be resumed from the epoch when the checkpoint's is saved. ```
================================================ FILE: docs/en/migration/schedule.md ================================================ # Migration of Schedule Settings We update schedule settings in MMagic 1.x. Important modifications are as following. - Now we use `optim_wrapper` field to specify all configuration about the optimization process. And the `optimizer` is a sub field of `optim_wrapper` now. - The `lr_config` field is removed and we use new `param_scheduler` to replace it. - The `total_iters` field is moved to `train_cfg` as `max_iters`, `val_cfg` and `test_cfg`, which configure the loop in training, validation and test.
Original New
```python optimizers = dict(generator=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch total_iters = 300000 # Total training iters lr_config = dict( # Learning rate scheduler config used to register LrUpdater hook policy='Step', by_epoch=False, step=[200000], gamma=0.5) # The policy of scheduler ``` ```python optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4), ) ) # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch. param_scheduler = dict( # Config of learning policy type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) # The policy of scheduler train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # Config of train loop type val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type ```
> More details of schedule settings are shown in [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/migration/param_scheduler.md). ================================================ FILE: docs/en/migration/visualization.md ================================================ # Migration of Visualization In 0.x, MMEditing use `VisualizationHook` to visualize results in training process. In 1.x version, we unify the function of those hooks into `BasicVisualizationHook` / `VisualizationHook`. Additionally, follow the design of MMEngine, we implement `ConcatImageVisualizer` / `Visualizer` and a group of `VisBackend` to draw and save the visualization results.
0.x version 1.x Version
```python visual_config = dict( type='VisualizationHook', output_dir='visual', interval=1000, res_name_list=['gt_img', 'masked_img', 'fake_res', 'fake_img'], ) ``` ```python vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ```
To learn more about the visualization function, please refers to [this tutorial](../user_guides/visualization.md). ================================================ FILE: docs/en/switch_language.md ================================================ # English # 简体中文 ================================================ FILE: docs/en/user_guides/config.md ================================================ # Tutorial 1: Learn about Configs in MMagic We incorporate modular and inheritance design into our config system, which is convenient to conduct various experiments. If you wish to inspect the config file, you may run `python tools/misc/print_config.py /PATH/TO/CONFIG` to see the complete config. You can learn about the usage of our config system according to the following tutorials. - [Tutorial 1: Learn about Configs in MMagic](#tutorial-1-learn-about-configs-in-mmagic) - [Modify config through script arguments](#modify-config-through-script-arguments) - [Config file structure](#config-file-structure) - [Config name style](#config-name-style) - [An example of EDSR](#an-example-of-edsr) - [Model config](#model-config) - [Data config](#data-config) - [Data pipeline](#data-pipeline) - [Dataloader](#dataloader) - [Evaluation config](#evaluation-config) - [Training and testing config](#training-and-testing-config) - [Optimization config](#optimization-config) - [Hook config](#hook-config) - [Runtime config](#runtime-config) - [An example of StyleGAN2](#an-example-of-stylegan2) - [Model config](#model-config-1) - [Dataset and evaluator config](#dataset-and-evaluator-config) - [Training and testing config](#training-and-testing-config-1) - [Optimization config](#optimization-config-1) - [Hook config](#hook-config-1) - [Runtime config](#runtime-config-1) - [Other examples](#other-examples) - [An example of config system for inpainting](#an-example-of-config-system-for-inpainting) - [An example of config system for matting](#an-example-of-config-system-for-matting) - [An example of config system for restoration](#an-example-of-config-system-for-restoration) ## Modify config through script arguments When submitting jobs using `tools/train.py` or `tools/test.py`, you may specify `--cfg-options` to in-place modify the config. - Update config keys of dict chains. The config options can be specified following the order of the dict keys in the original config. For example, `--cfg-options test_cfg.use_ema=False` changes the default sampling model to the original generator, and `--cfg-options train_dataloader.batch_size=8` changes the batch size of train dataloader. - Update keys inside a list of configs. Some config dicts are composed as a list in your config. For example, the training pipeline `train_dataloader.dataset.pipeline` is normally a list e.g. `[dict(type='LoadImageFromFile'), ...]`. If you want to change `'LoadImageFromFile'` to `'LoadImageFromWebcam'` in the pipeline, you may specify `--cfg-options train_dataloader.dataset.pipeline.0.type=LoadImageFromWebcam`. The training pipeline `train_pipeline` is normally a list e.g. `[dict(type='LoadImageFromFile'), ...]`. If you want to change `'LoadImageFromFile'` to `'LoadMask'` in the pipeline, you may specify `--cfg-options train_pipeline.0.type=LoadMask`. - Update values of list/tuples. If the value to be updated is a list or a tuple. You can set `--cfg-options key="[a,b]"` or `--cfg-options key=a,b`. It also allows nested list/tuple values, e.g., `--cfg-options key="[(a,b),(c,d)]"`. Note that the quotation mark " is necessary to support list/tuple data types, and that **NO** white space is allowed inside the quotation marks in the specified value. ## Config file structure There are 3 basic component types under `config/_base_`: datasets, models and default_runtime. Many methods could be easily constructed with one of each like AOT-GAN, EDVR, GLEAN, StyleGAN2, CycleGAN, SinGAN, etc. Configs consisting of components from `_base_` are called _primitive_. For all configs under the same folder, it is recommended to have only **one** _primitive_ config. All other configs should inherit from the _primitive_ config. In this way, the maximum of inheritance level is 3. For easy understanding, we recommend contributors to inherit from existing methods. For example, if some modification is made base on BasicVSR, user may first inherit the basic BasicVSR structure by specifying `_base_ = ../basicvsr/basicvsr_reds4.py`, then modify the necessary fields in the config files. If some modification is made base on StyleGAN2, user may first inherit the basic StyleGAN2 structure by specifying `_base_ = ../styleganv2/stylegan2_c2_ffhq_256_b4x8_800k.py`, then modify the necessary fields in the config files. If you are building an entirely new method that does not share the structure with any of the existing methods, you may create a folder `xxx` under `configs`, Please refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md) for detailed documentation. ## Config name style ``` {model}_[module setting]_{training schedule}_{dataset} ``` `{xxx}` is required field and `[yyy]` is optional. - `{model}`: model type like `stylegan`, `dcgan`, `basicvsr`, `dim`, etc. Settings referred in the original paper are included in this field as well (e.g., `Stylegan2-config-f`, `edvrm` of `edvrm_8xb4-600k_reds`.) - `[module setting]`: specific setting for some modules, including Encoder, Decoder, Generator, Discriminator, Normalization, loss, Activation, etc. E.g. `c64n7` of `basicvsr-pp_c64n7_8xb1-600k_reds4`, learning rate `Glr4e-4_Dlr1e-4` for dcgan, `gamma32.8` for stylegan3, `woReLUInplace` in sagan. In this section, information from different submodules (e.g., generator and discriminator) are connected with `_`. - `{training_scheduler}`: specific setting for training, including batch_size, schedule, etc. For example, learning rate (e.g., `lr1e-3`), number of gpu and batch size is used (e.g., `8xb32`), and total iterations (e.g., `160kiter`) or number of images shown in the discriminator (e.g., `12Mimgs`). - `{dataset}`: dataset name and data size info like `celeba-256x256` of `deepfillv1_4xb4_celeba-256x256`, `reds4` of `basicvsr_2xb4_reds4`, `ffhq`, `lsun-car`, `celeba-hq`. ## An example of EDSR To help the users have a basic idea of a complete config, we make a brief comments on the [config of the EDSR model](https://github.com/open-mmlab/mmagic/blob/main/configs/edsr/edsr_x2c64b16_g1_300k_div2k.py) we implemented as the following. For more detailed usage and the corresponding alternative for each modules, please refer to the API documentation and the [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md). ### Model config In MMagic's config, we use model fields to set up a model. ```python model = dict( type='BaseEditModel', # Name of the model generator=dict( # Config of the generator type='EDSRNet', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') # Config for pixel loss train_cfg=dict(), # Config of training model. test_cfg=dict(), # Config of testing model. data_preprocessor=dict( # The Config to build data preprocessor type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) ``` ### Data config [Dataloaders](https://pytorch.org/docs/stable/data.html?highlight=data%20loader#torch.utils.data.DataLoader) are required for the training, validation, and testing of the [runner](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html). Dataset and data pipeline need to be set to build the dataloader. Due to the complexity of this part, we use intermediate variables to simplify the writing of dataloader configs. #### Data pipeline ```python train_pipeline = [ # Training data processing pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find the corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find the corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='SetValues', dictionary=dict(scale=scale)), # Set value to destination keys dict(type='PairedRandomCrop', gt_patch_size=96), # Paired random crop dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='horizontal'), # Flip direction dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip direction dict(type='RandomTransposeHW', # Random transpose h and w for images keys=['lq', 'gt'], # Images to be transposed transpose_ratio=0.5 # Transpose ratio ), dict(type='PackInputs') # The config of collecting data from the current pipeline ] test_pipeline = [ # Test pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='PackInputs') # The config of collecting data from the current pipeline ] ``` #### Dataloader ```python dataset_type = 'BasicImageDataset' # The type of dataset data_root = 'data' # Root path of data train_dataloader = dict( num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive sampler=dict(type='InfiniteSampler', shuffle=True), # The type of data sampler dataset=dict( # Train dataset config type=dataset_type, # Type of dataset ann_file='meta_info_DIV2K800sub_GT.txt', # Path of annotation file metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # Root path of data data_prefix=dict( # Prefix of image path img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # Filename template pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive drop_last=False, # Whether drop the last incomplete batch sampler=dict(type='DefaultSampler', shuffle=False), # The type of data sampler dataset=dict( # Validation dataset config type=dataset_type, # Type of dataset metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # Root path of data data_prefix=dict(img='LRbicx2', gt='GTmod12'), # Prefix of image path pipeline=test_pipeline)) test_dataloader = val_dataloader ``` ### Evaluation config [Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html) are used to compute the metrics of the trained model on the validation and testing datasets. The config of evaluators consists of one or a list of metric configs: ```python val_evaluator = [ dict(type='MAE'), # The name of metrics to evaluate dict(type='PSNR', crop_border=scale), # The name of metrics to evaluate dict(type='SSIM', crop_border=scale), # The name of metrics to evaluate ] test_evaluator = val_evaluator # The config for testing evaluator ``` ### Training and testing config MMEngine's runner uses Loop to control the training, validation, and testing processes. Users can set the maximum training iteration and validation intervals with these fields. ```python train_cfg = dict( type='IterBasedTrainLoop', # The name of train loop type max_iters=300000, # The number of total iterations val_interval=5000, # The number of validation interval iterations ) val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type ``` ### Optimization config `optim_wrapper` is the field to configure optimization related settings. The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html). ```python optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) ) # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch. ``` `param_scheduler` is a field that configures methods of adjusting optimization hyper-parameters such as learning rate and momentum. Users can combine multiple schedulers to create a desired parameter adjustment strategy. Find more in [parameter scheduler tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/param_scheduler.html). ```python param_scheduler = dict( # Config of learning policy type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) ``` ### Hook config Users can attach hooks to training, validation, and testing loops to insert some operations during running. There are two different hook fields, one is `default_hooks` and the other is `custom_hooks`. `default_hooks` is a dict of hook configs. `default_hooks` are the hooks must required at runtime. They have default priority which should not be modified. If not set, runner will use the default values. To disable a default hook, users can set its config to `None`. ```python default_hooks = dict( # Used to build default hooks checkpoint=dict( # Config to set the checkpoint hook type='CheckpointHook', interval=5000, # The save interval is 5000 iterations save_optimizer=True, by_epoch=False, # Count by iterations out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # Config to register logger hook param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ``` `custom_hooks` is a list of hook configs. Users can develop there own hooks and insert them in this field. ```python custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] # Config of visualization hook ``` ### Runtime config ```python default_scope = 'mmagic' # Used to set registries location env_cfg = dict( # Parameters to setup distributed training, the port can also be set cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # The level of logging log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # Used to build log processor load_from = None # load models as a pre-trained model from a given path. This will not resume training. resume = False # Resume checkpoints from a given path, the training will be resumed from the epoch when the checkpoint's is saved. ``` ## An example of StyleGAN2 Taking [Stylegan2 at 1024x1024 scale](https://github.com/open-mmlab/mmagic/blob/main/configs//styleganv2/stylegan2_c2_8xb4-fp16-global-800kiters_quicktest-ffhq-256x256.py) as an example, we introduce each field in the config according to different function modules. ### Model config In addition to neural network components such as generator, discriminator etc, it also requires `data_preprocessor`, `loss_config`, and some of them contains `ema_config`. `data_preprocessor` is responsible for processing a batch of data output by dataloader. `loss_config` is responsible for weight of loss terms. `ema_config` is responsible for exponential moving average (EMA) operation for generator. ```python model = dict( type='StyleGAN2', # The name of the model data_preprocessor=dict(type='DataPreprocessor'), # The config of data preprocessor, usually includs image normalization and padding generator=dict( # The config for generator type='StyleGANv2Generator', # The name of the generator out_size=1024, # The output resolution of the generator style_channels=512), # The number of style channels of the generator discriminator=dict( # The config for discriminator type='StyleGAN2Discriminator', # The name of the discriminator in_size=1024), # The input resolution of the discriminator ema_config=dict( # The config for EMA type='ExponentialMovingAverage', # Specific the type of Average model interval=1, # The interval of EMA operation momentum=0.9977843871238888), # The momentum of EMA operation loss_config=dict( # The config for loss terms r1_loss_weight=80.0, # The weight for r1 gradient penalty r1_interval=16, # The interval of r1 gradient penalty norm_mode='HWC', # The normalization mode for r1 gradient penalty g_reg_interval=4, # The interval for generator's regularization g_reg_weight=8.0, # The weight for generator's regularization pl_batch_shrink=2)) # The factor of shrinking the batch size in path length regularization ``` ### Dataset and evaluator config [Dataloaders](https://pytorch.org/docs/stable/data.html?highlight=data%20loader#torch.utils.data.DataLoader) are required for the training, validation, and testing of the [runner](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html). Dataset and data pipeline need to be set to build the dataloader. Due to the complexity of this part, we use intermediate variables to simplify the writing of dataloader configs. ```python dataset_type = 'BasicImageDataset' # Dataset type, this will be used to define the dataset data_root = './data/ffhq/' # Root path of data train_pipeline = [ # Training data process pipeline dict(type='LoadImageFromFile', key='img'), # First pipeline to load images from file path dict(type='Flip', keys=['img'], direction='horizontal'), # Argumentation pipeline that flip the images dict(type='PackInputs', keys=['img']) # The last pipeline that formats the annotation data (if have) and decides which keys in the data should be packed into data_samples ] val_pipeline = [ dict(type='LoadImageFromFile', key='img'), # First pipeline to load images from file path dict(type='PackInputs', keys=['img']) # The last pipeline that formats the annotation data (if have) and decides which keys in the data should be packed into data_samples ] train_dataloader = dict( # The config of train dataloader batch_size=4, # Batch size of a single GPU num_workers=8, # Worker to pre-fetch data for each single GPU persistent_workers=True, # If ``True``, the dataloader will not shutdown the worker processes after an epoch end, which can accelerate training speed. sampler=dict( # The config of training data sampler type='InfiniteSampler', # InfiniteSampler for iteratiion-based training. Refers to https://github.com/open-mmlab/mmengine/blob/fe0eb0a5bbc8bf816d5649bfdd34908c258eb245/mmengine/dataset/sampler.py#L107 shuffle=True), # Whether randomly shuffle the training data dataset=dict( # The config of the training dataset type=dataset_type, data_root=data_root, pipeline=train_pipeline)) val_dataloader = dict( # The config of validation dataloader batch_size=4, # Batch size of a single GPU num_workers=8, # Worker to pre-fetch data for each single GPU dataset=dict( # The config of the validation dataset type=dataset_type, data_root=data_root, pipeline=val_pipeline), sampler=dict( # The config of validatioin data sampler type='DefaultSampler', # DefaultSampler which supports both distributed and non-distributed training. Refer to https://github.com/open-mmlab/mmengine/blob/fe0eb0a5bbc8bf816d5649bfdd34908c258eb245/mmengine/dataset/sampler.py#L14 shuffle=False), # Whether randomly shuffle the validation data persistent_workers=True) test_dataloader = val_dataloader # The config of the testing dataloader ``` [Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html) are used to compute the metrics of the trained model on the validation and testing datasets. The config of evaluators consists of one or a list of metric configs: ```python val_evaluator = dict( # The config for validation evaluator type='Evaluator', # The type of evaluation metrics=[ # The config for metrics dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ]) test_evaluator = val_evaluator # The config for testing evaluator ``` ### Training and testing config MMEngine's runner uses Loop to control the training, validation, and testing processes. Users can set the maximum training iteration and validation intervals with these fields. ```python train_cfg = dict( # The config for training by_epoch=False, # Set `by_epoch` as False to use iteration-based training val_begin=1, # Which iteration to start the validation val_interval=10000, # Validation intervals max_iters=800002) # Maximum training iterations val_cfg = dict(type='MultiValLoop') # The validation loop type test_cfg = dict(type='MultiTestLoop') # The testing loop type ``` ### Optimization config `optim_wrapper` is the field to configure optimization related settings. The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html). ```python optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( optimizer=dict(type='Adam', lr=0.0016, betas=(0, 0.9919919678228657))), discriminator=dict( optimizer=dict( type='Adam', lr=0.0018823529411764706, betas=(0, 0.9905854573074332)))) ``` `param_scheduler` is a field that configures methods of adjusting optimization hyperparameters such as learning rate and momentum. Users can combine multiple schedulers to create a desired parameter adjustment strategy. Find more in [parameter scheduler tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/param_scheduler.html). Since StyleGAN2 do not use parameter scheduler, we use config in [CycleGAN](https://github.com/open-mmlab/mmagic/blob/main/configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) as an example: ```python # parameter scheduler in CycleGAN config param_scheduler = dict( type='LinearLrInterval', # The type of scheduler interval=400, # The interval to update the learning rate by_epoch=False, # The scheduler is called by iteration start_factor=0.0002, # The number we multiply parameter value in the first iteration end_factor=0, # The number we multiply parameter value at the end of linear changing process. begin=40000, # The start iteration of the scheduler end=80000) # The end iteration of the scheduler ``` ### Hook config Users can attach hooks to training, validation, and testing loops to insert some operations during running. There are two different hook fields, one is `default_hooks` and the other is `custom_hooks`. `default_hooks` is a dict of hook configs. `default_hooks` are the hooks must required at runtime. They have default priority which should not be modified. If not set, runner will use the default values. To disable a default hook, users can set its config to `None`. ```python default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100, log_metric_by_epoch=False), checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, less_keys=['FID-Full-50k/fid'], greater_keys=['IS-50k/is'], save_optimizer=True, save_best='FID-Full-50k/fid')) ``` `custom_hooks` is a list of hook configs. Users can develop there own hooks and insert them in this field. ```python custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ``` ### Runtime config ```python default_scope = 'mmagic' # The default registry scope to find modules. Refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/registry.html # config for environment env_cfg = dict( cudnn_benchmark=True, # whether to enable cudnn benchmark. mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), # set multi process parameters. dist_cfg=dict(backend='nccl'), # set distributed parameters. ) log_level = 'INFO' # The level of logging log_processor = dict( type='LogProcessor', # log processor to process runtime logs by_epoch=False) # print log by iteration load_from = None # load model checkpoint as a pre-trained model for a given path resume = False # Whether to resume from the checkpoint define in `load_from`. If `load_from` is `None`, it will resume the latest checkpoint in `work_dir` ``` ## Other examples ### An example of config system for inpainting To help the users have a basic idea of a complete config and the modules in a inpainting system, we make brief comments on the config of Global&Local as the following. For more detailed usage and the corresponding alternative for each modules, please refer to the API documentation. ```python model = dict( type='GLInpaintor', # The name of inpaintor data_preprocessor=dict( type='DataPreprocessor', # The name of data preprocessor mean=[127.5], # Mean value used in data normalization std=[127.5], # Std value used in data normalization ), encdec=dict( type='GLEncoderDecoder', # The name of encoder-decoder encoder=dict(type='GLEncoder', norm_cfg=dict(type='SyncBN')), # The config of encoder decoder=dict(type='GLDecoder', norm_cfg=dict(type='SyncBN')), # The config of decoder dilation_neck=dict( type='GLDilationNeck', norm_cfg=dict(type='SyncBN'))), # The config of dilation neck disc=dict( type='GLDiscs', # The name of discriminator global_disc_cfg=dict( in_channels=3, # The input channel of discriminator max_channels=512, # The maximum middle channel in discriminator fc_in_channels=512 * 4 * 4, # The input channel of last fc layer fc_out_channels=1024, # The output channel of last fc channel num_convs=6, # The number of convs used in discriminator norm_cfg=dict(type='SyncBN') # The config of norm layer ), local_disc_cfg=dict( in_channels=3, # The input channel of discriminator max_channels=512, # The maximum middle channel in discriminator fc_in_channels=512 * 4 * 4, # The input channel of last fc layer fc_out_channels=1024, # The output channel of last fc channel num_convs=5, # The number of convs used in discriminator norm_cfg=dict(type='SyncBN') # The config of norm layer ), ), loss_gan=dict( type='GANLoss', # The name of GAN loss gan_type='vanilla', # The type of GAN loss loss_weight=0.001 # The weight of GAN loss ), loss_l1_hole=dict( type='L1Loss', # The type of l1 loss loss_weight=1.0 # The weight of l1 loss )) train_cfg = dict( type='IterBasedTrainLoop',# The name of train loop type max_iters=500002, # The number of total iterations val_interval=50000, # The number of validation interval iterations ) val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type val_evaluator = [ dict(type='MAE', mask_key='mask', scaling=100), # The name of metrics to evaluate dict(type='PSNR'), # The name of metrics to evaluate dict(type='SSIM'), # The name of metrics to evaluate ] test_evaluator = val_evaluator input_shape = (256, 256) # The shape of input image train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), # The config of loading image dict( type='LoadMask', # The type of loading mask pipeline mask_mode='bbox', # The type of mask mask_config=dict( max_bbox_shape=(128, 128), # The shape of bbox max_bbox_delta=40, # The changing delta of bbox height and width min_margin=20, # The minimum margin from bbox to the image border img_shape=input_shape)), # The input image shape dict( type='Crop', # The type of crop pipeline keys=['gt'], # The keys of images to be cropped crop_size=(384, 384), # The size of cropped patch random_crop=True, # Whether to use random crop ), dict( type='Resize', # The type of resizing pipeline keys=['gt'], # They keys of images to be resized scale=input_shape, # The scale of resizing function keep_ratio=False, # Whether to keep ratio during resizing ), dict( type='Normalize', # The type of normalizing pipeline keys=['gt_img'], # The keys of images to be normed mean=[127.5] * 3, # Mean value used in normalization std=[127.5] * 3, # Std value used in normalization to_rgb=False), # Whether to transfer image channels to rgb dict(type='GetMaskedImage'), # The config of getting masked image pipeline dict(type='PackInputs'), # The config of collecting data from the current pipeline ] test_pipeline = train_pipeline # Constructing testing/validation pipeline dataset_type = 'BasicImageDataset' # The type of dataset data_root = 'data/places' # Root path of data train_dataloader = dict( batch_size=12, # Batch size of a single GPU num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive sampler=dict(type='InfiniteSampler', shuffle=False), # The type of data sampler dataset=dict( # Train dataset config type=dataset_type, # Type of dataset data_root=data_root, # Root path of data data_prefix=dict(gt='data_large'), # Prefix of image path ann_file='meta/places365_train_challenge.txt', # Path of annotation file test_mode=False, pipeline=train_pipeline, )) val_dataloader = dict( batch_size=1, # Batch size of a single GPU num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive drop_last=False, # Whether drop the last incomplete batch sampler=dict(type='DefaultSampler', shuffle=False), # The type of data sampler dataset=dict( # Validation dataset config type=dataset_type, # Type of dataset data_root=data_root, # Root path of data data_prefix=dict(gt='val_large'), # Prefix of image path ann_file='meta/places365_val.txt', # Path of annotation file test_mode=True, pipeline=test_pipeline, )) test_dataloader = val_dataloader model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # The name of model wrapper optim_wrapper = dict( # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004)), disc=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004))) default_scope = 'mmagic' # Used to set registries location save_dir = './work_dirs' # Directory to save the model checkpoints and logs for the current experiments exp_name = 'gl_places' # The experiment name default_hooks = dict( # Used to build default hooks timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # Config to register logger hook param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( # Config to set the checkpoint hook type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( # Parameters to setup distributed training, the port can also be set cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type='LocalVisBackend')] # The name of visualization backend visualizer = dict( # Config used to build visualizer type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] # Used to build custom hooks log_level = 'INFO' # The level of logging log_processor = dict(type='LogProcessor', by_epoch=False) # Used to build log processor load_from = None # load models as a pre-trained model from a given path. This will not resume training. resume = False # Resume checkpoints from a given path, the training will be resumed from the epoch when the checkpoint's is saved. find_unused_parameters = False # Whether to set find unused parameters in ddp ``` ### An example of config system for matting To help the users have a basic idea of a complete config, we make a brief comments on the config of the original DIM model we implemented as the following. For more detailed usage and the corresponding alternative for each modules, please refer to the API documentation. ```python # model settings model = dict( type='DIM', # The name of model (we call mattor). data_preprocessor=dict( # The Config to build data preprocessor type='DataPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], bgr_to_rgb=True, proc_inputs='normalize', proc_trimap='rescale_to_zero_one', proc_gt='rescale_to_zero_one', ), backbone=dict( # The config of the backbone. type='SimpleEncoderDecoder', # The type of the backbone. encoder=dict( # The config of the encoder. type='VGG16'), # The type of the encoder. decoder=dict( # The config of the decoder. type='PlainDecoder')), # The type of the decoder. pretrained='./weights/vgg_state_dict.pth', # The pretrained weight of the encoder to be loaded. loss_alpha=dict( # The config of the alpha loss. type='CharbonnierLoss', # The type of the loss for predicted alpha matte. loss_weight=0.5), # The weight of the alpha loss. loss_comp=dict( # The config of the composition loss. type='CharbonnierCompLoss', # The type of the composition loss. loss_weight=0.5), # The weight of the composition loss. train_cfg=dict( # Config of training DIM model. train_backbone=True, # In DIM stage1, backbone is trained. train_refiner=False), # In DIM stage1, refiner is not trained. test_cfg=dict( # Config of testing DIM model. refine=False, # Whether use refiner output as output, in stage1, we don't use it. resize_method='pad', resize_mode='reflect', size_divisor=32, ), ) # data settings dataset_type = 'AdobeComp1kDataset' # Dataset type, this will be used to define the dataset. data_root = 'data/adobe_composition-1k' # Root path of data. train_pipeline = [ # Training data processing pipeline. dict( type='LoadImageFromFile', # Load alpha matte from file. key='alpha', # Key of alpha matte in annotation file. The pipeline will read alpha matte from path `alpha_path`. color_type='grayscale'), # Load as grayscale image which has shape (height, width). dict( type='LoadImageFromFile', # Load image from file. key='fg'), # Key of image to load. The pipeline will read fg from path `fg_path`. dict( type='LoadImageFromFile', # Load image from file. key='bg'), # Key of image to load. The pipeline will read bg from path `bg_path`. dict( type='LoadImageFromFile', # Load image from file. key='merged'), # Key of image to load. The pipeline will read merged from path `merged_path`. dict( type='CropAroundUnknown', # Crop images around unknown area (semi-transparent area). keys=['alpha', 'merged', 'fg', 'bg'], # Images to crop. crop_sizes=[320, 480, 640]), # Candidate crop size. dict( type='Flip', # Augmentation pipeline that flips the images. keys=['alpha', 'merged', 'fg', 'bg']), # Images to be flipped. dict( type='Resize', # Augmentation pipeline that resizes the images. keys=['alpha', 'merged', 'fg', 'bg'], # Images to be resized. scale=(320, 320), # Target size. keep_ratio=False), # Whether to keep the ratio between height and width. dict( type='GenerateTrimap', # Generate trimap from alpha matte. kernel_size=(1, 30)), # Kernel size range of the erode/dilate kernel. dict(type='PackInputs'), # The config of collecting data from the current pipeline ] test_pipeline = [ dict( type='LoadImageFromFile', # Load alpha matte. key='alpha', # Key of alpha matte in annotation file. The pipeline will read alpha matte from path `alpha_path`. color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', # Load image from file key='trimap', # Key of image to load. The pipeline will read trimap from path `trimap_path`. color_type='grayscale', # Load as grayscale image which has shape (height, width). save_original_img=True), # Save a copy of trimap for calculating metrics. It will be saved with key `ori_trimap` dict( type='LoadImageFromFile', # Load image from file key='merged'), # Key of image to load. The pipeline will read merged from path `merged_path`. dict(type='PackInputs'), # The config of collecting data from the current pipeline ] train_dataloader = dict( batch_size=1, # Batch size of a single GPU num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive sampler=dict(type='InfiniteSampler', shuffle=True), # The type of data sampler dataset=dict( # Train dataset config type=dataset_type, # Type of dataset data_root=data_root, # Root path of data ann_file='training_list.json', # Path of annotation file test_mode=False, pipeline=train_pipeline, )) val_dataloader = dict( batch_size=1, # Batch size of a single GPU num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive drop_last=False, # Whether drop the last incomplete batch sampler=dict(type='DefaultSampler', shuffle=False), # The type of data sampler dataset=dict( # Validation dataset config type=dataset_type, # Type of dataset data_root=data_root, # Root path of data ann_file='test_list.json', # Path of annotation file test_mode=True, pipeline=test_pipeline, )) test_dataloader = val_dataloader val_evaluator = [ dict(type='SAD'), # The name of metrics to evaluate dict(type='MattingMSE'), # The name of metrics to evaluate dict(type='GradientError'), # The name of metrics to evaluate dict(type='ConnectivityError'), # The name of metrics to evaluate ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', # The name of train loop type max_iters=1_000_000, # The number of total iterations val_interval=40000, # The number of validation interval iterations ) val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type # optimizer optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) ) # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch. default_scope = 'mmagic' # Used to set registries location save_dir = './work_dirs' # Directory to save the model checkpoints and logs for the current experiments. default_hooks = dict( # Used to build default hooks timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # Config to register logger hook param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( # Config to set the checkpoint hook type='CheckpointHook', interval=40000, # The save interval is 40000 iterations. by_epoch=False, # Count by iterations. out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( # Parameters to setup distributed training, the port can also be set cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # The level of logging log_processor = dict(type='LogProcessor', by_epoch=False) # Used to build log processor load_from = None # load models as a pre-trained model from a given path. This will not resume training. resume = False # Resume checkpoints from a given path, the training will be resumed from the epoch when the checkpoint's is saved. ``` ### An example of config system for restoration To help the users have a basic idea of a complete config, we make a brief comments on the config of the EDSR model we implemented as the following. For more detailed usage and the corresponding alternative for each modules, please refer to the API documentation. ```python exp_name = 'edsr_x2c64b16_1x16_300k_div2k' # The experiment name work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' load_from = None # based on pre-trained x2 model scale = 2 # Scale factor for upsampling # model settings model = dict( type='BaseEditModel', # Name of the model generator=dict( # Config of the generator type='EDSRNet', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') # Config for pixel loss train_cfg=dict(), # Config of training model. test_cfg=dict(), # Config of testing model. data_preprocessor=dict( # The Config to build data preprocessor type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ # Training data processing pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='SetValues', dictionary=dict(scale=scale)), # Set value to destination keys dict(type='PairedRandomCrop', gt_patch_size=96), # Paired random crop dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='horizontal'), # Flip direction dict(type='Flip', # Flip images keys=['lq', 'gt'], # Images to be flipped flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip direction dict(type='RandomTransposeHW', # Random transpose h and w for images keys=['lq', 'gt'], # Images to be transposed transpose_ratio=0.5 # Transpose ratio ), dict(type='PackInputs') # The config of collecting data from the current pipeline ] test_pipeline = [ # Test pipeline dict(type='LoadImageFromFile', # Load images from files key='img', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # Load images from files key='gt', # Keys in results to find corresponding path color_type='color', # Color type of image channel_order='rgb', # Channel order of image imdecode_backend='cv2'), # decode backend dict(type='ToTensor', keys=['img', 'gt']), # Convert images to tensor dict(type='PackInputs') # The config of collecting data from the current pipeline ] # dataset settings dataset_type = 'BasicImageDataset' # The type of dataset data_root = 'data' # Root path of data train_dataloader = dict( num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive sampler=dict(type='InfiniteSampler', shuffle=True), # The type of data sampler dataset=dict( # Train dataset config type=dataset_type, # Type of dataset ann_file='meta_info_DIV2K800sub_GT.txt', # Path of annotation file metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # Root path of data data_prefix=dict( # Prefix of image path img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # Filename template pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, # The number of workers to pre-fetch data for each single GPU persistent_workers=False, # Whether maintain the workers Dataset instances alive drop_last=False, # Whether drop the last incomplete batch sampler=dict(type='DefaultSampler', shuffle=False), # The type of data sampler dataset=dict( # Validation dataset config type=dataset_type, # Type of dataset metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # Root path of data data_prefix=dict(img='LRbicx2', gt='GTmod12'), # Prefix of image path pipeline=test_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), # The name of metrics to evaluate dict(type='PSNR', crop_border=scale), # The name of metrics to evaluate dict(type='SSIM', crop_border=scale), # The name of metrics to evaluate ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # Config of train loop type val_cfg = dict(type='ValLoop') # The name of validation loop type test_cfg = dict(type='TestLoop') # The name of test loop type # optimizer optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) ) # Config used to build optimizer, support all the optimizers in PyTorch whose arguments are also the same as those in PyTorch. param_scheduler = dict( # Config of learning policy type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) default_hooks = dict( # Used to build default hooks checkpoint=dict( # Config to set the checkpoint hook type='CheckpointHook', interval=5000, # The save interval is 5000 iterations save_optimizer=True, by_epoch=False, # Count by iterations out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # Config to register logger hook param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) default_scope = 'mmagic' # Used to set registries location save_dir = './work_dirs' # Directory to save the model checkpoints and logs for the current experiments. env_cfg = dict( # Parameters to setup distributed training, the port can also be set cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # The level of logging log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # Used to build log processor load_from = None # load models as a pre-trained model from a given path. This will not resume training. resume = False # Resume checkpoints from a given path, the training will be resumed from the epoch when the checkpoint's is saved. ``` ================================================ FILE: docs/en/user_guides/dataset_prepare.md ================================================ # Tutorial 2: Prepare datasets In this section, we will detail how to prepare data and adopt the proper dataset in our repo for different methods. We support multiple datasets of different tasks. There are two ways to use datasets for training and testing models in MMagic: 1. Using downloaded datasets directly 2. Preprocessing downloaded datasets before using them. The structure of this guide is as follows: - [Tutorial 2: Prepare datasets](#tutorial-2-prepare-datasets) - [Download datasets](#download-datasets) - [Prepare datasets](#prepare-datasets) - [The overview of the datasets in MMagic](#the-overview-of-the-datasets-in-mmagic) ## Download datasets You are supposed to download datasets from their homepage first. Most datasets are available after downloaded, so you only need to make sure the folder structure is correct and further preparation is not necessary. For example, you can simply prepare Vimeo90K-triplet datasets by downloading datasets from [homepage](http://toflow.csail.mit.edu/). ## Prepare datasets Some datasets need to be preprocessed before training or testing. We support many scripts to prepare datasets in [tools/dataset_converters](https://github.com/open-mmlab/mmagic/tree/main/tools/dataset_converters). And you can follow the tutorials of every dataset to run scripts. For example, we recommend cropping the DIV2K images to sub-images. We provide a script to prepare cropped DIV2K dataset. You can run the following command: ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` ## The overview of the datasets in MMagic We support detailed tutorials and split them according to different tasks. Please check our dataset zoo for data preparation of different tasks. If you're interested in more details of datasets in MMagic, please check the [advanced guides](../howto/dataset.md). ================================================ FILE: docs/en/user_guides/deploy.md ================================================ # Tutorial 8: Deploy models in MMagic The deployment of OpenMMLab codebases, including MMClassification, MMDetection, MMagic and so on are supported by [MMDeploy](https://github.com/open-mmlab/mmdeploy). The latest deployment guide for MMagic can be found from [here](https://mmdeploy.readthedocs.io/en/latest/04-supported-codebases/mmagic.html). This tutorial is organized as follows: - [Tutorial 8: Deploy models in MMagic](#tutorial-8-deploy-models-in-mmagic) - [Installation](#installation) - [Convert model](#convert-model) - [Model specification](#model-specification) - [Model inference](#model-inference) - [Backend model inference](#backend-model-inference) - [SDK model inference](#sdk-model-inference) - [Supported models](#supported-models) ## Installation Please follow the [guide](../get_started/install.md) to install mmagic. And then install mmdeploy from source by following [this](https://mmdeploy.readthedocs.io/en/latest/get_started.html#installation) guide. ```{note} If you install mmdeploy prebuilt package, please also clone its repository by 'git clone https://github.com/open-mmlab/mmdeploy.git --depth=1' to get the deployment config files. ``` ## Convert model Suppose MMagic and mmdeploy repositories are in the same directory, and the working directory is the root path of MMagic. Take [ESRGAN](../../../configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) model as an example. You can download its checkpoint from [here](https://download.openmmlab.com/MMagic/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth), and then convert it to onnx model as follows: ```python from mmdeploy.apis import torch2onnx from mmdeploy.backend.sdk.export_info import export2SDK img = 'tests/data/image/face/000001.png' work_dir = 'mmdeploy_models/mmagic/onnx' save_file = 'end2end.onnx' deploy_cfg = '../mmdeploy/configs/mmagic/super-resolution/super-resolution_onnxruntime_dynamic.py' model_cfg = 'configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py' model_checkpoint = 'esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth' device = 'cpu' # 1. convert model to onnx torch2onnx(img, work_dir, save_file, deploy_cfg, model_cfg, model_checkpoint, device) # 2. extract pipeline info for inference by MMDeploy SDK export2SDK(deploy_cfg, model_cfg, work_dir, pth=model_checkpoint, device=device) ``` It is crucial to specify the correct deployment config during model conversion.MMDeploy has already provided builtin deployment config [files](https://github.com/open-mmlab/mmdeploy/tree/main/configs/mmagic) of all supported backends for mmagic, under which the config file path follows the pattern: ``` {task}/{task}_{backend}-{precision}_{static | dynamic}_{shape}.py ``` - **{task}:** task in mmagic. - **{backend}:** inference backend, such as onnxruntime, tensorrt, pplnn, ncnn, openvino, coreml etc. - **{precision}:** fp16, int8. When it's empty, it means fp32 - **{static | dynamic}:** static shape or dynamic shape - **{shape}:** input shape or shape range of a model Therefore, in the above example, you can also convert `ESRGAN` to other backend models by changing the deployment config file, e.g., converting to tensorrt-fp16 model by `super-resolution_tensorrt-fp16_dynamic-32x32-512x512.py`. ```{tip} When converting mmagic models to tensorrt models, --device should be set to "cuda" ``` ## Model specification Before moving on to model inference chapter, let's know more about the converted model structure which is very important for model inference. The converted model locates in the working directory like `mmdeploy_models/mmagic/onnx` in the previous example. It includes: ``` mmdeploy_models/mmagic/onnx ├── deploy.json ├── detail.json ├── end2end.onnx └── pipeline.json ``` in which, - **end2end.onnx**: backend model which can be inferred by ONNX Runtime - ***xxx*.json**: the necessary information for mmdeploy SDK The whole package **mmdeploy_models/mmagic/onnx** is defined as **mmdeploy SDK model**, i.e., **mmdeploy SDK model** includes both backend model and inference meta information. ## Model inference ### Backend model inference Take the previous converted `end2end.onnx` model as an example, you can use the following code to inference the model. ```python from mmdeploy.apis.utils import build_task_processor from mmdeploy.utils import get_input_shape, load_config import torch deploy_cfg = '../mmdeploy/configs/mmagic/super-resolution/super-resolution_onnxruntime_dynamic.py' model_cfg = 'configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py' device = 'cpu' backend_model = ['mmdeploy_models/mmagic/onnx/end2end.onnx'] image = 'tests/data/image/lq/baboon_x4.png' # read deploy_cfg and model_cfg deploy_cfg, model_cfg = load_config(deploy_cfg, model_cfg) # build task and backend model task_processor = build_task_processor(model_cfg, deploy_cfg, device) model = task_processor.build_backend_model(backend_model) # process input image input_shape = get_input_shape(deploy_cfg) model_inputs, _ = task_processor.create_input(image, input_shape) # do model inference with torch.no_grad(): result = model.test_step(model_inputs) # visualize results task_processor.visualize( image=image, model=model, result=result[0], window_name='visualize', output_file='output_restorer.bmp') ``` ### SDK model inference You can also perform SDK model inference like following, ```python from mmdeploy_python import Restorer import cv2 img = cv2.imread('tests/data/image/lq/baboon_x4.png') # create a predictor restorer = Restorer(model_path='mmdeploy_models/mmagic/onnx', device_name='cpu', device_id=0) # perform inference result = restorer(img) # visualize inference result cv2.imwrite('output_restorer.bmp', result) ``` Besides python API, MMDeploy SDK also provides other FFI (Foreign Function Interface), such as C, C++, C#, Java and so on. You can learn their usage from [demos](https://github.com/open-mmlab/mmdeploy/tree/main/demo). ## Supported models Please refer to [here](https://mmdeploy.readthedocs.io/en/latest/04-supported-codebases/mmagic.html#supported-models) for the supported model list. ================================================ FILE: docs/en/user_guides/inference.md ================================================ # Tutorial 3: Inference with pre-trained models MMagic provides Hign-level APIs for you to easily play with state-of-the-art models on your own images or videos. In the new API, only two lines of code are needed to implement inference: ```python from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance editor = MMagicInferencer('pix2pix') # Infer a image. Input image path and output image path is needed. results = editor.infer(img='../resources/input/translation/gt_mask_0.png', result_out_dir='../resources/output/translation/tutorial_translation_pix2pix_res.jpg') ``` MMagic supports various fundamental generative models, including: unconditional Generative Adversarial Networks (GANs), conditional GANs, diffusion models, etc. MMagic also supports various applications, including: text-to-image, image-to-image translation, 3D-aware generation, image super-resolution, video super-resolution, video frame interpolation, image inpainting, image matting, image restoration, image colorization, image generation, etc. In this section, we will specify how to play with our pre-trained models. - [Tutorial 3: Inference with Pre-trained Models](#tutorial-3-inference-with-pre-trained-models) - [Prepare some images or videos for inference](#Prepare-some-images-or-videos-for-inference) - [Generative Models](#Generative-Models) - [Unconditional Generative Adversarial Networks (GANs)](<#Unconditional-Generative-Adversarial-Networks-(GANs)>) - [Conditional Generative Adversarial Networks (GANs)](<#Conditional-Generative-Adversarial-Networks-(GANs)>) - [Diffusion Models](#Diffusion-Models) - [Applications](#Applications) - [Text-to-Image](#Text-to-Image) - [Image-to-image translation](#Image-to-image-translation) - [3D-aware generation](#3D-aware-generation) - [Image super-resolution](#Image-super-resolution) - [Video super-resolution](#Video-super-resolution) - [Video frame interpolation](Video-frame-interpolation) - [Image inpainting](#Image-inpainting) - [Image matting](#Image-matting) - [Image restoration](#Image-restoration) - [Image colorization](#Image-colorization) - [Previous Versions](#Previous-Versions) ## Prepare some images or videos for inference Please refer to our [tutorials](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_tutorial.ipynb) for details. ## Generative Models ### Unconditional Generative Adversarial Networks (GANs) MMagic provides high-level APIs for sampling images with unconditional GANs. Unconditional GAN models do not need input, and output a image. We take 'styleganv1' as an example. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/unconditional/tutorial_unconditional_styleganv1_res.png' editor = MMagicInferencer('styleganv1') results = editor.infer(result_out_dir=result_out_dir) ``` Indeed, we have already provided a more friendly demo script to users. You can use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name styleganv1 \ --result-out-dir demo_unconditional_styleganv1_res.jpg ``` ### Conditional Generative Adversarial Networks (GANs) MMagic provides high-level APIs for sampling images with conditional GANs. Conditional GAN models take a label as input and output a image. We take 'biggan' as an example.. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/conditional/tutorial_conditinal_biggan_res.jpg' editor = MMagicInferencer('biggan', model_setting=1) results = editor.infer(label=1, result_out_dir=result_out_dir) ``` Indeed, we have already provided a more friendly demo script to users. You can use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name biggan \ --model-setting 1 \ --label 1 \ --result-out-dir demo_conditional_biggan_res.jpg ``` ### Diffusion Models MMagic provides high-level APIs for sampling images with diffusion models. f ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer editor = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = './resources/output/text2image/tutorial_text2image_sd_res.png' editor.infer(text=text_prompts, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir demo_text2image_stable_diffusion_res.png ``` ## Applications ### Text-to-Image Text-to-image models take text as input, and output a image. We take 'controlnet-canny' as an example. ```python import cv2 import numpy as np import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() cfg = Config.fromfile('configs/controlnet/controlnet-canny.py') controlnet = MODELS.build(cfg.model).cuda() control_url = 'https://user-images.githubusercontent.com/28132635/230288866-99603172-04cb-47b3-8adb-d1aa532d1d2c.jpg' control_img = mmcv.imread(control_url) control = cv2.Canny(control_img, 100, 200) control = control[:, :, None] control = np.concatenate([control] * 3, axis=2) control = Image.fromarray(control) prompt = 'Room with blue walls and a yellow ceiling.' output_dict = controlnet.infer(prompt, control=control) samples = output_dict['samples'] ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 1 \ --text "Room with blue walls and a yellow ceiling." \ --control 'https://user-images.githubusercontent.com/28132635/230297033-4f5c32df-365c-4cf4-8e4f-1b76a4cbb0b7.png' \ --result-out-dir demo_text2image_controlnet_canny_res.png ``` ### Image-to-image translation MMagic provides high-level APIs for translating images by using image translation models. Here is an example of building Pix2Pix and obtaining the translated images. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer editor = MMagicInferencer('pix2pix') results = editor.infer(img=img_path, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name pix2pix \ --img ${IMAGE_PATH} \ --result-out-dir ${SAVE_PATH} ``` ### 3D-aware generation ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/eg3d-output' editor = MMagicInferencer('eg3d') results = editor.infer(result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name eg3d \ --result-out-dir ./resources/output/eg3d-output ``` ### Image super-resolution Image super resolution models take a image as input, and output a high resolution image. We take 'esrgan' as an example. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = './resources/input/restoration/0901x2.png' result_out_dir = './resources/output/restoration/tutorial_restoration_esrgan_res.png' editor = MMagicInferencer('esrgan') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name esrgan \ --img ${IMAGE_PATH} \ --result-out-dir ${SAVE_PATH} ``` ### Video super-resolution ```python import os from mmagic.apis import MMagicInferencer from mmengine import mkdir_or_exist # Create a MMagicInferencer instance and infer video = './resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4' result_out_dir = './resources/output/video_super_resolution/tutorial_video_super_resolution_basicvsr_res.mp4' mkdir_or_exist(os.path.dirname(result_out_dir)) editor = MMagicInferencer('basicvsr') results = editor.infer(video=video, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name basicvsr \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_basicvsr_res.mp4 ``` ### Video frame interpolation Video interpolation models take a video as input, and output a interpolated video. We take 'flavr' as an example. ```python import os from mmagic.apis import MMagicInferencer from mmengine import mkdir_or_exist # Create a MMagicInferencer instance and infer video = './resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4' result_out_dir = './resources/output/video_interpolation/tutorial_video_interpolation_flavr_res.mp4' mkdir_or_exist(os.path.dirname(result_out_dir)) editor = MMagicInferencer('flavr') results = editor.infer(video=video, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name flavr \ --video ${VIDEO_PATH} \ --result-out-dir ${SAVE_PATH} ``` ### Image inpainting Inpaiting models take a masked image and mask pair as input, and output a inpainted image. We take 'global_local' as an example. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer img = './resources/input/inpainting/celeba_test.png' mask = './resources/input/inpainting/bbox_mask.png' # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/inpainting/tutorial_inpainting_global_local_res.jpg' editor = MMagicInferencer('global_local', model_setting=1) results = editor.infer(img=img, mask=mask, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name global_local \ --img ./resources/input/inpainting/celeba_test.png \ --mask ./resources/input/inpainting/bbox_mask.png \ --result-out-dir ./resources/output/inpainting/demo_inpainting_global_local_res.jpg ``` ### Image matting Inpaiting models take a image and trimap pair as input, and output a alpha image. We take 'gca' as an example. ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer img = './resources/input/matting/GT05.jpg' trimap = './resources/input/matting/GT05_trimap.jpg' # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/matting/tutorial_matting_gca_res.png' editor = MMagicInferencer('gca') results = editor.infer(img=img, trimap=trimap, result_out_dir=result_out_dir) ``` Use [demo/mmagic_inference_demo.py](../../../demo/mmagic_inference_demo.py) with the following commands: ```shell python demo/mmagic_inference_demo.py \ --model-name gca \ --img ./resources/input/matting/GT05.jpg \ --trimap ./resources/input/matting/GT05_trimap.jpg \ --result-out-dir ./resources/output/matting/demo_matting_gca_res.png ``` ### Image restoration ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = './resources/input/restoration/0901x2.png' result_out_dir = './resources/output/restoration/tutorial_restoration_nafnet_res.png' editor = MMagicInferencer('nafnet') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` ```shell python demo/mmagic_inference_demo.py \ --model-name nafnet \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_nafnet_res.png ``` ### Image colorization ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = 'https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg' result_out_dir = './resources/output/colorization/tutorial_colorization_res.png' editor = MMagicInferencer('inst_colorization') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` ```shell python demo/mmagic_inference_demo.py \ --model-name inst_colorization \ --img https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg \ --result-out-dir demo_colorization_res.png ``` ## Previous Versions If you want to use deprecated demos, please use [MMagic v1.0.0rc7](https://github.com/open-mmlab/mmagic/tree/v1.0.0rc7) and reference the [old tutorial](https://github.com/open-mmlab/mmagic/blob/v1.0.0rc7/docs/en/user_guides/inference.md). ================================================ FILE: docs/en/user_guides/metrics.md ================================================ # Tutorial 5: Using metrics in MMagic MMagic supports **17 metrics** to assess the quality of models. Please refer to [Train and Test in MMagic](../user_guides/train_test.md) for usages. Here, we will specify the details of different metrics one by one. The structure of this guide are as follows: - [Tutorial 5: Using metrics in MMagic](#tutorial-5-using-metrics-in-mmagic) - [MAE](#mae) - [MSE](#mse) - [PSNR](#psnr) - [SNR](#snr) - [SSIM](#ssim) - [NIQE](#niqe) - [SAD](#sad) - [MattingMSE](#mattingmse) - [GradientError](#gradienterror) - [ConnectivityError](#connectivityerror) - [FID and TransFID](#fid-and-transfid) - [IS and TransIS](#is-and-transis) - [Precision and Recall](#precision-and-recall) - [PPL](#ppl) - [SWD](#swd) - [MS-SSIM](#ms-ssim) - [Equivarience](#equivarience) ## MAE MAE is Mean Absolute Error metric for image. To evaluate with MAE, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='MAE'), ] ``` ## MSE MSE is Mean Squared Error metric for image. To evaluate with MSE, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='MSE'), ] ``` ## PSNR PSNR is Peak Signal-to-Noise Ratio. Our implement refers to https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio. To evaluate with PSNR, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='PSNR'), ] ``` ## SNR SNR is Signal-to-Noise Ratio. Our implementation refers to https://en.wikipedia.org/wiki/Signal-to-noise_ratio. To evaluate with SNR, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='SNR'), ] ``` ## SSIM SSIM is structural similarity for image, proposed in [Image quality assessment: from error visibility to structural similarity](https://live.ece.utexas.edu/publications/2004/zwang_ssim_ieeeip2004.pdf). The results of our implementation are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. To evaluate with SSIM, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='SSIM'), ] ``` ## NIQE NIQE is Natural Image Quality Evaluator metric, proposed in [Making a "Completely Blind" Image Quality Analyzer](http://www.live.ece.utexas.edu/publications/2013/mittal2013.pdf). Our implementation could produce almost the same results as the official MATLAB codes: http://live.ece.utexas.edu/research/quality/niqe_release.zip. To evaluate with NIQE, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='NIQE'), ] ``` ## SAD SAD is Sum of Absolute Differences metric for image matting. This metric compute per-pixel absolute difference and sum across all pixels. To evaluate with SAD, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='SAD'), ] ``` ## MattingMSE MattingMSE is Mean Squared Error metric for image matting. To evaluate with MattingMSE, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='MattingMSE'), ] ``` ## GradientError GradientError is Gradient error for evaluating alpha matte prediction. To evaluate with GradientError, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='GradientError'), ] ``` ## ConnectivityError ConnectivityError is Connectivity error for evaluating alpha matte prediction. To evaluate with ConnectivityError, please add the following configuration in the config file: ```python val_evaluator = [ dict(type='ConnectivityError'), ] ``` ## FID and TransFID Fréchet Inception Distance is a measure of similarity between two datasets of images. It was shown to correlate well with the human judgment of visual quality and is most often used to evaluate the quality of samples of Generative Adversarial Networks. FID is calculated by computing the Fréchet distance between two Gaussians fitted to feature representations of the Inception network. In `MMagic`, we provide two versions for FID calculation. One is the commonly used PyTorch version and the other one is used in StyleGAN paper. Meanwhile, we have compared the difference between these two implementations in the StyleGAN2-FFHQ1024 model (the details can be found [here](https://github.com/open-mmlab/mmagic/blob/main/configs/styleganv2/README.md)). Fortunately, there is a marginal difference in the final results. Thus, we recommend users adopt the more convenient PyTorch version. **About PyTorch version and Tero's version:** The commonly used PyTorch version adopts the modified InceptionV3 network to extract features for real and fake images. However, Tero's FID requires a [script module](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for Tensorflow InceptionV3. Note that applying this script module needs `PyTorch >= 1.6.0`. **About extracting real inception data:** For the users' convenience, the real features will be automatically extracted at test time and saved locally, and the stored features will be automatically read at the next test. Specifically, we will calculate a hash value based on the parameters used to calculate the real features, and use the hash value to mark the feature file, and when testing, if the `inception_pkl` is not set, we will look for the feature in `MMAGIC_CACHE_DIR` (~/.cache/openmmlab/mmagic/). If cached inception pkl is not found, then extracting will be performed. To use the FID metric, you should add the metric in a config file like this: ```python metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] ``` If you work on an new machine, then you can copy the `pkl` files in `MMAGIC_CACHE_DIR` and copy them to new machine and set `inception_pkl` field. ```python metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl= 'work_dirs/inception_pkl/inception_state-capture_mean_cov-full-33ad4546f8c9152e4b3bdb1b0c08dbaf.pkl', # copied from old machine sample_model='ema') ] ``` `TransFID` has same usage as `FID`, but it's designed for translation models like `Pix2Pix` and `CycleGAN`, which is adapted for our evaluator. You can refer to [evaluation](../user_guides/train_test.md) for details. ## IS and TransIS Inception score is an objective metric for evaluating the quality of generated images, proposed in [Improved Techniques for Training GANs](https://arxiv.org/pdf/1606.03498.pdf). It uses an InceptionV3 model to predict the class of the generated images, and suppose that 1) If an image is of high quality, it will be categorized into a specific class. 2) If images are of high diversity, the range of images' classes will be wide. So the KL-divergence of the conditional probability and marginal probability can indicate the quality and diversity of generated images. You can see the complete implementation in `metrics.py`, which refers to https://github.com/sbarratt/inception-score-pytorch/blob/master/inception_score.py. If you want to evaluate models with `IS` metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py metrics = [ xxx, dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] ``` To be noted that, the selection of Inception V3 and image resize method can significantly influence the final IS score. Therefore, we strongly recommend users may download the [Tero's script model of Inception V3](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) (load this script model need torch >= 1.6) and use `Bicubic` interpolation with `Pillow` backend. Corresponding to config, you can set `resize_method` and `use_pillow_resize` for image resizing. You can also set `inception_style` as `StyleGAN` for recommended tero's inception model, or `PyTorch` for torchvision's implementation. For environment without internet, you can download the inception's weights, and set `inception_path` to your inception model. We also perform a survey on the influence of data loading pipeline and the version of pretrained Inception V3 on the IS result. All IS are evaluated on the same group of images which are randomly selected from the ImageNet dataset.
Show the Comparison Results | Code Base | Inception V3 Version | Data Loader Backend | Resize Interpolation Method | IS | | :-------------------------------------------------------------: | :------------------: | :-----------------: | :-------------------------: | :-------------------: | | [OpenAI (baseline)](https://github.com/openai/improved-gan) | Tensorflow | Pillow | Pillow Bicubic | **312.255 +/- 4.970** | | [StyleGAN-Ada](https://github.com/NVlabs/stylegan2-ada-pytorch) | Tero's Script Model | Pillow | Pillow Bicubic | 311.895 +/ 4.844 | | mmagic (Ours) | Pytorch Pretrained | cv2 | cv2 Bilinear | 322.932 +/- 2.317 | | mmagic (Ours) | Pytorch Pretrained | cv2 | cv2 Bicubic | 324.604 +/- 5.157 | | mmagic (Ours) | Pytorch Pretrained | cv2 | Pillow Bicubic | 318.161 +/- 5.330 | | mmagic (Ours) | Pytorch Pretrained | Pillow | Pillow Bilinear | 313.126 +/- 5.449 | | mmagic (Ours) | Pytorch Pretrained | Pillow | cv2 Bilinear | 318.021+/-3.864 | | mmagic (Ours) | Pytorch Pretrained | Pillow | Pillow Bicubic | 317.997 +/- 5.350 | | mmagic (Ours) | Tero's Script Model | cv2 | cv2 Bilinear | 318.879 +/- 2.433 | | mmagic (Ours) | Tero's Script Model | cv2 | cv2 Bicubic | 316.125 +/- 5.718 | | mmagic (Ours) | Tero's Script Model | cv2 | Pillow Bicubic | **312.045 +/- 5.440** | | mmagic (Ours) | Tero's Script Model | Pillow | Pillow Bilinear | 308.645 +/- 5.374 | | mmagic (Ours) | Tero's Script Model | Pillow | Pillow Bicubic | 311.733 +/- 5.375 |
`TransIS` has same usage as `IS`, but it's designed for translation models like `Pix2Pix` and `CycleGAN`, which is adapted for our evaluator. You can refer to [evaluation](../user_guides/train_test.md) for details. ## Precision and Recall Our `Precision and Recall` implementation follows the version used in StyleGAN2. In this metric, a VGG network will be adopted to extract the features for images. Unfortunately, we have not found a PyTorch VGG implementation leading to similar results with Tero's version used in StyleGAN2. (About the differences, please see this [file](https://github.com/open-mmlab/mmagic/blob/main/configs/styleganv2/README.md).) Thus, in our implementation, we adopt [Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt) network by default. Importantly, applying this script module needs `PyTorch >= 1.6.0`. If with a lower PyTorch version, we will use the PyTorch official VGG network for feature extraction. To evaluate with `P&R`, please add the following configuration in the config file: ```python metrics = [ dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K') ] ``` ## PPL Perceptual path length measures the difference between consecutive images (their VGG16 embeddings) when interpolating between two random inputs. Drastic changes mean that multiple features have changed together and that they might be entangled. Thus, a smaller PPL score appears to indicate higher overall image quality by experiments. \ As a basis for our metric, we use a perceptually-based pairwise image distance that is calculated as a weighted difference between two VGG16 embeddings, where the weights are fit so that the metric agrees with human perceptual similarity judgments. If we subdivide a latent space interpolation path into linear segments, we can define the total perceptual length of this segmented path as the sum of perceptual differences over each segment, and a natural definition for the perceptual path length would be the limit of this sum under infinitely fine subdivision, but in practice we approximate it using a small subdivision `` $`\epsilon=10^{-4}`$ ``. The average perceptual path length in latent `space` Z, over all possible endpoints, is therefore `` $$`L_Z = E[\frac{1}{\epsilon^2}d(G(slerp(z_1,z_2;t))), G(slerp(z_1,z_2;t+\epsilon)))]`$$ `` Computing the average perceptual path length in latent `space` W is carried out in a similar fashion: `` $$`L_Z = E[\frac{1}{\epsilon^2}d(G(slerp(z_1,z_2;t))), G(slerp(z_1,z_2;t+\epsilon)))]`$$ `` Where `` $`z_1, z_2 \sim P(z)`$ ``, and `` $` t \sim U(0,1)`$ `` if we set `sampling` to full, `` $` t \in \{0,1\}`$ `` if we set `sampling` to end. `` $` G`$ `` is the generator(i.e. `` $` g \circ f`$ `` for style-based networks), and `` $` d(.,.)`$ `` evaluates the perceptual distance between the resulting images.We compute the expectation by taking 100,000 samples (set `num_images` to 50,000 in our code). You can find the complete implementation in `metrics.py`, which refers to https://github.com/rosinality/stylegan2-pytorch/blob/master/ppl.py. If you want to evaluate models with `PPL` metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/styleganv2/stylegan2_c2_ffhq_1024_b4x8.py metrics = [ xxx, dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] ``` ## SWD Sliced Wasserstein distance is a discrepancy measure for probability distributions, and smaller distance indicates generated images look like the real ones. We obtain the Laplacian pyramids of every image and extract patches from the Laplacian pyramids as descriptors, then SWD can be calculated by taking the sliced Wasserstein distance of the real and fake descriptors. You can see the complete implementation in `metrics.py`, which refers to https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/sliced_wasserstein.py. If you want to evaluate models with `SWD` metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py metrics = [ dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] ``` ## MS-SSIM Multi-scale structural similarity is used to measure the similarity of two images. We use MS-SSIM here to measure the diversity of generated images, and a low MS-SSIM score indicates the high diversity of generated images. You can see the complete implementation in `metrics.py`, which refers to https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py. If you want to evaluate models with `MS-SSIM` metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig') ] ``` ## Equivarience Equivarience of generative models refer to the exchangeability of model forward and geometric transformations. Currently this metric is only calculated for StyleGANv3, you can see the complete implementation in `metrics.py`, which refers to https://github.com/NVlabs/stylegan3/blob/main/metrics/equivariance.py. If you want to evaluate models with `Equivarience` metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/styleganv3/stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py metrics = [ dict( type='Equivariance', fake_nums=50000, sample_mode='ema', prefix='EQ', eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True)) ] ``` ================================================ FILE: docs/en/user_guides/train_test.md ================================================ # Tutorial 4: Train and test in MMagic In this section, we introduce how to test and train models in MMagic. In this section, we provide the following guides: - [Tutorial 4: Train and test in MMagic](#tutorial-4-train-and-test-in-mmagic) - [Prerequisite](#prerequisite) - [Test a model in MMagic](#test-a-model-in-mmagic) - [Test with a single GPUs](#test-with-a-single-gpus) - [Test with multiple GPUs](#test-with-multiple-gpus) - [Test with Slurm](#test-with-slurm) - [Test with specific metrics](#test-with-specific-metrics) - [Train a model in MMagic](#train-a-model-in-mmagic) - [Train with a single GPU](#train-with-a-single-gpu) - [Train with multiple nodes](#train-with-multiple-nodes) - [Train with multiple GPUs](#train-with-multiple-gpus) - [Train with Slurm](#train-with-slurm) - [Optional arguments](#optional-arguments) - [Train with specific evaluation metrics](#train-with-specific-evaluation-metrics) ## Prerequisite Users need to [prepare dataset](../user_guides/dataset_prepare.md) first to enable training and testing models in MMagic. ## Test a model in MMagic ### Test with a single GPUs You can use the following commands to test a pre-trained model with single GPUs. ```shell python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ``` For example, ```shell python tools/test.py configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` ### Test with multiple GPUs MMagic supports testing with multiple GPUs, which can largely save your time in testing models. You can use the following commands to test a pre-trained model with multiple GPUs. ```shell ./tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} ``` For example, ```shell ./tools/dist_test.sh configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` ### Test with Slurm If you run MMagic on a cluster managed with [slurm](https://slurm.schedmd.com/), you can use the script `slurm_test.sh`. (This script also supports single machine testing.) ```shell [GPUS=${GPUS}] ./tools/slurm_test.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} ${CHECKPOINT_FILE} ``` Here is an example of using 8 GPUs to test an example model on the 'dev' partition with the job name 'test'. ```shell GPUS=8 ./tools/slurm_test.sh dev test configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` You can check [slurm_test.sh](../../../tools/slurm_test.sh) for full arguments and environment variables. ### Test with specific metrics MMagic provides various **evaluation metrics**, i.e., MS-SSIM, SWD, IS, FID, Precision&Recall, PPL, Equivarience, TransFID, TransIS, etc. We have provided unified evaluation scripts in [tools/test.py](https://github.com/open-mmlab/mmagic/tree/main/tools/test.py) for all models. If users want to evaluate their models with some metrics, you can add the `metrics` into your config file like this: ```python # at the end of the configs/styleganv2/stylegan2_c2_ffhq_256_b4x8_800k.py metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] ``` As above, `metrics` consist of multiple metric dictionaries. Each metric will contain `type` to indicate the category of the metric. `fake_nums` denotes the number of images generated by the model. Some metrics will output a dictionary of results, you can also set `prefix` to specify the prefix of the results. If you set the prefix of FID as `FID-Full-50k`, then an example of output may be ```bash FID-Full-50k/fid: 3.6561 FID-Full-50k/mean: 0.4263 FID-Full-50k/cov: 3.2298 ``` Then users can test models with the command below: ```shell bash tools/dist_test.sh ${CONFIG_FILE} ${CKPT_FILE} ``` If you are in slurm environment, please switch to the [tools/slurm_test.sh](https://github.com/open-mmlab/mmagic/tree/main/tools/slurm_test.sh) by using the following commands: ```shell sh slurm_test.sh ${PLATFORM} ${JOBNAME} ${CONFIG_FILE} ${CKPT_FILE} ``` ## Train a model in MMagic MMagic supports multiple ways of training: 1. [Train with a single GPU](#train-with-a-single-gpu) 2. [Train with multiple GPUs](#train-with-multiple-gpus) 3. [Train with multiple nodes](#train-with-multiple-nodes) 4. [Train with Slurm](#train-with-slurm) Specifically, all outputs (log files and checkpoints) will be saved to the working directory, which is specified by `work_dir` in the config file. ### Train with a single GPU ```shell CUDA_VISIBLE=0 python tools/train.py configs/example_config.py --work-dir work_dirs/example ``` ### Train with multiple nodes To launch distributed training on multiple machines, which can be accessed via IPs, run the following commands: On the first machine: ```shell NNODES=2 NODE_RANK=0 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR tools/dist_train.sh $CONFIG $GPUS ``` On the second machine: ```shell NNODES=2 NODE_RANK=1 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR tools/dist_train.sh $CONFIG $GPUS ``` To speed up network communication, high speed network hardware, such as Infiniband, is recommended. Please refer to [PyTorch docs](https://pytorch.org/docs/1.11/distributed.html#launch-utility) for more information. ### Train with multiple GPUs ```shell ./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments] ``` ### Train with Slurm If you run MMagic on a cluster managed with [slurm](https://slurm.schedmd.com/), you can use the script `slurm_train.sh`. (This script also supports single machine training.) ```shell [GPUS=${GPUS}] ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} ${WORK_DIR} ``` Here is an example of using 8 GPUs to train an inpainting model on the dev partition. ```shell GPUS=8 ./tools/slurm_train.sh dev configs/inpainting/gl_places.py /nfs/xxxx/gl_places_256 ``` You can check [slurm_train.sh](https://github.com/open-mmlab/mmagic/blob/master/tools/slurm_train.sh) for full arguments and environment variables. ### Optional arguments - `--amp`: This argument is used for fixed-precision training. - `--resume`: This argument is used for auto resume if the training is aborted. ## Train with specific evaluation metrics Benefit from the `mmengine`'s `Runner`. We can evaluate model during training in a simple way as below. ```python # define metrics metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN') ] # define dataloader val_dataloader = dict( batch_size=128, num_workers=8, dataset=dict( type='BasicImageDataset', data_root='data/celeba-cropped/', pipeline=[ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(64, 64)), dict(type='PackInputs') ]), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) # define val interval train_cfg = dict(by_epoch=False, val_begin=1, val_interval=10000) # define val loop and evaluator val_cfg = dict(type='MultiValLoop') val_evaluator = dict(type='Evaluator', metrics=metrics) ``` You can set `val_begin` and `val_interval` to adjust when to begin validation and interval of validation. For details of metrics, refer to [metrics' guide](./metrics.md). ================================================ FILE: docs/en/user_guides/useful_tools.md ================================================ # Tutorial 7: Useful tools We provide lots of useful tools under `tools/` directory. The structure of this guide is as follows: - [Tutorial 7: Useful tools](#tutorial-7-useful-tools) - [Get the FLOPs and params](#get-the-flops-and-params) - [Publish a model](#publish-a-model) - [Print full config](#print-full-config) ## Get the FLOPs and params We provide a script adapted from [flops-counter.pytorch](https://github.com/sovrasov/flops-counter.pytorch) to compute the FLOPs and params of a given model. ```shell python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] ``` For example, ```shell python tools/analysis_tools/get_flops.py configs/resotorer/srresnet.py --shape 40 40 ``` You will get the result like this. ``` ============================== Input shape: (3, 40, 40) Flops: 4.07 GMac Params: 1.52 M ============================== ``` **Note**: This tool is still experimental and we do not guarantee that the number is correct. You may well use the result for simple comparisons, but double check it before you adopt it in technical reports or papers. (1) FLOPs are related to the input shape while parameters are not. The default input shape is (1, 3, 250, 250). (2) Some operators are not counted in FLOPs like GN and custom operators. You can add support for new operators by modifying [`mmcv/cnn/utils/flops_counter.py`](https://github.com/open-mmlab/mmcv/blob/master/mmcv/cnn/utils/flops_counter.py). ## Publish a model Before you upload a model to AWS, you may want to 1. convert model weights to CPU tensors 2. delete the optimizer states and 3. compute the hash of the checkpoint file and append time and the hash id to the filename. ```shell python tools/model_converters/publish_model.py ${INPUT_FILENAME} ${OUTPUT_FILENAME} ``` E.g., ```shell python tools/model_converters/publish_model.py work_dirs/stylegan2/latest.pth stylegan2_c2_8xb4_ffhq-1024x1024.pth ``` The final output filename will be `stylegan2_c2_8xb4_ffhq-1024x1024_{time}-{hash id}.pth`. ## Print full config MMGeneration incorporates config mechanism to set parameters used for training and testing models. With our [config](../user_guides/config.md) mechanism, users can easily conduct extensive experiments without hard coding. If you wish to inspect the config file, you may run `python tools/misc/print_config.py /PATH/TO/CONFIG` to see the complete config. An Example: ```shell python tools/misc/print_config.py configs/styleganv2/stylegan2_c2-PL_8xb4-fp16-partial-GD-no-scaler-800kiters_ffhq-256x256.py ``` ================================================ FILE: docs/en/user_guides/visualization.md ================================================ # Tutorial 6: Visualization The visualization of images is an important way to measure the quality of image processing, editing and synthesis. Using `visualizer` in config file can save visual results when training or testing. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/visualization.md) to learn the usage of visualization. MMagic provides a rich set of visualization functions. In this tutorial, we introduce the usage of the visualization functions provided by MMagic. - [Tutorial 6: Visualization](#tutorial-6-visualization) - [Overview](#overview) - [Visualization configuration of GANs](#visualization-configuration-of-gans) - [Visualization configuration of image translation models](#visualization-configuration-of-image-translation-models) - [Visualization configuration of diffusion models](#visualization-configuration-of-diffusion-models) - [Visualization configuration of inpainting models](#visualization-configuration-of-inpainting-models) - [Visualization configuration of matting models](#visualization-configuration-of-matting-models) - [Visualization configuration of SISR/VSR/VFI models](#visualization-configuration-of-sisrvsrvfi-models) - [Visualization Hook](#visualization-hook) - [Visualizer](#visualizer) - [VisBackend](#visbackend) - [Use Different Storage Backends](#use-different-storage-backends) ## Overview It is recommended to learn the basic concept of visualization in design documentation. In MMagic, the visualization of the training or testing process requires the configuration of three components: `VisualizationHook`, `Visualizer`, and `VisBackend`, The diagram below shows the relationship between Visualizer and VisBackend,
**VisualizationHook** fetches the visualization results of the model output in fixed intervals during training and passes them to Visualizer. **Visualizer** is responsible for converting the original visualization results into the desired type (png, gif, etc.) and then transferring them to **VisBackend** for storage or display. ### Visualization configuration of GANs For GAN models, such as StyleGAN and SAGAN, a usual configuration is shown below: ```python # VisualizationHook custom_hooks = [ dict( type='VisualizationHook', interval=5000, # visualization interval fixed_input=True, # whether use fixed noise input to generate images vis_kwargs_list=dict(type='GAN', name='fake_img') # pre-defined visualization arguments for GAN models ) ] # VisBackend vis_backends = [ dict(type='VisBackend'), # vis_backend for saving images to file system dict(type='WandbVisBackend', # vis_backend for uploading images to Wandb init_kwargs=dict( project='MMagic', # project name for Wandb name='GAN-Visualization-Demo' # name of the experiment for Wandb )) ] # Visualizer visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` If you apply Exponential Moving Average (EMA) to a generator and want to visualize the EMA model, you can modify config of `VisualizationHook` as below: ```python custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig in `fake_img` at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', # save images with prefix `fake_img` sample_model='ema/orig', # specified kwargs for `NoiseSampler` target_keys=['ema.fake_img', 'orig.fake_img'] # specific key to visualization )) ] ``` ### Visualization configuration of image translation models For Translation models, such as CycleGAN and Pix2Pix, visualization configs can be formed as below: ```python # VisualizationHook custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict( type='Translation', # Visualize results on the training set name='trans'), # save images with prefix `trans` dict( type='Translationval', # Visualize results on the validation set name='trans_val'), # save images with prefix `trans_val` ]) ] # VisBackend vis_backends = [ dict(type='VisBackend'), # vis_backend for saving images to file system dict(type='WandbVisBackend', # vis_backend for uploading images to Wandb init_kwargs=dict( project='MMagic', # project name for Wandb name='Translation-Visualization-Demo' # name of the experiment for Wandb )) ] # Visualizer visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` ### Visualization configuration of diffusion models For Diffusion models, such as Improved-DDPM, we can use the following configuration to visualize the denoising process through a gif: ```python # VisualizationHook custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='DDPMDenoising')) # pre-defined visualization argument for DDPM models ] # VisBackend vis_backends = [ dict(type='VisBackend'), # vis_backend for saving images to file system dict(type='WandbVisBackend', # vis_backend for uploading images to Wandb init_kwargs=dict( project='MMagic', # project name for Wandb name='Diffusion-Visualization-Demo' # name of the experiment for Wandb )) ] # Visualizer visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` ### Visualization configuration of inpainting models For inpainting models, such as AOT-GAN and Global&Local, a usual configuration is shown below: ```python # VisBackend vis_backends = [dict(type='LocalVisBackend')] # Visualizer visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) # VisualizationHook custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` ### Visualization configuration of matting models For matting models, such as DIM and GCA, a usual configuration is shown below: ```python # VisBackend vis_backends = [dict(type='LocalVisBackend')] # Visualizer visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='trimap_path', img_keys=['pred_alpha', 'trimap', 'gt_merged', 'gt_alpha'], bgr2rgb=True) # VisualizationHook custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` ### Visualization configuration of SISR/VSR/VFI models For SISR/VSR/VFI models, such as EDSR, EDVR and CAIN, a usual configuration is shown below: ```python # VisBackend vis_backends = [dict(type='LocalVisBackend')] # Visualizer visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=False) # VisualizationHook custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` The specific configuration of the `VisualizationHook`, `Visualizer` and `VisBackend` components are described below ## Visualization Hook In MMagic, we use `BasicVisualizationHook` and `VisualizationHook` as `VisualizationHook`. `VisualizationHook` supports three following cases. (1) Modify `vis_kwargs_list` to visualize the output of the model under specific inputs , which is suitable for visualization of the generated results of GAN and translation results of Image-to-Image-Translation models under specific data input, etc. Below are two typical examples: ```python # input as dict vis_kwargs_list = dict( type='Noise', # use 'Noise' sampler to generate model input name='fake_img', # define prefix of saved images ) # input as list of dict vis_kwargs_list = [ dict(type='Arguments', # use `Arguments` sampler to generate model input name='arg_output', # define prefix of saved images vis_mode='gif', # specific visualization mode as GIF forward_kwargs=dict(forward_mode='sampling', sample_kwargs=dict(show_pbar=True)) # specific kwargs for `Arguments` sampler ), dict(type='Data', # use `Data` sampler to feed data in dataloader to model as input n_samples=36, # specific how many samples want to generate fixed_input=False, # specific do not use fixed input for each visualization process ) ] ``` `vis_kwargs_list` takes dict or list of dict as input. Each of dict must contain a `type` field indicating the **type of sampler** used to generate the model input, and each of the dict must also contain the keyword fields necessary for the sampler (e.g. `ArgumentSampler` requires that the argument dictionary contain `forward_kwargs`). > To be noted that, this content is checked by the corresponding sampler and is not restricted by `BasicVisualizationHook`. In addition, the other fields are generic fields (e.g. `n_samples`, `n_row`, `name`, `fixed_input`, etc.). If not passed in, the default values from the BasicVisualizationHook initialization will be used. For the convenience of users, MMagic has pre-defined visualization parameters for **GAN**, **Translation models**, **SinGAN** and **Diffusion models**, and users can directly use the predefined visualization methods by using the following configuration: ```python vis_kwargs_list = dict(type='GAN') vis_kwargs_list = dict(type='SinGAN') vis_kwargs_list = dict(type='Translation') vis_kwargs_list = dict(type='TranslationVal') vis_kwargs_list = dict(type='TranslationTest') vis_kwargs_list = dict(type='DDPMDenoising') ``` ## Visualizer In MMagic, we implement `ConcatImageVisualizer` and `Visualizer`, which inherit from `mmengine.Visualizer`. The base class of `Visualizer` is `ManagerMixin` and this makes `Visualizer` a globally unique object. After being instantiated, `Visualizer` can be called at anywhere of the code by `Visualizer.get_current_instance()`, as shown below: ```python # configs vis_backends = [dict(type='VisBackend')] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # `get_instance()` is called for globally unique instantiation VISUALIZERS.build(cfg.visualizer) # Once instantiated by the above code, you can call the `get_current_instance` method at any location to get the visualizer visualizer = Visualizer.get_current_instance() ``` The core interface of `Visualizer` is `add_datasample`. Through this interface, This interface will call the corresponding drawing function according to the corresponding `vis_mode` to obtain the visualization result in `np.ndarray` type. Then `show` or `add_image` will be called to directly show the results or pass the visualization result to the predefined vis_backend. ## VisBackend In general, users do not need to manipulate `VisBackend` objects, only when the current visualization storage can not meet the needs, users will want to manipulate the storage backend directly. MMagic supports a variety of different visualization backends, including: - Basic VisBackend of MMEngine: including LocalVisBackend, TensorboardVisBackend and WandbVisBackend. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/visualization.md) to learn more about them - VisBackend: Backend for **File System**. Save the visualization results to the corresponding position. - TensorboardVisBackend: Backend for **Tensorboard**. Send the visualization results to Tensorboard. - WandbVisBackend: Backend for **Wandb**. Send the visualization results to Tensorboard. One `Visualizer` object can have access to any number of VisBackends and users can access to the backend by their class name in their code. ```python # configs vis_backends = [dict(type='Visualizer'), dict(type='WandbVisBackend')] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # code VISUALIZERS.build(cfg.visualizer) visualizer = Visualizer.get_current_instance() # access to the backend by class name gen_vis_backend = visualizer.get_backend('VisBackend') gen_wandb_vis_backend = visualizer.get_backend('GenWandbVisBackend') ``` When there are multiply VisBackend with the same class name, user must specific name for each VisBackend. ```python # configs vis_backends = [ dict(type='VisBackend', name='gen_vis_backend_1'), dict(type='VisBackend', name='gen_vis_backend_2') ] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # code VISUALIZERS.build(cfg.visualizer) visualizer = Visualizer.get_current_instance() local_vis_backend_1 = visualizer.get_backend('gen_vis_backend_1') local_vis_backend_2 = visualizer.get_backend('gen_vis_backend_2') ``` ### Visualize by Different Storage Backends If you want to use a different backend (Wandb, Tensorboard, or a custom backend with a remote window), just change the `vis_backends` in the config, as follows: **Local** ```python vis_backends = [dict(type='LocalVisBackend')] ``` **Tensorboard** ```python vis_backends = [dict(type='TensorboardVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, name='visualizer') ``` ```python vis_backends = [dict(type='WandbVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, name='visualizer') ``` ================================================ FILE: docs/zh_cn/.dev_scripts/update_dataset_zoo.py ================================================ import os from tqdm import tqdm def update_dataset_zoo(): target_dir = 'dataset_zoo' source_dir = '../../tools/dataset_converters' os.makedirs(target_dir, exist_ok=True) # generate overview overviewmsg = """ # 概览 """ # generate index.rst rstmsg = """ .. toctree:: :maxdepth: 1 :caption: Dataset Zoo overview.md """ subfolders = os.listdir(source_dir) for subf in tqdm(subfolders, desc='update dataset zoo'): target_subf = subf.replace('-', '_').lower() target_readme = os.path.join(target_dir, target_subf + '.md') source_readme = os.path.join(source_dir, subf, 'README_zh-CN.md') if not os.path.exists(source_readme): continue overviewmsg += f'\n- [{subf}]({target_subf}.md)' rstmsg += f'\n {target_subf}.md' # generate all tasks dataset_zoo command = f'cat {source_readme} > {target_readme}' os.popen(command) with open(os.path.join(target_dir, 'overview.md'), 'w') as f: f.write(overviewmsg) with open(os.path.join(target_dir, 'index.rst'), 'w') as f: f.write(rstmsg) if __name__ == '__main__': update_dataset_zoo() ================================================ FILE: docs/zh_cn/.dev_scripts/update_model_zoo.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. import functools as func import glob import os import os.path as osp import re from os.path import basename, dirname import numpy as np import titlecase from tqdm import tqdm github_link = 'https://github.com/open-mmlab/mmagic/blob/main/' def anchor(name): return re.sub(r'-+', '-', re.sub(r'[^a-zA-Z0-9\+]', '-', name.strip().lower())).strip('-') def summarize(stats, name): allpapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _, _, _, _, _ in stats]) allconfigs = func.reduce(lambda a, b: a.union(b), [c for _, c, _, _, _, _, _ in stats]) allckpts = func.reduce(lambda a, b: a.union(b), [c for _, _, c, _, _, _, _ in stats]) alltasks = func.reduce(lambda a, b: a.union(b), [t for _, _, _, t, _, _, _ in stats]) task_desc = '\n'.join([ f" - [{task}]({task.replace('-', '_').replace(' ', '_').lower()}.md)" # noqa for task in list(alltasks) ]) # Overview papertypes, papercounts = np.unique([t for t, _ in allpapers], return_counts=True) countstr = '\n'.join( [f' - {t}: {c}' for t, c in zip(papertypes, papercounts)]) countstr = '\n'.join([f' - ALGORITHM: {len(stats)}']) summary = f"""# {name} """ if name != 'Overview': summary += '\n## 概览' summary += f""" * 预训练权重个数: {len(allckpts)} * 配置文件个数: {len(allconfigs)} * 论文个数: {len(allpapers)} {countstr} """ if name == 'Overview': summary += f""" * 任务: {task_desc} """ return summary # Count algorithms def update_model_zoo(): target_dir = 'model_zoo' os.makedirs(target_dir, exist_ok=True) root_dir = dirname(dirname(dirname(dirname(osp.abspath(__file__))))) files = sorted(glob.glob(osp.join(root_dir, 'configs/*/README_zh-CN.md'))) stats = [] for f in tqdm(files, desc='update model zoo'): with open(f, 'r') as content_file: content = content_file.read() # title title = content.split('\n')[0].replace('#', '') year = title.split('\'')[-1].split(')')[0] # count papers papers = set( (papertype, titlecase.titlecase(paper.lower().strip()).replace('+', r'\+')) for (papertype, paper) in re.findall( r'\s*\n.*?\btitle\s*=\s*{(.*?)}', content, re.DOTALL)) # paper links revcontent = '\n'.join(list(reversed(content.splitlines()))) paperlinks = {} for _, p in papers: paper_link = osp.join(github_link, 'configs', basename(dirname(f)), 'README_zh-CN.md') # print(p, paper_link) paperlinks[p] = ' '.join( (f'[⇨]({paper_link}#{anchor(paperlink)})' for paperlink in re.findall( rf'\btitle\s*=\s*{{\s*{p}\s*}}.*?\n## (.*?)\s*[,;]?\s*\n', revcontent, re.DOTALL | re.IGNORECASE))) # print(' ', paperlinks[p]) paperlist = '\n'.join( sorted(f' - [{t}] {x} ({paperlinks[x]})' for t, x in papers)) # count configs configs = set(x.lower().strip() for x in re.findall(r'/configs/.*?\.py', content)) # count ckpts ckpts = list( x.lower().strip() for x in re.findall(r'\[model\]\(https\:\/\/.*\.pth', content)) ckpts.extend( x.lower().strip() for x in re.findall(r'\[ckpt\]\(https\:\/\/.*\.pth', content)) ckpts.extend( x.lower().strip() for x in re.findall(r'\[模型\]\(https\:\/\/.*\.pth', content)) ckpts.extend( x.lower().strip() for x in re.findall(r'\[权重\]\(https\:\/\/.*\.pth', content)) ckpts = set(ckpts) # count tasks task_desc = list( set(x.lower().strip() for x in re.findall(r'\*\*任务\*\*: .*', content))) tasks = set() if len(task_desc) > 0: tasks = set(task_desc[0].split('**任务**: ')[1].split(', ')) statsmsg = f"""## {title}""" if len(tasks) > 0: statsmsg += f"\n* Tasks: {','.join(list(tasks))}" statsmsg += f""" * 预训练权重个数: {len(ckpts)} * 配置文件个数: {len(configs)} * 论文个数: {len(papers)} {paperlist} """ # * We should have: {len(glob.glob(osp.join(dirname(f), '*.py')))} content = content.replace('# ', '## ') stats.append((papers, configs, ckpts, tasks, year, statsmsg, content)) # overview overview = summarize(stats, '概览') with open(osp.join(target_dir, 'overview.md'), 'w') as f: f.write(overview) alltasks = func.reduce(lambda a, b: a.union(b), [t for _, _, _, t, _, _, _ in stats]) # index.rst indexmsg = """ .. toctree:: :maxdepth: 1 :caption: 模型库 overview.md """ for task in alltasks: task = task.replace(' ', '_').replace('-', '_').lower() indexmsg += f' {task}.md\n' with open(osp.join(target_dir, 'index.rst'), 'w') as f: f.write(indexmsg) # task-specific for task in alltasks: filtered_model = [ (paper, config, ckpt, tasks, year, x, content) for paper, config, ckpt, tasks, year, x, content in stats if task in tasks ] filtered_model = sorted(filtered_model, key=lambda x: x[-3])[::-1] overview = summarize(filtered_model, task) msglist = '\n'.join(x for _, _, _, _, _, _, x in filtered_model) task = task.replace(' ', '_').replace('-', '_').lower() with open(osp.join(target_dir, f'{task}.md'), 'w') as f: f.write(overview + '\n' + msglist) if __name__ == '__main__': update_model_zoo() ================================================ FILE: docs/zh_cn/.gitignore ================================================ model_zoo dataset_zoo ================================================ FILE: docs/zh_cn/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile rm -rf _build rm -rf model_zoo rm -rf dataset_zoo @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ================================================ FILE: docs/zh_cn/_static/css/readthedocs.css ================================================ .header-logo { background-image: url("../image/mmagic-logo.png"); background-size: 142px 46px; height: 46px; width: 142px; } ================================================ FILE: docs/zh_cn/_templates/404.html ================================================ {% extends "layout.html" %} {% block body %}

未找到页面

未找到你要打开的页面。

如果你是从旧版本文档跳转至此,可能是对应的页面被移动了。请从左侧的目录中寻找新版本文档,或者跳转至首页

如果你找不到希望打开的文档,欢迎在 Issue 中告诉我们!

{% endblock %} ================================================ FILE: docs/zh_cn/advanced_guides/data_flow.md ================================================ # 数据流 - [数据流](#数据流) - [数据流概述](#数据流概述) - [数据集与模型之间的数据流](#数据集与模型之间的数据流) - [数据加载器的数据处理](#数据加载器的数据处理) - [数据预处理器的数据处理](#数据预处理器的数据处理) - [模型输出与可视化器之间的数据流](#模型输出与可视化器之间的数据流) ## 数据流概述 [Runner](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/design/runner.md) 相当于 MMEngine 中的“集成器”。它覆盖了框架的所有方面,并肩负着组织和调度几乎所有模块的责任,这意味着各模块之间的数据流也由 `Runner` 控制。在本章节中,我们将介绍 [Runner](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/runner.html) 管理的内部模块之间的数据流和数据格式约定。
在上图中,在训练迭代中,数据加载器(dataloader)从存储中加载图像并传输到数据预处理器(data preprocessor),数据预处理器会将图像放到特定的设备上,并将数据堆叠到批处理中,之后模型接受批处理数据作为输入,最后将模型的输出计算损失函数(loss)。在评估时模型参数会被冻结,模型的输出需要经由数据预处理器(data preprocessor)解构再被传递给 [Evaluator](./evaluation.md#ioumetric)计算指标或者提供给[Visualizer](../user_guides/visualization.md)进行可视化。 ## 数据集与模型之间的数据流 在本节中将介绍在MMagic中数据集中的数据流传递,关于[数据集定义](https://mmagic.readthedocs.io/zh_CN/latest/howto/dataset.html)和[数据处理管线](https://mmagic.readthedocs.io/zh_CN/latest/howto/transforms.html)相关的解读详见开发指南。数据集 (dataset) 和模型 (model)之间的数据流传递一般可以分为如下四个步骤 : 1. 读取 `XXDataset` 收集数据集的原始信息,并且通过数据处理管线对数据进行数据转换处理; 2. 使用 `PackInputs` 将转换完成的数据打包成为一个字典; 3. 使用 `collate_fn` 将各个张量集成为一个批处理张量; 4. 使用 `data_preprocessor` 把以上所有数据迁移到 GPUS 等目标设备,并在数据加载器中将之前打包的字典解压为一个元组,该元组包含输入图像与对应的元信息(`DataSample`)。 ### 数据处理管线的数据处理 在MMagic中,经由不同类型的`XXDataset`, 分别读取数据(LQ)以及标注(GT),并且在不同的数据预处理管道中进行数据转换,最后通过`PackInputs`将处理之后的数据打包为字典,此字典包含训练以及测试过程所需的所有数据。
base_edit_model.py base_conditional_gan.py
```python @MODELS.register_module() class BaseEditModel(BaseModel): """Base model for image and video editing. """ def forward(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs) -> Union[torch.Tensor, List[DataSample], dict]: if isinstance(inputs, dict): inputs = inputs['img'] if mode == 'tensor': return self.forward_tensor(inputs, data_samples, **kwargs) elif mode == 'predict': predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'loss': return self.forward_train(inputs, data_samples, **kwargs) ``` ```python @MODELS.register_module() class BaseConditionalGAN(BaseGAN): """Base class for Conditional GAM models. """ def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: if isinstance(inputs, Tensor): noise = inputs sample_kwargs = {} else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) sample_kwargs = inputs.get('sample_kwargs', dict()) num_batches = noise.shape[0] pass ... ```
例如在`BaseEditModel`和`BaseConditionalGAN`模型中分别需要输入(input)包括 `img` 和 `noise` 的键值输入。同时,相应的字段也应该在配置文件中暴露, 以[cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py](../../../configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-80kiters_facades.py)为例, ```python domain_a = 'photo' domain_b = 'mask' pack_input = dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}'], data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ``` ### 数据加载器的数据处理 以数据集中的获取字典列表作为输入,数据加载器(dataloader)中的 `collect_fn` 会提取每个字典的`inputs`并将其整合成一个批处理张量;此外,每个字典中的`data_sample`也会被整合为一个列表,从而输出一个与先前字典有相同键的字典;最终数据加载器会通过 `collect_fn` 输出这个字典。详细文档可见[数据集与数据加载器](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/dataset.html)。 ### 数据预处理器的数据处理 数据预处理是数据输入模型之前,处理数据过程的最后一步。 数据预处理过程会对图像进行归一处理,如把 BGR 模式转换为 RGB 模式,并将所有数据迁移至 GPU 等目标设备中 。上述各步骤完成后,最终会得到一个元组,该元组包含一个批处理图像的列表,和一个数据样本的列表。详细文档可见[数据预处理](./data_preprocessor.md)。 ## 模型输出与可视化器之间的数据流 MMEngine约定了[抽象数据接口](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/advanced_tutorials/data_element.md)用于数据传递,其中 [数据样本](./structures.md)(DataSample) 作为一层更加高级封装可以容纳更多类别的标签数据。在MMagic中,用于可视化对比的`ConcatImageVisualizer`同时也通过 `add_datasample` 方法控制可视化具体内容,具体配置如下。 ```python visualizer = dict( type='ConcatImageVisualizer', vis_backends=[dict(type='LocalVisBackend')], fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) ``` ================================================ FILE: docs/zh_cn/advanced_guides/data_preprocessor.md ================================================ # 数据预处理器 ## 数据preprocessor在训练流程中的位置 在模型训练过程中,图片数据先通过mmcv中的transform进行数据增强,并加载为dataloader,而后通过preprocessor将数据从cpu搬运到cuda上,并进行padding和归一化 mmcv中的transform来自各下游算法库中transform的迁移,防止各下游算法库中transform的冗余,以`configs/_base_/datasets/unpaired_imgs_256x256.py`为例,其完整config中的`train_pipeline`如下所示 ```python ... train_pipeline = [ dict(color_type='color', key='img_A', type='LoadImageFromFile'), dict(color_type='color', key='img_B', type='LoadImageFromFile'), dict(auto_remap=True, mapping=dict(img=['img_A', 'img_B',]), share_random_params=True, transforms=[dict(interpolation='bicubic', scale=(286, 286,), type='Resize'), dict(crop_size=(256, 256,), keys=['img',], random_crop=True, type='Crop'),], type='TransformBroadcaster'), dict(direction='horizontal', keys=['img_A', ], type='Flip'), dict(direction='horizontal', keys=['img_B', ], type='Flip'), dict(mapping=dict(img_mask='img_B', img_photo='img_A'), remapping=dict(img_mask='img_mask', img_photo='img_photo'), type='KeyMapper'), dict(data_keys=['img_photo', 'img_mask',], keys=['img_photo', 'img_mask',], type='PackInputs'), ] ... ``` data_preprocessor会对transform后的数据进行数据搬移,拼接和归一化,而后输入到网络中,以`mmagic/models/editors/cyclegan/cyclegan.py`中的`train_step`函数为例,代码中的引用逻辑如下 ```python ... message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper = optim_wrapper['discriminators'] inputs_dict = data['inputs'] outputs, log_vars = dict(), dict() ... ``` 在mmagic中的data_processor,其代码实现路径为`mmagic/models/data_preprocessors/data_preprocessor.py`,其数据处理流程如下图 ![image](https://github.com/jinxianwei/CloudImg/assets/81373517/f52a92ab-f86d-486d-86ac-a2f388a83ced) ================================================ FILE: docs/zh_cn/advanced_guides/evaluator.md ================================================ # 评估器 ## 评测指标与评测器 在模型的验证和测试中,通常需要对模型的精度进行定量的评测。在mmagic中实现了评测指标(metric)和评测器(evaluator)来完成这一功能。 - 评测指标(metric)用于根据测试数据和模型预测结果,特定模型精度指标的计算。在mmagic中内置了多种metric,详见[评价指标](https://mmagic.readthedocs.io/zh_CN/latest/user_guides/metrics.html)。同时metric和数据集解耦,每种metric可以用于多个数据集。 - 评测器(evaluator)是评测指标的上层模块,通常需要包含一个或者多个指标。评测器的作用是在模型评测时完成必要的数据格式转换,并调用评测指标来计算模型精度。评测器通常由[执行器](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/runner.html)或测试脚本构建,分别用于在线评测和离线评测。 mmagic中的评测器继承自mmengine中的评测器,基本使用方法也与mmengine中的评测器类似,具体可以参见[模型精度评测](https://mmengine.readthedocs.io/zh_CN/latest/design/evaluation.html)。但不同于其他上层视觉任务,生成模型的评估指标往往具有多种输入。例如Inception Score(IS)指标的输入仅为虚假图片和任意数量的真实图片;Perceptual path length(PPL) 则需要从隐空间中进行采样。为了对不同的评测指标进行兼容,mmagic设计了两个重要的方法prepare_metrics和prepare_samplers来实现上述要求。 ## prepare_metrics ```python class Evaluator(Evaluator): ... def prepare_metrics(self, module: BaseModel, dataloader: DataLoader): """Prepare for metrics before evaluation starts. Some metrics use pretrained model to extract feature. Some metrics use pretrained model to extract feature and input channel order may vary among those models. Therefore, we first parse the output color order from data preprocessor and set the color order for each metric. Then we pass the dataloader to each metrics to prepare pre-calculated items. (e.g. inception feature of the real images). If metric has no pre-calculated items, :meth:`metric.prepare` will be ignored. Once the function has been called, :attr:`self.is_ready` will be set as `True`. If :attr:`self.is_ready` is `True`, this function will directly return to avoid duplicate computation. Args: module (BaseModel): Model to evaluate. dataloader (DataLoader): The dataloader for real images. """ if self.metrics is None: self.is_ready = True return if self.is_ready: return # prepare metrics for metric in self.metrics: metric.prepare(module, dataloader) self.is_ready = True ``` prepare_metrics方法需要在评测开始之前调用。它被用于在每个评测指标开始评测之前进行预处理,会依次调用evaluator的所有评测指标的prepare方法来准备该评测指标的需要预先计算好的元素(例如一些隐藏层的特征)。同时为了避免多次重复调用,在所有评测指标预处理完成之后,evaluator.is_ready 标志位会被设置为True。 ```python class GenMetric(BaseMetric): ... def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: """Prepare for the pre-calculating items of the metric. Defaults to do nothing. Args: module (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for the real images. """ if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor ``` ## prepare_samplers 对于生成模型而言,不同的metric需要不同的输入。例如FID, KID, IS只需要生成的fake images,而PPL则需要隐空间的向量。因此mmagic将不同的评估指标按照输入的类型进行了分组,属于同一个组的一个或者多个评测指标共享一个数据的采样器,每个评测指标的sampler mode由该评测指标的SAMPLER_MODE属性决定。 ```python class GenMetric(BaseMetric): ... SAMPLER_MODE = 'normal' class GenerativeMetric(GenMetric): ... SAMPLER_MODE = 'Generative' ``` 而evaluator的prepare_samplers 方法就是根据所有评测指标的sampler mode来准备好data sampler。 ```python class Evaluator(Evaluator): ... def prepare_samplers(self, module: BaseModel, dataloader: DataLoader ) -> List[Tuple[List[BaseMetric], Iterator]]: """Prepare for the sampler for metrics whose sampling mode are different. For generative models, different metric need image generated with different inputs. For example, FID, KID and IS need images generated with random noise, and PPL need paired images on the specific noise interpolation path. Therefore, we first group metrics with respect to their sampler's mode (refers to :attr:~`GenMetrics.SAMPLER_MODE`), and build a shared sampler for each metric group. To be noted that, the length of the shared sampler depends on the metric of the most images required in each group. Args: module (BaseModel): Model to evaluate. Some metrics (e.g. PPL) require `module` in their sampler. dataloader (DataLoader): The dataloader for real image. Returns: List[Tuple[List[BaseMetric], Iterator]]: A list of "metrics-shared sampler" pair. """ if self.metrics is None: return [[[None], []]] # grouping metrics based on `SAMPLER_MODE` and `sample_mode` metric_mode_dict = defaultdict(list) for metric in self.metrics: # 为每个metric指定sampler group metric_md5 = self._cal_metric_hash(metric) metric_mode_dict[metric_md5].append(metric) metrics_sampler_list = [] for metrics in metric_mode_dict.values(): #为每个group生成sampler first_metric = metrics[0] metrics_sampler_list.append([ metrics, first_metric.get_metric_sampler(module, dataloader, metrics) ]) return metrics_sampler_list ``` 该方法会首先检查自身是否有需要计算的评测指标:如果没有直接返回,如果有则会遍历所有评测指标,对所有采样指标根据sampler_mode和sample_model进行分组, 具体实现方式为根据sampler_mode和sample_model计算hash码,将具有相同hash码的评测指标放入同一个列表里。 ```python class Evaluator(Evaluator): ... @staticmethod def _cal_metric_hash(metric: GenMetric): """Calculate a unique hash value based on the `SAMPLER_MODE` and `sample_model`.""" sampler_mode = metric.SAMPLER_MODE sample_model = metric.sample_model metric_dict = { 'SAMPLER_MODE': sampler_mode, 'sample_model': sample_model } if hasattr(metric, 'need_cond_input'): metric_dict['need_cond_input'] = metric.need_cond_input md5 = hashlib.md5(repr(metric_dict).encode('utf-8')).hexdigest() return md5 ``` 最后该方法会为每一个评测指标组生成一个sampler采样器,添加到列表返回。 ## 评测器评测流程 整个评测器的评测流程在方法mmagic.engine.runner.MultiValLoop.run和mmagic.engine.runner.MultiTestLoop.run中实现。以mmagic.engine.runner.MultiTestLoop.run为例: ```python class MultiValLoop(BaseLoop): ... def run(self): ... # 1. prepare all metrics and get the total length metrics_sampler_lists = [] meta_info_list = [] dataset_name_list = [] for evaluator, dataloader in zip(self.evaluators, self.dataloaders): # 1.1 prepare for metrics evaluator.prepare_metrics(module, dataloader) # 1.2 prepare for metric-sampler pair metrics_sampler_list = evaluator.prepare_samplers( module, dataloader) metrics_sampler_lists.append(metrics_sampler_list) # 1.3 update total length self._total_length += sum([ len(metrics_sampler[1]) for metrics_sampler in metrics_sampler_list ]) # 1.4 save metainfo and dataset's name meta_info_list.append( getattr(dataloader.dataset, 'metainfo', None)) dataset_name_list.append(dataloader.dataset.__class__.__name__) ``` runner首先会通过evaluator.prepare_metrics和evaluator.prepare_samplers两个方法来进行评测所需要的预处理工作和获取评测所需要的数据采样器;同时更新所有采样器的采样总长度。由于mmagic的评测指标和数据集进行了分离,因此一些在评测时所需要的meta_info也需要进行保存并传递给评测器。 ```python class MultiValLoop(BaseLoop): ... def run(self): ... # 2. run evaluation for idx in range(len(self.evaluators)): # 2.1 set self.evaluator for run_iter self.evaluator = self.evaluators[idx] self.dataloader = self.dataloaders[idx] # 2.2 update metainfo for evaluator and visualizer meta_info = meta_info_list[idx] dataset_name = dataset_name_list[idx] if meta_info: self.evaluator.dataset_meta = meta_info self._runner.visualizer.dataset_meta = meta_info else: warnings.warn( f'Dataset {dataset_name} has no metainfo. `dataset_meta` ' 'in evaluator, metric and visualizer will be None.') # 2.3 generate images metrics_sampler_list = metrics_sampler_lists[idx] for metrics, sampler in metrics_sampler_list: for data in sampler: self.run_iter(idx_counter, data, metrics) idx_counter += 1 # 2.4 evaluate metrics and update multi_metric metrics = self.evaluator.evaluate() if multi_metric and metrics.keys() & multi_metric.keys(): raise ValueError('Please set different prefix for different' ' datasets in `val_evaluator`') else: multi_metric.update(metrics) # 3. finish evaluation and call hooks self._runner.call_hook('after_val_epoch', metrics=multi_metric) self._runner.call_hook('after_val') ``` 在完成了评测前的准备之后,runner会遍历所有evaluator,依次进行评估,每个evaluator需要对应一个dataloader,完成一个数据集的评测工作。具体在对每个evaluator进行评测的过程中,首先需要将评测所需要的meta_info传递给评测器,随后遍历该evaluator的所有metrics_sampler,生成评测所需要的图像,最后再完成评测。 ================================================ FILE: docs/zh_cn/advanced_guides/structures.md ================================================ # Data Structure MMaigc的数据结构接口`DataSample` 继承自 MMEngine 的 [` BaseDataElement`](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/data_element.html).MMEngine 的抽象数据接口实现了基础的增/删/改/查功能,且支持不同设备间的数据迁移,也支持了类字典和张量的操作,充分满足了数据的日常使用需求,这也使得不同算法的数据接口可以得到统一。 特别的,`BaseDataElement` 中存在两种类型的数据: - `metainfo` 类型,包含数据的元信息以确保数据的完整性,如 `img_shape`, `img_id` 等数据所在图片的一些基本信息,方便可视化等情况下对数据进行恢复和使用。 - `data` 类型,如标注框、框的标签、和实例掩码等。 得益于统一的数据封装,算法库内的 [`visualizer`](https://mmagic.readthedocs.io/zh_CN/latest/user_guides/visualization.html), [`evaluator`](https://mmagic.readthedocs.io/zh_CN/latest/advanced_guides/evaluator.html), [`model`](https://mmagic.readthedocs.io/zh_CN/latest/howto/models.html) 等各个模块间的数据流通都得到了极大的简化。 `DataSample`中的数据分为以下几个属性: ```python - ``gt_img``: 原始图像 - ``pred_img``: 模型预测图像 - ``ref_img``:参考图像 - ``mask``: 图像修复中的遮挡区域 - ``trimap``: 图像抠图中的三通道图 - ``gt_alpha``: 图像抠图中原始Alpha图 - ``pred_alpha``: 图像抠图中模型预测Alpha图 - ``gt_fg``: 图像抠图中原始前景图 - ``pred_fg``: 图像抠图中模型预测前景图 - ``gt_bg``: 图像抠图中原始背景图 - ``pred_bg``: 图像抠图中模型预测背景图 - ``gt_merged``: 图像抠图中原始合并图 ``` 以下示例代码展示了 `DataSample` 的组成元素类型: ```python import torch import numpy as np from mmagic.structures import DataSample img_meta = dict(img_shape=(800, 1196, 3)) img = torch.rand((3, 800, 1196)) data_sample = DataSample(gt_img=img, metainfo=img_meta) assert 'img_shape' in data_sample.metainfo_keys() data_sample # `DataSample` 的组成元素类型 ``` `DataSample`同样支持`stack`和`split`操作对数据进行批处理: 1. Stack 该函数用于将数据样本列表堆叠成一个。当数据样本堆叠时,所有张量字段都将堆叠在第一维度。如果数据样本中有非张量字段,例如列表或字典,则这些字段的值将保存在列表中。 ``` Args: data_samples (Sequence['DataSample']): 待堆叠的数据样本序列 Returns: DataSample: 堆叠的数据样本 ``` 2. Split 该函数将在第一维度拆分数据样本序列。 ``` Args: allow_nonseq_value (bool): 是否允许在拆分操作中使用非顺序数据。如果为 "True", 将为所有拆分数据样本复制非序列数据;否则,将引发错误。默认为 "False"。 Returns: Sequence[DataSample]: 拆分后的数据样本列表。 ``` 以下示例代码展示了 `stack`和`split` 的使用方法: ```py import torch import numpy as np from mmagic.structures import DataSample img_meta1 = img_meta2 = dict(img_shape=(800, 1196, 3)) img1 = torch.rand((3, 800, 1196)) img2 = torch.rand((3, 800, 1196)) data_sample1 = DataSample(gt_img=img1, metainfo=img_meta1) data_sample2 = DataSample(gt_img=img2, metainfo=img_meta1) ``` ```py # 堆叠stack data_sample = DataSample.stack([data_sample1, data_sample2]) print(data_sample.gt_img.shape) torch.Size([2, 3, 800, 1196]) print(data_sample.metainfo) {'img_shape': [(800, 1196, 3), (800, 1196, 3)]} # 拆分split data_sample1_, data_sample2_ = data_sample.split() assert (data_sample1_.gt_img == img1).all() assert (data_sample2_.gt_img == img2).all() ``` ================================================ FILE: docs/zh_cn/changelog.md ================================================ # 变更日志 **亮点** - 我们的代码仓库中发布了一个先进而强大的图像 inpainting 算法 PowerPaint。 [Click to View](https://github.com/open-mmlab/mmagic/tree/main/projects/powerpaint)
**新功能和改进** - \[CodeCamp2023-645\] 新增 dreambooth 的new cfg, by @YanxingLiu in https://github.com/open-mmlab/mmagic/pull/2042 - \[Enhance\] 新增 _base_ 目录下的 new config by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2053 - \[Enhance\] 支持了 instance_crop 使用 from_pretrained by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2066 - \[Enhance\] 支持了最新的 diffusers 使用 lora by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2067 - \[Enhance\] 提升了 powerpaint by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2078 - \[Enhance\] 提升了 powerpaint by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2080 - \[Enhance\] 增加了 gradio_PowerPaint.py 的 outpainting by @zhuang2002 in https://github.com/open-mmlab/mmagic/pull/2084 - \[MMSIG\] 增加了 StyleGAN2 的新config by @xiaomile in https://github.com/open-mmlab/mmagic/pull/2057 - \[MMSIG\] \[Doc\] 更新了 data_preprocessor.md by @jinxianwei in https://github.com/open-mmlab/mmagic/pull/2055 - \[Enhance\] 提升了 PowerPaint by @zhuang2002 in https://github.com/open-mmlab/mmagic/pull/2093 **Bug 修复** - \[Fix\] 更新了 README.md by @eze1376 in https://github.com/open-mmlab/mmagic/pull/2048 - \[Fix\] 修复了 test tokenizer by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2050 - \[Fix\] 修复了 readthedocs building by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2052 - \[Fix\] 修复了 --local-rank for PyTorch >= 2.0.0 by @youqingxiaozhua in https://github.com/open-mmlab/mmagic/pull/2051 - \[Fix\] 修复了 animatediff download from openxlab by @JianxinDong in https://github.com/open-mmlab/mmagic/pull/2061 - \[Fix\] 修复了 best practice by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2063 - \[Fix\] 修复了 try import expand mask from transformers by @zengyh1900 in https://github.com/open-mmlab/mmagic/pull/2064 - \[Fix\] 更新了 diffusers to v0.23.0 by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2069 - \[Fix\] 修复了 openxlab link to powerpaint by @liuwenran in https://github.com/open-mmlab/mmagic/pull/2082 - \[Fix\] 更新了 swinir_x2s48w8d6e180_8xb4-lr2e-4-500k_div2k.py, use MultiValLoop. by @ashutoshsingh0223 in https://github.com/open-mmlab/mmagic/pull/2085 - \[Fix\] 修复了 a test expression that has a logical short circuit. by @munahaf in https://github.com/open-mmlab/mmagic/pull/2046 - \[Fix\] 修复了 Powerpaint load safetensors by @sdbds in https://github.com/open-mmlab/mmagic/pull/2088 **新贡献者** - @eze1376 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2048 - @youqingxiaozhua 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2051 - @JianxinDong 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2061 - @zhuang2002 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2076 - @ashutoshsingh0223 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2085 - @jinxianwei 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2055 - @munahaf 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2046 - @sdbds 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2088 **完整更新日志**: https://github.com/open-mmlab/mmagic/compare/v1.1.0...v1.2.0 ## v1.1.0 (22/09/2023) **亮点** 在这次的发版中,我们新支持了下面五个新的算法. - 支持了 ViCo, 一种新的 SD personalization 算法. [点击查看](https://github.com/open-mmlab/mmagic/blob/main/configs/vico/README.md)

- 支持了 AnimateDiff, 一个很火的 text2animation 算法. [点击查看](https://github.com/open-mmlab/mmagic/blob/main/configs/animatediff/README.md) ![512](https://github.com/ElliotQi/mmagic/assets/46469021/54d92aca-dfa9-4eeb-ba38-3f6c981e5399) - 支持了 SDXL. [点击查看](https://github.com/open-mmlab/mmagic/blob/main/configs/stable_diffusion_xl/README.md)
- 支持了 DragGAN. [点击查看](https://github.com/open-mmlab/mmagic/blob/main/configs/draggan/README.md)
- 支持了 FastComposer. [点击查看](https://github.com/open-mmlab/mmagic/blob/main/configs/fastcomposer/README.md)
**新功能和改进** - \[功能\] 支持使用diffusers pipeline进行推断,首先使用sd_xl。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2023 - \[增强\] 为sd推理器添加负面提示。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2021 - \[增强\] 更新setup.cfg中的flake8检查配置。由@LeoXing1996完成,在https://github.com/open-mmlab/mmagic/pull/2007 - \[增强\] 将'config_name'作为'model_setting'的补充添加。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2027 - \[增强\] 更快的测试。由@okotaku完成,在https://github.com/open-mmlab/mmagic/pull/2034 - \[增强\] 添加OpenXLab徽章。由@ZhaoQiiii完成,在https://github.com/open-mmlab/mmagic/pull/2037 **CodeCamp贡献** - \[CodeCamp2023-643\] 添加BigGAN的新配置。由@limafang完成,在https://github.com/open-mmlab/mmagic/pull/2003 - \[CodeCamp2023-648\] MMagic的新配置GuidedDiffusion。由@ooooo-create完成,在https://github.com/open-mmlab/mmagic/pull/2005 - \[CodeCamp2023-649\] MMagic的新配置Instance Colorization。由@ooooo-create完成,在https://github.com/open-mmlab/mmagic/pull/2010 - \[CodeCamp2023-652\] MMagic的新配置StyleGAN3。由@hhy150完成,在https://github.com/open-mmlab/mmagic/pull/2018 - \[CodeCamp2023-653\] 添加Real BasicVSR的新配置。由@RangeKing完成,在https://github.com/open-mmlab/mmagic/pull/2030 **Bug 修复** - \[修复\] 修复主页上的最佳实践和返回目录,将新模型添加到模型库中。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2001 - \[修复\] 检查CI错误并移除主流GPU测试。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2013 - \[修复\] 检查Circle CI内存。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2016 - \[修复\] 移除代码并修复剪辑损失的单元测试。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2017 - \[修复\] 在diffusers pipeline推理器单元测试中模拟推理。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2026 - \[修复\] 由于合并draggan而修复的错误。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2029 - \[修复\] 更新QR码。由@crazysteeaam完成,在https://github.com/open-mmlab/mmagic/pull/2009 - \[修复\] 用OpenXLab版本替换README中的下载链接。由@FerryHuang完成,在https://github.com/open-mmlab/mmagic/pull/2038 - \[修复\] 增加文档字符串覆盖率。由@liuwenran完成,在https://github.com/open-mmlab/mmagic/pull/2039 **新贡献者** - @limafang 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2003 - @ooooo-create 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2005 - @hhy150 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2018 - @ZhaoQiiii 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2037 - @ElliotQi 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1980 - @Beaconsyh08 首次贡献于 https://github.com/open-mmlab/mmagic/pull/2012 **完整更新日志**: https://github.com/open-mmlab/mmagic/compare/v1.0.2...v1.0.3 ## v1.0.2 (24/08/2023) **亮点** **1. 更详尽的文档** 感谢社区的贡献者们帮助我们改进文档。我们已经改进了许多文档,包括中文和英文版本。更多详细信息请参考[文档](https://mmagic.readthedocs.io/zh_CN/latest/)。 **2. 新的算法** - 支持了 Prompt-to-prompt, DDIM Inversion 和 Null-text Inversion. [点击查看.](https://github.com/open-mmlab/mmagic/blob/main/projects/prompt_to_prompt/README.md) 从左到右: origin image, DDIM inversion, Null-text inversion
Prompt-to-prompt 编辑
cat -> dog
spider man -> iron man(attention replace)
Effel tower -> Effel tower at night (attention refine)
blossom sakura tree -> blossom(-3) sakura tree (attention reweight)
- 支持了 Textual Inversion. [点击查看.](https://github.com/open-mmlab/mmagic/blob/main/configs/textual_inversion/README.md)
- 支持了 Attention Injection 以便使用 controlnet 生成更稳定的视频. [点击查看.](https://github.com/open-mmlab/mmagic/blob/main/configs/controlnet_animation/README.md) - 支持了 Stable Diffusion Inpainting. [点击查看.](https://github.com/open-mmlab/mmagic/blob/main/configs/stable_diffusion/README.md) **新功能和改进** - \[增强\] 支持在稳定扩散训练中的噪声偏移,由 @LeoXing1996 提交于 https://github.com/open-mmlab/mmagic/pull/1880 ↗ - \[社区\] 支持 Glide Upsampler,由 @Taited 提交于 https://github.com/open-mmlab/mmagic/pull/1663 ↗ - \[增强\] 支持 controlnet 推理器,由 @Z-Fran 提交于 https://github.com/open-mmlab/mmagic/pull/1891 ↗ - \[功能\] 支持 Albumentations 增强变换和流水线,由 @Z-Fran 提交于 https://github.com/open-mmlab/mmagic/pull/1894 ↗ - \[功能\] 为 unet 添加注意力注入,由 @liuwenran 提交于 https://github.com/open-mmlab/mmagic/pull/1895 ↗ - \[增强\] 更新基准测试脚本,由 @Z-Fran 提交于 https://github.com/open-mmlab/mmagic/pull/1907 ↗ - \[增强\] 更新 mmagic 文档,由 @crazysteeaam 提交于 https://github.com/open-mmlab/mmagic/pull/1920 ↗ - \[增强\] 支持 Prompt-to-prompt、ddim inversion 和 null-text inversion,由 @FerryHuang 提交于 https://github.com/open-mmlab/mmagic/pull/1908 ↗ - \[CodeCamp2023-302\] 支持 MMagic 可视化并编写用户指南,由 @aptsunny 提交于 https://github.com/open-mmlab/mmagic/pull/1939 ↗ - \[功能\] 支持textual inversion,由 @LeoXing1996 提交于 https://github.com/open-mmlab/mmagic/pull/1822 ↗ - \[增强\] 对一些模型采用 BaseModule,由 @LeoXing1996 提交于 https://github.com/open-mmlab/mmagic/pull/1543 ↗ - \[MMSIG\] 支持 DeblurGANv2 推理,由 @xiaomile 提交于 https://github.com/open-mmlab/mmagic/pull/1955 ↗ - \[CodeCamp2023-647\] 添加 EG3D 的新配置,由 @RangeKing 提交于 https://github.com/open-mmlab/mmagic/pull/1985 ↗ **Bug 修复** - 修复了 StableDiffusion 和 DreamBooth 训练中的 dtype 错误。 by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1879 - 修复了 gui VideoSlider 的 bug。 by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1885 - 修复了 init_model 和 glide demo 的问题。 by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1888 - 修复了当 dim=3 时的 InstColorization bug。 by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1901 - 修复了 sd 和 controlnet 的 fp16 bug。 by @Z-Fran in https://github.com/open-mmlab/mmagic/pull/1914 - 修复了 controlnet 中的 num_images_per_prompt。 by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1936 - 修正了 sd-inpainting 的 metafile 以修复推理器的初始化。 by @LeoXing1996 in https://github.com/open-mmlab/mmagic/pull/1995 **新贡献者** - @wyyang23 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1886 - @yehuixie 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1912 - @crazysteeaam 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1920 - @BUPT-NingXinyu 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1921 - @zhjunqin 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1918 - @xuesheng1031 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1923 - @wslgqq277g 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1934 - @LYMDLUT 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1933 - @RangeKing 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1930 - @xin-li-67 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1932 - @chg0901 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1931 - @aptsunny 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1939 - @YanxingLiu 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1943 - @tackhwa 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1937 - @Geo-Chou 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1940 - @qsun1 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1956 - @ththth888 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1961 - @sijiua 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1967 - @MING-ZCH 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1982 - @AllYoung 首次贡献于 https://github.com/open-mmlab/mmagic/pull/1996 ## v1.0.1 (26/05/2023) **新功能和改进** - 支持 StableDiffusion tomesd 加速. [#1801](https://github.com/open-mmlab/mmagic/pull/1801) - 支持所有 inpainting/matting/image restoration 模型的 inferencer. [#1833](https://github.com/open-mmlab/mmagic/pull/1833), [#1873](https://github.com/open-mmlab/mmagic/pull/1873) - 支持 animated drawings. [#1837](https://github.com/open-mmlab/mmagic/pull/1837) - 支持 Style-Based Global Appearance Flow for Virtual Try-On at projects. [#1786](https://github.com/open-mmlab/mmagic/pull/1786) - 支持 tokenizer wrapper 和 EmbeddingLayerWithFixe. [#1846](https://github.com/open-mmlab/mmagic/pull/1846) **Bug 修复** - 修复安装依赖. [#1819](https://github.com/open-mmlab/mmagic/pull/1819) - 修复 inst-colorization PackInputs. [#1828](https://github.com/open-mmlab/mmagic/pull/1828), [#1827](https://github.com/open-mmlab/mmagic/pull/1827) - 修复 pip install 时 inferencer 无法使用的问题. [#1875](https://github.com/open-mmlab/mmagic/pull/1875) ## v1.0.0 (25/04/2023) 我们正式发布 MMagic v1.0.0 版本,源自 [MMEditing](https://github.com/open-mmlab/mmediting) 和 [MMGeneration](https://github.com/open-mmlab/mmgeneration)。 ![mmagic-log](https://user-images.githubusercontent.com/49083766/233557648-9034f5a0-c85d-4092-b700-3a28072251b6.png) 自从 MMEditing 诞生以来,它一直是许多图像超分辨率、编辑和生成任务的首选算法库,帮助多个研究团队取得 10 余 项国际顶级赛事的胜利,支撑了 100 多个 GitHub 生态项目。经过 OpenMMLab 2.0 框架的迭代更新以及与 MMGeneration 的合并,MMEditing 已经成为了一个支持基于 GAN 和 CNN 的底层视觉算法的强大工具。 而今天,MMEditing 将更加拥抱生成式 AI(Generative AI),正式更名为 **MMagic**(**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation),致力于打造更先进、更全面的 AIGC 开源算法库。 在 MMagic 中,我们已经支持了 53+ 模型,分布于 Stable Diffusion 的微调、图文生成、图像及视频修复、超分辨率、编辑和生成等多种任务。配合 [MMEngine](https://github.com/open-mmlab/mmengine) 出色的训练与实验管理支持,MMagic 将为广大研究者与 AIGC 爱好者们提供更加快捷灵活的实验支持,助力你的 AIGC 探索之旅。使用 MMagic,体验更多生成的魔力!让我们一起开启超越编辑的新纪元! More than Editing, Unlock the Magic! **主要更新** **1. 新算法** 我们支持了4个新任务以及11个新算法。 - Text2Image / Diffusion - ControlNet - DreamBooth - Stable Diffusion - Disco Diffusion - GLIDE - Guided Diffusion - 3D-aware Generation - EG3D - Image Restoration - NAFNet - Restormer - SwinIR - Image Colorization - InstColorization https://user-images.githubusercontent.com/49083766/233564593-7d3d48ed-e843-4432-b610-35e3d257765c.mp4 **2. Magic Diffusion Model** 针对 Diffusion Model,我们提供了以下“魔法” - 支持基于 Stable Diffusion 与 Disco Diffusion 的图像生成. - 支持 Dreambooth 以及 DreamBooth LoRA 等 Finetune 方法. - 支持 ControlNet 进行可控性的文本到图像生成. ![de87f16f-bf6d-4a61-8406-5ecdbb9167b6](https://user-images.githubusercontent.com/49083766/233558077-2005e603-c5a8-49af-930f-e7a465ca818b.png) - 支持 xFormers 加速和优化策略,提高训练与推理效率. - 支持基于 MultiFrame Render 的视频生成. MMagic 支持通过 ControlNet 与多帧渲染法实现长视频的生成。 prompt keywords: a handsome man, silver hair, smiling, play basketball https://user-images.githubusercontent.com/12782558/227149757-fd054d32-554f-45d5-9f09-319184866d85.mp4 prompt keywords: a girl, black hair, white pants, smiling, play basketball https://user-images.githubusercontent.com/49083766/233559964-bd5127bd-52f6-44b6-a089-9d7adfbc2430.mp4 prompt keywords: a handsome man https://user-images.githubusercontent.com/12782558/227152129-d70d5f76-a6fc-4d23-97d1-a94abd08f95a.mp4 - 支持通过 Wrapper 调用 Diffusers 的基础模型以及采样策略. - SAM + MMagic = Generate Anything! 当下流行的 SAM(Segment Anything Model)也可以为 MMagic 提供更多加持!想制作自己的动画,可以移步至 [OpenMMLab PlayGround](https://github.com/open-mmlab/playground/blob/main/mmediting_sam/README.md)! https://user-images.githubusercontent.com/49083766/233562228-f39fc675-326c-4ae8-986a-c942059effd0.mp4 **3. 框架升级** 为了提升你的“施法”效率,我们对“魔术回路”做了以下升级: - 通过 OpenMMLab 2.0 框架的 MMEngine 和 MMCV, MMagic 将编辑框架分解为不同的组件,并且可以通过组合不同的模块轻松地构建自定义的编辑器模型。我们可以像搭建“乐高”一样定义训练流程,提供丰富的组件和策略。在 MMagic 中,你可以使用不同的 APIs 完全控制训练流程. - 支持 33+ 算法 Pytorch 2.0 加速. - 重构 DataSample,支持 batch 维度的组合与拆分. - 重构 DataPreprocessor,并统一各种任务在训练与推理时的数据格式. - 重构 MultiValLoop 与 MultiTestLoop,同时支持生成类型指标(e.g. FID)与重建类型指标(e.g. SSIM) 的评测,同时支持一次性评测多个数据集 - 支持本地可视化以及使用 tensorboard 或 wandb的可视化. **新功能和改进** - 支持 53+ 算法,232+ 配置,213+ 模型权重,26+ 损失函数,and 20+ 评价指标. - 支持 controlnet 动画生成以及 Gradio gui. [点击查看.](https://github.com/open-mmlab/mmagic/tree/main/configs/controlnet_animation) - 支持 Inferencer 和 Demo,使用High-level Inference APIs. [点击查看.](https://github.com/open-mmlab/mmagic/tree/main/demo) - 支持 Inpainting 推理的 Gradio gui. [点击查看.](https://github.com/open-mmlab/mmagic/blob/main/demo/gradio-demo.py) - 支持可视化图像/视频质量比较工具. [点击查看.](https://github.com/open-mmlab/mmagic/tree/main/tools/gui) - 开启 projects,助力社区更快向算法库中添加新算法. [点击查看.](https://github.com/open-mmlab/mmagic/tree/main/projects) - 完善数据集的预处理脚本和使用说明文档. [点击查看.](https://github.com/open-mmlab/mmagic/tree/main/tools/dataset_converters) ## v1.0.0rc7 (07/04/2023) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc7 版本。 此版本支持了 MMEditing 和 MMGeneration 的 51+ 模型,226+ configs 和 212+ checkpoints。以下是此次版本发布的重点新功能 - 支持了 DiffuserWrapper. - 支持了 ControlNet 的推理与训练. - 支持了 PyTorch 2.0. **新功能和改进** - 支持了 DiffuserWrapper. [#1692](https://github.com/open-mmlab/mmagic/pull/1692) - 支持了 ControlNet 的推理与训练. [#1744](https://github.com/open-mmlab/mmagic/pull/1744) - 支持了 PyTorch 2.0 (使用 'inductor' 后端成功编译 33+ 模型) [#1742](https://github.com/open-mmlab/mmagic/pull/1742). - 支持了图像超分和视频超分的 inferencer. [#1662](https://github.com/open-mmlab/mmagic/pull/1662), [#1720](https://github.com/open-mmlab/mmagic/pull/1720) - 重构 get_flops 脚本. [#1675](https://github.com/open-mmlab/mmagic/pull/1675) - 重构数据集的 dataset_converters 脚本和使用文档. [#1690](https://github.com/open-mmlab/mmagic/pull/1690) - 迁移 stylegan 算子到 MMCV 中. [#1383](https://github.com/open-mmlab/mmagic/pull/1383) **Bug 修复** - 修复 disco inferencer. [#1673](https://github.com/open-mmlab/mmagic/pull/1673) - 修复 nafnet optimizer 配置. [#1716](https://github.com/open-mmlab/mmagic/pull/1716) - 修复 tof typo. [#1711](https://github.com/open-mmlab/mmagic/pull/1711) **贡献者** @LeoXing1996, @Z-Fran, @plyfager, @zengyh1900, @liuwenran, @ryanxingql, @HAOCHENYE, @VongolaWu ## v1.0.0rc6 (02/03/2023) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc6 版本。 此版本支持了 MMEditing 和 MMGeneration 的 50+ 模型,222+ configs 和 209+ checkpoints。以下是此次版本发布的重点新功能 - 支持了 Inpainting 任务推理的 Gradio gui. - 支持了图像上色、图像翻译和 GAN 模型的 inferencer. **新功能和改进** - 重构了 FileIO. [#1572](https://github.com/open-mmlab/mmagic/pull/1572) - 重构了 registry. [#1621](https://github.com/open-mmlab/mmagic/pull/1621) - 重构了 Random degradations. [#1583](https://github.com/open-mmlab/mmagic/pull/1583) - 重构了 DataSample, DataPreprocessor, Metric 和 Loop. [#1656](https://github.com/open-mmlab/mmagic/pull/1656) - 使用 mmengine.basemodule 替换 nn.module. [#1491](https://github.com/open-mmlab/mmagic/pull/1491) - 重构了算法库主页. [#1609](https://github.com/open-mmlab/mmagic/pull/1609) - 支持了 Inpainting 任务推理的 Gradio gui. [#1601](https://github.com/open-mmlab/mmagic/pull/1601) - 支持了图像上色的 inferencer. [#1588](https://github.com/open-mmlab/mmagic/pull/1588) - 支持了图像翻译和所有 GAN 模型的 inferencer. [#1650](https://github.com/open-mmlab/mmagic/pull/1650) - 支持了 GAN 模型的 inferencer. [#1653](https://github.com/open-mmlab/mmagic/pull/1653), [#1659](https://github.com/open-mmlab/mmagic/pull/1659) - 新增 Print config 工具. [#1590](https://github.com/open-mmlab/mmagic/pull/1590) - 改进 type hints. [#1604](https://github.com/open-mmlab/mmagic/pull/1604) - 更新 metrics 和 datasets 的中文文档. [#1568](https://github.com/open-mmlab/mmagic/pull/1568), [#1638](https://github.com/open-mmlab/mmagic/pull/1638) - 更新 BigGAN 和 Disco-Diffusion 的中文文档. [#1620](https://github.com/open-mmlab/mmagic/pull/1620) - 更新 Guided-Diffusion 的 Evaluation 和 README. [#1547](https://github.com/open-mmlab/mmagic/pull/1547) **Bug 修复** - 修复 EMA `momentum`. [#1581](https://github.com/open-mmlab/mmagic/pull/1581) - 修复 RandomNoise 的输出类型. [#1585](https://github.com/open-mmlab/mmagic/pull/1585) - 修复 pytorch2onnx 工具. [#1629](https://github.com/open-mmlab/mmagic/pull/1629) - 修复 API 文档. [#1641](https://github.com/open-mmlab/mmagic/pull/1641), [#1642](https://github.com/open-mmlab/mmagic/pull/1642) - 修复 RealESRGAN 加载 EMA 参数. [#1647](https://github.com/open-mmlab/mmagic/pull/1647) - 修复 dataset_converters 脚本的 arg passing bug. [#1648](https://github.com/open-mmlab/mmagic/pull/1648) **贡献者** @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @liuwenran, @austinmw, @dienachtderwelt, @liangzelong, @i-aki-y, @xiaomile, @Li-Qingyun, @vansin, @Luo-Yihang, @ydengbi, @ruoningYu, @triple-Mu ## v1.0.0rc5 (04/01/2023) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc5 版本。 此版本支持了 MMEditing 和 MMGeneration 的 49+ 模型,180+ configs 和 177+ checkpoints。以下是此次版本发布的重点新功能 - 支持了 Restormer 算法. - 支持了 GLIDE 算法. - 支持了 SwinIR 算法. - 支持了 Stable Diffusion 算法. **新功能和改进** - 新增 Disco notebook. (#1507) - 优化测试 requirements 和 CI. (#1514) - 自动生成文档 summary 和 API docstring. (#1517) - 开启 projects. (#1526) - 支持 mscoco dataset. (#1520) - 改进中文文档. (#1532) - 添加 Type hints. (#1481) - 更新模型权重下载链接. (#1554) - 更新部署指南. (#1551) **Bug 修复** - 修复文档链接检查. (#1522) - 修复 ssim bug. (#1515) - 修复 realesrgan 的 `extract_gt_data`. (#1542) - 修复算法索引. (#1559) - F修复 disco-diffusion 的 config 路径. (#1553) - Fix text2image inferencer. (#1523) **贡献者** @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @liuwenran, @AlexZou14, @lvhan028, @xiaomile, @ldr426, @austin273, @whu-lee, @willaty, @curiosity654, @Zdafeng, @Taited ## v1.0.0rc4 (05/12/2022) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc4 版本。 此版本支持了 MMEditing 和 MMGeneration 的 45+ 模型,176+ configs 和 175+ checkpoints。以下是此次版本发布的重点新功能 - 支持了 High-level APIs. - 支持了 diffusion 算法. - 支持了 Text2Image 任务. - 支持了 3D-Aware Generation. **新功能和改进** - 支持和重构了 High-level APIs. (#1410) - 支持了 disco-diffusion 文生图算法. (#1234, #1504) - 支持了 EG3D 算法. (#1482, #1493, #1494, #1499) - 支持了 NAFNet 算法. (#1369) **Bug 修复** - 修复 srgan 的训练配置. (#1441) - 修复 cain 的 config. (#1404) - 修复 rdn 和 srcnn 的训练配置. (#1392) **贡献者** @plyfager, @LeoXing1996, @Z-Fran, @zengyh1900, @VongolaWu, @gaoyang07, @ChangjianZhao, @zxczrx123, @jackghosts, @liuwenran, @CCODING04, @RoseZhao929, @shaocongliu, @liangzelong. ## v1.0.0rc3 (10/11/2022) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc3 版本。 此版本支持了 MMEditing 和 MMGeneration 的 43+ 模型,170+ configs 和 169+ checkpoints。以下是此次版本发布的重点新功能 - 将 `mmdet` 和 `clip` 改为可选安装需求. **新功能和改进** - 支持 `mmdet` 的 `try_import`. (#1408) - 支持 `flip` 的 `try_import`. (#1420) - 更新 `.gitignore`. ($1416) - 设置 `inception_utils` 的 `real_feat` 为 cpu 变量. (#1415) - 更新 StyleGAN2 和 PEGAN 的 README 和 configs. (#1418) - 改进 API 文档的渲染. (#1373) **Bug 修复** - 修复 ESRGAN 的 config 和预训练模型加载. (#1407) - 修复 LSGAN 的 config. (#1409) - 修复 CAIN 的 config. (#1404) **贡献者** @Z-Fran, @zengyh1900, @plyfager, @LeoXing1996, @ruoningYu. ## v1.0.0rc2 (02/11/2022) **主要更新** 我们很高兴发布 MMEditing 1.0.0rc2 版本。 此版本支持了 MMEditing 和 MMGeneration 的 43+ 模型,170+ configs 和 169+ checkpoints。以下是此次版本发布的重点新功能 - 基于 patch 和 slider 的 图像和视频可视化质量比较工具. - 支持了图像上色算法. **新功能和改进** - 支持了质量比较工具. (#1303) - 支持了 instance aware colorization 上色算法. (#1370) - 支持使用不同采样模型的 multi-metrics. (#1171) - 改进代码实现 - 重构 evaluation metrics. (#1164) - 在 PGGAN 的 `forward` 中保存 gt 图像. (#1332) - 改进 `preprocess_div2k_dataset.py` 脚本的默认参数. (#1380) - 支持在 visualizer 中裁剪像素值. (#1365) - 支持了 SinGAN 数据集和 SinGAN demo. (#1363) - 支持 GenDataPreprocessor 中返回 int 和 float 数据类型. (#1385) - 改进文档 - 更新菜单切换. (#1162) - 修复 TTSR README. (#1325) **Bug 修复** - 修复 PPL bug. (#1172) - 修复 RDN `number of channels` 参数. (#1328) - 修复 demo 的 exceptions 类型. (#1372) - 修复 realesrgan ema. (#1341) - 改进 assertion 检查 `GenerateFacialHeatmap` 的数据类型为 `np.float32`. (#1310) - 修复 `unpaired_dataset.py` 的采样方式. (#1308) - 修复视频超分模型的 pytorch2onnx 脚本. (#1300) - 修复错误的 config 配置. (#1167,#1200,#1236,#1293,#1302,#1304,#1319,#1331,#1336,#1349,#1352,#1353,#1358,#1364,#1367,#1384,#1386,#1391,#1392,#1393) **贡献者** @LeoXing1996, @Z-Fran, @zengyh1900, @plyfager, @ryanxingql, @ruoningYu, @gaoyang07. ## v1.0.0rc1(23/9/2022) MMEditing 1.0.0rc1 已经合并了 MMGeneration 1.x。 - 支持 42+ 算法, 169+ 配置文件 and 168+ 预训练模型参数文件. - 支持 26+ loss functions, 20+ metrics. - 支持 tensorboard, wandb. - 支持 unconditional GANs, conditional GANs, image2image translation 以及 internal learning. ## v1.0.0rc0(31/8/2022) MMEditing 1.0.0rc0 是 MMEditing 1.x 的第一个版本,是 OpenMMLab 2.0 项目的一部分。 基于新的[训练引擎](https://github.com/open-mmlab/mmengine), MMEditing 1.x 统一了数据、模型、评测和可视化的接口。 该版本存在有一些 BC-breaking 的修改。 请在[迁移指南](https://mmagic.readthedocs.io/zh_CN/latest/migration/overview.html)中查看更多细节。 ================================================ FILE: docs/zh_cn/community/contributing.md ================================================ # 贡献代码 欢迎加入 MMagic 社区,我们致力于打造新一代人工智能内容生成(AIGC)工具箱,我们欢迎任何类型的贡献,包括但不限于 **修复错误** 修复代码实现错误的步骤如下: 1. 如果提交的代码改动较大,建议先提交 issue,并正确描述 issue 的现象、原因和复现方式,讨论后确认修复方案。 2. 修复错误并补充相应的单元测试,提交拉取请求。 **新增功能或组件** 1. 如果新功能或模块涉及较大的代码改动,建议先提交 issue,确认功能的必要性。 2. 实现新增功能并添单元测试,提交拉取请求。 **文档补充** 修复文档可以直接提交拉取请求 添加文档或将文档翻译成其他语言步骤如下 1. 提交 issue,确认添加文档的必要性。 2. 添加文档,提交拉取请求。 ### 拉取请求工作流 如果你对拉取请求不了解,没关系,接下来的内容将会从零开始,一步一步地指引你如何创建一个拉取请求。如果你想深入了解拉取请求的开发模式,可以参考 github [官方文档](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) #### 1. 复刻仓库 当你第一次提交拉取请求时,先复刻 OpenMMLab 原代码库,点击 GitHub 页面右上角的 **Fork** 按钮,复刻后的代码库将会出现在你的 GitHub 个人主页下。 将代码克隆到本地 ```shell git clone git@github.com:{username}/mmagic.git ``` 添加原代码库为上游代码库 ```bash git remote add upstream git@github.com:open-mmlab/mmagic ``` 检查 remote 是否添加成功,在终端输入 `git remote -v` ```bash origin git@github.com:{username}/mmagic.git (fetch) origin git@github.com:{username}/mmagic.git (push) upstream git@github.com:open-mmlab/mmagic (fetch) upstream git@github.com:open-mmlab/mmagic (push) ``` ```{note} 这里对 origin 和 upstream 进行一个简单的介绍,当我们使用 git clone 来克隆代码时,会默认创建一个 origin 的 remote,它指向我们克隆的代码库地址,而 upstream 则是我们自己添加的,用来指向原始代码库地址。当然如果你不喜欢他叫 upstream,也可以自己修改,比如叫 open-mmlab。我们通常向 origin 提交代码(即 fork 下来的远程仓库),然后向 upstream 提交一个 pull request。如果提交的代码和最新的代码发生冲突,再从 upstream 拉取最新的代码,和本地分支解决冲突,再提交到 origin。 ``` #### 2. 配置 pre-commit 在本地开发环境中,我们使用 [pre-commit](https://pre-commit.com/#intro) 来检查代码风格,以确保代码风格的统一。在提交代码,需要先安装 pre-commit(需要在 mmagic 目录下执行): ```shell pip install -U pre-commit pre-commit install ``` 检查 pre-commit 是否配置成功,并安装 `.pre-commit-config.yaml` 中的钩子: ```shell pre-commit run --all-files ``` ```{note} 如果你是中国用户,由于网络原因,可能会出现安装失败的情况,这时可以使用国内源 pre-commit install -c .pre-commit-config-zh-cn.yaml pre-commit run --all-files -c .pre-commit-config-zh-cn.yaml ``` 如果安装过程被中断,可以重复执行 `pre-commit run ...` 继续安装。 如果提交的代码不符合代码风格规范,pre-commit 会发出警告,并自动修复部分错误。 如果我们想临时绕开 pre-commit 的检查提交一次代码,可以在 `git commit` 时加上 `--no-verify`(需要保证最后推送至远程仓库的代码能够通过 pre-commit 检查)。 ```shell git commit -m "xxx" --no-verify ``` #### 3. 创建开发分支 安装完 pre-commit 之后,我们需要基于 main 创建开发分支,建议的分支命名规则为 `username/pr_name`。 ```shell git checkout -b yhc/refactor_contributing_doc ``` 在后续的开发中,如果本地仓库的 main 分支落后于 upstream 的 main 分支,我们需要先拉取 upstream 的代码进行同步,再执行上面的命令 ```shell git pull upstream main ``` #### 4. 提交代码并在本地通过单元测试 - mmagic 引入了 mypy 来做静态类型检查,以增加代码的鲁棒性。因此我们在提交代码时,需要补充 Type Hints。具体规则可以参考[教程](https://zhuanlan.zhihu.com/p/519335398)。 - 提交的代码同样需要通过单元测试 ```shell # 通过全量单元测试 pytest tests # 我们需要保证提交的代码能够通过修改模块的单元测试,以 runner 为例 pytest tests/test_runner/test_runner.py ``` 如果你由于缺少依赖无法运行修改模块的单元测试,可以参考[指引-单元测试](#单元测试) - 如果修改/添加了文档,参考[指引](#文档渲染)确认文档渲染正常。 #### 5. 推送代码到远程 代码通过单元测试和 pre-commit 检查后,将代码推送到远程仓库,如果是第一次推送,可以在 `git push` 后加上 `-u` 参数以关联远程分支 ```shell git push -u origin {branch_name} ``` 这样下次就可以直接使用 `git push` 命令推送代码了,而无需指定分支和远程仓库。 #### 6. 提交拉取请求(PR) (1) 在 GitHub 的 Pull request 界面创建拉取请求 (2) 根据指引修改 PR 描述,以便于其他开发者更好地理解你的修改 描述规范详见[拉取请求规范](#拉取请求规范)   **注意事项** (a) PR 描述应该包含修改理由、修改内容以及修改后带来的影响,并关联相关 Issue(具体方式见[文档](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)) (b) 如果是第一次为 OpenMMLab 做贡献,需要签署 CLA (c) 检查提交的 PR 是否通过 CI(集成测试) mmagic 会在不同的平台(Linux、Window、Mac),基于不同版本的 Python、PyTorch、CUDA 对提交的代码进行单元测试,以保证代码的正确性,如果有任何一个没有通过,我们可点击上图中的 `Details` 来查看具体的测试信息,以便于我们修改代码。 (3) 如果 PR 通过了 CI,那么就可以等待其他开发者的 review,并根据 reviewer 的意见,修改代码,并重复 [4](#4-提交代码并本地通过单元测试)-[5](#5-推送代码到远程) 步骤,直到 reviewer 同意合入 PR。 所有 reviewer 同意合入 PR 后,我们会尽快将 PR 合并到主分支。 #### 7. 解决冲突 随着时间的推移,我们的代码库会不断更新,这时候,如果你的 PR 与主分支存在冲突,你需要解决冲突,解决冲突的方式有两种: ```shell git fetch --all --prune git rebase upstream/main ``` 或者 ```shell git fetch --all --prune git merge upstream/main ``` 如果你非常善于处理冲突,那么可以使用 rebase 的方式来解决冲突,因为这能够保证你的 commit log 的整洁。如果你不太熟悉 `rebase` 的使用,那么可以使用 `merge` 的方式来解决冲突。 ### 指引 #### 单元测试 在提交修复代码错误或新增特性的拉取请求时,我们应该尽可能的让单元测试覆盖所有提交的代码,计算单元测试覆盖率的方法如下 ```shell python -m coverage run -m pytest /path/to/test_file python -m coverage html # check file in htmlcov/index.html ``` #### 文档渲染 在提交修复代码错误或新增特性的拉取请求时,可能会需要修改/新增模块的 docstring。我们需要确认渲染后的文档样式是正确的。 本地生成渲染后的文档的方法如下 ```shell pip install -r requirements/docs.txt cd docs/zh_cn/ # or docs/en make html # check file in ./docs/zh_cn/_build/html/index.html ``` ### 代码风格 #### Python [PEP8](https://www.python.org/dev/peps/pep-0008/) 作为 OpenMMLab 算法库首选的代码规范,我们使用以下工具检查和格式化代码 - [flake8](https://github.com/PyCQA/flake8): Python 官方发布的代码规范检查工具,是多个检查工具的封装 - [isort](https://github.com/timothycrosley/isort): 自动调整模块导入顺序的工具 - [yapf](https://github.com/google/yapf): Google 发布的代码规范检查工具 - [codespell](https://github.com/codespell-project/codespell): 检查单词拼写是否有误 - [mdformat](https://github.com/executablebooks/mdformat): 检查 markdown 文件的工具 - [docformatter](https://github.com/myint/docformatter): 格式化 docstring 的工具 yapf 和 isort 的配置可以在 [setup.cfg](../../../setup.cfg) 找到 通过配置 [pre-commit hook](https://pre-commit.com/) ,我们可以在提交代码时自动检查和格式化 `flake8`、`yapf`、`isort`、`trailing whitespaces`、`markdown files`,修复 `end-of-files`、`double-quoted-strings`、`python-encoding-pragma`、`mixed-line-ending`,调整 `requirments.txt` 的包顺序。 pre-commit 钩子的配置可以在 [.pre-commit-config](../../../.pre-commit-config.yaml) 找到。 pre-commit 具体的安装使用方式见[拉取请求](#2-配置-pre-commit)。 更具体的规范请参考 [OpenMMLab 代码规范](contributing.md#代码风格)。 #### C++ and CUDA C++ 和 CUDA 的代码规范遵从 [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) ### 拉取请求规范 1. 使用 [pre-commit hook](https://pre-commit.com),尽量减少代码风格相关问题 2. 一个`拉取请求`对应一个短期分支 3. 粒度要细,一个`拉取请求`只做一件事情,避免超大的`拉取请求` - Bad:实现 Faster R-CNN - Acceptable:给 Faster R-CNN 添加一个 box head - Good:给 box head 增加一个参数来支持自定义的 conv 层数 4. 每次 Commit 时需要提供清晰且有意义 commit 信息 5. 提供清晰且有意义的`拉取请求`描述 - 标题写明白任务名称,一般格式:\[Prefix\] Short description of the pull request (Suffix) - prefix: 新增功能 \[Feature\], 修 bug \[Fix\], 文档相关 \[Docs\], 开发中 \[WIP\] (暂时不会被review) - 描述里介绍`拉取请求`的主要修改内容,结果,以及对其他部分的影响, 参考`拉取请求`模板 - 关联相关的`议题` (issue) 和其他`拉取请求` 6. 如果引入了其他三方库,或借鉴了三方库的代码,请确认他们的许可证和 mmagic 兼容,并在借鉴的代码上补充 `This code is inspired from http://` ## 代码规范 ### 代码规范标准 #### PEP 8 —— Python 官方代码规范 [Python 官方的代码风格指南](https://www.python.org/dev/peps/pep-0008/),包含了以下几个方面的内容: - 代码布局,介绍了 Python 中空行、断行以及导入相关的代码风格规范。比如一个常见的问题:当我的代码较长,无法在一行写下时,何处可以断行? - 表达式,介绍了 Python 中表达式空格相关的一些风格规范。 - 尾随逗号相关的规范。当列表较长,无法一行写下而写成如下逐行列表时,推荐在末项后加逗号,从而便于追加选项、版本控制等。 ```python # Correct: FILES = ['setup.cfg', 'tox.ini'] # Correct: FILES = [ 'setup.cfg', 'tox.ini', ] # Wrong: FILES = ['setup.cfg', 'tox.ini',] # Wrong: FILES = [ 'setup.cfg', 'tox.ini' ] ``` - 命名相关规范、注释相关规范、类型注解相关规范,我们将在后续章节中做详细介绍。 "A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important." PEP 8 -- Style Guide for Python Code :::{note} PEP 8 的代码规范并不是绝对的,项目内的一致性要优先于 PEP 8 的规范。OpenMMLab 各个项目都在 setup.cfg 设定了一些代码规范的设置,请遵照这些设置。一个例子是在 PEP 8 中有如下一个例子: ```python # Correct: hypot2 = x*x + y*y # Wrong: hypot2 = x * x + y * y ``` 这一规范是为了指示不同优先级,但 OpenMMLab 的设置中通常没有启用 yapf 的 `ARITHMETIC_PRECEDENCE_INDICATION` 选项,因而格式规范工具不会按照推荐样式格式化,以设置为准。 ::: #### Google 开源项目风格指南 [Google 使用的编程风格指南](https://google.github.io/styleguide/pyguide.html),包括了 Python 相关的章节。相较于 PEP 8,该指南提供了更为详尽的代码指南。该指南包括了语言规范和风格规范两个部分。 其中,语言规范对 Python 中很多语言特性进行了优缺点的分析,并给出了使用指导意见,如异常、Lambda 表达式、列表推导式、metaclass 等。 风格规范的内容与 PEP 8 较为接近,大部分约定建立在 PEP 8 的基础上,也有一些更为详细的约定,如函数长度、TODO 注释、文件与 socket 对象的访问等。 推荐将该指南作为参考进行开发,但不必严格遵照,一来该指南存在一些 Python 2 兼容需求,例如指南中要求所有无基类的类应当显式地继承 Object, 而在仅使用 Python 3 的环境中,这一要求是不必要的,依本项目中的惯例即可。二来 OpenMMLab 的项目作为框架级的开源软件,不必对一些高级技巧过于避讳,尤其是 MMCV。但尝试使用这些技巧前应当认真考虑是否真的有必要,并寻求其他开发人员的广泛评估。 另外需要注意的一处规范是关于包的导入,在该指南中,要求导入本地包时必须使用路径全称,且导入的每一个模块都应当单独成行,通常这是不必要的,而且也不符合目前项目的开发惯例,此处进行如下约定: ```python # Correct from mmagic.cnn.bricks import (Conv2d, build_norm_layer, DropPath, MaxPool2d, Linear) from ..utils import ext_loader # Wrong from mmagic.cnn.bricks import Conv2d, build_norm_layer, DropPath, MaxPool2d, \ Linear # 使用括号进行连接,而不是反斜杠 from ...utils import is_str # 最多向上回溯一层,过多的回溯容易导致结构混乱 ``` OpenMMLab 项目使用 pre-commit 工具自动格式化代码,详情见[贡献代码](contributing.md#代码风格)。 ### 命名规范 #### 命名规范的重要性 优秀的命名是良好代码可读的基础。基础的命名规范对各类变量的命名做了要求,使读者可以方便地根据代码名了解变量是一个类 / 局部变量 / 全局变量等。而优秀的命名则需要代码作者对于变量的功能有清晰的认识,以及良好的表达能力,从而使读者根据名称就能了解其含义,甚至帮助了解该段代码的功能。 #### 基础命名规范 | 类型 | 公有 | 私有 | | --------------- | ---------------- | ------------------ | | 模块 | lower_with_under | \_lower_with_under | | 包 | lower_with_under | | | 类 | CapWords | \_CapWords | | 异常 | CapWordsError | | | 函数(方法) | lower_with_under | \_lower_with_under | | 函数 / 方法参数 | lower_with_under | | | 全局 / 类内常量 | CAPS_WITH_UNDER | \_CAPS_WITH_UNDER | | 全局 / 类内变量 | lower_with_under | \_lower_with_under | | 变量 | lower_with_under | \_lower_with_under | | 局部变量 | lower_with_under | | 注意: - 尽量避免变量名与保留字冲突,特殊情况下如不可避免,可使用一个后置下划线,如 class\_ - 尽量不要使用过于简单的命名,除了约定俗成的循环变量 i,文件变量 f,错误变量 e 等。 - 不会被用到的变量可以命名为 \_,逻辑检查器会将其忽略。 #### 命名技巧 良好的变量命名需要保证三点: 1. 含义准确,没有歧义 2. 长短适中 3. 前后统一 ```python # Wrong class Masks(metaclass=ABCMeta): # 命名无法表现基类;Instance or Semantic? pass # Correct class BaseInstanceMasks(metaclass=ABCMeta): pass # Wrong,不同地方含义相同的变量尽量用统一的命名 def __init__(self, inplanes, planes): pass def __init__(self, in_channels, out_channels): pass ``` 常见的函数命名方法: - 动宾命名法:crop_img, init_weights - 动宾倒置命名法:imread, bbox_flip 注意函数命名与参数的顺序,保证主语在前,符合语言习惯: - check_keys_exist(key, container) - check_keys_contain(container, key) 注意避免非常规或统一约定的缩写,如 nb -> num_blocks,in_nc -> in_channels ### docstring 规范 #### 为什么要写 docstring docstring 是对一个类、一个函数功能与 API 接口的详细描述,有两个功能,一是帮助其他开发者了解代码功能,方便 debug 和复用代码;二是在 Readthedocs 文档中自动生成相关的 API reference 文档,帮助不了解源代码的社区用户使用相关功能。 #### 如何写 docstring 与注释不同,一份规范的 docstring 有着严格的格式要求,以便于 Python 解释器以及 sphinx 进行文档解析,详细的 docstring 约定参见 [PEP 257](https://www.python.org/dev/peps/pep-0257/)。此处以例子的形式介绍各种文档的标准格式,参考格式为 [Google 风格](https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/#comments)。 1. 模块文档 代码风格规范推荐为每一个模块(即 Python 文件)编写一个 docstring,但目前 OpenMMLab 项目大部分没有此类 docstring,因此不做硬性要求。 ```python """A one line summary of the module or program, terminated by a period. Leave one blank line. The rest of this docstring should contain an overall description of the module or program. Optionally, it may also contain a brief description of exported classes and functions and/or usage examples. Typical usage example: foo = ClassFoo() bar = foo.FunctionBar() """ ``` 2. 类文档 类文档是我们最常需要编写的,此处,按照 OpenMMLab 的惯例,我们使用了与 Google 风格不同的写法。如下例所示,文档中没有使用 Attributes 描述类属性,而是使用 Args 描述 __init__ 函数的参数。 在 Args 中,遵照 `parameter (type): Description.` 的格式,描述每一个参数类型和功能。其中,多种类型可使用 `(float or str)` 的写法,可以为 None 的参数可以写为 `(int, optional)`。 ```python class BaseRunner(metaclass=ABCMeta): """The base class of Runner, a training helper for PyTorch. All subclasses should implement the following APIs: - ``run()`` - ``train()`` - ``val()`` - ``save_checkpoint()`` Args: model (:obj:`torch.nn.Module`): The model to be run. batch_processor (callable, optional): A callable method that process a data batch. The interface of this method should be ``batch_processor(model, data, train_mode) -> dict``. Defaults to None. optimizer (dict or :obj:`torch.optim.Optimizer`, optional): It can be either an optimizer (in most cases) or a dict of optimizers (in models that requires more than one optimizer, e.g., GAN). Defaults to None. work_dir (str, optional): The working directory to save checkpoints and logs. Defaults to None. logger (:obj:`logging.Logger`): Logger used during training. Defaults to None. (The default value is just for backward compatibility) meta (dict, optional): A dict records some import information such as environment info and seed, which will be logged in logger hook. Defaults to None. max_epochs (int, optional): Total training epochs. Defaults to None. max_iters (int, optional): Total training iterations. Defaults to None. """ def __init__(self, model, batch_processor=None, optimizer=None, work_dir=None, logger=None, meta=None, max_iters=None, max_epochs=None): ... ``` 另外,在一些算法实现的主体类中,建议加入原论文的链接;如果参考了其他开源代码的实现,则应加入 modified from,而如果是直接复制了其他代码库的实现,则应加入 copied from ,并注意源码的 License。如有必要,也可以通过 .. math:: 来加入数学公式 ```python # 参考实现 # This func is modified from `detectron2 # `_. # 复制代码 # This code was copied from the `ubelt # library`_. # 引用论文 & 添加公式 class LabelSmoothLoss(nn.Module): r"""Initializer for the label smoothed cross entropy loss. Refers to `Rethinking the Inception Architecture for Computer Vision `_. This decreases gap between output scores and encourages generalization. Labels provided to forward can be one-hot like vectors (NxC) or class indices (Nx1). And this accepts linear combination of one-hot like labels from mixup or cutmix except multi-label task. Args: label_smooth_val (float): The degree of label smoothing. num_classes (int, optional): Number of classes. Defaults to None. mode (str): Refers to notes, Options are "original", "classy_vision", "multi_label". Defaults to "classy_vision". reduction (str): The method used to reduce the loss. Options are "none", "mean" and "sum". Defaults to 'mean'. loss_weight (float): Weight of the loss. Defaults to 1.0. Note: if the ``mode`` is "original", this will use the same label smooth method as the original paper as: .. math:: (1-\epsilon)\delta_{k, y} + \frac{\epsilon}{K} where :math:`\epsilon` is the ``label_smooth_val``, :math:`K` is the ``num_classes`` and :math:`\delta_{k,y}` is Dirac delta, which equals 1 for k=y and 0 otherwise. if the ``mode`` is "classy_vision", this will use the same label smooth method as the `facebookresearch/ClassyVision `_ repo as: .. math:: \frac{\delta_{k, y} + \epsilon/K}{1+\epsilon} if the ``mode`` is "multi_label", this will accept labels from multi-label task and smoothing them as: .. math:: (1-2\epsilon)\delta_{k, y} + \epsilon ``` ```{note} 注意 \`\`here\`\`、\`here\`、"here" 三种引号功能是不同。 在 reStructured 语法中,\`\`here\`\` 表示一段代码;\`here\` 表示斜体;"here" 无特殊含义,一般可用来表示字符串。其中 \`here\` 的用法与 Markdown 中不同,需要多加留意。 另外还有 :obj:\`type\` 这种更规范的表示类的写法,但鉴于长度,不做特别要求,一般仅用于表示非常用类型。 ``` 3. 方法(函数)文档 函数文档与类文档的结构基本一致,但需要加入返回值文档。对于较为复杂的函数和类,可以使用 Examples 字段加入示例;如果需要对参数加入一些较长的备注,可以加入 Note 字段进行说明。 对于使用较为复杂的类或函数,比起看大段大段的说明文字和参数文档,添加合适的示例更能帮助用户迅速了解其用法。需要注意的是,这些示例最好是能够直接在 Python 交互式环境中运行的,并给出一些相对应的结果。如果存在多个示例,可以使用注释简单说明每段示例,也能起到分隔作用。 ```python def import_modules_from_strings(imports, allow_failed_imports=False): """Import modules from the given list of strings. Args: imports (list | str | None): The given module names to be imported. allow_failed_imports (bool): If True, the failed imports will return None. Otherwise, an ImportError is raise. Defaults to False. Returns: List[module] | module | None: The imported modules. All these three lines in docstring will be compiled into the same line in readthedocs. Examples: >>> osp, sys = import_modules_from_strings( ... ['os.path', 'sys']) >>> import os.path as osp_ >>> import sys as sys_ >>> assert osp == osp_ >>> assert sys == sys_ """ ... ``` 如果函数接口在某个版本发生了变化,需要在 docstring 中加入相关的说明,必要时添加 Note 或者 Warning 进行说明,例如: ```python class CheckpointHook(Hook): """Save checkpoints periodically. Args: out_dir (str, optional): The root directory to save checkpoints. If not specified, ``runner.work_dir`` will be used by default. If specified, the ``out_dir`` will be the concatenation of ``out_dir`` and the last level directory of ``runner.work_dir``. Defaults to None. `Changed in version 1.3.15.` file_client_args (dict, optional): Arguments to instantiate a FileClient. See :class:`mmagic.fileio.FileClient` for details. Defaults to None. `New in version 1.3.15.` Warning: Before v1.3.15, the ``out_dir`` argument indicates the path where the checkpoint is stored. However, in v1.3.15 and later, ``out_dir`` indicates the root directory and the final path to save checkpoint is the concatenation of out_dir and the last level directory of ``runner.work_dir``. Suppose the value of ``out_dir`` is "/path/of/A" and the value of ``runner.work_dir`` is "/path/of/B", then the final path will be "/path/of/A/B". ``` 如果参数或返回值里带有需要展开描述字段的 dict,则应该采用如下格式: ```python def func(x): r""" Args: x (None): A dict with 2 keys, ``padded_targets``, and ``targets``. - ``targets`` (list[Tensor]): A list of tensors. Each tensor has the shape of :math:`(T_i)`. Each element is the index of a character. - ``padded_targets`` (Tensor): A tensor of shape :math:`(N)`. Each item is the length of a word. Returns: dict: A dict with 2 keys, ``padded_targets``, and ``targets``. - ``targets`` (list[Tensor]): A list of tensors. Each tensor has the shape of :math:`(T_i)`. Each element is the index of a character. - ``padded_targets`` (Tensor): A tensor of shape :math:`(N)`. Each item is the length of a word. """ return x ``` ```{important} 为了生成 readthedocs 文档,文档的编写需要按照 ReStructrued 文档格式,否则会产生文档渲染错误,在提交 PR 前,最好生成并预览一下文档效果。 语法规范参考: - [reStructuredText Primer - Sphinx documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#) - [Example Google Style Python Docstrings ‒ napoleon 0.7 documentation](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html#example-google) ``` ### 注释规范 #### 为什么要写注释 对于一个开源项目,团队合作以及社区之间的合作是必不可少的,因而尤其要重视合理的注释。不写注释的代码,很有可能过几个月自己也难以理解,造成额外的阅读和修改成本。 #### 如何写注释 最需要写注释的是代码中那些技巧性的部分。如果你在下次代码审查的时候必须解释一下,那么你应该现在就给它写注释。对于复杂的操作,应该在其操作开始前写上若干行注释。对于不是一目了然的代码,应在其行尾添加注释。 —— Google 开源项目风格指南 ```python # We use a weighted dictionary search to find out where i is in # the array. We extrapolate position based on the largest num # in the array and the array size and then do binary search to # get the exact number. if i & (i-1) == 0: # True if i is 0 or a power of 2. ``` 为了提高可读性, 注释应该至少离开代码2个空格. 另一方面, 绝不要描述代码. 假设阅读代码的人比你更懂Python, 他只是不知道你的代码要做什么. —— Google 开源项目风格指南 ```python # Wrong: # Now go through the b array and make sure whenever i occurs # the next element is i+1 # Wrong: if i & (i-1) == 0: # True if i bitwise and i-1 is 0. ``` 在注释中,可以使用 Markdown 语法,因为开发人员通常熟悉 Markdown 语法,这样可以便于交流理解,如可使用单反引号表示代码和变量(注意不要和 docstring 中的 ReStructured 语法混淆) ```python # `_reversed_padding_repeated_twice` is the padding to be passed to # `F.pad` if needed (e.g., for non-zero padding types that are # implemented as two ops: padding + conv). `F.pad` accepts paddings in # reverse order than the dimension. self._reversed_padding_repeated_twice = _reverse_repeat_tuple(self.padding, 2) ``` #### 注释示例 1. 出自 `mmcv/utils/registry.py`,对于较为复杂的逻辑结构,通过注释,明确了优先级关系。 ```python # self.build_func will be set with the following priority: # 1. build_func # 2. parent.build_func # 3. build_from_cfg if build_func is None: if parent is not None: self.build_func = parent.build_func else: self.build_func = build_from_cfg else: self.build_func = build_func ``` 2. 出自 `mmcv/runner/checkpoint.py`,对于 bug 修复中的一些特殊处理,可以附带相关的 issue 链接,帮助其他人了解 bug 背景。 ```python def _save_ckpt(checkpoint, file): # The 1.6 release of PyTorch switched torch.save to use a new # zipfile-based file format. It will cause RuntimeError when a # checkpoint was saved in high version (PyTorch version>=1.6.0) but # loaded in low version (PyTorch version<1.6.0). More details at # https://github.com/open-mmlab/mmpose/issues/904 if digit_version(TORCH_VERSION) >= digit_version('1.6.0'): torch.save(checkpoint, file, _use_new_zipfile_serialization=False) else: torch.save(checkpoint, file) ``` ### 类型注解 #### 为什么要写类型注解 类型注解是对函数中变量的类型做限定或提示,为代码的安全性提供保障、增强代码的可读性、避免出现类型相关的错误。 Python 没有对类型做强制限制,类型注解只起到一个提示作用,通常你的 IDE 会解析这些类型注解,然后在你调用相关代码时对类型做提示。另外也有类型注解检查工具,这些工具会根据类型注解,对代码中可能出现的问题进行检查,减少 bug 的出现。 需要注意的是,通常我们不需要注释模块中的所有函数: 1. 公共的 API 需要注释 2. 在代码的安全性,清晰性和灵活性上进行权衡是否注释 3. 对于容易出现类型相关的错误的代码进行注释 4. 难以理解的代码请进行注释 5. 若代码中的类型已经稳定,可以进行注释. 对于一份成熟的代码,多数情况下,即使注释了所有的函数,也不会丧失太多的灵活性. #### 如何写类型注解 1. 函数 / 方法类型注解,通常不对 self 和 cls 注释。 ```python from typing import Optional, List, Tuple # 全部位于一行 def my_method(self, first_var: int) -> int: pass # 另起一行 def my_method( self, first_var: int, second_var: float) -> Tuple[MyLongType1, MyLongType1, MyLongType1]: pass # 单独成行(具体的应用场合与行宽有关,建议结合 yapf 自动化格式使用) def my_method( self, first_var: int, second_var: float ) -> Tuple[MyLongType1, MyLongType1, MyLongType1]: pass # 引用尚未被定义的类型 class MyClass: def __init__(self, stack: List["MyClass"]) -> None: pass ``` 注:类型注解中的类型可以是 Python 内置类型,也可以是自定义类,还可以使用 Python 提供的 wrapper 类对类型注解进行装饰,一些常见的注解如下: ```python # 数值类型 from numbers import Number # 可选类型,指参数可以为 None from typing import Optional def foo(var: Optional[int] = None): pass # 联合类型,指同时接受多种类型 from typing import Union def foo(var: Union[float, str]): pass from typing import Sequence # 序列类型 from typing import Iterable # 可迭代类型 from typing import Any # 任意类型 from typing import Callable # 可调用类型 from typing import List, Dict # 列表和字典的泛型类型 from typing import Tuple # 元组的特殊格式 # 虽然在 Python 3.9 中,list, tuple 和 dict 本身已支持泛型,但为了支持之前的版本 # 我们在进行类型注解时还是需要使用 List, Tuple, Dict 类型 # 另外,在对参数类型进行注解时,尽量使用 Sequence & Iterable & Mapping # List, Tuple, Dict 主要用于返回值类型注解 # 参见 https://docs.python.org/3/library/typing.html#typing.List ``` 2. 变量类型注解,一般用于难以直接推断其类型时 ```python # Recommend: 带类型注解的赋值 a: Foo = SomeUndecoratedFunction() a: List[int]: [1, 2, 3] # List 只支持单一类型泛型,可使用 Union b: Tuple[int, int] = (1, 2) # 长度固定为 2 c: Tuple[int, ...] = (1, 2, 3) # 变长 d: Dict[str, int] = {'a': 1, 'b': 2} # Not Recommend:行尾类型注释 # 虽然这种方式被写在了 Google 开源指南中,但这是一种为了支持 Python 2.7 版本 # 而补充的注释方式,鉴于我们只支持 Python 3, 为了风格统一,不推荐使用这种方式。 a = SomeUndecoratedFunction() # type: Foo a = [1, 2, 3] # type: List[int] b = (1, 2, 3) # type: Tuple[int, ...] c = (1, "2", 3.5) # type: Tuple[int, Text, float] ``` 3. 泛型 上文中我们知道,typing 中提供了 list 和 dict 的泛型类型,那么我们自己是否可以定义类似的泛型呢? ```python from typing import TypeVar, Generic KT = TypeVar('KT') VT = TypeVar('VT') class Mapping(Generic[KT, VT]): def __init__(self, data: Dict[KT, VT]): self._data = data def __getitem__(self, key: KT) -> VT: return self._data[key] ``` 使用上述方法,我们定义了一个拥有泛型能力的映射类,实际用法如下: ```python mapping = Mapping[str, float]({'a': 0.5}) value: float = example['a'] ``` 另外,我们也可以利用 TypeVar 在函数签名中指定联动的多个类型: ```python from typing import TypeVar, List T = TypeVar('T') # Can be anything A = TypeVar('A', str, bytes) # Must be str or bytes def repeat(x: T, n: int) -> List[T]: """Return a list containing n references to x.""" return [x]*n def longest(x: A, y: A) -> A: """Return the longest of two strings.""" return x if len(x) >= len(y) else y ``` 更多关于类型注解的写法请参考 [typing](https://docs.python.org/3/library/typing.html)。 #### 类型注解检查工具 [mypy](https://mypy.readthedocs.io/en/stable/) 是一个 Python 静态类型检查工具。根据你的类型注解,mypy 会检查传参、赋值等操作是否符合类型注解,从而避免可能出现的 bug。 例如如下的一个 Python 脚本文件 test.py: ```python def foo(var: int) -> float: return float(var) a: str = foo('2.0') b: int = foo('3.0') # type: ignore ``` 运行 mypy test.py 可以得到如下检查结果,分别指出了第 4 行在函数调用和返回值赋值两处类型错误。而第 5 行同样存在两个类型错误,由于使用了 type: ignore 而被忽略了,只有部分特殊情况可能需要此类忽略。 ``` test.py:4: error: Incompatible types in assignment (expression has type "float", variable has type "int") test.py:4: error: Argument 1 to "foo" has incompatible type "str"; expected "int" Found 2 errors in 1 file (checked 1 source file) ``` ================================================ FILE: docs/zh_cn/community/projects.md ================================================ # 生态项目 欢迎来到 MMagic 社区! MMagic 社区由来自学术界和工业界的广大研究人员、机器学习和应用工程师编写的教程、库和项目组成。 该社区的目标是支持、加速和帮助您使用 MMagic 探索 AIGC,例如图像、视频、3D 内容生成、编辑和处理。 这里有一些基于 MMagic 的项目。 它们是如何将 MMagic 用作库的示例,以使您的项目更易于维护。请在[MMagic Ecosystem](https://openmmlab.com/ecosystem)中找到更多项目。 ## 在 OpenMMLab 社区上展示您的项目 您可以提交您的项目,以便它可以显示在[OpenMMLab](https://openmmlab.com/ecosystem)的主页上。 ## 添加示例项目到 MMagic 这是一个关于如何将项目添加到 MMagic 的[示例项目](../../../projects/example_project)。 您可以从 [example project](../../../projects/example_project) 复制并创建自己的项目。 我们还提供了下面列出的一些文档供您参考: - [贡献指南](https://mmagic.readthedocs.io/zh_CN/latest/community/contributing.html) 新贡献者指南,了解如何将您的项目添加到 MMagic。 - [新模型指南](https://mmagic.readthedocs.io/zh_CN/latest/howto/models.html) 添加新模型的文档。 - [讨论](https://github.com/open-mmlab/mmagic/discussions) 欢迎开始讨论! ## 库和工具箱的项目 - [PowerVQE](https://github.com/ryanxingql/powervqe):基于 PyTorch 和 MMagic 的压缩视频质量增强开放框架 - [VR-Baseline](https://github.com/linjing7/VR-Baseline):视频修复工具箱 - [Derain-Toolbox](https://github.com/biubiubiiu/derain-toolbox):单图像去雨工具箱和基准 ## 研究论文项目 - [Towards Interpretable Video Super-Resolution via Alternating Optimization, ECCV 2022](https://arxiv.org/abs/2207.10765)[\[github\]](https://github.com/caojiezhang/DAVSR) - [SepLUT:Separable Image-adaptive Lookup Tables for Real-time Image Enhancement, ECCV 2022](https://arxiv.org/abs/2207.08351)[\[github\]](https://github.com/ImCharlesY/SepLUT) - [TTVSR: Learning Trajectory-Aware Transformer for Video Super-Resolution, CVPR 2022](https://arxiv.org/abs/2204.04216)[\[github\]](https://github.com/researchmm/TTVSR) - [Arbitrary-Scale Image Synthesis, CVPR 2022](https://arxiv.org/pdf/2204.02273.pdf)[\[github\]](https://github.com/vglsd/ScaleParty) - [Investigating Tradeoffs in Real-World Video Super-Resolution(RealBasicVSR), CVPR 2022](https://arxiv.org/abs/2111.12704)[\[github\]](https://github.com/ckkelvinchan/RealBasicVSR) - [BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment, CVPR 2022](https://arxiv.org/abs/2104.13371)[\[github\]](https://github.com/ckkelvinchan/BasicVSR_PlusPlus) - [Multi-Scale Memory-Based Video Deblurring, CVPR 2022](https://arxiv.org/abs/2204.02977)[\[github\]](https://github.com/jibo27/MemDeblur) - [AdaInt:Learning Adaptive Intervals for 3D Lookup Tables on Real-time Image Enhancement, CVPR 2022](https://arxiv.org/abs/2204.13983)[\[github\]](https://github.com/ImCharlesY/AdaInt) - [A New Dataset and Transformer for Stereoscopic Video Super-Resolution, CVPRW 2022](https://openaccess.thecvf.com/content/CVPR2022W/NTIRE/papers/Imani_A_New_Dataset_and_Transformer_for_Stereoscopic_Video_Super-Resolution_CVPRW_2022_paper.pdf)[\[github\]](https://github.com/H-deep/Trans-SVSR) - [Liquid warping GAN with attention: A unified framework for human image synthesis, TPAMI 2021](https://arxiv.org/pdf/2011.09055.pdf)[\[github\]](https://github.com/iPERDance/iPERCore) - [BasicVSR:The Search for Essential Components in Video Super-Resolution and Beyond, CVPR 2021](https://arxiv.org/abs/2012.02181)[\[github\]](https://github.com/ckkelvinchan/BasicVSR-IconVSR) - [GLEAN:Generative Latent Bank for Large-Factor Image Super-Resolution, CVPR 2021](https://arxiv.org/abs/2012.00739)[\[github\]](https://github.com/ckkelvinchan/GLEAN) - [DAN:Unfolding the Alternating Optimization for Blind Super Resolution, NeurIPS 2020](https://arxiv.org/abs/2010.02631v4)[\[github\]](https://github.com/AlexZou14/DAN-Basd-on-Openmmlab) ================================================ FILE: docs/zh_cn/conf.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import subprocess import sys import pytorch_sphinx_theme sys.path.insert(0, os.path.abspath('../..')) # -- Project information ----------------------------------------------------- project = 'MMagic' copyright = '2023, MMagic Authors' author = 'MMagic Authors' # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', 'sphinx.ext.autosectionlabel', 'sphinx_markdown_tables', 'sphinx_copybutton', 'sphinx_tabs.tabs', 'myst_parser', ] extensions.append('notfound.extension') # enable customizing not-found page extensions.append('autoapi.extension') autoapi_type = 'python' autoapi_dirs = ['../../mmagic'] autoapi_add_toctree_entry = False autoapi_template_dir = '_templates' # autoapi_options = ['members', 'undoc-members', 'show-module-summary'] # # Core library for html generation from docstrings # extensions.append('sphinx.ext.autodoc') # extensions.append('sphinx.ext.autodoc.typehints') # # Enable 'expensive' imports for sphinx_autodoc_typehints # set_type_checking_flag = True # # Sphinx-native method. Not as good as sphinx_autodoc_typehints # autodoc_typehints = "description" # extensions.append('sphinx.ext.autosummary') # Create neat summary tables # autosummary_generate = True # Turn on sphinx.ext.autosummary # # Add __init__ doc (ie. params) to class summaries # autoclass_content = 'both' # autodoc_skip_member = [] # # If no docstring, inherit from base class # autodoc_inherit_docstrings = True autodoc_mock_imports = [ 'mmagic.version', 'mmcv._ext', 'mmcv.ops.ModulatedDeformConv2d', 'mmcv.ops.modulated_deform_conv2d', 'clip', 'resize_right', 'pandas' ] source_suffix = { '.rst': 'restructuredtext', '.md': 'markdown', } # Ignore >>> when copying code copybutton_prompt_text = r'>>> |\.\.\. ' copybutton_prompt_is_regexp = True # Add any paths that contain templates here, relative to this directory. templates_path = ['../en/_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # html_theme = 'sphinx_rtd_theme' html_theme = 'pytorch_sphinx_theme' html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()] html_theme_options = { # 'logo_url': 'https://mmocr.readthedocs.io/en/latest/', 'menu': [ { 'name': 'GitHub', 'url': 'https://github.com/open-mmlab/mmagic', }, { 'name': '版本', 'children': [ { 'name': 'MMagic 1.x', 'url': 'https://mmagic.readthedocs.io/zh_CN/latest/', 'description': 'Main 分支文档' }, { 'name': 'MMEditing 0.x', 'url': 'https://mmagic.readthedocs.io/zh_CN/0.x/', 'description': '0.x 分支文档' }, ], 'active': True, }, ], 'menu_lang': 'cn' } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_css_files = ['css/readthedocs.css'] myst_enable_extensions = ['colon_fence'] myst_heading_anchors = 3 language = 'zh_CN' # The master toctree document. root_doc = 'index' notfound_template = '404.html' def builder_inited_handler(app): subprocess.run(['python', './.dev_scripts/update_model_zoo.py']) subprocess.run(['python', './.dev_scripts/update_dataset_zoo.py']) def skip_member(app, what, name, obj, skip, options): if what == 'package' or what == 'module': skip = True return skip def setup(app): app.connect('builder-inited', builder_inited_handler) app.connect('autoapi-skip-member', skip_member) ================================================ FILE: docs/zh_cn/device/npu_zh.md ================================================ # NPU (华为昇腾) ## 使用方法 首先,请参考[MMCV](https://mmcv.readthedocs.io/zh_CN/latest/get_started/build.html#npu-mmcv-full) 安装带有 NPU 支持的 MMCV与 [mmengine](https://mmengine.readthedocs.io/en/latest/get_started/installation.html#build-from-source) 。 使用如下命令,可以利用 8 个 NPU 训练模型(以 edsr 为例): ```shell bash tools/dist_train.sh configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py 8 ``` 或者,使用如下命令,在一个 NPU 上训练模型(以 edsr 为例): ```shell python tools/train.py configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py ``` ## 经过验证的模型 | Model | Dataset | PSNR | SSIM | Download | | :----------------------------------------------------------------------------------------: | ------- | :---: | :--- | :--------------------------------------------------------------------------------------------- | | [edsr_x2c64b16_1x16_300k_div2k](https://github.com/open-mmlab/mmagic/blob/main/configs/edsr/edsr_x2c64b16_1xb16-300k_div2k.py) | DIV2K | 35.83 | 0.94 | [log](https://download.openmmlab.com/mmediting/device/npu/edsr/edsr_x2c64b16_1xb16-300k_div2k.log) | **注意:** - 如果没有特别标记,NPU 上的结果与使用 FP32 的 GPU 上的结果相同。 **以上所有模型权重及训练日志均由华为昇腾团队提供** ================================================ FILE: docs/zh_cn/faq.md ================================================ # 常见问题解答 我们在此列出了许多用户面临的一些常见问题及其相应的解决方案。如果您发现任何常见问题,并有办法帮助他人解决这些问题,请随时丰富列表内容。如果这里的内容没有涵盖您的问题,请使用[提供的模板](https://github.com/open-mmlab/mmagic/issues/new/choose)创建一个问题,并确保填写了模板中的所有必要信息。 ## 常见问题 **问题1:** “xxx: ‘yyy is not in the zzz registry’”. **回答1:** 只有导入模块文件时,才会触发注册表机制。所以你需要在某个地方导入该文件。 **问题2:** 某个数据集的文件夹结构是什么? **回答2:** 您可以根据[数据集准备](https://github.com/sijiua/mmagic/blob/dev-1.x/docs/en/user_guides/dataset_prepare.md)教程来确保文件夹结构的正确性。 **问题3:** 如何使用 LMDB 数据训练模型? **回答3:** 您可以使用工具/数据中的脚本制作 LMDB 文件。更多详情请参见[数据集准备](https://github.com/sijiua/mmagic/blob/dev-1.x/docs/en/user_guides/dataset_prepare.md)教程。 **问题4:** 为什么使用了 MMCV==xxx,但在导入 mmagic 时却出现了不兼容? **回答4:** 这是因为 MMCV 和 MMagic 的版本不兼容。兼容的 MMagic 和 MMCV 版本如下所示。请选择正确的 MMCV 版本以避免安装问题。 | MMagic版本 | MMCV 版本 | | :--------: | :--------------: | | master | mmcv-full>=2.0.0 | 注意:如果已安装 mmcv,则需要先运行 pip uninstall mmcv。如果同时安装了 mmcv 和 mmcv-full,则会出现模块未找到错误(ModuleNotFoundError)。 **问题5:** 如何忽略基本配置中的某些字段? **回答5:** 有些时候您可以设置 _delete_=True 来忽略基本配置中的某些字段。您可以参考 [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md#delete-key-in-dict) 的简单说明。 您可以仔细阅读[本教程](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md),以便更好地理解这一功能。 **问题6:** 如何在配置中使用中间变量? **回答6:** 有些中间变量会在配置文件中使用,比如数据集中的 train_pipeline/test_pipeline。值得注意的是,当修改子配置中的中间变量时,用户需要再次将中间变量传递到相应的字段中。 ================================================ FILE: docs/zh_cn/get_started/install.md ================================================ # 安装教程 在本节中,你将了解到: - [安装教程](#安装教程) - [安装](#安装) - [前提条件](#前提条件) - [最佳实践](#最佳实践) - [自定义安装](#自定义安装) - [CUDA版本](#cuda版本) - [不使用MIM安装MMCV](#不使用mim安装mmcv) - [在Docker中使用MMagic](#在docker中使用mmagic) - [问题解决](#问题解决) - [使用多个MMagic版本开发](#使用多个mmagic版本开发) ## 安装 我们建议用户按照我们的[最佳实践](#最佳实践)来安装MMagic。 然而,整个过程是高度可定制的。更多信息请参阅[自定义安装](#自定义安装)部分。 ### 前提条件 在本节中,我们将演示如何使用PyTorch准备环境。 MMagic可以在Linux, Windows, 和macOS上运行。它要求: - Python >= 3.7 - [PyTorch](https://pytorch.org/) >= 1.8 - [MMCV](https://github.com/open-mmlab/mmcv) >= 2.0.0 > 如果您对PyTorch有经验并且已经安装了它,直接跳过这一部分,跳到[下一节](#最佳实践)。否则, 您可以按照以下步骤来准备环境。 **Step 0.** 从[官方网站](https://docs.conda.io/en/latest/miniconda.html)下载和安装Miniconda. **Step 1.** 创建一个[conda虚拟环境](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html#)并激活它 ```shell conda create --name mmagic python=3.8 -y conda activate mmagic ``` **Step 2.** 按照[官方说明](https://pytorch.org/get-started/locally/)安装PyTorch,例如 - 在GPU平台上: ```shell conda install pytorch torchvision cudatoolkit=11.3 -c pytorch ``` - 在CPU平台上: ```shell conda install pytorch=1.10 torchvision cpuonly -c pytorch ``` ### 最佳实践 **Step 0.** 使用[MIM](https://github.com/open-mmlab/mim)安装[MMCV](https://github.com/open-mmlab/mmcv)。 ```shell pip install -U openmim mim install 'mmcv>=2.0.0' ``` **Step 1.** 安装[MMEngine](https://github.com/open-mmlab/mmengine)。 ```shell mim install 'mmengine' ``` 或者 ```shell pip install mmengine ``` 或者 ```shell pip install git+https://github.com/open-mmlab/mmengine.git ``` **Step 2.** 安装MMagic。 ```shell mim install 'mmagic' ``` 或者 ```shell pip install mmagic ``` 或者从源代码安装[MMagic](https://github.com/open-mmlab/mmagic)。 ```shell git clone https://github.com/open-mmlab/mmagic.git cd mmagic pip3 install -e . -v ``` **Step 5.** 检查MMagic是否安装成功。 ```shell cd ~ python -c "import mmagic; print(mmagic.__version__)" # 示例输出: 1.0.0 ``` 显示正确的版本号,则表示安装成功。 ```{note} 你可能想知道附加在`pip install`后面的`-e .`是什么意思。 下面是说明: - `-e`表示[可编辑模式](https://pip.pypa.io/en/latest/cli/pip_install/#cmdoption-e). 当`import mmagic`时,将导入克隆目录下的模块。 如果`pip install`没有附加`-e`, pip会将克隆的代码复制到类似`lib/python/site-package`的地方。 因此,除非再次执行`pip install`命令,否则在克隆目录下修改后的代码不会生效。 因此,`pip install`命令附带`-e`对于开发人员来说特别方便。如果修改了一些代码,下次导入新的代码时不需要重新安装。 - `.`表示此目录中的代码。 你也可以使用`pip install -e .[all]`命令,这将安装更多的依赖项,特别是对于预提交hooks和单元测试。 ``` ### 自定义安装 #### CUDA版本 安装PyTorch时,您需要指定CUDA的版本。如果您不清楚该选择哪一个,请遵循我们的建议: - 对于基于Ampere的NVIDIA GPUs,如GeForce 30系列和NVIDIA A100,必须使用CUDA 11。 - 对于较老的NVIDIA GPUs,是向后兼容的,但CUDA 10.2提供了更好的兼容性,更轻量。 请确保GPU驱动程序满足最低版本要求。 更多信息请参见[此表](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-major-component-versions__table-cuda-toolkit-driver-versions)。 **注意** 如果遵循我们的最佳实践,安装CUDA runtime库就足够了,因为不会在本地编译CUDA代码。 但是,如果您希望从源代码编译MMCV或开发其他CUDA算子,则需要从NVIDIA的[开发者网站](https://developer.nvidia.com/cuda-downloads)安装完整的CUDA工具包,其版本应与PyTorch的CUDA版本匹配。即,在 `conda install` 命令中指定的cudatoolkit版本。 #### 不使用MIM安装MMCV MMCV包含c++和CUDA扩展,因此以一种复杂的方式依赖于PyTorch。MIM自动解决了这种依赖关系,并使安装更容易。然而,这并不是必须的。 要使用pip而不是MIM安装MMCV,请遵循[MMCV安装指南](https://mmcv.readthedocs.io/en/latest/get_started/installation.html)。这需要根据PyTorch版本及其CUDA版本手动指定find-url。 例如,以下命令install mmcv-full是针对PyTorch 1.10.x和CUDA 11.3构建的。 ```shell pip install 'mmcv>=2.0.0' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html ``` #### 在Docker中使用MMagic 我们提供一个[Dockerfile](https://github.com/open-mmlab/mmagic/blob/main/docker/Dockerfile)来构建一个镜像。请确保您的[docker版本](https://docs.docker.com/engine/install/)>=19.03。 ```shell # 使用PyTorch 1.8, CUDA 11.1构建一个镜像 # 如果您喜欢其他版本,只需修改Dockerfile docker build -t mmagic docker/ ``` 使用如下命令运行 ```shell docker run --gpus all --shm-size=8g -it -v {DATA_DIR}:/mmagic/data mmagic ``` #### 问题解决 如果在安装过程中遇到问题,请先查看[FAQ](../faq.md)页面。如果找不到解决方案,可以在GitHub上[open an issue](https://github.com/open-mmlab/mmagic/issues/new/choose)。 ### 使用多个MMagic版本开发 训练和测试脚本已经修改了`PYTHONPATH`,以确保脚本使用当前目录中的`MMagic`。 要使用环境中安装的默认MMagic,而不是您正在使用的MMagic,可以删除这些脚本中的以下行 ```shell PYTHONPATH="$(dirname $0)/..":$PYTHONPATH ``` ================================================ FILE: docs/zh_cn/get_started/overview.md ================================================ # 概述 欢迎来到 MMagic! 在本节中,您将了解 - [MMagic是什么?](#mmagic-是什么) - [为什么要使用 MMagic?](#为什么要使用-mmagic) - [新手入门](#新手入门) - [基础教程](#基础教程) - [进阶教程](#进阶教程) ## MMagic 是什么? MMagic (**M**ultimodal **A**dvanced, **G**enerative, and **I**ntelligent **C**reation) 是一个供专业人工智能研究人员和机器学习工程师去处理、编辑和生成图像与视频的开源 AIGC 工具箱。 MMagic 允许研究人员和工程师使用最先进的预训练模型,并且可以轻松训练和开发新的定制模型。 MMagic 支持各种基础生成模型,包括: - 无条件生成对抗网络 (GANs) - 条件生成对抗网络 (GANs) - 内部学习 - 扩散模型 - 还有许多其他生成模型即将推出! MMagic 支持各种应用程序,包括: - 图文生成 - 图像翻译 - 3D 生成 - 图像超分辨率 - 视频超分辨率 - 视频插帧 - 图像补全 - 图像抠图 - 图像修复 - 图像上色 - 图像生成 - 还有许多其他应用程序即将推出!

## 为什么要使用 MMagic? - **SOTA 算法** MMagic 提供了处理、编辑、生成图像和视频的 SOTA 算法。 - **强有力且流行的应用** MMagic 支持了流行的图像修复、图文生成、3D生成、图像修补、抠图、超分辨率和生成等任务的应用。特别是 MMagic 支持了 Stable Diffusion 的微调和许多激动人心的 diffusion 应用,例如 ControlNet 动画生成。MMagic 也支持了 GANs 的插值,投影,编辑和其他流行的应用。请立即开始你的 AIGC 探索之旅! - **高效的框架** 通过 OpenMMLab 2.0 框架的 MMEngine 和 MMCV, MMagic 将编辑框架分解为不同的组件,并且可以通过组合不同的模块轻松地构建自定义的编辑器模型。我们可以像搭建“乐高”一样定义训练流程,提供丰富的组件和策略。在 MMagic 中,你可以使用不同的 APIs 完全控制训练流程。得益于 [MMSeparateDistributedDataParallel](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/wrappers/seperate_distributed.py), 动态模型结构的分布式训练可以轻松实现。 ## 新手入门 安装说明见[安装](install.md)。 ## 基础教程 对于初学者,我们建议从 [基础教程](../user_guides/config.md) 学习 MMagic 的基本用法。 ## 进阶教程 对于熟悉 MMagic 的用户,可能想了解 MMagic 的进阶实用,以及如何扩展算法库,如何使用多个算法库框架等高级用法,请参考[进阶教程](../advanced_guides/evaluator.md)。 ## 开发指南 想要使用 MMagic 进行深度开发的用户,可以参考[开发指南](../howto/models.md)。 ================================================ FILE: docs/zh_cn/get_started/quick_run.md ================================================ # 快速运行 成功安装MMagic后,现在您可以玩转MMagic了!如果您要从文本生成图像,只需要MMagic的几行代码! ```python from mmagic.apis import MMagicInferencer sd_inferencer = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = 'output/sd_res.png' sd_inferencer.infer(text=text_prompts, result_out_dir=result_out_dir) ``` 或者您可以运行以下命令。 ```bash python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir ./output/sd_res.png ``` 您将在文件夹`output/`中看到一个新图像`sd_res.png`,其中包含生成的样本。 更重要的是,如果您想让这些照片更清晰,MMagic的超分辨率只需要几行代码! ```python from mmagic.apis import MMagicInferencer config = 'configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py' checkpoint = 'https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_x4c64b23g32_1x16_400k_div2k_20200508-f8ccaf3b.pth' img_path = 'tests/data/image/lq/baboon_x4.png' editor = MMagicInferencer('esrgan', model_config=config, model_ckpt=checkpoint) output = editor.infer(img=img_path,result_out_dir='output.png') ``` 现在,您可以在 `output.png` 中查看您想要的图片。 ================================================ FILE: docs/zh_cn/howto/dataset.md ================================================ # 如何自定义数据集 本文档将介绍 MMagic 中每一个数据集的设计方式,以及用户如何设计自定义数据集。 - [如何自定义数据集](#如何自定义数据集) - [支持的数据集格式](#支持的数据集格式) - [BasicImageDataset](#basicimagedataset) - [BasicFramesDataset](#basicframesdataset) - [BasicConditonalDataset](#basicconditonaldataset) - [1. 逐行读取的标注文件格式(例如 txt 文件)](#1-逐行读取的标注文件格式例如-txt-文件) - [2. 基于字典的标注文件格式(例如 json)](#2-基于字典的标注文件格式例如-json) - [3. 基于文件夹的标注格式(无需标注文件)](#3-基于文件夹的标注格式无需标注文件) - [ImageNet 和 CIFAR10 数据集](#imagenet-和-cifar10-数据集) - [AdobeComp1kDataset](#adobecomp1kdataset) - [GrowScaleImgDataset](#growscaleimgdataset) - [SinGANDataset](#singandataset) - [PairedImageDataset](#pairedimagedataset) - [UnpairedImageDataset](#unpairedimagedataset) - [实现一个新的数据集](#实现一个新的数据集) - [重复数据集](#重复数据集) ## 支持的数据集格式 在 MMagic 中,所有的数据集都是从 `BaseDataset` 类继承而来的。 每个数据集都通过 `load_data_list` 方法来加载数据信息列表(例如数据所在的路径)。 在 `__getitem__` 方法中,调用 `prepare_data` 来获取前处理后的数据。 在 `prepare_data` 方法中,数据加载流程包括如下步骤: 1. 通过传入的索引来获取数据信息,由 `get_data_info` 方法实现。 2. 对数据应用数据转换,由 `pipeline` 方法实现。 ### BasicImageDataset **BasicImageDataset** `mmagic.datasets.BasicImageDataset` 是一个通用图片数据集,是为了底层视觉任务而设计的,比如图像超分辨率,图像修复和无条件图像生成。可以选择是否使用标注文件。 如使用标注文件,标注的格式可以如下所示: ```bash Case 1 (CelebA-HQ): 000001.png 000002.png Case 2 (DIV2K): 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) 0001_s003.png (480,480,3) 0002_s001.png (480,480,3) 0002_s002.png (480,480,3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) ``` 下面我们给出几个如何使用 `BasicImageDataset` 的示例。假定文件结构如下: ```md mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ │ ├── image.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ │ │ ├── image_x4.png │ │ ├── DIV2K_valid_HR │ │ ├── DIV2K_valid_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ ├── places │ │ ├── test_set │ │ ├── train_set | | ├── meta | | | ├── Places365_train.txt | | | ├── Places365_val.txt | ├── celebahq │ │ ├── imgs_1024 ``` 按照以上的文件结构给出 3 个示例。 示例 1: 加载 `DIV2K` 数据集来训练一个 `SISR` 模型。 ```python dataset = BasicImageDataset( ann_file='', metainfo=dict( dataset_type='div2k', task_name='sisr'), data_root='data/DIV2K', data_prefix=dict( gt='DIV2K_train_HR', img='DIV2K_train_LR_bicubic/X4'), filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=[]) ``` 示例 2: 加载 `places` 数据集来训练一个 `inpainting` 模型. ```python dataset = BasicImageDataset( ann_file='meta/Places365_train.txt', metainfo=dict( dataset_type='places365', task_name='inpainting'), data_root='data/places', data_prefix=dict(gt='train_set'), pipeline=[]) ``` 示例 3: 加载 `CelebA-HQ` 数据集来训练一个 `PGGAN` 模型. ```python dataset = BasicImageDataset( pipeline=[], data_root='./data/celebahq/imgs_1024') ``` ### BasicFramesDataset **BasicFramesDataset** `mmagic.datasets.BasicFramesDataset` 也是一个通用图片数据集,为视频帧的底层视觉任务而设计的,比如视频的超分辨率和视频帧插值。 可以选择是否使用标注文件。 如使用标注文件, 标注的格式示例所示: ```bash Case 1 (Vid4): calendar 41 city 34 foliage 49 walk 47 Case 2 (REDS): 000/00000000.png (720, 1280, 3) 000/00000001.png (720, 1280, 3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) ``` 假定文件结构如下: ```bash mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── Vid4 │ │ ├── BIx4 │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── GT │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── meta_info_Vid4_GT.txt │ ├── vimeo-triplet │ │ ├── sequences | | | ├── 00001 │ │ │ │ ├── 0389 │ │ │ │ │ ├── img1.png │ │ │ │ │ ├── img2.png │ │ │ │ │ ├── img3.png │ │ ├── tri_trainlist.txt ``` 按照以上的文件结构给出两个示例。 示例 1: 加载 `Vid4` 数据集来训练一个 `VSR` 模型. ```python dataset = BasicFramesDataset( ann_file='meta_info_Vid4_GT.txt', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root='data/Vid4', data_prefix=dict(img='BIx4', gt='GT'), pipeline=[], depth=2, num_input_frames=5) ``` 示例 2: 加载 `Vimeo90k` 数据集来训练一个 `VFI` 模型. ```python dataset = BasicFramesDataset( ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root='data/vimeo-triplet', data_prefix=dict(img='sequences', gt='sequences'), pipeline=[], depth=2, load_frames_list=dict( img=['img1.png', 'img3.png'], gt=['img2.png'])) ``` ### BasicConditonalDataset **BasicConditonalDataset** `mmagic.datasets.BasicConditonalDataset` 是为条件生成对抗网络而设计的(例如 `SAGAN`、`BigGAN`)。该数据集支持为标注文件加载标签。 `BasicConditonalDataset` 支持如下 3 种标注格式。 #### 1. 逐行读取的标注文件格式(例如 txt 文件) 样本文件结构: ``` data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... ``` 样本标注文件格式(第一列是图像的路径,第二列是类别的索引) ``` folder_1/xxx.png 0 folder_1/xxy.png 1 folder_2/123.png 5 folder_2/nsdf3.png 3 ... ``` `ImageNet` 数据集的配置示例: ```python dataset=dict( type='BasicConditionalDataset, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), ``` #### 2. 基于字典的标注文件格式(例如 json) 样本文件结构: ``` data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... ``` 样本标注文件格式(键为图像的路径,值为标签)。 ``` { "folder_1/xxx.png": [1, 2, 3, 4], "folder_1/xxy.png": [2, 4, 1, 0], "folder_2/123.png": [0, 9, 8, 1], "folder_2/nsdf3.png", [1, 0, 0, 2], ... } ``` `EG3D (shapenet-car) ` 数据集的配置示例: ```python dataset = dict( type='BasicConditionalDataset', data_root='./data/eg3d/shapenet-car', ann_file='annotation.json', pipeline=train_pipeline) ``` 在这种类型的注释中,标签可以是任何类型,不仅限于索引。 #### 3. 基于文件夹的标注格式(无需标注文件) 样本文件结构: ``` data_prefix/ ├── class_x │ ├── xxx.png │ ├── xxy.png │ └── ... │ └── xxz.png └── class_y ├── 123.png ├── nsdf3.png ├── ... └── asd932_.png ``` 如果在配置的 `ann_file` 中指定了标注文件,则将使用上面的前两种方式生成数据集,否则将尝试使用第三种方式。 ### ImageNet 和 CIFAR10 数据集 **ImageNet 数据集** `mmagic.datasets.ImageNet` 和 **CIFAR10 数据集**`mmagic.datasets.CIFAR10` 是为 `ImageNet` 和 `CIFAR10` 这两个数据集而设计的。 这两个数据集都是基于 `BasicConditionalDataset` 封装的。您可以使用它们来轻松加载这两个数据集的数据。 `ImageNet` 的配置示例: ```python pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='RandomCropLongEdge', keys=['img']), dict(type='Resize', scale=(128, 128), keys=['img'], backend='pillow'), dict(type='Flip', keys=['img'], flip_ratio=0.5, direction='horizontal'), dict(type='PackInputs') ] dataset=dict( type='ImageNet', data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=pipeline), ``` `CIFAR10` 的配置示例: ```python pipeline = [dict(type='PackInputs')] dataset = dict( type='CIFAR10', data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=pipeline) ``` ### AdobeComp1kDataset **AdobeComp1kDataset** `mmagic.datasets.AdobeComp1kDataset` 是为 `Adobe composition-1k` 数据集而设计的。 该数据集加载(alpha, fg, bg)数据,并对数据执行指定的变换。您可以在 `pipeline` 中指定在线合成图像或加载离线已合成的图像。 在线合成 `comp-1k` 数据集示例: ```md [ { "alpha": 'alpha/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] ``` 离线合成 `comp-1k` 数据集示例: ```md [ { "alpha": 'alpha/000.png', "merged": 'merged/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "merged": 'merged/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] ``` ### GrowScaleImgDataset `GrowScaleImgDataset` 是为了动态 GAN 模型(例如 `PGGAN` 和 `StyleGANv1`)而设计的。 在这个数据集中,我们支持在训练过程中切换数据根目录,来加载不同分辨率的训练图像。 这个过程是通过 `GrowScaleImgDataset.update_annotations` 方法实现的,并在训练过程中由 `PGGANFetchDataHook.before_train_iter` 调用。 ```python def update_annotations(self, curr_scale): # 确定是否需要更新数据根目录 if curr_scale == self._actual_curr_scale: return False # 按图像分辨率(尺度)提取新的数据根目录 for scale in self._img_scales: if curr_scale <= scale: self._curr_scale = scale break if scale == self._img_scales[-1]: assert RuntimeError( f'Cannot find a suitable scale for {curr_scale}') self._actual_curr_scale = curr_scale self.data_root = self.data_roots[str(self._curr_scale)] # 使用新的数据根目录重新加载数据列表 self.load_data_list() # print basic dataset information to check the validity print_log('Update Dataset: ' + repr(self), 'current') return True ``` ### SinGANDataset `SinGANDataset` 是为 `SinGAN` 模型训练而设计的数据集。在 `SinGAN` 的训练中,我们不会去迭代数据集中的图像,而是返回一个一致的预处理图像字典。 由于不需要根据给定的索引加载相应的图像数据,我们绕过了 `BaseDataset` 的默认数据加载逻辑。 ```python def load_data_list(self, min_size, max_size, scale_factor_init): # 加载单张图像 real = mmcv.imread(self.data_root) self.reals, self.scale_factor, self.stop_scale = create_real_pyramid( real, min_size, max_size, scale_factor_init) self.data_dict = {} # 生成多尺度图像 for i, real in enumerate(self.reals): self.data_dict[f'real_scale{i}'] = real self.data_dict['input_sample'] = np.zeros_like( self.data_dict['real_scale0']).astype(np.float32) def __getitem__(self, index): # 直接返回转换过的数据字典 return self.pipeline(self.data_dict) ``` ### PairedImageDataset `PairedImageDataset` 专为需要成对训练数据的图像转换模型(例如 `Pix2Pix`)设计。 目录结构如下所示,其中每个图像文件都是图像对的拼接。 ``` ./data/dataset_name/ ├── test │ └── XXX.jpg └── train └── XXX.jpg ``` 在 `PairedImageDataset` 中,我们在 `load_data_list` 方法中扫描文件列表,然后将路径保存在 `pair_path` 字段中,以适配 `LoadPairedImageFromFile` 中的转换。 ```python def load_data_list(self): data_infos = [] pair_paths = sorted(self.scan_folder(self.data_root)) for pair_path in pair_paths: # save path in the specific field data_infos.append(dict(pair_path=pair_path)) return data_infos ``` ### UnpairedImageDataset `UnpairedImageDataset` 是专为不需要成对数据的图像转换模型(例如 `CycleGAN`)设计的数据集。 目录结构如下所示: ``` ./data/dataset_name/ ├── testA │ └── XXX.jpg ├── testB │ └── XXX.jpg ├── trainA │ └── XXX.jpg └── trainB └── XXX.jpg ``` 在该数据集中,我们重载了 `__getitem__` 方法,实现了在训练过程中加载随机的图像对。 ```python def __getitem__(self, idx): if not self.test_mode: return self.prepare_train_data(idx) return self.prepare_test_data(idx) def prepare_train_data(self, idx): img_a_path = self.data_infos_a[idx % self.len_a]['path'] idx_b = np.random.randint(0, self.len_b) img_b_path = self.data_infos_b[idx_b]['path'] results = dict() results[f'img_{self.domain_a}_path'] = img_a_path results[f'img_{self.domain_b}_path'] = img_b_path return self.pipeline(results) def prepare_test_data(self, idx): img_a_path = self.data_infos_a[idx % self.len_a]['path'] img_b_path = self.data_infos_b[idx % self.len_b]['path'] results = dict() results[f'img_{self.domain_a}_path'] = img_a_path results[f'img_{self.domain_b}_path'] = img_b_path return self.pipeline(results) ``` ## 实现一个新的数据集 如果您需要为一个新的底层 CV 任务(例如去噪、去雨、去雾和去反射)创建一个数据集,或者现有的数据集格式不符合您的需求,您可以将新的数据格式重新组织成现有的格式,或者在 `mmagic/datasets` 中创建一个新的数据集中来加载数据。 从现有的数据集基类中继承(例如 `BasicImageDataset` 和 `BasicFramesDataset`)会比较容易创建一个新的数据集。 您也可以创建一个继承自 [BaseDataset](https://github.com/open-mmlab/mmengine/blob/main/mmengine/dataset/base_dataset.py) 的新数据集,它是定义在 [MMEngine](https://github.com/open-mmlab/mmengine) 中的数据集基类。 下面是创建一个用于视频帧插值的数据集的示例: ```python from .basic_frames_dataset import BasicFramesDataset from mmagic.registry import DATASETS @DATASETS.register_module() class NewVFIDataset(BasicFramesDataset): """Introduce the dataset Examples of file structure. Args: pipeline (list[dict | callable]): A sequence of data transformations. folder (str | :obj:`Path`): Path to the folder. ann_file (str | :obj:`Path`): Path to the annotation file. test_mode (bool): Store `True` when building test dataset. Default: `False`. """ def __init__(self, ann_file, metainfo, data_root, data_prefix, pipeline, test_mode=False): super().__init__(ann_file, metainfo, data_root, data_prefix, pipeline, test_mode) self.data_infos = self.load_annotations() def load_annotations(self): """Load annoations for the dataset. Returns: list[dict]: A list of dicts for paired paths and other information. """ data_infos = [] ... return data_infos ``` 欢迎[提交新的数据集类到 MMagic](https://github.com/open-mmlab/mmagic/compare) ### 重复数据集 我们使用 [RepeatDataset](https://github.com/open-mmlab/mmengine/blob/main/mmengine/dataset/dataset_wrapper.py) 作为包装器来重复数据集。 例如,假设原始数据集是 `Dataset_A`,为了重复它,配置文件应该如下所示: ```python dataset_A_train = dict( type='RepeatDataset', times=N, dataset=dict( # This is the original config of Dataset_A type='Dataset_A', ... pipeline=train_pipeline ) ) ``` 您可以参考 [MMEngine 中的教程](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/basedataset.md)。 ================================================ FILE: docs/zh_cn/howto/losses.md ================================================ # 如何设计自己的损失函数 `losses` 在 `MMagic` 中注册为 `LOSSES`。 在 MMagic 中设计自己的损失函数,步骤和在 MMagic 中自定义任何其他模型类似。 本节主要具体介绍了如何在 MMagic 中实现自定义的损失函数。 本教程建议您在实现自定义的损失函数时,应该遵循本教程相同的设计,这样在我们的框架中使用您新定义的损失函数,就不需要额外的工作。 本指南包括: - [设计你自己的损失函数](#如何设计自己的损失函数) - [支持损失函数介绍](#支持的损失函数介绍) - [设计一个新的损失函数](#设计一个新的损失函数) - [MSELoss 的一个例子](#MSELoss-的一个例子) - [DiscShiftLoss 的一个例子](#DiscShiftLoss-的一个例子) - [GANWithCustomizedLoss 的一个例子](#GANWithCustomizedLoss-的一个例子) - [可用损失函数](#可用损失函数) - [常规损失函数](#常规损失函数) - [损失函数组件](#损失函数组件) ## 支持的损失函数介绍 为了方便使用,您可以直接使用我们为具体算法设置的默认损失计算过程,如lsgan、biggan、styleganv2等。 以`stylegan2`为例,我们使用R1梯度惩罚和生成器路径长度正则化作为可配置损失,用户可以调整相关参数,如 `r1_loss_weight` 和 `g_reg_weight`。 ```python # stylegan2_base.py loss_config =dict( r1_loss_weight=10。 / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2。 * g_reg_interval, pl_batch_shrink=2) model=dict( type='StyleGAN2', xxx, loss_config=loss_config) ``` ## 设计一个新的损失函数 ### MSELoss 的一个例子 一般来说,要实现一个损失模块,我们会编写一个函数实现,然后用类实现包装它。 以MSELoss为例: ```python @masked_loss def mse_loss(pred,target): return F.mse_loss(pred,target,reduction='none') @LOSSES.register_module() Class MSELoss(nn.Module): def __init__(self, loss_weight=1.0, reduction='mean', sample_wise=False): # 代码可以在``mmagic/models/losses/pixelwise_loss.py``中找到 def forward(self, pred, target, weight=None, **kwargs): # 代码可以在``mmagic/models/losses/pixelwise_loss.py``中找到 ``` 根据这个损失函数的定义,我们现在可以简单地通过在配置文件中定义它来使用: ```python pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean') ``` 请注意,上面的`pixel_loss`必须在模型中定义。 详情请参考[自定义模型](./models.md)。 与自定义模型类似,为了使用您自己实现的损失函数,您需要在编写后在`mmagic/models/losses/__init__.py`中导入该损失函数。 ### DiscShiftLoss 的一个例子 一般来说,要实现一个损失模块,我们会编写一个函数实现,然后用类实现包装它。 但是,在 MMagic 中,我们提供了另一个统一的接口 data_info 供用户定义输入参数和数据项之间的映射。 ```python @weighted_loss def disc_shift_loss(pred): return pred**2 @MODULES.register_module() Class DiscShiftLoss(nn.Module): def __init__(self, loss_weight=1.0, data_info=None): super(DiscShiftLoss,self).__init__() # 代码可以在``mmagic/models/losses/disc_auxiliary_loss.py``中找到 def forward(self, *args, **kwargs): # 代码可以在``mmagic/models/losses/disc_auxiliary_loss.py``中找到 ``` 这种损失模块设计的目标是允许在生成模型(`MODELS`)中自动使用它,而无需其他复杂代码来定义数据和关键字参数之间的映射。 因此,与 OpenMMLab 中的其他框架不同,我们的损失模块包含一个特殊的关键字 data_info,它是一个定义输入参数与生成模型数据之间映射的字典。 以`DiscShiftLoss`为例,用户在编写配置文件时,可能会用到这个loss,如下: ```python dict(type='DiscShiftLoss', loss_weight=0.001 * 0.5, data_info=dict(pred='disc_pred_real')) ``` `data_info` 中的信息告诉模块使用 `disc_pred_real` 数据作为 `pred` 参数的输入张量。 一旦 `data_info` 不为 `None`,我们的损失模块将自动构建计算图。 ```python @MODULES.register_module() class DiscShiftLoss(nn.Module): def __init__(self, loss_weight=1.0, data_info=None): super(DiscShiftLoss, self).__init__() self.loss_weight = loss_weight self.data_info = data_info def forward(self, *args, **kwargs): # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) kwargs.update(dict(weight=self.loss_weight)) return disc_shift_loss(**kwargs) else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. return disc_shift_loss(*args, weight=self.loss_weight, **kwargs) @staticmethod def loss_name(): return 'loss_disc_shift' ``` 如这部分代码所示,一旦用户设置了“data_info”,损失模块将收到一个包含所有必要数据和模块的字典,该字典由训练过程中的“MODELS”提供。 如果此字典作为非关键字参数给出,则应将其作为第一个参数提供。 如果您使用关键字参数,请将其命名为 `outputs_dict`。 ### GANWithCustomizedLoss 的一个例子 为了构建计算图,生成模型必须提供包含各种数据的字典。 仔细观察任何生成模型,你会发现我们将各种特征和模块收集到字典中。 我们在这里提供了一个自定义的`GANWithCustomizedLoss`来展示这个过程。 ```python class GANWithCustomizedLoss(BaseModel): def __init__(self, gan_loss, disc_auxiliary_loss, gen_auxiliary_loss, *args, **kwargs): # ... if gan_loss is not None: self.gan_loss = MODULES.build(gan_loss) else: self.gan_loss = None if disc_auxiliary_loss: self.disc_auxiliary_losses = MODULES.build(disc_auxiliary_loss) if not isinstance(self.disc_auxiliary_losses, nn.ModuleList): self.disc_auxiliary_losses = nn.ModuleList( [self.disc_auxiliary_losses]) else: self.disc_auxiliary_loss = None if gen_auxiliary_loss: self.gen_auxiliary_losses = MODULES.build(gen_auxiliary_loss) if not isinstance(self.gen_auxiliary_losses, nn.ModuleList): self.gen_auxiliary_losses = nn.ModuleList( [self.gen_auxiliary_losses]) else: self.gen_auxiliary_losses = None def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: # ... # get data dict to compute losses for disc data_dict_ = dict( iteration=curr_iter, gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs) loss_disc, log_vars_disc = self._get_disc_loss(data_dict_) # ... def _get_disc_loss(self, outputs_dict): # Construct losses dict. If you hope some items to be included in the # computational graph, you have to add 'loss' in its name. Otherwise, # items without 'loss' in their name will just be used to print # information. losses_dict = {} # gan loss losses_dict['loss_disc_fake'] = self.gan_loss( outputs_dict['disc_pred_fake'], target_is_real=False, is_disc=True) losses_dict['loss_disc_real'] = self.gan_loss( outputs_dict['disc_pred_real'], target_is_real=True, is_disc=True) # disc auxiliary loss if self.with_disc_auxiliary_loss: for loss_module in self.disc_auxiliary_losses: loss_ = loss_module(outputs_dict) if loss_ is None: continue # the `loss_name()` function return name as 'loss_xxx' if loss_module.loss_name() in losses_dict: losses_dict[loss_module.loss_name( )] = losses_dict[loss_module.loss_name()] + loss_ else: losses_dict[loss_module.loss_name()] = loss_ loss, log_var = self.parse_losses(losses_dict) return loss, log_var ``` 在这里,`_get_disc_loss` 将帮助自动组合各种损失函数。 因此,只要用户设计相同规则的损失模块,就可以在生成模型的训练中插入任何一种损失,无需对模型代码进行其他修改。 您只需要在配置文件中定义 `data_info` 即可。 ## 可用损失函数 我们在配置中列出了可用的损失示例,如下所示。 ### 常规损失函数
Method class Example
vanilla gan loss mmagic.models.GANLoss ```python # dic gan loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ) ```
lsgan loss mmagic.models.GANLoss
wgan loss mmagic.models.GANLoss ```python # deepfillv1 loss_gan=dict( type='GANLoss', gan_type='wgan', loss_weight=0.0001, ) ```
hinge loss mmagic.models.GANLoss ```python # deepfillv2 loss_gan=dict( type='GANLoss', gan_type='hinge', loss_weight=0.1, ) ```
smgan loss mmagic.models.GANLoss ```python # aot-gan loss_gan=dict( type='GANLoss', gan_type='smgan', loss_weight=0.01, ) ```
gradient penalty mmagic.models.GradientPenaltyLoss ```python # deepfillv1 loss_gp=dict(type='GradientPenaltyLoss', loss_weight=10.) ```
discriminator shift loss mmagic.models.DiscShiftLoss ```python # deepfillv1 loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001) ```
clip loss mmagic.models.CLIPLoss
L1 composition loss mmagic.models.L1CompositionLoss
MSE composition loss mmagic.models.MSECompositionLoss
charbonnier composition loss mmagic.models.CharbonnierCompLoss ```python # dim loss_comp=dict(type='CharbonnierCompLoss', loss_weight=0.5) ```
face id Loss mmagic.models.FaceIdLoss
light cnn feature loss mmagic.models.LightCNNFeatureLoss ```python # dic gan feature_loss=dict( type='LightCNNFeatureLoss', pretrained=pretrained_light_cnn, loss_weight=0.1, criterion='l1') ```
gradient loss mmagic.models.GradientLoss
l1 Loss mmagic.models.L1Loss ```python # dic gan pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') ```
mse loss mmagic.models.MSELoss ```python # dic gan align_loss=dict(type='MSELoss', loss_weight=0.1, reduction='mean') ```
charbonnier loss mmagic.models.CharbonnierLoss ```python # dim loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5) ```
masked total variation loss mmagic.models.MaskedTVLoss ```python # partial conv loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1 ) ```
perceptual loss mmagic.models.PerceptualLoss ```python # real_basicvsr perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False) ```
transferal perceptual loss mmagic.models.TransferalPerceptualLoss ```python # ttsr transferal_perceptual_loss=dict( type='TransferalPerceptualLoss', loss_weight=1e-2, use_attention=False, criterion='mse') ```
### 损失函数组件 对于“GANWithCustomizedLoss”,我们提供了几个组件来构建自定义损失。 | Method | class | | ------------------------------------ | ------------------------------------------- | | clip loss component | mmagic.models.CLIPLossComps | | discriminator shift loss component | mmagic.models. DiscShiftLossComps | | gradient penalty loss component | mmagic.models. GradientPenaltyLossComps | | r1 gradient penalty component | mmagic.models. R1GradientPenaltyComps | | face Id loss component | mmagic.models. FaceIdLossComps | | gan loss component | mmagic.models. GANLossComps | | generator path regularizer component | mmagic.models.GeneratorPathRegularizerComps | ================================================ FILE: docs/zh_cn/howto/models.md ================================================ # 如何设计自己的模型 MMagic建立在MMEngine和MMCV的基础上,使用户能够快速地设计新模型,轻松地地训练和评估它们。 在本节中,您将学习如何设计自己的模型。 本指南的结构如下: - [如何设计自己的模型](#如何设计自己的模型) - [MMagic中的模型概述](#mmagic中的模型概述) - [一个SRCNN的例子](#一个srcnn的例子) - [Step 1: 定义SRCNN网络](#step-1-定义srcnn网络) - [Step 2: 定义SRCNN的模型](#step-2-定义srcnn的模型) - [Step 3: 开始训练SRCNN](#step-3-开始训练srcnn) - [一个DCGAN的例子](#一个dcgan的例子) - [Step 1: 定义DCGAN的网络](#step-1-定义dcgan的网络) - [Step 2: 设计DCGAN的模型](#step-2-设计dcgan的模型) - [Step 3: 开始训练DCGAN](#step-3-开始训练dcgan) - [参考文献](#参考文献) ## MMagic中的模型概述 在MMagic中,一个算法可以分为两部分: **Model** 和 **Module**. - **Model** 是最顶层的包装,并且总是继承自MMEngine中提供的 `BaseModel` 。 **Model** 负责网络前向、损耗计算、反向、参数更新等. 在MMagic中, **Model** 应该注册为 `MODELS`. - **Module** 模块包括用于训练或推理的 **architectures** , 预定义的 **loss classes**, 以及对批量输入数据预处理的 **data preprocessors** 。 **Module** 总是作为**Model**的元素呈现。 在MMagic中, **Module** 应该注册为 **MODULES**。 以DCGAN model 模型为例,[生成器](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_generator.py) 和 [判别器](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_discriminator.py) 是 **Module**, 分别用于生成图像和鉴别图像真伪。 [`DCGAN`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan.py) 是 **Model**, 它从dataloader中获取数据,交替训练生成器和鉴别器。 您可以通过以下链接找到 **Model** 和 **Module** 的实现。 - **Model**: - [Editors](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/editors) - **Module**: - [Layers](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/layers) - [Losses](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/losses) - [Data Preprocessor](https://github.com/open-mmlab/mmagic/tree/main/mmagic/models/data_preprocessors) ## 一个SRCNN的例子 这里,我们以经典图像超分辨率模型SRCNN\[1\]的实现为例。 ### Step 1: 定义SRCNN网络 SRCNN 是第一个用于单幅图像超分辨率\[1\]的深度学习方法。为了实现SRCNN的网络架构,我们需要创建一个新文件 `mmagic/models/editors/srgan/sr_resnet.py` 并执行 `class MSRResNet`。 在这一步中,我们通过继承`mmengine.models.BaseModule`来实现 `class MSRResNet`,并在`__init__`函数中定义网络架构。 特别地,我们需要使用`@MODELS.register_module()`将`class MSRResNet`的实现添加到MMagic的注册中。 ```python import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from mmagic.models.utils import (PixelShufflePack, ResidualBlockNoBN, default_init_weights, make_layer) @MODELS.register_module() class MSRResNet(BaseModule): """修改后的SRResNet。 由 "使用生成对抗网络的照片-现实的单幅图像超级分辨率 "中的SRResNet修改而来的压缩版本。 它使用无BN的残差块,类似于EDSR。 目前支持x2、x3和x4上采样比例因子。 Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_blocks (int): Block number in the trunk network. Default: 16. upscale_factor (int): Upsampling factor. Support x2, x3 and x4. Default: 4. """ _supported_upscale_factors = [2, 3, 4] def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=16, upscale_factor=4): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.mid_channels = mid_channels self.num_blocks = num_blocks self.upscale_factor = upscale_factor self.conv_first = nn.Conv2d( in_channels, mid_channels, 3, 1, 1, bias=True) self.trunk_net = make_layer( ResidualBlockNoBN, num_blocks, mid_channels=mid_channels) # upsampling if self.upscale_factor in [2, 3]: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, self.upscale_factor, upsample_kernel=3) elif self.upscale_factor == 4: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) else: raise ValueError( f'Unsupported scale factor {self.upscale_factor}. ' f'Currently supported ones are ' f'{self._supported_upscale_factors}.') self.conv_hr = nn.Conv2d( mid_channels, mid_channels, 3, 1, 1, bias=True) self.conv_last = nn.Conv2d( mid_channels, out_channels, 3, 1, 1, bias=True) self.img_upsampler = nn.Upsample( scale_factor=self.upscale_factor, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self.init_weights() def init_weights(self): """Init weights for models. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. strict (boo, optional): Whether strictly load the pretrained model. Defaults to True. """ for m in [self.conv_first, self.conv_hr, self.conv_last]: default_init_weights(m, 0.1) ``` 然后,我们实现了`class MSRResNet`的`forward` 函数, 该函数将输入张量作为输入张量,然后返回`MSRResNet`的结果。 ```python def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ feat = self.lrelu(self.conv_first(x)) out = self.trunk_net(feat) if self.upscale_factor in [2, 3]: out = self.upsample1(out) elif self.upscale_factor == 4: out = self.upsample1(out) out = self.upsample2(out) out = self.conv_last(self.lrelu(self.conv_hr(out))) upsampled_img = self.img_upsampler(x) out += upsampled_img return out ``` 在`class MSRResNet`实现后,我们需要更新`mmagic/models/editors/__init__.py`中的模型列表,以便我们可以通过`mmagic.models.editors`导入和使用`class MSRResNet`。 ```python from .srgan.sr_resnet import MSRResNet ``` ### Step 2: 定义SRCNN的模型 网络架构实现后, 我们需要定义我们的模型`class BaseEditModel` 并实现`class BaseEditModel`的前向循环。 为了实现`class BaseEditModel`, 我们创建一个新文件`mmagic/models/base_models/base_edit_model.py`。 具体来说,`class BaseEditModel`继承自`mmengine.model.BaseModel`. 在`__init__`函数中,我们定义了`class BaseEditModel`的损失函数,训练, 测试配置和网络。 ```python from typing import List, Optional import torch from mmengine.model import BaseModel from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class BaseEditModel(BaseModel): """用于图像和视频编辑的基本模型。 它必须包含一个生成器,将帧作为输入并输出插值帧。它也有一个用于训练的pixel-wise损失。 Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. Default: None. """ def __init__(self, generator, pixel_loss, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.train_cfg = train_cfg self.test_cfg = test_cfg # generator self.generator = MODELS.build(generator) # loss self.pixel_loss = MODELS.build(pixel_loss) ``` 因为`mmengine.model.BaseModel`提供了算法模型的基本功能,例如权重初始化、批量输入预处理、解析损失和更新模型参数。 因此,子类继承自BaseModel,即本例中的`class BaseEditModel`, 只需要实现forward方法,该方法实现了计算损失和预测的逻辑。 具体来说,`class BaseEditModel`实现的`forward`函数将`batch_inputs`和`data_samples`作为输入,并根据模式参数返回结果。 ```python def forward(self, batch_inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs): """返回训练、验证、测试和简单推理过程的损失或预测。 BaseModel的``forward``方法是一个抽象方法,它的子类必须实现这个方法。 接受由:attr:`data_preprocessor`处理的``batch_inputs`` 和 ``data_samples``, 并根据模式参数返回结果。. 在非分布式训练、验证和测试过程中, ``forward``将被``BaseModel.train_step``, ``BaseModel.val_step``和``BaseModel.val_step``直接调用。 在分布式数据并行训练过程中,``MMSeparateDistributedDataParallel.train_step``将首先调用``DistributedDataParallel.forward``以启用自动梯度同步,然后调用``forward``获得训练损失。 Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor`` - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict or tensor for custom use. """ if mode == 'tensor': return self.forward_tensor(batch_inputs, data_samples, **kwargs) elif mode == 'predict': return self.forward_inference(batch_inputs, data_samples, **kwargs) elif mode == 'loss': return self.forward_train(batch_inputs, data_samples, **kwargs) ``` 具体来说,在`forward_tensor`中, `class BaseEditModel`直接返回网络的前向张量。 ```python def forward_tensor(self, batch_inputs, data_samples=None, **kwargs): """Forward tensor. Returns result of simple forward. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: result of simple forward. """ feats = self.generator(batch_inputs, **kwargs) return feats ``` 在`forward_inference`函数中,`class BaseEditModel`首先将前向张量转换为图像,然后返回该图像作为输出。 ```python def forward_inference(self, batch_inputs, data_samples=None, **kwargs): """Forward inference. Returns predictions of validation, testing, and simple inference. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: List[DataSample]: predictions. """ feats = self.forward_tensor(batch_inputs, data_samples, **kwargs) feats = self.data_preprocessor.destructor(feats) predictions = [] for idx in range(feats.shape[0]): predictions.append( DataSample( pred_img=feats[idx].to('cpu'), metainfo=data_samples[idx].metainfo)) return predictions ``` 在`forward_train`中, `class BaseEditModel`计算损失函数,并返回一个包含损失的字典作为输出。 ```python def forward_train(self, batch_inputs, data_samples=None, **kwargs): """Forward training. Returns dict of losses of training. Args: batch_inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ feats = self.forward_tensor(batch_inputs, data_samples, **kwargs) gt_imgs = [data_sample.gt_img.data for data_sample in data_samples] batch_gt_data = torch.stack(gt_imgs) loss = self.pixel_loss(feats, batch_gt_data) return dict(loss=loss) ``` 在实现了`class BaseEditModel`之后,我们需要更新 `mmagic/models/__init__.py`中的模型列表,这样我们就可以通过`mmagic.models`导入和使用`class BaseEditModel`。 ```python from .base_models.base_edit_model import BaseEditModel ``` ### Step 3: 开始训练SRCNN 在实现了网络结构和SRCNN的前向循环后、 现在我们可以创建一个新的文件`configs/srcnn/srcnn_x4k915_g1_1000k_div2k.py` 来设置训练SRCNN所需的配置。 在配置文件中,我们需要指定我们的模型`class BaseEditModel`的参数,包括生成器网络结构、损失函数、额外的训练和测试配置,以及输入张量的数据预处理器。请参考[MMagic中的损失函数介绍](./losses.md)了解MMagic中损失函数的更多细节。 ```python # model settings model = dict( type='BaseEditModel', generator=dict( type='SRCNNNet', channels=(3, 64, 32, 3), kernel_sizes=(9, 1, 5), upscale_factor=scale), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=dict( type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.], )) ``` 我们还需要根据创建自己的数据加载器来指定训练数据加载器和测试数据加载器。 最后,我们可以开始训练我们自己的模型: ```python python tools/train.py configs/srcnn/srcnn_x4k915_g1_1000k_div2k.py ``` ## 一个DCGAN的例子 这里,我们以经典gan模型DCGAN\[2\]的实现为例。 ### Step 1: 定义DCGAN的网络 DCGAN是一种经典的图像生成对抗网络\[2\]。为了实现DCGAN的网络架构,我们需要创建两个新文件`mmagic/models/editors/dcgan/dcgan_generator.py`和`mmagic/models/editors/dcgan/dcgan_discriminator.py`,并实现生成器(`class DCGANGenerator`) 和鉴别器(`class DCGANDiscriminator`)。 在这一步中,我们实现了`class DCGANGenerator`, `class DCGANDiscriminator` 并在`__init__`函数中定义了网络架构。 特别地,我们需要使用`@MODULES.register_module()`来将生成器和鉴别器添加到MMagic的注册中。 以下面的代码为例: ```python import torch.nn as nn from mmcv.cnn import ConvModule from mmcv.runner import load_checkpoint from mmcv.utils.parrots_wrapper import _BatchNorm from mmengine.logging import MMLogger from mmengine.model.utils import normal_init from mmagic.models.builder import MODULES from ..common import get_module_device @MODULES.register_module() class DCGANGenerator(nn.Module): def __init__(self, output_scale, out_channels=3, base_channels=1024, input_scale=4, noise_size=100, default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='ReLU'), out_act_cfg=dict(type='Tanh'), pretrained=None): super().__init__() self.output_scale = output_scale self.base_channels = base_channels self.input_scale = input_scale self.noise_size = noise_size # 上采样的次数 self.num_upsamples = int(np.log2(output_scale // input_scale)) # 输出4x4的特征图 self.noise2feat = ConvModule( noise_size, base_channels, kernel_size=4, stride=1, padding=0, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg) # 建立上采样骨干(不包括输出层) upsampling = [] curr_channel = base_channels for _ in range(self.num_upsamples - 1): upsampling.append( ConvModule( curr_channel, curr_channel // 2, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) curr_channel //= 2 self.upsampling = nn.Sequential(*upsampling) # 输出层 self.output_layer = ConvModule( curr_channel, out_channels, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=None, act_cfg=out_act_cfg) ``` 然后,我们实现了`DCGANGenerator`的`forward`函数,该函数接受 `noise`张量或`num_batches`,然后返回`DCGANGenerator`的结果。 ```python def forward(self, noise, num_batches=0, return_noise=False): noise_batch = noise_batch.to(get_module_device(self)) x = self.noise2feat(noise_batch) x = self.upsampling(x) x = self.output_layer(x) return x ``` 如果你想为你的网络实现特定的权重初始化方法,你需要自己添加`init_weights`函数。 ```python def init_weights(self, pretrained=None): if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): normal_init(m, 0, 0.02) elif isinstance(m, _BatchNorm): nn.init.normal_(m.weight.data) nn.init.constant_(m.bias.data, 0) else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') ``` 在实现`DCGANGenerator`类之后,我们需要更新`mmagic/models/editors/__init__.py`中的模型列表,以便我们可以通过`mmagic.models.editors`导入和使用`DCGANGenerator`类。 类`DCGANDiscriminator`的实现遵循类似的逻辑,你可以在[这里](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/editors/dcgan/dcgan_discriminator.py)找到实现。 ### Step 2: 设计DCGAN的模型 在实现了网络**Module**之后,我们需要定义我们的**Model**类 `DCGAN`。 你的**Model**应该继承自MMEngine提供的[`BaseModel`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/base_model/base_model.py#L16),并实现三个函数,`train_step`, `val_step`和`test_step`。 - `train_step`: 这个函数负责更新网络的参数,由MMEngine的Loop ([`IterBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L183)或 [`EpochBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L18))调用。 `train_step`将数据批处理和[`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md)作为输入并返回一个日志字典。 - `val_step`: 该函数负责在训练过程中获取用于验证的输出,由 [`MultiValLoop`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/engine/runner/multi_loops.py#L19)调用。 - `test_step`: 该函数负责在测试过程中获取输出,由[`MultiTestLoop`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/engine/runner/multi_loops.py#L274)调用。 > 请注意,在`train_step`, `val_step`和`test_step`中,调用`DataPreprocessor`对输入数据进行预处理,然后再将它们提供给神经网络。要了解有关`DataPreprocessor`的更多信息,请参阅此[文件](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/data_preprocessors/gen_preprocessor.py) and 和本[教程](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/tutorials/model.md#%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E5%99%A8datapreprocessor)。 为了简化使用,我们在MMagic中提供了[`BaseGAN`](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/base_models/base_gan.py)类,它为GAN模型实现了通用的`train_step`, `val_step`和`test_step`函数。使用`BaseGAN`作为基类,每个特定的GAN算法只需要实现`train_generator` and `train_discriminator`. 在`train_step`中,我们支持数据预处理、梯度累积(由[`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md)实现)和指数滑动平均(EMA)通过[(`ExponentialMovingAverage`)](https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/base_models/average_model.py#L19)实现。使用`BaseGAN.train_step`,每个特定的GAN算法只需要实现`train_generator`和`train_discriminator`。 ```python def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts # 训练判别器,使用MMEngine提供的上下文管理器 with disc_optimizer_wrapper.optim_context(self.discriminator): # train_discriminator should be implemented! log_vars = self.train_discriminator( **data, optimizer_wrapper=disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) # update generator, use context manager provided by MMEngine for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): # train_generator should be implemented! log_vars_gen = self.train_generator( **data, optimizer_wrapper=gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) # return the log dict return log_vars ``` 在`val_step`和`test_step`,我们渐进地调用数据预处理和`BaseGAN.forward`。 ```python def val_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) # call `forward` outputs = self(**data) return outputs def test_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) # call `orward` outputs = self(**data) return outputs ``` 然后,我们在`DCGAN`类中实现`train_generator`和`train_discriminator`。 ```python from typing import Dict, Tuple import torch import torch.nn.functional as F from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from .base_gan import BaseGAN @MODELS.register_module() class DCGAN(BaseGAN): def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: losses_dict = dict() losses_dict['loss_disc_fake'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 0. * torch.ones_like(disc_pred_fake)) losses_dict['loss_disc_real'] = F.binary_cross_entropy_with_logits( disc_pred_real, 1. * torch.ones_like(disc_pred_real)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple: losses_dict = dict() losses_dict['loss_gen'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 1. * torch.ones_like(disc_pred_fake)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator( self, inputs, data_sample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: real_imgs = inputs['img'] num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs, data_sample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: num_batches = inputs['img'].shape[0] noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ``` 在实现了`class DCGAN`之后,我们需要更新`mmagic/models/__init__.py`中的模型列表,以便我们可以通过`mmagic.models`导入和使用`class DCGAN`。 ### Step 3: 开始训练DCGAN 在实现了网络**Module**和DCGAN的**Model**之后,现在我们可以创建一个新文件`configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py` 来设置训练DCGAN所需的配置。 在配置文件中,我们需要指定模型的参数,`class DCGAN`,包括生成器网络架构和输入张量的数据预处理器。 ```python # model settings model = dict( type='DCGAN', noise_size=100, data_preprocessor=dict(type='GANDataPreprocessor'), generator=dict(type='DCGANGenerator', output_scale=64, base_channels=1024), discriminator=dict( type='DCGANDiscriminator', input_scale=64, output_scale=4, out_channels=1)) ``` 我们还需要根据[创建自己的数据加载器](dataset.md)指定训练数据加载器和测试数据加载器。 最后,我们可以开始训练我们自己的模型: ```python python tools/train.py configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py ``` ## 参考文献 1. Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou. Image Super-Resolution Using Deep Convolutional Networks\[J\]. IEEE transactions on pattern analysis and machine intelligence, 2015. 2. Radford, Alec, Luke Metz, and Soumith Chintala. "Unsupervised representation learning with deep convolutional generative adversarial networks." arXiv preprint arXiv:1511.06434 (2015). ================================================ FILE: docs/zh_cn/howto/transforms.md ================================================ # 如何设计自己的数据变换 在本教程中,我们将介绍MMagic中变换流水线的设计。 The structure of this guide are as follows: - [如何设计自己的数据变换](#如何设计自己的数据变换) - [MMagic中的数据流水线](#mmagic中的数据流水线) - [数据变换的一个简单示例](#数据变换的一个简单示例) - [BasicVSR的一个示例](#basicvsr的一个示例) - [Pix2Pix的一个示例](#pix2pix的一个示例) - [MMagic中支持的数据变换](#mmagic中支持的数据变换) - [数据加载](#数据加载) - [预处理](#预处理) - [格式化](#格式化) - [扩展和使用自定义流水线](#扩展和使用自定义流水线) - [一个简单的MyTransform示例](#一个简单的mytransform示例) - [一个翻转变换的示例](#一个翻转变换的示例) ## MMagic中的数据流水线 按照典型的惯例,我们使用 `Dataset` 和 `DataLoader` 来加载多个线程的数据。 `Dataset` 返回一个与模型的forward方法的参数相对应的数据项的字典。 数据准备流水线和数据集是分开的。通常,一个数据集定义了如何处理标注,而一个数据管道定义了准备一个数据字典的所有步骤。 一个流水线由一连串的操作组成。每个操作都需要一个字典作为输入,并为下一个变换输出一个字典。 这些操作被分为数据加载、预处理和格式化。 在MMagic中,所有数据变换都继承自 `BaseTransform`。 变换的输入和输出类型都是字典。 ### 数据变换的一个简单示例 ```python >>> from mmagic.transforms import LoadPairedImageFromFile >>> transforms = LoadPairedImageFromFile( >>> key='pair', >>> domain_a='horse', >>> domain_b='zebra', >>> flag='color'), >>> data_dict = {'pair_path': './data/pix2pix/facades/train/1.png'} >>> data_dict = transforms(data_dict) >>> print(data_dict.keys()) dict_keys(['pair_path', 'pair', 'pair_ori_shape', 'img_mask', 'img_photo', 'img_mask_path', 'img_photo_path', 'img_mask_ori_shape', 'img_photo_ori_shape']) ``` 一般来说,变换流水线的最后一步必须是 `PackInputs`. `PackInputs` 将把处理过的数据打包成一个包含两个字段的字典:`inputs` 和 `data_samples`. `inputs` 是你想用作模型输入的变量,它可以是 `torch.Tensor` 的类型, `torch.Tensor` 的字典,或者你想要的任何类型。 `data_samples` 是一个 `DataSample` 的列表. 每个 `DataSample` 都包含真实值和对应输入的必要信息。 ### BasicVSR的一个示例 下面是一个BasicVSR的流水线示例。 ```python train_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='SetValues', dictionary=dict(scale=scale)), dict(type='PairedRandomCrop', gt_patch_size=256), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict( type='Flip', keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type='RandomTransposeHW', keys=['img', 'gt'], transpose_ratio=0.5), dict(type='MirrorSequence', keys=['img', 'gt']), dict(type='PackInputs') ] val_pipeline = [ dict(type='GenerateSegmentIndices', interval_list=[1]), dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='PackInputs') ] test_pipeline = [ dict(type='LoadImageFromFile', key='img', channel_order='rgb'), dict(type='LoadImageFromFile', key='gt', channel_order='rgb'), dict(type='MirrorSequence', keys=['img']), dict(type='PackInputs') ] ``` 对于每个操作,我们列出了添加/更新/删除的相关字典字段,标记为 '\*' 的字典字段是可选的。 ### Pix2Pix的一个示例 下面是一个在aerial2maps数据集上Pix2Pix训练的流水线示例。 ```python source_domain = 'aerial' target_domain = 'map' pipeline = [ dict( type='LoadPairedImageFromFile', io_backend='disk', key='pair', domain_a=domain_a, domain_b=domain_b, flag='color'), dict( type='TransformBroadcaster', mapping={'img': [f'img_{domain_a}', f'img_{domain_b}']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='mmagic.Resize', scale=(286, 286), interpolation='bicubic'), dict(type='mmagic.FixedCrop', crop_size=(256, 256)) ]), dict( type='Flip', keys=[f'img_{domain_a}', f'img_{domain_b}'], direction='horizontal'), dict( type='PackInputs', keys=[f'img_{domain_a}', f'img_{domain_b}', 'pair']) ``` ## MMagic中支持的数据变换 ### 数据加载
Transform Modification of Results' keys
LoadImageFromFile - add: img, img_path, img_ori_shape, \*ori_img
RandomLoadResizeBg - add: bg
LoadMask - add: mask
GetSpatialDiscountMask - add: discount_mask
### 预处理
Transform Modification of Results' keys
Resize - add: scale_factor, keep_ratio, interpolation, backend - update: specified by keys
MATLABLikeResize - add: scale, output_shape - update: specified by keys
RandomRotation - add: degrees - update: specified by keys
Flip - add: flip, flip_direction - update: specified by keys
RandomAffine - update: specified by keys
RandomJitter - update: fg (img)
ColorJitter - update: specified by keys
BinarizeImage - update: specified by keys
RandomMaskDilation - add: img_dilate_kernel_size
RandomTransposeHW - add: transpose
RandomDownSampling - update: scale, gt (img), lq (img)
RandomBlur - update: specified by keys
RandomResize - update: specified by keys
RandomNoise - update: specified by keys
RandomJPEGCompression - update: specified by keys
RandomVideoCompression - update: specified by keys
DegradationsWithShuffle - update: specified by keys
GenerateFrameIndices - update: img_path (gt_path, lq_path)
GenerateFrameIndiceswithPadding - update: img_path (gt_path, lq_path)
TemporalReverse - add: reverse - update: specified by keys
GenerateSegmentIndices - add: interval - update: img_path (gt_path, lq_path)
MirrorSequence - update: specified by keys
CopyValues - add: specified by dst_key
UnsharpMasking - add: img_unsharp
Crop - add: img_crop_bbox, crop_size - update: specified by keys
RandomResizedCrop - add: img_crop_bbox - update: specified by keys
FixedCrop - add: crop_size, crop_pos - update: specified by keys
PairedRandomCrop - update: gt (img), lq (img)
CropAroundCenter - add: crop_bbox - update: fg (img), alpha (img), trimap (img), bg (img)
CropAroundUnknown - add: crop_bbox - update: specified by keys
CropAroundFg - add: crop_bbox - update: specified by keys
ModCrop - update: gt (img)
CropLike - update: specified by target_key
GetMaskedImage - add: masked_img
GenerateFacialHeatmap - add: heatmap
GenerateCoordinateAndCell - add: coord, cell - update: gt (img)
Normalize - add: img_norm_cfg - update: specified by keys
RescaleToZeroOne - update: specified by keys
### 格式化
Transform Modification of Results' keys
ToTensor update: specified by keys.
FormatTrimap - update: trimap
PackInputs - add: inputs, data_sample - remove: all other keys
### Albumentations MMagic 支持添加 [Albumentations](https://github.com/albumentations-team/albumentations) 库中的 transformation,请浏览 https://albumentations.ai/docs/getting_started/transforms_and_targets 获取更多 transformation 的信息。 使用 Albumentations 的示例如下: ```python albu_transforms = [ dict( type='Resize', height=100, width=100, ), dict( type='RandomFog', p=0.5, ), dict( type='RandomRain', p=0.5 ), dict( type='RandomSnow', p=0.5, ), ] pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Albumentations', keys=['img'], transforms=albu_transforms), dict(type='PackInputs') ] ``` ## 扩展和使用自定义流水线 ### 一个简单的MyTransform示例 1. 在文件中写入一个新的流水线,例如在 `my_pipeline.py`中。它接受一个字典作为输入,并返回一个字典。 ```python import random from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class MyTransform(BaseTransform): """Add your transform Args: p (float): Probability of shifts. Default 0.5. """ def __init__(self, p=0.5): self.p = p def transform(self, results): if random.random() > self.p: results['dummy'] = True return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(p={self.p})') return repr_str ``` 2. 在你的配置文件中导入并使用该流水线。 确保导入相对于你的训练脚本所在的位置。 ```python train_pipeline = [ ... dict(type='MyTransform', p=0.2), ... ] ``` ### 一个翻转变换的示例 这里我们以一个简单的翻转变换为例: ```python import random import mmcv from mmcv.transforms import BaseTransform, TRANSFORMS @TRANSFORMS.register_module() class MyFlip(BaseTransform): def __init__(self, direction: str): super().__init__() self.direction = direction def transform(self, results: dict) -> dict: img = results['img'] results['img'] = mmcv.imflip(img, direction=self.direction) return results ``` 因此,我们可以实例化一个 `MyFlip` 对象,用它来处理数据字典。 ```python import numpy as np transform = MyFlip(direction='horizontal') data_dict = {'img': np.random.rand(224, 224, 3)} data_dict = transform(data_dict) processed_img = data_dict['img'] ``` 或者,我们可以在配置文件的数据流水线中使用 `MyFlip` 变换。 ```python pipeline = [ ... dict(type='MyFlip', direction='horizontal'), ... ] ``` 请注意,如果你想在配置中使用 `MyFlip` ,你必须确保在程序运行过程中导入包含 `MyFlip` 的文件。 ================================================ FILE: docs/zh_cn/index.rst ================================================ 欢迎来到 MMagic 的中文文档! ===================================== 您可以在页面左下角切换中英文文档。 .. note:: 目前英文版有更多的内容,欢迎加入我们一起提升中文文档! 您可以通过 issue,discussion 或者我们的社区群来联系我们! .. toctree:: :maxdepth: 1 :caption: MMagic 社区 community/contributing.md community/projects.md .. toctree:: :maxdepth: 1 :caption: 新手入门 概述 安装 快速运行 .. toctree:: :maxdepth: 1 :caption: 基础教程 user_guides/config.md user_guides/dataset_prepare.md user_guides/inference.md user_guides/train_test.md user_guides/metrics.md user_guides/visualization.md user_guides/useful_tools.md user_guides/deploy.md .. toctree:: :maxdepth: 2 :caption: 进阶教程 advanced_guides/evaluator.md advanced_guides/structures.md advanced_guides/data_preprocessor.md advanced_guides/data_flow.md .. toctree:: :maxdepth: 1 :caption: 开发指南 howto/models.md howto/dataset.md howto/transforms.md howto/losses.md .. toctree:: :maxdepth: 1 :caption: 常见问题 faq.md .. toctree:: :maxdepth: 2 :caption: 模型库 model_zoo/index.rst .. toctree:: :maxdepth: 1 :caption: 数据集库 dataset_zoo/index.rst .. toctree:: :maxdepth: 1 :caption: 变更日志 changelog.md .. toctree:: :maxdepth: 2 :caption: 接口文档(英文) mmagic/apis.inferencers mmagic/structures mmagic/datasets mmagic/datasets.transforms mmagic/evaluation mmagic/visualization mmagic/engine.hooks mmagic/engine.logging mmagic/engine.optimizers mmagic/engine.runner mmagic/engine.schedulers mmagic/models.archs mmagic/models.base_models mmagic/models.losses mmagic/models.data_preprocessors mmagic/models.utils mmagic/models.editors mmagic/utils .. toctree:: :maxdepth: 1 :caption: 迁移指南 migration/overview.md migration/runtime.md migration/models.md migration/eval_test.md migration/schedule.md migration/data.md migration/distributed_train.md migration/optimizers.md migration/visualization.md migration/amp.md .. toctree:: :maxdepth: 1 :caption: 设备支持 device/npu_zh.md .. toctree:: :caption: 语言切换 switch_language.md Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: docs/zh_cn/make.bat ================================================ @ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd ================================================ FILE: docs/zh_cn/migration/amp.md ================================================ # 混合精度训练的迁移 在 0.x 版中,MMEditing 并不支持对整体前向过程的混合精度训练。相反,用户必须使用 `auto_fp16` 装饰器来适配特定子模块,然后再将子模块的参数转化成 fp16。这样就可以拥有对模型参数的更细粒度的控制,但是该方法使用起来很繁琐,而且用户需要自己处理一些操作,比如训练过程中损失函数的缩放 MMagic 1.x 版使用了 MMEngine 提供的 `AmpOptimWrapper`,在 `AmpOptimWrapper.update_params` 中,梯度缩放和 `GradScaler` 更新将被自动执行,且在 `optim_context` 上下文管理其中,`auto_cast`被应用到整个前向过程中。 具体来说,0.x 版和 1.x 版之间的差异如下所示:
0.x 版 1.x 版
```python # 配置 runner = dict(fp16_loss_scaler=dict(init_scale=512)) ``` ```python # 代码 import torch.nn as nn from mmedit.models.builder import build_model from mmedit.core.runners.fp16_utils import auto_fp16 class DemoModule(nn.Module): def __init__(self, cfg): self.net = build_model(cfg) @auto_fp16 def forward(self, x): return self.net(x) class DemoModel(nn.Module): def __init__(self, cfg): super().__init__(self) self.demo_network = DemoModule(cfg) def train_step(self, data_batch, optimizer, ddp_reducer=None, loss_scaler=None, use_apex_amp=False, running_status=None): # 从 data_batch 中获取数据 inputs = data_batch['img'] output = self.demo_network(inputs) optimizer.zero_grad() loss, log_vars = self.get_loss(data_dict_) if ddp_reducer is not None: ddp_reducer.prepare_for_backward(_find_tensors(loss_disc)) if loss_scaler: # 添加 fp16 支持 loss_scaler.scale(loss_disc).backward() elif use_apex_amp: from apex import amp with amp.scale_loss(loss_disc, optimizer, loss_id=0) as scaled_loss_disc: scaled_loss_disc.backward() else: loss_disc.backward() if loss_scaler: loss_scaler.unscale_(optimizer) loss_scaler.step(optimizer) else: optimizer.step() ``` ```python # 配置 optim_wrapper = dict( constructor='OptimWrapperConstructor', generator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-06), type='AmpOptimWrapper', # 使用 amp 封装器 loss_scale='dynamic'), discriminator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-06), type='AmpOptimWrapper', # 使用 amp 封装器 loss_scale='dynamic')) ``` ```python # 代码 import torch.nn as nn from mmagic.registry import MODULES from mmengine.model import BaseModel class DemoModule(nn.Module): def __init__(self, cfg): self.net = MODULES.build(cfg) def forward(self, x): return self.net(x) class DemoModel(BaseModel): def __init__(self, cfg): super().__init__(self) self.demo_network = DemoModule(cfg) def train_step(self, data, optim_wrapper): # 从 data_batch 中获取数据 data = self.data_preprocessor(data, True) inputs = data['inputs'] with optim_wrapper.optim_context(self.discriminator): output = self.demo_network(inputs) loss_dict = self.get_loss(output) # 使用 `BaseModel` 提供的 parse_loss loss, log_vars = self.parse_loss(loss_dict) optimizer_wrapper.update_params(loss) return log_vars ```
若要避免用户操作配置文件,MMagic 在 `train.py` 里提供了 `--amp` 选项,其可以让用户在不修改配置文件的情况下启动混合精度训练,用户可以使用以下命令启动混合精度训练: ```bash bash tools/dist_train.sh CONFIG GPUS --amp # 对 slurm 用户 bash tools/slurm_train.sh PARTITION JOB_NAME CONFIG WORK_DIR --amp ``` ================================================ FILE: docs/zh_cn/migration/data.md ================================================ # Data Settings 的迁移 本篇文档负责介绍 data settings 的迁移方式: - \[Data Settings 的迁移\](#Data Settings 的迁移) - [Data Pipelines](#data-pipelines) - [Dataloader](#dataloader) ## Data Pipelines 在 MMagic 1.x 中我们更新了 data pipeline 的设置,有以下几个重要的修改: - 去除了 `normalization` 和 `color space` 两种数据变换操作,并将它们移动到了 `data_preprocessor` 部分。 - 原版本中格式化数据变换 pipeline 的 `Collect` 和 `ToTensor` 在新版本中被整合为 `PackInputs`。更多的细节可以在 [数据变换文档](../howto/transforms.md) 中查看。
原版本 新版本
```python train_pipeline = [ # Train pipeline dict(type='LoadImageFromFile', # 从文件读取图片 io_backend='disk', # io backend key='lq', # 找到结果对应路径的 keys flag='unchanged'), # 读取图片的 flag dict(type='LoadImageFromFile', # 从文件读取图片 io_backend='disk', # io backend key='gt', # 找到结果对应路径的 keys flag='unchanged'), # 读取图片的 flag dict(type='RescaleToZeroOne', keys=['lq', 'gt']), # 将图片从 [0, 255] 缩放到 [0, 1] dict(type='Normalize', # normalize 图片的 augmentation pipeline keys=['lq', 'gt'], # 需要 normalized 的图片 mean=[0, 0, 0], # 平均值 std=[1, 1, 1], # 标准差 to_rgb=True), # 是否转换到 rgb 通道 dict(type='PairedRandomCrop', gt_patch_size=96), # PairedRandomCrop dict(type='Flip', # 翻转图片 keys=['lq', 'gt'], # 需要翻转的图片 flip_ratio=0.5, # 翻转概率 direction='horizontal'), # Flip 方向 dict(type='Flip', # Flip 图片 keys=['lq', 'gt'], # 需要翻转的图片 flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip 方向 dict(type='RandomTransposeHW', # 随即对图片的高和宽转置 keys=['lq', 'gt'], # 需要 transpose 的图片 transpose_ratio=0.5 # Transpose ratio ), dict(type='Collect', # Pipeline that decides which keys in the data should be passed to the model keys=['lq', 'gt'], # Keys to pass to the model meta_keys=['lq_path', 'gt_path']), # Meta information keys. 训练时 meta information 不是必须的 dict(type='ToTensor', # 图片转为 tensor keys=['lq', 'gt']) # 需要转换为 tensor 的图片 ] test_pipeline = [ # Test pipeline dict( type='LoadImageFromFile', # 从文件读取图片 io_backend='disk', # io backend key='lq', # 找到结果对应路径的 keys flag='unchanged'), # flag for reading images dict( type='LoadImageFromFile', # 从文件读取图片 io_backend='disk', # io backend key='gt', # 找到结果对应路径的 keys flag='unchanged'), # flag for reading images dict(type='RescaleToZeroOne', keys=['lq', 'gt']), # 将图片从 [0, 255] 缩放到 [0, 1] dict( type='Normalize', # 对输入图片执行 normalization 的数据增强 pipeline keys=['lq', 'gt'], # 需要 normalized 图片 mean=[0, 0, 0], # Mean values std=[1, 1, 1], # Standard variance to_rgb=True), # 是否转为 rgb 格式 dict(type='Collect', # Pipeline that decides which keys in the data should be passed to the model keys=['lq', 'gt'], # Keys to pass to the model meta_keys=['lq_path', 'gt_path']), # Meta information keys dict(type='ToTensor', # 图片转为 tensor keys=['lq', 'gt']) # 需要转换为 tensor 的图片 ] ``` ```python train_pipeline = [ # train pipeline dict(type='LoadImageFromFile', # 从文件读取图片 key='img', # 找到结果对应路径的 keys color_type='color', # 图片的 color type channel_order='rgb', # 图片的 channel 顺序 imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # 从文件读取图片 key='gt', # 找到结果对应路径的 keys color_type='color', # 图片的 color type channel_order='rgb', # 图片的 channel 顺序 imdecode_backend='cv2'), # decode backend dict(type='SetValues', dictionary=dict(scale=scale)), # 设置 destination keys dict(type='PairedRandomCrop', gt_patch_size=96), # PairedRandomCrop dict(type='Flip', # 翻转图片 keys=['lq', 'gt'], # 需要翻转的图片 flip_ratio=0.5, # Flip ratio direction='horizontal'), # Flip 方向 dict(type='Flip', # Flip images keys=['lq', 'gt'], # 需要翻转的图片 flip_ratio=0.5, # Flip ratio direction='vertical'), # Flip 方向 dict(type='RandomTransposeHW', # 随即对图片的高和宽进行转置 keys=['lq', 'gt'], # 需要转置的图片 transpose_ratio=0.5 # Transpose ratio ), dict(type='PackInputs') # 在当前 pipeline 中收集数据的设置 ] test_pipeline = [ # Test pipeline dict(type='LoadImageFromFile', # 从文件读取图片 key='img', # 找到结果对应路径的 keys color_type='color', # 图片的 color type channel_order='rgb', # 图片的 channel order imdecode_backend='cv2'), # decode backend dict(type='LoadImageFromFile', # 从文件读取图片 key='gt', # 找到结果对应路径的 keys color_type='color', # 图片的 color type channel_order='rgb', # 图片的 channel order imdecode_backend='cv2'), # decode backend dict(type='PackInputs') # 在当前 pipeline 中收集数据的设置 ] ```
## Dataloader 在 MMagic 1.x 中我们更新了 dataloader 的设置方式,有以下几个重要的修改: - 原版本中的 `data` 字段分为了 `train_dataloader` , `val_dataloader` 和 `test_dataloader` 三个独立的部分。这样我们就可以细粒度的对各部分进行配置。例如用户就可以针对训练和测试制定不同的 sampler 和 batch size 。 - `samples_per_gpu` 更名为 `batch_size` 。 - `workers_per_gpu` 更名为 `num_workers` 。
原版本 新版本
```python data = dict( # train samples_per_gpu=16, # 每个 GPU 上的 batch_size workers_per_gpu=4, # 每个 GPU 上做 pre-fetch 的 worker 数 drop_last=True, # 在 data_loader 中使用 drop_last train=dict( # Train dataset 配置 type='RepeatDataset', # 对 iter-based 模型设置为 RepeatDataset times=1000, # RepeatDataset 的 repeated times 参数 dataset=dict( type=train_dataset_type, # 数据集类型 lq_folder='data/DIV2K/DIV2K_train_LR_bicubic/X2_sub', # lq 的文件路径 gt_folder='data/DIV2K/DIV2K_train_HR_sub', # ground truth 的文件路径 ann_file='data/DIV2K/meta_info_DIV2K800sub_GT.txt', # 标注文件的路径 pipeline=train_pipeline, # 参照 train_pipeline scale=scale)), # Upsampling 的 scale factor # validation val_samples_per_gpu=1, # validation 时每个 GPU 上的 batch_size val_workers_per_gpu=4, # validation 是每个 GPU 上做 pre-fetch 的 worker 数 val=dict( type=val_dataset_type, # 数据集类型 lq_folder='data/val_set5/Set5_bicLRx2', # lq 的文件路径 gt_folder='data/val_set5/Set5_mod12', # ground truth 的文件路径 pipeline=test_pipeline, # 参照 test_pipeline scale=scale, # Upsampling 的 scale factor filename_tmpl='{}'), # filename 模板 # test test=dict( type=val_dataset_type, # 数据集类型 lq_folder='data/val_set5/Set5_bicLRx2', # lq 的文件路径 gt_folder='data/val_set5/Set5_mod12', # ground truth 的文件路径 pipeline=test_pipeline, # 参照 test_pipeline scale=scale, # Upsampling 的 scale factor filename_tmpl='{}'), # filename 模板 ) ``` ```python dataset_type = 'BasicImageDataset' # 数据集类型 data_root = 'data' # 数据集根目录 train_dataloader = dict( batch_size=16, num_workers=4, # 每个 GPU 上做 pre-fetch 的 worker 数 persistent_workers=False, # 是否保持 workers instance 存活 sampler=dict(type='InfiniteSampler', shuffle=True), # data sampler 类型 dataset=dict( # 训练数据集 config type=dataset_type, # 数据集类型 ann_file='meta_info_DIV2K800sub_GT.txt', # 标注文件路径 metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # 数据根目录 data_prefix=dict( # 图像文件前缀 img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # Filename 模板 pipeline=train_pipeline)) val_dataloader = dict( batch_size=1, num_workers=4, # 每个 GPU 上做 pre-fetch 的 worker 数 persistent_workers=False, # 是否保持 workers instance 存活 drop_last=False, # 是否丢弃最后未完成的 batch sampler=dict(type='DefaultSampler', shuffle=False), # data sampler 类型 dataset=dict( # Validation 数据集设置 type=dataset_type, # 数据集类型 metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # 数据根目录 data_prefix=dict(img='LRbicx2', gt='GTmod12'), # 图像文件前缀 pipeline=test_pipeline)) test_dataloader = val_dataloader ```
================================================ FILE: docs/zh_cn/migration/distributed_train.md ================================================ # 分布式训练的迁移 我们已经将[MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x)合并至MMagic。以下是针对MMGeneration中分布式训练的迁移事项。 在0.x版中,MMGeneration使用`DDPWrapper`和`DynamicRunner`来训练对应的静态和动态模型(例如PGGAN和StyleGANv2),但在1.x 版中,我们使用MMEngine提供的`MMSeparateDistributedDataParallel`来实现分布式训练。 如下是配置前后对比:
0.x版中的静态模型 1.x版中的静态模型
```python # 使用DDPWrapper use_ddp_wrapper = True find_unused_parameters = False runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=False) ``` ```python model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=False) ```
0.x版中的动态模型 1.x版中的动态模型
```python use_ddp_wrapper = False find_unused_parameters = False # 使用DynamicRunner runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=True) ``` ```python model_wrapper_cfg = dict( type='MMSeparateDistributedDataParallel', broadcast_buffers=False, find_unused_parameters=True) # 针对动态模型,设置`find_unused_parameters`标志为True ```
================================================ FILE: docs/zh_cn/migration/eval_test.md ================================================ # 评估与测试设置的迁移 我们更新了 MMagic 1.x 中的评估设置,重要修改如下: - 评估字段被分为 `val_evaluator` 和 `test_evaluator` , `interval` 被移动到 `train_cfg.val_interval` 。 - 评估指标从 `test_cfg` 移至 `val_evaluator` 和 `test_evaluator`
原评估配置 新评估配置
```python train_cfg = None # 训练配置字典变量设为 None test_cfg = dict( # 测试配置字典变量 metrics=['PSNR'], # 测试期间使用的指标 PSNR (峰值信噪比) crop_border=scale) # 评估期间裁剪边框 evaluation = dict( # 构建评估钩子的配置字典变量 interval=5000, # 评价间隔 save_image=True, # 评估期间保存图像 gpu_collect=True) # 使用 GPU 收集 ``` ```python val_evaluator = [ dict(type='PSNR', crop_border=scale), # 要评估的指标名称 ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # 训练循环类型配置 val_cfg = dict(type='ValLoop') # 验证循环类型的名称 test_cfg = dict(type='TestLoop') # 测试循环类型的名称 ```
我们已将[MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x)合并到 MMagic 中. 这里是关于 MMGeneration 的评估和测试设置的迁移。 评估字段分为 `val_evaluator` 和 `test_evaluator` ,并且评估字段不再支持 `interval` 和 `save_best` 参数。 - `interval` 移至 `train_cfg.val_interval`,请参阅[调度设置](./schedule.md)。 - `save_best` 移至 `default_hooks.checkpoint.save_best`。
0.x 版本 1.x 新版本
```python evaluation = dict( type='GenerativeEvalHook', interval=10000, metrics=[ dict( type='FID', num_images=50000, bgr2rgb=True, inception_args=dict(type='StyleGAN')), dict(type='IS', num_images=50000) ], best_metric=['fid', 'is'], sample_kwargs=dict(sample_model='ema')) ``` ```python val_evaluator = dict( type='Evaluator', metrics=[ dict( type='FID', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig'), dict( type='IS', prefix='IS-50k', fake_nums=50000)]) # 设置最佳配置 default_hooks = dict( checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, less_keys=['FID-Full-50k/fid'], greater_keys=['IS-50k/is'], save_optimizer=True, save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) test_evaluator = val_evaluator ```
为了正确评估和测试模型,我们需要在 `val_cfg` 和 `test_cfg` 中设置特定的循环。
0.x 版本中的静态模型 1.x 版本中的静态模型
```python total_iters = 1000000 runner = dict( type='DynamicIterBasedRunner', is_dynamic_ddp=False, pass_training_status=True) ``` ```python train_cfg = dict( by_epoch=False, # 使用基于迭代的训练 max_iters=1000000, # 最大训练迭代次数 val_begin=1, val_interval=10000) # 评价间隔 val_cfg = dict(type='MultiValLoop') # 验证中的特定循环 test_cfg = dict(type='MultiTestLoop') # 测试中的特定循环 ```
================================================ FILE: docs/zh_cn/migration/models.md ================================================ # 模型的迁移 我们在 MMagic 1.x. 版本更新了模型设定,其中重要的改动如下所示: - 删除 `pretrained` 字段. - 在模型设定中添加 `train_cfg` 和 `test_cfg` 字段. - 添加 `data_preprocessor` 字段. 这里主要是将归一化和颜色空间转换操作从 `dataset transform` 流程中移动到 `data_preprocessor` 中. 我们接下来会介绍`data_preprocessor`.
Original New
```python model = dict( type='BasicRestorer', # Name of the model generator=dict( # Config of the generator type='EDSR', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pretrained=None, pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean')) # Config for pixel loss model training and testing settings ``` ```python model = dict( type='BaseEditModel', # Name of the model generator=dict( # Config of the generator type='EDSRNet', # Type of the generator in_channels=3, # Channel number of inputs out_channels=3, # Channel number of outputs mid_channels=64, # Channel number of intermediate features num_blocks=16, # Block number in the trunk network upscale_factor=scale, # Upsampling factor res_scale=1, # Used to scale the residual in residual block rgb_mean=(0.4488, 0.4371, 0.4040), # Image mean in RGB orders rgb_std=(1.0, 1.0, 1.0)), # Image std in RGB orders pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') # Config for pixel loss train_cfg=dict(), # Config of training model. test_cfg=dict(), # Config of testing model. data_preprocessor=dict( # The Config to build data preprocessor type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) ```
我们在 MMagic 1.x. 版本中对模型进行了重构,其中重要的改动如下所示: - MMagic 1.x 中的 `models` 被重构为六个部分:`archs`、`base_models`、`data_preprocessors`、`editors`、`diffusion_schedulers` 和 `losses`. - 在 `models` 中添加了 `data_preprocessor` 模块。这里主要是将归一化和颜色空间转换操作从 `dataset transform` 流程中移动到 `data_preprocessor` 中.此时,数据流经过数据预处理后,会先经过 `data_preprocessor` 模块的转换,然后再输入到模型中. 模型的更多详细信息请参见[模型指南](../howto/models.md). ================================================ FILE: docs/zh_cn/migration/optimizers.md ================================================ # 优化器的迁移 我们已经将[MMGeneration 1.x](https://github.com/open-mmlab/mmgeneration/tree/1.x)合并至MMagic。以下是针对MMGeneration中优化器的迁移事项。 在0.x版中,MMGeneration使用PyTorch自带的优化器,其只提供了通用参数优化,而在1.x版中,我们则使用了MMEngine提供的`OptimizerWrapper`。 对比PyTorch自带的`Optimizer`,`OptimizerWrapper`可以支持如下功能: - `OptimizerWrapper.update_params`在一个单一的函数中就实现了`zero_grad`,`backward`和`step` - 支持梯度自动累积 - 提供一个名为`OptimizerWrapper.optim_context`的上下文管理器来封装前向进程,`optim_context`会根据当前更新迭代数目来自动调用`torch.no_sync`,在AMP(Auto Mixed Precision)训练中,`autocast`也会在`optim_context`中被调用。 对GAN模型,生成器和鉴别器采用不同的优化器和训练策略。要使GAN模型的`train_step`函数签名和其它模型的保持一致,我们使用从`OptimizerWrapper`继承下来的`OptimWrapperDict`来封装生成器和鉴别器的优化器,为了便于该流程的自动化MMagic实现了`MultiOptimWrapperContructor`构造器。如你想训练GAN模型,那么应该在你的配置中指定该构造器。 如下是0.x版和1.x版的配置对比
0.x版 1.x版
```python optimizer = dict( generator=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6), discriminator=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6)) ``` ```python optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) ```
> 注意,在1.x版中,MMGeneration使用`OptimWrapper`来实现梯度累加,这就会导致在0.x版和1.x版之间,`discriminator_steps`配置(用于在多次更新鉴别器之后更新一次生成器的训练技巧)与梯度累加均出现不一致问题。 - 在0.x版中,我们在配置里使用`disc_steps`,`gen_steps`和`batch_accumulation_steps` 。`disc_steps`和`batch_accumulation_steps`会根据`train_step`的调用次数来进行统计(亦即dataloader中数据的读取次数)。因此鉴别器的一段连续性更新次数为`disc_steps // batch_accumulation_steps`。且对于生成器,`gen_steps`是生成器实际的一段连续性更新次数 - 但在1.x版中,我们在配置里则使用了`discriminator_steps`,`generator_steps` 和`accumulative_counts`。`discriminator_steps`和`generator_steps`指的是自身在更新其它模型之前的一段连续性的更新次数 以BigGAN-128配置为例。
0.x版 1.x版
```python model = dict( type='BasiccGAN', generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True), gan_loss=dict(type='GANLoss', gan_type='hinge')) # 连续性更新鉴别器`disc_steps // batch_accumulation_steps = 8 // 8 = 1`次 # 连续性更新生成器`gen_steps = 1`次 # 生成器与鉴别器在每次更新之前执行`batch_accumulation_steps = 8`次梯度累加 train_cfg = dict( disc_steps=8, gen_steps=1, batch_accumulation_steps=8, use_ema=True) ``` ```python model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, init_type='ortho', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True), # 连续性更新鉴别器`discriminator_steps = 1`次 # 连续性更新生成器`generator_steps = 1`次 generator_steps=1, discriminator_steps=1) optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( # 生成器在每次更新之前执行`accumulative_counts = 8`次梯度累加 accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( # 鉴别器在每次更新之前执行`accumulative_counts = 8`次梯度累加 accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) ```
================================================ FILE: docs/zh_cn/migration/overview.md ================================================ # 概览 本节将从以下几个方面介绍如何从 MMEditing 0.x 迁移至 MMagic 1.x: - [概览](#概览) - [新依赖项](#新依赖项) - [总体结构](#总体结构) - [其他配置设置](#其他配置设置) ## 新依赖项 MMagic 1.x 依赖于一些新的包,您可以按照[安装教程](../get_started/install.md)准备一个新的干净环境并重新安装。 ## 总体结构 我们在 MMagic 1.x 中对总体结构进行了重构,具体如下: - 旧版本 MMEdit 中的 `core` 被拆分为 `engine`、`evaluation`、`structures` 和 `visualization` - 旧版本 MMEdit 中 `datasets` 的 `pipelines` 被重构为 `transforms` - MMagic 1.x 中的 `models` 被重构为六个部分:`archs`、`base_models`、`data_preprocessors`、`editors`、`diffusion_schedulers` 和 `losses`。 ## 其他配置设置 我们将配置文件重命名为新模板:`{model_settings}_{module_setting}_{training_setting}_{datasets_info}`。 更多配置细节请参见[配置指南](../user_guides/config.md)。 ================================================ FILE: docs/zh_cn/migration/runtime.md ================================================ # 运行设置的迁移 我们更新了 MMagic 1.x 中的运行设置,重要修改如下: - `checkpoint_config` 被移动到 `default_hooks.checkpoint`,`log_config` 被移动到 `default_hooks.logger`。 我们将许多 hooks 设置从脚本代码移动到运行配置的 `default_hooks` 字段中。 - `resume_from` 被移除,使用 `resume` 替代它。 - 如果 resume=True 并且 load_from 不是 None, 则从load_from中的检查点恢复训练。 - 如果 resume=True 且 load_from 为 None,则尝试从工作目录中的最新检查点恢复。 - 如果 resume=False 且 load_from 不为None,则仅加载检查点,不恢复训练。 - 如果 resume=False 且 load_from 为 None,则不加载也不恢复。 - `dist_params` 字段现在是 `env_cfg` 的一个子字段。 并且在 `env_cfg` 还有一些新的配置。 - `workflow` 相关功能已被删除。 - 新字段 `visualizer`: 可视化工具是一个新设计。在 runner 中使用可视化器实例来处理结果和日志可视化并保存到不同的后端,例如 Local、TensorBoard 和 Wandb。 - 新字段 `default_scope`: 所有注册器搜索 module 的起点。
原始配置 新的配置
```python checkpoint_config = dict( # 设置检查点 hook 的配置, 参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py 完成的 interval=5000, # 保存间隔为 5000 次迭代 save_optimizer=True, # 也保存优化器 by_epoch=False) # 通过 iterations 计数 log_config = dict( # 注册日志 hook 的配置 interval=100, # 打印日志的间隔 hooks=[ dict(type='TextLoggerHook', by_epoch=False), # logger 用来记录训练过程 dict(type='TensorboardLoggerHook'), # 也支持 Tensorboard logger ]) visual_config = None # 可视化配置,我们不使用它。 # runtime settings dist_params = dict(backend='nccl') # 设置分布式训练的参数,还可以设置端口 log_level = 'INFO' # 日志等级 load_from = None # 从指定路径加载预训练模型,这不会恢复训练 resume_from = None # 从给定路径恢复检查点,训练将从保存检查点的epoch开始恢复 workflow = [('train', 1)] # Runner 的工作流程. [('train', 1)] 意味着只有一个工作流,并且名为“train”的工作流执行一次。 在训练当前的抠图模型时,请保持此项不变 ``` ```python default_hooks = dict( # 用来创建默认 hooks checkpoint=dict( # 设置 checkpoint hook 的配置 type='CheckpointHook', interval=5000, # 保存间隔为5000次迭代 save_optimizer=True, by_epoch=False, # 通过 iterations 计数 out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # 注册 logger hook 的配置 param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) default_scope = 'mmedit' # 用来设置注册位置 env_cfg = dict( # 设置分布式训练的参数,还可以设置端口 cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # 日志等级 log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # 用来创建日志处理器 load_from = None # 从指定路径加载预训练模型,这不会恢复训练 resume = False # 从给定路径恢复检查点,训练将从保存检查点的epoch开始恢复 ```
================================================ FILE: docs/zh_cn/migration/schedule.md ================================================ # 调度器的迁移 我们更新了MMagic 1.x 中的调度器设置,重要修改如下: - 现在我们使用 `optim_wrapper` 字段来指定关于优化过程的所有配置。`optimizer` 字段现在是 `optim_wrapper` 的一个子字段。 - `lr_config` 字段被移除,我们使用新的 `param_scheduler` 来代替它。 - `total_iters` 字段已移至 `train_cfg`,作为 `max_iters`, `val_cfg` 和 `test_cfg`,用于配置训练、验证和测试中的循环。
Original New
```python optimizers = dict(generator=dict(type='Adam', lr=1e-4, betas=(0.9, 0.999))) # 用于构建优化器的配置,支持 PyTorch 中的所有优化器,其参数与 PyTorch 中的参数相同。 total_iters = 300000 # 总训练迭代次数 lr_config = dict( # 用于注册 LrUpdater hook 的学习率调度器配置 policy='Step', by_epoch=False, step=[200000], gamma=0.5) # 调度器的策略 ``` ```python optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4), ) ) # 用于构建优化器的配置,支持 PyTorch 中的所有优化器,其参数与 PyTorch 中的参数相同。 param_scheduler = dict( # 学习策略的配置 type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) # 调度器的策略 train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # 训练循环类型的配置 val_cfg = dict(type='ValLoop') # 验证循环类型的名称 test_cfg = dict(type='TestLoop') # 测试循环类型的名称 ```
> 有关调度器设置的更多详细信息可在 [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/migration/param_scheduler.md) 中找到。 ================================================ FILE: docs/zh_cn/migration/visualization.md ================================================ # 可视化的迁移 在0.x版中,MMEditing使用`VisualizationHook`来对训练过程中生成的结果进行可视化,在1.x版中,我们将该功能整合到`BasicVisualizationHook` / `VisualizationHook`中,而且遵循MMEngine的设计,我们实现了`ConcatImageVisualizer` / `Visualizer`和一系列`VisBackend`来绘制和保存可视化结果。
0.x版 1.x版
```python visual_config = dict( type='VisualizationHook', output_dir='visual', interval=1000, res_name_list=['gt_img', 'masked_img', 'fake_res', 'fake_img'], ) ``` ```python vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ```
要了解更多关于可视化的功能,请参阅[这个教程](../user_guides/visualization.md)。 ================================================ FILE: docs/zh_cn/stat.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. import functools as func import glob import re from os.path import basename, splitext import numpy as np import titlecase def anchor(name): return re.sub(r'-+', '-', re.sub(r'[^a-zA-Z0-9\+]', '-', name.strip().lower())).strip('-') # Count algorithms files = sorted(glob.glob('*_models.md')) # files = sorted(glob.glob('docs/*_models.md')) stats = [] for f in files: with open(f, 'r') as content_file: content = content_file.read() # title title = content.split('\n')[0].replace('#', '') # count papers papers = set( (papertype, titlecase.titlecase(paper.lower().strip()).replace('+', r'\+')) for (papertype, paper) in re.findall( r'\s*\n.*?\btitle\s*=\s*{(.*?)}', content, re.DOTALL)) # paper links revcontent = '\n'.join(list(reversed(content.splitlines()))) paperlinks = {} for _, p in papers: print(p) paperlinks[p] = ' '.join( (f'[⇨]({splitext(basename(f))[0]}.html#{anchor(paperlink)})' for paperlink in re.findall( rf'\btitle\s*=\s*{{\s*{p}\s*}}.*?\n## (.*?)\s*[,;]?\s*\n', revcontent, re.DOTALL | re.IGNORECASE))) print(' ', paperlinks[p]) paperlist = '\n'.join( sorted(f' - [{t}] {x} ({paperlinks[x]})' for t, x in papers)) # count configs configs = set(x.lower().strip() for x in re.findall(r'https.*configs/.*\.py', content)) # count ckpts ckpts = set(x.lower().strip() for x in re.findall(r'https://download.*\.pth', content) if 'mmedit' in x) statsmsg = f""" ## [{title}]({f}) * 模型权重文件数量: {len(ckpts)} * 配置文件数量: {len(configs)} * 论文数量: {len(papers)} {paperlist} """ stats.append((papers, configs, ckpts, statsmsg)) allpapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _, _ in stats]) allconfigs = func.reduce(lambda a, b: a.union(b), [c for _, c, _, _ in stats]) allckpts = func.reduce(lambda a, b: a.union(b), [c for _, _, c, _ in stats]) # Summarize msglist = '\n'.join(x for _, _, _, x in stats) papertypes, papercounts = np.unique([t for t, _ in allpapers], return_counts=True) countstr = '\n'.join( [f' - {t}: {c}' for t, c in zip(papertypes, papercounts)]) modelzoo = f""" # 总览 * 模型权重文件数量: {len(allckpts)} * 配置文件数量: {len(allconfigs)} * 论文数量: {len(allpapers)} {countstr} 有关支持的数据集,请参阅 [数据集总览](datasets.md)。 {msglist} """ with open('modelzoo.md', 'w') as f: f.write(modelzoo) # Count datasets files = sorted(glob.glob('*_datasets.md')) datastats = [] for f in files: with open(f, 'r') as content_file: content = content_file.read() # title title = content.split('\n')[0].replace('#', '') # count papers papers = set( (papertype, titlecase.titlecase(paper.lower().strip()).replace('+', r'\+')) for (papertype, paper) in re.findall( r'\s*\n.*?\btitle\s*=\s*{(.*?)}', content, re.DOTALL)) # paper links revcontent = '\n'.join(list(reversed(content.splitlines()))) paperlinks = {} for _, p in papers: print(p) paperlinks[p] = ', '.join( (f'[{p} ⇨]({splitext(basename(f))[0]}.html#{anchor(p)})' for p in re.findall( rf'\btitle\s*=\s*{{\s*{p}\s*}}.*?\n## (.*?)\s*[,;]?\s*\n', revcontent, re.DOTALL | re.IGNORECASE))) print(' ', paperlinks[p]) paperlist = '\n'.join( sorted(f' - [{t}] {x} ({paperlinks[x]})' for t, x in papers)) # count configs configs = set(x.lower().strip() for x in re.findall(r'https.*configs/.*\.py', content)) # count ckpts ckpts = set(x.lower().strip() for x in re.findall(r'https://download.*\.pth', content) if 'mmedit' in x) statsmsg = f""" ## [{title}]({f}) * 论文数量: {len(papers)} {paperlist} """ datastats.append((papers, configs, ckpts, statsmsg)) alldatapapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _, _ in datastats]) # Summarize msglist = '\n'.join(x for _, _, _, x in stats) datamsglist = '\n'.join(x for _, _, _, x in datastats) papertypes, papercounts = np.unique([t for t, _ in alldatapapers], return_counts=True) countstr = '\n'.join( [f' - {t}: {c}' for t, c in zip(papertypes, papercounts)]) modelzoo = f""" # 总览 * 论文数量: {len(alldatapapers)} {countstr} 有关支持的算法, 可参见 [模型总览](modelzoo.md). {datamsglist} """ with open('datasets.md', 'w') as f: f.write(modelzoo) ================================================ FILE: docs/zh_cn/switch_language.md ================================================ ## English ## 简体中文 ================================================ FILE: docs/zh_cn/user_guides/config.md ================================================ # 教程1 了解MMagic的配置文件 我们在我们的配置系统中采用了模块化和继承设计,方便进行各种实验。 如果您希望查看配置文件,您可以运行 `python tools/misc/print_config.py /PATH/TO/CONFIG` 来查看完整的配置。 您可以根据以下教程了解我们配置系统的使用方法。 - [教程1:了解MMagic中的配置](#教程1-了解MMagic的配置文件) - [通过脚本参数修改配置](#通过脚本参数修改配置) - [配置文件结构](#配置文件结构) - [配置文件命名风格](#配置文件命名风格) - [EDSR的示例](#EDSR的示例) - [模型配置](#模型配置) - [数据配置](#数据配置) - [数据流程](#数据流程) - [数据加载器](#数据加载器) - [评估配置](#评估配置) - [训练和测试配置](#训练和测试配置) - [优化配置](#优化配置) - [钩子配置](#钩子配置) - [运行时配置](#运行时配置) - [StyleGAN2的示例](#StyleGAN2的示例) - [模型配置](#模型配置) - [数据集和评估器配置](#数据集和评估器配置) - [训练和测试配置](#训练和测试配置-1) - [优化配置](#优化配置-1) - [钩子配置](#钩子配置-1) - [运行时配置](#运行时配置-1) - [其他示例](#其他示例) - [修复任务的配置示例](#修复任务的配置示例) - [抠图任务的配置示例](#抠图任务的配置示例) - [恢复任务的配置示例](#恢复任务的配置示例) ## 通过脚本参数修改配置 使用 `tools/train.py`或 `tools/test.py` 来运行时,您可以通过指定 `--cfg-options` 来临时修改配置。 - 更新字典链中的配置键 可以按照原始配置中字典键的顺序指定配置选项。例如,`--cfg-options test_cfg.use_ema=False` 将默认的采样模型更改为原始生成器,`--cfg-options train_dataloader.batch_size=8` 将训练数据加载器的批大小更改为8。 - 更新配置列表中的键 您的配置中有些配置字典是作为列表组成的。例如,训练流程 `train_dataloader.dataset.pipeline` 通常是一个列表,例如 `[dict(type='LoadImageFromFile'), ...]`。如果您想要在流程中将 `'LoadImageFromFile'` 更改为 `'LoadImageFromWebcam'`,可以指定 `--cfg-options train_dataloader.dataset.pipeline.0.type=LoadImageFromWebcam` 。训练流程 `train_pipeline` 通常也是一个列表,例如 `[dict(type='LoadImageFromFile'), ...]` 。如果您想要将 `'LoadImageFromFile'` 更改为 `'LoadMask'`,可以指定 `--cfg-options train_pipeline.0.type=LoadMask`。 - 更新列表/元组的值 如果要更新的值是列表或元组,您可以设置 `--cfg-options key="[a,b]"` 或 `--cfg-options key=a,b` 。它还允许嵌套的列表/元组值,例如 `--cfg-options key="[(a,b),(c,d)]"`。请注意,为了支持列表/元组数据类型,引号 `"` 是必需的,并且在指定的值内引号之间不允许有空格。 ## 配置文件结构 在`config/_base_` 目录下有三种基本组件类型:数据集(datasets)、模型(models)和默认运行时(default_runtime)。许多方法都可以通过使用其中的每种组件之一进行简单构建,例如AOT-GAN、EDVR、GLEAN、StyleGAN2、CycleGAN、SinGAN等。由`_base_` 组件组成的配置被称为原始配置。 对于同一文件夹下的所有配置文件,建议只有**一个**原始配置。所有其他配置文件都应该继承自原始配置。同时,最大的继承层级为3。 为了便于理解,我们建议贡献者从现有方法中继承。例如,如果基于BasicVSR进行了某些修改,用户可以通过在配置文件中指定`_base_ = ../basicvsr/basicvsr_reds4.py` 来首先继承基本的BasicVSR结构,然后修改配置文件中的必要字段。如果基于StyleGAN2进行了某些修改,用户可以通过在配置文件中指定`_base_ = ../styleganv2/stylegan2_c2_ffhq_256_b4x8_800k.py` 来首先继承基本的StyleGAN2结构,然后修改配置文件中的必要字段。 如果您正在构建一种完全不与任何现有方法共享结构的全新方法,您可以在`configs`目录下创建一个名为`xxx`的文件夹。 详细的文档请参考[MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md)。 ## 配置文件命名风格 配置文件按照下面的风格命名。我们建议社区贡献者使用同样的风格。 ``` {model}_[module setting]_{training schedule}_{dataset} ``` `{xxx}` 是必填字段,`[yyy]` 是可选字段。 - `{model}`:模型类型,如 `stylegan`、`dcgan`、`basicvsr`、`dim` 等。原始论文中提到的设置也包含在此字段中(例如 `Stylegan2-config-f`、`edvrm` 的 `edvrm_8xb4-600k_reds`)。 - `[module setting]`:某些模块的具体设置,包括 Encoder、Decoder、Generator、Discriminator、Normalization、loss、Activation 等。例如 `c64n7` 的 `basicvsr-pp_c64n7_8xb1-600k_reds4`,dcgan 的学习率 `Glr4e-4_Dlr1e-4`,stylegan3 的 `gamma32.8`,sagan 中的 `woReLUInplace`。在这个部分,来自不同子模块(例如 generator 和 discriminator)的信息用 `_` 连接起来。 - `{training_scheduler}`:训练的特定设置,包括批量大小、训练计划等。例如,学习率(例如 `lr1e-3`),使用的 GPU 数量和批量大小(例如 `8xb32`),总迭代次数(例如 `160kiter`)或在 discriminator 中显示的图像数量(例如 `12Mimgs`)。 - `{dataset}`:数据集名称和数据大小信息,例如 `deepfillv1_4xb4_celeba-256x256` 的 `celeba-256x256`,`basicvsr_2xb4_reds4` 的 `reds4`,`ffhq`,`lsun-car`,`celeba-hq`。 ## EDSR的示例 为了帮助用户对完整的配置文件有一个基本的了解,我们对我们实现的[EDSR模型的配置文件](https://github.com/open-mmlab/mmagic/blob/main/configs/edsr/edsr_x2c64b16_g1_300k_div2k.py) 进行简要说明,如下所示。关于每个模块的更详细用法和相应的替代方案,请参考API文档和[MMEngine中的教程](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md)。 ### 模型配置 在MMagic的配置文件中,我们使用 `model` 字段来设置模型。 ```python model = dict( type='BaseEditModel', # 模型的名称 generator=dict( # 生成器的配置 type='EDSRNet', # 生成器的类型 in_channels=3, # 输入的通道数 out_channels=3, # 输出的通道数 mid_channels=64, # 中间特征的通道数 num_blocks=16, # 主干网络中的块数 upscale_factor=scale, # 上采样因子 res_scale=1, # 用于缩放残差块中的残差 rgb_mean=(0.4488, 0.4371, 0.4040), # RGB图像的均值 rgb_std=(1.0, 1.0, 1.0)), # RGB图像的标准差 pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), # 配置像素损失 train_cfg=dict(), # 训练模型的配置 test_cfg=dict(), # 测试模型的配置 data_preprocessor=dict( # 数据预处理器的配置 type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.]) ) ``` ### 数据配置 训练、验证和测试[运行器(runner)](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html) 都需要使用[数据加载器(Dataloader)](https://pytorch.org/docs/stable/data.html?highlight=data%20loader#torch.utils.data.DataLoader)。 为了构建数据加载器,需要设置数据集(Dataset)和数据处理流程(data pipeline)。 由于这部分的复杂性,我们使用中间变量来简化数据加载器配置的编写。 #### 数据流程 ```python train_pipeline = [ # 训练数据处理流程 dict(type='LoadImageFromFile', # 从文件中加载图像 key='img', # 在结果中查找对应路径的键名 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='LoadImageFromFile', # 从文件中加载图像 key='gt', # 在结果中查找对应路径的键名 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='SetValues', dictionary=dict(scale=scale)), # 将值设置给目标键名 dict(type='PairedRandomCrop', gt_patch_size=96), # 随机裁剪成配对图像 dict(type='Flip', # 翻转图像 keys=['lq', 'gt'], # 需要翻转的图像键名 flip_ratio=0.5, # 翻转比例 direction='horizontal'), # 翻转方向 dict(type='Flip', # 翻转图像 keys=['lq', 'gt'], # 需要翻转的图像键名 flip_ratio=0.5, # 翻转比例 direction='vertical'), # 翻转方向 dict(type='RandomTransposeHW', # 随机交换图像的宽高 keys=['lq', 'gt'], # 需要交换的图像键名 transpose_ratio=0.5 # 交换比例 ), dict(type='PackInputs') # 从当前处理流程中收集数据的配置 ] test_pipeline = [ # 测试数据处理流程 dict(type='LoadImageFromFile', # 从文件中加载图像 key='img', # 在结果中查找对应路径的键名 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='LoadImageFromFile', # 从文件中加载图像 key='gt', # 在结果中查找对应路径的键名 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='PackInputs') # 从当前处理流程中收集数据的配置 ] ``` #### 数据加载器 ```python dataset_type = 'BasicImageDataset' # 数据集的类型 data_root = 'data' # 数据的根路径 train_dataloader = dict( num_workers=4, # 每个 GPU 预取数据的工作进程数 persistent_workers=False, # 是否保持工作进程中的数据集实例处于活动状态 sampler=dict(type='InfiniteSampler', shuffle=True), # 数据采样器的类型 dataset=dict( # 训练数据集配置 type=dataset_type, # 数据集的类型 ann_file='meta_info_DIV2K800sub_GT.txt', # 注释文件的路径 metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # 数据的根路径 data_prefix=dict( # 图像路径的前缀 img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # 文件名模板 pipeline=train_pipeline) ) val_dataloader = dict( num_workers=4, # 每个 GPU 预取数据的工作进程数 persistent_workers=False, # 是否保持工作进程中的数据集实例处于活动状态 drop_last=False, # 是否丢弃最后一个不完整的批次 sampler=dict(type='DefaultSampler', shuffle=False), # 数据采样器的类型 dataset=dict( # 验证数据集配置 type=dataset_type, # 数据集的类型 metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # 数据的根路径 data_prefix=dict(img='LRbicx2', gt='GTmod12'), # 图像路径的前缀 pipeline=test_pipeline) ) test_dataloader = val_dataloader ``` ### 评估配置 [评估器](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html)用于计算在验证集和测试集上训练模型的指标。 评估器的配置包括一个或多个指标配置: ```python val_evaluator = [ dict(type='MAE'), # 要评估的指标名称 dict(type='PSNR', crop_border=scale), # 要评估的指标名称 dict(type='SSIM', crop_border=scale), # 要评估的指标名称 ] test_evaluator = val_evaluator # 测试评估器的配置与验证评估器相同 ``` ### 训练和测试配置 MMEngine的运行器使用Loop来控制训练、验证和测试过程。 用户可以使用这些字段设置最大训练迭代次数和验证间隔。 ```python train_cfg = dict( type='IterBasedTrainLoop', # 训练循环类型的名称 max_iters=300000, # 总迭代次数 val_interval=5000, # 验证间隔迭代次数 ) val_cfg = dict(type='ValLoop') # 验证循环类型的名称 test_cfg = dict(type='TestLoop') # 测试循环类型的名称 ``` ### 优化配置 `optim_wrapper`是用于配置优化相关设置的字段。 优化器包装器不仅提供优化器的功能,还支持梯度裁剪、混合精度训练等功能。在[optimizer wrapper教程](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html) 中可以了解更多信息。 ```python optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) # 用于构建优化器的配置,支持所有与PyTorch中参数相同的优化器。 ``` `param_scheduler`是一个配置优化超参数(如学习率和动量)调整方法的字段。 用户可以结合多个调度器来创建所需的参数调整策略。 在[parameter scheduler教程](https://mmengine.readthedocs.io/en/latest/tutorials/param_scheduler.html)中可以了解更多信息。 ```python param_scheduler = dict( # 学习策略的配置 type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) ``` ### 钩子配置 用户可以将钩子(hooks)附加到训练、验证和测试循环中,在运行过程中插入一些操作。有两个不同的钩子字段,一个是`default_hooks` ,另一个是`custom_hooks`。 `default_hooks`是一个包含钩子配置的字典。`default_hooks` 是运行时必需的钩子,它们具有默认的优先级,不应修改。如果未设置,默认值将被使用。要禁用默认钩子,用户可以将其配置设置为`None`。 ```python default_hooks = dict( # 用于构建默认钩子的配置 checkpoint=dict( # 配置检查点钩子 type='CheckpointHook', interval=5000, # 保存间隔为5000次迭代 save_optimizer=True, by_epoch=False, # 以迭代次数计数 out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # 配置注册日志钩子 param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) ``` `custom_hooks`是一个钩子配置的列表。用户可以开发自己的钩子并将其插入到该字段中。 ```python custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] # 可视化钩子的配置 ``` ### 运行时配置 ```python default_scope = 'mmagic' # 用于设置注册表位置 env_cfg = dict( # 设置分布式训练的参数,端口也可以设置 cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # 日志记录的级别 log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # 用于构建日志处理器 load_from = None # 从给定路径加载模型作为预训练模型。这不会恢复训练。 resume = False # 从给定路径恢复检查点,训练将从检查点保存的时期继续。 ``` ## StyleGAN2的示例 以[Stylegan2 在 1024x1024 分辨率上的配置文件](https://github.com/open-mmlab/mmagic/blob/main/configs//styleganv2/stylegan2_c2_8xb4-fp16-global-800kiters_quicktest-ffhq-256x256.py) 为例,我们根据不同的功能模块介绍配置中的各个字段。 ### 模型配置 除了包括生成器、鉴别器等神经网络组件之外,还需要`data_preprocessor`、`loss_config`等字段,其中一些还包含`ema_config`。 `data_preprocessor`负责处理数据加载器输出的一个批次数据。 `loss_config`负责设置损失项的权重。 `ema_config`负责为生成器执行指数移动平均(EMA)操作。 ```python model = dict( type='StyleGAN2', # 模型的名称 data_preprocessor=dict(type='DataPreprocessor'), # 数据预处理器的配置,通常包括图像归一化和填充 generator=dict( # 生成器的配置 type='StyleGANv2Generator', # 生成器的名称 out_size=1024, # 生成器的输出分辨率 style_channels=512), # 生成器的风格通道数 discriminator=dict( # 鉴别器的配置 type='StyleGAN2Discriminator', # 鉴别器的名称 in_size=1024), # 鉴别器的输入分辨率 ema_config=dict( # EMA的配置 type='ExponentialMovingAverage', # 平均模型的具体类型 interval=1, # EMA操作的间隔 momentum=0.9977843871238888), # EMA操作的动量 loss_config=dict( # 损失项的配置 r1_loss_weight=80.0, # r1梯度惩罚的权重 r1_interval=16, # r1梯度惩罚的间隔 norm_mode='HWC', # r1梯度惩罚的归一化模式 g_reg_interval=4, # 生成器的正则化间隔 g_reg_weight=8.0, # 生成器的正则化权重 pl_batch_shrink=2)) # 路径长度正则化中缩减批次大小的因子 ``` ### 数据集和评估器配置 训练、验证和测试[runner](https://mmengine.readthedocs.io/en/latest/tutorials/runner.html) 需要使用数据加载器[Dataloaders](https://pytorch.org/docs/stable/data.html?highlight=data%20loader#torch.utils.data.DataLoader)。 需要设置数据集和数据处理流程来构建数据加载器。由于这部分的复杂性,我们使用中间变量来简化数据加载器配置的编写。 ```python dataset_type = 'BasicImageDataset' # 数据集类型,将用于定义数据集 data_root = './data/ffhq/' # 数据的根目录 train_pipeline = [ # 训练数据处理流程 dict(type='LoadImageFromFile', key='img'), # 第一个处理流程,从文件路径加载图像 dict(type='Flip', keys=['img'], direction='horizontal'), # 图像翻转的数据增强处理流程 dict(type='PackInputs', keys=['img']) # 最后一个处理流程,格式化注释数据(如果有)并决定哪些键应该打包到data_samples中 ] val_pipeline = [ dict(type='LoadImageFromFile', key='img'), # 第一个处理流程,从文件路径加载图像 dict(type='PackInputs', keys=['img']) # 最后一个处理流程,格式化注释数据(如果有)并决定哪些键应该打包到data_samples中 ] train_dataloader = dict( # 训练数据加载器的配置 batch_size=4, # 单个GPU的批次大小 num_workers=8, # 每个单个GPU的数据预取工作线程数 persistent_workers=True, # 如果为True,则数据加载器将在一个epoch结束后不会关闭工作进程,这可以加速训练速度。 sampler=dict( # 训练数据采样器的配置 type='InfiniteSampler', # 用于迭代训练的InfiniteSampler。参考 https://github.com/open-mmlab/mmengine/blob/fe0eb0a5bbc8bf816d5649bfdd34908c258eb245/mmengine/dataset/sampler.py#L107 shuffle=True), # 是否随机打乱训练数据 dataset=dict( # 训练数据集的配置 type=dataset_type, data_root=data_root, pipeline=train_pipeline)) val_dataloader = dict( # 验证数据加载器的配置 batch_size=4, # 单个GPU的批次大小 num_workers=8, # 每个单个GPU的数据预取工作线程数 dataset=dict( # 验证数据集的配置 type=dataset_type, data_root=data_root, pipeline=val_pipeline), sampler=dict( # 验证数据采样器的配置 type='DefaultSampler', # 支持分布式和非分布式训练的DefaultSampler。参考 https://github.com/open-mmlab/mmengine/blob/fe0eb0a5bbc8bf816d5649bfdd34908c258eb245/mmengine/dataset/sampler.py#L14 shuffle=False), # 是否随机打乱验证数据 persistent_workers=True) test_dataloader = val_dataloader # 测试数据加载器的配置与验证数据加载器相同 ``` [评估器](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html)用于计算在验证和测试数据集上训练模型的指标。 评估器的配置由一个或多个指标配置组成: ```python val_evaluator = dict( # 验证评估器的配置 type='Evaluator', # 评估类型 metrics=[ # 指标的配置 dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ]) test_evaluator = val_evaluator # 测试评估器的配置与验证评估器相同 ``` ### 训练和测试配置 MMEngine的runner使用Loop来控制训练、验证和测试过程。 用户可以使用以下字段设置最大训练迭代次数和验证间隔: ```python train_cfg = dict( # 训练配置 by_epoch=False, # 设置`by_epoch`为False以使用基于迭代的训练 val_begin=1, # 开始验证的迭代次数 val_interval=10000, # 验证间隔 max_iters=800002) # 最大训练迭代次数 val_cfg = dict(type='MultiValLoop') # 验证循环类型 test_cfg = dict(type='MultiTestLoop') # 测试循环类型 ``` ### 优化配置 `optim_wrapper`是配置优化相关设置的字段。 优化器包装器不仅提供优化器的功能,还支持梯度裁剪、混合精度训练等功能。在[optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html) 中可以找到更多信息。 ```python optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( optimizer=dict(type='Adam', lr=0.0016, betas=(0, 0.9919919678228657))), discriminator=dict( optimizer=dict( type='Adam', lr=0.0018823529411764706, betas=(0, 0.9905854573074332)))) ``` `param_scheduler`是一个配置优化超参数(如学习率和动量)调整方法的字段。 用户可以组合多个调度器来创建所需的参数调整策略。 在[parameter scheduler tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/param_scheduler.html)中可以找到更多信息。 由于StyleGAN2不使用参数调度器,我们以[CycleGAN](https://github.com/open-mmlab/mmagic/blob/main/configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) 的配置作为示例: ```python # CycleGAN配置中的参数调度器 param_scheduler = dict( type='LinearLrInterval', # 调度器的类型 interval=400, # 更新学习率的间隔 by_epoch=False, # 调度器按迭代调用 start_factor=0.0002, # 在第一次迭代中乘以参数值的数值 end_factor=0, # 在线性变化过程结束时乘以参数值的数值 begin=40000, # 调度器的起始迭代次数 end=80000) # 调度器的结束迭代次数 ``` ### 钩子配置 用户可以在训练、验证和测试循环中附加钩子,以在运行过程中插入一些操作。这里有两个不同的钩子字段,一个是`default_hooks` ,另一个是`custom_hooks`。 `default_hooks`是一个钩子配置的字典。`default_hooks` 是在运行时必须的钩子。它们具有默认的优先级,不应该被修改。如果没有设置,运行器将使用默认值。要禁用一个默认钩子,用户可以将其配置设置为`None`。 ```python default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100, log_metric_by_epoch=False), checkpoint=dict( type='CheckpointHook', interval=10000, by_epoch=False, less_keys=['FID-Full-50k/fid'], greater_keys=['IS-50k/is'], save_optimizer=True, save_best='FID-Full-50k/fid')) ``` `custom_hooks` 是一个钩子配置的列表。用户可以开发自己的钩子并将它们插入到这个字段中。 ```python custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ``` ### 运行时配置 ```python default_scope = 'mmagic' # 默认的注册表作用域,用于查找模块。参考 https://mmengine.readthedocs.io/en/latest/advanced_tutorials/registry.html # 环境配置 env_cfg = dict( cudnn_benchmark=True, # 是否启用cudnn基准测试 mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), # 设置多进程参数 dist_cfg=dict(backend='nccl') # 设置分布式参数 ) log_level = 'INFO' # 日志级别 log_processor = dict( type='LogProcessor', # 日志处理器,用于处理运行时日志 by_epoch=False) # 按迭代打印日志 load_from = None # 从给定路径加载模型检查点作为预训练模型 resume = False # 是否从`load_from`定义的检查点恢复训练。如果`load_from`为`None`,将恢复`work_dir`中的最新检查点 ``` ## 其他示例 ### 修复任务的配置示例 为了帮助用户对修复系统的完整配置和模块有一个基本的了解,我们对全局和局部修复的配置进行简要注释,如下所示。有关更详细的用法和每个模块的替代选项,请参考API文档。 ```python model = dict( type='GLInpaintor', # 修复模型的名称 data_preprocessor=dict( type='DataPreprocessor', # 数据预处理器的名称 mean=[127.5], # 数据归一化时使用的均值 std=[127.5], # 数据归一化时使用的标准差 ), encdec=dict( type='GLEncoderDecoder', # 编码器-解码器的名称 encoder=dict(type='GLEncoder', norm_cfg=dict(type='SyncBN')), # 编码器的配置 decoder=dict(type='GLDecoder', norm_cfg=dict(type='SyncBN')), # 解码器的配置 dilation_neck=dict( type='GLDilationNeck', norm_cfg=dict(type='SyncBN'))), # 膨胀模块的配置 disc=dict( type='GLDiscs', # 判别器的名称 global_disc_cfg=dict( in_channels=3, # 判别器的输入通道数 max_channels=512, # 判别器中间通道的最大数量 fc_in_channels=512 * 4 * 4, # 最后一个全连接层的输入通道数 fc_out_channels=1024, # 最后一个全连接层的输出通道数 num_convs=6, # 判别器中使用的卷积层数量 norm_cfg=dict(type='SyncBN') # 归一化层的配置 ), local_disc_cfg=dict( in_channels=3, # 判别器的输入通道数 max_channels=512, # 判别器中间通道的最大数量 fc_in_channels=512 * 4 * 4, # 最后一个全连接层的输入通道数 fc_out_channels=1024, # 最后一个全连接层的输出通道数 num_convs=5, # 判别器中使用的卷积层数量 norm_cfg=dict(type='SyncBN') # 归一化层的配置 ), ), loss_gan=dict( type='GANLoss', # GAN损失的名称 gan_type='vanilla', # GAN损失的类型 loss_weight=0.001 # GAN损失的权重 ), loss_l1_hole=dict( type='L1Loss', # L1损失的类型 loss_weight=1.0 # L1损失的权重 ) ) train_cfg = dict( type='IterBasedTrainLoop', # 训练循环的类型 max_iters=500002, # 总迭代次数 val_interval=50000 # 验证间隔的迭代次数 ) val_cfg = dict(type='ValLoop') # 验证循环的类型 test_cfg = dict(type='TestLoop') # 测试循环的类型 val_evaluator = [ dict(type='MAE', mask_key='mask', scaling=100), # 用于评估的指标名称 dict(type='PSNR'), # 用于评估的指标名称 dict(type='SSIM'), # 用于评估的指标名称 ] test_evaluator = val_evaluator input_shape = (256, 256) # 输入图像的形状 train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), # 加载图像的配置 dict( type='LoadMask', # 加载掩膜的类型 mask_mode='bbox', # 掩膜的类型 mask_config=dict( max_bbox_shape=(128, 128), # 边界框的形状 max_bbox_delta=40, # 边界框高度和宽度的变化范围 min_margin=20, # 边界框与图像边界的最小间距 img_shape=input_shape)), # 输入图像的形状 dict( type='Crop', # 裁剪的类型 keys=['gt'], # 需要裁剪的图像的键 crop_size=(384, 384), # 裁剪后的大小 random_crop=True, # 是否随机裁剪 ), dict( type='Resize', # 调整大小的类型 keys=['gt'], # 需要调整大小的图像的键 scale=input_shape, # 调整大小的比例 keep_ratio=False, # 是否保持比例 ), dict( type='Normalize', # 归一化的类型 keys=['gt_img'], # 需要归一化的图像的键 mean=[127.5] * 3, # 归一化时使用的均值 std=[127.5] * 3, # 归一化时使用的标准差 to_rgb=False), # 是否将图像通道转换为RGB dict(type='GetMaskedImage'), # 获取掩膜图像的配置 dict(type='PackInputs'), # 收集当前流水线中的数据的配置 ] test_pipeline = train_pipeline # 构建测试/验证流水线 dataset_type = 'BasicImageDataset' # 数据集的类型 data_root = 'data/places' # 数据的根路径 train_dataloader = dict( batch_size=12, # 单个GPU的批处理大小 num_workers=4, # 每个单个GPU预取数据的工作线程数 persistent_workers=False, # 是否保持工作线程的数据集实例 sampler=dict(type='InfiniteSampler', shuffle=False), # 数据采样器的类型 dataset=dict( # 训练数据集的配置 type=dataset_type, # 数据集的类型 data_root=data_root, # 数据的根路径 data_prefix=dict(gt='data_large'), # 图像路径的前缀 ann_file='meta/places365_train_challenge.txt', # 注释文件的路径 test_mode=False, pipeline=train_pipeline, )) val_dataloader = dict( batch_size=1, # 单个GPU的批处理大小 num_workers=4, # 每个单个GPU预取数据的工作线程数 persistent_workers=False, # 是否保持工作线程的数据集实例 drop_last=False, # 是否丢弃最后一个不完整的批次 sampler=dict(type='DefaultSampler', shuffle=False), # 数据采样器的类型 dataset=dict( # 验证数据集的配置 type=dataset_type, # 数据集的类型 data_root=data_root, # 数据的根路径 data_prefix=dict(gt='val_large'), # 图像路径的前缀 ann_file='meta/places365_val.txt', # 注释文件的路径 test_mode=True, pipeline=test_pipeline, )) test_dataloader = val_dataloader model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') # 模型包装器的名称 optim_wrapper = dict( # 用于构建优化器的配置,支持PyTorch中的所有优化器,其参数与PyTorch中的优化器的参数相同 constructor='MultiOptimWrapperConstructor', generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004)), disc=dict(type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0004))) default_scope = 'mmagic' # 用于设置注册表位置 save_dir = './work_dirs' # 保存模型检查点和日志的目录 exp_name = 'gl_places' # 实验名称 default_hooks = dict( # 用于构建默认挂钩 timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # 注册记录器挂钩的配置 param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( # 设置检查点挂钩的配置 type='CheckpointHook', interval=50000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( # 用于设置分布式训练的参数,也可以设置端口 cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type='LocalVisBackend')] # 可视化后端的名称 visualizer = dict( # 用于构建可视化器的配置 type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] # 用于构建自定义挂钩 log_level = 'INFO' # 记录级别 log_processor = dict(type='LogProcessor', by_epoch=False) # 用于构建日志处理器 load_from = None # 从给定路径加载预训练模型 resume = False # 从给定路径恢复检查点 find_unused_parameters = False # 是否在DDP中设置未使用的参数 ``` ### 抠图任务的配置示例 为了帮助用户对完整的配置有一个基本的了解,我们对我们实现的原始DIM(Deep Image Matting)模型的配置进行了简要的注释,如下所示。有关每个模块的更详细用法和相应的替代方案,请参阅API文档。 ```python # 模型设置 model = dict( type='DIM', # 模型的名称(我们称之为mattor)。 data_preprocessor=dict( # 数据预处理器的配置 type='DataPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], bgr_to_rgb=True, proc_inputs='normalize', proc_trimap='rescale_to_zero_one', proc_gt='rescale_to_zero_one', ), backbone=dict( # 骨干网络的配置。 type='SimpleEncoderDecoder', # 骨干网络的类型。 encoder=dict( # 编码器的配置。 type='VGG16'), # 编码器的类型。 decoder=dict( # 解码器的配置。 type='PlainDecoder')), # 解码器的类型。 pretrained='./weights/vgg_state_dict.pth', # 要加载的编码器的预训练权重。 loss_alpha=dict( # alpha损失的配置。 type='CharbonnierLoss', # 预测的alpha融合图像的损失类型。 loss_weight=0.5), # alpha损失的权重。 loss_comp=dict( # 合成损失的配置。 type='CharbonnierCompLoss', # 合成损失的类型。 loss_weight=0.5), # 合成损失的权重。 train_cfg=dict( # DIM模型的训练配置。 train_backbone=True, # 在DIM阶段1中,训练骨干网络。 train_refiner=False), # 在DIM阶段1中,不训练refiner。 test_cfg=dict( # DIM模型的测试配置。 refine=False, # 是否使用refiner输出作为输出,在阶段1中我们不使用它。 resize_method='pad', resize_mode='reflect', size_divisor=32, ), ) # 数据设置 dataset_type = 'AdobeComp1kDataset' # 数据集类型,用于定义数据集。 data_root = 'data/adobe_composition-1k' # 数据的根路径。 train_pipeline = [ # 训练数据处理流程。 dict( type='LoadImageFromFile', # 从文件加载alpha融合图像。 key='alpha', # 注释文件中alpha融合图像的键。该流程将从路径`alpha_path`读取alpha融合图像。 color_type='grayscale'), # 加载为灰度图像,具有形状(高度,宽度)。 dict( type='LoadImageFromFile', # 从文件加载图像。 key='fg'), # 要加载的图像的键。该流程将从路径`fg_path`读取前景图像。 dict( type='LoadImageFromFile', # 从文件加载图像。 key='bg'), # 要加载的图像的键。该流程将从路径`bg_path`读取背景图像。 dict( type='LoadImageFromFile', # 从文件加载图像。 key='merged'), # 要加载的图像的键。该流程将从路径`merged_path`读取合并图像。 dict( type='CropAroundUnknown', # 在未知区域(半透明区域)周围裁剪图像。 keys=['alpha', 'merged', 'fg', 'bg'], # 要裁剪的图像。 crop_sizes=[320, 480, 640]), # 候选裁剪大小。 dict( type='Flip', # 翻转图像的增强流程。 keys=['alpha', 'merged', 'fg', 'bg']), # 要翻转的图像。 dict( type='Resize', # 调整图像大小的增强流程。 keys=['alpha', 'merged', 'fg', 'bg'], # 要调整大小的图像。 scale=(320, 320), # 目标大小。 keep_ratio=False), # 是否保持高度和宽度之间的比例。 dict( type='GenerateTrimap', # 从alpha融合图像生成trimap。 kernel_size=(1, 30)), # 腐蚀/膨胀内核的大小范围。 dict(type='PackInputs'), # 从当前流程中收集数据的配置 ] test_pipeline = [ dict( type='LoadImageFromFile', # 加载alpha融合图像。 key='alpha', # 注释文件中alpha融合图像的键。该流程将从路径`alpha_path`读取alpha融合图像。 color_type='grayscale', save_original_img=True), dict( type='LoadImageFromFile', # 从文件加载图像。 key='trimap', # 要加载的图像的键。该流程将从路径`trimap_path`读取trimap。 color_type='grayscale', # 加载为灰度图像,具有形状(高度,宽度)。 save_original_img=True), # 保存trimap的副本用于计算指标。它将以键`ori_trimap`保存。 dict( type='LoadImageFromFile', # 从文件加载图像。 key='merged'), # 要加载的图像的键。该流程将从路径`merged_path`读取合并图像。 dict(type='PackInputs'), # 从当前流程中收集数据的配置 ] train_dataloader = dict( batch_size=1, # 单个GPU的批处理大小 num_workers=4, # 每个单个GPU预提取数据的工作线程数 persistent_workers=False, # 是否保持工作线程Dataset实例处于活动状态 sampler=dict(type='InfiniteSampler', shuffle=True), # 数据采样器的类型 dataset=dict( # 训练数据集的配置 type=dataset_type, # 数据集的类型 data_root=data_root, # 数据的根路径 ann_file='training_list.json', # 注释文件的路径 test_mode=False, pipeline=train_pipeline, )) val_dataloader = dict( batch_size=1, # 单个GPU的批处理大小 num_workers=4, # 每个单个GPU预提取数据的工作线程数 persistent_workers=False, # 是否保持工作线程Dataset实例处于活动状态 drop_last=False, # 是否丢弃最后一个不完整的批次 sampler=dict(type='DefaultSampler', shuffle=False), # 数据采样器的类型 dataset=dict( # 验证数据集的配置 type=dataset_type, # 数据集的类型 data_root=data_root, # 数据的根路径 ann_file='test_list.json', # 注释文件的路径 test_mode=True, pipeline=test_pipeline, )) test_dataloader = val_dataloader val_evaluator = [ dict(type='SAD'), # 要评估的指标名称 dict(type='MattingMSE'), # 要评估的指标名称 dict(type='GradientError'), # 要评估的指标名称 dict(type='ConnectivityError'), # 要评估的指标名称 ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', # 训练循环类型的名称 max_iters=1_000_000, # 总迭代次数 val_interval=40000, # 验证间隔迭代次数 ) val_cfg = dict(type='ValLoop') # 验证循环类型的名称 test_cfg = dict(type='TestLoop') # 测试循环类型的名称 # 优化器 optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) ) # 用于构建优化器的配置,支持PyTorch中所有优化器,其参数也与PyTorch中的参数相同。 default_scope = 'mmagic' # 用于设置注册表位置 save_dir = './work_dirs' # 保存当前实验的模型检查点和日志的目录。 default_hooks = dict( # 用于构建默认钩子 timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # 注册日志记录器钩子的配置 param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict( # 配置检查点钩子 type='CheckpointHook', interval=40000, # 保存间隔为40000次迭代。 by_epoch=False, # 按迭代计数。 out_dir=save_dir), sampler_seed=dict(type='DistSamplerSeedHook'), ) env_cfg = dict( # 设置分布式训练的参数,也可以设置端口 cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # 日志级别 log_processor = dict(type='LogProcessor', by_epoch=False) # 用于构建日志处理器的配置。 # 导入模块并设置MMDetection的配置 load_from = None # 从给定路径加载模型作为预训练模型,这不会恢复训练。 resume = False # 从给定路径恢复检查点,训练将从检查点保存的时期恢复。 ``` ### 恢复任务的配置示例 为了帮助用户对完整配置有一个基本的理解,我们对我们实现的EDSR模型的配置进行了简要的注释,如下所示。有关更详细的用法和每个模块的相应替代方案,请参阅API文档。 ```python exp_name = 'edsr_x2c64b16_1x16_300k_div2k' # 实验名称 work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' load_from = None # 基于预训练的x2模型 scale = 2 # 上采样的比例 # 模型设置 model = dict( type='BaseEditModel', # 模型名称 generator=dict( # 生成器的配置 type='EDSRNet', # 生成器的类型 in_channels=3, # 输入的通道数 out_channels=3, # 输出的通道数 mid_channels=64, # 中间特征的通道数 num_blocks=16, # 主干网络中的块数 upscale_factor=scale, # 上采样因子 res_scale=1, # 用于缩放残差块中的残差 rgb_mean=(0.4488, 0.4371, 0.4040), # 图像的RGB均值 rgb_std=(1.0, 1.0, 1.0)), # 图像的RGB标准差 pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean') # 像素损失的配置 train_cfg = dict(), # 训练模型的配置 test_cfg = dict(), # 测试模型的配置 data_preprocessor = dict( # 数据预处理器的配置 type='DataPreprocessor', mean=[0., 0., 0.], std=[255., 255., 255.])) train_pipeline = [ # 训练数据处理的流程 dict(type='LoadImageFromFile', # 从文件加载图像 key='img', # 结果中寻找对应路径的关键字 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='LoadImageFromFile', # 从文件加载图像 key='gt', # 结果中寻找对应路径的关键字 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='SetValues', dictionary=dict(scale=scale)), # 设置目标关键字的值 dict(type='PairedRandomCrop', gt_patch_size=96), # 随机裁剪配对图像 dict(type='Flip', # 翻转图像 keys=['lq', 'gt'], # 需要翻转的图像 flip_ratio=0.5, # 翻转的比例 direction='horizontal'), # 翻转的方向 dict(type='Flip', # 翻转图像 keys=['lq', 'gt'], # 需要翻转的图像 flip_ratio=0.5, # 翻转的比例 direction='vertical'), # 翻转的方向 dict(type='RandomTransposeHW', # 随机转置图像的高度和宽度 keys=['lq', 'gt'], # 需要转置的图像 transpose_ratio=0.5 # 转置的比例 ), dict(type='PackInputs') # 收集当前流程中的数据的配置 ] test_pipeline = [ # 测试流程 dict(type='LoadImageFromFile', # 从文件加载图像 key='img', # 结果中寻找对应路径的关键字 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='LoadImageFromFile', # 从文件加载图像 key='gt', # 结果中寻找对应路径的关键字 color_type='color', # 图像的颜色类型 channel_order='rgb', # 图像的通道顺序 imdecode_backend='cv2'), # 解码后端 dict(type='ToTensor', keys=['img', 'gt']), # 将图像转换为张量 dict(type='PackInputs') # 收集当前流程中的数据的配置 ] # 数据集设置 dataset_type = 'BasicImageDataset' # 数据集的类型 data_root = 'data' # 数据的根路径 train_dataloader = dict( num_workers=4, # 每个GPU预提取数据的工作进程数 persistent_workers=False, # 是否保持工作进程中的数据集实例处于活动状态 sampler=dict(type='InfiniteSampler', shuffle=True), # 数据采样器的类型 dataset=dict( # 训练数据集的配置 type=dataset_type, # 数据集的类型 ann_file='meta_info_DIV2K800sub_GT.txt', # 注释文件的路径 metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', # 数据的根路径 data_prefix=dict( # 图像路径的前缀 img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), filename_tmpl=dict(img='{}', gt='{}'), # 文件名模板 pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, # 每个GPU预提取数据的工作进程数 persistent_workers=False, # 是否保持工作进程中的数据集实例处于活动状态 drop_last=False, # 是否丢弃最后一个不完整的批次 sampler=dict(type='DefaultSampler', shuffle=False), # 数据采样器的类型 dataset=dict( # 验证数据集的配置 type=dataset_type, # 数据集的类型 metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', # 数据的根路径 data_prefix=dict(img='LRbicx2', gt='GTmod12'), # 图像路径的前缀 pipeline=test_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type='MAE'), # 用于评估的指标的名称 dict(type='PSNR', crop_border=scale), # 用于评估的指标的名称 dict(type='SSIM', crop_border=scale), # 用于评估的指标的名称 ] test_evaluator = val_evaluator train_cfg = dict( type='IterBasedTrainLoop', max_iters=300000, val_interval=5000) # 训练循环类型的配置 val_cfg = dict(type='ValLoop') # 验证循环类型的名称 test_cfg = dict(type='TestLoop') # 测试循环类型的名称 # 优化器 optim_wrapper = dict( dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.00001), ) ) # 用于构建优化器的配置,支持PyTorch中所有优化器,参数与PyTorch中的相同。 param_scheduler = dict( # 学习策略的配置 type='MultiStepLR', by_epoch=False, milestones=[200000], gamma=0.5) default_hooks = dict( # 用于构建默认钩子 checkpoint=dict( # 配置保存检查点的钩子 type='CheckpointHook', interval=5000, # 保存间隔为5000次迭代 save_optimizer=True, by_epoch=False, # 以迭代计数 out_dir=save_dir, ), timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), # 注册记录器钩子的配置 param_scheduler=dict(type='ParamSchedulerHook'), sampler_seed=dict(type='DistSamplerSeedHook'), ) default_scope = 'mmagic' # 用于设置注册表位置 save_dir = './work_dirs' # 保存当前实验的模型检查点和日志的目录。 env_cfg = dict( # 设置分布式训练的参数,端口也可以设置 cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' # 记录的级别 log_processor = dict(type='LogProcessor', window_size=100, by_epoch=False) # 用于构建日志处理器 load_from = None # 从给定路径加载模型作为预训练模型,这不会恢复训练。 resume = False # 从给定路径恢复检查点,训练将从检查点保存的时期恢复。 ``` ================================================ FILE: docs/zh_cn/user_guides/dataset_prepare.md ================================================ # 教程 2:准备数据集 在本节中,我们将详细介绍如何准备数据并在本仓库的不同任务中采用适当的数据集。 我们支持不同任务的多个数据集。 在MMagic中,有两种方法可以将数据集用于训练和测试模型: 1. 直接使用下载的数据集 2. 在使用下载的数据集之前对其进行预处理 本文的结构如下: - \[教程 2:准备数据集\](#教程 2:准备数据集) - [下载数据集](#下载数据集) - [准备数据集](#准备数据集) - [MMagic中的数据集概述](#MMagic中的数据集概述) ## 下载数据集 首先,建议您从官方的页面下载数据集。 大多数数据集在下载后都是可用的,因此您只需确保文件夹结构正确,无需进一步准备。 例如,您可以通过从[主页](http://toflow.csail.mit.edu/)下载,来简单地准备Vimeo90K-triplet数据集. ## 准备数据集 一些数据集需要在训练或测试之前进行预处理。我们在 [tools/dataset_converters](https://github.com/open-mmlab/mmagic/tree/main/tools/dataset_converters)中支持许多用来准备数据集的脚本。 您可以遵循每个数据集的教程来运行脚本。例如,我们建议将DIV2K图像裁剪为子图像。我们提供了一个脚本来准备裁剪的DIV2K数据集。可以运行以下命令: ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` ## MMagic中的数据集概述 我们支持详细的教程,并根据不同的任务进行拆分。 请查看我们的数据集概览,了解不同任务的数据准备。 如果您对MMagic中数据集的更多细节感兴趣,请查看[进阶教程](../howto/dataset.md)。 ================================================ FILE: docs/zh_cn/user_guides/deploy.md ================================================ # 教程 8:模型部署指南 [MMDeploy](https://github.com/open-mmlab/mmdeploy) 是 OpenMMLab 的部署仓库,负责包括 MMClassification、MMDetection、MMagic 等在内的各算法库的部署工作。 你可以从[这里](https://mmdeploy.readthedocs.io/zh_CN/latest/04-supported-codebases/mmagic.html)获取 MMDeploy 对 MMClassification 部署支持的最新文档。 本文的结构如下: - [安装](#安装) - [模型转换](#模型转换) - [模型规范](#模型规范) - [模型推理](#模型推理) - [后端模型推理](#后端模型推理) - [SDK 模型推理](#sdk-模型推理) - [模型支持列表](#模型支持列表) ## 安装 请参考[此处](../get_started/install.md)安装 mmagic。然后,按照[说明](https://mmdeploy.readthedocs.io/zh_CN/latest/get_started.html#mmdeploy)安装 mmdeploy。 ```{note} 如果安装的是 mmdeploy 预编译包,那么也请通过 'git clone https://github.com/open-mmlab/mmdeploy.git --depth=1' 下载 mmdeploy 源码。因为它包含了部署时要用到的配置文件 ``` ## 模型转换 假设在安装步骤中,mmagic 和 mmdeploy 代码库在同级目录下,并且当前的工作目录为 mmagic 的根目录,那么以 [ESRGAN](../../../configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py) 模型为例,你可以从[此处](https://download.openmmlab.com/mmediting/restorers/esrgan/esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth)下载对应的 checkpoint,并使用以下代码将之转换为 onnx 模型: ```python from mmdeploy.apis import torch2onnx from mmdeploy.backend.sdk.export_info import export2SDK img = 'tests/data/image/face/000001.png' work_dir = 'mmdeploy_models/mmagic/onnx' save_file = 'end2end.onnx' deploy_cfg = '../mmdeploy/configs/mmagic/super-resolution/super-resolution_onnxruntime_dynamic.py' model_cfg = 'configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py' model_checkpoint = 'esrgan_psnr_x4c64b23g32_1x16_1000k_div2k_20200420-bf5c993c.pth' device = 'cpu' # 1. convert model to onnx torch2onnx(img, work_dir, save_file, deploy_cfg, model_cfg, model_checkpoint, device) # 2. extract pipeline info for inference by MMDeploy SDK export2SDK(deploy_cfg, model_cfg, work_dir, pth=model_checkpoint, device=device) ``` 转换的关键之一是使用正确的配置文件。项目中已内置了各后端部署[配置文件](https://github.com/open-mmlab/mmdeploy/tree/main/configs/mmagic)。 文件的命名模式是: ``` {task}/{task}_{backend}-{precision}_{static | dynamic}_{shape}.py ``` 其中: - **{task}:** mmagic 中的任务 - **{backend}:** 推理后端名称。比如,onnxruntime、tensorrt、pplnn、ncnn、openvino、coreml 等等 - **{precision}:** 推理精度。比如,fp16、int8。不填表示 fp32 - **{static | dynamic}:** 动态、静态 shape - **{shape}:** 模型输入的 shape 或者 shape 范围 在上例中,你也可以把 `ESRGAN` 转为其他后端模型。比如使用`super-resolution_tensorrt-fp16_dynamic-32x32-512x512.py`,把模型转为 tensorrt-fp16 模型。 ```{tip} 当转 tensorrt 模型时, --device 需要被设置为 "cuda" ``` ## 模型规范 在使用转换后的模型进行推理之前,有必要了解转换结果的结构。 它存放在 `--work-dir` 指定的路路径下。 上例中的`mmdeploy_models/mmagic/onnx`,结构如下: ``` mmdeploy_models/mmagic/onnx ├── deploy.json ├── detail.json ├── end2end.onnx └── pipeline.json ``` 重要的是: - **end2end.onnx**: 推理引擎文件。可用 ONNX Runtime 推理 - ***xxx*.json**: mmdeploy SDK 推理所需的 meta 信息 整个文件夹被定义为**mmdeploy SDK model**。换言之,**mmdeploy SDK model**既包括推理引擎,也包括推理 meta 信息。 ## 模型推理 ### 后端模型推理 以上述模型转换后的 `end2end.onnx` 为例,你可以使用如下代码进行推理: ```python from mmdeploy.apis.utils import build_task_processor from mmdeploy.utils import get_input_shape, load_config import torch deploy_cfg = '../mmdeploy/configs/mmagic/super-resolution/super-resolution_onnxruntime_dynamic.py' model_cfg = 'configs/esrgan/esrgan_psnr-x4c64b23g32_1xb16-1000k_div2k.py' device = 'cpu' backend_model = ['mmdeploy_models/mmagic/onnx/end2end.onnx'] image = 'tests/data/image/lq/baboon_x4.png' # read deploy_cfg and model_cfg deploy_cfg, model_cfg = load_config(deploy_cfg, model_cfg) # build task and backend model task_processor = build_task_processor(model_cfg, deploy_cfg, device) model = task_processor.build_backend_model(backend_model) # process input image input_shape = get_input_shape(deploy_cfg) model_inputs, _ = task_processor.create_input(image, input_shape) # do model inference with torch.no_grad(): result = model.test_step(model_inputs) # visualize results task_processor.visualize( image=image, model=model, result=result[0], window_name='visualize', output_file='output_restorer.bmp') ``` ### SDK 模型推理 你也可以参考如下代码,对 SDK model 进行推理: ```python from mmdeploy_python import Restorer import cv2 img = cv2.imread('tests/data/image/lq/baboon_x4.png') # create a predictor restorer = Restorer(model_path='mmdeploy_models/mmagic/onnx', device_name='cpu', device_id=0) # perform inference result = restorer(img) # visualize inference result cv2.imwrite('output_restorer.bmp', result) ``` 除了python API,mmdeploy SDK 还提供了诸如 C、C++、C#、Java等多语言接口。 你可以参考[样例](https://github.com/open-mmlab/mmdeploy/tree/main/demo)学习其他语言接口的使用方法。 ## 模型支持列表 请参考[这里](https://mmdeploy.readthedocs.io/zh_CN/latest/04-supported-codebases/mmagic.html#id7) ================================================ FILE: docs/zh_cn/user_guides/index.rst ================================================ .. toctree:: :maxdepth: 3 config.md .. toctree:: :maxdepth: 3 datasets/dataset_prepare.md .. toctree:: :maxdepth: 3 inference.md train_test.md useful_tools.md visualization.md ================================================ FILE: docs/zh_cn/user_guides/inference.md ================================================ # 教程3:使用预训练模型推理 MMagic 提供了高级API,让您可以轻松地在自己的图像或视频上使用最先进的模型进行操作。 在新的API中,仅需两行代码即可进行推理。 ```python from mmagic.apis import MMagicInferencer # 创建MMagicInferencer实例 editor = MMagicInferencer('pix2pix') # 推理图片.需要输入图片路径与输出图片路径 results = editor.infer(img='../resources/input/translation/gt_mask_0.png', result_out_dir='../resources/output/translation/tutorial_translation_pix2pix_res.jpg') ``` MMagic支持各种基础生成模型,包括无条件生成对抗网络(GANs)、条件GANs、扩散模型等。 MMagic 同样支持多种应用,包括:文生图、图生图的转换、3D感知生成、图像超分、视频超分、视频帧插值、图像修补、图像抠图、图像恢复、图像上色、图像生成等。 在本节中,我们将详细说明如何使用我们预训练的模型进行操作。 - 教程3: 使用预训练模型推理 - [准备一些图片或者视频用于推理](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Prepare-some-images-or-videos-for-inference) - 生成模型 - [无条件生成对抗网络 (GANs)]() - [条件生成对抗网络(GANs)]() - [扩散模型](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Diffusion-Models) - 应用 - [文生图](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Text-to-Image) - [图生图的转换](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-to-image-translation) - [3D感知生成](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#3D-aware-generation) - [图像超分](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-super-resolution) - [视频超分](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Video-super-resolution) - [视频帧插值](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/Video-frame-interpolation) - [图像修补](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-inpainting) - [图像抠图](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-matting) - [图像恢复](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-restoration) - [图像上色](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Image-colorization) - [以前的版本](https://github.com/open-mmlab/mmagic/blob/main/docs/zh_cn/user_guides/inference.md#Previous-Versions) ## 准备一些图片或者视频用于推理 请参考我们的[教程](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_tutorial.ipynb)获取详细信息。 ## 生成模型 ### 无条件生成对抗网络(GANs) MMagic提供了用于使用无条件GANs进行图像采样的高级API。无条件GAN模型不需要输入,并输出一张图像。我们以'styleganv1'为例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # 创建MMagicInferencer实例,并进行推理 result_out_dir = './resources/output/unconditional/tutorial_unconditional_styleganv1_res.png' editor = MMagicInferencer('styleganv1') results = editor.infer(result_out_dir=result_out_dir) ``` 确实,我们已经为用户提供了一个更友好的演示脚本。您可以使用以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py): ```python python demo/mmagic_inference_demo.py \ --model-name styleganv1 \ --result-out-dir demo_unconditional_styleganv1_res.jpg ``` ### 条件生成对抗网络(GANs) MMagic提供了使用条件GAN进行图像采样的高级API。条件GAN模型接受一个标签作为输入,并输出一张图像。我们以'biggan'为例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # 创建MMagicInferencer实例,并进行推理 result_out_dir = './resources/output/conditional/tutorial_conditinal_biggan_res.jpg' editor = MMagicInferencer('biggan', model_setting=1) results = editor.infer(label=1, result_out_dir=result_out_dir) ``` 我们已经为用户提供了一个更友好的演示脚本。您可以使用以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py): ```shell python demo/mmagic_inference_demo.py \ --model-name biggan \ --model-setting 1 \ --label 1 \ --result-out-dir demo_conditional_biggan_res.jpg ``` ### 扩散模型 MMagic提供了使用扩散模型进行图像采样的高级API。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # 创建MMagicInferencer实例,并进行推理 editor = MMagicInferencer(model_name='stable_diffusion') text_prompts = 'A panda is having dinner at KFC' result_out_dir = './resources/output/text2image/tutorial_text2image_sd_res.png' editor.infer(text=text_prompts, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name stable_diffusion \ --text "A panda is having dinner at KFC" \ --result-out-dir demo_text2image_stable_diffusion_res.png ``` ## 应用 ### 文生图 文生图模型将文本作为输入,输出一张图片。我们以'controlnet-canny'为例。 ```python import cv2 import numpy as np import mmcv from mmengine import Config from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() cfg = Config.fromfile('configs/controlnet/controlnet-canny.py') controlnet = MODELS.build(cfg.model).cuda() control_url = 'https://user-images.githubusercontent.com/28132635/230288866-99603172-04cb-47b3-8adb-d1aa532d1d2c.jpg' control_img = mmcv.imread(control_url) control = cv2.Canny(control_img, 100, 200) control = control[:, :, None] control = np.concatenate([control] * 3, axis=2) control = Image.fromarray(control) prompt = 'Room with blue walls and a yellow ceiling.' output_dict = controlnet.infer(prompt, control=control) samples = output_dict['samples'] ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name controlnet \ --model-setting 1 \ --text "Room with blue walls and a yellow ceiling." \ --control 'https://user-images.githubusercontent.com/28132635/230297033-4f5c32df-365c-4cf4-8e4f-1b76a4cbb0b7.png' \ --result-out-dir demo_text2image_controlnet_canny_res.png ``` ### 图生图的转换 MMagic提供了使用图像翻译模型进行图像翻译的高级API。下面是构建Pix2Pix并获取翻译图像的示例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer editor = MMagicInferencer('pix2pix') results = editor.infer(img=img_path, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name pix2pix \ --img ${IMAGE_PATH} \ --result-out-dir ${SAVE_PATH} ``` ### 3D感知生成 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer result_out_dir = './resources/output/eg3d-output' editor = MMagicInferencer('eg3d') results = editor.infer(result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name eg3d \ --result-out-dir ./resources/output/eg3d-output ``` ### 图像超分 图像超分辨率模型接受一张图像作为输入,并输出一张高分辨率图像。我们以 'esrgan' 为例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = './resources/input/restoration/0901x2.png' result_out_dir = './resources/output/restoration/tutorial_restoration_esrgan_res.png' editor = MMagicInferencer('esrgan') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name esrgan \ --img ${IMAGE_PATH} \ --result-out-dir ${SAVE_PATH} ``` ### 视频超分 ```python import os from mmagic.apis import MMagicInferencer from mmengine import mkdir_or_exist # Create a MMagicInferencer instance and infer video = './resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4' result_out_dir = './resources/output/video_super_resolution/tutorial_video_super_resolution_basicvsr_res.mp4' mkdir_or_exist(os.path.dirname(result_out_dir)) editor = MMagicInferencer('basicvsr') results = editor.infer(video=video, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name basicvsr \ --video ./resources/input/video_restoration/QUuC4vJs_000084_000094_400x320.mp4 \ --result-out-dir ./resources/output/video_restoration/demo_video_restoration_basicvsr_res.mp4 ``` ### 视频帧插值 视频插值模型接受一个视频作为输入,并输出一个插值后的视频。我们以 'flavr' 为例。 ```python import os from mmagic.apis import MMagicInferencer from mmengine import mkdir_or_exist # Create a MMagicInferencer instance and infer video = './resources/input/video_interpolation/b-3LLDhc4EU_000000_000010.mp4' result_out_dir = './resources/output/video_interpolation/tutorial_video_interpolation_flavr_res.mp4' mkdir_or_exist(os.path.dirname(result_out_dir)) editor = MMagicInferencer('flavr') results = editor.infer(video=video, result_out_dir=result_out_dir) ``` ### 图像修补 修复模型接受一对屏蔽图像和屏蔽蒙版作为输入,并输出一个修复后的图像。我们以 'global_local' 为例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer img = './resources/input/matting/GT05.jpg' trimap = './resources/input/matting/GT05_trimap.jpg' # 创建MMagicInferencer实例,并进行推理 result_out_dir = './resources/output/matting/tutorial_matting_gca_res.png' editor = MMagicInferencer('gca') results = editor.infer(img=img, trimap=trimap, result_out_dir=result_out_dir) ``` ### 图像抠图 **抠图**模型接受一对图像和修剪映射作为输入,并输出一个 alpha 图像。我们以 'gca' 为例。 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer img = './resources/input/matting/GT05.jpg' trimap = './resources/input/matting/GT05_trimap.jpg' # 创建MMagicInferencer实例,并进行推理 result_out_dir = './resources/output/matting/tutorial_matting_gca_res.png' editor = MMagicInferencer('gca') results = editor.infer(img=img, trimap=trimap, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name gca \ --img ./resources/input/matting/GT05.jpg \ --trimap ./resources/input/matting/GT05_trimap.jpg \ --result-out-dir ./resources/output/matting/demo_matting_gca_res.png ``` ### 图像恢复 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = './resources/input/restoration/0901x2.png' result_out_dir = './resources/output/restoration/tutorial_restoration_nafnet_res.png' editor = MMagicInferencer('nafnet') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name nafnet \ --img ./resources/input/restoration/0901x2.png \ --result-out-dir ./resources/output/restoration/demo_restoration_nafnet_res.png ``` ### 图像上色 ```python import mmcv import matplotlib.pyplot as plt from mmagic.apis import MMagicInferencer # Create a MMagicInferencer instance and infer img = 'https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg' result_out_dir = './resources/output/colorization/tutorial_colorization_res.png' editor = MMagicInferencer('inst_colorization') results = editor.infer(img=img, result_out_dir=result_out_dir) ``` 通过以下命令使用[demo/mmagic_inference_demo.py](https://github.com/open-mmlab/mmagic/blob/main/demo/mmagic_inference_demo.py) ```shell python demo/mmagic_inference_demo.py \ --model-name inst_colorization \ --img https://github-production-user-asset-6210df.s3.amazonaws.com/49083766/245713512-de973677-2be8-4915-911f-fab90bb17c40.jpg \ --result-out-dir demo_colorization_res.png ``` ## 以前的版本 如果您想使用已弃用的演示,请使用[MMagic v1.0.0rc7](https://github.com/open-mmlab/mmagic/tree/v1.0.0rc7)并参考[旧教程](https://github.com/open-mmlab/mmagic/blob/v1.0.0rc7/docs/en/user_guides/inference.md)。 ================================================ FILE: docs/zh_cn/user_guides/metrics.md ================================================ # 教程 5:使用评价指标 MMagic支持**17个指标**以评估模型质量。 有关用法,请参阅[MMagic中的训练与测试](../user_guides/train_test.md)。 在这里,我们将逐个介绍不同指标的详细信息。 本文的结构如下: 01. [MAE](#mae) 02. [MSE](#mse) 03. [PSNR](#psnr) 04. [SNR](#snr) 05. [SSIM](#ssim) 06. [NIQE](#niqe) 07. [SAD](#sad) 08. [MattingMSE](#mattingmse) 09. [GradientError](#gradienterror) 10. [ConnectivityError](#connectivityerror) 11. [FID and TransFID](#fid-and-transfid) 12. [IS and TransIS](#is-and-transis) 13. [Precision and Recall](#precision-and-recall) 14. [PPL](#ppl) 15. [SWD](#swd) 16. [MS-SSIM](#ms-ssim) 17. [Equivarience](#equivarience) ## MAE MAE是图像的平均绝对误差。 要使用MAE进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='MAE'), ] ``` ## MSE MSE是图像的均方误差。 要使用MSE进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='MSE'), ] ``` ## PSNR PSNR是峰值信噪比。我们的实现方法来自https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio。 要使用PSNR进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='PSNR'), ] ``` ## SNR SNR是信噪比。我们的实现方法来自 https://en.wikipedia.org/wiki/Signal-to-noise_ratio。 要使用SNR进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='SNR'), ] ``` ## SSIM SSIM是图像的结构相似度,在[图像质量评估:从错误可见性到结构相似度](https://live.ece.utexas.edu/publications/2004/zwang_ssim_ieeeip2004.pdf)中提出。我们实现的结果与https://ece.uwaterloo.ca/~z70wang/research/ssim/官方发布的MATLAB代码相同。 要使用SSIM进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='SSIM'), ] ``` ## NIQE NIQE是自然图像质量评估指标,在[制作'完全盲'图像质量分析仪](http://www.live.ece.utexas.edu/publications/2013/mittal2013.pdf)中提出。我们的实现可以产生几乎与官方MATLAB代码相同的结果:http://live.ece.utexas.edu/research/quality/niqe_release.zip。 要使用NIQE进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='NIQE'), ] ``` ## SAD SAD是图像抠图的绝对误差和。该指标计算每个像素的绝对差和所有像素的总和。 要使用SAD进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='SAD'), ] ``` ## MattingMSE MattingMSE是图像抠图的均方误差。 要使用MattingMSE进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='MattingMSE'), ] ``` ## GradientError GradientError是用于评估alpha matte预测的梯度误差。 要使用GradientError进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='GradientError'), ] ``` ## ConnectivityError ConnectivityError是用于评估alpha matte预测的连通性误差。 要使用ConnectivityError进行评估,请在配置文件中添加以下配置: ```python val_evaluator = [ dict(type='ConnectivityError'), ] ``` ## FID 和 TransFID Fréchet初始距离是两个图像数据集之间相似度的度量。它被证明与人类对视觉质量的判断有很好的相关性,最常用于评估生成对抗网络样本的质量。FID是通过计算两个高斯函数之间的Fréchet距离来计算的,这些高斯函数适合于Inception网络的特征表示。 在`MMagic`中,我们提供了两个版本的FID计算。一个是常用的PyTorch版本,另一个用于StyleGAN。同时,我们在StyleGAN2-FFHQ1024模型中比较了这两种实现之间的差异(详细信息可以在这里找到\[https://github.com/open-mmlab/mmagic/blob/main/configs/styleganv2/README.md\])。幸运的是,最终结果只是略有不同。因此,我们建议用户采用更方便的PyTorch版本。 **关于PyTorch版本和Tero版本:** 常用的PyTorch版本采用修改后的InceptionV3网络提取真假图像特征。然而,Tero的FID需要Tensorflow InceptionV3的[脚本模块](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt)。注意,应用此脚本模块需要' PyTorch >= 1.6.0 '。 **关于提取真实的初始数据:** 为了方便用户,在测试时自动提取真实的特征并保存在本地,存储的特征在下次测试时自动读取。具体来说,我们将根据用于计算实际特性的参数计算一个哈希值,并使用哈希值来标记特性文件,在测试时,如果' inception_pkl '没有设置,我们将在' MMAGIC_CACHE_DIR ' (~/.cache/openmmlab/mmagic/)中寻找该特性。如果未找到缓存的初始pkl,则将执行提取。 要使用FID指标,请在配置文件中添加以下配置: ```python metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] ``` 如果您在一台新机器上工作,那么您可以复制'MMAGIC_CACHE_DIR'中的'pkl'文件,将它们复制到新机器并设置'inception_pkl'字段。 ```python metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', inception_pkl= 'work_dirs/inception_pkl/inception_state-capture_mean_cov-full-33ad4546f8c9152e4b3bdb1b0c08dbaf.pkl', # copied from old machine sample_model='ema') ] ``` 'TransFID'与'FID'的用法相同,但TransFID是为'Pix2Pix'和'CycleGAN'等翻译模型设计的,适用于我们的评估器。更多信息您可以参考[evaluation](../user_guides/train_test.md)。 ## IS 和 TransIS Inception评分是评估生成图像质量的客观指标,在[改进的训练GANs技术](https://arxiv.org/pdf/1606.03498.pdf)中提出。它使用一个InceptionV3模型来预测生成的图像的类别,并假设: 1)如果图像质量高,它将被归类到特定的类别。2)如果图像具有较高的多样性,则图像的类别范围将很广。因此,条件概率和边际概率的kl -散度可以指示生成图像的质量和多样性。您可以在'metrics.py'中看到完整的实现,它指向https://github.com/sbarratt/inception-score-pytorch/blob/master/inception_score.py。 如果您想使用'IS'指标评估模型,请在配置文件中添加以下配置: ```python # at the end of the configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py metrics = [ xxx, dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] ``` 需要注意的是,Inception V3的选择和图像大小的调整方法会显著影响最终的IS评分。因此,我们强烈建议用户可以下载[Tero's script model of Inception V3](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt)(加载此脚本模型需要torch >= 1.6),并使用'Bicubic'插值与'Pillow'后端。 对应于config,您可以设置'resize_method'和'use_pillow_resize'用于图像大小的调整。您也可以将'inception_style'设置为'StyleGAN'用于推荐的tero的初始模型,或'PyTorch'用于torchvision的实现。对于没有互联网的环境,您可以下载初始的权重,并将'inception_path'设置为您的初始模型。 我们还调查了数据加载管线和预训练的Inception V3版本对IS结果的影响。所有IS都在同一组图像上进行评估,这些图像是从ImageNet数据集中随机选择的。
显示对比结果 | Code Base | Inception V3 Version | Data Loader Backend | Resize Interpolation Method | IS | | :-------------------------------------------------------------: | :------------------: | :-----------------: | :-------------------------: | :-------------------: | | [OpenAI (baseline)](https://github.com/openai/improved-gan) | Tensorflow | Pillow | Pillow Bicubic | **312.255 +/- 4.970** | | [StyleGAN-Ada](https://github.com/NVlabs/stylegan2-ada-pytorch) | Tero's Script Model | Pillow | Pillow Bicubic | 311.895 +/ 4.844 | | mmagic (Ours) | Pytorch Pretrained | cv2 | cv2 Bilinear | 322.932 +/- 2.317 | | mmagic (Ours) | Pytorch Pretrained | cv2 | cv2 Bicubic | 324.604 +/- 5.157 | | mmagic (Ours) | Pytorch Pretrained | cv2 | Pillow Bicubic | 318.161 +/- 5.330 | | mmagic (Ours) | Pytorch Pretrained | Pillow | Pillow Bilinear | 313.126 +/- 5.449 | | mmagic (Ours) | Pytorch Pretrained | Pillow | cv2 Bilinear | 318.021+/-3.864 | | mmagic (Ours) | Pytorch Pretrained | Pillow | Pillow Bicubic | 317.997 +/- 5.350 | | mmagic (Ours) | Tero's Script Model | cv2 | cv2 Bilinear | 318.879 +/- 2.433 | | mmagic (Ours) | Tero's Script Model | cv2 | cv2 Bicubic | 316.125 +/- 5.718 | | mmagic (Ours) | Tero's Script Model | cv2 | Pillow Bicubic | **312.045 +/- 5.440** | | mmagic (Ours) | Tero's Script Model | Pillow | Pillow Bilinear | 308.645 +/- 5.374 | | mmagic (Ours) | Tero's Script Model | Pillow | Pillow Bicubic | 311.733 +/- 5.375 |
'TransIS'与'IS'的用法相同,但TransIS是为'Pix2Pix'和'CycleGAN'这样的翻译模型设计的,这是为我们的评估器改编的。更多信息可参考[evaluation](../user_guides/train_test.md)。 ## Precision and Recall 我们的'Precision and Recall'实现遵循StyleGAN2中使用的版本。在该度量中,采用VGG网络对图像进行特征提取。不幸的是,我们还没有发现PyTorch VGG实现与StyleGAN2中使用的Tero版本产生类似的结果。(关于差异,请参阅这个[文件](https://github.com/open-mmlab/mmagicing/blob/main/configs/styleganv2/README.md)。)因此,在我们的实现中,我们默认采用[Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt)网络。需要注意的是,应用这个脚本模块需要'PyTorch >= 1.6.0'。如果使用较低的PyTorch版本,我们将使用PyTorch官方VGG网络进行特征提取。 要使用' P&R '进行评估,请在配置文件中添加以下配置: ```python metrics = [ dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K') ] ``` ## PPL 当在两个随机输入之间进行插值时,感知路径长度测量连续图像(其VGG16嵌入)之间的差异。剧烈的变化意味着多个特征一起发生了变化,它们可能会叠加在一起。通过实验表明,较小的PPL分数表明整体图像质量较高。 作为该指标的基础,我们使用基于感知的成对图像距离,该距离被计算为两个VGG16嵌入之间的加权差,其中权重被拟合,从而评价指标与人类的感知相似性判断一致。 如果我们将潜在空间插值路径细分为线性段,我们可以将该分段路径的总感知长度定义为每个段上感知差异的总和,并且感知路径长度的自然定义将是无限细分下的总和的极限,但在实践中,我们使用一个小的细分`` $`\epsilon=10^{-4}`$ ``来近似它。 因此,潜在`space`Z中所有可能端点的平均感知路径长度为 `` $$`L_Z = E[\frac{1}{\epsilon^2}d(G(slerp(z_1,z_2;t))), G(slerp(z_1,z_2;t+\epsilon)))]`$$ `` 以类似的方式计算潜在 `space` W中的平均感知路径长度:: `` $$`L_Z = E[\frac{1}{\epsilon^2}d(G(slerp(z_1,z_2;t))), G(slerp(z_1,z_2;t+\epsilon)))]`$$ `` 当 `` $`z_1, z_2 \sim P(z)`$ ``, 如果我们设置 `sampling` 为 ` full`, 则 `` $` t \sim U(0,1)`$ ``, 如果设置 `sampling` 为 `end`,则`` $` t \in \{0,1\}`$ ``。 `` $` G`$ `` 是生成器(i.e. `` $` g \circ f`$ `` 用于style-based网络), `` $` d(.,.)`$ `` 用于计算结果图像之间的感知距离。我们通过取100,000个样本来计算期望(在代码中将' num_images '设置为50,000)。 您可以在'metrics.py'中找到完整的实现,参考https://github.com/rosinality/stylegan2-pytorch/blob/master/ppl.py。 如果您想使用'PPL'指标评估模型,请在配置文件中添加以下配置: ```python # at the end of the configs/styleganv2/stylegan2_c2_ffhq_1024_b4x8.py metrics = [ xxx, dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] ``` ## SWD 切片Wasserstein距离是概率分布的差异度量,距离越小表示生成的图像越真实。我们获得每个图像的拉普拉斯金字塔,并从拉普拉斯金字塔中提取小块作为描述符,然后可以通过获取真实和伪描述符切片的Wasserstein距离来计算SWD。 您可以在'metrics.py'中看到完整的实现,参考https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/sliced_wasserstein.py。 如果您想使用'SWD'指标评估模型,请在配置文件中添加以下配置: ```python # at the end of the configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py metrics = [ dict( type='SWD', prefix='swd', fake_nums=16384, sample_model='orig', image_shape=(3, 64, 64)) ] ``` ## MS-SSIM 采用多尺度结构相似度来衡量两幅图像的相似度。我们在这里使用MS-SSIM来衡量生成图像的多样性,MS-SSIM得分低表示生成图像的多样性高。您可以在'metrics.py'中看到完整的实现,参考https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py。 如果您想使用'MS-SSIM'指标评估模型,请在配置文件中添加以下配置: ```python # at the end of the configs/dcgan/dcgan_1xb128-5epoches_lsun-bedroom-64x64.py metrics = [ dict( type='MS_SSIM', prefix='ms-ssim', fake_nums=10000, sample_model='orig') ] ``` ## Equivarience 生成模型的等价性是指模型正变换和几何变换的互换性。目前这个指标只针对StyleGANv3计算,您可以在'metrics.py'中看到完整的实现,参考https://github.com/NVlabs/stylegan3/blob/main/metrics/equivariance.py。 如果您想使用'Equivarience'指标评估模型,请在配置文件中添加以下配置: ```python # at the end of the configs/styleganv3/stylegan3-t_gamma2.0_8xb4-fp16-noaug_ffhq-256x256.py metrics = [ dict( type='Equivariance', fake_nums=50000, sample_mode='ema', prefix='EQ', eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True)) ] ``` ================================================ FILE: docs/zh_cn/user_guides/train_test.md ================================================ # 教程 4:在MMagic环境下训练与测试 在该部分中,您将学到如何在MMagic环境下完成训练与测试 我们提供如下教程: - [预先准备](#预先准备) - [在MMagic中测试模型](#在MMagic中测试模型) - [在单个GPU上测试](#在单个GPU上测试) - [在多个GPU上测试](#在多个GPU上测试) - [在Slurm上测试](#在Slurm上测试) - [使用特定指标进行测试](#使用特定指标进行测试) - [在MMagic中训练模型](#在MMagic中训练模型) - [在单个GPU上训练](#在单个GPU上训练) - [在多个GPU上训练](#在多个GPU上训练) - [在多个节点上训练](#在多个节点上训练) - [在Slurm上训练](#在Slurm上训练) - [使用特定的评估指标进行训练](#使用特定的评估指标进行训练) ## 预先准备 用户需要首先 [准备数据集](../user_guides/dataset_prepare.md) 从而能够在MMagic环境中训练和测试。 ## 在MMagic中测试模型 ### 在单个GPU上测试 您可以通过如下命令使用单个GPU来测试预训练模型。 ```shell python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ``` 例如: ```shell python tools/test.py configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` ### 在多个GPU上测试 MMagic支持使用多个GPU测试,能够极大地节约模型测试时间。 可以通过如下命令使用多个GPU来测试预训练模型。 ```shell ./tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} ``` 例如: ```shell ./tools/dist_test.sh configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` ### 在Slurm上测试 如果您在由 [slurm](https://slurm.schedmd.com/) 管理的集群上运行MMagic,可以使用脚本`slurm_test.sh`。(此脚本还支持单机测试。) ```shell [GPUS=${GPUS}] ./tools/slurm_test.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} ${CHECKPOINT_FILE} ``` 下面是一个使用8个GPU在“dev”分区上测试一个示例模型的例子,作业名称为“test”。 ```shell GPUS=8 ./tools/slurm_test.sh dev test configs/example_config.py work_dirs/example_exp/example_model_20200202.pth ``` 您可以检查 [slurm_test.sh](../../../tools/slurm_test.sh) 以获取完整的参数和环境变量。 ### 使用特定指标进行测试 MMagic 提供各种评**估值指标**,例如:MS-SSIM、SWD、IS、FID、Precision&Recall、PPL、Equivarience、TransFID、TransIS等。 我们在[tools/test.py](https://github.com/open-mmlab/mmagic/tree/main/tools/test.py)中为所有模型提供了统一的评估脚本。 如果用户想用一些指标来评估他们的模型,你可以像这样将 `metrics` 添加到你的配置文件中: ```python # 在文件 configs/styleganv2/stylegan2_c2_ffhq_256_b4x8_800k.py 的末尾 metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type='PrecisionAndRecall', fake_nums=50000, prefix='PR-50K'), dict(type='PerceptualPathLength', fake_nums=50000, prefix='ppl-w') ] ``` 如上所述, `metrics` 由多个指标字典组成。 每个指标包含 `type` 来表示其类别。 `fake_nums` 表示模型生成的图像数量。 有些指标会输出一个结果字典,您也可以设置 `prefix` 来指定结果的前缀。 如果将FID的前缀设置为 `FID-Full-50k`,则输出的示例可能是 ```bash FID-Full-50k/fid: 3.6561 FID-Full-50k/mean: 0.4263 FID-Full-50k/cov: 3.2298 ``` 然后用户可以使用下面的命令测试模型: ```shell bash tools/dist_test.sh ${CONFIG_FILE} ${CKPT_FILE} ``` 如果您在 slurm 环境中,请使用如下命令切换到 [tools/slurm_test.sh](https://github.com/open-mmlab/mmagic/tree/main/tools/slurm_test.sh): ```shell sh slurm_test.sh ${PLATFORM} ${JOBNAME} ${CONFIG_FILE} ${CKPT_FILE} ``` ## 在MMagic中训练模型 MMagic支持多种训练方式: 1. [在单个GPU上训练](#在单个GPU上训练) 2. [在单个GPU上训练](#在单个GPU上训练) 3. [在多个节点上训练](#在多个节点上训练) 4. [在Slurm上训练](#在Slurm上训练) Specifically, all outputs (log files and checkpoints) will be saved to the working directory, which is specified by `work_dir` in the config file. ### 在单个GPU上训练 ```shell CUDA_VISIBLE=0 python tools/train.py configs/example_config.py --work-dir work_dirs/example ``` ### 在多个节点上训练 要在多台机器上启动分布式训练,这些机器可以通过IP访问,运行以下命令: 在第一台机器上: ```shell NNODES=2 NODE_RANK=0 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR tools/dist_train.sh $CONFIG $GPUS ``` 在第二台机器上: ```shell NNODES=2 NODE_RANK=1 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR tools/dist_train.sh $CONFIG $GPUS ``` 为了提高网络通信速度,建议使用高速网络硬件,如Infiniband。 请参考 [PyTorch docs](https://pytorch.org/docs/1.11/distributed.html#launch-utility) 以获取更多信息。 ### 在多个GPU上训练 ```shell ./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments] ``` ### 在Slurm上训练 如果您在由 [slurm](https://slurm.schedmd.com/) 管理的集群上运行MMagic,可以使用脚本`slurm_train.sh`。(此脚本还支持单机测试。) ```shell [GPUS=${GPUS}] ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} ${WORK_DIR} ``` 下面是一个使用8个gpu在dev分区上训练inpainting模型的示例。 ```shell GPUS=8 ./tools/slurm_train.sh dev configs/inpainting/gl_places.py /nfs/xxxx/gl_places_256 ``` 你可以在 [slurm_train.sh](https://github.com/open-mmlab/mmagic/blob/master/tools/slurm_train.sh) 上查阅完整参数和环境变量。 ### 可选参数 - `--amp`:此参数用于固定精度训练。 - `--resume`:此参数用于在训练中止时自动恢复。 ## 使用特定的评估指标进行训练 受益于 `mmengine`的 `Runner`,我们可以在训练过程中对模型进行简单的评估,如下所示。 ```python # 定义指标 metrics = [ dict( type='FrechetInceptionDistance', prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN') ] # 定义dataloader val_dataloader = dict( batch_size=128, num_workers=8, dataset=dict( type='BasicImageDataset', data_root='data/celeba-cropped/', pipeline=[ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(64, 64)), dict(type='PackInputs') ]), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) # 定义 val interval train_cfg = dict(by_epoch=False, val_begin=1, val_interval=10000) # 定义 val loop 和 evaluator val_cfg = dict(type='MultiValLoop') val_evaluator = dict(type='Evaluator', metrics=metrics) ``` 可以设置 `val_begin` 和 `val_interval` 来调整何时开始验证和验证间隔。 有关指标的详细信息,请参考 [metrics' guide](./metrics.md). ================================================ FILE: docs/zh_cn/user_guides/useful_tools.md ================================================ # 教程 7:实用工具(待更新) 我们在 `tools/` 目录下提供了很多有用的工具。 ### 获取 FLOP 和参数量(实验性) 我们提供了一个改编自 [flops-counter.pytorch](https://github.com/sovrasov/flops-counter.pytorch) 的脚本来计算模型的 FLOP 和参数量。 ```shell python tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] ``` 例如, ```shell python tools/get_flops.py configs/resotorer/srresnet.py --shape 40 40 ``` 你会得到以下的结果。 ``` ============================== Input shape: (3, 40, 40) Flops: 4.07 GMac Params: 1.52 M ============================== ``` **注**:此工具仍处于实验阶段,我们不保证数字正确。 您可以将结果用于简单的比较,但在技术报告或论文中采用它之前,请仔细检查它。 (1) FLOPs 与输入形状有关,而参数量与输入形状无关。默认输入形状为 (1, 3, 250, 250)。 (2) 一些运算符不计入 FLOP,如 GN 和自定义运算符。 你可以通过修改 [`mmcv/cnn/utils/flops_counter.py`](https://github.com/open-mmlab/mmcv/blob/master/mmcv/cnn/utils/flops_counter.py) 来添加对新运算符的支持。 ### 发布模型 在将模型上传到 AWS 之前,您可能需要 (1) 将模型权重转换为 CPU tensors, (2) 删除优化器状态,和 (3) 计算模型权重文件的哈希并将哈希 ID 附加到文件名。 ```shell python tools/publish_model.py ${INPUT_FILENAME} ${OUTPUT_FILENAME} ``` 例如, ```shell python tools/publish_model.py work_dirs/example_exp/latest.pth example_model_20200202.pth ``` 最终输出文件名将是 `example_model_20200202-{hash id}.pth`. ### 转换为 ONNX(实验性) 我们提供了一个脚本将模型转换为 [ONNX](https://github.com/onnx/onnx) 格式。 转换后的模型可以通过 [Netron](https://github.com/lutzroeder/netron) 等工具进行可视化。此外,我们还支持比较 Pytorch 和 ONNX 模型之间的输出结果。 ```bash python tools/pytorch2onnx.py ${CFG_PATH} \ ${CHECKPOINT_PATH} \ ${MODEL_TYPE} \ ${IMAGE_PATH} \ --trimap-path ${TRIMAP_PATH} \ --output-file ${OUTPUT_ONNX} \ --show \ --verify \ --dynamic-export ``` 参数说明: - `config` : 模型配置文件的路径。 - `checkpoint` : 模型模型权重文件的路径。 - `model_type` : 配置文件的模型类型,选项: `inpainting`, `mattor`, `restorer`, `synthesizer`。 - `image_path` : 输入图像文件的路径。 - `--trimap-path` : 输入三元图文件的路径,用于 mattor 模型。 - `--output-file`: 输出 ONNX 模型的路径。默认为 `tmp.onnx`。 - `--opset-version` : ONNX opset 版本。默认为 11。 - `--show`: 确定是否打印导出模型的架构。默认为 `False`。 - `--verify`: 确定是否验证导出模型的正确性。默认为 `False`。 - `--dynamic-export`: 确定是否导出具有动态输入和输出形状的 ONNX 模型。默认为 `False`。 **注**:此工具仍处于试验阶段。目前不支持某些自定义运算符。我们现在只支持 `mattor` 和 `restorer`。 #### 支持导出到 ONNX 的模型列表 下表列出了保证可导出到 ONNX 并可在 ONNX Runtime 中运行的模型。 | 模型 | 配置 | 动态形状 | 批量推理 | 备注 | | :------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------: | :------: | :--: | | ESRGAN | [esrgan_x4c64b23g32_g1_400k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/esrgan/esrgan_x4c64b23g32_g1_400k_div2k.py) | Y | Y | | | ESRGAN | [esrgan_psnr_x4c64b23g32_g1_1000k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/esrgan/esrgan_psnr_x4c64b23g32_g1_1000k_div2k.py) | Y | Y | | | SRCNN | [srcnn_x4k915_g1_1000k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/srcnn/srcnn_x4k915_g1_1000k_div2k.py) | Y | Y | | | DIM | [dim_stage3_v16_pln_1x1_1000k_comp1k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/dim/dim_stage3_v16_pln_1x1_1000k_comp1k.py) | Y | Y | | | GCA | [gca_r34_4x10_200k_comp1k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/gca/gca_r34_4x10_200k_comp1k.py) | N | Y | | | IndexNet | [indexnet_mobv2_1x16_78k_comp1k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/indexnet/indexnet_mobv2_1x16_78k_comp1k.py) | Y | Y | | **注**: - *以上所有模型均使用 Pytorch==1.6.0 和 onnxruntime==1.5.1* - 如果您遇到上面列出的模型的任何问题,请创建一个 issue,我们会尽快处理。对于列表中未包含的型号,请尝试自行解决。 - 由于此功能是实验性的并且可能会快速更改,请始终尝试使用最新的 `mmcv` 和 `mmagic`。 ### 将 ONNX 转换为 TensorRT(实验性) 我们还提供了将 [ONNX](https://github.com/onnx/onnx) 模型转换为 [TensorRT](https://github.com/NVIDIA/TensorRT) 格式的脚本。 此外,我们支持比较 ONNX 和 TensorRT 模型之间的输出结果。 ```bash python tools/onnx2tensorrt.py ${CFG_PATH} \ ${MODEL_TYPE} \ ${IMAGE_PATH} \ ${INPUT_ONNX} \ --trt-file ${OUT_TENSORRT} \ --max-shape INT INT INT INT \ --min-shape INT INT INT INT \ --workspace-size INT \ --fp16 \ --show \ --verify \ --verbose ``` 参数说明: - `config` : 模型配置文件的路径。 - `model_type` :配置文件的模型类型,选项: `inpainting`, `mattor`, `restorer`, `synthesizer`。 - `img_path` : 输入图像文件的路径。 - `onnx_file` : 输入 ONNX 文件的路径。 - `--trt-file` : 输出 TensorRT 模型的路径。默认为 `tmp.trt`。 - `--max-shape` : 模型输入的最大形状。 - `--min-shape` : 模型输入的最小形状。 - `--workspace-size`: 以 GiB 为单位的最大工作空间大小。默认为 1 GiB。 - `--fp16`: 确定是否以 fp16 模式导出 TensorRT。默认为 `False`。 - `--show`: 确定是否显示 ONNX 和 TensorRT 的输出。默认为 `False`。 - `--verify`: 确定是否验证导出模型的正确性。默认为 `False`。 - `--verbose`: 确定在创建 TensorRT 引擎时是否详细记录日志消息。默认为 `False`。 **注**:此工具仍处于试验阶段。 目前不支持某些自定义运算符。 我们现在只支持 `restorer`。 在生成 SRCNN 的 ONNX 文件时,将 SCRNN 模型中的 'bicubic' 替换为 'bilinear' \[此处\](https://github.com/open-mmlab/mmagic/blob/764e6065e315b7d0033762038fcbf0bb1c570d4d/mmagic.bones/modelsrnn py#L40)。 因为 TensorRT 目前不支持 bicubic 插值,最终性能将下降约 4%。 #### 支持导出到 TensorRT 的模型列表 下表列出了保证可导出到 TensorRT 引擎并可在 TensorRT 中运行的模型。 | 模型 | 配置 | 动态形状 | 批量推理 | 备注 | | :----: | :-------------------------------------------------------------------------------------------------------------------------------------------: | :------: | :------: | :-----------------------------------: | | ESRGAN | [esrgan_x4c64b23g32_g1_400k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/esrgan/esrgan_x4c64b23g32_g1_400k_div2k.py) | Y | Y | | | ESRGAN | [esrgan_psnr_x4c64b23g32_g1_1000k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/esrgan/esrgan_psnr_x4c64b23g32_g1_1000k_div2k.py) | Y | Y | | | SRCNN | [srcnn_x4k915_g1_1000k_div2k.py](https://github.com/open-mmlab/mmagic/blob/master/configs/restorers/srcnn/srcnn_x4k915_g1_1000k_div2k.py) | Y | Y | 'bicubic' 上采样必须替换为 'bilinear' | **注**: - *以上所有模型均使用 Pytorch==1.8.1、onnxruntime==1.7.0 和 tensorrt==7.2.3.4 进行测试* - 如果您遇到上面列出的模型的任何问题,请创建一个问题,我们会尽快处理。 对于列表中未包含的型号,请尝试自行解决。 - 由于此功能是实验性的并且可能会快速更改,因此请始终尝试使用最新的 `mmcv` 和 `mmagic`。 ### 评估 ONNX 和 TensorRT 模型(实验性) 我们在 `tools/deploy_test.py` 中提供了评估 TensorRT 和 ONNX 模型的方法。 #### 先决条件 要评估 ONNX 和 TensorRT 模型,应先安装 onnx、onnxruntime 和 TensorRT。遵循 [mmcv 中的 ONNXRuntime](https://mmcv.readthedocs.io/en/latest/onnxruntime_op.html) 和 \[mmcv 中的 TensorRT 插件\](https://github.com/open-mmlab/mmcv/blob/master/docs/tensorrt_plugin.md%EF%BC%89%E4%BD%BF%E7%94%A8 ONNXRuntime 自定义操作和 TensorRT 插件安装 `mmcv-full`。 #### 用法 ```bash python tools/deploy_test.py \ ${CONFIG_FILE} \ ${MODEL_PATH} \ ${BACKEND} \ --out ${OUTPUT_FILE} \ --save-path ${SAVE_PATH} \ ----cfg-options ${CFG_OPTIONS} \ ``` #### 参数说明: - `config`: 模型配置文件的路径。 - `model`: TensorRT 或 ONNX 模型文件的路径。 - `backend`: 用于测试的后端,选择 tensorrt 或 onnxruntime。 - `--out`: pickle 格式的输出结果文件的路径。 - `--save-path`: 存储图像的路径,如果没有给出,则不会保存图像。 - `--cfg-options`: 覆盖使用的配置文件中的一些设置,`xxx=yyy` 格式的键值对将被合并到配置文件中。 #### 结果和模型
Model Config Dataset Metric PyTorch ONNX Runtime TensorRT FP32 TensorRT FP16
ESRGAN esrgan_x4c64b23g32_g1_400k_div2k.py Set5 PSNR 28.2700 28.2619 28.2619 28.2616
SSIM 0.7778 0.7784 0.7784 0.7783
Set14 PSNR 24.6328 24.6290 24.6290 24.6274
SSIM 0.6491 0.6494 0.6494 0.6494
DIV2K PSNR 26.6531 26.6532 26.6532 26.6532
SSIM 0.7340 0.7340 0.7340 0.7340
ESRGAN esrgan_psnr_x4c64b23g32_g1_1000k_div2k.py Set5 PSNR 30.6428 30.6307 30.6307 30.6305
SSIM 0.8559 0.8565 0.8565 0.8566
Set14 PSNR 27.0543 27.0422 27.0422 27.0411
SSIM 0.7447 0.7450 0.7450 0.7449
DIV2K PSNR 29.3354 29.3354 29.3354 29.3339
SSIM 0.8263 0.8263 0.8263 0.8263
SRCNN srcnn_x4k915_g1_1000k_div2k.py Set5 PSNR 28.4316 28.4120 27.2144 27.2127
SSIM 0.8099 0.8106 0.7782 0.7781
Set14 PSNR 25.6486 25.6367 24.8613 24.8599
SSIM 0.7014 0.7015 0.6674 0.6673
DIV2K PSNR 27.7460 27.7460 26.9891 26.9862
SSIM 0.7854 0.78543 0.7605 0.7604
**注**: - 所有 ONNX 和 TensorRT 模型都使用数据集上的动态形状进行评估,图像根据原始配置文件进行预处理。 - 此工具仍处于试验阶段,我们目前仅支持 `restorer`。 ================================================ FILE: docs/zh_cn/user_guides/visualization.md ================================================ # 教程 6:可视化 图像的可视化是衡量图像处理、编辑和合成质量的重要手段。 在配置文件中使用 `visualizer` 可以在训练或测试时保存可视化结果。您可以跟随[MMEngine文档](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/advanced_tutorials/visualization.md)学习可视化的用法。MMagic提供了一套丰富的可视化功能。 在本教程中,我们将介绍MMagic提供的可视化函数的用法。 - [教程6:可视化](#教程6:可视化) - [概述](#概述) - [GAN的可视化配置](#gan的可视化配置) - [图像翻译模型的可视化配置](#图像翻译模型的可视化配置) - [扩散模型的可视化配置](#扩散模型的可视化配置) - [图像补全模型的可视化配置](#图像补全模型的可视化配置) - [图像抠图模型的可视化配置](#图像抠图模型的可视化配置) - [SISR/VSR/VFI等模型的可视化配置](#sisrvsrvfi等模型的可视化配置) - [可视化钩子](#可视化钩子) - [可视化器](#可视化器) - [可视化后端](#可视化后端) - [在不同的存储后端可视化](#在不同的存储后端可视化) ## 概述 建议先学习 [设计文档](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/design/visualization.md) 里关于可视化的基本概念。 在MMagic中,训练或测试过程的可视化需要配置三个组件:`VisualizationHook`、`Visualizer`和`VisBackend`, 如下图表展示了 `Visualizer` 和 `VisBackend` 的关系。
**VisualizationHook** 在训练期间以固定的间隔获取模型输出的可视化结果,并将其传递给**Visualizer**。 **Visualizer** 负责将原始可视化结果转换为所需的类型(png, gif等),然后将其传输到**VisBackend**进行存储或显示。 ### GAN的可视化配置 对于像`StyleGAN`和`SAGAN`这样的GAN模型,通常的配置如下所示: ```python # 可视化钩子 custom_hooks = [ dict( type='VisualizationHook', interval=5000, # 配置可视化勾子的间隔数 fixed_input=True, # 是否固定噪声输入生成图像 vis_kwargs_list=dict(type='GAN', name='fake_img') # 对于GAN模型预先定义可视化参数 ) ] # 可视化后端 vis_backends = [ dict(type='VisBackend'), # 可视化后端用于存储。 dict(type='WandbVisBackend', # 可以上传至Wandb的可视化后端 init_kwargs=dict( project='MMagic', # Wandb项目名 name='GAN-Visualization-Demo' # Wandb实验命名 )) ] # 可视化器 visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` 如果您将指数移动平均(EMA)应用于生成器,并希望可视化EMA模型,您可以修改`VisualizationHook`的配置,如下所示: ```python custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # 同时在`fake_img`中可视化ema以及orig vis_kwargs_list=dict( type='Noise', name='fake_img', # 使用`fake_img`保存图片 sample_model='ema/orig', # 对于`NoiseSampler`特别定义参数 target_keys=['ema.fake_img', 'orig.fake_img'] # 指定的可视化的键值 )) ] ``` ### 图像翻译模型的可视化配置 对于`CycleGAN`、`Pix2Pix`等翻译模型,可以形成如下可视化配置: ```python # 可视化钩子 custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=[ dict( type='Translation', # 在训练集可视化结果 name='trans'), # 保存`trans`字段的图像 dict( type='Translationval', # 在验证集可视化结果 name='trans_val'), # 保存`trans_val`字段的图像 ]) ] # 可视化后端 vis_backends = [ dict(type='VisBackend'), # 可视化后端用于存储。 dict(type='WandbVisBackend', # 可以上传至Wandb的可视化后端 init_kwargs=dict( project='MMagic', # Wandb项目名 name='Translation-Visualization-Demo' # Wandb实验命名 )) ] # 可视化器 visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` ### 扩散模型的可视化配置 对于扩散模型,例如`Improved-DDPM`,我们可以使用以下配置通过gif来可视化去噪过程: ```python # 可视化钩子 custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, vis_kwargs_list=dict(type='DDPMDenoising')) # 对于DDPM模型预先定义可视化参数 ] # 可视化后端 vis_backends = [ dict(type='VisBackend'), # 可视化后端用于存储。 dict(type='WandbVisBackend', # 可以上传至Wandb的可视化后端 init_kwargs=dict( project='MMagic', # Wandb项目名 name='Diffusion-Visualization-Demo' # Wandb实验命名 )) ] # 可视化器 visualizer = dict(type='Visualizer', vis_backends=vis_backends) ``` ### 图像补全模型的可视化配置 对于图像补全模型,如`AOT-GAN`和`Global&Local`,通常的配置如下所示: ```python # 可视化后端 vis_backends = [dict(type='LocalVisBackend')] # 可视化器 visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) # 可视化钩子 custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` ### 图像抠图模型的可视化配置 对于`DIM`和`GCA`等图像抠图模型,通常的配置如下所示: ```python # 可视化后端 vis_backends = [dict(type='LocalVisBackend')] # 可视化器 visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='trimap_path', img_keys=['pred_alpha', 'trimap', 'gt_merged', 'gt_alpha'], bgr2rgb=True) # 可视化钩子 custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` ### SISR/VSR/VFI等模型的可视化配置 对于SISR/VSR/VFI等模型,如`EDSR`, `EDVR`和`CAIN`,通常的配置如下所示: ```python # 可视化后端 vis_backends = [dict(type='LocalVisBackend')] # 可视化器 visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=False) # 可视化钩子 custom_hooks = [dict(type='BasicVisualizationHook', interval=1)] ``` 可视化钩子、可视化器和可视化后端组件的具体配置如下所述. ## 可视化钩子 在MMagic中,我们使用`BasicVisualizationHook`和`VisualizationHook`作为可视化钩子。 可视化钩子支持以下三种情况。 (1) 修改`vis_kwargs_list`,实现特定输入下模型输出的可视化,适用于特定数据输入下GAN生成结果和图像翻译模型的翻译结果的可视化等。下面是两个典型的例子: ```python # input as dict vis_kwargs_list = dict( type='Noise', # 使用'Noise'采样生成模型输入 name='fake_img', # 定义保存图像的命名 ) # input as list of dict vis_kwargs_list = [ dict(type='Arguments', # 使用'Arguments'采样生成模型输入 name='arg_output', # 定义保存图像的命名 vis_mode='gif', # 通过gif来可视化 forward_kwargs=dict(forward_mode='sampling', sample_kwargs=dict(show_pbar=True)) # 为'Arguments'采样定义参数 ), dict(type='Data', # 在dataloader使用'Data'采样提供数据作为可视化输入 n_samples=36, # 定义多少采样生成可视化结果 fixed_input=False, # 定义对于可视化过程不固定输入 ) ] ``` `vis_kwargs_list`接受字典或字典的列表作为输入。每个字典必须包含一个`type`字段,指示用于生成模型输入的采样器类型,并且每个字典还必须包含采样器所需的关键字字段(例如:`ArgumentSampler`要求参数字典包含`forward_kwargs`)。 > 需要注意的是,此内容由相应的采样器检查,不受`BasicVisualizationHook`的限制。 此外,其他字段是通用字段(例如:`n_samples`、`n_row`,`name`,`fixed_input`等等)。 如果没有传入,则使用`BasicVisualizationHook`初始化的默认值。 为了方便用户使用,MMagic为**GAN**、**Translation models**、**SinGAN**和**Diffusion models**预置了可视化参数,用户可以通过以下配置直接使用预定义的可视化方法: ```python vis_kwargs_list = dict(type='GAN') vis_kwargs_list = dict(type='SinGAN') vis_kwargs_list = dict(type='Translation') vis_kwargs_list = dict(type='TranslationVal') vis_kwargs_list = dict(type='TranslationTest') vis_kwargs_list = dict(type='DDPMDenoising') ``` ## 可视化器 在MMagic中,我们实现了`ConcatImageVisualizer`和`Visualizer`,它们继承自`mmengine.Visualizer`。 `Visualizer`的基类是`ManagerMixin`,这使得`Visualizer`成为一个全局唯一的对象。 在实例化之后,`Visualizer`可以在代码的任何地方通过`Visualizer.get_current_instance()`调用,如下所示: ```python # configs vis_backends = [dict(type='VisBackend')] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # `get_instance()` 是为全局唯一实例化调用 VISUALIZERS.build(cfg.visualizer) # 通过上述代码实例化后,您可以在任何位置调用`get_current_instance`方法来获取可视化器 visualizer = Visualizer.get_current_instance() ``` `Visualizer`的核心接口是`add_datasample`。 通过这个界面,该接口将根据相应的`vis_mode`调用相应的绘图函数,以获得`np.ndarray`类型的可视化结果。 然后调用`show`或`add_image`来直接显示结果或将可视化结果传递给预定义的`vis_backend`。 ## 可视化后端 - MMEngine的基本VisBackend包括`LocalVisBackend`、`TensorboardVisBackend`和`WandbVisBackend`。您可以关注[MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/advanced_tutorials/visualization.md)了解更多有关它们的信息。 - `VisBackend`: **File System**的后端。将可视化结果保存到相应位置。 - `TensorboardVisBackend`: **Tensorboard**的后端。将可视化结果发送到Tensorboard。 - `WandbVisBackend`: **Wandb**的后端。将可视化结果发送到Tensorboard。 一个`Visualizer`对象可以访问任意数量的`visbackend`,用户可以在代码中通过类名访问后端。 ```python # 配置文件 vis_backends = [dict(type='Visualizer'), dict(type='WandbVisBackend')] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # 代码内 VISUALIZERS.build(cfg.visualizer) visualizer = Visualizer.get_current_instance() # 通过类名访问后端 gen_vis_backend = visualizer.get_backend('VisBackend') gen_wandb_vis_backend = visualizer.get_backend('GenWandbVisBackend') ``` 当有多个`VisBackend`具有相同的类名时,用户必须为每个`VisBackend`指定名称。 ```python # 配置文件 vis_backends = [ dict(type='VisBackend', name='gen_vis_backend_1'), dict(type='VisBackend', name='gen_vis_backend_2') ] visualizer = dict( type='Visualizer', vis_backends=vis_backends, name='visualizer') ``` ```python # 代码内 VISUALIZERS.build(cfg.visualizer) visualizer = Visualizer.get_current_instance() local_vis_backend_1 = visualizer.get_backend('gen_vis_backend_1') local_vis_backend_2 = visualizer.get_backend('gen_vis_backend_2') ``` ### 在不同的存储后端可视化 如果想用不同的存储后端( Wandb, Tensorboard, 或者远程窗口里常规的后端),像以下这样改配置文件的 `vis_backends` 就行了: **Local** ```python vis_backends = [dict(type='LocalVisBackend')] ``` **Tensorboard** ```python vis_backends = [dict(type='TensorboardVisBackend')] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, name='visualizer') ``` **Wandb** ```python vis_backends = [dict(type='WandbVisBackend', init_kwargs=dict(project={PROJECTS}, name={EXPNAME}))] visualizer = dict( type='ConcatImageVisualizer', vis_backends=vis_backends, name='visualizer') ``` ================================================ FILE: mmagic/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmcv import mmengine from .version import __version__, version_info try: from mmcv.utils import digit_version except ImportError: def digit_version(version_str): digit_ver = [] for x in version_str.split('.'): if x.isdigit(): digit_ver.append(int(x)) elif x.find('rc') != -1: patch_version = x.split('rc') digit_ver.append(int(patch_version[0]) - 1) digit_ver.append(int(patch_version[1])) return digit_ver MMCV_MIN = '2.0.0' MMCV_MAX = '2.2.0' mmcv_min_version = digit_version(MMCV_MIN) mmcv_max_version = digit_version(MMCV_MAX) mmcv_version = digit_version(mmcv.__version__) MMENGINE_MIN = '0.4.0' MMENGINE_MAX = '1.0.0' mmengine_min_version = digit_version(MMENGINE_MIN) mmengine_max_version = digit_version(MMENGINE_MAX) mmengine_version = digit_version(mmengine.__version__) assert (mmcv_min_version <= mmcv_version < mmcv_max_version), \ f'mmcv=={mmcv.__version__} is used but incompatible. ' \ f'Please install mmcv-full>={mmcv_min_version}, <{mmcv_max_version}.' assert (mmengine_min_version <= mmengine_version < mmengine_max_version), \ f'mmengine=={mmengine.__version__} is used but incompatible. ' \ f'Please install mmengine>={mmengine_min_version}, ' \ f'<{mmengine_max_version}.' __all__ = ['__version__', 'version_info'] ================================================ FILE: mmagic/apis/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .inferencers.inference_functions import init_model from .mmagic_inferencer import MMagicInferencer __all__ = ['MMagicInferencer', 'init_model'] ================================================ FILE: mmagic/apis/inferencers/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Optional, Union import torch from mmagic.utils import ConfigType from .colorization_inferencer import ColorizationInferencer from .conditional_inferencer import ConditionalInferencer from .controlnet_animation_inferencer import ControlnetAnimationInferencer from .diffusers_pipeline_inferencer import DiffusersPipelineInferencer from .eg3d_inferencer import EG3DInferencer from .image_super_resolution_inferencer import ImageSuperResolutionInferencer from .inpainting_inferencer import InpaintingInferencer from .matting_inferencer import MattingInferencer from .text2image_inferencer import Text2ImageInferencer from .translation_inferencer import TranslationInferencer from .unconditional_inferencer import UnconditionalInferencer from .video_interpolation_inferencer import VideoInterpolationInferencer from .video_restoration_inferencer import VideoRestorationInferencer __all__ = [ 'ColorizationInferencer', 'ConditionalInferencer', 'EG3DInferencer', 'InpaintingInferencer', 'MattingInferencer', 'ImageSuperResolutionInferencer', 'Text2ImageInferencer', 'TranslationInferencer', 'UnconditionalInferencer', 'VideoInterpolationInferencer', 'VideoRestorationInferencer', 'ControlnetAnimationInferencer', 'DiffusersPipelineInferencer' ] class Inferencers: """Class to assign task to different inferencers. Args: task (str): Inferencer task. config (str or ConfigType): Model config or the path to it. ckpt (str, optional): Path to the checkpoint. device (str, optional): Device to run inference. If None, the best device will be automatically used. seed (int): The random seed used in inference. Defaults to 2022. """ def __init__(self, task: Optional[str] = None, config: Optional[Union[ConfigType, str]] = None, ckpt: Optional[str] = None, device: torch.device = None, extra_parameters: Optional[Dict] = None, seed: int = 2022) -> None: self.task = task if self.task in ['conditional', 'Conditional GANs']: self.inferencer = ConditionalInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['colorization', 'Colorization']: self.inferencer = ColorizationInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['unconditional', 'Unconditional GANs', 'DragGAN']: self.inferencer = UnconditionalInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['matting', 'Matting']: self.inferencer = MattingInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['inpainting', 'Inpainting']: self.inferencer = InpaintingInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['translation', 'Image2Image']: self.inferencer = TranslationInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['Image super-resolution', 'Image Super-Resolution']: self.inferencer = ImageSuperResolutionInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['video_restoration', 'Video Super-Resolution']: self.inferencer = VideoRestorationInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['video_interpolation', 'Video Interpolation']: self.inferencer = VideoInterpolationInferencer( config, ckpt, device, extra_parameters) elif self.task in [ 'text2image', 'Text2Image', 'Text2Image, Image2Image' ]: self.inferencer = Text2ImageInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['3D_aware_generation', '3D-aware Generation']: self.inferencer = EG3DInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['controlnet_animation']: self.inferencer = ControlnetAnimationInferencer(config) elif self.task in [ 'Image Restoration', 'Denoising, Deblurring, Deraining', 'Image Super-Resolution, Image denoising, JPEG compression ' 'artifact reduction', 'Deblurring' ]: self.inferencer = ImageSuperResolutionInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['Diffusers Pipeline']: self.inferencer = DiffusersPipelineInferencer( config, ckpt, device, extra_parameters, seed=seed) else: raise ValueError(f'Unknown inferencer task: {self.task}') def __call__(self, **kwargs) -> Union[Dict, List[Dict]]: """Call the inferencer. Args: kwargs: Keyword arguments for the inferencer. Returns: Union[Dict, List[Dict]]: Results of inference pipeline. """ return self.inferencer(**kwargs) def get_extra_parameters(self) -> List[str]: """Each inferencer may has its own parameters. Call this function to get these parameters. Returns: List[str]: List of unique parameters. """ return self.inferencer.get_extra_parameters() ================================================ FILE: mmagic/apis/inferencers/base_mmagic_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Any, Dict, List, Optional, Sequence, Tuple, Union import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmengine.infer import BaseInferencer from mmengine.runner import load_checkpoint from mmengine.structures import BaseDataElement from torchvision import utils from mmagic.registry import MODELS from mmagic.utils import ConfigType, SampleList, register_all_modules from .inference_functions import set_random_seed InputType = Union[str, int, np.ndarray] InputsType = Union[InputType, Sequence[InputType]] PredType = Union[BaseDataElement, SampleList] ImgType = Union[np.ndarray, Sequence[np.ndarray]] ResType = Union[Dict, List[Dict], BaseDataElement, List[BaseDataElement]] class BaseMMagicInferencer(BaseInferencer): """Base inferencer. Args: config (str or ConfigType): Model config or the path to it. ckpt (str, optional): Path to the checkpoint. device (str, optional): Device to run inference. If None, the best device will be automatically used. extra_parameters (Dict, optional): Extra parameters for different models in inference stage. seed (str, optional): Seed for inference. """ func_kwargs = dict( preprocess=[], forward=[], visualize=['result_out_dir'], postprocess=['get_datasample']) func_order = dict(preprocess=0, forward=1, visualize=2, postprocess=3) extra_parameters = dict() def __init__(self, config: Union[ConfigType, str], ckpt: Optional[str], device: Optional[str] = None, extra_parameters: Optional[Dict] = None, seed: int = 2022, **kwargs) -> None: # Load config to cfg if device is None: device = torch.device( 'cuda' if torch.cuda.is_available() else 'cpu') self.device = device register_all_modules() super().__init__(config, ckpt, device) self._init_extra_parameters(extra_parameters) self.base_params = self._dispatch_kwargs(**kwargs) self.seed = seed set_random_seed(self.seed) def _init_model(self, cfg: Union[ConfigType, str], ckpt: Optional[str], device: str) -> None: """Initialize the model with the given config and checkpoint on the specific device.""" model = MODELS.build(cfg.model) if ckpt is not None and ckpt != '': ckpt = load_checkpoint(model, ckpt, map_location='cpu') if cfg.model.get( 'init_cfg') and cfg.model.init_cfg.type == 'convert_from_unet': model.init_weights() model.cfg = cfg model.to(device) model.eval() return model def _init_pipeline(self, cfg: ConfigType) -> Compose: """Initialize the test pipeline.""" if 'test_dataloader' in cfg and \ 'dataset' in cfg.test_dataloader and \ 'pipeline' in cfg.test_dataloader.dataset: pipeline_cfg = cfg.test_dataloader.dataset.pipeline return Compose(pipeline_cfg) return None def _init_extra_parameters(self, extra_parameters: Dict) -> None: """Initialize extra_parameters of each kind of inferencer.""" if extra_parameters is not None: for key in self.extra_parameters.keys(): if key in extra_parameters.keys(): self.extra_parameters[key] = extra_parameters[key] def _update_extra_parameters(self, **kwargs) -> None: """update extra_parameters during run time.""" if 'extra_parameters' in kwargs: input_extra_parameters = kwargs['extra_parameters'] if input_extra_parameters is not None: for key in self.extra_parameters.keys(): if key in input_extra_parameters.keys(): self.extra_parameters[key] = \ input_extra_parameters[key] def _dispatch_kwargs(self, **kwargs) -> Tuple[Dict, Dict, Dict, Dict]: """Dispatch kwargs to preprocess(), forward(), visualize() and postprocess() according to the actual demands.""" results = [{}, {}, {}, {}] dispatched_kwargs = set() # Dispatch kwargs according to self.func_kwargs for func_name, func_kwargs in self.func_kwargs.items(): for func_kwarg in func_kwargs: if func_kwarg in kwargs: dispatched_kwargs.add(func_kwarg) results[self.func_order[func_name]][func_kwarg] = kwargs[ func_kwarg] return results def __call__(self, **kwargs) -> Union[Dict, List[Dict]]: """Call the inferencer. Args: kwargs: Keyword arguments for the inferencer. Returns: Union[Dict, List[Dict]]: Results of inference pipeline. """ if ('extra_parameters' in kwargs.keys() and kwargs['extra_parameters'] and 'infer_with_grad' in kwargs['extra_parameters'].keys() and kwargs['extra_parameters']['infer_with_grad']): results = self.base_call(**kwargs) else: with torch.no_grad(): results = self.base_call(**kwargs) return results def base_call(self, **kwargs) -> Union[Dict, List[Dict]]: """Call the inferencer. Args: kwargs: Keyword arguments for the inferencer. Returns: Union[Dict, List[Dict]]: Results of inference pipeline. """ self._update_extra_parameters(**kwargs) params = self._dispatch_kwargs(**kwargs) preprocess_kwargs = self.base_params[0].copy() preprocess_kwargs.update(params[0]) forward_kwargs = self.base_params[1].copy() forward_kwargs.update(params[1]) visualize_kwargs = self.base_params[2].copy() visualize_kwargs.update(params[2]) postprocess_kwargs = self.base_params[3].copy() postprocess_kwargs.update(params[3]) data = self.preprocess(**preprocess_kwargs) preds = self.forward(data, **forward_kwargs) imgs = self.visualize(preds, **visualize_kwargs) results = self.postprocess(preds, imgs, **postprocess_kwargs) return results def get_extra_parameters(self) -> List[str]: """Each inferencer may has its own parameters. Call this function to get these parameters. Returns: List[str]: List of unique parameters. """ return list(self.extra_parameters.keys()) def postprocess( self, preds: PredType, imgs: Optional[List[np.ndarray]] = None, is_batch: bool = False, get_datasample: bool = False, ) -> Union[ResType, Tuple[ResType, np.ndarray]]: """Postprocess predictions. Args: preds (List[Dict]): Predictions of the model. imgs (Optional[np.ndarray]): Visualized predictions. is_batch (bool): Whether the inputs are in a batch. Defaults to False. get_datasample (bool): Whether to use Datasample to store inference results. If False, dict will be used. Returns: result (Dict): Inference results as a dict. imgs (torch.Tensor): Image result of inference as a tensor or tensor list. """ results = preds if not get_datasample: results = [] for pred in preds: result = self._pred2dict(pred) results.append(result) if not is_batch: results = results[0] return results, imgs def _pred2dict(self, pred_tensor: torch.Tensor) -> Dict: """Extract elements necessary to represent a prediction into a dictionary. It's better to contain only basic data elements such as strings and numbers in order to guarantee it's json-serializable. Args: pred_tensor (torch.Tensor): The tensor to be converted. Returns: dict: The output dictionary. """ result = {} result['infer_results'] = pred_tensor return result def visualize(self, inputs: list, preds: Any, show: bool = False, result_out_dir: str = '', **kwargs) -> List[np.ndarray]: """Visualize predictions. Customize your visualization by overriding this method. visualize should return visualization results, which could be np.ndarray or any other objects. Args: inputs (list): Inputs preprocessed by :meth:`_inputs_to_list`. preds (Any): Predictions of the model. show (bool): Whether to display the image in a popup window. Defaults to False. result_out_dir (str): Output directory of images. Defaults to ''. Returns: List[np.ndarray]: Visualization results. """ results = (preds[:, [2, 1, 0]] + 1.) / 2. # save images if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) utils.save_image(results, result_out_dir) return results ================================================ FILE: mmagic/apis/inferencers/colorization_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import mmcv import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmengine.dataset.utils import default_collate as collate from mmagic.structures import DataSample from mmagic.utils import tensor2img from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class ColorizationInferencer(BaseMMagicInferencer): """inferencer that predicts with colorization models.""" func_kwargs = dict( preprocess=['img'], forward=[], visualize=['result_out_dir'], postprocess=[]) def preprocess(self, img: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: img(InputsType): Image to be translated by models. Returns: results(Dict): Results of preprocess. """ # build the data pipeline test_pipeline = Compose(self.model.cfg.test_pipeline) # prepare data data = dict(img_path=img) _data = test_pipeline(data) data = dict() data['inputs'] = _data['inputs'] / 255.0 data = collate([data]) data['data_samples'] = [_data['data_samples']] if 'empty_box' not in data['data_samples'][0]: data['data_samples'][0].set_data({'empty_box': True}) if not data['data_samples'][0].empty_box: data['data_samples'][0].cropped_img.data = \ data['data_samples'][0].cropped_img.data / 255.0 if 'cuda' in str(self.device): data['inputs'] = data['inputs'].cuda() data['data_samples'][0] = data['data_samples'][0].cuda() data['data_samples'] = DataSample.stack(data['data_samples']) return data def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" with torch.no_grad(): result = self.model(mode='tensor', **inputs) return result def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ results = tensor2img(preds[0]) if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) mmcv.imwrite(results, result_out_dir) return results ================================================ FILE: mmagic/apis/inferencers/conditional_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import numpy as np import torch from mmengine import mkdir_or_exist from torchvision import utils from mmagic.structures import DataSample from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class ConditionalInferencer(BaseMMagicInferencer): """inferencer that predicts with conditional models.""" func_kwargs = dict( preprocess=['label'], forward=[], visualize=['result_out_dir'], postprocess=[]) extra_parameters = dict(num_batches=4, sample_model='orig') def preprocess(self, label: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: label(InputsType): Input label for condition models. Returns: results(Dict): Results of preprocess. """ num_batches = self.extra_parameters['num_batches'] sample_model = self.extra_parameters['sample_model'] results = dict( num_batches=num_batches, labels=label, sample_model=sample_model) return results def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" return self.model(inputs) def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ res_list = [] res_list.extend([item.fake_img.data.cpu() for item in preds]) results = torch.stack(res_list, dim=0) results = results[:, [2, 1, 0]] / 255. # save images if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) utils.save_image(results, result_out_dir) return results def _pred2dict(self, data_sample: DataSample) -> Dict: """Extract elements necessary to represent a prediction into a dictionary. It's better to contain only basic data elements such as strings and numbers in order to guarantee it's json-serializable. Args: data_sample (DataSample): The data sample to be converted. Returns: dict: The output dictionary. """ result = {} result['fake_img'] = data_sample.fake_img.data.cpu() result['gt_label'] = data_sample.gt_label.label return result ================================================ FILE: mmagic/apis/inferencers/controlnet_animation_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List, Optional, Union import cv2 import mmcv import numpy as np import PIL.Image import requests import torch from controlnet_aux import HEDdetector from mmengine.config import Config from mmengine.runner import set_random_seed from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.utils import ConfigType from .base_mmagic_inferencer import BaseMMagicInferencer VIDEO_EXTENSIONS = ('.mp4', '.mov', '.avi') IMAGE_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG') def load_image(image: Union[str, PIL.Image.Image]) -> PIL.Image.Image: """ Args: Loads `image` to a PIL Image. image (`str` or `PIL.Image.Image`): The image to convert to the PIL Image format. Returns: `PIL.Image.Image`: A PIL Image. """ if isinstance(image, str): if image.startswith('http://') or image.startswith('https://'): image = PIL.Image.open(requests.get(image, stream=True).raw) elif os.path.isfile(image): image = PIL.Image.open(image) else: raise ValueError( f'Incorrect path or url, URLs must start with `http://` ' f'or `https://`, and {image} is not a valid path') elif isinstance(image, PIL.Image.Image): image = image else: raise ValueError( 'Incorrect format used for image. Should be an url linking' ' to an image, a local path, or a PIL image.') image = PIL.ImageOps.exif_transpose(image) image = image.convert('RGB') return image class ControlnetAnimationInferencer(BaseMMagicInferencer): """Base inferencer. Args: config (str or ConfigType): Model config or the path to it. ckpt (str, optional): Path to the checkpoint. device (str, optional): Device to run inference. If None, the best device will be automatically used. result_out_dir (str): Output directory of images. Defaults to ''. """ func_kwargs = dict( preprocess=[], forward=[], visualize=['result_out_dir'], postprocess=['get_datasample']) func_order = dict(preprocess=0, forward=1, visualize=2, postprocess=3) extra_parameters = dict() def __init__(self, config: Union[ConfigType, str], device: Optional[str] = None, extra_parameters: Optional[Dict] = None, dtype=torch.float32, **kwargs) -> None: cfg = Config.fromfile(config) self.hed = HEDdetector.from_pretrained(cfg.control_detector) self.inference_method = cfg.inference_method if self.inference_method == 'attention_injection': cfg.model.attention_injection = True self.pipe = MODELS.build(cfg.model).cuda().eval() control_scheduler_cfg = dict( type=cfg.control_scheduler, from_config=self.pipe.scheduler.config, ) control_scheduler = DIFFUSION_SCHEDULERS.build(control_scheduler_cfg) self.pipe.test_scheduler = control_scheduler @torch.no_grad() def __call__(self, prompt=None, video=None, negative_prompt=None, controlnet_conditioning_scale=0.7, image_width=512, image_height=512, save_path=None, strength=0.75, num_inference_steps=20, seed=1, output_fps=None, reference_img=None, **kwargs) -> Union[Dict, List[Dict]]: """Call the inferencer. Args: kwargs: Keyword arguments for the inferencer. Returns: Union[Dict, List[Dict]]: Results of inference pipeline. """ if save_path is None: from datetime import datetime datestring = datetime.now().strftime('%y%m%d-%H%M%S') save_path = '/tmp/' + datestring + '.mp4' set_random_seed(seed) latent_width = image_width // 8 latent_height = image_height // 8 init_noise_shape = (1, 4, latent_height, latent_width) init_noise_all_frame = torch.randn( init_noise_shape, dtype=self.pipe.controlnet.dtype).cuda() init_noise_shape_cat = (1, 4, latent_height, latent_width * 3) init_noise_all_frame_cat = torch.randn( init_noise_shape_cat, dtype=self.pipe.controlnet.dtype).cuda() latent_mask = torch.zeros( (1, 4, image_height // 8, image_width // 8 * 3)) latent_mask[:, :, :, image_width // 8 + 1:image_width // 8 * 2 - 1] = 1.0 latent_mask = latent_mask.type(self.pipe.controlnet.dtype).cuda() # load the images input_file_extension = os.path.splitext(video)[1] from_video = True all_images = [] if input_file_extension in VIDEO_EXTENSIONS: video_reader = mmcv.VideoReader(video) input_fps = int(video_reader.fps) if output_fps is None: output_fps = input_fps if output_fps > input_fps: output_fps = input_fps sample_rate = int(input_fps / output_fps) fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_writer = cv2.VideoWriter(save_path, fourcc, output_fps, (image_width, image_height)) for frame in video_reader: all_images.append(np.flip(frame, axis=2)) else: frame_files = os.listdir(video) frame_files = [os.path.join(video, f) for f in frame_files] frame_files.sort() for frame in frame_files: frame_extension = os.path.splitext(frame)[1] if frame_extension in IMAGE_EXTENSIONS: all_images.append(frame) if not os.path.exists(save_path): os.makedirs(save_path) from_video = False if self.inference_method == 'multi-frame rendering': # first result if from_video: image = PIL.Image.fromarray(all_images[0]) else: image = load_image(all_images[0]) image = image.resize((image_width, image_height)) detect_resolution = min(image_width, image_height) hed_image = self.hed( image, detect_resolution=detect_resolution, image_resolution=detect_resolution) hed_image = hed_image.resize((image_width, image_height)) result = self.pipe.infer( control=hed_image, latent_image=image, prompt=prompt, negative_prompt=negative_prompt, strength=strength, controlnet_conditioning_scale=controlnet_conditioning_scale, num_inference_steps=num_inference_steps, latents=init_noise_all_frame)['samples'][0] first_result = result first_hed = hed_image last_result = result last_hed = hed_image for ind in range(len(all_images)): if from_video: if ind % sample_rate > 0: continue image = PIL.Image.fromarray(all_images[ind]) else: image = load_image(all_images[ind]) print('processing frame ind ' + str(ind)) image = image.resize((image_width, image_height)) hed_image = self.hed(image, image_resolution=image_width) concat_img = PIL.Image.new('RGB', (image_width * 3, image_height)) concat_img.paste(last_result, (0, 0)) concat_img.paste(image, (image_width, 0)) concat_img.paste(first_result, (image_width * 2, 0)) concat_hed = PIL.Image.new('RGB', (image_width * 3, image_height), 'black') concat_hed.paste(last_hed, (0, 0)) concat_hed.paste(hed_image, (image_width, 0)) concat_hed.paste(first_hed, (image_width * 2, 0)) result = self.pipe.infer( control=concat_hed, latent_image=concat_img, prompt=prompt, negative_prompt=negative_prompt, strength=strength, controlnet_conditioning_scale= # noqa controlnet_conditioning_scale, num_inference_steps=num_inference_steps, latents=init_noise_all_frame_cat, latent_mask=latent_mask, )['samples'][0] result = result.crop( (image_width, 0, image_width * 2, image_height)) last_result = result last_hed = hed_image if from_video: video_writer.write(np.flip(np.asarray(result), axis=2)) else: frame_name = frame_files[ind].split('/')[-1] save_name = os.path.join(save_path, frame_name) result.save(save_name) if from_video: video_writer.release() else: if reference_img is None: if from_video: image = PIL.Image.fromarray(all_images[0]) else: image = load_image(all_images[0]) image = image.resize((image_width, image_height)) detect_resolution = min(image_width, image_height) hed_image = self.hed( image, detect_resolution=detect_resolution, image_resolution=detect_resolution) hed_image = hed_image.resize((image_width, image_height)) result = self.pipe.infer( control=hed_image, latent_image=image, prompt=prompt, negative_prompt=negative_prompt, strength=strength, controlnet_conditioning_scale= # noqa controlnet_conditioning_scale, num_inference_steps=num_inference_steps, latents=init_noise_all_frame)['samples'][0] reference_img = result else: reference_img = load_image(reference_img) reference_img = reference_img.resize( (image_width, image_height)) for ind in range(len(all_images)): if from_video: if ind % sample_rate > 0: continue image = PIL.Image.fromarray(all_images[ind]) else: image = load_image(all_images[ind]) print('processing frame ind ' + str(ind)) image = image.resize((image_width, image_height)) hed_image = self.hed(image, image_resolution=image_width) result = self.pipe.infer( control=hed_image, latent_image=image, prompt=prompt, negative_prompt=negative_prompt, strength=strength, controlnet_conditioning_scale= # noqa controlnet_conditioning_scale, num_inference_steps=num_inference_steps, latents=init_noise_all_frame, reference_img=reference_img, )['samples'][0] if from_video: video_writer.write(np.flip(np.asarray(result), axis=2)) else: frame_name = frame_files[ind].split('/')[-1] save_name = os.path.join(save_path, frame_name) result.save(save_name) if from_video: video_writer.release() return save_path ================================================ FILE: mmagic/apis/inferencers/diffusers_pipeline_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import numpy as np from mmengine import mkdir_or_exist from PIL.Image import Image from torchvision.utils import save_image from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class DiffusersPipelineInferencer(BaseMMagicInferencer): """inferencer that predicts with text2image models.""" func_kwargs = dict( preprocess=[ 'text', 'negative_prompt', 'num_inference_steps', 'height', 'width' ], forward=[], visualize=['result_out_dir'], postprocess=[]) def preprocess(self, text: InputsType = None, negative_prompt: InputsType = None, num_inference_steps: int = 20, height=None, width=None) -> Dict: """Process the inputs into a model-feedable format. Args: text(InputsType): text input for text-to-image model. negative_prompt(InputsType): negative prompt. Returns: result(Dict): Results of preprocess. """ result = self.extra_parameters if text: result['prompt'] = text if negative_prompt: result['negative_prompt'] = negative_prompt if num_inference_steps: result['num_inference_steps'] = num_inference_steps if height: result['height'] = height if width: result['width'] = width return result def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" images = self.model(**inputs).images return images def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) if type(preds) is list: preds = preds[0] if type(preds) is Image: preds.save(result_out_dir) else: save_image(preds, result_out_dir, normalize=True) return preds ================================================ FILE: mmagic/apis/inferencers/eg3d_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from collections import defaultdict from typing import Dict, List, Optional, Sequence, Union import numpy as np import torch from mmengine import print_log from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from PIL import Image from torch.nn import functional as F from torchvision.utils import make_grid from mmagic.structures import DataSample from mmagic.utils import ForwardInputs, try_import from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType from .inference_functions import calculate_grid_size imageio = try_import('imageio') imageio_ffmpeg = try_import('imageio_ffmpeg') class EG3DInferencer(BaseMMagicInferencer): func_kwargs = dict( preprocess=['inputs'], forward=['num_images', 'interpolation'], visualize=[ 'result_out_dir', 'vis_mode', 'save_img', 'save_video', 'img_suffix', 'video_suffix' ], postprocess=[]) extra_parameters = dict(num_batches=4, sample_model='ema', add_noise=False) def preprocess(self, inputs: InputsType = None) -> ForwardInputs: """Process the inputs into a model-feedable format. Args: inputs (List[Union[str, np.ndarray]]): The conditional inputs for the inferencer. Defaults to None. Returns: ForwardInputs: The preprocessed inputs and data samples. """ if isinstance(inputs, Sequence): assert all([type(inputs[0]) == type(lab) for lab in inputs ]), ('All label inputs must have the same type.') if isinstance(inputs[0], list): for lab in inputs: assert all([isinstance(l_, float) for l_ in lab]) inputs = np.array(inputs).astype(np.float32) elif isinstance(inputs[0], np.ndarray): assert all([lab.ndim == 1 for lab in inputs]) inputs = [input_.astype(np.float32) for input_ in inputs] else: raise ValueError( 'EG3D only support ndarry or list as label input.') data_sample_list = [] for lab in inputs: data_sample = DataSample() data_sample.set_gt_label(lab) data_sample_list.append(data_sample.to(self.device)) self.extra_parameters['num_batches'] = len(inputs) else: data_sample_list = None num_batches = self.extra_parameters['num_batches'] sample_model = self.extra_parameters['sample_model'] add_noise = self.extra_parameters['add_noise'] inputs = dict( num_batches=num_batches, sample_model=sample_model, add_noise=add_noise) if data_sample_list is None: data_samples = None else: data_samples = DataSample.stack(data_sample_list) return inputs, data_samples def forward(self, inputs: ForwardInputs, interpolation: Optional[str] = 'both', num_images: int = 100) -> Union[dict, List[dict]]: """Forward the inputs to the model. Args: inputs (ForwardInputs): Model inputs. If data sample (the second element of `inputs`) is not passed, will generate a sequence of images corresponding to passed `interpolation` mode. interpolation (str): The interpolation mode. Supported choices are 'both', 'conditioning', and 'camera'. Defaults to 'both'. num_images (int): The number of frames of interpolation. Defaults to 500. Returns: Union[dict, List[dict]]: Output dict corresponds to the input condition or the list of output dict of each frame during the interpolation process. """ inputs, data_sample = inputs # unpack the tuple # forward as the passed input if data_sample is not None: outputs = self.model(inputs, data_sample) output_dict = defaultdict(list) # return outputs for output in outputs: fake_img = output.fake_img.data depth_img = output.depth lr_img = output.lr_img.data ray_origins = output.ray_origins ray_directions = output.ray_directions output_dict['fake_img'].append(fake_img) output_dict['depth'].append(depth_img) output_dict['lr_img'].append(lr_img) output_dict['ray_origins'].append(ray_origins) output_dict['ray_directions'].append(ray_directions) for k in output_dict.keys(): output_dict[k] = torch.stack(output_dict[k], dim=0) return output_dict num_batches = inputs['num_batches'] output_list = self.model.interpolation(num_images, num_batches, interpolation) return output_list def visualize(self, preds: Union[PredType, List[PredType]], vis_mode: str = 'both', save_img: bool = True, save_video: bool = True, img_suffix: str = '.png', video_suffix: str = '.mp4', result_out_dir: str = 'eg3d_output') -> None: """Visualize predictions. Args: preds (Union[PredType, List[PredType]]): Prediction os model. vis_mode (str, optional): Which output to visualize. Supported choices are 'both', 'depth', and 'img'. Defaults to 'all'. save_img (bool, optional): Whether save images. Defaults to True. save_video (bool, optional): Whether save videos. Defaults to True. img_suffix (str, optional): The suffix of saved images. Defaults to '.png'. video_suffix (str, optional): The suffix of saved videos. Defaults to '.mp4'. result_out_dir (str, optional): The save director of image and videos. Defaults to 'eg3d_output'. """ if save_video: assert imageio is not None, ( 'Please install imageio by \'pip install ' 'imageio\' to save video.') assert imageio_ffmpeg is not None, ( 'Please install imageio-ffmpeg by \'pip install ' 'imageio-ffmpeg\' to save video.') os.makedirs(result_out_dir, exist_ok=True) assert vis_mode.upper() in ['BOTH', 'DEPTH', 'IMG'] if vis_mode.upper() == 'BOTH': vis_mode = ['DEPTH', 'IMG'] if not isinstance(vis_mode, list): vis_mode = [vis_mode] if not isinstance(preds, list): preds = [preds] if save_video: save_video = False print_log('Only one frame of output is generated and cannot ' 'save video. Set \'save_video\' to \'False\' ' 'automatically.') if not save_img: save_img = True print_log('Only one frame of output is generated can only save' 'image. Set \'save_img\' to \'True\' automatically.') # save video batch_size = preds[0]['fake_img'].shape[0] img_dict = {} for target in vis_mode: target = 'fake_img' if target.upper() == 'IMG' else target if target.lower() == 'fake_img': imgs = self.preprocess_img(preds) else: imgs = self.preprocess_depth(preds) img_dict[target.lower()] = imgs nrow = calculate_grid_size(batch_size) if save_video: video_path = osp.join( result_out_dir, f'{target.lower()}_seed{self.seed}{video_suffix}') video_writer = imageio.get_writer( video_path, mode='I', fps=60, codec='libx264', bitrate='10M') frame_list = torch.split(imgs, batch_size) for idx, frame in enumerate(frame_list): # frame: [bz, C, H, W] frame_grid = make_grid( frame, nrow=nrow).permute(1, 2, 0)[..., (2, 1, 0)] frame_grid = frame_grid.numpy().astype(np.uint8) if save_video: video_writer.append_data(frame_grid) if save_img: if len(frame_list) != 1: img_name = (f'{target.lower()}_frame{idx}_' f'seed{self.seed}{img_suffix}') else: img_name = (f'{target.lower()}_seed{self.seed}' f'{img_suffix}') img_path = osp.join(result_out_dir, img_name) Image.fromarray(frame_grid).save(img_path) if save_video: video_writer.close() print_log(f'Save video to \'{video_path}\'.', 'current') if len(vis_mode) > 1: fake_img = img_dict['fake_img'] depth_img = img_dict['depth'] # [num_frame * bz, 3, H, W * 2] imgs = torch.cat([fake_img, depth_img], dim=-1) nrow = calculate_grid_size(batch_size, aspect_ratio=2) if save_video: video_path = osp.join( result_out_dir, f'combine_seed{self.seed}{video_suffix}') video_writer = imageio.get_writer( video_path, mode='I', fps=60, codec='libx264', bitrate='10M') frame_list = torch.split(imgs, batch_size) for idx, frame in enumerate(frame_list): frame_grid = make_grid( frame, nrow=nrow).permute(1, 2, 0)[..., (2, 1, 0)] frame_grid = frame_grid.numpy().astype(np.uint8) if save_video: video_writer.append_data(frame_grid) if save_img: if len(frame_list) != 1: img_name = (f'combine_frame{idx}_' f'seed{self.seed}{img_suffix}') else: img_name = (f'combine_seed{self.seed}' f'{img_suffix}') img_path = osp.join(result_out_dir, img_name) Image.fromarray(frame_grid).save(img_path) if save_video: video_writer.close() print_log(f'Save video to \'{video_path}\'.', 'current') def preprocess_img(self, preds: List[dict]) -> torch.Tensor: """Preprocess images in the predictions. Args: preds (List[dict]): List of prediction dict of each frame. Returns: torch.Tensor: Preprocessed image tensor shape like [num_frame * bz, 3, H, W]. """ imgs = [p['fake_img'].cpu() for p in preds] imgs = torch.cat(imgs, dim=0) # [num_frame * bz, 3, H, W] imgs = ((imgs + 1) / 2 * 255.).clamp(0, 255) return imgs def preprocess_depth(self, preds: List[dict]) -> torch.Tensor: """Preprocess depth in the predictions. Args: preds (List[dict]): List of prediction dict of each frame. Returns: torch.Tensor: Preprocessed depth tensor shape like [num_frame * bz, 3, H, W]. """ depth = [p['depth'].cpu() for p in preds] depth = torch.cat(depth, dim=0) depth = -depth depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255. depth = depth.clamp(0, 255).repeat(1, 3, 1, 1) img_size = preds[0]['fake_img'].shape[-1] if img_size != depth.shape[-1]: interpolation_kwargs = dict( size=img_size, mode='bilinear', align_corners=False) if digit_version(TORCH_VERSION) >= digit_version('1.11.0'): interpolation_kwargs['antialias'] = True depth = F.interpolate(depth, **interpolation_kwargs) return depth def postprocess(self, preds: PredType, imgs: Optional[List[np.ndarray]] = None, is_batch: bool = False, get_datasample: bool = False) -> Dict[str, torch.tensor]: """Postprocess predictions. Args: preds (List[Dict]): Predictions of the model. imgs (Optional[np.ndarray]): Visualized predictions. is_batch (bool): Whether the inputs are in a batch. Defaults to False. get_datasample (bool): Whether to use Datasample to store inference results. If False, dict will be used. Returns: Dict[str, torch.Tensor]: Inference results as a dict. """ if isinstance(preds[0], dict): keys = preds[0].keys() outputs = defaultdict(list) for pred in preds: for k in keys: outputs[k].append(pred[k]) for k in keys: outputs[k] = torch.stack(outputs[k], dim=0) return outputs # directly return the dict return preds ================================================ FILE: mmagic/apis/inferencers/image_super_resolution_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import mmcv import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmagic.utils import tensor2img from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class ImageSuperResolutionInferencer(BaseMMagicInferencer): """inferencer that predicts with restoration models.""" func_kwargs = dict( preprocess=['img', 'ref'], forward=[], visualize=['result_out_dir'], postprocess=[]) def preprocess(self, img: InputsType, ref: InputsType = None) -> Dict: """Process the inputs into a model-feedable format. Args: img(InputsType): Image to be restored by models. ref(InputsType): Reference image for restoration models. Defaults to None. Returns: data(Dict): Results of preprocess. """ cfg = self.model.cfg # select the data pipeline if cfg.get('inference_pipeline', None): test_pipeline = cfg.inference_pipeline elif cfg.get('demo_pipeline', None): test_pipeline = cfg.demo_pipeline elif cfg.get('test_pipeline', None): test_pipeline = cfg.test_pipeline else: test_pipeline = cfg.val_pipeline keys_to_remove = ['gt', 'gt_path'] for key in keys_to_remove: for pipeline in list(test_pipeline): if 'key' in pipeline and key == pipeline['key']: test_pipeline.remove(pipeline) if 'keys' in pipeline and key in pipeline['keys']: pipeline['keys'].remove(key) if len(pipeline['keys']) == 0: test_pipeline.remove(pipeline) if 'meta_keys' in pipeline and key in pipeline['meta_keys']: pipeline['meta_keys'].remove(key) # build the data pipeline test_pipeline = Compose(test_pipeline) # prepare data if ref: # Ref-SR data = dict(img_path=img, ref_path=ref) else: # SISR data = dict(img_path=img) _data = test_pipeline(data) data = dict() data['inputs'] = [_data['inputs']] data['data_samples'] = [_data['data_samples']] return data def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" inputs = self.model.data_preprocessor(inputs) with torch.no_grad(): result = self.model(mode='predict', **inputs) return result def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ result = preds[0].output.pred_img / 255. results = tensor2img(result)[..., ::-1] if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) mmcv.imwrite(results, result_out_dir) return results ================================================ FILE: mmagic/apis/inferencers/inference_functions.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import mmcv import numpy as np import torch from mmengine import Config from mmengine.config import ConfigDict from mmengine.fileio import get_file_backend from mmengine.registry import init_default_scope from mmengine.runner import load_checkpoint from mmengine.runner import set_random_seed as set_random_seed_engine from mmagic.registry import MODELS VIDEO_EXTENSIONS = ('.mp4', '.mov', '.avi') FILE_CLIENT = get_file_backend(backend_args={'backend': 'local'}) def set_random_seed(seed, deterministic=False, use_rank_shift=True): """Set random seed. In this function, we just modify the default behavior of the similar function defined in MMCV. Args: seed (int): Seed to be used. deterministic (bool): Whether to set the deterministic option for CUDNN backend, i.e., set `torch.backends.cudnn.deterministic` to True and `torch.backends.cudnn.benchmark` to False. Default: False. rank_shift (bool): Whether to add rank number to the random seed to have different random seed in different threads. Default: True. """ set_random_seed_engine(seed, deterministic, use_rank_shift) def delete_cfg(cfg, key='init_cfg'): """Delete key from config object. Args: cfg (str or :obj:`mmengine.Config`): Config object. key (str): Which key to delete. """ if key in cfg: cfg.pop(key) for _key in cfg.keys(): if isinstance(cfg[_key], ConfigDict): delete_cfg(cfg[_key], key) def init_model(config, checkpoint=None, device='cuda:0'): """Initialize a model from config file. Args: config (str or :obj:`mmengine.Config`): Config file path or the config object. checkpoint (str, optional): Checkpoint path. If left as None, the model will not load any weights. device (str): Which device the model will deploy. Default: 'cuda:0'. Returns: nn.Module: The constructed model. """ if isinstance(config, str): config = Config.fromfile(config) elif not isinstance(config, Config): raise TypeError('config must be a filename or Config object, ' f'but got {type(config)}') # config.test_cfg.metrics = None delete_cfg(config.model, 'init_cfg') init_default_scope(config.get('default_scope', 'mmagic')) model = MODELS.build(config.model) if checkpoint is not None: checkpoint = load_checkpoint(model, checkpoint) model.cfg = config # save the config in the model for convenience model.to(device) model.eval() return model def pad_sequence(data, window_size): """Pad frame sequence data. Args: data (Tensor): The frame sequence data. window_size (int): The window size used in sliding-window framework. Returns: data (Tensor): The padded result. """ padding = window_size // 2 data = torch.cat([ data[:, 1 + padding:1 + 2 * padding].flip(1), data, data[:, -1 - 2 * padding:-1 - padding].flip(1) ], dim=1) return data def read_image(filepath): """Read image from file. Args: filepath (str): File path. Returns: image (np.array): Image. """ img_bytes = FILE_CLIENT.get(filepath) image = mmcv.imfrombytes( img_bytes, flag='color', channel_order='rgb', backend='pillow') return image def read_frames(source, start_index, num_frames, from_video, end_index): """Read frames from file or video. Args: source (list | mmcv.VideoReader): Source of frames. start_index (int): Start index of frames. num_frames (int): frames number to be read. from_video (bool): Weather read frames from video. end_index (int): The end index of frames. Returns: images (np.array): Images. """ images = [] last_index = min(start_index + num_frames, end_index) # read frames from video if from_video: for index in range(start_index, last_index): if index >= source.frame_cnt: break images.append(np.flip(source.get_frame(index), axis=2)) else: files = source[start_index:last_index] images = [read_image(f) for f in files] return images def calculate_grid_size(num_batches: int = 1, aspect_ratio: int = 1) -> int: """Calculate the number of images per row (nrow) to make the grid closer to square when formatting a batch of images to grid. Args: num_batches (int, optional): Number of images per batch. Defaults to 1. aspect_ratio (int, optional): The aspect ratio (width / height) of each image sample. Defaults to 1. Returns: int: Calculated number of images per row. """ curr_ncol, curr_nrow = 1, num_batches curr_delta = curr_nrow * aspect_ratio - curr_ncol nrow = curr_nrow delta = curr_delta while curr_delta > 0: curr_ncol += 1 curr_nrow = math.ceil(num_batches / curr_ncol) curr_delta = curr_nrow * aspect_ratio - curr_ncol if curr_delta < delta and curr_delta >= 0: nrow, delta = curr_nrow, curr_delta return nrow ================================================ FILE: mmagic/apis/inferencers/inpainting_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import mmcv import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmagic.utils import tensor2img from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class InpaintingInferencer(BaseMMagicInferencer): """inferencer that predicts with inpainting models.""" func_kwargs = dict( preprocess=['img', 'mask'], forward=[], visualize=['result_out_dir'], postprocess=[]) def _init_pipeline(self, cfg) -> Compose: """Initialize the test pipeline.""" return None def preprocess(self, img: InputsType, mask: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: img(InputsType): Image to be inpainted by models. mask(InputsType): Image mask for inpainting models. Returns: results(Dict): Results of preprocess. """ infer_pipeline_cfg = [ dict(type='LoadImageFromFile', key='gt', channel_order='bgr'), dict( type='LoadMask', mask_mode='file', ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] infer_pipeline = Compose(infer_pipeline_cfg) # prepare data _data = infer_pipeline(dict(gt_path=img, mask_path=mask)) data = dict() data['inputs'] = [_data['inputs']] data['data_samples'] = [_data['data_samples']] return data def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" inputs = self.model.data_preprocessor(inputs) with torch.no_grad(): result = self.model(mode='predict', **inputs) return result def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Mask of input image. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ result = preds[0].output.pred_img / 255. result = tensor2img(result)[..., ::-1] if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) mmcv.imwrite(result, result_out_dir) return result ================================================ FILE: mmagic/apis/inferencers/matting_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import mmcv import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmagic.structures import DataSample from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class MattingInferencer(BaseMMagicInferencer): """inferencer that predicts with matting models.""" func_kwargs = dict( preprocess=['img', 'trimap'], forward=[], visualize=['result_out_dir'], postprocess=[]) def preprocess(self, img: InputsType, trimap: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: img(InputsType): Image to be processed by models. mask(InputsType): Mask corresponding to the input image. Returns: results(Dict): Results of preprocess. """ # remove alpha from test_pipeline keys_to_remove = ['alpha', 'ori_alpha'] for key in keys_to_remove: for pipeline in list(self.cfg.test_pipeline): if 'key' in pipeline and key == pipeline['key']: self.cfg.test_pipeline.remove(pipeline) if 'keys' in pipeline and key in pipeline['keys']: pipeline['keys'].remove(key) if len(pipeline['keys']) == 0: self.cfg.test_pipeline.remove(pipeline) if 'meta_keys' in pipeline and key in pipeline['meta_keys']: pipeline['meta_keys'].remove(key) # build the data pipeline test_pipeline = Compose(self.cfg.test_pipeline) # prepare data data = dict(merged_path=img, trimap_path=trimap) _data = test_pipeline(data) trimap = _data['data_samples'].trimap.data preprocess_res = dict() preprocess_res['inputs'] = [_data['inputs']] preprocess_res['data_samples'] = [_data['data_samples']] return preprocess_res def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" inputs = self.model.data_preprocessor(inputs) with torch.no_grad(): return self.model(mode='predict', **inputs) def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ result = preds[0].output result = result.pred_alpha.data.cpu() # save images if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) mmcv.imwrite(result.numpy(), result_out_dir) return result def _pred2dict(self, data_sample: DataSample) -> Dict: """Extract elements necessary to represent a prediction into a dictionary. It's better to contain only basic data elements such as strings and numbers in order to guarantee it's json-serializable. Args: data_sample (DataSample): The data sample to be converted. Returns: dict: The output dictionary. """ result = {} result['pred_alpha'] = data_sample.output.pred_alpha.data.cpu() return result ================================================ FILE: mmagic/apis/inferencers/text2image_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import mmcv import numpy as np from mmengine import mkdir_or_exist from PIL.Image import Image, fromarray from torchvision.utils import save_image from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class Text2ImageInferencer(BaseMMagicInferencer): """inferencer that predicts with text2image models.""" func_kwargs = dict( preprocess=['text', 'control', 'negative_prompt'], forward=[], visualize=['result_out_dir'], postprocess=[]) extra_parameters = dict(height=None, width=None, seed=1) def preprocess(self, text: InputsType, control: str = None, negative_prompt: InputsType = None) -> Dict: """Process the inputs into a model-feedable format. Args: text(InputsType): text input for text-to-image model. control(str): control img dir for controlnet. negative_prompt(InputsType): negative prompt. Returns: result(Dict): Results of preprocess. """ result = self.extra_parameters if type(text) is dict: result['text_prompts'] = text else: result['prompt'] = text if control: control_img = mmcv.imread(control) control_img = fromarray(control_img) result['control'] = control_img result.pop('seed', None) if negative_prompt: result['negative_prompt'] = negative_prompt return result def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" image = self.model.infer(**inputs)['samples'] return image def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) if type(preds) is list: preds = preds[0] if type(preds) is Image: preds.save(result_out_dir) else: save_image(preds, result_out_dir, normalize=True) return preds ================================================ FILE: mmagic/apis/inferencers/translation_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import numpy as np import torch from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmengine.dataset.utils import default_collate as collate from torchvision import utils from mmagic.models.base_models import BaseTranslationModel from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class TranslationInferencer(BaseMMagicInferencer): """inferencer that predicts with translation models.""" func_kwargs = dict( preprocess=['img'], forward=[], visualize=['result_out_dir'], postprocess=[]) def preprocess(self, img: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: img(InputsType): Image to be translated by models. Returns: results(Dict): Results of preprocess. """ assert isinstance(self.model, BaseTranslationModel) # get source domain and target domain self.target_domain = self.model._default_domain source_domain = self.model.get_other_domains(self.target_domain)[0] cfg = self.model.cfg # build the data pipeline test_pipeline = Compose(cfg.test_pipeline) # prepare data # dirty code to deal with test data pipeline data = dict() data['pair_path'] = img data['img_A_path'] = img data['img_B_path'] = img data = collate([test_pipeline(data)]) data = self.model.data_preprocessor(data, False) inputs_dict = data['inputs'] results = inputs_dict[f'img_{source_domain}'] return results def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" with torch.no_grad(): results = self.model( inputs, test_mode=True, target_domain=self.target_domain) output = results['target'] return output def visualize(self, preds: PredType, result_out_dir: str = None) -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ results = (preds[:, [2, 1, 0]] + 1.) / 2. # save images if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) utils.save_image(results, result_out_dir) return results ================================================ FILE: mmagic/apis/inferencers/unconditional_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Dict, List import numpy as np import torch from mmengine import mkdir_or_exist from torchvision import utils from mmagic.structures import DataSample from .base_mmagic_inferencer import BaseMMagicInferencer, InputsType, PredType class UnconditionalInferencer(BaseMMagicInferencer): """inferencer that predicts with unconditional models.""" func_kwargs = dict( preprocess=[], forward=[], visualize=['result_out_dir'], postprocess=[]) extra_parameters = dict( num_batches=4, sample_model='orig', sample_kwargs=None, noise=None) def preprocess(self) -> Dict: """Process the inputs into a model-feedable format. Returns: results(Dict): Results of preprocess. """ num_batches = self.extra_parameters['num_batches'] sample_model = self.extra_parameters['sample_model'] noise = self.extra_parameters['noise'] sample_kwargs = self.extra_parameters['sample_kwargs'] results = dict( num_batches=num_batches, sample_model=sample_model, sample_kwargs=sample_kwargs, noise=noise) return results def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model.""" return self.model(inputs) def visualize(self, preds: PredType, result_out_dir: str = '') -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ res_list = [] res_list.extend([item.fake_img.data.cpu() for item in preds]) results = torch.stack(res_list, dim=0) if results.shape[1] == 3: results = results[:, [2, 1, 0]] / 255. else: results = results / 255. # save images if result_out_dir: mkdir_or_exist(os.path.dirname(result_out_dir)) utils.save_image(results, result_out_dir) return results def _pred2dict(self, data_sample: DataSample) -> Dict: """Extract elements necessary to represent a prediction into a dictionary. It's better to contain only basic data elements such as strings and numbers in order to guarantee it's json-serializable. Args: data_sample (DataSample): The data sample to be converted. Returns: dict: The output dictionary. """ result = {} result['fake_img'] = data_sample.fake_img.data.cpu() result['noise'] = data_sample.noise.data.cpu() if hasattr(data_sample, 'latent'): result['latent'] = data_sample.latent if hasattr(data_sample, 'feats'): result['feats'] = data_sample.feats return result ================================================ FILE: mmagic/apis/inferencers/video_interpolation_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import os import os.path as osp from typing import Dict, List, Optional, Tuple, Union import cv2 import mmcv import mmengine import numpy as np import torch from mmengine.dataset import Compose from mmengine.dataset.utils import default_collate as collate from mmengine.logging import MMLogger from mmengine.utils import ProgressBar from .base_mmagic_inferencer import (BaseMMagicInferencer, InputsType, PredType, ResType) from .inference_functions import VIDEO_EXTENSIONS, read_frames, read_image class VideoInterpolationInferencer(BaseMMagicInferencer): """inferencer that predicts with video interpolation models.""" func_kwargs = dict( preprocess=['video'], forward=['result_out_dir'], visualize=[], postprocess=[]) extra_parameters = dict( start_idx=0, end_idx=None, batch_size=4, fps_multiplier=0, fps=0, filename_tmpl='{:08d}.png') def preprocess(self, video: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: video(InputsType): Video to be interpolated by models. Returns: video(InputsType): Video to be interpolated by models. """ # build the data pipeline if self.model.cfg.get('demo_pipeline', None): test_pipeline = self.model.cfg.demo_pipeline elif self.model.cfg.get('test_pipeline', None): test_pipeline = self.model.cfg.test_pipeline else: test_pipeline = self.model.cfg.val_pipeline # remove the data loading pipeline tmp_pipeline = [] for pipeline in test_pipeline: if pipeline['type'] not in [ 'GenerateSegmentIndices', 'LoadImageFromFile' ]: tmp_pipeline.append(pipeline) test_pipeline = tmp_pipeline # compose the pipeline self.test_pipeline = Compose(test_pipeline) return video def forward(self, inputs: InputsType, result_out_dir: InputsType = '') -> PredType: """Forward the inputs to the model. Args: inputs (InputsType): Input video directory. result_out_dir (str): Output directory of video. Defaults to ''. Returns: PredType: Result of forwarding """ # check if the input is a video input_file_extension = os.path.splitext(inputs)[1] if input_file_extension in VIDEO_EXTENSIONS: source = mmcv.VideoReader(inputs) input_fps = source.fps length = source.frame_cnt from_video = True h, w = source.height, source.width if self.extra_parameters['fps_multiplier']: assert self.extra_parameters['fps_multiplier'] > 0, \ '`fps_multiplier` cannot be negative' output_fps = \ self.extra_parameters['fps_multiplier'] * input_fps else: fps = self.extra_parameters['fps'] output_fps = fps if fps > 0 else input_fps * 2 else: files = os.listdir(inputs) files = [osp.join(inputs, f) for f in files] files.sort() source = files length = files.__len__() from_video = False example_frame = read_image(files[0]) h, w = example_frame.shape[:2] fps = self.extra_parameters['fps'] output_fps = fps if fps > 0 else 60 # check if the output is a video output_file_extension = os.path.splitext(result_out_dir)[1] mmengine.utils.mkdir_or_exist(osp.dirname(result_out_dir)) if output_file_extension in VIDEO_EXTENSIONS: fourcc = cv2.VideoWriter_fourcc(*'mp4v') target = cv2.VideoWriter(result_out_dir, fourcc, output_fps, (w, h)) to_video = True else: to_video = False self.extra_parameters['end_idx'] = min( self.extra_parameters['end_idx'], length) \ if self.extra_parameters['end_idx'] is not None else length # calculate step args step_size = \ self.model.step_frames * self.extra_parameters['batch_size'] lenth_per_step = self.model.required_frames + \ self.model.step_frames * (self.extra_parameters['batch_size'] - 1) repeat_frame = self.model.required_frames - self.model.step_frames prog_bar = ProgressBar( math.ceil((self.extra_parameters['end_idx'] + step_size - lenth_per_step - self.extra_parameters['start_idx']) / step_size)) output_index = self.extra_parameters['start_idx'] for start_index in range(self.extra_parameters['start_idx'], self.extra_parameters['end_idx'], step_size): images = read_frames( source, start_index, lenth_per_step, from_video, end_index=self.extra_parameters['end_idx']) # data prepare data = dict(img=images, inputs_path=None, key=inputs) data = self.test_pipeline(data)['inputs'] / 255.0 data = collate([data]) # data.shape: [1, t, c, h, w] # forward the model data = self.model.split_frames(data) input_tensors = data.clone().detach() with torch.no_grad(): output = self.model(data.to(self.device), mode='tensor') if len(output.shape) == 4: output = output.unsqueeze(1) output_tensors = output.cpu() if len(output_tensors.shape) == 4: output_tensors = output_tensors.unsqueeze(1) result = self.model.merge_frames(input_tensors, output_tensors) if not self.extra_parameters['start_idx'] == start_index: result = result[repeat_frame:] prog_bar.update() # save frames if to_video: for frame in result: target.write(frame) else: filename_tmpl = self.extra_parameters['filename_tmpl'] for frame in result: save_path = osp.join(result_out_dir, filename_tmpl.format(output_index)) mmcv.imwrite(frame, save_path) output_index += 1 if start_index + lenth_per_step >= \ self.extra_parameters['end_idx']: break if to_video: target.release() logger: MMLogger = MMLogger.get_current_instance() logger.info(f'Output video is save at {result_out_dir}.') return {} def visualize(self, preds: PredType, result_out_dir: str = '') -> List[np.ndarray]: """Visualize is not needed in this inferencer.""" logger: MMLogger = MMLogger.get_current_instance() logger.info('Visualization is implemented in forward process.') return None def postprocess( self, preds: PredType, imgs: Optional[List[np.ndarray]] = None ) -> Union[ResType, Tuple[ResType, np.ndarray]]: """Postprocess is not needed in this inferencer.""" logger: MMLogger = MMLogger.get_current_instance() logger.info('Postprocess is implemented in forward process.') return None ================================================ FILE: mmagic/apis/inferencers/video_restoration_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import glob import os import os.path as osp from typing import Dict, List, Optional, Tuple, Union import cv2 import mmcv import mmengine import numpy as np import torch from mmengine.dataset import Compose from mmengine.logging import MMLogger from mmengine.utils import ProgressBar from mmagic.utils import tensor2img from .base_mmagic_inferencer import (BaseMMagicInferencer, InputsType, PredType, ResType) from .inference_functions import VIDEO_EXTENSIONS, pad_sequence class VideoRestorationInferencer(BaseMMagicInferencer): """inferencer that predicts with video restoration models.""" func_kwargs = dict( preprocess=['video'], forward=[], visualize=['result_out_dir'], postprocess=[]) extra_parameters = dict( start_idx=0, filename_tmpl='{:08d}.png', window_size=0, max_seq_len=None) def preprocess(self, video: InputsType) -> Dict: """Process the inputs into a model-feedable format. Args: video(InputsType): Video to be restored by models. Returns: results(InputsType): Results of preprocess. """ # build the data pipeline if self.model.cfg.get('demo_pipeline', None): test_pipeline = self.model.cfg.demo_pipeline elif self.model.cfg.get('test_pipeline', None): test_pipeline = self.model.cfg.test_pipeline else: test_pipeline = self.model.cfg.val_pipeline # check if the input is a video file_extension = osp.splitext(video)[1] if file_extension in VIDEO_EXTENSIONS: video_reader = mmcv.VideoReader(video) # load the images data = dict(img=[], img_path=None, key=video) for frame in video_reader: data['img'].append(np.flip(frame, axis=2)) # remove the data loading pipeline tmp_pipeline = [] for pipeline in test_pipeline: if pipeline['type'] not in [ 'GenerateSegmentIndices', 'LoadImageFromFile' ]: tmp_pipeline.append(pipeline) test_pipeline = tmp_pipeline else: # the first element in the pipeline must be # 'GenerateSegmentIndices' if test_pipeline[0]['type'] != 'GenerateSegmentIndices': raise TypeError('The first element in the pipeline must be ' f'"GenerateSegmentIndices", but got ' f'"{test_pipeline[0]["type"]}".') # specify start_idx and filename_tmpl test_pipeline[0]['start_idx'] = self.extra_parameters['start_idx'] test_pipeline[0]['filename_tmpl'] = \ self.extra_parameters['filename_tmpl'] # prepare data sequence_length = len(glob.glob(osp.join(video, '*'))) lq_folder = osp.dirname(video) key = osp.basename(video) data = dict( img_path=lq_folder, gt_path='', key=key, sequence_length=sequence_length) # compose the pipeline test_pipeline = Compose(test_pipeline) data = test_pipeline(data) results = data['inputs'].unsqueeze(0) / 255.0 # in cpu return results def forward(self, inputs: InputsType) -> PredType: """Forward the inputs to the model. Args: inputs (InputsType): Images array of input video. Returns: PredType: Results of forwarding """ with torch.no_grad(): if self.extra_parameters[ 'window_size'] > 0: # sliding window framework data = pad_sequence(inputs, self.extra_parameters['window_size']) result = [] # yapf: disable for i in range(0, data.size(1) - 2 * (self.extra_parameters['window_size'] // 2)): # noqa # yapf: enable data_i = data[:, i:i + self.extra_parameters['window_size']].to( self.device) result.append( self.model(inputs=data_i, mode='tensor').cpu()) result = torch.stack(result, dim=1) else: # recurrent framework if self.extra_parameters['max_seq_len'] is None: result = self.model( inputs=inputs.to(self.device), mode='tensor').cpu() else: result = [] for i in range(0, inputs.size(1), self.extra_parameters['max_seq_len']): result.append( self.model( inputs=inputs[:, i:i + self. extra_parameters['max_seq_len']]. to(self.device), mode='tensor').cpu()) result = torch.cat(result, dim=1) return result def visualize(self, preds: PredType, result_out_dir: str = '') -> List[np.ndarray]: """Visualize predictions. Args: preds (List[Union[str, np.ndarray]]): Forward results by the inferencer. data (List[Dict]): Not needed by this kind of inferencer. result_out_dir (str): Output directory of image. Defaults to ''. Returns: List[np.ndarray]: Result of visualize """ file_extension = os.path.splitext(result_out_dir)[1] mmengine.utils.mkdir_or_exist(osp.dirname(result_out_dir)) prog_bar = ProgressBar(preds.size(1)) if file_extension in VIDEO_EXTENSIONS: # save as video h, w = preds.shape[-2:] fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_writer = cv2.VideoWriter(result_out_dir, fourcc, 25, (w, h)) for i in range(0, preds.size(1)): img = tensor2img(preds[:, i, :, :, :]) video_writer.write(img.astype(np.uint8)) prog_bar.update() cv2.destroyAllWindows() video_writer.release() else: for i in range(self.extra_parameters['start_idx'], self.extra_parameters['start_idx'] + preds.size(1)): output_i = \ preds[:, i - self.extra_parameters['start_idx'], :, :, :] output_i = tensor2img(output_i) filename_tmpl = self.extra_parameters['filename_tmpl'] save_path_i = f'{result_out_dir}/{filename_tmpl.format(i)}' mmcv.imwrite(output_i, save_path_i) prog_bar.update() logger: MMLogger = MMLogger.get_current_instance() logger.info(f'Output video is save at {result_out_dir}.') return [] def postprocess( self, preds: PredType, imgs: Optional[List[np.ndarray]] = None ) -> Union[ResType, Tuple[ResType, np.ndarray]]: """Postprocess is not needed in this inferencer.""" logger: MMLogger = MMLogger.get_current_instance() logger.info('Postprocess is implemented in visualize process.') return None ================================================ FILE: mmagic/apis/mmagic_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import warnings from typing import Dict, List, Optional, Union import torch import yaml from mmengine.registry import init_default_scope from .inferencers import Inferencers from .inferencers.base_mmagic_inferencer import InputsType class MMagicInferencer: """MMagicInferencer API for mmagic models inference. Args: model_name (str): Name of the editing model. model_setting (str): Setting of a specific model. Default to 'a'. model_config (str): Path to the config file for the editing model. Default to None. model_ckpt (str): Path to the checkpoint file for the editing model. Default to None. config_dir (str): Path to the directory containing config files. Default to 'configs/'. device (torch.device): Device to use for inference. Default to 'cuda'. Examples: >>> # inference of a conditional model, biggan for example >>> editor = MMagicInferencer(model_name='biggan') >>> editor.infer(label=1, result_out_dir='./biggan_res.jpg') >>> # inference of a translation model, pix2pix for example >>> editor = MMagicInferencer(model_name='pix2pix') >>> editor.infer(img='./test.jpg', result_out_dir='./pix2pix_res.jpg') >>> # see demo/mmediting_inference_tutorial.ipynb for more examples """ # unsupported now # singan, liif # output should be checked # dic, glean inference_supported_models = [ # colorization models 'inst_colorization', # conditional models 'biggan', 'sngan_proj', 'sagan', # unconditional models 'dcgan', 'deblurganv2', 'wgan-gp', 'lsgan', 'ggan', 'pggan', 'styleganv1', 'styleganv2', 'styleganv3', # matting models 'dim', 'indexnet', 'gca', # inpainting models 'aot_gan', 'deepfillv1', 'deepfillv2', 'global_local', 'partial_conv', # translation models 'pix2pix', 'cyclegan', # image super-resolution models 'srcnn', 'srgan_resnet', 'edsr', 'esrgan', 'rdn', 'dic', 'ttsr', 'glean', 'real_esrgan', # video_interpolation models 'flavr', 'cain', # video_restoration models 'edvr', 'tdan', 'basicvsr', 'iconvsr', 'basicvsr_pp', 'real_basicvsr', # image_restoration models 'nafnet', 'swinir', 'restormer', # text2image models 'controlnet', 'disco_diffusion', 'stable_diffusion', # 3D-aware generation 'eg3d', # animation inferencer 'controlnet_animation', # draggan 'draggan', # diffusers pipeline inferencer 'diffusers_pipeline', ] inference_supported_models_cfg = {} inference_supported_models_cfg_inited = False def __init__(self, model_name: str = None, model_setting: int = None, config_name: int = None, model_config: str = None, model_ckpt: str = None, device: torch.device = None, extra_parameters: Dict = None, seed: int = 2022, **kwargs) -> None: init_default_scope('mmagic') MMagicInferencer.init_inference_supported_models_cfg() inferencer_kwargs = {} inferencer_kwargs.update( self._get_inferencer_kwargs(model_name, model_setting, config_name, model_config, model_ckpt, extra_parameters)) self.inferencer = Inferencers( device=device, seed=seed, **inferencer_kwargs) def _get_inferencer_kwargs(self, model_name: Optional[str], model_setting: Optional[int], config_name: Optional[int], model_config: Optional[str], model_ckpt: Optional[str], extra_parameters: Optional[Dict]) -> Dict: """Get the kwargs for the inferencer.""" kwargs = {} if model_name is not None: cfgs = self.get_model_config(model_name) kwargs['task'] = cfgs['task'] setting_to_use = 0 if model_setting: setting_to_use = model_setting config_dir = cfgs['settings'][setting_to_use]['Config'] if config_name: for setting in cfgs['settings']: if setting['Name'] == config_name: config_dir = setting['Config'] break config_dir = config_dir[config_dir.find('configs'):] if osp.exists( osp.join(osp.dirname(__file__), '..', '..', config_dir)): kwargs['config'] = osp.join( osp.dirname(__file__), '..', '..', config_dir) else: kwargs['config'] = osp.join( osp.dirname(__file__), '..', '.mim', config_dir) if 'Weights' in cfgs['settings'][setting_to_use].keys(): kwargs['ckpt'] = cfgs['settings'][setting_to_use]['Weights'] if model_name == 'controlnet': kwargs['ckpt'] = None if model_config is not None: if kwargs.get('config', None) is not None: warnings.warn( f'{model_name}\'s default config ' f'is overridden by {model_config}', UserWarning) kwargs['config'] = model_config if model_ckpt is not None: if kwargs.get('ckpt', None) is not None: warnings.warn( f'{model_name}\'s default checkpoint ' f'is overridden by {model_ckpt}', UserWarning) kwargs['ckpt'] = model_ckpt if extra_parameters is not None: kwargs['extra_parameters'] = extra_parameters return kwargs def print_extra_parameters(self): """Print the unique parameters of each kind of inferencer.""" extra_parameters = self.inferencer.get_extra_parameters() print(extra_parameters) def infer(self, img: InputsType = None, video: InputsType = None, label: InputsType = None, trimap: InputsType = None, mask: InputsType = None, result_out_dir: str = '', **kwargs) -> Union[Dict, List[Dict]]: """Infer edit model on an image(video). Args: img (str): Img path. video (str): Video path. label (int): Label for conditional or unconditional models. trimap (str): Trimap path for matting models. mask (str): Mask path for inpainting models. result_out_dir (str): Output directory of result image or video. Defaults to ''. Returns: Dict or List[Dict]: Each dict contains the inference result of each image or video. """ return self.inferencer( img=img, video=video, label=label, trimap=trimap, mask=mask, result_out_dir=result_out_dir, **kwargs) def get_model_config(self, model_name: str) -> Dict: """Get the model configuration including model config and checkpoint url. Args: model_name (str): Name of the model. Returns: dict: Model configuration. """ if model_name not in self.inference_supported_models: raise ValueError(f'Model {model_name} is not supported.') else: return self.inference_supported_models_cfg[model_name] @staticmethod def init_inference_supported_models_cfg() -> None: if not MMagicInferencer.inference_supported_models_cfg_inited: if osp.exists( osp.join(osp.dirname(__file__), '..', '..', 'configs')): all_cfgs_dir = osp.join( osp.dirname(__file__), '..', '..', 'configs') else: all_cfgs_dir = osp.join( osp.dirname(__file__), '..', '.mim', 'configs') for model_name in MMagicInferencer.inference_supported_models: meta_file_dir = osp.join(all_cfgs_dir, model_name, 'metafile.yml') with open(meta_file_dir, 'r') as stream: parsed_yaml = yaml.safe_load(stream) task = parsed_yaml['Models'][0]['Results'][0]['Task'] MMagicInferencer.inference_supported_models_cfg[ model_name] = {} MMagicInferencer.inference_supported_models_cfg[model_name][ 'task'] = task # noqa MMagicInferencer.inference_supported_models_cfg[model_name][ 'settings'] = parsed_yaml['Models'] # noqa MMagicInferencer.inference_supported_models_cfg_inited = True @staticmethod def get_inference_supported_models() -> List: """static function for getting inference supported modes.""" return MMagicInferencer.inference_supported_models @staticmethod def get_inference_supported_tasks() -> List: """static function for getting inference supported tasks.""" if not MMagicInferencer.inference_supported_models_cfg_inited: MMagicInferencer.init_inference_supported_models_cfg() supported_task = set() for key in MMagicInferencer.inference_supported_models_cfg.keys(): if MMagicInferencer.inference_supported_models_cfg[key]['task'] \ not in supported_task: supported_task.add(MMagicInferencer. inference_supported_models_cfg[key]['task']) return list(supported_task) @staticmethod def get_task_supported_models(task: str) -> List: """static function for getting task supported models.""" if not MMagicInferencer.inference_supported_models_cfg_inited: MMagicInferencer.init_inference_supported_models_cfg() supported_models = [] for key in MMagicInferencer.inference_supported_models_cfg.keys(): if MMagicInferencer.inference_supported_models_cfg[key][ 'task'] == task: supported_models.append(key) return supported_models ================================================ FILE: mmagic/configs/_base_/datasets/basicvsr_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicFramesDataset from mmagic.datasets.transforms import (GenerateSegmentIndices, LoadImageFromFile, MirrorSequence, PackInputs) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM # configs for REDS4 reds_data_root = 'data/REDS' reds_pipeline = [ dict(type=GenerateSegmentIndices, interval_list=[1]), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] reds_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=reds_data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_val.txt', depth=1, num_input_frames=100, fixed_seq_len=100, pipeline=reds_pipeline)) reds_evaluator = [ dict(type=PSNR, prefix='REDS4-BIx4-RGB'), dict(type=SSIM, prefix='REDS4-BIx4-RGB') ] # configs for vimeo90k-bd and vimeo90k-bi vimeo_90k_data_root = 'data/vimeo90k' vimeo_90k_file_list = [ 'im1.png', 'im2.png', 'im3.png', 'im4.png', 'im5.png', 'im6.png', 'im7.png' ] vimeo_90k_pipeline = [ dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=MirrorSequence, keys=['img']), dict(type=PackInputs) ] vimeo_90k_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vimeo90k_seq', task_name='vsr'), data_root=vimeo_90k_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vimeo90K_test_GT.txt', depth=2, num_input_frames=7, fixed_seq_len=7, load_frames_list=dict(img=vimeo_90k_file_list, gt=['im4.png']), pipeline=vimeo_90k_pipeline)) vimeo_90k_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vimeo90k_seq', task_name='vsr'), data_root=vimeo_90k_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vimeo90K_test_GT.txt', depth=2, num_input_frames=7, fixed_seq_len=7, load_frames_list=dict(img=vimeo_90k_file_list, gt=['im4.png']), pipeline=vimeo_90k_pipeline)) vimeo_90k_bd_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Vimeo-90K-T-BDx4-Y'), dict(type=SSIM, convert_to='Y', prefix='Vimeo-90K-T-BDx4-Y'), ] vimeo_90k_bi_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Vimeo-90K-T-BIx4-Y'), dict(type=SSIM, convert_to='Y', prefix='Vimeo-90K-T-BIx4-Y'), ] # config for UDM10 (BDx4) udm10_data_root = 'data/UDM10' udm10_pipeline = [ dict( type=GenerateSegmentIndices, interval_list=[1], filename_tmpl='{:04d}.png'), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] udm10_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='udm10', task_name='vsr'), data_root=udm10_data_root, data_prefix=dict(img='BDx4', gt='GT'), pipeline=udm10_pipeline)) udm10_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='UDM10-BDx4-Y'), dict(type=SSIM, convert_to='Y', prefix='UDM10-BDx4-Y') ] # config for vid4 vid4_data_root = 'data/Vid4' vid4_pipeline = [ dict(type=GenerateSegmentIndices, interval_list=[1]), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] vid4_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=1, pipeline=vid4_pipeline)) vid4_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=1, pipeline=vid4_pipeline)) vid4_bd_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='VID4-BDx4-Y'), dict(type=SSIM, convert_to='Y', prefix='VID4-BDx4-Y'), ] vid4_bi_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='VID4-BIx4-Y'), dict(type=SSIM, convert_to='Y', prefix='VID4-BIx4-Y'), ] # config for test test_cfg = dict(type=MultiTestLoop) test_dataloader = [ reds_dataloader, vimeo_90k_bd_dataloader, vimeo_90k_bi_dataloader, udm10_dataloader, vid4_bd_dataloader, vid4_bi_dataloader, ] test_evaluator = [ reds_evaluator, vimeo_90k_bd_evaluator, vimeo_90k_bi_evaluator, udm10_evaluator, vid4_bd_evaluator, vid4_bi_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/celeba.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.evaluation import MAE, PSNR, SSIM # Base config for CelebA-HQ dataset # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data/CelebA-HQ' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt=''), ann_file='train_celeba_img_list.txt', test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt=''), ann_file='val_celeba_img_list.txt', test_mode=True, )) test_dataloader = val_dataloader val_evaluator = [ dict(type=MAE, mask_key='mask', scaling=100), # By default, compute with pixel value from 0-1 # scale=2 to align with 1.0 # scale=100 seems to align with readme dict(type=PSNR), dict(type=SSIM), ] test_evaluator = val_evaluator ================================================ FILE: mmagic/configs/_base_/datasets/cifar10_noaug.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset.sampler import DefaultSampler, InfiniteSampler from mmagic.datasets.cifar10_dataset import CIFAR10 from mmagic.datasets.transforms.formatting import PackInputs cifar_pipeline = [dict(type=PackInputs)] cifar_dataset = dict( type=CIFAR10, data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline) train_dataloader = dict( num_workers=2, dataset=cifar_dataset, sampler=dict(type=InfiniteSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset, sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset, sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/cifar10_nopad.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets import CIFAR10 from mmagic.datasets.transforms import Flip, PackInputs cifar_pipeline = [ dict(type=Flip, keys=['gt'], flip_ratio=0.5, direction='horizontal'), dict(type=PackInputs) ] cifar_dataset = dict( type=CIFAR10, data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline) # test dataset do not use flip cifar_pipeline_test = [dict(type=PackInputs)] cifar_dataset_test = dict( type=CIFAR10, data_root='./data', data_prefix='cifar10', test_mode=False, pipeline=cifar_pipeline_test) train_dataloader = dict( num_workers=2, dataset=cifar_dataset, sampler=dict(type=InfiniteSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset_test, sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=32, num_workers=2, dataset=cifar_dataset_test, sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/comp1k.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.evaluation import SAD, ConnectivityError, GradientError, MattingMSE # Base config for Composition-1K dataset # dataset settings dataset_type = 'AdobeComp1kDataset' data_root = 'data/adobe_composition-1k' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, ann_file='training_list.json', test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, ann_file='test_list.json', test_mode=True, )) test_dataloader = val_dataloader # TODO: matting val_evaluator = [ dict(type=SAD), dict(type=MattingMSE), dict(type=GradientError), dict(type=ConnectivityError), ] test_evaluator = val_evaluator ================================================ FILE: mmagic/configs/_base_/datasets/deblurring-defocus_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import MAE, PSNR, SSIM test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='imgL', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='imgR', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] dpdd_data_root = 'data/DPDD' dpdd_indoor_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='DPDD-Indoor', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), ann_file='indoor_labels.txt', pipeline=test_pipeline)) dpdd_indoor_evaluator = [ dict(type=MAE, prefix='DPDD-Indoor'), dict(type=PSNR, prefix='DPDD-Indoor'), dict(type=SSIM, prefix='DPDD-Indoor'), ] dpdd_outdoor_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='DPDD-Outdoor', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), ann_file='outdoor_labels.txt', pipeline=test_pipeline)) dpdd_outdoor_evaluator = [ dict(type=MAE, prefix='DPDD-Outdoor'), dict(type=PSNR, prefix='DPDD-Outdoor'), dict(type=SSIM, prefix='DPDD-Outdoor'), ] dpdd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='DPDD-Combined', task_name='deblurring'), data_root=dpdd_data_root, data_prefix=dict( img='inputC', imgL='inputL', imgR='inputR', gt='target'), pipeline=test_pipeline)) dpdd_evaluator = [ dict(type=MAE, prefix='DPDD-Combined'), dict(type=PSNR, prefix='DPDD-Combined'), dict(type=SSIM, prefix='DPDD-Combined'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ dpdd_indoor_dataloader, dpdd_outdoor_dataloader, dpdd_dataloader, ] test_evaluator = [ dpdd_indoor_evaluator, dpdd_outdoor_evaluator, dpdd_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/deblurring-motion_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] gopro_data_root = 'data/gopro/test' gopro_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='GoPro', task_name='deblurring'), data_root=gopro_data_root, data_prefix=dict(img='blur', gt='sharp'), pipeline=test_pipeline)) gopro_evaluator = [ dict(type=PSNR, prefix='GoPro'), dict(type=SSIM, prefix='GoPro'), ] hide_data_root = 'data/HIDE' hide_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='HIDE', task_name='deblurring'), data_root=hide_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) hide_evaluator = [ dict(type=PSNR, prefix='HIDE'), dict(type=SSIM, prefix='HIDE'), ] realblurj_data_root = 'data/RealBlur_J' realblurj_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='RealBlur_J', task_name='deblurring'), data_root=realblurj_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) realblurj_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='RealBlurJ'), dict(type=SSIM, convert_to='Y', prefix='RealBlurJ'), ] realblurr_data_root = 'data/RealBlur_R' realblurr_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='RealBlur_R', task_name='deblurring'), data_root=realblurr_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) realblurr_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='RealBlurR'), dict(type=SSIM, convert_to='Y', prefix='RealBlurR'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ gopro_dataloader, hide_dataloader, realblurj_dataloader, realblurr_dataloader, ] test_evaluator = [ gopro_evaluator, hide_evaluator, realblurj_evaluator, realblurr_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/decompression_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import (LoadImageFromFile, PackInputs, RandomJPEGCompression) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM quality = 10 test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=RandomJPEGCompression, params=dict(quality=[quality, quality]), bgr2rgb=True, keys=['img']), dict(type=PackInputs) ] classic5_data_root = 'data/Classic5' classic5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='classic5', task_name='CAR'), data_root=classic5_data_root, data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) classic5_evaluator = [ dict(type=PSNR, prefix='Classic5'), dict(type=SSIM, prefix='Classic5'), ] live1_data_root = 'data/LIVE1' live1_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='live1', task_name='CAR'), data_root=live1_data_root, data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) live1_evaluator = [ dict(type=PSNR, prefix='LIVE1'), dict(type=SSIM, prefix='LIVE1'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ classic5_dataloader, live1_dataloader, ] test_evaluator = [ classic5_evaluator, live1_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/denoising-gaussian_color_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import (LoadImageFromFile, PackInputs, RandomNoise) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM sigma = 15 test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=RandomNoise, params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=0), keys=['img']), dict(type=PackInputs) ] data_root = 'data/denoising_gaussian_test' cbsd68_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='CBSD68', task_name='denoising'), data_root=data_root, data_prefix=dict(img='CBSD68', gt='CBSD68'), pipeline=test_pipeline)) cbsd68_evaluator = [ dict(type=PSNR, prefix='CBSD68'), dict(type=SSIM, prefix='CBSD68'), ] kodak24_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Kodak24', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Kodak24', gt='Kodak24'), pipeline=test_pipeline)) kodak24_evaluator = [ dict(type=PSNR, prefix='Kodak24'), dict(type=SSIM, prefix='Kodak24'), ] mcmaster_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='McMaster', task_name='denoising'), data_root=data_root, data_prefix=dict(img='McMaster', gt='McMaster'), pipeline=test_pipeline)) mcmaster_evaluator = [ dict(type=PSNR, prefix='McMaster'), dict(type=SSIM, prefix='McMaster'), ] urban100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Urban100', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Urban100', gt='Urban100'), pipeline=test_pipeline)) urban100_evaluator = [ dict(type=PSNR, prefix='Urban100'), dict(type=SSIM, prefix='Urban100'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ cbsd68_dataloader, kodak24_dataloader, mcmaster_dataloader, urban100_dataloader, ] test_evaluator = [ cbsd68_evaluator, kodak24_evaluator, mcmaster_evaluator, urban100_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/denoising-gaussian_gray_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import (LoadImageFromFile, PackInputs, RandomNoise) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM sigma = 15 test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', to_y_channel=True, imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', to_y_channel=True, imdecode_backend='cv2'), dict( type=RandomNoise, params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[sigma, sigma], gaussian_gray_noise_prob=1), keys=['img']), dict(type=PackInputs) ] data_root = 'data/denoising_gaussian_test' set12_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Set12', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Set12', gt='Set12'), pipeline=test_pipeline)) set12_evaluator = [ dict(type=PSNR, prefix='Set12'), dict(type=SSIM, prefix='Set12'), ] bsd68_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='BSD68', task_name='denoising'), data_root=data_root, data_prefix=dict(img='BSD68', gt='BSD68'), pipeline=test_pipeline)) bsd68_evaluator = [ dict(type=PSNR, prefix='BSD68'), dict(type=SSIM, prefix='BSD68'), ] urban100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Urban100', task_name='denoising'), data_root=data_root, data_prefix=dict(img='Urban100', gt='Urban100'), pipeline=test_pipeline)) urban100_evaluator = [ dict(type=PSNR, prefix='Urban100'), dict(type=SSIM, prefix='Urban100'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ set12_dataloader, bsd68_dataloader, urban100_dataloader, ] test_evaluator = [ set12_evaluator, bsd68_evaluator, urban100_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/denoising-real_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] sidd_data_root = 'data/SIDD/val/' sidd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='SIDD', task_name='denoising'), data_root=sidd_data_root, data_prefix=dict(img='noisy', gt='gt'), filename_tmpl=dict(gt='{}_GT', img='{}_NOISY'), pipeline=test_pipeline)) sidd_evaluator = [ dict(type=PSNR, prefix='SIDD'), dict(type=SSIM, prefix='SIDD'), ] dnd_data_root = 'data/DND' dnd_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='DND', task_name='denoising'), data_root=dnd_data_root, data_prefix=dict(img='input', gt='groundtruth'), pipeline=test_pipeline)) dnd_evaluator = [ dict(type=PSNR, prefix='DND'), dict(type=SSIM, prefix='DND'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ sidd_dataloader, # dnd_dataloader, ] test_evaluator = [ sidd_evaluator, # dnd_dataloader, ] ================================================ FILE: mmagic/configs/_base_/datasets/deraining_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] rain100h_data_root = 'data/Rain100H' rain100h_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Rain100H', task_name='deraining'), data_root=rain100h_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) rain100h_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Rain100H'), dict(type=SSIM, convert_to='Y', prefix='Rain100H'), ] rain100l_data_root = 'data/Rain100L' rain100l_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Rain100L', task_name='deraining'), data_root=rain100l_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) rain100l_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Rain100L'), dict(type=SSIM, convert_to='Y', prefix='Rain100L'), ] test100_data_root = 'data/Test100' test100_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Test100', task_name='deraining'), data_root=test100_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test100_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Test100'), dict(type=SSIM, convert_to='Y', prefix='Test100'), ] test1200_data_root = 'data/Test1200' test1200_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Test1200', task_name='deraining'), data_root=test1200_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test1200_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Test1200'), dict(type=SSIM, convert_to='Y', prefix='Test1200'), ] test2800_data_root = 'data/Test2800' test2800_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='Test2800', task_name='deraining'), data_root=test2800_data_root, data_prefix=dict(img='input', gt='target'), pipeline=test_pipeline)) test2800_evaluator = [ dict(type=PSNR, convert_to='Y', prefix='Test2800'), dict(type=SSIM, convert_to='Y', prefix='Test2800'), ] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ rain100h_dataloader, rain100l_dataloader, test100_dataloader, test1200_dataloader, test2800_dataloader, ] test_evaluator = [ rain100h_evaluator, rain100l_evaluator, test100_evaluator, test1200_evaluator, test2800_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/ffhq_flip.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset.sampler import DefaultSampler, InfiniteSampler from mmagic.datasets.basic_image_dataset import BasicImageDataset from mmagic.datasets.transforms.aug_shape import Flip from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile dataset_type = BasicImageDataset train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=Flip, keys=['gt'], direction='horizontal'), dict(type=PackInputs, keys='gt') ] val_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=PackInputs, keys=['gt']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/grow_scale_imgs_ffhq_styleganv1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets import BasicImageDataset, GrowScaleImgDataset from mmagic.datasets.transforms import Flip, LoadImageFromFile, PackInputs dataset_type = 'GrowScaleImgDataset' pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=Flip, keys='gt', direction='horizontal'), dict(type=PackInputs) ] train_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type=GrowScaleImgDataset, data_roots={ '1024': './data/ffhq/images', '256': './data/ffhq/ffhq_imgs/ffhq_256', }, gpu_samples_base=4, # note that this should be changed with total gpu number gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4, '128': 4, '256': 4, '512': 4, '1024': 4 }, len_per_stage=300000, pipeline=pipeline), sampler=dict(type=InfiniteSampler, shuffle=True)) test_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type=BasicImageDataset, data_prefix=dict(gt=''), pipeline=pipeline, data_root='./data/ffhq/images'), sampler=dict(type=DefaultSampler, shuffle=False)) val_dataloader = test_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/imagenet_128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets.transforms import (CenterCropLongEdge, Flip, LoadImageFromFile, PackInputs, RandomCropLongEdge, Resize) # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=RandomCropLongEdge, keys='gt'), dict(type=Resize, scale=(128, 128), keys='gt', backend='pillow'), dict(type=Flip, keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type=PackInputs) ] test_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=CenterCropLongEdge, keys='gt'), dict(type=Resize, scale=(128, 128), keys='gt', backend='pillow'), dict(type=PackInputs) ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/imagenet_256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets.transforms import (CenterCropLongEdge, Flip, LoadImageFromFile, PackInputs, RandomCropLongEdge, Resize) # dataset settings dataset_type = 'ImageNet' # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type=LoadImageFromFile, key='img'), dict(type=RandomCropLongEdge, keys=['img']), dict(type=Resize, scale=(256, 256), keys=['img'], backend='pillow'), dict(type=Flip, keys=['img'], flip_ratio=0.5, direction='horizontal'), dict(type=PackInputs) ] test_pipeline = [ dict(type=LoadImageFromFile, key='img'), dict(type=CenterCropLongEdge, keys=['img']), dict(type=Resize, scale=(256, 256), backend='pillow'), dict(type=PackInputs) ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/imagenet_512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset.sampler import DefaultSampler from mmagic.datasets.imagenet_dataset import ImageNet from mmagic.datasets.transforms.aug_shape import Flip, Resize from mmagic.datasets.transforms.crop import (CenterCropLongEdge, RandomCropLongEdge) from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile # dataset settings dataset_type = ImageNet # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=RandomCropLongEdge, keys='gt'), dict(type=Resize, scale=(512, 512), keys='gt', backend='pillow'), dict(type=Flip, keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type=PackInputs) ] test_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=CenterCropLongEdge, keys='gt'), dict(type=Resize, scale=(512, 512), keys='gt', backend='pillow'), dict(type=PackInputs) ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/imagenet_64.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset.sampler import DefaultSampler from mmagic.datasets.imagenet_dataset import ImageNet from mmagic.datasets.transforms.aug_shape import Flip, Resize from mmagic.datasets.transforms.crop import (CenterCropLongEdge, RandomCropLongEdge) from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile # dataset settings dataset_type = ImageNet # different from mmcls, we adopt the setting used in BigGAN. # We use `RandomCropLongEdge` in training and `CenterCropLongEdge` in testing. train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=RandomCropLongEdge, keys='gt'), dict(type=Resize, scale=(64, 64), keys='gt', backend='pillow'), dict(type=Flip, keys='gt', flip_ratio=0.5, direction='horizontal'), dict(type=PackInputs) ] test_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=CenterCropLongEdge, keys='gt'), dict(type=Resize, scale=(64, 64), keys='gt', backend='pillow'), dict(type=PackInputs) ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/imagenet_noaug_128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # dataset settings from mmengine.dataset.sampler import DefaultSampler from mmagic.datasets.imagenet_dataset import ImageNet from mmagic.datasets.transforms.aug_shape import Resize from mmagic.datasets.transforms.crop import CenterCropLongEdge from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile dataset_type = ImageNet # different from mmcls, we adopt the setting used in BigGAN. # Remove `RandomFlip` augmentation and change `RandomCropLongEdge` to # `CenterCropLongEdge` to eliminate randomness. # dataset settings train_pipeline = [ dict(type=LoadImageFromFile, key='img'), dict(type=CenterCropLongEdge), dict(type=Resize, scale=(128, 128), backend='pillow'), dict(type=PackInputs) ] test_pipeline = [ dict(type=LoadImageFromFile, key='img'), dict(type=CenterCropLongEdge), dict(type=Resize, scale=(128, 128), backend='pillow'), dict(type=PackInputs) ] train_dataloader = dict( batch_size=None, num_workers=5, dataset=dict( type=dataset_type, data_root='data/imagenet', ann_file='meta/train.txt', data_prefix='train', pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=True), persistent_workers=True) val_dataloader = dict( batch_size=64, num_workers=5, dataset=dict( type=dataset_type, data_root='./data/imagenet/', ann_file='meta/train.txt', data_prefix='train', pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = val_dataloader ================================================ FILE: mmagic/configs/_base_/datasets/liif_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import (GenerateCoordinateAndCell, LoadImageFromFile, PackInputs, RandomDownSampling) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM scale_test_list = [2, 3, 4, 6, 18, 30] test_pipelines = [[ dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=RandomDownSampling, scale_min=scale_test, scale_max=scale_test), dict(type=GenerateCoordinateAndCell, scale=scale_test, reshape_gt=False), dict(type=PackInputs) ] for scale_test in scale_test_list] # test config for Set5 set5_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root='data/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] set5_evaluators = [[ dict(type=PSNR, crop_border=scale, prefix=f'Set5x{scale}'), dict(type=SSIM, crop_border=scale, prefix=f'Set5x{scale}'), ] for scale in scale_test_list] # test config for Set14 set14_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root='data/Set14', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] set14_evaluators = [[ dict(type=PSNR, crop_border=scale, prefix=f'Set14x{scale}'), dict(type=SSIM, crop_border=scale, prefix=f'Set14x{scale}'), ] for scale in scale_test_list] # test config for DIV2K div2k_dataloaders = [ dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root='data/DIV2K', data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) for test_pipeline in test_pipelines ] div2k_evaluators = [[ dict(type=PSNR, crop_border=scale, prefix=f'DIV2Kx{scale}'), dict(type=SSIM, crop_border=scale, prefix=f'DIV2Kx{scale}'), ] for scale in scale_test_list] # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ *set5_dataloaders, *set14_dataloaders, *div2k_dataloaders, ] test_evaluator = [ *set5_evaluators, *set14_evaluators, *div2k_evaluators, ] ================================================ FILE: mmagic/configs/_base_/datasets/lsun_stylegan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets.transforms import LoadImageFromFile, PackInputs dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=PackInputs) ] val_pipeline = [dict(type=LoadImageFromFile, key='gt'), dict(type=PackInputs)] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/paired_imgs_256x256_crop.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets.transforms import (FixedCrop, Flip, LoadPairedImageFromFile, PackInputs, Resize) dataset_type = 'PairedImageDataset' # domain_a = None # set by user # domain_b = None # set by user train_pipeline = [ dict( type=LoadPairedImageFromFile, key='pair', domain_a='A', domain_b='B', color_type='color'), dict( type=Resize, keys=['img_A', 'img_B'], scale=(286, 286), interpolation='bicubic'), dict(type=FixedCrop, keys=['img_A', 'img_B'], crop_size=(256, 256)), dict(type=Flip, keys=['img_A', 'img_B'], direction='horizontal'), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type=PackInputs, # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] test_pipeline = [ dict( type=LoadPairedImageFromFile, key='pair', domain_a='A', domain_b='B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=[ dict( type=Resize, scale=(256, 256), keys='img', interpolation='bicubic') ]), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type=PackInputs, # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=4, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/places.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.evaluation import MAE, PSNR, SSIM # Base config for places365 dataset # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data/Places' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt='data_large'), ann_file='meta/places365_train_challenge.txt', # Note that Places365-standard (1.8M images) and # Place365-challenge (8M images) use different image lists. test_mode=False, )) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=dataset_type, data_root=data_root, data_prefix=dict(gt='val_large'), ann_file='meta/places365_val.txt', test_mode=True, )) test_dataloader = val_dataloader val_evaluator = [ dict(type=MAE, mask_key='mask', scaling=100), # By default, compute with pixel value from 0-1 # scale=2 to align with 1.0 # scale=100 seems to align with readme dict(type=PSNR), dict(type=SSIM), ] test_evaluator = val_evaluator ================================================ FILE: mmagic/configs/_base_/datasets/sisr_x2_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM, Evaluator test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=2, prefix='Set5'), dict(type=SSIM, crop_border=2, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx2', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=2, prefix='Set14'), dict(type=SSIM, crop_border=2, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, # ann_file='meta_info_DIV2K800sub_GT.txt', ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X2_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=2, prefix='DIV2K'), dict(type=SSIM, crop_border=2, prefix='DIV2K'), ]) # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/sisr_x3_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM, Evaluator test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=3, prefix='Set5'), dict(type=SSIM, crop_border=3, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx3', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=3, prefix='Set14'), dict(type=SSIM, crop_border=3, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X3_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=3, prefix='DIV2K'), dict(type=SSIM, crop_border=3, prefix='DIV2K'), ]) # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/sisr_x4_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM, Evaluator test_pipeline = [ dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=PackInputs) ] # test config for Set5 set5_data_root = 'data/Set5' set5_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=set5_data_root, data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) set5_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=4, prefix='Set5'), dict(type=SSIM, crop_border=4, prefix='Set5'), ]) set14_data_root = 'data/Set14' set14_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, metainfo=dict(dataset_type='set14', task_name='sisr'), data_root=set14_data_root, data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=test_pipeline)) set14_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=4, prefix='Set14'), dict(type=SSIM, crop_border=4, prefix='Set14'), ]) # test config for DIV2K div2k_data_root = 'data/DIV2K' div2k_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicImageDataset, ann_file='meta_info_DIV2K100sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=div2k_data_root, data_prefix=dict( img='DIV2K_train_LR_bicubic/X4_sub', gt='DIV2K_train_HR_sub'), pipeline=test_pipeline)) div2k_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=4, prefix='DIV2K'), dict(type=SSIM, crop_border=4, prefix='DIV2K'), ]) # test config test_cfg = dict(type=MultiTestLoop) test_dataloader = [ set5_dataloader, set14_dataloader, div2k_dataloader, ] test_evaluator = [ set5_evaluator, set14_evaluator, div2k_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/tdan_test_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicFramesDataset from mmagic.datasets.transforms import (GenerateFrameIndiceswithPadding, GenerateSegmentIndices, LoadImageFromFile, PackInputs) from mmagic.engine.runner import MultiTestLoop from mmagic.evaluation import PSNR, SSIM, Evaluator # configs for SPMCS-30 SPMC_data_root = 'data/SPMCS' SPMC_pipeline = [ dict(type=GenerateFrameIndiceswithPadding, padding='reflection'), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] SPMC_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='spmcs', task_name='vsr'), data_root=SPMC_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_SPMCS_GT.txt', depth=2, num_input_frames=5, pipeline=SPMC_pipeline)) SPMC_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='spmcs', task_name='vsr'), data_root=SPMC_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_SPMCS_GT.txt', depth=2, num_input_frames=5, pipeline=SPMC_pipeline)) SPMC_bd_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=8, convert_to='Y', prefix='SPMCS-BDx4-Y'), dict(type=SSIM, crop_border=8, convert_to='Y', prefix='SPMCS-BDx4-Y'), ]) SPMC_bi_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, crop_border=8, convert_to='Y', prefix='SPMCS-BIx4-Y'), dict(type=SSIM, crop_border=8, convert_to='Y', prefix='SPMCS-BIx4-Y'), ]) # config for vid4 vid4_data_root = 'data/Vid4' vid4_pipeline = [ # dict(type=GenerateSegmentIndices, interval_list=[1]), dict(type=GenerateFrameIndiceswithPadding, padding='reflection'), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] vid4_bd_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BDx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=5, pipeline=vid4_pipeline)) vid4_bi_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root=vid4_data_root, data_prefix=dict(img='BIx4', gt='GT'), ann_file='meta_info_Vid4_GT.txt', depth=2, num_input_frames=5, pipeline=vid4_pipeline)) vid4_bd_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, convert_to='Y', prefix='VID4-BDx4-Y'), dict(type=SSIM, convert_to='Y', prefix='VID4-BDx4-Y'), ]) vid4_bi_evaluator = dict( type=Evaluator, metrics=[ dict(type=PSNR, convert_to='Y', prefix='VID4-BIx4-Y'), dict(type=SSIM, convert_to='Y', prefix='VID4-BIx4-Y'), ]) # config for test test_cfg = dict(type=MultiTestLoop) test_dataloader = [ SPMC_bd_dataloader, SPMC_bi_dataloader, vid4_bd_dataloader, vid4_bi_dataloader, ] test_evaluator = [ SPMC_bd_evaluator, SPMC_bi_evaluator, vid4_bd_evaluator, vid4_bi_evaluator, ] ================================================ FILE: mmagic/configs/_base_/datasets/unconditional_imgs_128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets.transforms import LoadImageFromFile, PackInputs, Resize # dataset_type = 'BasicImageDataset' dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=Resize, keys='gt', scale=(128, 128)), dict(type=PackInputs) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/unconditional_imgs_64x64.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets.transforms import LoadImageFromFile, PackInputs, Resize dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=Resize, keys='gt', scale=(64, 64)), dict(type=PackInputs) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/unconditional_imgs_flip_512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset.sampler import DefaultSampler, InfiniteSampler from mmagic.datasets.basic_image_dataset import BasicImageDataset from mmagic.datasets.transforms.aug_shape import Flip, Resize from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile dataset_type = BasicImageDataset # TODO: train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict(type=Resize, keys='gt', scale=(512, 512)), dict(type=Flip, keys=['gt'], direction='horizontal'), # TODO: dict(type=PackInputs) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/unconditional_imgs_flip_lanczos_resize_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='Resize', keys='gt', scale=(256, 256), interpolation='lanczos', backend='pillow'), dict(type='Flip', keys=['gt'], direction='horizontal'), dict(type='PackInputs') ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=None, num_workers=4, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=None, num_workers=4, dataset=dict( type=dataset_type, data_prefix=dict(gt=''), data_root=None, # set by user pipeline=train_pipeline), sampler=dict(type='DefaultSampler', shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/datasets/unpaired_imgs_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmagic.datasets.transforms import Crop, Flip, PackInputs, Resize dataset_type = 'UnpairedImageDataset' domain_a = None # set by user domain_b = None # set by user train_pipeline = [ dict(type='LoadImageFromFile', key='img_A', color_type='color'), dict(type='LoadImageFromFile', key='img_B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=[ dict(type=Resize, scale=(286, 286), interpolation='bicubic'), dict( type=Crop, keys=['img'], crop_size=(256, 256), random_crop=True), ]), dict(type=Flip, keys=['img_A'], direction='horizontal'), dict(type=Flip, keys=['img_B'], direction='horizontal'), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type=PackInputs, # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] test_pipeline = [ dict(type='LoadImageFromFile', key='img_A', color_type='color'), dict(type='LoadImageFromFile', key='img_B', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_A', 'img_B']}, auto_remap=True, share_random_params=True, transforms=dict( type=Resize, scale=(256, 256), interpolation='bicubic'), ), # NOTE: users should implement their own keyMapper and Pack operation # dict( # type='KeyMapper', # mapping={ # f'img_{domain_a}': 'img_A', # f'img_{domain_b}': 'img_B' # }, # remapping={ # f'img_{domain_a}': f'img_{domain_a}', # f'img_{domain_b}': f'img_{domain_b}' # }), # dict( # type=PackInputs, # keys=[f'img_{domain_a}', f'img_{domain_b}'], # data_keys=[f'img_{domain_a}', f'img_{domain_b}']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=4, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user test_mode=True, pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=4, dataset=dict( type=dataset_type, data_root=None, # set by user test_mode=True, pipeline=test_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) ================================================ FILE: mmagic/configs/_base_/default_runtime.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, LoggerHook, ParamSchedulerHook) from mmengine.visualization import LocalVisBackend from mmagic.engine import BasicVisualizationHook, IterTimerHook, LogProcessor from mmagic.visualization import ConcatImageVisualizer default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), checkpoint=dict( type=CheckpointHook, interval=5000, out_dir=save_dir, by_epoch=False, max_keep_ckpts=10, save_best='PSNR', rule='greater', ), sampler_seed=dict(type=DistSamplerSeedHook), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) log_level = 'INFO' log_processor = dict(type=LogProcessor, window_size=100, by_epoch=False) load_from = None resume = False vis_backends = [dict(type=LocalVisBackend)] visualizer = dict( type=ConcatImageVisualizer, vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type=BasicVisualizationHook, interval=1)] ================================================ FILE: mmagic/configs/_base_/gen_default_runtime.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.hooks import CheckpointHook, LoggerHook from mmengine.model import MMSeparateDistributedDataParallel from mmagic.engine import (IterTimerHook, LogProcessor, MultiOptimWrapperConstructor, MultiTestLoop, MultiValLoop) from mmagic.evaluation import Evaluator from mmagic.visualization import VisBackend, Visualizer default_scope = 'mmagic' randomness = dict(seed=2022, diff_rank_seed=True) # env settings dist_params = dict(backend='nccl') # disable opencv multithreading to avoid system being overloaded opencv_num_threads = 0 # set multi-process start method as `fork` to speed up the training mp_start_method = 'fork' # configure for default hooks default_hooks = dict( # record time of every iteration. timer=dict(type=IterTimerHook), # print log every 100 iterations. logger=dict(type=LoggerHook, interval=100, log_metric_by_epoch=False), # save checkpoint per 10000 iterations checkpoint=dict( type=CheckpointHook, interval=10000, by_epoch=False, max_keep_ckpts=20, less_keys=['FID-Full-50k/fid', 'FID-50k/fid', 'swd/avg'], greater_keys=['IS-50k/is', 'ms-ssim/avg'], save_optimizer=True)) # config for environment env_cfg = dict( # whether to enable cudnn benchmark. cudnn_benchmark=True, # set multi process parameters. mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), # set distributed parameters. dist_cfg=dict(backend='nccl')) # set log level log_level = 'INFO' log_processor = dict(type=LogProcessor, by_epoch=False) # load from which checkpoint load_from = None # whether to resume training from the loaded checkpoint resume = None # config for model wrapper model_wrapper_cfg = dict( type=MMSeparateDistributedDataParallel, broadcast_buffers=False, find_unused_parameters=False) # set visualizer vis_backends = [dict(type=VisBackend)] visualizer = dict(type=Visualizer, vis_backends=vis_backends) # config for training train_cfg = dict(by_epoch=False, val_begin=1, val_interval=10000) # config for val val_cfg = dict(type=MultiValLoop) val_evaluator = dict(type=Evaluator) # config for test test_cfg = dict(type=MultiTestLoop) test_evaluator = dict(type=Evaluator) # config for optim_wrapper_constructor optim_wrapper = dict(constructor=MultiOptimWrapperConstructor) ================================================ FILE: mmagic/configs/_base_/inpaint_default_runtime.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, LoggerHook, ParamSchedulerHook) from mmengine.runner import LogProcessor from mmengine.visualization import LocalVisBackend from mmagic.engine.hooks import BasicVisualizationHook from mmagic.visualization import ConcatImageVisualizer default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), checkpoint=dict( type=CheckpointHook, interval=50000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type=DistSamplerSeedHook), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type=LocalVisBackend)] visualizer = dict( type=ConcatImageVisualizer, vis_backends=vis_backends, fn_key='gt_path', img_keys=['gt_img', 'input', 'pred_img'], bgr2rgb=True) custom_hooks = [dict(type=BasicVisualizationHook, interval=1)] log_level = 'INFO' log_processor = dict(type=LogProcessor, by_epoch=False) load_from = None resume = False # TODO: support auto scaling lr ================================================ FILE: mmagic/configs/_base_/matting_default_runtime.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, LoggerHook, ParamSchedulerHook) from mmengine.runner import LogProcessor from mmengine.visualization import LocalVisBackend from mmagic.engine.hooks import BasicVisualizationHook from mmagic.visualization import ConcatImageVisualizer default_scope = 'mmagic' save_dir = './work_dirs' default_hooks = dict( timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), checkpoint=dict( type=CheckpointHook, interval=10000, by_epoch=False, out_dir=save_dir), sampler_seed=dict(type=DistSamplerSeedHook), ) env_cfg = dict( cudnn_benchmark=False, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=4), dist_cfg=dict(backend='nccl'), ) vis_backends = [dict(type=LocalVisBackend)] visualizer = dict( type=ConcatImageVisualizer, vis_backends=vis_backends, fn_key='trimap_path', img_keys=['pred_alpha', 'trimap', 'gt_merged', 'gt_alpha'], bgr2rgb=True) custom_hooks = [dict(type=BasicVisualizationHook, interval=2000)] log_level = 'INFO' log_processor = dict(type=LogProcessor, by_epoch=False) load_from = None resume = False # TODO: support auto scaling lr ================================================ FILE: mmagic/configs/_base_/models/base_cyclegan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.archs import PatchDiscriminator from mmagic.models.editors import CycleGAN from mmagic.models.editors.cyclegan import ResnetGenerator _domain_a = None # set by user _domain_b = None # set by user model = dict( type=CycleGAN, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=ResnetGenerator, in_channels=3, out_channels=3, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type=PatchDiscriminator, in_channels=3, base_channels=64, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02)), default_domain=None, # set by user reachable_domains=None, # set by user related_domains=None # set by user ) ================================================ FILE: mmagic/configs/_base_/models/base_deepfillv1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import MMSeparateDistributedDataParallel from mmengine.optim import OptimWrapper from mmagic.models import DataPreprocessor from mmagic.models.archs import MultiLayerDiscriminator from mmagic.models.editors import (ContextualAttentionNeck, DeepFillDecoder, DeepFillEncoder, DeepFillEncoderDecoder, DeepFillRefiner, DeepFillv1Discriminators, DeepFillv1Inpaintor, GLDilationNeck, GLEncoderDecoder) from mmagic.models.losses import (DiscShiftLoss, GANLoss, GradientPenaltyLoss, L1Loss) # DistributedDataParallel model_wrapper_cfg = dict(type=MMSeparateDistributedDataParallel) model = dict( type=DeepFillv1Inpaintor, data_preprocessor=dict( type=DataPreprocessor, mean=[127.5], std=[127.5], ), encdec=dict( type=DeepFillEncoderDecoder, stage1=dict( type=GLEncoderDecoder, encoder=dict(type=DeepFillEncoder, padding_mode='reflect'), decoder=dict( type=DeepFillDecoder, in_channels=128, padding_mode='reflect'), dilation_neck=dict( type=GLDilationNeck, in_channels=128, act_cfg=dict(type='ELU'), padding_mode='reflect')), stage2=dict( type=DeepFillRefiner, encoder_attention=dict( type=DeepFillEncoder, encoder_type='stage2_attention', padding_mode='reflect'), encoder_conv=dict( type=DeepFillEncoder, encoder_type='stage2_conv', padding_mode='reflect'), dilation_neck=dict( type=GLDilationNeck, in_channels=128, act_cfg=dict(type='ELU'), padding_mode='reflect'), contextual_attention=dict( type=ContextualAttentionNeck, in_channels=128, padding_mode='reflect'), decoder=dict( type=DeepFillDecoder, in_channels=256, padding_mode='reflect'))), disc=dict( type=DeepFillv1Discriminators, global_disc_cfg=dict( type=MultiLayerDiscriminator, in_channels=3, max_channels=256, fc_in_channels=256 * 16 * 16, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), local_disc_cfg=dict( type=MultiLayerDiscriminator, in_channels=3, max_channels=512, fc_in_channels=512 * 8 * 8, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2))), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type=GANLoss, gan_type='wgan', loss_weight=0.0001, ), loss_l1_hole=dict( type=L1Loss, loss_weight=1.0, ), loss_l1_valid=dict( type=L1Loss, loss_weight=1.0, ), loss_gp=dict(type=GradientPenaltyLoss, loss_weight=10.), loss_disc_shift=dict(type=DiscShiftLoss, loss_weight=0.001)) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0001)), disc=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0001))) # learning policy # Fixed ================================================ FILE: mmagic/configs/_base_/models/base_deepfillv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import MMSeparateDistributedDataParallel from mmengine.optim import OptimWrapper from mmagic.models import DataPreprocessor from mmagic.models.archs import MultiLayerDiscriminator from mmagic.models.base_models import TwoStageInpaintor from mmagic.models.editors import (ContextualAttentionNeck, DeepFillDecoder, DeepFillEncoder, DeepFillEncoderDecoder, DeepFillRefiner, GLDilationNeck, GLEncoderDecoder) from mmagic.models.losses import GANLoss, L1Loss # DistributedDataParallel model_wrapper_cfg = dict(type=MMSeparateDistributedDataParallel) model = dict( type=TwoStageInpaintor, disc_input_with_mask=True, data_preprocessor=dict( type=DataPreprocessor, mean=[127.5], std=[127.5], ), encdec=dict( type=DeepFillEncoderDecoder, stage1=dict( type=GLEncoderDecoder, encoder=dict( type=DeepFillEncoder, conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), decoder=dict( type=DeepFillDecoder, conv_type='gated_conv', in_channels=96, channel_factor=0.75, out_act_cfg=dict(type='Tanh'), padding_mode='reflect'), dilation_neck=dict( type=GLDilationNeck, in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect')), stage2=dict( type=DeepFillRefiner, encoder_attention=dict( type=DeepFillEncoder, encoder_type='stage2_attention', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), encoder_conv=dict( type=DeepFillEncoder, encoder_type='stage2_conv', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), dilation_neck=dict( type=GLDilationNeck, in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect'), contextual_attention=dict( type=ContextualAttentionNeck, in_channels=96, conv_type='gated_conv', padding_mode='reflect'), decoder=dict( type=DeepFillDecoder, in_channels=192, conv_type='gated_conv', out_act_cfg=dict(type='Tanh'), padding_mode='reflect'))), disc=dict( type=MultiLayerDiscriminator, in_channels=4, max_channels=256, fc_in_channels=None, num_convs=6, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=True, ), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type=GANLoss, gan_type='hinge', loss_weight=0.1, ), loss_l1_hole=dict( type=L1Loss, loss_weight=1.0, ), loss_l1_valid=dict( type=L1Loss, loss_weight=1.0, ), ) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0001)), disc=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0001))) # learning policy # Fixed ================================================ FILE: mmagic/configs/_base_/models/base_edvr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmengine.hooks import CheckpointHook from mmengine.optim import OptimWrapper from mmengine.runner import IterBasedTrainLoop from mmagic.datasets import BasicFramesDataset from mmagic.datasets.transforms import (Flip, GenerateFrameIndices, GenerateFrameIndiceswithPadding, GenerateSegmentIndices, LoadImageFromFile, PackInputs, PairedRandomCrop, RandomTransposeHW, SetValues, TemporalReverse) from mmagic.engine.runner import MultiTestLoop, MultiValLoop from mmagic.evaluation import PSNR, SSIM _base_ = '../default_runtime.py' scale = 4 train_pipeline = [ dict(type=GenerateFrameIndices, interval_list=[1], frames_per_clip=99), dict(type=TemporalReverse, keys='img_path', reverse_ratio=0), dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb'), dict(type=SetValues, dictionary=dict(scale=scale)), dict(type=PairedRandomCrop, gt_patch_size=256), dict( type=Flip, keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type=Flip, keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type=RandomTransposeHW, keys=['img', 'gt'], transpose_ratio=0.5), dict(type=PackInputs) ] val_pipeline = [ dict(type=GenerateFrameIndiceswithPadding, padding='reflection_circle'), dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb'), dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb'), dict(type=PackInputs) ] demo_pipeline = [ dict(type=GenerateSegmentIndices, interval_list=[1]), dict( type=LoadImageFromFile, key='img', color_type='color', channel_order='rgb'), dict(type=PackInputs) ] data_root = 'data/REDS' save_dir = './work_dirs' train_dataloader = dict( num_workers=8, batch_size=8, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_train.txt', depth=2, num_input_frames=5, num_output_frames=1, pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='reds_reds4', task_name='vsr'), data_root=data_root, data_prefix=dict(img='train_sharp_bicubic/X4', gt='train_sharp'), ann_file='meta_info_reds4_val.txt', depth=2, num_input_frames=5, num_output_frames=1, pipeline=val_pipeline)) test_dataloader = val_dataloader val_evaluator = [ dict(type=PSNR), dict(type=SSIM), ] test_evaluator = val_evaluator train_cfg = dict(type=IterBasedTrainLoop, max_iters=600_000, val_interval=5000) val_cfg = dict(type=MultiValLoop) test_cfg = dict(type=MultiTestLoop) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type=OptimWrapper, optimizer=dict(type='Adam', lr=2e-4, betas=(0.9, 0.999)), ) default_hooks = dict( checkpoint=dict( type=CheckpointHook, interval=5000, save_optimizer=True, out_dir=save_dir, by_epoch=False)) ================================================ FILE: mmagic/configs/_base_/models/base_gl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import MMSeparateDistributedDataParallel from mmengine.optim import OptimWrapper from mmagic.models import DataPreprocessor from mmagic.models.editors import (GLDecoder, GLDilationNeck, GLEncoder, GLEncoderDecoder) from mmagic.models.editors.global_local import GLDiscs, GLInpaintor from mmagic.models.losses import GANLoss, L1Loss # DistributedDataParallel model_wrapper_cfg = dict(type=MMSeparateDistributedDataParallel) model = dict( type=GLInpaintor, data_preprocessor=dict( type=DataPreprocessor, mean=[127.5], std=[127.5], ), encdec=dict( type=GLEncoderDecoder, encoder=dict(type=GLEncoder, norm_cfg=dict(type='SyncBN')), decoder=dict(type=GLDecoder, norm_cfg=dict(type='SyncBN')), dilation_neck=dict(type=GLDilationNeck, norm_cfg=dict(type='SyncBN'))), disc=dict( type=GLDiscs, global_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='SyncBN'), ), local_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=5, norm_cfg=dict(type='SyncBN'), ), ), loss_gan=dict( type=GANLoss, gan_type='vanilla', loss_weight=0.001, ), loss_l1_hole=dict( type=L1Loss, loss_weight=1.0, )) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0004)), disc=dict(type=OptimWrapper, optimizer=dict(type='Adam', lr=0.0004))) # learning policy # Fixed ================================================ FILE: mmagic/configs/_base_/models/base_glean.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, LoggerHook, ParamSchedulerHook) from mmengine.model import MMSeparateDistributedDataParallel from mmengine.optim import CosineAnnealingLR, OptimWrapper from mmengine.runner import IterBasedTrainLoop from mmagic.engine.runner import MultiTestLoop, MultiValLoop from mmagic.evaluation import MAE, PSNR, SSIM _base_ = '../default_runtime.py' # DistributedDataParallel model_wrapper_cfg = dict( type=MMSeparateDistributedDataParallel, find_unused_parameters=True) save_dir = './work_dirs' val_evaluator = [ dict(type=MAE), dict(type=PSNR), dict(type=SSIM), ] test_evaluator = val_evaluator train_cfg = dict(type=IterBasedTrainLoop, max_iters=300_000, val_interval=5000) val_cfg = dict(type=MultiValLoop) test_cfg = dict(type=MultiTestLoop) # optimizer optim_wrapper = dict( constructor='MultiOptimWrapperConstructor', generator=dict( type=OptimWrapper, optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), discriminator=dict( type=OptimWrapper, optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), ) # learning policy param_scheduler = dict( type=CosineAnnealingLR, by_epoch=False, T_max=600_000, eta_min=1e-7) default_hooks = dict( checkpoint=dict( type=CheckpointHook, interval=5000, save_optimizer=True, by_epoch=False, out_dir=save_dir, save_best=['MAE', 'PSNR', 'SSIM'], rule=['less', 'greater', 'greater']), timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), sampler_seed=dict(type=DistSamplerSeedHook), ) ================================================ FILE: mmagic/configs/_base_/models/base_liif.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, LoggerHook, ParamSchedulerHook) from mmengine.optim import MultiStepLR, OptimWrapper from mmengine.runner import IterBasedTrainLoop from mmagic.datasets.transforms import (Flip, GenerateCoordinateAndCell, LoadImageFromFile, PackInputs, RandomDownSampling, RandomTransposeHW) from mmagic.engine.runner import MultiValLoop from mmagic.evaluation import MAE, PSNR, SSIM, Evaluator _base_ = '../default_runtime.py' work_dir = './work_dirs/liif' save_dir = './work_dirs' scale_min, scale_max = 1, 4 scale_test = 4 train_pipeline = [ dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type=RandomDownSampling, scale_min=scale_min, scale_max=scale_max, patch_size=48), dict( type=Flip, keys=['img', 'gt'], flip_ratio=0.5, direction='horizontal'), dict(type=Flip, keys=['img', 'gt'], flip_ratio=0.5, direction='vertical'), dict(type=RandomTransposeHW, keys=['img', 'gt'], transpose_ratio=0.5), dict(type=GenerateCoordinateAndCell, sample_quantity=2304), dict(type=PackInputs) ] val_pipeline = [ dict( type=LoadImageFromFile, key='gt', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict(type=RandomDownSampling, scale_min=scale_max, scale_max=scale_max), dict(type=GenerateCoordinateAndCell, reshape_gt=False), dict(type=PackInputs) ] # test_pipeline = [ # dict( # type=LoadImageFromFile, # key='gt', # color_type='color', # channel_order='rgb', # imdecode_backend='cv2'), # dict( # type=LoadImageFromFile, # key='img', # color_type='color', # channel_order='rgb', # imdecode_backend='cv2'), # dict(type=GenerateCoordinateAndCell, scale=scale_test, # reshape_gt=False), # dict(type=PackInputs) # ] # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' train_dataloader = dict( num_workers=8, batch_size=16, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, ann_file='meta_info_DIV2K800sub_GT.txt', metainfo=dict(dataset_type='div2k', task_name='sisr'), data_root=data_root + '/DIV2K', data_prefix=dict(gt='DIV2K_train_HR_sub'), pipeline=train_pipeline)) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=dataset_type, metainfo=dict(dataset_type='set5', task_name='sisr'), data_root=data_root + '/Set5', data_prefix=dict(img='LRbicx4', gt='GTmod12'), pipeline=val_pipeline)) val_evaluator = dict( type=Evaluator, metrics=[ dict(type=MAE), dict(type=PSNR, crop_border=scale_max), dict(type=SSIM, crop_border=scale_max), ]) train_cfg = dict( type=IterBasedTrainLoop, max_iters=1_000_000, val_interval=3000) val_cfg = dict(type=MultiValLoop) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type=OptimWrapper, optimizer=dict(type='Adam', lr=1e-4)) # learning policy param_scheduler = dict( type=MultiStepLR, by_epoch=False, milestones=[200_000, 400_000, 600_000, 800_000], gamma=0.5) default_hooks = dict( checkpoint=dict( type=CheckpointHook, interval=3000, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), sampler_seed=dict(type=DistSamplerSeedHook), ) ================================================ FILE: mmagic/configs/_base_/models/base_pconv.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import MMSeparateDistributedDataParallel from mmengine.optim import OptimWrapper from mmagic.models import DataPreprocessor from mmagic.models.editors import (PConvDecoder, PConvEncoder, PConvEncoderDecoder, PConvInpaintor) from mmagic.models.losses import L1Loss, MaskedTVLoss, PerceptualLoss # DistributedDataParallel model_wrapper_cfg = dict(type=MMSeparateDistributedDataParallel) model = dict( type=PConvInpaintor, data_preprocessor=dict( type=DataPreprocessor, mean=[127.5], std=[127.5], ), encdec=dict( type=PConvEncoderDecoder, encoder=dict( type=PConvEncoder, norm_cfg=dict(type='SyncBN', requires_grad=False), norm_eval=True), decoder=dict(type=PConvDecoder, norm_cfg=dict(type='SyncBN'))), disc=None, loss_composed_percep=dict( type=PerceptualLoss, vgg_type='vgg16', layer_weights={ '4': 1., '9': 1., '16': 1., }, perceptual_weight=0.05, style_weight=120, pretrained=('torchvision://vgg16')), loss_out_percep=True, loss_l1_hole=dict( type=L1Loss, loss_weight=6., ), loss_l1_valid=dict( type=L1Loss, loss_weight=1., ), loss_tv=dict( type=MaskedTVLoss, loss_weight=0.1, )) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type=OptimWrapper, optimizer=dict(type='Adam', lr=0.00005)) # learning policy # Fixed ================================================ FILE: mmagic/configs/_base_/models/base_pix2pix.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.archs import PatchDiscriminator from mmagic.models.editors import Pix2Pix from mmagic.models.editors.pix2pix import UnetGenerator source_domain = None # set by user target_domain = None # set by user # model settings model = dict( type=Pix2Pix, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=UnetGenerator, in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type=PatchDiscriminator, in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)), loss_config=dict(pixel_loss_weight=100.0), default_domain=target_domain, reachable_domains=[target_domain], related_domains=[target_domain, source_domain]) ================================================ FILE: mmagic/configs/_base_/models/base_styleganv1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors.stylegan1 import (StyleGAN1, StyleGAN1Discriminator, StyleGAN1Generator) model = dict( type=StyleGAN1, data_preprocessor=dict(type=DataPreprocessor), style_channels=512, generator=dict(type=StyleGAN1Generator, out_size=None, style_channels=512), discriminator=dict(type=StyleGAN1Discriminator, in_size=None)) ================================================ FILE: mmagic/configs/_base_/models/base_styleganv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import ExponentialMovingAverage from mmagic.models import DataPreprocessor from mmagic.models.editors import StyleGAN2 from mmagic.models.editors.stylegan2 import (StyleGAN2Discriminator, StyleGAN2Generator) # define GAN model d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) loss_config = dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2) model = dict( type=StyleGAN2, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=StyleGAN2Generator, out_size=None, # Need to be set. style_channels=512, ), discriminator=dict( type=StyleGAN2Discriminator, in_size=None, # Need to be set. ), ema_config=dict(type=ExponentialMovingAverage), loss_config=loss_config) ================================================ FILE: mmagic/configs/_base_/models/base_styleganv3.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # define GAN model from mmagic.models.base_models.average_model import ExponentialMovingAverage from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.stylegan2 import StyleGAN2Discriminator from mmagic.models.editors.stylegan3 import StyleGAN3, StyleGAN3Generator d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) model = dict( type=StyleGAN3, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=StyleGAN3Generator, # StyleGANv3Generator noise_size=512, style_channels=512, out_size=None, # Need to be set. img_channels=3, ), discriminator=dict( type=StyleGAN2Discriminator, in_size=None, # Need to be set. ), ema_config=dict(type=ExponentialMovingAverage), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) ================================================ FILE: mmagic/configs/_base_/models/base_tof.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.dataset import DefaultSampler, InfiniteSampler from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, LoggerHook, ParamSchedulerHook) from mmengine.optim import MultiStepLR, OptimWrapper from mmengine.runner import IterBasedTrainLoop from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine.runner import MultiTestLoop, MultiValLoop from mmagic.evaluation import MAE, PSNR, SSIM _base_ = '../default_runtime.py' train_pipeline = [ dict( type=LoadImageFromFile, key='img', channel_order='rgb', imdecode_backend='pillow'), dict( type=LoadImageFromFile, key='gt', channel_order='rgb', imdecode_backend='pillow'), dict(type=PackInputs) ] demo_pipeline = [ dict( type=LoadImageFromFile, key='img', channel_order='rgb', imdecode_backend='pillow'), dict(type=PackInputs) ] # dataset settings train_dataset_type = 'BasicFramesDataset' val_dataset_type = 'BasicFramesDataset' data_root = 'data/vimeo_triplet' save_dir = './work_dirs' train_dataloader = dict( num_workers=4, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=train_dataset_type, ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=train_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) val_dataloader = dict( num_workers=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=val_dataset_type, ann_file='tri_testlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), pipeline=train_pipeline, depth=2, load_frames_list=dict(img=['im1.png', 'im3.png'], gt=['im2.png']))) test_dataloader = val_dataloader val_evaluator = [ dict(type=MAE), dict(type=PSNR), dict(type=SSIM), ] test_evaluator = val_evaluator # 5000 iters == 1 epoch epoch_length = 5000 train_cfg = dict( type=IterBasedTrainLoop, max_iters=1_000_000, val_interval=epoch_length) val_cfg = dict(type=MultiValLoop) test_cfg = dict(type=MultiTestLoop) # optimizer optim_wrapper = dict( constructor='DefaultOptimWrapperConstructor', type=OptimWrapper, optimizer=dict( type='Adam', lr=5e-5, betas=(0.9, 0.99), weight_decay=1e-4, ), ) # learning policy param_scheduler = dict( type=MultiStepLR, by_epoch=False, gamma=0.5, milestones=[200000, 400000, 600000, 800000]) default_hooks = dict( checkpoint=dict( type=CheckpointHook, interval=epoch_length, save_optimizer=True, by_epoch=False, out_dir=save_dir, ), timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), sampler_seed=dict(type=DistSamplerSeedHook), ) ================================================ FILE: mmagic/configs/_base_/models/biggan/base_biggan_128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='BigGAN', num_classes=1000, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='BigGANGenerator', output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False, init_cfg=dict(type='ortho')), discriminator=dict( type='BigGANDiscriminator', input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho')), generator_steps=1, discriminator_steps=1) ================================================ FILE: mmagic/configs/_base_/models/dcgan/base_dcgan_128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors import DCGAN from mmagic.models.editors.dcgan import DCGANDiscriminator, DCGANGenerator # define GAN model model = dict( type=DCGAN, noise_size=100, data_preprocessor=dict(type=DataPreprocessor), generator=dict(type=DCGANGenerator, output_scale=128, base_channels=1024), discriminator=dict( type=DCGANDiscriminator, input_scale=128, output_scale=4, out_channels=100)) ================================================ FILE: mmagic/configs/_base_/models/dcgan/base_dcgan_64x64.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors import DCGAN from mmagic.models.editors.dcgan import DCGANDiscriminator, DCGANGenerator # define GAN model model = dict( type=DCGAN, noise_size=100, data_preprocessor=dict(type=DataPreprocessor), generator=dict(type=DCGANGenerator, output_scale=64, base_channels=1024), discriminator=dict( type=DCGANDiscriminator, input_scale=64, output_scale=4, out_channels=1)) ================================================ FILE: mmagic/configs/_base_/models/sagan/base_sagan_128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors import SAGAN from mmagic.models.editors.biggan import SelfAttentionBlock from mmagic.models.editors.sagan import ProjDiscriminator, SNGANGenerator model = dict( type=SAGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=SNGANGenerator, output_scale=128, base_channels=64, attention_cfg=dict(type=SelfAttentionBlock), attention_after_nth_block=4, with_spectral_norm=True), discriminator=dict( type=ProjDiscriminator, input_scale=128, base_channels=64, attention_cfg=dict(type=SelfAttentionBlock), attention_after_nth_block=1, with_spectral_norm=True), generator_steps=1, discriminator_steps=1) ================================================ FILE: mmagic/configs/_base_/models/sagan/base_sagan_32x32.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors import SAGAN from mmagic.models.editors.biggan import SelfAttentionBlock from mmagic.models.editors.sagan import ProjDiscriminator, SNGANGenerator model = dict( type=SAGAN, data_preprocessor=dict(type=DataPreprocessor), num_classes=10, generator=dict( type=SNGANGenerator, num_classes=10, output_scale=32, base_channels=256, attention_cfg=dict(type=SelfAttentionBlock), attention_after_nth_block=2, with_spectral_norm=True), discriminator=dict( type=ProjDiscriminator, num_classes=10, input_scale=32, base_channels=128, attention_cfg=dict(type=SelfAttentionBlock), attention_after_nth_block=1, with_spectral_norm=True), generator_steps=1, discriminator_steps=5) ================================================ FILE: mmagic/configs/_base_/models/sngan_proj/base_sngan_proj_128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors.sagan import (SAGAN, ProjDiscriminator, SNGANGenerator) # define GAN model model = dict( type=SAGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), generator=dict(type=SNGANGenerator, output_scale=128, base_channels=64), discriminator=dict( type=ProjDiscriminator, input_scale=128, base_channels=64), discriminator_steps=2) ================================================ FILE: mmagic/configs/_base_/models/sngan_proj/base_sngan_proj_32x32.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import DataPreprocessor from mmagic.models.editors.sagan import (SAGAN, ProjDiscriminator, SNGANGenerator) # define GAN model model = dict( type=SAGAN, num_classes=10, data_preprocessor=dict(type=DataPreprocessor), generator=dict(type=SNGANGenerator, output_scale=32, base_channels=256), discriminator=dict( type=ProjDiscriminator, input_scale=32, base_channels=128), discriminator_steps=5) ================================================ FILE: mmagic/configs/_base_/schedules/.gitkeep ================================================ ================================================ FILE: mmagic/configs/biggan/biggan-deep_cvt-hugging-face-rgb_imagenet1k-128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.biggan import (BigGAN, BigGANDeepDiscriminator, BigGANGenerator) with read_base(): from .._base_.datasets.imagenet_noaug_128 import * from .._base_.gen_default_runtime import * ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type=BigGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), ema_config=ema_config, generator=dict( type=BigGANGenerator, output_scale=128, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type=BigGANDeepDiscriminator, input_scale=128, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.biggan import (BigGAN, BigGANDiscriminator, BigGANGenerator) with read_base(): from .._base_.datasets.imagenet_noaug_128 import * from .._base_.gen_default_runtime import * # setting image size to 256x256 train_dataloader.dataset.pipeline[2].scale = (256, 256) test_dataloader.dataset.pipeline[2].scale = (256, 256) val_dataloader.dataset.pipeline[2].scale = (256, 256) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type=BigGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), ema_config=ema_config, generator=dict( type=BigGANGenerator, output_scale=256, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type=BigGANDiscriminator, input_scale=256, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/biggan/biggan-deep_cvt-hugging-face_rgb_imagenet1k-512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.biggan import (BigGAN, BigGANDiscriminator, BigGANGenerator) with read_base(): from .._base_.datasets.imagenet_noaug_128 import * from .._base_.gen_default_runtime import * # setting image size to 512x512 train_dataloader.dataset.pipeline[2].scale = (512, 512) test_dataloader.dataset.pipeline[2].scale = (512, 512) val_dataloader.dataset.pipeline[2].scale = (512, 512) ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type=BigGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), ema_config=ema_config, generator=dict( type=BigGANGenerator, output_scale=512, noise_size=128, num_classes=1000, base_channels=128, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), concat_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type=BigGANDiscriminator, input_scale=512, num_classes=1000, base_channels=128, sn_eps=1e-6, sn_style='torch', act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/biggan/biggan_2xb25-500kiters_cifar10-32x32.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.engine import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.biggan import (BigGAN, BigGANDiscriminator, BigGANGenerator) # define model with read_base(): from .._base_.datasets.cifar10_noaug import * from .._base_.gen_default_runtime import * ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, start_iter=1000) model = dict( type=BigGAN, num_classes=10, data_preprocessor=dict(type=DataPreprocessor, output_channel_order='BGR'), generator=dict( type=BigGANGenerator, output_scale=32, noise_size=128, num_classes=10, base_channels=64, with_shared_embedding=False, sn_eps=1e-8, sn_style='torch', split_noise=False, auto_sync_bn=False, init_cfg=dict(type='N02')), discriminator=dict( type=BigGANDiscriminator, input_scale=32, num_classes=10, base_channels=64, sn_eps=1e-8, sn_style='torch', with_spectral_norm=True, init_cfg=dict(type='N02')), generator_steps=1, discriminator_steps=4, ema_config=ema_config) # define dataset train_dataloader = dict(batch_size=25, num_workers=8) val_dataloader = dict(batch_size=25, num_workers=8) test_dataloader = dict(batch_size=25, num_workers=8) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), ] optim_wrapper = dict( generator=dict(optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0002, betas=(0.0, 0.999)))) train_cfg = dict(max_iters=500000) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/biggan/biggan_ajbrock-sn_8xb32-1500kiters_imagenet1k-128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.engine import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance with read_base(): from .._base_.datasets.imagenet_noaug_128 import * from .._base_.gen_default_runtime import * from .._base_.models.biggan.base_biggan_128x128 import * # define model ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict(ema_config=ema_config) train_cfg = dict(max_iters=1500000) # define dataset train_dataloader = dict( batch_size=32, num_workers=8, dataset=dict(data_root='data/imagenet')) # define optimizer optim_wrapper = dict( generator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0001, betas=(0.0, 0.999), eps=1e-6)), discriminator=dict( accumulative_counts=8, optimizer=dict(type='Adam', lr=0.0004, betas=(0.0, 0.999), eps=1e-6))) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=10000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), ] metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # save multi best checkpoints default_hooks = dict( checkpoint=dict( save_best=['FID-Full-50k/fid', 'IS-50k/is'], rule=['less', 'greater'])) val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/biggan/biggan_cvt-BigGAN-PyTorch-rgb_imagenet1k-128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.biggan import (BigGAN, BigGANDiscriminator, BigGANGenerator) with read_base(): from .._base_.datasets.imagenet_noaug_128 import * from .._base_.gen_default_runtime import * ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=0.0001, update_buffers=True, start_iter=20000) model = dict( type=BigGAN, num_classes=1000, data_preprocessor=dict(type=DataPreprocessor), ema_config=ema_config, generator=dict( type=BigGANGenerator, output_scale=128, noise_size=120, num_classes=1000, base_channels=96, shared_dim=128, with_shared_embedding=True, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), split_noise=True, auto_sync_bn=False, rgb2bgr=True, init_cfg=dict(type='ortho')), discriminator=dict( type=BigGANDiscriminator, input_scale=128, num_classes=1000, base_channels=96, sn_eps=1e-6, act_cfg=dict(type='ReLU', inplace=True), with_spectral_norm=True, init_cfg=dict(type='ortho'))) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type='IS', prefix='IS-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/dreambooth/dreambooth-finetune_text_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.gen_default_runtime import * from mmengine.dataset.sampler import InfiniteSampler from torch.optim import AdamW from mmagic.datasets.dreambooth_dataset import DreamBoothDataset from mmagic.datasets.transforms.aug_shape import Resize from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile from mmagic.engine import VisualizationHook from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.editors.disco_diffusion.clip_wrapper import ClipWrapper from mmagic.models.editors.dreambooth import DreamBooth # config for model stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] model = dict( type=DreamBooth, vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', from_pretrained=stable_diffusion_v15_url, subfolder='unet', ), text_encoder=dict( type=ClipWrapper, clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, finetune_text_encoder=True, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type=DataPreprocessor), val_prompts=val_prompts) train_cfg = dict(max_iters=1000) optim_wrapper.update( modules='.*unet', optimizer=dict(type=AdamW, lr=5e-6), accumulative_counts=4 # batch size = 4 * 1 = 4 ) pipeline = [ dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=Resize, scale=(512, 512)), dict(type=PackInputs) ] dataset = dict( type=DreamBoothDataset, data_root='./data/dreambooth', concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type=InfiniteSampler, shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks.update(dict(logger=dict(interval=10))) custom_hooks = [ dict( type=VisualizationHook, interval=50, fixed_input=True, vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: mmagic/configs/dreambooth/dreambooth-prior_pre.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .dreambooth import * # config for model model.update(dict(prior_loss_weight=1, class_prior_prompt='a dog')) ================================================ FILE: mmagic/configs/dreambooth/dreambooth.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.gen_default_runtime import * from mmengine.dataset.sampler import InfiniteSampler from torch.optim import AdamW from mmagic.datasets.dreambooth_dataset import DreamBoothDataset from mmagic.datasets.transforms.aug_shape import Resize from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile from mmagic.engine import VisualizationHook from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.editors.disco_diffusion.clip_wrapper import ClipWrapper from mmagic.models.editors.dreambooth import DreamBooth stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] model = dict( type=DreamBooth, vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', from_pretrained=stable_diffusion_v15_url, subfolder='unet', ), text_encoder=dict( type=ClipWrapper, clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type=DataPreprocessor), val_prompts=val_prompts) train_cfg = dict(max_iters=1000) optim_wrapper.update( modules='.*unet', optimizer=dict(type=AdamW, lr=5e-6), accumulative_counts=4 # batch size = 4 * 1 = 4 ) pipeline = [ dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=Resize, scale=(512, 512)), dict(type=PackInputs) ] dataset = dict( type=DreamBoothDataset, data_root='./data/dreambooth', concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type=InfiniteSampler, shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks.update(dict(logger=dict(interval=10))) custom_hooks = [ dict( type=VisualizationHook, interval=50, fixed_input=True, vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: mmagic/configs/dreambooth/dreambooth_lora-prior_pre.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .dreambooth_lora import * model.update(dict(prior_loss_weight=1, class_prior_prompt='a dog')) ================================================ FILE: mmagic/configs/dreambooth/dreambooth_lora.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.gen_default_runtime import * from mmengine.dataset.sampler import InfiniteSampler from torch.optim import AdamW from mmagic.datasets.dreambooth_dataset import DreamBoothDataset from mmagic.datasets.transforms.aug_shape import Resize from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile from mmagic.engine import VisualizationHook from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.editors.disco_diffusion.clip_wrapper import ClipWrapper from mmagic.models.editors.dreambooth import DreamBooth stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' val_prompts = [ 'a sks dog in basket', 'a sks dog on the mountain', 'a sks dog beside a swimming pool', 'a sks dog on the desk', 'a sleeping sks dog', 'a screaming sks dog', 'a man in the garden' ] lora_config = dict(target_modules=['to_q', 'to_k', 'to_v']) model = dict( type=DreamBooth, vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet2DConditionModel', from_pretrained=stable_diffusion_v15_url, subfolder='unet', ), text_encoder=dict( type=ClipWrapper, clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_v15_url, subfolder='scheduler'), data_preprocessor=dict(type=DataPreprocessor), prior_loss_weight=0, val_prompts=val_prompts, lora_config=lora_config) train_cfg = dict(max_iters=1000) optim_wrapper = dict( # Only optimize LoRA mappings modules='.*.lora_mapping', # NOTE: lr should be larger than dreambooth finetuning optimizer=dict(type=AdamW, lr=5e-4), accumulative_counts=1) pipeline = [ dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=Resize, scale=(512, 512)), dict(type=PackInputs) ] dataset = dict( type=DreamBoothDataset, data_root='./data/dreambooth', # TODO: rename to instance concept_dir='imgs', prompt='a photo of sks dog', pipeline=pipeline) train_dataloader = dict( dataset=dataset, num_workers=16, sampler=dict(type=InfiniteSampler, shuffle=True), persistent_workers=True, batch_size=1) val_cfg = val_evaluator = val_dataloader = None test_cfg = test_evaluator = test_dataloader = None # hooks default_hooks.update(dict(logger=dict(interval=10))) custom_hooks = [ dict( type=VisualizationHook, interval=50, fixed_input=True, vis_kwargs_list=dict(type='Data', name='fake_img'), n_samples=1) ] ================================================ FILE: mmagic/configs/eg3d/eg3d_cvt-official-rgb_afhq-512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/config.html#a-pure-python-style-configuration-file-beta for more details. # noqa # mmcv >= 2.0.1 # mmengine >= 0.8.0 from mmengine.config import read_base from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicConditionalDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.eg3d import EG3D, GaussianCamera, TriplaneGenerator with read_base(): from .._base_.gen_default_runtime import * model = dict( type=EG3D, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=TriplaneGenerator, out_size=512, triplane_channels=32, triplane_size=256, num_mlps=2, sr_add_noise=False, sr_in_size=128, neural_rendering_resolution=128, renderer_cfg=dict( ray_start=2.25, ray_end=3.3, box_warp=1, depth_resolution=48, depth_resolution_importance=48, white_back=False, ), rgb2bgr=True), camera=dict( type=GaussianCamera, horizontal_mean=3.14 / 2, horizontal_std=0.35, vertical_mean=3.14 / 2 - 0.05, vertical_std=0.25, radius=2.7, fov=18.837, look_at=[0, 0, 0.2])) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_afhq.pkl' metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type=FrechetInceptionDistance, prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig') ] test_pipeline = [ dict(type=LoadImageFromFile, key='img', color_type='color'), dict(type=PackInputs) ] test_dataset = dict( type=BasicConditionalDataset, data_root='./data/eg3d/afhq', ann_file='afhq.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 4` cost nearly **9.5GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: mmagic/configs/eg3d/eg3d_cvt-official-rgb_ffhq-512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/config.html#a-pure-python-style-configuration-file-beta for more details. # noqa # mmcv >= 2.0.1 # mmengine >= 0.8.0 from mmengine.config import read_base from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicConditionalDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.eg3d import EG3D, GaussianCamera, TriplaneGenerator with read_base(): from .._base_.gen_default_runtime import * model = dict( type=EG3D, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=TriplaneGenerator, out_size=512, triplane_channels=32, triplane_size=256, num_mlps=2, neural_rendering_resolution=128, sr_add_noise=False, sr_in_size=128, # NOTE: double hidden channels and out channels for FFHQ-512 sr_hidden_channels=256, sr_out_channels=128, renderer_cfg=dict( ray_start=2.25, ray_end=3.3, box_warp=1, depth_resolution=48, depth_resolution_importance=48, white_back=False, ), rgb2bgr=True), camera=dict( type=GaussianCamera, horizontal_mean=3.14 / 2, horizontal_std=0.35, vertical_mean=3.14 / 2 - 0.05, vertical_std=0.25, radius=2.7, fov=18.837, look_at=[0, 0, 0.2])) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_ffhq_512.pkl' metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type=FrechetInceptionDistance, prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig') ] test_pipeline = [ dict(type=LoadImageFromFile, key='img', color_type='color'), dict(type=PackInputs) ] test_dataset = dict( type=BasicConditionalDataset, data_root='./data/eg3d/ffhq_512', ann_file='ffhq_512.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 4` cost nearly **9.5GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=4, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: mmagic/configs/eg3d/eg3d_cvt-official-rgb_shapenet-128x128.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/config.html#a-pure-python-style-configuration-file-beta for more details. # noqa # mmcv >= 2.0.1 # mmengine >= 0.8.0 from mmengine.config import read_base from mmengine.dataset import DefaultSampler from mmagic.datasets import BasicConditionalDataset from mmagic.datasets.transforms import LoadImageFromFile, PackInputs from mmagic.engine import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors.eg3d import EG3D, TriplaneGenerator, UniformCamera with read_base(): from .._base_.gen_default_runtime import * model = dict( type=EG3D, data_preprocessor=dict(type=DataPreprocessor), generator=dict( type=TriplaneGenerator, out_size=128, zero_cond_input=True, cond_scale=0, sr_in_size=64, renderer_cfg=dict( # Official implementation set ray_start, ray_end and box_warp as # 0.1, 2.6 and 1.6 respectively, and FID is 7.2441 # ray_start=0.1, # ray_end=2.6, # box_warp=1.6, ray_start=0.4, ray_end=2.0, box_warp=1.7, depth_resolution=64, depth_resolution_importance=64, white_back=True, ), rgb2bgr=True), camera=dict( type=UniformCamera, horizontal_mean=3.141, horizontal_std=3.141, vertical_mean=3.141 / 2, vertical_std=3.141 / 2, focal=1.025390625, up=[0, 0, 1], radius=1.2), ) train_cfg = train_dataloader = optim_wrapper = None val_cfg = val_dataloader = val_evaluator = None inception_pkl = './work_dirs/inception_pkl/eg3d_shapenet.pkl' metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full', fake_nums=50000, inception_pkl=inception_pkl, need_cond_input=True, sample_model='orig'), dict( type=FrechetInceptionDistance, prefix='FID-Random-Camera', fake_nums=50000, inception_pkl=inception_pkl, sample_model='orig'), ] test_pipeline = [ dict(type=LoadImageFromFile, key='img', color_type='color'), dict(type=PackInputs) ] test_dataset = dict( type=BasicConditionalDataset, data_root='./data/eg3d/shapenet-car', ann_file='shapenet.json', pipeline=test_pipeline) test_dataloader = dict( # NOTE: `batch_size = 16` cost nearly **12GB** of GPU memory, # modification this param by yourself corresponding to your own GPU. batch_size=16, persistent_workers=False, drop_last=False, sampler=dict(type=DefaultSampler, shuffle=False), num_workers=9, dataset=test_dataset) test_evaluator = dict(metrics=metrics) custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, # save_at_test=False, vis_kwargs_list=dict(type='GAN', name='fake_img')) ] ================================================ FILE: mmagic/configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .adm_ddim250_8xb32_imagenet_256x256 import * from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.editors.guided_diffusion.classifier import EncoderUNetModel model.update( dict( classifier=dict( type=EncoderUNetModel, image_size=256, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=2, attention_resolutions=(8, 16, 32), channel_mult=(1, 1, 2, 2, 4, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention'))) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet_512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .adm_ddim250_8xb32_imagenet_512x512 import * from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.editors.guided_diffusion.classifier import EncoderUNetModel model.update( dict( classifier=dict( type=EncoderUNetModel, image_size=512, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=2, attention_resolutions=(16, 32, 64), channel_mult=(0.5, 1, 1, 2, 2, 4, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention'))) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/guided_diffusion/adm-g_ddim25_8xb32_imagenet_64x64.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .adm_ddim250_8xb32_imagenet_64x64 import * from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.editors.guided_diffusion.classifier import EncoderUNetModel model.update( dict( classifier=dict( type=EncoderUNetModel, image_size=64, in_channels=3, model_channels=128, out_channels=1000, num_res_blocks=4, attention_resolutions=(2, 4, 8), channel_mult=(1, 2, 3, 4), use_fp16=False, num_head_channels=64, use_scale_shift_norm=True, resblock_updown=True, pool='attention'))) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/guided_diffusion/adm_ddim250_8xb32_imagenet_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.imagenet_64 import * from .._base_.gen_default_runtime import * from mmagic.engine.hooks.visualization_hook import VisualizationHook from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.diffusion_schedulers.ddim_scheduler import EditDDIMScheduler from mmagic.models.editors.ddpm.denoising_unet import (DenoisingUnet, MultiHeadAttentionBlock) from mmagic.models.editors.guided_diffusion.adm import AblatedDiffusionModel model = dict( type=AblatedDiffusionModel, data_preprocessor=dict(type=DataPreprocessor), unet=dict( type=DenoisingUnet, image_size=256, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type=MultiHeadAttentionBlock, num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True), diffusion_scheduler=dict( type=EditDDIMScheduler, variance_type='learned_range', beta_schedule='linear'), rgb2bgr=True, use_fp16=False) test_dataloader.update(dict(batch_size=32, num_workers=8)) train_cfg = dict(max_iters=100000) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) # VIS_HOOK custom_hooks = [dict(type=VisualizationHook, interval=5000, fixed_input=True)] ================================================ FILE: mmagic/configs/guided_diffusion/adm_ddim250_8xb32_imagenet_512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.imagenet_512 import * from .._base_.gen_default_runtime import * from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.diffusion_schedulers.ddim_scheduler import EditDDIMScheduler from mmagic.models.editors.ddpm.denoising_unet import (DenoisingUnet, MultiHeadAttentionBlock) from mmagic.models.editors.guided_diffusion import AblatedDiffusionModel model = dict( type=AblatedDiffusionModel, data_preprocessor=dict(type=DataPreprocessor), unet=dict( type=DenoisingUnet, image_size=512, in_channels=3, base_channels=256, resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type=MultiHeadAttentionBlock, num_heads=4, num_head_channels=64, use_new_attention_order=False), use_scale_shift_norm=True), diffusion_scheduler=dict( type=EditDDIMScheduler, variance_type='learned_range', beta_schedule='linear'), rgb2bgr=True, use_fp16=False) test_dataloader.update(dict(batch_size=32, num_workers=8)) train_cfg = dict(max_iters=100000) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/guided_diffusion/adm_ddim250_8xb32_imagenet_64x64.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.imagenet_64 import * from .._base_.gen_default_runtime import * from mmagic.evaluation.metrics import FrechetInceptionDistance from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.diffusion_schedulers.ddim_scheduler import EditDDIMScheduler from mmagic.models.editors.ddpm.denoising_unet import (DenoisingUnet, MultiHeadAttentionBlock) from mmagic.models.editors.guided_diffusion import AblatedDiffusionModel model = dict( type=AblatedDiffusionModel, data_preprocessor=dict(type=DataPreprocessor), unet=dict( type=DenoisingUnet, image_size=64, in_channels=3, base_channels=192, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type=MultiHeadAttentionBlock, num_heads=4, num_head_channels=64, use_new_attention_order=True), use_scale_shift_norm=True), diffusion_scheduler=dict( type=EditDDIMScheduler, variance_type='learned_range', beta_schedule='squaredcos_cap_v2'), rgb2bgr=True, use_fp16=False) test_dataloader.update(dict(batch_size=32, num_workers=8)) train_cfg = dict(max_iters=100000) metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='orig', sample_kwargs=dict( num_inference_steps=250, show_progress=True, classifier_scale=1.)) ] val_evaluator = dict(metrics=metrics) test_evaluator = dict(metrics=metrics) ================================================ FILE: mmagic/configs/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.nn.modules import HuberLoss from mmagic.datasets.transforms.aug_shape import Resize from mmagic.datasets.transforms.crop import InstanceCrop from mmagic.datasets.transforms.formatting import PackInputs from mmagic.datasets.transforms.loading import LoadImageFromFile from mmagic.models.data_preprocessors.data_preprocessor import DataPreprocessor from mmagic.models.editors.inst_colorization.colorization_net import \ ColorizationNet from mmagic.models.editors.inst_colorization.fusion_net import FusionNet from mmagic.models.editors.inst_colorization.inst_colorization import \ InstColorization with read_base(): from .._base_.default_runtime import * experiment_name = 'inst-colorization_full_official_cocostuff_256x256' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' stage = 'full' model = dict( type=InstColorization, data_preprocessor=dict( type=DataPreprocessor, mean=[127.5], std=[127.5], ), image_model=dict( type=ColorizationNet, input_nc=4, output_nc=2, norm_type='batch'), instance_model=dict( type=ColorizationNet, input_nc=4, output_nc=2, norm_type='batch'), fusion_model=dict( type=FusionNet, input_nc=4, output_nc=2, norm_type='batch'), color_data_opt=dict( ab_thresh=0, p=1.0, sample_PS=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, ], ab_norm=110, ab_max=110., ab_quant=10., l_norm=100., l_cent=50., mask_cent=0.5), which_direction='AtoB', loss=dict(type=HuberLoss, delta=.01)) # yapf: disable test_pipeline = [ dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict( type=InstanceCrop, config_file='mmdet::mask_rcnn/mask-rcnn_x101-32x8d_fpn_ms-poly-3x_coco.py', # noqa finesize=256, box_num_upbound=5), dict( type=Resize, keys=['img', 'cropped_img'], scale=(256, 256), keep_ratio=False), dict( type=PackInputs, data_keys=['box_info', 'box_info_2x', 'box_info_4x', 'box_info_8x']), ] ================================================ FILE: mmagic/configs/real_basicvsr/realbasicvsr_c64b20_1x30x8_8xb1_lr5e_5_150k_reds.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/config.html#a-pure-python-style-configuration-file-beta for more details. # noqa # mmcv >= 2.0.1 # mmengine >= 0.8.0 from mmengine.config import read_base from mmengine.optim.optimizer import OptimWrapper from mmengine.runner.loops import IterBasedTrainLoop from torch.optim.adam import Adam from mmagic.engine import MultiOptimWrapperConstructor from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors import (RealBasicVSR, RealBasicVSRNet, UNetDiscriminatorWithSpectralNorm) from mmagic.models.losses import GANLoss, L1Loss, PerceptualLoss with read_base(): from .realbasicvsr_wogan_c64b20_2x30x8_8xb2_lr1e_4_300k_reds import * experiment_name = 'realbasicvsr_c64b20-1x30x8_8xb1-lr5e-5-150k_reds' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' # load_from = 'https://download.openmmlab.com/mmediting/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds_20211027-0e2ff207.pth' # noqa scale = 4 # model settings model.update( dict( type=RealBasicVSR, generator=dict( type=RealBasicVSRNet, mid_channels=64, num_propagation_blocks=20, num_cleaning_blocks=20, dynamic_refine_thres=255, # change to 5 for test spynet_pretrained= 'https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', is_fix_cleaning=False, is_sequential_cleaning=False), discriminator=dict( type=UNetDiscriminatorWithSpectralNorm, in_channels=3, mid_channels=64, skip_connection=True), pixel_loss=dict(type=L1Loss, loss_weight=1.0, reduction='mean'), cleaning_loss=dict(type=L1Loss, loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type=PerceptualLoss, layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type=GANLoss, gan_type='vanilla', loss_weight=5e-2, real_label_val=1.0, fake_label_val=0), is_use_sharpened_gt_in_pixel=True, is_use_sharpened_gt_in_percep=True, is_use_sharpened_gt_in_gan=False, is_use_ema=True, data_preprocessor=dict( type=DataPreprocessor, mean=[0., 0., 0.], std=[255., 255., 255.], ))) # optimizer optim_wrapper.update( dict( _delete_=True, constructor=MultiOptimWrapperConstructor, generator=dict( type=OptimWrapper, optimizer=dict(type=Adam, lr=5e-5, betas=(0.9, 0.99))), discriminator=dict( type=OptimWrapper, optimizer=dict(type=Adam, lr=1e-4, betas=(0.9, 0.99))), )) train_cfg.update( dict(type=IterBasedTrainLoop, max_iters=150_000, val_interval=5000)) ================================================ FILE: mmagic/configs/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_8xb2_lr1e_4_300k_reds.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/config.html#a-pure-python-style-configuration-file-beta for more details. # noqa # mmcv >= 2.0.1 # mmengine >= 0.8.0 from mmengine.config import read_base from mmengine.dataset.sampler import DefaultSampler, InfiniteSampler from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, LoggerHook, ParamSchedulerHook) from mmengine.optim.optimizer.optimizer_wrapper import OptimWrapper from mmengine.runner.loops import IterBasedTrainLoop from torch.optim.adam import Adam from mmagic.datasets import BasicFramesDataset from mmagic.datasets.transforms import (Clip, CopyValues, DegradationsWithShuffle, FixedCrop, Flip, GenerateSegmentIndices, LoadImageFromFile, MirrorSequence, PackInputs, RandomBlur, RandomJPEGCompression, RandomNoise, RandomResize, RandomTransposeHW, RandomVideoCompression, SetValues, UnsharpMasking) from mmagic.engine import MultiOptimWrapperConstructor from mmagic.engine.hooks import (BasicVisualizationHook, ExponentialMovingAverageHook, IterTimerHook) from mmagic.evaluation import Evaluator from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors import RealBasicVSR, RealBasicVSRNet from mmagic.models.losses import L1Loss with read_base(): from .._base_.default_runtime import * experiment_name = 'realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds' work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' scale = 4 # model settings model = dict( type=RealBasicVSR, generator=dict( type=RealBasicVSRNet, mid_channels=64, num_propagation_blocks=20, num_cleaning_blocks=20, dynamic_refine_thres=255, # change to 1.5 for test spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/' 'basicvsr/spynet_20210409-c6c1bd09.pth', is_fix_cleaning=False, is_sequential_cleaning=False), pixel_loss=dict(type=L1Loss, loss_weight=1.0, reduction='mean'), cleaning_loss=dict(type=L1Loss, loss_weight=1.0, reduction='mean'), is_use_sharpened_gt_in_pixel=True, is_use_ema=True, data_preprocessor=dict( type=DataPreprocessor, mean=[0., 0., 0.], std=[255., 255., 255.], )) train_pipeline = [ dict(type=GenerateSegmentIndices, interval_list=[1]), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=SetValues, dictionary=dict(scale=scale)), dict(type=FixedCrop, keys=['gt'], crop_size=(256, 256)), dict(type=Flip, keys=['gt'], flip_ratio=0.5, direction='horizontal'), dict(type=Flip, keys=['gt'], flip_ratio=0.5, direction='vertical'), dict(type=RandomTransposeHW, keys=['gt'], transpose_ratio=0.5), dict(type=MirrorSequence, keys=['gt']), dict( type=UnsharpMasking, keys=['gt'], kernel_size=51, sigma=0, weight=0.5, threshold=10), dict(type=CopyValues, src_keys=['gt_unsharp'], dst_keys=['img']), dict( type=RandomBlur, params=dict( kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 3], sigma_y=[0.2, 3], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2], sigma_x_step=0.02, sigma_y_step=0.02, rotate_angle_step=0.31416, beta_gaussian_step=0.05, beta_plateau_step=0.1, omega_step=0.0628), keys=['img'], ), dict( type=RandomResize, params=dict( resize_mode_prob=[0.2, 0.7, 0.1], # up, down, keep resize_scale=[0.15, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3.0, 1 / 3.0, 1 / 3.0], resize_step=0.015, is_size_even=True), keys=['img'], ), dict( type=RandomNoise, params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 30], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 3], poisson_gray_noise_prob=0.4, gaussian_sigma_step=0.1, poisson_scale_step=0.005), keys=['img'], ), dict( type=RandomJPEGCompression, params=dict(quality=[30, 95], quality_step=3), keys=['img'], ), dict( type=RandomVideoCompression, params=dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5]), keys=['img'], ), dict( type=RandomBlur, params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=[ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ], kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1], sigma_x=[0.2, 1.5], sigma_y=[0.2, 1.5], rotate_angle=[-3.1416, 3.1416], beta_gaussian=[0.5, 4], beta_plateau=[1, 2], sigma_x_step=0.02, sigma_y_step=0.02, rotate_angle_step=0.31416, beta_gaussian_step=0.05, beta_plateau_step=0.1, omega_step=0.0628), keys=['img'], ), dict( type=RandomResize, params=dict( resize_mode_prob=[0.3, 0.4, 0.3], # up, down, keep resize_scale=[0.3, 1.2], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], resize_step=0.03, is_size_even=True), keys=['img'], ), dict( type=RandomNoise, params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.5, 0.5], gaussian_sigma=[1, 25], gaussian_gray_noise_prob=0.4, poisson_scale=[0.05, 2.5], poisson_gray_noise_prob=0.4, gaussian_sigma_step=0.1, poisson_scale_step=0.005), keys=['img'], ), dict( type=RandomJPEGCompression, params=dict(quality=[30, 95], quality_step=3), keys=['img'], ), dict( type=DegradationsWithShuffle, degradations=[ dict( type=RandomVideoCompression, params=dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5]), keys=['img'], ), [ dict( type=RandomResize, params=dict( target_size=(64, 64), resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), ), dict( type=RandomBlur, params=dict( prob=0.8, kernel_size=[7, 9, 11, 13, 15, 17, 19, 21], kernel_list=['sinc'], kernel_prob=[1], omega=[3.1416 / 3, 3.1416], omega_step=0.0628), ), ] ], keys=['img'], ), dict(type=Clip, keys=['img']), dict(type=PackInputs) ] val_pipeline = [ dict( type=GenerateSegmentIndices, interval_list=[1], filename_tmpl='{:04d}.png'), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=PackInputs) ] test_pipeline = [ dict( type=GenerateSegmentIndices, interval_list=[1], filename_tmpl='{:08d}.png'), dict(type=LoadImageFromFile, key='gt', channel_order='rgb'), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=PackInputs) ] demo_pipeline = [ dict(type=GenerateSegmentIndices, interval_list=[1]), dict(type=LoadImageFromFile, key='img', channel_order='rgb'), dict(type=PackInputs) ] data_root = 'data' train_dataloader = dict( num_workers=10, batch_size=2, persistent_workers=False, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='reds', task_name='vsr'), data_root=f'{data_root}/REDS', data_prefix=dict(img='train_sharp_sub', gt='train_sharp_sub'), depth=1, num_input_frames=15, pipeline=train_pipeline)) val_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='udm10', task_name='vsr'), data_root=f'{data_root}/UDM10', data_prefix=dict(img='BIx4', gt='GT'), pipeline=val_pipeline)) test_dataloader = dict( num_workers=1, batch_size=1, persistent_workers=False, sampler=dict(type=DefaultSampler, shuffle=False), dataset=dict( type=BasicFramesDataset, metainfo=dict(dataset_type='video_lq', task_name='vsr'), data_root=f'{data_root}/VideoLQ', data_prefix=dict(img='', gt=''), pipeline=test_pipeline)) val_evaluator = dict( type=Evaluator, metrics=[ dict(type='PSNR'), dict(type='SSIM'), ]) test_evaluator = dict( type=Evaluator, metrics=[dict(type='NIQE', input_order='CHW', convert_to='Y')]) train_cfg = dict(type=IterBasedTrainLoop, max_iters=300_000, val_interval=5000) # optimizer optim_wrapper = dict( constructor=MultiOptimWrapperConstructor, generator=dict( type=OptimWrapper, optimizer=dict(type=Adam, lr=1e-4, betas=(0.9, 0.99)))) # NO learning policy default_hooks = dict( checkpoint=dict( type=CheckpointHook, interval=5000, save_optimizer=True, out_dir=save_dir, max_keep_ckpts=10, save_best='PSNR', rule='greater', by_epoch=False), timer=dict(type=IterTimerHook), logger=dict(type=LoggerHook, interval=100), param_scheduler=dict(type=ParamSchedulerHook), sampler_seed=dict(type=DistSamplerSeedHook), ) custom_hooks = [ dict(type=BasicVisualizationHook, interval=5), dict( type=ExponentialMovingAverageHook, module_keys=('generator_ema'), interval=1, interp_cfg=dict(momentum=0.001), ) ] ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_800kiters_ffhq_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.optim import Adam from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.datasets.ffhq_flip import * # noqa: F403,F405 from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg.update(max_iters=800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/ffhq/ffhq_imgs/ffhq_256' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_800kiters_lsun_cat_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.optim import Adam from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.datasets.lsun_stylegan import * # noqa: F403,F405 from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg.update(max_iters=800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-cat' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_800kiters_lsun_church_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.optim import Adam from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.datasets.lsun_stylegan import * # noqa: F403,F405 from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg.update(max_iters=800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-church' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_800kiters_lsun_horse_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.optim import Adam from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.datasets.lsun_stylegan import * # noqa: F403,F405 from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=256), discriminator=dict(in_size=256), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg.update(max_iters=800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/lsun-horse' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_ffhq_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from torch.optim import Adam from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.datasets.ffhq_flip import * # noqa: F403,F405 from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=1024), discriminator=dict(in_size=1024), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) extra_parameters = dict(num_batches=1, sample_model='orig') train_cfg.update(max_iters=800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = './data/ffhq/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_8xb4_lsun_car_384x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmengine.dataset import DefaultSampler, InfiniteSampler from torch.optim import Adam from mmagic.datasets.transforms import (Flip, LoadImageFromFile, NumpyPad, PackInputs) from mmagic.engine import VisualizationHook from mmagic.evaluation import (FrechetInceptionDistance, PerceptualPathLength, PrecisionAndRecall) from mmagic.models import BaseGAN with read_base(): from .._base_.gen_default_runtime import * # noqa: F403,F405 from .._base_.models.base_styleganv2 import * # noqa: F403,F405 # reg params d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) ema_half_life = 10. # G_smoothing_kimg model.update( generator=dict(out_size=512), discriminator=dict(in_size=512), ema_config=dict( type=ExponentialMovingAverage, interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))), loss_config=dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2)) train_cfg.update(max_iters=1800002) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.002 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # DATA batch_size = 4 data_root = './data/lsun/images/car' dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type=LoadImageFromFile, key='gt'), dict( type=NumpyPad, keys='img', padding=((64, 64), (0, 0), (0, 0)), ), dict(type=Flip, keys=['gt'], direction='horizontal'), dict(type=PackInputs) ] val_pipeline = train_pipeline # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type=InfiniteSampler, shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, pipeline=train_pipeline)) val_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_root=data_root, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) test_dataloader = dict( batch_size=4, num_workers=8, dataset=dict( type=dataset_type, data_root=data_root, # set by user pipeline=val_pipeline), sampler=dict(type=DefaultSampler, shuffle=False), persistent_workers=True) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-50k', fake_nums=50000, real_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict(type=PrecisionAndRecall, fake_nums=50000, prefix='PR-50K'), dict(type=PerceptualPathLength, fake_nums=50000, prefix='ppl-w') ] # NOTE: config for save multi best checkpoints # default_hooks.update( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_PL_8xb4_fp16_partial_GD_no_scaler_800kiters_ffhq_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmengine.optim import AmpOptimWrapper with read_base(): from mmagic.configs.styleganv2.stylegan2_c2_8xb4_800kiters_ffhq_256x256 import * model.update( generator=dict(out_size=256, num_fp16_scales=4), discriminator=dict(in_size=256, num_fp16_scales=4), loss_config=dict(scale_r1_loss=True)) optim_wrapper.update( generator=dict(type=AmpOptimWrapper, loss_scale=512), discriminator=dict(type=AmpOptimWrapper, loss_scale=512)) ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_PL_R1_8xb4_apex_fp16_no_scaler_800kiters_ffhq_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from mmagic.configs.styleganv2.stylegan2_c2_8xb4_800kiters_ffhq_256x256 import * model.update(loss_config=dict(r1_use_apex_amp=False, g_reg_use_apex_amp=False)) train_cfg.update(max_iters=800002) # remain to be refactored apex_amp = dict(mode='gan', init_args=dict(opt_level='O1', num_losses=2)) resume_from = None ================================================ FILE: mmagic/configs/styleganv2/stylegan2_c2_PL_R1_8xb4_fp16_globalG_partialD_no_scaler_800kiters_ffhq_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base from mmengine.optim import AmpOptimWrapper with read_base(): from mmagic.configs.styleganv2.stylegan2_c2_8xb4_800kiters_ffhq_256x256 import * model.update( generator=dict(out_size=256, fp16_enabled=True), discriminator=dict(in_size=256, fp16_enabled=False, num_fp16_scales=4), ) train_cfg.update(max_iters=800000) optim_wrapper.update( generator=dict(type=AmpOptimWrapper, loss_scale=512), discriminator=dict(type=AmpOptimWrapper, loss_scale=512)) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_r_ada_gamma33_8xb4_fp16_metfaces_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.ffhq_flip import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from torch.optim import Adam from mmagic.engine.hooks.visualization_hook import VisualizationHook from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.base_models.average_model import ExponentialMovingAverage from mmagic.models.base_models.base_gan import BaseGAN from mmagic.models.editors.stylegan2.stylegan2_discriminator import ( ADAAug, ADAStyleGAN2Discriminator) # 模型的配置 from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } r1_gamma = 3.3 # set by user d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) load_from = 'https://download.openmmlab.com/mmediting/stylegan3/stylegan3_r_ffhq_1024_b4x8_cvt_official_rgb_20220329_234933-ac0500a1.pth' # noqa # ada settings aug_kwargs = { 'xflip': 1, 'rotate90': 1, 'xint': 1, 'scale': 1, 'rotate': 1, 'aniso': 1, 'xfrac': 1, 'brightness': 1, 'contrast': 1, 'lumaflip': 1, 'hue': 1, 'saturation': 1 } ema_half_life = 10. # G_smoothing_kimg ema_kimg = 10 ema_nimg = ema_kimg * 1000 ema_beta = 0.5**(32 / max(ema_nimg, 1e-8)) ema_config = dict( type=ExponentialMovingAverage, interval=1, momentum=ema_beta, start_iter=0) model.update( generator=dict( out_size=1024, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict( type=ADAStyleGAN2Discriminator, in_size=1024, input_bgr2rgb=True, data_aug=dict(type=ADAAug, aug_pipeline=aug_kwargs, ada_kimg=100)), loss_config=dict( r1_loss_weight=r1_gamma / 2.0 * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC'), ema_config=ema_config) # 优化配置 optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) # 数据集配置 batch_size = 4 data_root = 'data/metfaces/images/' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) # 训练配置 train_cfg.update(max_iters=160000) # VIS_HOOK hook配置 custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img')) ] # METRICS 评估配置 metrics = [ dict( type=FrechetInceptionDistance, # FID prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) # default_hooks = dict(checkpoint=dict(save_best='FID-Full-50k/fid')) # 只是加进去 default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_r_cvt_official_rgb_8xb4_ffhq_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.ffhq_flip import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan2.stylegan2_discriminator import \ StyleGAN2Discriminator from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } r1_gamma = 32.8 d_reg_interval = 16 model.update( generator=dict( out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg, rgb2bgr=True), discriminator=dict(type=StyleGAN2Discriminator, in_size=1024)) batch_size = 4 data_root = './data/ffhq/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_r_cvt_official_rgb_8xb4_ffhqu_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.unconditional_imgs_flip_lanczos_resize_256x256 \ import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 32768, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } model.update( generator=dict( out_size=256, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1)) batch_size = 4 data_root = './data/ffhqu/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_r_cvt_official_rgb_8xb4x8_afhqv2_512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.unconditional_imgs_flip_512x512 import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan2.stylegan2_discriminator import \ StyleGAN2Discriminator from mmagic.models.editors.stylegan3.stylegan3_generator import \ StyleGAN3Generator from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 65536, 'channel_max': 1024, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } model.update( generator=dict( type=StyleGAN3Generator, # 'StyleGANv3Generator',Registry里面用于区分别名 noise_size=512, style_channels=512, out_size=512, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(type=StyleGAN2Discriminator, in_size=512)) batch_size = 4 data_root = 'data/afhqv2/' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_ada_gamma66_8xb4_fp16_metfaces_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.ffhq_flip import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from torch.optim import Adam from mmagic.engine.hooks.visualization_hook import VisualizationHook from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.base_models.average_model import ExponentialMovingAverage from mmagic.models.base_models.base_gan import BaseGAN from mmagic.models.editors.stylegan2.stylegan2_discriminator import ( ADAAug, ADAStyleGAN2Discriminator) from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 6.6 # set by user d_reg_interval = 16 g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) load_from = 'https://download.openmmlab.com/mmediting/stylegan3/stylegan3_t_ffhq_1024_b4x8_cvt_official_rgb_20220329_235113-db6c6580.pth' # noqa # ada settings aug_kwargs = { 'xflip': 1, 'rotate90': 1, 'xint': 1, 'scale': 1, 'rotate': 1, 'aniso': 1, 'xfrac': 1, 'brightness': 1, 'contrast': 1, 'lumaflip': 1, 'hue': 1, 'saturation': 1 } ema_half_life = 10. # G_smoothing_kimg ema_kimg = 10 ema_nimg = ema_kimg * 1000 ema_beta = 0.5**(32 / max(ema_nimg, 1e-8)) ema_config = dict( type=ExponentialMovingAverage, interval=1, momentum=ema_beta, start_iter=0) model.update( generator=dict( out_size=1024, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict( type=ADAStyleGAN2Discriminator, in_size=1024, input_bgr2rgb=True, data_aug=dict(type=ADAAug, aug_pipeline=aug_kwargs, ada_kimg=100)), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/metfaces/images/' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg.update(max_iters=160000) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img') ) # vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_cvt_official_rgb_8xb4_afhqv2_512x512.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.unconditional_imgs_flip_512x512 import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model.update( generator=dict( out_size=512, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=512)) batch_size = 4 data_root = 'data/afhqv2/' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_cvt_official_rgb_8xb4_ffhq_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.ffhq_flip import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model.update( generator=dict( out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg, rgb2bgr=True), discriminator=dict(in_size=1024)) batch_size = 4 data_root = './data/ffhq/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_cvt_official_rgb_8xb4_ffhqu_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.unconditional_imgs_flip_lanczos_resize_256x256 import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * # synthesis network的配置(generator) from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 16384, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } model.update( generator=dict( out_size=256, img_channels=3, rgb2bgr=True, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1)) batch_size = 4 data_root = './data/ffhqu/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg = train_dataloader = optim_wrapper = None metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_gamma20_8xb4_fp16_noaug_ffhq_256x256.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.unconditional_imgs_flip_lanczos_resize_256x256 \ import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from torch.optim import Adam from mmagic.engine.hooks.visualization_hook import VisualizationHook from mmagic.evaluation.metrics.equivariance import Equivariance from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.base_models.average_model import RampUpEMA from mmagic.models.base_models.base_gan import BaseGAN from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 16384, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 2. # set by user d_reg_interval = 16 ema_config = dict( type=RampUpEMA, interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=32, eps=1e-8, start_iter=0) model.update( generator=dict(out_size=256, img_channels=3, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=256, channel_multiplier=1), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/ffhq/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg.update(max_iters=800002) custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img') ) # vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema'), dict( type=Equivariance, fake_nums=50000, sample_mode='ema', prefix='EQ', eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True)) ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/configs/styleganv3/stylegan3_t_gamma328_8xb4_fp16_noaug_ffhq_1024x1024.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.config import read_base with read_base(): from .._base_.datasets.ffhq_flip import * from .._base_.gen_default_runtime import * from .._base_.models.base_styleganv3 import * from torch.optim import Adam from mmagic.engine.hooks.visualization_hook import VisualizationHook from mmagic.evaluation.metrics.fid import FrechetInceptionDistance from mmagic.models.base_models.average_model import RampUpEMA from mmagic.models.base_models.base_gan import BaseGAN from mmagic.models.editors.stylegan3.stylegan3_modules import SynthesisNetwork batch_size = 32 magnitude_ema_beta = 0.5**(batch_size / (20 * 1e3)) synthesis_cfg = { 'type': SynthesisNetwork, 'channel_base': 32768, 'channel_max': 512, 'magnitude_ema_beta': 0.999 } r1_gamma = 32.8 d_reg_interval = 16 ema_config = dict( type=RampUpEMA, interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=batch_size, eps=1e-8, start_iter=0) model.update( generator=dict(out_size=1024, img_channels=3, synthesis_cfg=synthesis_cfg), discriminator=dict(in_size=1024), loss_config=dict(r1_loss_weight=r1_gamma / 2.0 * d_reg_interval), ema_config=ema_config) g_reg_interval = 4 g_reg_ratio = g_reg_interval / (g_reg_interval + 1) d_reg_ratio = d_reg_interval / (d_reg_interval + 1) optim_wrapper.update( generator=dict( optimizer=dict( type=Adam, lr=0.0025 * g_reg_ratio, betas=(0, 0.99**g_reg_ratio))), discriminator=dict( optimizer=dict( type=Adam, lr=0.002 * d_reg_ratio, betas=(0, 0.99**d_reg_ratio)))) batch_size = 4 data_root = 'data/ffhq/images' train_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) val_dataloader.update(batch_size=batch_size, dataset=dict(data_root=data_root)) test_dataloader.update( batch_size=batch_size, dataset=dict(data_root=data_root)) train_cfg.update(max_iters=800002) # VIS_HOOK custom_hooks = [ dict( type=VisualizationHook, interval=5000, fixed_input=True, vis_kwargs_list=dict(type=BaseGAN, name='fake_img') ) # vis_kwargs_list=dict(type='GAN', name='fake_img')) ] # METRICS metrics = [ dict( type=FrechetInceptionDistance, prefix='FID-Full-50k', fake_nums=50000, inception_style='StyleGAN', sample_model='ema') ] # NOTE: config for save multi best checkpoints # default_hooks = dict( # checkpoint=dict( # save_best=['FID-Full-50k/fid', 'IS-50k/is'], # rule=['less', 'greater'])) default_hooks.update(checkpoint=dict(save_best='FID-Full-50k/fid')) val_evaluator.update(metrics=metrics) test_evaluator.update(metrics=metrics) ================================================ FILE: mmagic/datasets/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .basic_conditional_dataset import BasicConditionalDataset from .basic_frames_dataset import BasicFramesDataset from .basic_image_dataset import BasicImageDataset from .cifar10_dataset import CIFAR10 from .comp1k_dataset import AdobeComp1kDataset from .controlnet_dataset import ControlNetDataset from .dreambooth_dataset import DreamBoothDataset from .grow_scale_image_dataset import GrowScaleImgDataset from .imagenet_dataset import ImageNet from .mscoco_dataset import MSCoCoDataset from .paired_image_dataset import PairedImageDataset from .singan_dataset import SinGANDataset from .textual_inversion_dataset import TextualInversionDataset from .unpaired_image_dataset import UnpairedImageDataset __all__ = [ 'AdobeComp1kDataset', 'BasicImageDataset', 'BasicFramesDataset', 'BasicConditionalDataset', 'UnpairedImageDataset', 'PairedImageDataset', 'ImageNet', 'CIFAR10', 'GrowScaleImgDataset', 'SinGANDataset', 'MSCoCoDataset', 'ControlNetDataset', 'DreamBoothDataset', 'ViCoDataset', 'ControlNetDataset', 'SDFinetuneDataset', 'TextualInversionDataset' ] ================================================ FILE: mmagic/datasets/basic_conditional_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Sequence, Union import mmengine import numpy as np from mmengine.dataset import BaseDataset from mmengine.fileio import get_file_backend from mmengine.logging import MMLogger from mmagic.registry import DATASETS from .data_utils import expanduser, find_folders, get_samples @DATASETS.register_module() class BasicConditionalDataset(BaseDataset): """Custom dataset for conditional GAN. This class is based on the combination of `BaseDataset` (https://github.com/open- mmlab/mmclassification/blob/main/mmcls/datasets/base_dataset.py) # noqa and `CustomDataset` (https://github.com/open- mmlab/mmclassification/blob/main/mmcls/datasets/custom.py). # noqa. The dataset supports two kinds of annotation format. 1. A annotation file read by line (e.g., txt) is provided, and each line indicates a sample: The sample files: :: data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... The annotation file (the first column is the image path and the second column is the index of category): :: folder_1/xxx.png 0 folder_1/xxy.png 1 folder_2/123.png 5 folder_2/nsdf3.png 3 ... Please specify the name of categories by the argument ``classes`` or ``metainfo``. 2. A dict-based annotation file (e.g., json) is provided, key and value indicate the path and label of the sample: The sample files: :: data_prefix/ ├── folder_1 │ ├── xxx.png │ ├── xxy.png │ └── ... └── folder_2 ├── 123.png ├── nsdf3.png └── ... The annotation file (the key is the image path and the value column is the label): :: { "folder_1/xxx.png": [1, 2, 3, 4], "folder_1/xxy.png": [2, 4, 1, 0], "folder_2/123.png": [0, 9, 8, 1], "folder_2/nsdf3.png", [1, 0, 0, 2], ... } In this kind of annotation, labels can be any type and not restricted to an index. 3. The samples are arranged in the specific way: :: data_prefix/ ├── class_x │ ├── xxx.png │ ├── xxy.png │ └── ... │ └── xxz.png └── class_y ├── 123.png ├── nsdf3.png ├── ... └── asd932_.png If the ``ann_file`` is specified, the dataset will be generated by the first two ways, otherwise, try the third way. Args: ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str): The root directory for ``data_prefix`` and ``ann_file``. Defaults to ''. data_prefix (str | dict): Prefix for the data. Defaults to ''. extensions (Sequence[str]): A sequence of allowed extensions. Defaults to ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif'). lazy_init (bool): Whether to load annotation during instantiation. In some cases, such as visualization, only the meta information of the dataset is needed, which is not necessary to load annotation file. ``Basedataset`` can skip load annotations to save time by set ``lazy_init=False``. Defaults to False. **kwargs: Other keyword arguments in :class:`BaseDataset`. """ def __init__(self, ann_file: str = '', metainfo: Optional[dict] = None, data_root: str = '', data_prefix: Union[str, dict] = '', extensions: Sequence[str] = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif'), lazy_init: bool = False, classes: Union[str, Sequence[str], None] = None, **kwargs): assert (ann_file or data_prefix or data_root), \ 'One of `ann_file`, `data_root` and `data_prefix` must '\ 'be specified.' if isinstance(data_prefix, str): data_prefix = dict(gt_path=expanduser(data_prefix)) ann_file = expanduser(ann_file) metainfo = self._compat_classes(metainfo, classes) self.extensions = tuple(set([i.lower() for i in extensions])) super().__init__( # The base class requires string ann_file but this class doesn't ann_file=ann_file, metainfo=metainfo, data_root=data_root, data_prefix=data_prefix, # Force to lazy_init for some modification before loading data. lazy_init=True, **kwargs) # Full initialize the dataset. if not lazy_init: self.full_init() def _find_samples(self, file_backend): """find samples from ``data_prefix``.""" classes, folder_to_idx = find_folders(self.img_prefix, file_backend) samples, empty_classes = get_samples( self.img_prefix, folder_to_idx, is_valid_file=self.is_valid_file, file_backend=file_backend, ) if len(samples) == 0: raise RuntimeError( f'Found 0 files in subfolders of: {self.data_prefix}. ' f'Supported extensions are: {",".join(self.extensions)}') if self.CLASSES is not None: assert len(self.CLASSES) == len(classes), \ f"The number of subfolders ({len(classes)}) doesn't match " \ f'the number of specified classes ({len(self.CLASSES)}). ' \ 'Please check the data folder.' else: self._metainfo['classes'] = tuple(classes) if empty_classes: logger = MMLogger.get_current_instance() logger.warning( 'Found no valid file in the folder ' f'{", ".join(empty_classes)}. ' f"Supported extensions are: {', '.join(self.extensions)}") self.folder_to_idx = folder_to_idx return samples def load_data_list(self): """Load image paths and gt_labels.""" if self.img_prefix: file_backend = get_file_backend(uri=self.img_prefix) if not self.ann_file: samples = self._find_samples(file_backend) elif self.ann_file.endswith('json'): samples = mmengine.fileio.io.load(self.ann_file) samples = [[name, label] for name, label in samples.items()] elif self.ann_file.endswith('txt'): lines = mmengine.list_from_file(self.ann_file) samples = [x.strip().rsplit(' ', 1) for x in lines] else: raise TypeError('Only support \'json\' and \'txt\' as annotation.') def add_prefix(filename, prefix=''): if not prefix: return filename else: return file_backend.join_path(prefix, filename) data_list = [] for filename, gt_label in samples: img_path = add_prefix(filename, self.img_prefix) # convert digit label to int if isinstance(gt_label, str): gt_label = int(gt_label) if gt_label.isdigit() else gt_label info = {'gt_path': img_path, 'gt_label': gt_label} data_list.append(info) return data_list def is_valid_file(self, filename: str) -> bool: """Check if a file is a valid sample.""" return filename.lower().endswith(self.extensions) @property def img_prefix(self): """The prefix of images.""" return self.data_prefix['gt_path'] @property def CLASSES(self): """Return all categories names.""" return self._metainfo.get('classes', None) @property def class_to_idx(self): """Map mapping class name to class index. Returns: dict: mapping from class name to class index. """ return {cat: i for i, cat in enumerate(self.CLASSES)} def get_gt_labels(self): """Get all ground-truth labels (categories). Returns: np.ndarray: categories for all images. """ gt_labels = np.array( [self.get_data_info(i)['gt_label'] for i in range(len(self))]) return gt_labels def get_cat_ids(self, idx: int) -> List[int]: """Get category id by index. Args: idx (int): Index of data. Returns: cat_ids (List[int]): Image category of specified index. """ return [int(self.get_data_info(idx)['gt_label'])] def _compat_classes(self, metainfo, classes): """Merge the old style ``classes`` arguments to ``metainfo``.""" if isinstance(classes, str): # take it as a file path class_names = mmengine.list_from_file(expanduser(classes)) elif isinstance(classes, (tuple, list)): class_names = classes elif classes is not None: raise ValueError(f'Unsupported type {type(classes)} of classes.') if metainfo is None: metainfo = {} if classes is not None: metainfo = {'classes': tuple(class_names), **metainfo} return metainfo def full_init(self): """Load annotation file and set ``BaseDataset._fully_initialized`` to True.""" super().full_init() # To support the standard OpenMMLab 2.0 annotation format. Generate # metainfo in internal format from standard metainfo format. if 'categories' in self._metainfo and 'classes' not in self._metainfo: categories = sorted( self._metainfo['categories'], key=lambda x: x['id']) self._metainfo['classes'] = tuple( [cat['category_name'] for cat in categories]) def __repr__(self): """Print the basic information of the dataset. Returns: str: Formatted string. """ head = 'Dataset ' + self.__class__.__name__ body = [] if self._fully_initialized: body.append(f'Number of samples: \t{self.__len__()}') else: body.append("Haven't been initialized") if self.CLASSES is not None: body.append(f'Number of categories: \t{len(self.CLASSES)}') else: body.append('The `CLASSES` meta info is not set.') body.extend(self.extra_repr()) if len(self.pipeline.transforms) > 0: body.append('With transforms:') for t in self.pipeline.transforms: body.append(f' {t}') lines = [head] + [' ' * 4 + line for line in body] return '\n'.join(lines) def extra_repr(self) -> List[str]: """The extra repr information of the dataset.""" body = [] body.append(f'Annotation file: \t{self.ann_file}') body.append(f'Prefix of images: \t{self.img_prefix}') return body ================================================ FILE: mmagic/datasets/basic_frames_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from typing import Callable, List, Optional, Union from mmengine.dataset import BaseDataset from mmengine.fileio import get_file_backend, list_from_file from ..registry import DATASETS @DATASETS.register_module() class BasicFramesDataset(BaseDataset): """BasicFramesDataset for open source projects in OpenMMLab/MMagic. This dataset is designed for low-level vision tasks with frames, such as video super-resolution and video frame interpolation. The annotation file is optional. If use annotation file, the annotation format can be shown as follows. .. code-block:: none Case 1 (Vid4): calendar 41 city 34 foliage 49 walk 47 Case 2 (REDS): 000/00000000.png (720, 1280, 3) 000/00000001.png (720, 1280, 3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) Args: ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str, optional): The root directory for ``data_prefix`` and ``ann_file``. Defaults to None. data_prefix (dict, optional): Prefix for training data. Defaults to dict(img='', gt=''). pipeline (list, optional): Processing pipeline. Defaults to []. test_mode (bool, optional): ``test_mode=True`` means in test phase. Defaults to False. filename_tmpl (str): Template for each filename. Note that the template excludes the file extension. Default: '{}'. search_key (str): The key used for searching the folder to get data_list. Default: 'gt'. backend_args (dict, optional): Arguments to instantiate the prefix of uri corresponding backend. Defaults to None. depth (int): The depth of path. Default: 1 num_input_frames (None | int): Number of input frames. Default: None. num_output_frames (None | int): Number of output frames. Default: None. fixed_seq_len (None | int): The fixed sequence length. If None, BasicFramesDataset will obtain the length of each sequence. Default: None. load_frames_list (dict): Load frames list for each key. Default: dict(). Examples: Assume the file structure as the following: mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── Vid4 │ │ ├── BIx4 │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── GT │ │ │ ├── city │ │ │ │ ├── img1.png │ │ ├── meta_info_Vid4_GT.txt │ ├── places │ │ ├── sequences | | | ├── 00001 │ │ │ │ ├── 0389 │ │ │ │ │ ├── img1.png │ │ │ │ │ ├── img2.png │ │ │ │ │ ├── img3.png │ │ ├── tri_trainlist.txt Case 1: Loading Vid4 dataset for training a VSR model. .. code-block:: python dataset = BasicFramesDataset( ann_file='meta_info_Vid4_GT.txt', metainfo=dict(dataset_type='vid4', task_name='vsr'), data_root='data/Vid4', data_prefix=dict(img='BIx4', gt='GT'), pipeline=[], depth=2, num_input_frames=5) Case 2: Loading Vimeo90k dataset for training a VFI model. .. code-block:: python dataset = BasicFramesDataset( ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root='data/vimeo-triplet', data_prefix=dict(img='sequences', gt='sequences'), pipeline=[], depth=2, load_frames_list=dict( img=['img1.png', 'img3.png'], gt=['img2.png'])) See more details in unittest tests/test_datasets/test_base_frames_dataset.py TestFramesDatasets().test_version_1_method() """ METAINFO = dict(dataset_type='base_edit_dataset', task_name='editing') def __init__(self, ann_file: str = '', metainfo: Optional[dict] = None, data_root: Optional[str] = None, data_prefix: dict = dict(img=''), pipeline: List[Union[dict, Callable]] = [], test_mode: bool = False, filename_tmpl: dict = dict(), search_key: Optional[str] = None, backend_args: Optional[dict] = None, depth: int = 1, num_input_frames: Optional[int] = None, num_output_frames: Optional[int] = None, fixed_seq_len: Optional[int] = None, load_frames_list: dict = dict(), **kwargs): for key in data_prefix: if key not in filename_tmpl: filename_tmpl[key] = '{}' if search_key is None: keys = list(data_prefix.keys()) search_key = keys[0] self.search_key = search_key self.filename_tmpl = filename_tmpl self.use_ann_file = (ann_file != '') if backend_args is None: self.backend_args = None else: self.backend_args = backend_args.copy() self.depth = depth self.seq_lens = dict(fixed_seq_len=fixed_seq_len) self.num_input_frames = num_input_frames self.num_output_frames = num_output_frames self.load_frames_list = load_frames_list self.file_backend = get_file_backend( uri=data_root, backend_args=backend_args) super().__init__( ann_file=ann_file, metainfo=metainfo, data_root=data_root, data_prefix=data_prefix, pipeline=pipeline, test_mode=test_mode, **kwargs) def load_data_list(self) -> List[dict]: """Load data list from folder or annotation file. Returns: list[dict]: A list of annotation. """ path_list = self._get_path_list() self._set_seq_lens() data_list = [] for path in path_list: basename, _ = osp.splitext(path) sequence_length = self.seq_lens['fixed_seq_len'] if sequence_length is None: sequence_length = self.seq_lens[path.split(os.sep)[0]] data = dict( key=basename, num_input_frames=self.num_input_frames, num_output_frames=self.num_output_frames, sequence_length=sequence_length) for key in self.data_prefix: if key in self.load_frames_list: folder = osp.join(self.data_prefix[key], path) data[f'{key}_path'] = self._get_frames_list(key, folder) # The list of frames has been loaded, # ``sequence_length`` is useless # Avoid loading frames by ``sequence_length`` in pipeline data['sequence_length'] = None # overwrite ``num_input_frames`` and ``num_output_frames`` if key == 'img': data['num_input_frames'] = len(data[f'{key}_path']) elif key == 'gt': data['num_output_frames'] = len(data[f'{key}_path']) else: data[f'{key}_path'] = self.data_prefix[key] data_list.append(data) return data_list def _get_path_list(self): """Get list of paths from annotation file or folder of dataset. Returns: list[str]: A list of paths. """ if self.use_ann_file: path_list = self._get_path_list_from_ann() else: path_list = self._get_path_list_from_folder(depth=self.depth) return path_list def _get_path_list_from_ann(self): """Get list of paths from annotation file. Returns: list[str]: A list of paths. """ ann_list = list_from_file( self.ann_file, backend_args=self.backend_args) path_list = [] for ann in ann_list: if ann.isspace() or ann == '': continue path = ann.split(' ')[0] # Compatible with Windows file systems path = path.replace('/', os.sep) splitted_path = path.split(os.sep) if self.seq_lens['fixed_seq_len'] is None: self.seq_lens[splitted_path[0]] = 0 ann_depth = len(splitted_path) if self.depth > ann_depth: # desire "folder/file", but the ann_file provides "folder". sub_path_list = self._get_path_list_from_folder( sub_folder=path, need_ext=False, depth=self.depth - ann_depth) path_list.extend( [path + os.sep + sub_path for sub_path in sub_path_list]) elif self.depth < ann_depth: # desire "folder", while the ann_file provides "folder/file". desire_path = f'{os.sep}'.join(splitted_path[:self.depth]) if desire_path not in path_list: path_list.append(desire_path) else: # desire "folder/file" and the ann_file provides "folder/file". # or desire "folder" and the ann_file provides "folder". path_list.append(path) return path_list def _get_path_list_from_folder(self, sub_folder=None, need_ext=True, depth=1): """Get list of paths from folder. Args: sub_folder (None | str): The path of sub_folder. Default: None. need_ext (bool): Whether need ext. Default: True. depth (int): Residual depth of path, recursively called to ``depth == 1``. Default: 1 Returns: list[str]: A list of paths. """ folder = self.data_prefix[self.search_key] tmpl = self.filename_tmpl[self.search_key].format('') path_list = [] if sub_folder: folder = osp.join(folder, sub_folder) listdir = list(self.file_backend.list_dir_or_file(dir_path=folder)) listdir.sort() for path in listdir: basename, ext = osp.splitext(path) if not (sub_folder or self.seq_lens['fixed_seq_len']): self.seq_lens[basename] = 0 if depth > 1: sub_path_list = self._get_path_list_from_folder( sub_folder=path) path_list.extend( [path + os.sep + sub_path for sub_path in sub_path_list]) elif basename.endswith(tmpl): if need_ext: path = path.replace(tmpl + ext, ext) else: path = path.replace(tmpl + ext, '') path_list.append(path) return path_list def _set_seq_lens(self): """Get sequence lengths.""" if self.seq_lens['fixed_seq_len']: return folder = self.data_prefix[self.search_key] for key in self.seq_lens.keys(): if key == 'fixed_seq_len': continue path = osp.join(folder, key) num_frames = len(list(self.file_backend.list_dir_or_file(path))) self.seq_lens[key] = num_frames def _get_frames_list(self, key, folder): """Obtain list of frames. Args: key (str): The key of frames list, e.g. ``img``, ``gt``. folder (str): Folder of frames. Return: list[str]: The paths list of frames. """ if 'all' in self.load_frames_list[key]: # load all files = list(self.file_backend.list_dir_or_file(dir_path=folder)) else: files = self.load_frames_list[key] files.sort() tmpl = self.filename_tmpl[key] files = [tmpl.format(file) for file in files] paths = [osp.join(folder, file) for file in files] return paths ================================================ FILE: mmagic/datasets/basic_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import re from typing import Callable, List, Optional, Tuple, Union from mmengine.dataset import BaseDataset from mmengine.fileio import get_file_backend, list_from_file from mmagic.registry import DATASETS IMG_EXTENSIONS = ('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tif', '.TIF', '.tiff', '.TIFF') @DATASETS.register_module() class BasicImageDataset(BaseDataset): """BasicImageDataset for open source projects in OpenMMLab/MMagic. This dataset is designed for low-level vision tasks with image, such as super-resolution and inpainting. The annotation file is optional. If use annotation file, the annotation format can be shown as follows. .. code-block:: none Case 1 (CelebA-HQ): 000001.png 000002.png Case 2 (DIV2K): 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) 0001_s003.png (480,480,3) 0002_s001.png (480,480,3) 0002_s002.png (480,480,3) Case 3 (Vimeo90k): 00001/0266 (256, 448, 3) 00001/0268 (256, 448, 3) Args: ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str, optional): The root directory for ``data_prefix`` and ``ann_file``. Defaults to None. data_prefix (dict, optional): Prefix for training data. Defaults to dict(img=None, ann=None). pipeline (list, optional): Processing pipeline. Defaults to []. test_mode (bool, optional): ``test_mode=True`` means in test phase. Defaults to False. filename_tmpl (dict): Template for each filename. Note that the template excludes the file extension. Default: dict(). search_key (str): The key used for searching the folder to get data_list. Default: 'gt'. backend_args (dict, optional): Arguments to instantiate the prefix of uri corresponding backend. Defaults to None. suffix (str or tuple[str], optional): File suffix that we are interested in. Default: None. recursive (bool): If set to True, recursively scan the directory. Default: False. Note: Assume the file structure as the following: .. code-block:: none mmagic (root) ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ │ ├── image.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ │ │ ├── image_x4.png │ │ ├── DIV2K_valid_HR │ │ ├── DIV2K_valid_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ ├── places │ │ ├── test_set │ │ ├── train_set | | ├── meta | | | ├── Places365_train.txt | | | ├── Places365_val.txt Examples: Case 1: Loading DIV2K dataset for training a SISR model. .. code-block:: python dataset = BasicImageDataset( ann_file='', metainfo=dict( dataset_type='div2k', task_name='sisr'), data_root='data/DIV2K', data_prefix=dict( gt='DIV2K_train_HR', img='DIV2K_train_LR_bicubic/X4'), filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=[]) Case 2: Loading places dataset for training an inpainting model. .. code-block:: python dataset = BasicImageDataset( ann_file='meta/Places365_train.txt', metainfo=dict( dataset_type='places365', task_name='inpainting'), data_root='data/places', data_prefix=dict(gt='train_set'), pipeline=[]) """ METAINFO = dict(dataset_type='basic_image_dataset', task_name='editing') def __init__(self, ann_file: str = '', metainfo: Optional[dict] = None, data_root: Optional[str] = None, data_prefix: dict = dict(img=''), pipeline: List[Union[dict, Callable]] = [], test_mode: bool = False, filename_tmpl: dict = dict(), search_key: Optional[str] = None, backend_args: Optional[dict] = None, img_suffix: Optional[Union[str, Tuple[str]]] = IMG_EXTENSIONS, recursive: bool = False, **kwards): for key in data_prefix: if key not in filename_tmpl: filename_tmpl[key] = '{}' if search_key is None: keys = list(data_prefix.keys()) search_key = keys[0] self.search_key = search_key self.filename_tmpl = filename_tmpl self.use_ann_file = (ann_file != '') if backend_args is None: self.backend_args = None else: self.backend_args = backend_args.copy() self.img_suffix = img_suffix self.recursive = recursive self.file_backend = get_file_backend( uri=data_root, backend_args=backend_args) super().__init__( ann_file=ann_file, metainfo=metainfo, data_root=data_root, data_prefix=data_prefix, pipeline=pipeline, test_mode=test_mode, **kwards) def load_data_list(self) -> List[dict]: """Load data list from folder or annotation file. Returns: list[dict]: A list of annotation. """ path_list = self._get_path_list() data_list = [] for file in path_list: basename, ext = osp.splitext(file) if basename.startswith(os.sep): # Avoid absolute-path-like annotations basename = basename[1:] data = dict(key=basename) for key in self.data_prefix: path = osp.join(self.data_prefix[key], (f'{self.filename_tmpl[key].format(basename)}' f'{ext}')) data[f'{key}_path'] = path data_list.append(data) return data_list def _get_path_list(self): """Get list of paths from annotation file or folder of dataset. Returns: list[dict]: A list of paths. """ path_list = [] if self.use_ann_file: path_list = self._get_path_list_from_ann() else: path_list = self._get_path_list_from_folder() return path_list def _get_path_list_from_ann(self): """Get list of paths from annotation file. Returns: List: List of paths. """ ann_list = list_from_file( self.ann_file, backend_args=self.backend_args) path_list = [] for ann in ann_list: if ann.isspace() or ann == '': continue path = ann.split(' ')[0] # Compatible with Windows file systems path = path.replace('/', os.sep) path_list.append(path) return path_list def _get_path_list_from_folder(self): """Get list of paths from folder. Returns: List: List of paths. """ path_list = [] folder = self.data_prefix[self.search_key] tmpl = self.filename_tmpl[self.search_key].format('') virtual_path = self.filename_tmpl[self.search_key].format('.*') for img_path in self.file_backend.list_dir_or_file( dir_path=folder, list_dir=False, suffix=self.img_suffix, recursive=self.recursive, ): basename, ext = osp.splitext(img_path) if re.match(virtual_path, basename): img_path = img_path.replace(tmpl + ext, ext) path_list.append(img_path) return path_list ================================================ FILE: mmagic/datasets/categories.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Pre-defined categories names of various datasets. IMAGENET_CATEGORIES = ( 'tench, Tinca tinca', 'goldfish, Carassius auratus', 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias', # noqa: E501 'tiger shark, Galeocerdo cuvieri', 'hammerhead, hammerhead shark', 'electric ray, crampfish, numbfish, torpedo', 'stingray', 'cock', 'hen', 'ostrich, Struthio camelus', 'brambling, Fringilla montifringilla', 'goldfinch, Carduelis carduelis', 'house finch, linnet, Carpodacus mexicanus', 'junco, snowbird', 'indigo bunting, indigo finch, indigo bird, Passerina cyanea', 'robin, American robin, Turdus migratorius', 'bulbul', 'jay', 'magpie', 'chickadee', 'water ouzel, dipper', 'kite', 'bald eagle, American eagle, Haliaeetus leucocephalus', 'vulture', 'great grey owl, great gray owl, Strix nebulosa', 'European fire salamander, Salamandra salamandra', 'common newt, Triturus vulgaris', 'eft', 'spotted salamander, Ambystoma maculatum', 'axolotl, mud puppy, Ambystoma mexicanum', 'bullfrog, Rana catesbeiana', 'tree frog, tree-frog', 'tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui', 'loggerhead, loggerhead turtle, Caretta caretta', 'leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea', # noqa: E501 'mud turtle', 'terrapin', 'box turtle, box tortoise', 'banded gecko', 'common iguana, iguana, Iguana iguana', 'American chameleon, anole, Anolis carolinensis', 'whiptail, whiptail lizard', 'agama', 'frilled lizard, Chlamydosaurus kingi', 'alligator lizard', 'Gila monster, Heloderma suspectum', 'green lizard, Lacerta viridis', 'African chameleon, Chamaeleo chamaeleon', 'Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis', # noqa: E501 'African crocodile, Nile crocodile, Crocodylus niloticus', 'American alligator, Alligator mississipiensis', 'triceratops', 'thunder snake, worm snake, Carphophis amoenus', 'ringneck snake, ring-necked snake, ring snake', 'hognose snake, puff adder, sand viper', 'green snake, grass snake', 'king snake, kingsnake', 'garter snake, grass snake', 'water snake', 'vine snake', 'night snake, Hypsiglena torquata', 'boa constrictor, Constrictor constrictor', 'rock python, rock snake, Python sebae', 'Indian cobra, Naja naja', 'green mamba', 'sea snake', 'horned viper, cerastes, sand viper, horned asp, Cerastes cornutus', 'diamondback, diamondback rattlesnake, Crotalus adamanteus', 'sidewinder, horned rattlesnake, Crotalus cerastes', 'trilobite', 'harvestman, daddy longlegs, Phalangium opilio', 'scorpion', 'black and gold garden spider, Argiope aurantia', 'barn spider, Araneus cavaticus', 'garden spider, Aranea diademata', 'black widow, Latrodectus mactans', 'tarantula', 'wolf spider, hunting spider', 'tick', 'centipede', 'black grouse', 'ptarmigan', 'ruffed grouse, partridge, Bonasa umbellus', 'prairie chicken, prairie grouse, prairie fowl', 'peacock', 'quail', 'partridge', 'African grey, African gray, Psittacus erithacus', 'macaw', 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita', 'lorikeet', 'coucal', 'bee eater', 'hornbill', 'hummingbird', 'jacamar', 'toucan', 'drake', 'red-breasted merganser, Mergus serrator', 'goose', 'black swan, Cygnus atratus', 'tusker', 'echidna, spiny anteater, anteater', 'platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus', # noqa: E501 'wallaby, brush kangaroo', 'koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus', # noqa: E501 'wombat', 'jellyfish', 'sea anemone, anemone', 'brain coral', 'flatworm, platyhelminth', 'nematode, nematode worm, roundworm', 'conch', 'snail', 'slug', 'sea slug, nudibranch', 'chiton, coat-of-mail shell, sea cradle, polyplacophore', 'chambered nautilus, pearly nautilus, nautilus', 'Dungeness crab, Cancer magister', 'rock crab, Cancer irroratus', 'fiddler crab', 'king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica', # noqa: E501 'American lobster, Northern lobster, Maine lobster, Homarus americanus', # noqa: E501 'spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish', # noqa: E501 'crayfish, crawfish, crawdad, crawdaddy', 'hermit crab', 'isopod', 'white stork, Ciconia ciconia', 'black stork, Ciconia nigra', 'spoonbill', 'flamingo', 'little blue heron, Egretta caerulea', 'American egret, great white heron, Egretta albus', 'bittern', 'crane', 'limpkin, Aramus pictus', 'European gallinule, Porphyrio porphyrio', 'American coot, marsh hen, mud hen, water hen, Fulica americana', 'bustard', 'ruddy turnstone, Arenaria interpres', 'red-backed sandpiper, dunlin, Erolia alpina', 'redshank, Tringa totanus', 'dowitcher', 'oystercatcher, oyster catcher', 'pelican', 'king penguin, Aptenodytes patagonica', 'albatross, mollymawk', 'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', # noqa: E501 'killer whale, killer, orca, grampus, sea wolf, Orcinus orca', 'dugong, Dugong dugon', 'sea lion', 'Chihuahua', 'Japanese spaniel', 'Maltese dog, Maltese terrier, Maltese', 'Pekinese, Pekingese, Peke', 'Shih-Tzu', 'Blenheim spaniel', 'papillon', 'toy terrier', 'Rhodesian ridgeback', 'Afghan hound, Afghan', 'basset, basset hound', 'beagle', 'bloodhound, sleuthhound', 'bluetick', 'black-and-tan coonhound', 'Walker hound, Walker foxhound', 'English foxhound', 'redbone', 'borzoi, Russian wolfhound', 'Irish wolfhound', 'Italian greyhound', 'whippet', 'Ibizan hound, Ibizan Podenco', 'Norwegian elkhound, elkhound', 'otterhound, otter hound', 'Saluki, gazelle hound', 'Scottish deerhound, deerhound', 'Weimaraner', 'Staffordshire bullterrier, Staffordshire bull terrier', 'American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier', # noqa: E501 'Bedlington terrier', 'Border terrier', 'Kerry blue terrier', 'Irish terrier', 'Norfolk terrier', 'Norwich terrier', 'Yorkshire terrier', 'wire-haired fox terrier', 'Lakeland terrier', 'Sealyham terrier, Sealyham', 'Airedale, Airedale terrier', 'cairn, cairn terrier', 'Australian terrier', 'Dandie Dinmont, Dandie Dinmont terrier', 'Boston bull, Boston terrier', 'miniature schnauzer', 'giant schnauzer', 'standard schnauzer', 'Scotch terrier, Scottish terrier, Scottie', 'Tibetan terrier, chrysanthemum dog', 'silky terrier, Sydney silky', 'soft-coated wheaten terrier', 'West Highland white terrier', 'Lhasa, Lhasa apso', 'flat-coated retriever', 'curly-coated retriever', 'golden retriever', 'Labrador retriever', 'Chesapeake Bay retriever', 'German short-haired pointer', 'vizsla, Hungarian pointer', 'English setter', 'Irish setter, red setter', 'Gordon setter', 'Brittany spaniel', 'clumber, clumber spaniel', 'English springer, English springer spaniel', 'Welsh springer spaniel', 'cocker spaniel, English cocker spaniel, cocker', 'Sussex spaniel', 'Irish water spaniel', 'kuvasz', 'schipperke', 'groenendael', 'malinois', 'briard', 'kelpie', 'komondor', 'Old English sheepdog, bobtail', 'Shetland sheepdog, Shetland sheep dog, Shetland', 'collie', 'Border collie', 'Bouvier des Flandres, Bouviers des Flandres', 'Rottweiler', 'German shepherd, German shepherd dog, German police dog, alsatian', 'Doberman, Doberman pinscher', 'miniature pinscher', 'Greater Swiss Mountain dog', 'Bernese mountain dog', 'Appenzeller', 'EntleBucher', 'boxer', 'bull mastiff', 'Tibetan mastiff', 'French bulldog', 'Great Dane', 'Saint Bernard, St Bernard', 'Eskimo dog, husky', 'malamute, malemute, Alaskan malamute', 'Siberian husky', 'dalmatian, coach dog, carriage dog', 'affenpinscher, monkey pinscher, monkey dog', 'basenji', 'pug, pug-dog', 'Leonberg', 'Newfoundland, Newfoundland dog', 'Great Pyrenees', 'Samoyed, Samoyede', 'Pomeranian', 'chow, chow chow', 'keeshond', 'Brabancon griffon', 'Pembroke, Pembroke Welsh corgi', 'Cardigan, Cardigan Welsh corgi', 'toy poodle', 'miniature poodle', 'standard poodle', 'Mexican hairless', 'timber wolf, grey wolf, gray wolf, Canis lupus', 'white wolf, Arctic wolf, Canis lupus tundrarum', 'red wolf, maned wolf, Canis rufus, Canis niger', 'coyote, prairie wolf, brush wolf, Canis latrans', 'dingo, warrigal, warragal, Canis dingo', 'dhole, Cuon alpinus', 'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus', 'hyena, hyaena', 'red fox, Vulpes vulpes', 'kit fox, Vulpes macrotis', 'Arctic fox, white fox, Alopex lagopus', 'grey fox, gray fox, Urocyon cinereoargenteus', 'tabby, tabby cat', 'tiger cat', 'Persian cat', 'Siamese cat, Siamese', 'Egyptian cat', 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor', # noqa: E501 'lynx, catamount', 'leopard, Panthera pardus', 'snow leopard, ounce, Panthera uncia', 'jaguar, panther, Panthera onca, Felis onca', 'lion, king of beasts, Panthera leo', 'tiger, Panthera tigris', 'cheetah, chetah, Acinonyx jubatus', 'brown bear, bruin, Ursus arctos', 'American black bear, black bear, Ursus americanus, Euarctos americanus', # noqa: E501 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus', 'sloth bear, Melursus ursinus, Ursus ursinus', 'mongoose', 'meerkat, mierkat', 'tiger beetle', 'ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle', 'ground beetle, carabid beetle', 'long-horned beetle, longicorn, longicorn beetle', 'leaf beetle, chrysomelid', 'dung beetle', 'rhinoceros beetle', 'weevil', 'fly', 'bee', 'ant, emmet, pismire', 'grasshopper, hopper', 'cricket', 'walking stick, walkingstick, stick insect', 'cockroach, roach', 'mantis, mantid', 'cicada, cicala', 'leafhopper', 'lacewing, lacewing fly', "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk", # noqa: E501 'damselfly', 'admiral', 'ringlet, ringlet butterfly', 'monarch, monarch butterfly, milkweed butterfly, Danaus plexippus', 'cabbage butterfly', 'sulphur butterfly, sulfur butterfly', 'lycaenid, lycaenid butterfly', 'starfish, sea star', 'sea urchin', 'sea cucumber, holothurian', 'wood rabbit, cottontail, cottontail rabbit', 'hare', 'Angora, Angora rabbit', 'hamster', 'porcupine, hedgehog', 'fox squirrel, eastern fox squirrel, Sciurus niger', 'marmot', 'beaver', 'guinea pig, Cavia cobaya', 'sorrel', 'zebra', 'hog, pig, grunter, squealer, Sus scrofa', 'wild boar, boar, Sus scrofa', 'warthog', 'hippopotamus, hippo, river horse, Hippopotamus amphibius', 'ox', 'water buffalo, water ox, Asiatic buffalo, Bubalus bubalis', 'bison', 'ram, tup', 'bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis', # noqa: E501 'ibex, Capra ibex', 'hartebeest', 'impala, Aepyceros melampus', 'gazelle', 'Arabian camel, dromedary, Camelus dromedarius', 'llama', 'weasel', 'mink', 'polecat, fitch, foulmart, foumart, Mustela putorius', 'black-footed ferret, ferret, Mustela nigripes', 'otter', 'skunk, polecat, wood pussy', 'badger', 'armadillo', 'three-toed sloth, ai, Bradypus tridactylus', 'orangutan, orang, orangutang, Pongo pygmaeus', 'gorilla, Gorilla gorilla', 'chimpanzee, chimp, Pan troglodytes', 'gibbon, Hylobates lar', 'siamang, Hylobates syndactylus, Symphalangus syndactylus', 'guenon, guenon monkey', 'patas, hussar monkey, Erythrocebus patas', 'baboon', 'macaque', 'langur', 'colobus, colobus monkey', 'proboscis monkey, Nasalis larvatus', 'marmoset', 'capuchin, ringtail, Cebus capucinus', 'howler monkey, howler', 'titi, titi monkey', 'spider monkey, Ateles geoffroyi', 'squirrel monkey, Saimiri sciureus', 'Madagascar cat, ring-tailed lemur, Lemur catta', 'indri, indris, Indri indri, Indri brevicaudatus', 'Indian elephant, Elephas maximus', 'African elephant, Loxodonta africana', 'lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens', 'giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca', 'barracouta, snoek', 'eel', 'coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch', # noqa: E501 'rock beauty, Holocanthus tricolor', 'anemone fish', 'sturgeon', 'gar, garfish, garpike, billfish, Lepisosteus osseus', 'lionfish', 'puffer, pufferfish, blowfish, globefish', 'abacus', 'abaya', "academic gown, academic robe, judge's robe", 'accordion, piano accordion, squeeze box', 'acoustic guitar', 'aircraft carrier, carrier, flattop, attack aircraft carrier', 'airliner', 'airship, dirigible', 'altar', 'ambulance', 'amphibian, amphibious vehicle', 'analog clock', 'apiary, bee house', 'apron', 'ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin', # noqa: E501 'assault rifle, assault gun', 'backpack, back pack, knapsack, packsack, rucksack, haversack', 'bakery, bakeshop, bakehouse', 'balance beam, beam', 'balloon', 'ballpoint, ballpoint pen, ballpen, Biro', 'Band Aid', 'banjo', 'bannister, banister, balustrade, balusters, handrail', 'barbell', 'barber chair', 'barbershop', 'barn', 'barometer', 'barrel, cask', 'barrow, garden cart, lawn cart, wheelbarrow', 'baseball', 'basketball', 'bassinet', 'bassoon', 'bathing cap, swimming cap', 'bath towel', 'bathtub, bathing tub, bath, tub', 'beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon', # noqa: E501 'beacon, lighthouse, beacon light, pharos', 'beaker', 'bearskin, busby, shako', 'beer bottle', 'beer glass', 'bell cote, bell cot', 'bib', 'bicycle-built-for-two, tandem bicycle, tandem', 'bikini, two-piece', 'binder, ring-binder', 'binoculars, field glasses, opera glasses', 'birdhouse', 'boathouse', 'bobsled, bobsleigh, bob', 'bolo tie, bolo, bola tie, bola', 'bonnet, poke bonnet', 'bookcase', 'bookshop, bookstore, bookstall', 'bottlecap', 'bow', 'bow tie, bow-tie, bowtie', 'brass, memorial tablet, plaque', 'brassiere, bra, bandeau', 'breakwater, groin, groyne, mole, bulwark, seawall, jetty', 'breastplate, aegis, egis', 'broom', 'bucket, pail', 'buckle', 'bulletproof vest', 'bullet train, bullet', 'butcher shop, meat market', 'cab, hack, taxi, taxicab', 'caldron, cauldron', 'candle, taper, wax light', 'cannon', 'canoe', 'can opener, tin opener', 'cardigan', 'car mirror', 'carousel, carrousel, merry-go-round, roundabout, whirligig', "carpenter's kit, tool kit", 'carton', 'car wheel', 'cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM', # noqa: E501 'cassette', 'cassette player', 'castle', 'catamaran', 'CD player', 'cello, violoncello', 'cellular telephone, cellular phone, cellphone, cell, mobile phone', 'chain', 'chainlink fence', 'chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour', # noqa: E501 'chain saw, chainsaw', 'chest', 'chiffonier, commode', 'chime, bell, gong', 'china cabinet, china closet', 'Christmas stocking', 'church, church building', 'cinema, movie theater, movie theatre, movie house, picture palace', 'cleaver, meat cleaver, chopper', 'cliff dwelling', 'cloak', 'clog, geta, patten, sabot', 'cocktail shaker', 'coffee mug', 'coffeepot', 'coil, spiral, volute, whorl, helix', 'combination lock', 'computer keyboard, keypad', 'confectionery, confectionary, candy store', 'container ship, containership, container vessel', 'convertible', 'corkscrew, bottle screw', 'cornet, horn, trumpet, trump', 'cowboy boot', 'cowboy hat, ten-gallon hat', 'cradle', 'crane', 'crash helmet', 'crate', 'crib, cot', 'Crock Pot', 'croquet ball', 'crutch', 'cuirass', 'dam, dike, dyke', 'desk', 'desktop computer', 'dial telephone, dial phone', 'diaper, nappy, napkin', 'digital clock', 'digital watch', 'dining table, board', 'dishrag, dishcloth', 'dishwasher, dish washer, dishwashing machine', 'disk brake, disc brake', 'dock, dockage, docking facility', 'dogsled, dog sled, dog sleigh', 'dome', 'doormat, welcome mat', 'drilling platform, offshore rig', 'drum, membranophone, tympan', 'drumstick', 'dumbbell', 'Dutch oven', 'electric fan, blower', 'electric guitar', 'electric locomotive', 'entertainment center', 'envelope', 'espresso maker', 'face powder', 'feather boa, boa', 'file, file cabinet, filing cabinet', 'fireboat', 'fire engine, fire truck', 'fire screen, fireguard', 'flagpole, flagstaff', 'flute, transverse flute', 'folding chair', 'football helmet', 'forklift', 'fountain', 'fountain pen', 'four-poster', 'freight car', 'French horn, horn', 'frying pan, frypan, skillet', 'fur coat', 'garbage truck, dustcart', 'gasmask, respirator, gas helmet', 'gas pump, gasoline pump, petrol pump, island dispenser', 'goblet', 'go-kart', 'golf ball', 'golfcart, golf cart', 'gondola', 'gong, tam-tam', 'gown', 'grand piano, grand', 'greenhouse, nursery, glasshouse', 'grille, radiator grille', 'grocery store, grocery, food market, market', 'guillotine', 'hair slide', 'hair spray', 'half track', 'hammer', 'hamper', 'hand blower, blow dryer, blow drier, hair dryer, hair drier', 'hand-held computer, hand-held microcomputer', 'handkerchief, hankie, hanky, hankey', 'hard disc, hard disk, fixed disk', 'harmonica, mouth organ, harp, mouth harp', 'harp', 'harvester, reaper', 'hatchet', 'holster', 'home theater, home theatre', 'honeycomb', 'hook, claw', 'hoopskirt, crinoline', 'horizontal bar, high bar', 'horse cart, horse-cart', 'hourglass', 'iPod', 'iron, smoothing iron', "jack-o'-lantern", 'jean, blue jean, denim', 'jeep, landrover', 'jersey, T-shirt, tee shirt', 'jigsaw puzzle', 'jinrikisha, ricksha, rickshaw', 'joystick', 'kimono', 'knee pad', 'knot', 'lab coat, laboratory coat', 'ladle', 'lampshade, lamp shade', 'laptop, laptop computer', 'lawn mower, mower', 'lens cap, lens cover', 'letter opener, paper knife, paperknife', 'library', 'lifeboat', 'lighter, light, igniter, ignitor', 'limousine, limo', 'liner, ocean liner', 'lipstick, lip rouge', 'Loafer', 'lotion', 'loudspeaker, speaker, speaker unit, loudspeaker system, speaker system', # noqa: E501 "loupe, jeweler's loupe", 'lumbermill, sawmill', 'magnetic compass', 'mailbag, postbag', 'mailbox, letter box', 'maillot', 'maillot, tank suit', 'manhole cover', 'maraca', 'marimba, xylophone', 'mask', 'matchstick', 'maypole', 'maze, labyrinth', 'measuring cup', 'medicine chest, medicine cabinet', 'megalith, megalithic structure', 'microphone, mike', 'microwave, microwave oven', 'military uniform', 'milk can', 'minibus', 'miniskirt, mini', 'minivan', 'missile', 'mitten', 'mixing bowl', 'mobile home, manufactured home', 'Model T', 'modem', 'monastery', 'monitor', 'moped', 'mortar', 'mortarboard', 'mosque', 'mosquito net', 'motor scooter, scooter', 'mountain bike, all-terrain bike, off-roader', 'mountain tent', 'mouse, computer mouse', 'mousetrap', 'moving van', 'muzzle', 'nail', 'neck brace', 'necklace', 'nipple', 'notebook, notebook computer', 'obelisk', 'oboe, hautboy, hautbois', 'ocarina, sweet potato', 'odometer, hodometer, mileometer, milometer', 'oil filter', 'organ, pipe organ', 'oscilloscope, scope, cathode-ray oscilloscope, CRO', 'overskirt', 'oxcart', 'oxygen mask', 'packet', 'paddle, boat paddle', 'paddlewheel, paddle wheel', 'padlock', 'paintbrush', "pajama, pyjama, pj's, jammies", 'palace', 'panpipe, pandean pipe, syrinx', 'paper towel', 'parachute, chute', 'parallel bars, bars', 'park bench', 'parking meter', 'passenger car, coach, carriage', 'patio, terrace', 'pay-phone, pay-station', 'pedestal, plinth, footstall', 'pencil box, pencil case', 'pencil sharpener', 'perfume, essence', 'Petri dish', 'photocopier', 'pick, plectrum, plectron', 'pickelhaube', 'picket fence, paling', 'pickup, pickup truck', 'pier', 'piggy bank, penny bank', 'pill bottle', 'pillow', 'ping-pong ball', 'pinwheel', 'pirate, pirate ship', 'pitcher, ewer', "plane, carpenter's plane, woodworking plane", 'planetarium', 'plastic bag', 'plate rack', 'plow, plough', "plunger, plumber's helper", 'Polaroid camera, Polaroid Land camera', 'pole', 'police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria', # noqa: E501 'poncho', 'pool table, billiard table, snooker table', 'pop bottle, soda bottle', 'pot, flowerpot', "potter's wheel", 'power drill', 'prayer rug, prayer mat', 'printer', 'prison, prison house', 'projectile, missile', 'projector', 'puck, hockey puck', 'punching bag, punch bag, punching ball, punchball', 'purse', 'quill, quill pen', 'quilt, comforter, comfort, puff', 'racer, race car, racing car', 'racket, racquet', 'radiator', 'radio, wireless', 'radio telescope, radio reflector', 'rain barrel', 'recreational vehicle, RV, R.V.', 'reel', 'reflex camera', 'refrigerator, icebox', 'remote control, remote', 'restaurant, eating house, eating place, eatery', 'revolver, six-gun, six-shooter', 'rifle', 'rocking chair, rocker', 'rotisserie', 'rubber eraser, rubber, pencil eraser', 'rugby ball', 'rule, ruler', 'running shoe', 'safe', 'safety pin', 'saltshaker, salt shaker', 'sandal', 'sarong', 'sax, saxophone', 'scabbard', 'scale, weighing machine', 'school bus', 'schooner', 'scoreboard', 'screen, CRT screen', 'screw', 'screwdriver', 'seat belt, seatbelt', 'sewing machine', 'shield, buckler', 'shoe shop, shoe-shop, shoe store', 'shoji', 'shopping basket', 'shopping cart', 'shovel', 'shower cap', 'shower curtain', 'ski', 'ski mask', 'sleeping bag', 'slide rule, slipstick', 'sliding door', 'slot, one-armed bandit', 'snorkel', 'snowmobile', 'snowplow, snowplough', 'soap dispenser', 'soccer ball', 'sock', 'solar dish, solar collector, solar furnace', 'sombrero', 'soup bowl', 'space bar', 'space heater', 'space shuttle', 'spatula', 'speedboat', "spider web, spider's web", 'spindle', 'sports car, sport car', 'spotlight, spot', 'stage', 'steam locomotive', 'steel arch bridge', 'steel drum', 'stethoscope', 'stole', 'stone wall', 'stopwatch, stop watch', 'stove', 'strainer', 'streetcar, tram, tramcar, trolley, trolley car', 'stretcher', 'studio couch, day bed', 'stupa, tope', 'submarine, pigboat, sub, U-boat', 'suit, suit of clothes', 'sundial', 'sunglass', 'sunglasses, dark glasses, shades', 'sunscreen, sunblock, sun blocker', 'suspension bridge', 'swab, swob, mop', 'sweatshirt', 'swimming trunks, bathing trunks', 'swing', 'switch, electric switch, electrical switch', 'syringe', 'table lamp', 'tank, army tank, armored combat vehicle, armoured combat vehicle', 'tape player', 'teapot', 'teddy, teddy bear', 'television, television system', 'tennis ball', 'thatch, thatched roof', 'theater curtain, theatre curtain', 'thimble', 'thresher, thrasher, threshing machine', 'throne', 'tile roof', 'toaster', 'tobacco shop, tobacconist shop, tobacconist', 'toilet seat', 'torch', 'totem pole', 'tow truck, tow car, wrecker', 'toyshop', 'tractor', 'trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi', # noqa: E501 'tray', 'trench coat', 'tricycle, trike, velocipede', 'trimaran', 'tripod', 'triumphal arch', 'trolleybus, trolley coach, trackless trolley', 'trombone', 'tub, vat', 'turnstile', 'typewriter keyboard', 'umbrella', 'unicycle, monocycle', 'upright, upright piano', 'vacuum, vacuum cleaner', 'vase', 'vault', 'velvet', 'vending machine', 'vestment', 'viaduct', 'violin, fiddle', 'volleyball', 'waffle iron', 'wall clock', 'wallet, billfold, notecase, pocketbook', 'wardrobe, closet, press', 'warplane, military plane', 'washbasin, handbasin, washbowl, lavabo, wash-hand basin', 'washer, automatic washer, washing machine', 'water bottle', 'water jug', 'water tower', 'whiskey jug', 'whistle', 'wig', 'window screen', 'window shade', 'Windsor tie', 'wine bottle', 'wing', 'wok', 'wooden spoon', 'wool, woolen, woollen', 'worm fence, snake fence, snake-rail fence, Virginia fence', 'wreck', 'yawl', 'yurt', 'web site, website, internet site, site', 'comic book', 'crossword puzzle, crossword', 'street sign', 'traffic light, traffic signal, stoplight', 'book jacket, dust cover, dust jacket, dust wrapper', 'menu', 'plate', 'guacamole', 'consomme', 'hot pot, hotpot', 'trifle', 'ice cream, icecream', 'ice lolly, lolly, lollipop, popsicle', 'French loaf', 'bagel, beigel', 'pretzel', 'cheeseburger', 'hotdog, hot dog, red hot', 'mashed potato', 'head cabbage', 'broccoli', 'cauliflower', 'zucchini, courgette', 'spaghetti squash', 'acorn squash', 'butternut squash', 'cucumber, cuke', 'artichoke, globe artichoke', 'bell pepper', 'cardoon', 'mushroom', 'Granny Smith', 'strawberry', 'orange', 'lemon', 'fig', 'pineapple, ananas', 'banana', 'jackfruit, jak, jack', 'custard apple', 'pomegranate', 'hay', 'carbonara', 'chocolate sauce, chocolate syrup', 'dough', 'meat loaf, meatloaf', 'pizza, pizza pie', 'potpie', 'burrito', 'red wine', 'espresso', 'cup', 'eggnog', 'alp', 'bubble', 'cliff, drop, drop-off', 'coral reef', 'geyser', 'lakeside, lakeshore', 'promontory, headland, head, foreland', 'sandbar, sand bar', 'seashore, coast, seacoast, sea-coast', 'valley, vale', 'volcano', 'ballplayer, baseball player', 'groom, bridegroom', 'scuba diver', 'rapeseed', 'daisy', "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum", # noqa: E501 'corn', 'acorn', 'hip, rose hip, rosehip', 'buckeye, horse chestnut, conker', 'coral fungus', 'agaric', 'gyromitra', 'stinkhorn, carrion fungus', 'earthstar', 'hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa', # noqa: E501 'bolete', 'ear, spike, capitulum', 'toilet tissue, toilet paper, bathroom tissue') CIFAR10_CATEGORIES = ('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') ================================================ FILE: mmagic/datasets/cifar10_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pickle from typing import List, Optional import mmengine.dist as dist import numpy as np from mmengine.fileio import get_file_backend from mmagic.registry import DATASETS from .basic_conditional_dataset import BasicConditionalDataset from .categories import CIFAR10_CATEGORIES from .data_utils import check_md5, download_and_extract_archive @DATASETS.register_module() class CIFAR10(BasicConditionalDataset): """`CIFAR10 `_ Dataset. This implementation is modified from https://github.com/pytorch/vision/blob/master/torchvision/datasets/cifar.py Args: data_prefix (str): Prefix for data. test_mode (bool): ``test_mode=True`` means in test phase. It determines to use the training set or test set. metainfo (dict, optional): Meta information for dataset, such as categories information. Defaults to None. data_root (str): The root directory for ``data_prefix``. Defaults to ''. download (bool): Whether to download the dataset if not exists. Defaults to True. **kwargs: Other keyword arguments in :class:`BaseDataset`. """ # noqa: E501 base_folder = 'cifar-10-batches-py' url = 'https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz' filename = 'cifar-10-python.tar.gz' tgz_md5 = 'c58f30108f718f92721af3b95e74349a' train_list = [ ['data_batch_1', 'c99cafc152244af753f735de768cd75f'], ['data_batch_2', 'd4bba439e000b95fd0a9bffe97cbabec'], ['data_batch_3', '54ebc095f3ab1f0389bbae665268c751'], ['data_batch_4', '634d18415352ddfa80567beed471001a'], ['data_batch_5', '482c414d41f54cd18b22e5b47cb7c3cb'], ] test_list = [ ['test_batch', '40351d587109b95175f43aff81a1287e'], ] meta = { 'filename': 'batches.meta', 'key': 'label_names', 'md5': '5ff9c542aee3614f3951f8cda6e48888', } METAINFO = {'classes': CIFAR10_CATEGORIES} def __init__(self, data_prefix: str, test_mode: bool, metainfo: Optional[dict] = None, data_root: str = '', download: bool = True, **kwargs): self.download = download super().__init__( # The CIFAR dataset doesn't need specify annotation file ann_file='', metainfo=metainfo, data_root=data_root, data_prefix=dict(root=data_prefix), test_mode=test_mode, **kwargs) def load_data_list(self): """Load images and ground truth labels.""" root_prefix = self.data_prefix['root'] file_backend = get_file_backend(uri=root_prefix) if dist.is_main_process() and not self._check_integrity(): if file_backend.name != 'LocalBackend': raise RuntimeError( f'The dataset on {root_prefix} is not integrated, ' f'please manually handle it.') if self.download: download_and_extract_archive( self.url, root_prefix, filename=self.filename, md5=self.tgz_md5) else: raise RuntimeError( f'Cannot find {self.__class__.__name__} dataset in ' f"{self.data_prefix['root']}, you can specify " '`download=True` to download automatically.') dist.barrier() assert self._check_integrity(), \ 'Download failed or shared storage is unavailable. Please ' \ f'download the dataset manually through {self.url}.' if not self.test_mode: downloaded_list = self.train_list else: downloaded_list = self.test_list imgs = [] gt_labels = [] # load the picked numpy arrays for file_name, _ in downloaded_list: file_path = file_backend.join_path(root_prefix, self.base_folder, file_name) content = file_backend.get(file_path) entry = pickle.loads(content, encoding='latin1') imgs.append(entry['data']) if 'labels' in entry: gt_labels.extend(entry['labels']) else: gt_labels.extend(entry['fine_labels']) imgs = np.vstack(imgs).reshape(-1, 3, 32, 32) imgs = imgs.transpose((0, 2, 3, 1)) # convert to HWC if self.CLASSES is None: # The metainfo in the file has the lowest priority, therefore # we only need to load it if classes is not specified. self._load_meta() data_list = [] for img, gt_label in zip(imgs, gt_labels): info = { 'gt': img, 'gt_label': int(gt_label), 'gt_channel_order': 'RGB' } data_list.append(info) return data_list def _load_meta(self): """Load categories information from metafile.""" root = self.data_prefix['root'] file_backend = get_file_backend(uri=root) path = file_backend.join_path(root, self.base_folder, self.meta['filename']) md5 = self.meta.get('md5', None) if not file_backend.exists(path) or (md5 is not None and not check_md5(path, md5)): raise RuntimeError( 'Dataset metadata file not found or corrupted.' + ' You can use `download=True` to download it') content = file_backend.get(path) data = pickle.loads(content, encoding='latin1') self._metainfo.setdefault('classes', data[self.meta['key']]) def _check_integrity(self): """Check the integrity of data files.""" root = self.data_prefix['root'] file_backend = get_file_backend(uri=root) for fentry in (self.train_list + self.test_list): filename, md5 = fentry[0], fentry[1] fpath = file_backend.join_path(root, self.base_folder, filename) if not file_backend.exists(fpath): return False if md5 is not None and not check_md5( fpath, md5, file_backend=file_backend): return False return True def extra_repr(self) -> List[str]: """The extra repr information of the dataset.""" body = [f"Prefix of data: \t{self.data_prefix['root']}"] return body ================================================ FILE: mmagic/datasets/comp1k_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from typing import List, Union from mmengine.dataset import BaseDataset from mmengine.fileio import load from mmagic.registry import DATASETS @DATASETS.register_module() class AdobeComp1kDataset(BaseDataset): """Adobe composition-1k dataset. The dataset loads (alpha, fg, bg) data and apply specified transforms to the data. You could specify whether composite merged image online or load composited merged image in pipeline. Example for online comp-1k dataset: :: [ { "alpha": 'alpha/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] Example for offline comp-1k dataset: :: [ { "alpha": 'alpha/000.png', "merged": 'merged/000.png', "fg": 'fg/000.png', "bg": 'bg/000.png' }, { "alpha": 'alpha/001.png', "merged": 'merged/001.png', "fg": 'fg/001.png', "bg": 'bg/001.png' }, ] Args: ann_file (str): Annotation file path. Defaults to ''. data_root (str, optional): The root directory for ``data_prefix`` and ``ann_file``. Defaults to None. pipeline (list, optional): Processing pipeline. Defaults to []. test_mode (bool, optional): ``test_mode=True`` means in test phase. Defaults to False. **kwargs: Other arguments passed to :class:`mmengine.dataset.BaseDataset`. Examples: See unit-tests TODO: Move some codes in unittest here """ # TODO: Support parsing folder structures without annotation files. METAINFO = dict(dataset_type='matting_dataset', task_name='matting') def load_data_list(self) -> List[dict]: """Load annotations from an annotation file named as ``self.ann_file`` In order to be compatible to both new and old annotation format, we copy implementations from mmengine and do some modifications. Returns: list[dict]: A list of annotation. """ # noqa: E501 # `self.ann_file` denotes the absolute annotation file path if # `self.root=None` or relative path if `self.root=/path/to/data/`. annotations = load(self.ann_file) assert annotations, f'annotation file "{self.ann_file}" is empty.' if isinstance(annotations, list): # Old annotation format, we get data_list only raw_data_list = annotations elif isinstance(annotations, dict): # New annotation format, follow original routine in base class if 'data_list' not in annotations or 'metainfo' not in annotations: raise ValueError('Annotation must have data_list and metainfo ' 'keys') metainfo = annotations['metainfo'] raw_data_list = annotations['data_list'] # Meta information load from annotation file will not influence the # existed meta information load from `BaseDataset.METAINFO` and # `metainfo` arguments defined in constructor. for k, v in metainfo.items(): self._metainfo.setdefault(k, v) else: raise TypeError( f'The annotations loaded from annotation file ' f'should be a list or dict, but got {type(annotations)}!') # load and parse data_infos. data_list = [] for raw_data_info in raw_data_list: # parse raw data information to target format data_info = self.parse_data_info(raw_data_info) if isinstance(data_info, dict): # For image tasks, `data_info` should information if single # image, such as dict(img_path='xxx', width=360, ...) data_list.append(data_info) elif isinstance(data_info, list): # For video tasks, `data_info` could contain image # information of multiple frames, such as # [dict(video_path='xxx', timestamps=...), # dict(video_path='xxx', timestamps=...)] for item in data_info: if not isinstance(item, dict): raise TypeError('data_list must be list of dict, but ' f'got {type(item)}') data_list.extend(data_info) else: raise TypeError('data_info should be a dict or list of dict, ' f'but got {type(data_info)}') return data_list def parse_data_info(self, raw_data_info: dict) -> Union[dict, List[dict]]: """Join data_root to each path in data_info.""" data_info = raw_data_info.copy() for key in raw_data_info: data_info[key] = osp.join(self.data_root, data_info[key]) return data_info ================================================ FILE: mmagic/datasets/controlnet_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import json import os from typing import Callable, List, Union from mmengine.dataset import BaseDataset from mmagic.registry import DATASETS @DATASETS.register_module() class ControlNetDataset(BaseDataset): """Demo dataset to test ControlNet. Modified from https://github.com/lllyas viel/ControlNet/blob/16ea3b5379c1e78a4bc8e3fc9cae8d65c42511b1/tutorial_data set.py # noqa. You can download the demo data from https://huggingface.co/lllyasviel/ControlNet/blob/main/training/fill50k.zip # noqa and then unzip the file to the ``data`` folder. Args: ann_file (str): Path to the annotation file. Defaults to 'prompt.json' as ControlNet's default. data_root (str): Path to the data root. Defaults to './data/fill50k'. pipeline (list[dict | callable]): A sequence of data transforms. """ def __init__(self, ann_file: str = 'prompt.json', data_root: str = './data/fill50k', control_key='source', image_key='target', pipeline: List[Union[dict, Callable]] = []): self.control_key = control_key self.image_key = image_key super().__init__( ann_file=ann_file, data_root=data_root, pipeline=pipeline) def load_data_list(self) -> List[dict]: """Load annotations from an annotation file named as ``self.ann_file`` Returns: list[dict]: A list of annotation. """ data_list = [] with open(self.ann_file, 'rt') as file: anno_list = file.readlines() for anno in anno_list: anno = json.loads(anno) # source = anno['source'] # target = anno['target'] source = anno[self.control_key] target = anno[self.image_key] prompt = anno['prompt'] source = os.path.join(self.data_root, source) target = os.path.join(self.data_root, target) data_list.append({ 'source_path': source, 'target_path': target, 'prompt': prompt }) return data_list ================================================ FILE: mmagic/datasets/data_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import gzip import hashlib import os import os.path import os.path as osp import shutil import tarfile import tempfile import urllib.error import urllib.request import zipfile from os import PathLike from typing import Callable, Dict, List, Tuple from mmengine.fileio.backends import BaseStorageBackend # TODO: we can use FileClient.infer_client to replace this function def infer_io_backend(data_root: str) -> str: """Infer the io backend from the given data_root. Args: data_root (str): The path of data root. Returns: str: The io backend. """ if (data_root.upper().startswith('HTTP') or data_root.upper().startswith('HTTPS')): backend = 'http' elif data_root.upper().startswith('S3') or ( len(data_root.split(':')) > 2 and data_root.split(':')[1].upper() == 'S3'): # two case: # 1. s3://xxxxx (raw petrel path) # 2. CONFIG:s3://xxx (petrel path with specific config) backend = 'petrel' else: # use default one backend = 'local' return backend def calculate_md5(fpath: str, file_backend: BaseStorageBackend = None, chunk_size: int = 1024 * 1024) -> str: """Calculate MD5 of the file. Args: fpath (str): The path of the file. file_backend (BaseStorageBackend, optional): The file backend to fetch the file. Defaults to None. chunk_size (int, optional): The chunk size to calculate MD5. Defaults to 1024*1024. Returns: str: The string of MD5. """ md5 = hashlib.md5() if file_backend is None or file_backend.name == 'LocalBackend': with open(fpath, 'rb') as f: for chunk in iter(lambda: f.read(chunk_size), b''): md5.update(chunk) else: md5.update(file_backend.get(fpath)) return md5.hexdigest() def check_md5(fpath, md5, **kwargs) -> bool: """Checn whether the MD5 of the file. Args: fpath (str): The path of the file. md5 (str): Target MD5 value. Returns: bool: If true, the MD5 of passed file is same as target MD5. """ return md5 == calculate_md5(fpath, **kwargs) def check_integrity(fpath, md5=None) -> bool: """Check whether the file is integrity by comparing the MD5 of the file with target MD5. Args: fpath (str): The path of the file. md5 (str, optional): The target MD5 value. Defaults to None. Returns: bool: If true, the passed file is integrity. """ if not os.path.isfile(fpath): return False if md5 is None: return True return check_md5(fpath, md5) def download_url_to_file(url, dst, hash_prefix=None, progress=True): """Download object at the given URL to a local path. Modified from https://pytorch.org/docs/stable/hub.html#torch.hub.download_url_to_file Args: url (str): URL of the object to download dst (str): Full path where object will be saved, e.g. ``/tmp/temporary_file`` hash_prefix (string, optional): If not None, the SHA256 downloaded file should start with ``hash_prefix``. Defaults to None. progress (bool): whether or not to display a progress bar to stderr. Defaults to True """ file_size = None req = urllib.request.Request(url) u = urllib.request.urlopen(req) meta = u.info() if hasattr(meta, 'getheaders'): content_length = meta.getheaders('Content-Length') else: content_length = meta.get_all('Content-Length') if content_length is not None and len(content_length) > 0: file_size = int(content_length[0]) # We deliberately save it in a temp file and move it after download is # complete. This prevents a local file being overridden by a broken # download. dst = os.path.expanduser(dst) dst_dir = os.path.dirname(dst) f = tempfile.NamedTemporaryFile(delete=False, dir=dst_dir) import rich.progress columns = [ rich.progress.DownloadColumn(), rich.progress.BarColumn(bar_width=None), rich.progress.TimeRemainingColumn(), ] try: if hash_prefix is not None: sha256 = hashlib.sha256() with rich.progress.Progress(*columns) as pbar: task = pbar.add_task('download', total=file_size, visible=progress) while True: buffer = u.read(8192) if len(buffer) == 0: break f.write(buffer) if hash_prefix is not None: sha256.update(buffer) pbar.update(task, advance=len(buffer)) f.close() if hash_prefix is not None: digest = sha256.hexdigest() if digest[:len(hash_prefix)] != hash_prefix: raise RuntimeError( 'invalid hash value (expected "{}", got "{}")'.format( hash_prefix, digest)) shutil.move(f.name, dst) finally: f.close() if os.path.exists(f.name): os.remove(f.name) def download_url(url, root, filename=None, md5=None): """Download a file from a url and place it in root. Args: url (str): URL to download file from. root (str): Directory to place downloaded file in. filename (str | None): Name to save the file under. If filename is None, use the basename of the URL. md5 (str | None): MD5 checksum of the download. If md5 is None, download without md5 check. """ root = os.path.expanduser(root) if not filename: filename = os.path.basename(url) fpath = os.path.join(root, filename) os.makedirs(root, exist_ok=True) if check_integrity(fpath, md5): print(f'Using downloaded and verified file: {fpath}') else: try: print(f'Downloading {url} to {fpath}') download_url_to_file(url, fpath) except (urllib.error.URLError, IOError) as e: if url[:5] == 'https': url = url.replace('https:', 'http:') print('Failed download. Trying https -> http instead.' f' Downloading {url} to {fpath}') download_url_to_file(url, fpath) else: raise e # check integrity of downloaded file if not check_integrity(fpath, md5): raise RuntimeError('File not found or corrupted.') def _is_tarxz(filename): """Judge whether the file is `.tar.xz`""" return filename.endswith('.tar.xz') def _is_tar(filename): """Judge whether the file is `.tar`""" return filename.endswith('.tar') def _is_targz(filename): """Judge whether the file is `.tar.gz`""" return filename.endswith('.tar.gz') def _is_tgz(filename): """Judge whether the file is `.tgz`""" return filename.endswith('.tgz') def _is_gzip(filename): """Judge whether the file is `.gzip`""" return filename.endswith('.gz') and not filename.endswith('.tar.gz') def _is_zip(filename): """Judge whether the file is `.zip`""" return filename.endswith('.zip') def extract_archive(from_path, to_path=None, remove_finished=False): """Extract the archive.""" if to_path is None: to_path = os.path.dirname(from_path) if _is_tar(from_path): with tarfile.open(from_path, 'r') as tar: tar.extractall(path=to_path) elif _is_targz(from_path) or _is_tgz(from_path): with tarfile.open(from_path, 'r:gz') as tar: tar.extractall(path=to_path) elif _is_tarxz(from_path): with tarfile.open(from_path, 'r:xz') as tar: tar.extractall(path=to_path) elif _is_gzip(from_path): to_path = os.path.join( to_path, os.path.splitext(os.path.basename(from_path))[0]) with open(to_path, 'wb') as out_f, gzip.GzipFile(from_path) as zip_f: out_f.write(zip_f.read()) elif _is_zip(from_path): with zipfile.ZipFile(from_path, 'r') as z: z.extractall(to_path) else: raise ValueError(f'Extraction of {from_path} not supported') if remove_finished: os.remove(from_path) def download_and_extract_archive(url, download_root, extract_root=None, filename=None, md5=None, remove_finished=False): """Download and extract the archive.""" download_root = os.path.expanduser(download_root) if extract_root is None: extract_root = download_root if not filename: filename = os.path.basename(url) download_url(url, download_root, filename, md5) archive = os.path.join(download_root, filename) print(f'Extracting {archive} to {extract_root}') extract_archive(archive, extract_root, remove_finished) def open_maybe_compressed_file(path: str): """Return a file object that possibly decompresses 'path' on the fly. Decompression occurs when argument `path` is a string and ends with '.gz' or '.xz'. """ if not isinstance(path, str): return path if path.endswith('.gz'): import gzip return gzip.open(path, 'rb') if path.endswith('.xz'): import lzma return lzma.open(path, 'rb') return open(path, 'rb') def expanduser(path): """Expand ~ and ~user constructions. If user or $HOME is unknown, do nothing. """ if isinstance(path, (str, PathLike)): return osp.expanduser(path) else: return path def find_folders(root: str, file_backend: BaseStorageBackend ) -> Tuple[List[str], Dict[str, int]]: """Find classes by folders under a root. Args: root (string): root directory of folders Returns: Tuple[List[str], Dict[str, int]]: - folders: The name of sub folders under the root. - folder_to_idx: The map from folder name to class idx. """ folders = list( file_backend.list_dir_or_file( root, list_dir=True, list_file=False, recursive=False, )) folders.sort() folder_to_idx = {folders[i]: i for i in range(len(folders))} return folders, folder_to_idx def get_samples(root: str, folder_to_idx: Dict[str, int], is_valid_file: Callable, file_backend: BaseStorageBackend): """Make dataset by walking all images under a root. Args: root (string): root directory of folders folder_to_idx (dict): the map from class name to class idx is_valid_file (Callable): A function that takes path of a file and check if the file is a valid sample file. Returns: Tuple[list, set]: - samples: a list of tuple where each element is (image, class_idx) - empty_folders: The folders don't have any valid files. """ samples = [] available_classes = set() for folder_name in sorted(list(folder_to_idx.keys())): _dir = file_backend.join_path(root, folder_name) files = list( file_backend.list_dir_or_file( _dir, list_dir=False, list_file=True, recursive=True, )) for file in sorted(list(files)): if is_valid_file(file): path = file_backend.join_path(folder_name, file) item = (path, folder_to_idx[folder_name]) samples.append(item) available_classes.add(folder_name) empty_folders = set(folder_to_idx.keys()) - available_classes return samples, empty_folders ================================================ FILE: mmagic/datasets/dreambooth_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from typing import Callable, List, Union from mmengine import FileClient from mmengine.dataset import BaseDataset from mmagic.registry import DATASETS @DATASETS.register_module() class DreamBoothDataset(BaseDataset): """Dataset for DreamBooth. Args: data_root (str): Path to the data root. concept_dir (str): Path to the concept images. prompt (str): Prompt of the concept. pipeline (list[dict | callable]): A sequence of data transforms. """ def __init__(self, data_root: str, concept_dir: str, prompt: str, pipeline: List[Union[dict, Callable]] = []): data_prefix = dict(img_path=concept_dir) self.prompt = prompt super().__init__( data_root=data_root, data_prefix=data_prefix, pipeline=pipeline) def load_data_list(self) -> list: """Load data list from concept_dir and class_dir.""" data_list = [] img_dir = self.data_prefix['img_path'] file_client = FileClient.infer_client(uri=img_dir) img_dir = osp.abspath(img_dir) for data_name in file_client.list_dir_or_file(img_dir, list_dir=False): data_info = dict( img_path=file_client.join_path(img_dir, data_name), prompt=self.prompt) data_list.append(data_info) return data_list ================================================ FILE: mmagic/datasets/grow_scale_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Union from mmengine import print_log from mmengine.dataset import BaseDataset from mmengine.fileio import get_file_backend from mmagic.registry import DATASETS @DATASETS.register_module() class GrowScaleImgDataset(BaseDataset): """Grow Scale Unconditional Image Dataset. This dataset is similar with ``UnconditionalImageDataset``, but offer more dynamic functionalities for the supporting complex algorithms, like PGGAN. Highlight functionalities: #. Support growing scale dataset. The motivation is to decrease data pre-processing load in CPU. In this dataset, you can provide ``imgs_roots`` like: .. code-block:: python {'64': 'path_to_64x64_imgs', '512': 'path_to_512x512_imgs'} Then, in training scales lower than 64x64, this dataset will set ``self.imgs_root`` as 'path_to_64x64_imgs'; #. Offer ``samples_per_gpu`` according to different scales. In this dataset, ``self.samples_per_gpu`` will help runner to know the updated batch size. Basically, This dataset contains raw images for training unconditional GANs. Given a root dir, we will recursively find all images in this root. The transformation on data is defined by the pipeline. Args: imgs_root (str): Root path for unconditional images. pipeline (list[dict | callable]): A sequence of data transforms. len_per_stage (int, optional): The length of dataset for each scale. This args change the length dataset by concatenating or extracting subset. If given a value less than 0., the original length will be kept. Defaults to 1e6. gpu_samples_per_scale (dict | None, optional): Dict contains ``samples_per_gpu`` for each scale. For example, ``{'32': 4}`` will set the scale of 32 with ``samples_per_gpu=4``, despite other scale with ``samples_per_gpu=self.gpu_samples_base``. gpu_samples_base (int, optional): Set default ``samples_per_gpu`` for each scale. Defaults to 32. io_backend (str, optional): The storage backend type. Options are "disk", "ceph", "memcached", "lmdb", "http" and "petrel". Default: None. test_mode (bool, optional): If True, the dataset will work in test mode. Otherwise, in train mode. Default to False. """ _VALID_IMG_SUFFIX = ('.jpg', '.png', '.jpeg', '.JPEG') def __init__(self, data_roots: dict, pipeline, len_per_stage=int(1e6), gpu_samples_per_scale=None, gpu_samples_base=32, io_backend: Optional[str] = None, file_lists: Optional[Union[str, dict]] = None, test_mode=False): assert isinstance(data_roots, dict) self.data_roots = data_roots self._img_scales = sorted([int(x) for x in data_roots.keys()]) self._curr_scale = self._img_scales[0] self._actual_curr_scale = self._curr_scale self.data_root = self.data_roots[str(self._curr_scale)] # len_per_stage = -1, keep the original length self.len_per_stage = len_per_stage self.curr_stage = 0 self.gpu_samples_per_scale = gpu_samples_per_scale if self.gpu_samples_per_scale is not None: assert isinstance(self.gpu_samples_per_scale, dict) else: self.gpu_samples_per_scale = dict() self.gpu_samples_base = gpu_samples_base if io_backend is None: data_root_ = list(data_roots.values())[0] self.file_backend = get_file_backend(uri=data_root_) else: self.file_backend = get_file_backend( backend_args={'backend': io_backend}) # use current data root to initialize and do not support # `serialize_data` super().__init__( data_root=self.data_root, pipeline=pipeline, test_mode=test_mode, serialize_data=False) # print basic dataset information to check the validity print_log(repr(self), 'current') def load_data_list(self): """Load annotations.""" # recursively find all of the valid images from imgs_root data_list = self.file_backend.list_dir_or_file( self.data_root, list_dir=False, suffix=self._VALID_IMG_SUFFIX, recursive=True) self.data_list = [ self.file_backend.join_path(self.data_root, x) for x in data_list ] if self.len_per_stage > 0: self.concat_imgs_list_to(self.len_per_stage) self.samples_per_gpu = self.gpu_samples_per_scale.get( str(self._actual_curr_scale), self.gpu_samples_base) return self.data_list def update_annotations(self, curr_scale): """Update annotations. Args: curr_scale (int): Current image scale. Returns: bool: Whether to update. """ if curr_scale == self._actual_curr_scale: return False for scale in self._img_scales: if curr_scale <= scale: self._curr_scale = scale break if scale == self._img_scales[-1]: assert RuntimeError( f'Cannot find a suitable scale for {curr_scale}') self._actual_curr_scale = curr_scale self.data_root = self.data_roots[str(self._curr_scale)] self.load_data_list() # print basic dataset information to check the validity print_log('Update Dataset: ' + repr(self), 'current') return True def concat_imgs_list_to(self, num): """Concat image list to specified length. Args: num (int): The length of the concatenated image list. """ if num <= len(self.data_list): self.data_list = self.data_list[:num] return concat_factor = (num // len(self.data_list)) + 1 imgs = self.data_list * concat_factor self.data_list = imgs[:num] def prepare_train_data(self, idx): """Prepare training data. Args: idx (int): Index of current batch. Returns: dict: Prepared training data batch. """ results = dict(gt_path=self.data_list[idx]) return self.pipeline(results) def prepare_test_data(self, idx): """Prepare testing data. Args: idx (int): Index of current batch. Returns: dict: Prepared training data batch. """ results = dict(gt_path=self.data_list[idx]) return self.pipeline(results) def __getitem__(self, idx): """Get the idx-th image and data information of dataset after ``self.pipeline``, and ``full_init`` will be called if the dataset has not been fully initialized. During training phase, if ``self.pipeline`` get ``None``, ``self._rand_another`` will be called until a valid image is fetched or the maximum limit of refetch is reached. Args: idx (int): The index of self.data_list. Returns: dict: The idx-th image and data information of dataset after ``self.pipeline``. """ if not self.test_mode: return self.prepare_train_data(idx) return self.prepare_test_data(idx) def __repr__(self): """Print ``self.transforms`` in sequence. Returns: str: Formatted string. """ dataset_name = self.__class__ imgs_root = self.data_root num_imgs = len(self) return (f'dataset_name: {dataset_name}, total {num_imgs} images in ' f'imgs_root: {imgs_root}') ================================================ FILE: mmagic/datasets/imagenet_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Union from mmagic.registry import DATASETS from .basic_conditional_dataset import BasicConditionalDataset from .categories import IMAGENET_CATEGORIES @DATASETS.register_module() class ImageNet(BasicConditionalDataset): """`ImageNet `_ Dataset. The dataset supports two kinds of annotation format. More details can be found in :class:`CustomDataset`. Args: ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str): The root directory for ``data_prefix`` and ``ann_file``. Defaults to ''. data_prefix (str | dict): Prefix for training data. Defaults to ''. **kwargs: Other keyword arguments in :class:`CustomDataset` and :class:`BaseDataset`. """ # noqa: E501 IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif') METAINFO = {'classes': IMAGENET_CATEGORIES} def __init__(self, ann_file: str = '', metainfo: Optional[dict] = None, data_root: str = '', data_prefix: Union[str, dict] = '', **kwargs): kwargs = {'extensions': self.IMG_EXTENSIONS, **kwargs} super().__init__( ann_file=ann_file, metainfo=metainfo, data_root=data_root, data_prefix=data_prefix, **kwargs) ================================================ FILE: mmagic/datasets/mscoco_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import random from typing import Optional, Sequence, Union import mmengine from mmengine.fileio import get_file_backend from mmagic.registry import DATASETS from .basic_conditional_dataset import BasicConditionalDataset @DATASETS.register_module() @DATASETS.register_module('MSCOCO') class MSCoCoDataset(BasicConditionalDataset): """MSCoCo 2014 dataset. Args: ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str): The root directory for ``data_prefix`` and ``ann_file``. Defaults to ''. drop_caption_rate (float, optional): Rate of dropping caption, used for training. Defaults to 0.0. phase (str, optional): Subdataset used for certain phase, can be set to `train`, `test` and `val`. Defaults to 'train'. year (int, optional): Version of CoCo dataset, can be set to 2014 and 2017. Defaults to 2014. data_prefix (str | dict): Prefix for the data. Defaults to ''. extensions (Sequence[str]): A sequence of allowed extensions. Defaults to ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif'). lazy_init (bool): Whether to load annotation during instantiation. In some cases, such as visualization, only the meta information of the dataset is needed, which is not necessary to load annotation file. ``Basedataset`` can skip load annotations to save time by set ``lazy_init=False``. Defaults to False. caption_style (str): If you want to add a style description for each caption, you can set caption_style to your style prompt. For example, 'realistic style'. Defaults to empty str. **kwargs: Other keyword arguments in :class:`BaseDataset`. """ METAINFO = dict(dataset_type='text_image_dataset', task_name='editing') def __init__(self, ann_file: str = '', metainfo: Optional[dict] = None, data_root: str = '', drop_caption_rate=0.0, phase='train', year=2014, data_prefix: Union[str, dict] = '', extensions: Sequence[str] = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif'), lazy_init: bool = False, classes: Union[str, Sequence[str], None] = None, caption_style: str = '', **kwargs): ann_file = os.path.join('annotations', 'captions_' + phase + f'{year}.json') if ann_file == '' else ann_file self.year = year assert self.year == 2014 or self.year == 2017, \ 'Caption is only supported in 2014 or 2017.' self.image_prename = '' if self.year == 2014: self.image_prename = 'COCO_' + phase + f'{year}_' self.phase = phase self.drop_rate = drop_caption_rate self.caption_style = caption_style super().__init__( ann_file=ann_file, metainfo=metainfo, data_root=data_root, data_prefix=data_prefix, extensions=extensions, lazy_init=lazy_init, classes=classes, **kwargs) def load_data_list(self): """Load image paths and gt_labels.""" if self.img_prefix: file_backend = get_file_backend(uri=self.img_prefix) json_file = mmengine.fileio.io.load(self.ann_file) def add_prefix(filename, prefix=''): if not prefix: return filename else: return file_backend.join_path(prefix, filename) data_list = [] for item in json_file['annotations']: image_name = self.image_prename + str( item['image_id']).zfill(12) + '.jpg' img_path = add_prefix( os.path.join(self.phase + str(self.year), image_name), self.img_prefix) caption = item['caption'].lower() if self.caption_style != '': caption = caption + ' ' + self.caption_style info = { 'img_path': img_path, 'gt_prompt': caption if (self.phase != 'train' or self.drop_rate < 1e-6 or random.random() >= self.drop_rate) else '' } data_list.append(info) return data_list ================================================ FILE: mmagic/datasets/paired_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from typing import Optional from mmengine.dataset import BaseDataset from mmengine.fileio import get_file_backend from mmagic.registry import DATASETS IMG_EXTENSIONS = ('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tif', '.TIF', '.tiff', '.TIFF') @DATASETS.register_module() class PairedImageDataset(BaseDataset): """General paired image folder dataset for image generation. It assumes that the training directory is '/path/to/data/train'. During test time, the directory is '/path/to/data/test'. '/path/to/data' can be initialized by args 'dataroot'. Each sample contains a pair of images concatenated in the w dimension (A|B). Args: dataroot (str | :obj:`Path`): Path to the folder root of paired images. pipeline (List[dict | callable]): A sequence of data transformations. test_mode (bool): Store `True` when building test dataset. Default: `False`. test_dir (str): Subfolder of dataroot which contain test images. Default: 'test'. """ def __init__(self, data_root, pipeline, io_backend: Optional[str] = None, test_mode=False, test_dir='test'): phase = test_dir if test_mode else 'train' self.data_root = osp.join(str(data_root), phase) if io_backend is None: self.file_backend = get_file_backend(uri=data_root) else: self.file_backend = get_file_backend( backend_args={'backend': io_backend}) super().__init__( data_root=self.data_root, pipeline=pipeline, test_mode=test_mode) # self.data_infos = self.load_annotations() def load_data_list(self): """Load paired image paths. Returns: list[dict]: List that contains paired image paths. """ data_infos = [] pair_paths = sorted(self.scan_folder(self.data_root)) for pair_path in pair_paths: data_infos.append(dict(pair_path=pair_path)) return data_infos def scan_folder(self, path): """Obtain image path list (including sub-folders) from a given folder. Args: path (str | :obj:`Path`): Folder path. Returns: list[str]: Image list obtained from the given folder. """ imgs_list = self.file_backend.list_dir_or_file( path, list_dir=False, suffix=IMG_EXTENSIONS, recursive=True) images = [self.file_backend.join_path(path, img) for img in imgs_list] assert images, f'{path} has no valid image file.' return images ================================================ FILE: mmagic/datasets/singan_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import mmcv import numpy as np from mmengine.dataset import BaseDataset from mmagic.registry import DATASETS def create_real_pyramid(real, min_size, max_size, scale_factor_init): """Create image pyramid. This function is modified from the official implementation: https://github.com/tamarott/SinGAN/blob/master/SinGAN/functions.py#L221 In this implementation, we adopt the rescaling function from MMCV. Args: real (np.array): The real image array. min_size (int): The minimum size for the image pyramid. max_size (int): The maximum size for the image pyramid. scale_factor_init (float): The initial scale factor. """ num_scales = int( np.ceil( np.log(np.power(min_size / min(real.shape[0], real.shape[1]), 1)) / np.log(scale_factor_init))) + 1 scale2stop = int( np.ceil( np.log( min([max_size, max([real.shape[0], real.shape[1]])]) / max([real.shape[0], real.shape[1]])) / np.log(scale_factor_init))) stop_scale = num_scales - scale2stop scale1 = min(max_size / max([real.shape[0], real.shape[1]]), 1) real_max = mmcv.imrescale(real, scale1) scale_factor = np.power( min_size / (min(real_max.shape[0], real_max.shape[1])), 1 / (stop_scale)) scale2stop = int( np.ceil( np.log( min([max_size, max([real.shape[0], real.shape[1]])]) / max([real.shape[0], real.shape[1]])) / np.log(scale_factor_init))) stop_scale = num_scales - scale2stop reals = [] for i in range(stop_scale + 1): scale = np.power(scale_factor, stop_scale - i) curr_real = mmcv.imrescale(real, scale) reals.append(curr_real) return reals, scale_factor, stop_scale @DATASETS.register_module() class SinGANDataset(BaseDataset): """SinGAN Dataset. In this dataset, we create an image pyramid and save it in the cache. Args: img_path (str): Path to the single image file. min_size (int): Min size of the image pyramid. Here, the number will be set to the ``min(H, W)``. max_size (int): Max size of the image pyramid. Here, the number will be set to the ``max(H, W)``. scale_factor_init (float): Rescale factor. Note that the actual factor we use may be a little bit different from this value. num_samples (int, optional): The number of samples (length) in this dataset. Defaults to -1. """ def __init__(self, data_root, min_size, max_size, scale_factor_init, pipeline, num_samples=-1): self.min_size = min_size self.max_size = max_size self.scale_factor_init = scale_factor_init self.num_samples = num_samples super().__init__(data_root=data_root, pipeline=pipeline) def full_init(self): """Skip the full init process for SinGANDataset.""" self.load_data_list(self.min_size, self.max_size, self.scale_factor_init) def load_data_list(self, min_size, max_size, scale_factor_init): """Load annotations for SinGAN Dataset. Args: min_size (int): The minimum size for the image pyramid. max_size (int): The maximum size for the image pyramid. scale_factor_init (float): The initial scale factor. """ real = mmcv.imread(self.data_root) self.reals, self.scale_factor, self.stop_scale = create_real_pyramid( real, min_size, max_size, scale_factor_init) self.data_dict = {} for i, real in enumerate(self.reals): self.data_dict[f'real_scale{i}'] = real self.data_dict['input_sample'] = np.zeros_like( self.data_dict['real_scale0']).astype(np.float32) def __getitem__(self, index): """Get `:attr:self.data_dict`. For SinGAN, we use single image with different resolution to train the model. Args: idx (int): This will be ignored in :class:`SinGANDataset`. Returns: dict: Dict contains input image in different resolution. ``self.pipeline``. """ return self.pipeline(deepcopy(self.data_dict)) def __len__(self): """Get the length of filtered dataset and automatically call ``full_init`` if the dataset has not been fully init. Returns: int: The length of filtered dataset. """ return int(1e6) if self.num_samples < 0 else self.num_samples ================================================ FILE: mmagic/datasets/textual_inversion_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from random import choice from typing import Callable, List, Union from mmengine import FileClient from mmengine.dataset import BaseDataset from mmagic.registry import DATASETS @DATASETS.register_module() class TextualInversionDataset(BaseDataset): """Dataset for Textual Inversion and ViCo. Args: data_root (str): Path to the data root. concept_dir (str): Path to the concept images. placeholder (str): A string to denote the concept. template (list[str]): A list of strings like 'A photo of {}'. with_image_reference (bool): Is used for vico training. pipeline (list[dict | callable]): A sequence of data transforms. """ def __init__( self, data_root: str, concept_dir: str, placeholder: str, template: str, # used for vico training with_image_reference: bool = False, pipeline: List[Union[dict, Callable]] = []): data_prefix = dict(img_path=concept_dir) self.placeholder = placeholder if osp.exists(osp.join(data_root, concept_dir)): self.num_images = len(os.listdir(osp.join(data_root, concept_dir))) if osp.exists(template): with open(template, 'r') as file: self.template = file.readlines() self.with_image_reference = with_image_reference super().__init__( data_root=data_root, data_prefix=data_prefix, pipeline=pipeline) def load_data_list(self) -> list: """Load data list from concept_dir and class_dir.""" data_list = [] img_dir = self.data_prefix['img_path'] file_client = FileClient.infer_client(uri=img_dir) img_dir = osp.abspath(img_dir) for data_name in file_client.list_dir_or_file(img_dir, list_dir=False): data_info = dict( img_path=file_client.join_path(img_dir, data_name)) data_list.append(data_info) return data_list def prepare_data(self, idx): """Get data processed by ``self.pipeline``. Args: idx (int): The index of ``data_info``. Returns: Any: Depends on ``self.pipeline``. """ data_info = self.get_data_info(idx) if self.with_image_reference: numbers = list(range(self.num_images)) if len(numbers) > 1: numbers.remove(idx % self.num_images) img_dir = self.data_prefix['img_path'] file_client = FileClient.infer_client(uri=img_dir) img_dir = osp.abspath(img_dir) data_names = list( file_client.list_dir_or_file(img_dir, list_dir=False)) image_ref_path = file_client.join_path(img_dir, data_names[choice(numbers)]) data_info['img_ref_path'] = image_ref_path # load random template selected_template = choice(self.template) prompt = selected_template.format(self.placeholder) data_info['prompt'] = prompt return self.pipeline(data_info) ================================================ FILE: mmagic/datasets/transforms/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .albu_function import AlbuCorruptFunction, PairedAlbuTransForms from .albumentations import Albumentations from .alpha import GenerateSeg, GenerateSoftSeg from .aug_frames import MirrorSequence, TemporalReverse from .aug_pixel import (BinarizeImage, Clip, ColorJitter, RandomAffine, RandomMaskDilation, UnsharpMasking) from .aug_shape import (Flip, NumpyPad, RandomRotation, RandomTransposeHW, Resize) from .crop import (CenterCropLongEdge, Crop, CropAroundCenter, CropAroundFg, CropAroundUnknown, CropLike, FixedCrop, InstanceCrop, ModCrop, PairedRandomCrop, RandomCropLongEdge, RandomResizedCrop) from .fgbg import (CompositeFg, MergeFgAndBg, PerturbBg, RandomJitter, RandomLoadResizeBg) from .formatting import PackInputs from .generate_assistant import (GenerateCoordinateAndCell, GenerateFacialHeatmap) from .generate_frame_indices import (GenerateFrameIndices, GenerateFrameIndiceswithPadding, GenerateSegmentIndices) from .get_masked_image import GetMaskedImage from .loading import (GetSpatialDiscountMask, LoadImageFromFile, LoadMask, LoadPairedImageFromFile) from .matlab_like_resize import MATLABLikeResize from .normalization import Normalize, RescaleToZeroOne from .random_degradations import (DegradationsWithShuffle, RandomBlur, RandomJPEGCompression, RandomNoise, RandomResize, RandomVideoCompression) from .random_down_sampling import RandomDownSampling from .trimap import (FormatTrimap, GenerateTrimap, GenerateTrimapWithDistTransform, TransformTrimap) from .values import CopyValues, SetValues __all__ = [ 'BinarizeImage', 'Clip', 'ColorJitter', 'CopyValues', 'Crop', 'CropLike', 'DegradationsWithShuffle', 'LoadImageFromFile', 'LoadMask', 'Flip', 'FixedCrop', 'GenerateCoordinateAndCell', 'GenerateFacialHeatmap', 'GenerateFrameIndices', 'GenerateFrameIndiceswithPadding', 'GenerateSegmentIndices', 'GetMaskedImage', 'GetSpatialDiscountMask', 'MATLABLikeResize', 'MirrorSequence', 'ModCrop', 'Normalize', 'PackInputs', 'PairedRandomCrop', 'RandomAffine', 'RandomBlur', 'RandomDownSampling', 'RandomJPEGCompression', 'RandomMaskDilation', 'RandomNoise', 'RandomResize', 'RandomResizedCrop', 'RandomRotation', 'RandomTransposeHW', 'RandomVideoCompression', 'RescaleToZeroOne', 'Resize', 'SetValues', 'TemporalReverse', 'ToTensor', 'UnsharpMasking', 'CropAroundCenter', 'CropAroundFg', 'GenerateSeg', 'CropAroundUnknown', 'GenerateSoftSeg', 'FormatTrimap', 'TransformTrimap', 'GenerateTrimap', 'GenerateTrimapWithDistTransform', 'CompositeFg', 'RandomLoadResizeBg', 'MergeFgAndBg', 'PerturbBg', 'RandomJitter', 'LoadPairedImageFromFile', 'CenterCropLongEdge', 'RandomCropLongEdge', 'NumpyPad', 'InstanceCrop', 'Albumentations', 'AlbuCorruptFunction', 'PairedAlbuTransForms' ] ================================================ FILE: mmagic/datasets/transforms/albu_function.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List import albumentations as albu from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class PairedAlbuTransForms(BaseTransform): """PairedAlbuTransForms augmentation. Apply the same AlbuTransforms augmentation to paired images. """ def __init__(self, size: int, lq_key: str = 'img', gt_key: str = 'gt', scope: str = 'geometric', crop: str = 'random', p: float = 0.5): self.size = size self.lq_key = lq_key self.gt_key = gt_key self.scope = scope self.crop = crop self.p = p augs = { 'weak': albu.Compose([ albu.HorizontalFlip(), ], p=self.p), 'geometric': albu.OneOf([ albu.HorizontalFlip(always_apply=True), albu.ShiftScaleRotate(always_apply=True), albu.Transpose(always_apply=True), albu.OpticalDistortion(always_apply=True), albu.ElasticTransform(always_apply=True), ], p=self.p) } aug_fn = augs[self.scope] crop_fn = { 'random': albu.RandomCrop(self.size, self.size, always_apply=True), 'center': albu.CenterCrop(self.size, self.size, always_apply=True) }[self.crop] pad = albu.PadIfNeeded(self.size, self.size) self.pipeline = albu.Compose([aug_fn, pad, crop_fn], additional_targets={'target': 'image'}) def transform(self, results): """processing input results according to `self.pipeline`. Args: results (dict): contains the processed data through the transform pipeline. Returns: results: the processed data. """ r = self.pipeline( image=results[self.lq_key], target=results[self.gt_key]) results[self.lq_key] = r['image'] results[self.gt_key] = r['target'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(size={self.size}, ' f'lq_key={self.lq_key}, ' f'gt_key={self.gt_key}, ' f'scope={self.scope}, ' f'crop={self.crop}, ' f'p={self.p})') return repr_str @TRANSFORMS.register_module() class AlbuTransForms(BaseTransform): """AlbuTransForms augmentation. Apply the same AlbuTransForms augmentation to the input images. """ def __init__(self, size: int, keys: List, scope: str = 'geometric', crop: str = 'random', p: float = 0.5): self.size = size self.keys = keys self.scope = scope self.crop = crop self.p = p augs = { 'weak': albu.Compose([ albu.HorizontalFlip(), ]), 'geometric': albu.OneOf([ albu.HorizontalFlip(always_apply=True), albu.ShiftScaleRotate(always_apply=True), albu.Transpose(always_apply=True), albu.OpticalDistortion(always_apply=True), albu.ElasticTransform(always_apply=True), ], p=self.p) } aug_fn = augs[self.scope] crop_fn = { 'random': albu.RandomCrop(self.size, self.size, always_apply=True), 'center': albu.CenterCrop(self.size, self.size, always_apply=True) }[self.crop] pad = albu.PadIfNeeded(self.size, self.size) self.pipeline = albu.Compose([aug_fn, pad, crop_fn]) def transform(self, results): """processing input results according to `self.pipeline`. Args: results (dict): contains the processed data through the transform pipeline. Returns: results: the processed data. """ for key in self.keys: r = self.pipeline(image=results[key]) results[key] = r['image'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(size={self.size}, ' f'keys={self.keys}, ' f'scope={self.scope}, ' f'crop={self.crop}, ' f'p={self.p})') return repr_str @TRANSFORMS.register_module() class PairedAlbuNormalize(BaseTransform): """PairedAlbuNormalize augmentation. Apply the same AlbuNormalize augmentation to the paired images. """ def __init__(self, lq_key: str, gt_key: str, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), max_pixel_value: float = 255.0, always_apply: bool = False, p: float = 1.0): self.lq_key = lq_key self.gt_key = gt_key self.mean = mean self.std = std self.max_pixel_value = max_pixel_value self.always_apply = always_apply self.p = p normalize = albu.Normalize( mean=self.mean, std=self.std, max_pixel_value=self.max_pixel_value, always_apply=self.always_apply, p=self.p) self.normalize = albu.Compose([normalize], additional_targets={'target': 'image'}) def transform(self, results): """processing input results according to `self.normalize`. Args: results (dict): contains the processed data through the transform pipeline. Returns: results: the processed data. """ if self.gt_key not in results.keys(): r = self.normalize(image=results[self.lq_key]) else: r = self.normalize( image=results[self.lq_key], target=results[self.gt_key]) results[self.gt_key] = r['target'] results[self.lq_key] = r['image'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(lq_key={self.lq_key}, ' f'gt_key={self.gt_key}, ' f'mean={self.mean}, ' f'std={self.std}, ' f'max_pixel_value={self.max_pixel_value}, ' f'always_apply={self.always_apply}, ' f'p={self.p}) ') return repr_str @TRANSFORMS.register_module() class AlbuNormalize(BaseTransform): """AlbuNormalize augmentation. Apply the same AlbuNormalize augmentation to the input images. """ def __init__(self, keys: List, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), max_pixel_value: float = 255.0, always_apply: bool = False, p: float = 1.0): self.keys = keys self.mean = mean self.std = std self.max_pixel_value = max_pixel_value self.always_apply = always_apply self.p = p normalize = albu.Normalize( mean=self.mean, std=self.std, max_pixel_value=self.max_pixel_value, always_apply=self.always_apply, p=self.p) self.normalize = albu.Compose([normalize]) def transform(self, results): """processing input results according to `self.normalize`. Args: results (dict): contains the processed data through the transform pipeline. Returns: results: the processed data. """ for key in self.keys: r = self.normalize(image=results[key]) results[key] = r['image'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, ' f'mean={self.mean}, ' f'std={self.std}, ' f'max_pixel_value={self.max_pixel_value}, ' f'always_apply={self.always_apply}, ' f'p={self.p}) ') return repr_str def _resolve_aug_fn(name): d = { 'cutout': albu.Cutout, 'rgb_shift': albu.RGBShift, 'hsv_shift': albu.HueSaturationValue, 'motion_blur': albu.MotionBlur, 'median_blur': albu.MedianBlur, 'snow': albu.RandomSnow, 'shadow': albu.RandomShadow, 'fog': albu.RandomFog, 'brightness_contrast': albu.RandomBrightnessContrast, 'gamma': albu.RandomGamma, 'sun_flare': albu.RandomSunFlare, 'sharpen': albu.Sharpen, 'jpeg': albu.ImageCompression, 'gray': albu.ToGray, 'pixelize': albu.Downscale, # ToDo: partial gray } return d[name] @TRANSFORMS.register_module() class AlbuCorruptFunction(BaseTransform): """AlbuCorruptFunction augmentation. Apply the same AlbuCorruptFunction augmentation to the input images. """ def __init__(self, keys: List[str], config: List[dict], p: float = 1.0): self.keys = keys self.config = config self.p = p augs = [] for aug_params in self.config: name = aug_params.pop('name') cls = _resolve_aug_fn(name) prob = aug_params.pop('prob') if 'prob' in aug_params else .5 augs.append(cls(p=prob, **aug_params)) self.augs = albu.OneOf(augs, p=self.p) def transform(self, results): """processing input results according to `self.augs`. Args: results (dict): contains the processed data through the transform pipeline. Returns: results: the processed data. """ for key in self.keys: results[key] = self.augs(image=results[key])['image'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, ' f'config={self.config}, ' f'p={self.p}) ') return repr_str ================================================ FILE: mmagic/datasets/transforms/albumentations.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import inspect from typing import List import numpy as np from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS try: import albumentations from albumentations import Compose except ImportError: albumentations = None Compose = None @TRANSFORMS.register_module() class Albumentations(BaseTransform): """Albumentation augmentation. Adds custom transformations from Albumentations library. Please, visit `https://github.com/albumentations-team/albumentations` and `https://albumentations.ai/docs/getting_started/transforms_and_targets` to get more information. An example of ``transforms`` is as followed: .. code-block:: albu_transforms = [ dict( type='Resize', height=100, width=100, ), dict( type='RandomFog', p=0.5, ), dict( type='RandomRain', p=0.5 ), dict( type='RandomSnow', p=0.5, ), ] pipeline = [ dict( type='LoadImageFromFile', key='img', color_type='color', channel_order='rgb', imdecode_backend='cv2'), dict( type='Albumentations', keys=['img'], transforms=albu_transforms), dict(type='PackInputs') ] Args: keys (list[str]): A list specifying the keys whose values are modified. transforms (list[dict]): A list of albu transformations. """ def __init__(self, keys: List[str], transforms: List[dict]) -> None: if Compose is None: raise RuntimeError('Please install albumentations') self.keys = keys # Args will be modified later, copying it will be safer transforms = copy.deepcopy(transforms) self.transforms = transforms self.aug = Compose([self.albu_builder(t) for t in self.transforms]) def albu_builder(self, cfg: dict) -> albumentations: """Import a module from albumentations. It inherits some of :func:`build_from_cfg` logic. Args: cfg (dict): Config dict. It should at least contain the key "type". Returns: obj: The constructed object. """ assert isinstance(cfg, dict) and 'type' in cfg args = cfg.copy() obj_type = args.pop('type') if isinstance(obj_type, str): if albumentations is None: raise RuntimeError('Please install albumentations') obj_cls = getattr(albumentations, obj_type) elif inspect.isclass(obj_type): obj_cls = obj_type else: raise TypeError( f'type must be a str or valid type, but got {type(obj_type)}') if 'transforms' in args: args['transforms'] = [ self.albu_builder(transform) for transform in args['transforms'] ] return obj_cls(**args) def _apply_albu(self, imgs): is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] outputs = [] for img in imgs: outputs.append(self.aug(image=img)['image']) if is_single_image: outputs = outputs[0] return outputs def transform(self, results): """Transform function of Albumentations.""" for k in self.keys: results[k] = self._apply_albu(results[k]) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += f'(keys={self.keys}, transforms={self.transforms})' return repr_str ================================================ FILE: mmagic/datasets/transforms/alpha.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Augmentation on alpha matte.""" # Not used in current algorithms import random import cv2 import numpy as np from mmcv.transforms import BaseTransform from mmengine.utils import is_list_of, is_tuple_of from mmagic.registry import TRANSFORMS from mmagic.utils import random_choose_unknown @TRANSFORMS.register_module() class GenerateSeg(BaseTransform): """Generate segmentation mask from alpha matte. Args: kernel_size (int, optional): Kernel size for both erosion and dilation. The kernel will have the same height and width. Defaults to 5. erode_iter_range (tuple, optional): Iteration of erosion. Defaults to (10, 20). dilate_iter_range (tuple, optional): Iteration of dilation. Defaults to (15, 30). num_holes_range (tuple, optional): Range of number of holes to randomly select from. Defaults to (0, 3). hole_sizes (list, optional): List of (h, w) to be selected as the size of the rectangle hole. Defaults to [(15, 15), (25, 25), (35, 35), (45, 45)]. blur_ksizes (list, optional): List of (h, w) to be selected as the kernel_size of the gaussian blur. Defaults to [(21, 21), (31, 31), (41, 41)]. """ def __init__(self, kernel_size=5, erode_iter_range=(10, 20), dilate_iter_range=(15, 30), num_holes_range=(0, 3), hole_sizes=[(15, 15), (25, 25), (35, 35), (45, 45)], blur_ksizes=[(21, 21), (31, 31), (41, 41)]): self.kernel_size = kernel_size self.erode_iter_range = erode_iter_range self.dilate_iter_range = dilate_iter_range self.num_holes_range = num_holes_range self.hole_sizes = hole_sizes self.blur_ksizes = blur_ksizes @staticmethod def _crop_hole(img, start_point, hole_size): """Create a all-zero rectangle hole in the image. Args: img (np.ndarray): Source image. start_point (tuple[int]): The top-left point of the rectangle. hole_size (tuple[int]): The height and width of the rectangle hole. Return: np.ndarray: The cropped image. """ top, left = start_point bottom = top + hole_size[0] right = left + hole_size[1] height, weight = img.shape[:2] if top < 0 or bottom > height or left < 0 or right > weight: raise ValueError(f'crop area {(left, top, right, bottom)} exceeds ' f'image size {(height, weight)}') img[top:bottom, left:right] = 0 return img def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ alpha = results['alpha'] trimap = results['trimap'] # generate segmentation mask kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (self.kernel_size, self.kernel_size)) seg = (alpha > 0.5).astype(np.float32) seg = cv2.erode( seg, kernel, iterations=np.random.randint(*self.erode_iter_range)) seg = cv2.dilate( seg, kernel, iterations=np.random.randint(*self.dilate_iter_range)) # generate some holes in segmentation mask num_holes = np.random.randint(*self.num_holes_range) for _ in range(num_holes): hole_size = random.choice(self.hole_sizes) unknown = trimap == 128 start_point = random_choose_unknown(unknown, hole_size) seg = self._crop_hole(seg, start_point, hole_size) trimap = self._crop_hole(trimap, start_point, hole_size) # perform gaussian blur to segmentation mask seg = cv2.GaussianBlur(seg, random.choice(self.blur_ksizes), 0) results['seg'] = seg.astype(np.uint8) results['num_holes'] = num_holes return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += ( f'(kernel_size={self.kernel_size}, ' f'erode_iter_range={self.erode_iter_range}, ' f'dilate_iter_range={self.dilate_iter_range}, ' f'num_holes_range={self.num_holes_range}, ' f'hole_sizes={self.hole_sizes}, blur_ksizes={self.blur_ksizes}') return repr_str @TRANSFORMS.register_module() class GenerateSoftSeg(BaseTransform): """Generate soft segmentation mask from input segmentation mask. Required key is "seg", added key is "soft_seg". Args: fg_thr (float, optional): Threshold of the foreground in the normalized input segmentation mask. Defaults to 0.2. border_width (int, optional): Width of border to be padded to the bottom of the mask. Defaults to 25. erode_ksize (int, optional): Fixed kernel size of the erosion. Defaults to 5. dilate_ksize (int, optional): Fixed kernel size of the dilation. Defaults to 5. erode_iter_range (tuple, optional): Iteration of erosion. Defaults to (10, 20). dilate_iter_range (tuple, optional): Iteration of dilation. Defaults to (3, 7). blur_ksizes (list, optional): List of (h, w) to be selected as the kernel_size of the gaussian blur. Defaults to [(21, 21), (31, 31), (41, 41)]. """ def __init__(self, fg_thr=0.2, border_width=25, erode_ksize=3, dilate_ksize=5, erode_iter_range=(10, 20), dilate_iter_range=(3, 7), blur_ksizes=[(21, 21), (31, 31), (41, 41)]): if not isinstance(fg_thr, float): raise TypeError(f'fg_thr must be a float, but got {type(fg_thr)}') if not isinstance(border_width, int): raise TypeError( f'border_width must be an int, but got {type(border_width)}') if not isinstance(erode_ksize, int): raise TypeError( f'erode_ksize must be an int, but got {type(erode_ksize)}') if not isinstance(dilate_ksize, int): raise TypeError( f'dilate_ksize must be an int, but got {type(dilate_ksize)}') if (not is_tuple_of(erode_iter_range, int) or len(erode_iter_range) != 2): raise TypeError('erode_iter_range must be a tuple of 2 int, ' f'but got {erode_iter_range}') if (not is_tuple_of(dilate_iter_range, int) or len(dilate_iter_range) != 2): raise TypeError('dilate_iter_range must be a tuple of 2 int, ' f'but got {dilate_iter_range}') if not is_list_of(blur_ksizes, tuple): raise TypeError( f'blur_ksizes must be a list of tuple, but got {blur_ksizes}') self.fg_thr = fg_thr self.border_width = border_width self.erode_ksize = erode_ksize self.dilate_ksize = dilate_ksize self.erode_iter_range = erode_iter_range self.dilate_iter_range = dilate_iter_range self.blur_ksizes = blur_ksizes def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ seg = results['seg'].astype(np.float32) / 255 height, _ = seg.shape[:2] seg[seg > self.fg_thr] = 1 # to align with the original repo, pad the bottom of the mask seg = cv2.copyMakeBorder(seg, 0, self.border_width, 0, 0, cv2.BORDER_REPLICATE) # erode/dilate segmentation mask erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (self.erode_ksize, self.erode_ksize)) dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (self.dilate_ksize, self.dilate_ksize)) seg = cv2.erode( seg, erode_kernel, iterations=np.random.randint(*self.erode_iter_range)) seg = cv2.dilate( seg, dilate_kernel, iterations=np.random.randint(*self.dilate_iter_range)) # perform gaussian blur to segmentation mask seg = cv2.GaussianBlur(seg, random.choice(self.blur_ksizes), 0) # remove the padded rows seg = (seg * 255).astype(np.uint8) seg = np.delete(seg, range(height, height + self.border_width), 0) results['soft_seg'] = seg return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(fg_thr={self.fg_thr}, ' f'border_width={self.border_width}, ' f'erode_ksize={self.erode_ksize}, ' f'dilate_ksize={self.dilate_ksize}, ' f'erode_iter_range={self.erode_iter_range}, ' f'dilate_iter_range={self.dilate_iter_range}, ' f'blur_ksizes={self.blur_ksizes})') return repr_str ================================================ FILE: mmagic/datasets/transforms/aug_frames.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class MirrorSequence(BaseTransform): """Extend short sequences (e.g. Vimeo-90K) by mirroring the sequences. Given a sequence with N frames (x1, ..., xN), extend the sequence to (x1, ..., xN, xN, ..., x1). Required Keys: - [KEYS] Modified Keys: - [KEYS] Args: keys (list[str]): The frame lists to be extended. """ def __init__(self, keys): self.keys = keys def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: if isinstance(results[key], list): results[key] = results[key] + results[key][::-1] else: raise TypeError('The input must be of class list[nparray]. ' f'Got {type(results[key])}.') return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys})') return repr_str @TRANSFORMS.register_module() class TemporalReverse(BaseTransform): """Reverse frame lists for temporal augmentation. Required keys are the keys in attributes "lq" and "gt", added or modified keys are "lq", "gt" and "reverse". Args: keys (list[str]): The frame lists to be reversed. reverse_ratio (float): The probability to reverse the frame lists. Default: 0.5. """ def __init__(self, keys, reverse_ratio=0.5): self.keys = keys self.reverse_ratio = reverse_ratio def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ reverse = np.random.random() < self.reverse_ratio if reverse: for key in self.keys: results[key].reverse() results['reverse'] = reverse return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += f'(keys={self.keys}, reverse_ratio={self.reverse_ratio})' return repr_str ================================================ FILE: mmagic/datasets/transforms/aug_pixel.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import numbers import random from typing import Dict import cv2 import numpy as np import torch import torchvision.transforms as transforms from mmcv.transforms import BaseTransform from PIL import Image from mmagic.registry import TRANSFORMS class BinarizeImage(BaseTransform): """Binarize image. Args: keys (Sequence[str]): The images to be binarized. binary_thr (float): Threshold for binarization. a_min (int): Lower limits of pixel value. a_max (int): Upper limits of pixel value. dtype (np.dtype): Set the data type of the output. Default: np.uint8 """ def __init__(self, keys, binary_thr, a_min=0, a_max=1, dtype=np.uint8): self.keys = keys self.binary_thr = binary_thr self.a_min = a_min self.a_max = a_max self.dtype = dtype def _binarize(self, img): """Binarize image. Args: img (np.ndarray): Input image. Returns: img (np.ndarray): Output image. """ # Binarize to 0/1 img = (img[..., :] > self.binary_thr).astype(np.uint8) if self.a_min != 0 or self.a_max != 1 or self.dtype != np.uint8: img = img * (self.a_max - self.a_min) + self.a_min img = img.astype(self.dtype) return img def transform(self, results): """The transform function of BinarizeImage. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for k in self.keys: results[k] = self._binarize(results[k]) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += ( f'(keys={self.keys}, binary_thr={self.binary_thr}, ' f'a_min={self.a_min}, a_max={self.a_max}, dtype={self.dtype})') return repr_str @TRANSFORMS.register_module() class Clip(BaseTransform): """Clip the pixels. Modified keys are the attributes specified in "keys". Args: keys (list[str]): The keys whose values are clipped. a_min (int): Lower limits of pixel value. a_max (int): Upper limits of pixel value. """ def __init__(self, keys, a_min=0, a_max=255): self.keys = keys self.a_min = a_min self.a_max = a_max def _clip(self, input_): """Clip the pixels. Args: input_ (Union[List, np.ndarray]): Pixels to clip. Returns: Union[List, np.ndarray]: Clipped pixels. """ is_single_image = False if isinstance(input_, np.ndarray): is_single_image = True input_ = [input_] # clip input_ = [np.clip(v, self.a_min, self.a_max) for v in input_] if is_single_image: input_ = input_[0] return input_ def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict with the values of the specified keys are rounded and clipped. """ for key in self.keys: results[key] = self._clip(results[key]) return results def __repr__(self): result = self.__class__.__name__ result += f'(a_min={self.a_min}, a_max={self.a_max})' return result @TRANSFORMS.register_module() class ColorJitter(BaseTransform): """An interface for torch color jitter so that it can be invoked in mmagic pipeline. Randomly change the brightness, contrast and saturation of an image. Modified keys are the attributes specified in "keys". Required Keys: - [KEYS] Modified Keys: - [KEYS] Args: keys (list[str]): The images to be resized. channel_order (str): Order of channel, candidates are 'bgr' and 'rgb'. Default: 'rgb'. Notes: ``**kwards`` follows the args list of ``torchvision.transforms.ColorJitter``. brightness (float or tuple of float (min, max)): How much to jitter brightness. brightness_factor is chosen uniformly from [max(0, 1 - brightness), 1 + brightness] or the given [min, max]. Should be non negative numbers. contrast (float or tuple of float (min, max)): How much to jitter contrast. contrast_factor is chosen uniformly from [max(0, 1 - contrast), 1 + contrast] or the given [min, max]. Should be non negative numbers. saturation (float or tuple of float (min, max)): How much to jitter saturation. saturation_factor is chosen uniformly from [max(0, 1 - saturation), 1 + saturation] or the given [min, max]. Should be non negative numbers. hue (float or tuple of float (min, max)): How much to jitter hue. hue_factor is chosen uniformly from [-hue, hue] or the given [min, max]. Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5. """ def __init__(self, keys, channel_order='rgb', **kwargs): assert keys, 'Keys should not be empty.' assert 'to_rgb' not in kwargs, ( '`to_rgb` is not support in ColorJitter, ' "which is replaced by `channel_order` ('rgb' or 'bgr')") self.keys = keys self.channel_order = channel_order self._transform = transforms.ColorJitter(**kwargs) def _color_jitter(self, image, this_seed): """Color Jitter Function. Args: image (np.ndarray): Image. this_seed (int): Seed of torch. Returns: image (np.ndarray): The output image. """ if self.channel_order.lower() == 'bgr': image = image[..., ::-1] image = Image.fromarray(image) torch.manual_seed(this_seed) image = self._transform(image) image = np.asarray(image) if self.channel_order.lower() == 'bgr': image = image[..., ::-1] return image def transform(self, results: Dict) -> Dict: """The transform function of ColorJitter. Args: results (dict): The result dict. Returns: dict: The result dict. """ this_seed = random.randint(0, 2**32) for k in self.keys: if isinstance(results[k], list): results[k] = [ self._color_jitter(v, this_seed) for v in results[k] ] else: results[k] = self._color_jitter(results[k], this_seed) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, channel_order={self.channel_order}, ' f'brightness={self._transform.brightness}, ' f'contrast={self._transform.contrast}, ' f'saturation={self._transform.saturation}, ' f'hue={self._transform.hue})') return repr_str @TRANSFORMS.register_module() class RandomAffine(BaseTransform): """Apply random affine to input images. This class is adopted from https://github.com/pytorch/vision/blob/v0.5.0/torchvision/transforms/ transforms.py#L1015 It should be noted that in https://github.com/Yaoyi-Li/GCA-Matting/blob/master/dataloader/ data_generator.py#L70 random flip is added. See explanation of `flip_ratio` below. Required keys are the keys in attribute "keys", modified keys are keys in attribute "keys". Args: keys (Sequence[str]): The images to be affined. degrees (float | tuple[float]): Range of degrees to select from. If it is a float instead of a tuple like (min, max), the range of degrees will be (-degrees, +degrees). Set to 0 to deactivate rotations. translate (tuple, optional): Tuple of maximum absolute fraction for horizontal and vertical translations. For example translate=(a, b), then horizontal shift is randomly sampled in the range -img_width * a < dx < img_width * a and vertical shift is randomly sampled in the range -img_height * b < dy < img_height * b. Default: None. scale (tuple, optional): Scaling factor interval, e.g (a, b), then scale is randomly sampled from the range a <= scale <= b. Default: None. shear (float | tuple[float], optional): Range of shear degrees to select from. If shear is a float, a shear parallel to the x axis and a shear parallel to the y axis in the range (-shear, +shear) will be applied. Else if shear is a tuple of 2 values, a x-axis shear and a y-axis shear in (shear[0], shear[1]) will be applied. Default: None. flip_ratio (float, optional): Probability of the image being flipped. The flips in horizontal direction and vertical direction are independent. The image may be flipped in both directions. Default: None. """ def __init__(self, keys, degrees, translate=None, scale=None, shear=None, flip_ratio=None): self.keys = keys if isinstance(degrees, numbers.Number): assert degrees >= 0, ('If degrees is a single number, ' 'it must be positive.') self.degrees = (-degrees, degrees) else: assert isinstance(degrees, tuple) and len(degrees) == 2, \ 'degrees should be a tuple and it must be of length 2.' self.degrees = degrees if translate is not None: assert isinstance(translate, tuple) and len(translate) == 2, \ 'translate should be a tuple and it must be of length 2.' for t in translate: assert 0.0 <= t <= 1.0, ('translation values should be ' 'between 0 and 1.') self.translate = translate if scale is not None: assert isinstance(scale, tuple) and len(scale) == 2, \ 'scale should be a tuple and it must be of length 2.' for s in scale: assert s > 0, 'scale values should be positive.' self.scale = scale if shear is not None: if isinstance(shear, numbers.Number): assert shear >= 0, ('If shear is a single number, ' 'it must be positive.') self.shear = (-shear, shear) else: assert isinstance(shear, tuple) and len(shear) == 2, \ 'shear should be a tuple and it must be of length 2.' # X-Axis and Y-Axis shear with (min, max) self.shear = shear else: self.shear = shear if flip_ratio is not None: assert isinstance(flip_ratio, float), 'flip_ratio should be a float.' self.flip_ratio = flip_ratio else: self.flip_ratio = 0 @staticmethod def _get_params(degrees, translate, scale_ranges, shears, flip_ratio, img_size): """Get parameters for affine transformation. Returns: paras (tuple): Params to be passed to the affine transformation. """ angle = np.random.uniform(degrees[0], degrees[1]) if translate is not None: max_dx = translate[0] * img_size[0] max_dy = translate[1] * img_size[1] translations = (np.round(np.random.uniform(-max_dx, max_dx)), np.round(np.random.uniform(-max_dy, max_dy))) else: translations = (0, 0) if scale_ranges is not None: scale = (np.random.uniform(scale_ranges[0], scale_ranges[1]), np.random.uniform(scale_ranges[0], scale_ranges[1])) else: scale = (1.0, 1.0) if shears is not None: shear = np.random.uniform(shears[0], shears[1]) else: shear = 0.0 # Because `flip` is used as a multiplier in line 479 and 480, # so -1 stands for flip and 1 stands for no flip. Thus `flip` # should be an 'inverse' flag as the result of the comparison. # See https://github.com/open-mmlab/mmagic/pull/799 for more detail flip = (np.random.rand(2) > flip_ratio).astype(np.int32) * 2 - 1 return angle, translations, scale, shear, flip @staticmethod def _get_inverse_affine_matrix(center, angle, translate, scale, shear, flip): """Helper method to compute inverse matrix for affine transformation. As it is explained in PIL.Image.rotate, we need compute INVERSE of affine transformation matrix: M = T * C * RSS * C^-1 where T is translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]; C is translation matrix to keep center: [1, 0, cx | 0, 1, cy | 0, 0, 1]; RSS is rotation with scale and shear matrix. It is different from the original function in torchvision. 1. The order are changed to flip -> scale -> rotation -> shear. 2. x and y have different scale factors. RSS(shear, a, scale, f) = [ cos(a + shear)*scale_x*f -sin(a + shear)*scale_y 0] [ sin(a)*scale_x*f cos(a)*scale_y 0] [ 0 0 1] Thus, the inverse is M^-1 = C * RSS^-1 * C^-1 * T^-1. """ angle = math.radians(angle) shear = math.radians(shear) scale_x = 1.0 / scale[0] * flip[0] scale_y = 1.0 / scale[1] * flip[1] # Inverted rotation matrix with scale and shear d = math.cos(angle + shear) * math.cos(angle) + math.sin( angle + shear) * math.sin(angle) matrix = [ math.cos(angle) * scale_x, math.sin(angle + shear) * scale_x, 0, -math.sin(angle) * scale_y, math.cos(angle + shear) * scale_y, 0 ] matrix = [m / d for m in matrix] # Apply inverse of translation and of center translation: # RSS^-1 * C^-1 * T^-1 matrix[2] += matrix[0] * (-center[0] - translate[0]) + matrix[1] * ( -center[1] - translate[1]) matrix[5] += matrix[3] * (-center[0] - translate[0]) + matrix[4] * ( -center[1] - translate[1]) # Apply center translation: C * RSS^-1 * C^-1 * T^-1 matrix[2] += center[0] matrix[5] += center[1] return matrix def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ h, w = results[self.keys[0]].shape[:2] # if image is too small, set degree to 0 to reduce introduced dark area if np.maximum(h, w) < 1024: params = self._get_params((0, 0), self.translate, self.scale, self.shear, self.flip_ratio, (h, w)) else: params = self._get_params(self.degrees, self.translate, self.scale, self.shear, self.flip_ratio, (h, w)) center = (w * 0.5 - 0.5, h * 0.5 - 0.5) M = self._get_inverse_affine_matrix(center, *params) M = np.array(M).reshape((2, 3)) for key in self.keys: ori_ndim = results[key].ndim results[key] = cv2.warpAffine( results[key], M, (w, h), flags=cv2.INTER_NEAREST + cv2.WARP_INVERSE_MAP) if ori_ndim == 3 and results[key].ndim == 2: results[key] = results[key][..., None] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, degrees={self.degrees}, ' f'translate={self.translate}, scale={self.scale}, ' f'shear={self.shear}, flip_ratio={self.flip_ratio})') return repr_str @TRANSFORMS.register_module() class RandomMaskDilation(BaseTransform): """Randomly dilate binary masks. Args: keys (Sequence[str]): The images to be resized. binary_thr (float): Threshold for obtaining binary mask. Default: 0. kernel_min (int): Min size of dilation kernel. Default: 9. kernel_max (int): Max size of dilation kernel. Default: 49. """ def __init__(self, keys, binary_thr=0., kernel_min=9, kernel_max=49): self.keys = keys self.kernel_min = kernel_min self.kernel_max = kernel_max self.binary_thr = binary_thr def _random_dilate(self, img): kernel_size = np.random.randint(self.kernel_min, self.kernel_max + 1) kernel = np.ones((kernel_size, kernel_size), dtype=np.uint8) dilate_kernel_size = kernel_size img_ = cv2.dilate(img, kernel, iterations=1) img_ = (img_ > self.binary_thr).astype(np.float32) return img_, dilate_kernel_size def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for k in self.keys: results[k], d_kernel = self._random_dilate(results[k]) if len(results[k].shape) == 2: results[k] = np.expand_dims(results[k], axis=2) results[k + '_dilate_kernel_size'] = d_kernel return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, kernel_min={self.kernel_min}, ' f'kernel_max={self.kernel_max})') return repr_str @TRANSFORMS.register_module() class UnsharpMasking(BaseTransform): """Apply unsharp masking to an image or a sequence of images. Args: kernel_size (int): The kernel_size of the Gaussian kernel. sigma (float): The standard deviation of the Gaussian. weight (float): The weight of the "details" in the final output. threshold (float): Pixel differences larger than this value are regarded as "details". keys (list[str]): The keys whose values are processed. Added keys are "xxx_unsharp", where "xxx" are the attributes specified in "keys". """ def __init__(self, kernel_size, sigma, weight, threshold, keys): if kernel_size % 2 == 0: raise ValueError('kernel_size must be an odd number, but ' f'got {kernel_size}.') self.kernel_size = kernel_size self.sigma = sigma self.weight = weight self.threshold = threshold self.keys = keys kernel = cv2.getGaussianKernel(kernel_size, sigma) self.kernel = np.matmul(kernel, kernel.transpose()) def _unsharp_masking(self, imgs): """Unsharp masking function.""" is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] outputs = [] for img in imgs: img = img.astype(np.float32) residue = img - cv2.filter2D(img, -1, self.kernel) mask = np.float32(np.abs(residue) > self.threshold) soft_mask = cv2.filter2D(mask, -1, self.kernel) sharpened = np.clip(img + self.weight * residue, 0, 255) outputs.append(soft_mask * sharpened + (1 - soft_mask) * img) if is_single_image: outputs = outputs[0] return outputs def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: results[f'{key}_unsharp'] = self._unsharp_masking(results[key]) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, kernel_size={self.kernel_size}, ' f'sigma={self.sigma}, weight={self.weight}, ' f'threshold={self.threshold})') return repr_str ================================================ FILE: mmagic/datasets/transforms/aug_shape.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random from copy import deepcopy from typing import Dict, List, Union import mmcv import numpy as np from mmcv.transforms import BaseTransform from mmengine.utils import is_tuple_of from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class Flip(BaseTransform): """Flip the input data with a probability. Reverse the order of elements in the given data with a specific direction. The shape of the data is preserved, but the elements are reordered. Required keys are the keys in attributes "keys", added or modified keys are "flip", "flip_direction" and the keys in attributes "keys". It also supports flipping a list of images with the same flip. Required Keys: - [KEYS] Modified Keys: - [KEYS] Args: keys (Union[str, List[str]]): The images to be flipped. flip_ratio (float): The probability to flip the images. Default: 0.5. direction (str): Flip images horizontally or vertically. Options are "horizontal" | "vertical". Default: "horizontal". """ _directions = ['horizontal', 'vertical'] def __init__(self, keys, flip_ratio=0.5, direction='horizontal'): if direction not in self._directions: raise ValueError(f'Direction {direction} is not supported.' f'Currently support ones are {self._directions}') self.keys = keys if isinstance(keys, list) else [keys] self.flip_ratio = flip_ratio self.direction = direction def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ flip = np.random.random() < self.flip_ratio if flip: for key in self.keys: if isinstance(results[key], list): for v in results[key]: mmcv.imflip_(v, self.direction) else: mmcv.imflip_(results[key], self.direction) if 'flip_infos' not in results: results['flip_infos'] = [] flip_info = dict( keys=self.keys, direction=self.direction, ratio=self.flip_ratio, flip=flip) results['flip_infos'].append(flip_info) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, flip_ratio={self.flip_ratio}, ' f'direction={self.direction})') return repr_str @TRANSFORMS.register_module() class RandomRotation(BaseTransform): """Rotate the image by a randomly-chosen angle, measured in degree. Args: keys (list[str]): The images to be rotated. degrees (tuple[float] | tuple[int] | float | int): If it is a tuple, it represents a range (min, max). If it is a float or int, the range is constructed as (-degrees, degrees). """ def __init__(self, keys, degrees): if isinstance(degrees, (int, float)): if degrees < 0.0: raise ValueError('Degrees must be positive if it is a number.') else: degrees = (-degrees, degrees) elif not is_tuple_of(degrees, (int, float)): raise TypeError(f'Degrees must be float | int or tuple of float | ' 'int, but got ' f'{type(degrees)}.') self.keys = keys self.degrees = degrees def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ angle = random.uniform(self.degrees[0], self.degrees[1]) for k in self.keys: results[k] = mmcv.imrotate(results[k], angle) if results[k].ndim == 2: results[k] = np.expand_dims(results[k], axis=2) results['degrees'] = self.degrees return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, degrees={self.degrees})') return repr_str @TRANSFORMS.register_module() class RandomTransposeHW(BaseTransform): """Randomly transpose images in H and W dimensions with a probability. (TransposeHW = horizontal flip + anti-clockwise rotation by 90 degrees) When used with horizontal/vertical flips, it serves as a way of rotation augmentation. It also supports randomly transposing a list of images. Required keys are the keys in attributes "keys", added or modified keys are "transpose" and the keys in attributes "keys". Args: keys (list[str]): The images to be transposed. transpose_ratio (float): The probability to transpose the images. Default: 0.5. """ def __init__(self, keys, transpose_ratio=0.5): self.keys = keys if isinstance(keys, list) else [keys] self.transpose_ratio = transpose_ratio def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ transpose = np.random.random() < self.transpose_ratio if transpose: for key in self.keys: if isinstance(results[key], list): results[key] = [v.transpose(1, 0, 2) for v in results[key]] else: results[key] = results[key].transpose(1, 0, 2) results['transpose'] = transpose return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += ( f'(keys={self.keys}, transpose_ratio={self.transpose_ratio})') return repr_str @TRANSFORMS.register_module() class Resize(BaseTransform): """Resize data to a specific size for training or resize the images to fit the network input regulation for testing. When used for resizing images to fit network input regulation, the case is that a network may have several downsample and then upsample operation, then the input height and width should be divisible by the downsample factor of the network. For example, the network would downsample the input for 5 times with stride 2, then the downsample factor is 2^5 = 32 and the height and width should be divisible by 32. Required keys are the keys in attribute "keys", added or modified keys are "keep_ratio", "scale_factor", "interpolation" and the keys in attribute "keys". Required Keys: - Required keys are the keys in attribute "keys" Modified Keys: - Modified the keys in attribute "keys" or save as new key ([OUT_KEY]) Added Keys: - [OUT_KEY]_shape - keep_ratio - scale_factor - interpolation All keys in "keys" should have the same shape. "test_trans" is used to record the test transformation to align the input's shape. Args: keys (str | list[str]): The image(s) to be resized. scale (float | tuple[int]): If scale is tuple[int], target spatial size (h, w). Otherwise, target spatial size is scaled by input size. Note that when it is used, `size_factor` and `max_size` are useless. Default: None keep_ratio (bool): If set to True, images will be resized without changing the aspect ratio. Otherwise, it will resize images to a given size. Default: False. Note that it is used together with `scale`. size_factor (int): Let the output shape be a multiple of size_factor. Default:None. Note that when it is used, `scale` should be set to None and `keep_ratio` should be set to False. max_size (int): The maximum size of the longest side of the output. Default:None. Note that it is used together with `size_factor`. interpolation (str): Algorithm used for interpolation: "nearest" | "bilinear" | "bicubic" | "area" | "lanczos". Default: "bilinear". backend (str | None): The image resize backend type. Options are `cv2`, `pillow`, `None`. If backend is None, the global imread_backend specified by ``mmcv.use_backend()`` will be used. Default: None. output_keys (list[str] | None): The resized images. Default: None Note that if it is not `None`, its length should be equal to keys. """ def __init__(self, keys: Union[str, List[str]] = 'img', scale=None, keep_ratio=False, size_factor=None, max_size=None, interpolation='bilinear', backend=None, output_keys=None): assert keys, 'Keys should not be empty.' keys = [keys] if not isinstance(keys, list) else keys if output_keys: assert len(output_keys) == len(keys) else: output_keys = keys if size_factor: assert scale is None, ('When size_factor is used, scale should ', f'be None. But received {scale}.') assert keep_ratio is False, ('When size_factor is used, ' 'keep_ratio should be False.') if max_size: assert size_factor is not None, ( 'When max_size is used, ' f'size_factor should also be set. But received {size_factor}.') if isinstance(scale, float): if scale <= 0: raise ValueError(f'Invalid scale {scale}, must be positive.') elif is_tuple_of(scale, int): max_long_edge = max(scale) max_short_edge = min(scale) if max_short_edge == -1: # assign np.inf to long edge for rescaling short edge later. scale = (np.inf, max_long_edge) elif scale is not None: raise TypeError( f'Scale must be None, float or tuple of int, but got ' f'{type(scale)}.') self.keys = keys self.output_keys = output_keys self.scale = scale self.size_factor = size_factor self.max_size = max_size self.keep_ratio = keep_ratio self.interpolation = interpolation self.backend = backend def _resize(self, img): """Resize function. Args: img (np.ndarray): Image. Returns: img (np.ndarray): Resized image. """ if isinstance(img, list): for i, image in enumerate(img): size, img[i] = self._resize(image) return size, img else: if self.keep_ratio: img, self.scale_factor = mmcv.imrescale( img, self.scale, return_scale=True, interpolation=self.interpolation, backend=self.backend) else: img, w_scale, h_scale = mmcv.imresize( img, self.scale, return_scale=True, interpolation=self.interpolation, backend=self.backend) self.scale_factor = np.array((w_scale, h_scale), dtype=np.float32) if len(img.shape) == 2: img = np.expand_dims(img, axis=2) return img.shape, img def transform(self, results: Dict) -> Dict: """Transform function to resize images. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ if self.size_factor: h, w = results[self.keys[0]].shape[:2] new_h = h - (h % self.size_factor) new_w = w - (w % self.size_factor) if self.max_size: new_h = min(self.max_size - (self.max_size % self.size_factor), new_h) new_w = min(self.max_size - (self.max_size % self.size_factor), new_w) self.scale = (new_w, new_h) for key, out_key in zip(self.keys, self.output_keys): if key in results: size, results[out_key] = self._resize(results[key]) results[f'{out_key}_shape'] = size # copy metainfo if f'ori_{key}_shape' in results: results[f'ori_{out_key}_shape'] = deepcopy( results[f'ori_{key}_shape']) if f'{key}_channel_order' in results: results[f'{out_key}_channel_order'] = deepcopy( results[f'{key}_channel_order']) if f'{key}_color_type' in results: results[f'{out_key}_color_type'] = deepcopy( results[f'{key}_color_type']) results['scale_factor'] = self.scale_factor results['keep_ratio'] = self.keep_ratio results['interpolation'] = self.interpolation results['backend'] = self.backend return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += ( f'(keys={self.keys}, output_keys={self.output_keys}, ' f'scale={self.scale}, ' f'keep_ratio={self.keep_ratio}, size_factor={self.size_factor}, ' f'max_size={self.max_size}, interpolation={self.interpolation})') return repr_str @TRANSFORMS.register_module() class NumpyPad(BaseTransform): """Numpy Padding. In this augmentation, numpy padding is adopted to customize padding augmentation. Please carefully read the numpy manual in: https://numpy.org/doc/stable/reference/generated/numpy.pad.html If you just hope a single dimension to be padded, you must set ``padding`` like this: :: padding = ((2, 2), (0, 0), (0, 0)) In this case, if you adopt an input with three dimension, only the first dimension will be padded. Args: keys (Union[str, List[str]]): The images to be padded. padding (int | tuple(int)): Please refer to the args ``pad_width`` in ``numpy.pad``. """ def __init__(self, keys, padding, **kwargs): if isinstance(keys, str): keys = [keys] self.keys = keys self.padding = padding self.kwargs = kwargs def transform(self, results): """Call function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: results[key] = np.pad(results[key], self.padding, **self.kwargs) return results def __repr__(self) -> str: repr_str = self.__class__.__name__ repr_str += ( f'(keys={self.keys}, padding={self.padding}, kwargs={self.kwargs})' ) return repr_str ================================================ FILE: mmagic/datasets/transforms/blur_kernels.py ================================================ # This code is referenced from BasicSR with modifications. # Reference: https://github.com/xinntao/BasicSR/blob/master/basicsr/data/degradations.py # noqa # Original license: Copyright (c) 2020 xinntao, under the Apache 2.0 license. import numpy as np from scipy import special def get_rotated_sigma_matrix(sig_x, sig_y, theta): """Calculate the rotated sigma matrix (two dimensional matrix). Args: sig_x (float): Standard deviation along the horizontal direction. sig_y (float): Standard deviation along the vertical direction. theta (float): Rotation in radian. Returns: np.ndarray: Rotated sigma matrix. """ diag = np.array([[sig_x**2, 0], [0, sig_y**2]]).astype(np.float32) rot = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]).astype(np.float32) return np.matmul(rot, np.matmul(diag, rot.T)) def _mesh_grid(kernel_size): """Generate the mesh grid, centering at zero. Args: kernel_size (int): The size of the kernel. Returns: x_grid (np.ndarray): x-coordinates with shape (kernel_size, kernel_size). y_grid (np.ndarray): y-coordinates with shape (kernel_size, kernel_size). xy_grid (np.ndarray): stacked coordinates with shape (kernel_size, kernel_size, 2). """ range_ = np.arange(-kernel_size // 2 + 1., kernel_size // 2 + 1.) x_grid, y_grid = np.meshgrid(range_, range_) xy_grid = np.hstack((x_grid.reshape((kernel_size * kernel_size, 1)), y_grid.reshape(kernel_size * kernel_size, 1))).reshape(kernel_size, kernel_size, 2) return xy_grid, x_grid, y_grid def calculate_gaussian_pdf(sigma_matrix, grid): """Calculate PDF of the bivariate Gaussian distribution. Args: sigma_matrix (np.ndarray): The variance matrix with shape (2, 2). grid (np.ndarray): Coordinates generated by :func:`_mesh_grid`, with shape (K, K, 2), where K is the kernel size. Returns: kernel (np.ndarray): Un-normalized kernel. """ inverse_sigma = np.linalg.inv(sigma_matrix) kernel = np.exp(-0.5 * np.sum(np.matmul(grid, inverse_sigma) * grid, 2)) return kernel def bivariate_gaussian(kernel_size, sig_x, sig_y=None, theta=None, grid=None, is_isotropic=True): """Generate a bivariate isotropic or anisotropic Gaussian kernel. In isotropic mode, only `sig_x` is used. `sig_y` and `theta` are ignored. Args: kernel_size (int): The size of the kernel sig_x (float): Standard deviation along horizontal direction. sig_y (float | None, optional): Standard deviation along the vertical direction. If it is None, 'is_isotropic' must be set to True. Default: None. theta (float | None, optional): Rotation in radian. If it is None, 'is_isotropic' must be set to True. Default: None. grid (ndarray, optional): Coordinates generated by :func:`_mesh_grid`, with shape (K, K, 2), where K is the kernel size. Default: None is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): normalized kernel (i.e. sum to 1). """ if grid is None: grid, _, _ = _mesh_grid(kernel_size) if is_isotropic: sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]]).astype(np.float32) else: if sig_y is None: raise ValueError('"sig_y" cannot be None if "is_isotropic" is ' 'False.') sigma_matrix = get_rotated_sigma_matrix(sig_x, sig_y, theta) kernel = calculate_gaussian_pdf(sigma_matrix, grid) kernel = kernel / np.sum(kernel) return kernel def bivariate_generalized_gaussian(kernel_size, sig_x, sig_y=None, theta=None, beta=1, grid=None, is_isotropic=True): """Generate a bivariate generalized Gaussian kernel. Described in `Parameter Estimation For Multivariate Generalized Gaussian Distributions` by Pascal et. al (2013). In isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored. Args: kernel_size (int): The size of the kernel sig_x (float): Standard deviation along horizontal direction sig_y (float | None, optional): Standard deviation along the vertical direction. If it is None, 'is_isotropic' must be set to True. Default: None. theta (float | None, optional): Rotation in radian. If it is None, 'is_isotropic' must be set to True. Default: None. beta (float, optional): Shape parameter, beta = 1 is the normal distribution. Default: 1. grid (ndarray, optional): Coordinates generated by :func:`_mesh_grid`, with shape (K, K, 2), where K is the kernel size. Default: None is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): normalized kernel. """ if grid is None: grid, _, _ = _mesh_grid(kernel_size) if is_isotropic: sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]]).astype(np.float32) else: sigma_matrix = get_rotated_sigma_matrix(sig_x, sig_y, theta) inverse_sigma = np.linalg.inv(sigma_matrix) kernel = np.exp( -0.5 * np.power(np.sum(np.matmul(grid, inverse_sigma) * grid, 2), beta)) kernel = kernel / np.sum(kernel) return kernel def bivariate_plateau(kernel_size, sig_x, sig_y, theta, beta, grid=None, is_isotropic=True): """Generate a plateau-like anisotropic kernel. This kernel has a form of 1 / (1+x^(beta)). Ref: https://stats.stackexchange.com/questions/203629/is-there-a-plateau-shaped-distribution # noqa In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored. Args: kernel_size (int): The size of the kernel sig_x (float): Standard deviation along horizontal direction sig_y (float): Standard deviation along the vertical direction. theta (float): Rotation in radian. beta (float): Shape parameter, beta = 1 is the normal distribution. grid (np.ndarray, optional): Coordinates generated by :func:`_mesh_grid`, with shape (K, K, 2), where K is the kernel size. Default: None is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): normalized kernel (i.e. sum to 1). """ if grid is None: grid, _, _ = _mesh_grid(kernel_size) if is_isotropic: sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]]).astype(np.float32) else: sigma_matrix = get_rotated_sigma_matrix(sig_x, sig_y, theta) inverse_sigma = np.linalg.inv(sigma_matrix) kernel = np.reciprocal( np.power(np.sum(np.matmul(grid, inverse_sigma) * grid, 2), beta) + 1) kernel = kernel / np.sum(kernel) return kernel def random_bivariate_gaussian_kernel(kernel_size, sigma_x_range, sigma_y_range, rotation_range, noise_range=None, is_isotropic=True): """Randomly generate bivariate isotropic or anisotropic Gaussian kernels. In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored. Args: kernel_size (int): The size of the kernel. sigma_x_range (tuple): The range of the standard deviation along the horizontal direction. Default: [0.6, 5] sigma_y_range (tuple): The range of the standard deviation along the vertical direction. Default: [0.6, 5] rotation_range (tuple): Range of rotation in radian. noise_range (tuple, optional): Multiplicative kernel noise. Default: None. is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): The kernel whose parameters are sampled from the specified range. """ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.' assert sigma_x_range[0] <= sigma_x_range[1], 'Wrong sigma_x_range.' sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1]) if is_isotropic is False: assert sigma_y_range[0] <= sigma_y_range[1], 'Wrong sigma_y_range.' assert rotation_range[0] <= rotation_range[1], 'Wrong rotation_range.' sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1]) rotation = np.random.uniform(rotation_range[0], rotation_range[1]) else: sigma_y = sigma_x rotation = 0 kernel = bivariate_gaussian( kernel_size, sigma_x, sigma_y, rotation, is_isotropic=is_isotropic) # add multiplicative noise if noise_range is not None: assert noise_range[0] <= noise_range[1], 'Wrong noise range.' noise = np.random.uniform( noise_range[0], noise_range[1], size=kernel.shape) kernel = kernel * noise kernel = kernel / np.sum(kernel) return kernel def random_bivariate_generalized_gaussian_kernel(kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_range, noise_range=None, is_isotropic=True): """Randomly generate bivariate generalized Gaussian kernels. In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored. Args: kernel_size (int): The size of the kernel. sigma_x_range (tuple): The range of the standard deviation along the horizontal direction. Default: [0.6, 5] sigma_y_range (tuple): The range of the standard deviation along the vertical direction. Default: [0.6, 5] rotation_range (tuple): Range of rotation in radian. beta_range (float): The range of the shape parameter, beta = 1 is the normal distribution. noise_range (tuple, optional): Multiplicative kernel noise. Default: None. is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): Normalized kernel. """ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.' assert sigma_x_range[0] <= sigma_x_range[1], 'Wrong sigma_x_range.' sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1]) if is_isotropic is False: assert sigma_y_range[0] <= sigma_y_range[1], 'Wrong sigma_y_range.' assert rotation_range[0] <= rotation_range[1], 'Wrong rotation_range.' sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1]) rotation = np.random.uniform(rotation_range[0], rotation_range[1]) else: sigma_y = sigma_x rotation = 0 # assume beta_range[0] <= 1 <= beta_range[1] if np.random.uniform() <= 0.5: beta = np.random.uniform(beta_range[0], 1) else: beta = np.random.uniform(1, beta_range[1]) kernel = bivariate_generalized_gaussian( kernel_size, sigma_x, sigma_y, rotation, beta, is_isotropic=is_isotropic) # add multiplicative noise if noise_range is not None: assert noise_range[0] <= noise_range[1], 'Wrong noise range.' noise = np.random.uniform( noise_range[0], noise_range[1], size=kernel.shape) kernel = kernel * noise kernel = kernel / np.sum(kernel) return kernel def random_bivariate_plateau_kernel(kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_range, noise_range=None, is_isotropic=True): """Randomly generate bivariate plateau kernels. In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored. Args: kernel_size (int): The size of the kernel. sigma_x_range (tuple): The range of the standard deviation along the horizontal direction. Default: [0.6, 5] sigma_y_range (tuple): The range of the standard deviation along the vertical direction. Default: [0.6, 5] rotation_range (tuple): Range of rotation in radian. beta_range (float): The range of the shape parameter, beta = 1 is the normal distribution. noise_range (tuple, optional): Multiplicative kernel noise. Default: None. is_isotropic (bool, optional): Whether to use an isotropic kernel. Default: True. Returns: kernel (np.ndarray): Plateau kernel. """ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.' assert sigma_x_range[0] <= sigma_x_range[1], 'Wrong sigma_x_range.' sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1]) if is_isotropic is False: assert sigma_y_range[0] <= sigma_y_range[1], 'Wrong sigma_y_range.' assert rotation_range[0] <= rotation_range[1], 'Wrong rotation_range.' sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1]) rotation = np.random.uniform(rotation_range[0], rotation_range[1]) else: sigma_y = sigma_x rotation = 0 # TODO: this may be not proper if np.random.uniform() <= 0.5: beta = np.random.uniform(beta_range[0], 1) else: beta = np.random.uniform(1, beta_range[1]) kernel = bivariate_plateau( kernel_size, sigma_x, sigma_y, rotation, beta, is_isotropic=is_isotropic) # add multiplicative noise if noise_range is not None: assert noise_range[0] <= noise_range[1], 'Wrong noise range.' noise = np.random.uniform( noise_range[0], noise_range[1], size=kernel.shape) kernel = kernel * noise kernel = kernel / np.sum(kernel) return kernel def random_circular_lowpass_kernel(omega_range, kernel_size, pad_to=0): """Generate a 2D Sinc filter. Reference: https://dsp.stackexchange.com/questions/58301/2-d-circularly-symmetric-low-pass-filter # noqa Args: omega_range (tuple): The cutoff frequency in radian (pi is max). kernel_size (int): The size of the kernel. It must be an odd number. pad_to (int, optional): The size of the padded kernel. It must be odd or zero. Default: 0. Returns: kernel (np.ndarray): The Sinc kernel with specified parameters. """ err = np.geterr() np.seterr(divide='ignore', invalid='ignore') assert kernel_size % 2 == 1, 'Kernel size must be an odd number.' omega = np.random.uniform(omega_range[0], omega_range[-1]) kernel = np.fromfunction( lambda x, y: omega * special.j1(omega * np.sqrt( (x - (kernel_size - 1) / 2)**2 + (y - (kernel_size - 1) / 2)**2)) / (2 * np.pi * np.sqrt((x - (kernel_size - 1) / 2)**2 + (y - (kernel_size - 1) / 2)**2)), [kernel_size, kernel_size]) kernel[(kernel_size - 1) // 2, (kernel_size - 1) // 2] = omega**2 / (4 * np.pi) kernel = kernel / np.sum(kernel) if pad_to > kernel_size: pad_size = (pad_to - kernel_size) // 2 kernel = np.pad(kernel, ((pad_size, pad_size), (pad_size, pad_size))) np.seterr(**err) return kernel def random_mixed_kernels(kernel_list, kernel_prob, kernel_size, sigma_x_range=[0.6, 5], sigma_y_range=[0.6, 5], rotation_range=[-np.pi, np.pi], beta_gaussian_range=[0.5, 8], beta_plateau_range=[1, 2], omega_range=[0, np.pi], noise_range=None): """Randomly generate a kernel. Args: kernel_list (list): A list of kernel types. Choices are 'iso', 'aniso', 'skew', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc'. kernel_prob (list): The probability of choosing of the corresponding kernel. kernel_size (int): The size of the kernel. sigma_x_range (list, optional): The range of the standard deviation along the horizontal direction. Default: (0.6, 5). sigma_y_range (list, optional): The range of the standard deviation along the vertical direction. Default: (0.6, 5). rotation_range (list, optional): Range of rotation in radian. Default: (-np.pi, np.pi). beta_gaussian_range (list, optional): The range of the shape parameter for generalized Gaussian. Default: (0.5, 8). beta_plateau_range (list, optional): The range of the shape parameter for plateau kernel. Default: (1, 2). omega_range (list, optional): The range of omega used in Sinc kernel. Default: (0, np.pi). noise_range (list, optional): Multiplicative kernel noise. Default: None. Returns: kernel (np.ndarray): The kernel whose parameters are sampled from the specified range. """ kernel_type = np.random.choice(kernel_list, p=kernel_prob) if kernel_type == 'iso': kernel = random_bivariate_gaussian_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, noise_range=noise_range, is_isotropic=True) elif kernel_type == 'aniso': kernel = random_bivariate_gaussian_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, noise_range=noise_range, is_isotropic=False) elif kernel_type == 'generalized_iso': kernel = random_bivariate_generalized_gaussian_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_gaussian_range, noise_range=noise_range, is_isotropic=True) elif kernel_type == 'generalized_aniso': kernel = random_bivariate_generalized_gaussian_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_gaussian_range, noise_range=noise_range, is_isotropic=False) elif kernel_type == 'plateau_iso': kernel = random_bivariate_plateau_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_plateau_range, noise_range=None, is_isotropic=True) elif kernel_type == 'plateau_aniso': kernel = random_bivariate_plateau_kernel( kernel_size, sigma_x_range, sigma_y_range, rotation_range, beta_plateau_range, noise_range=None, is_isotropic=False) elif kernel_type == 'sinc': kernel = random_circular_lowpass_kernel(omega_range, kernel_size) return kernel ================================================ FILE: mmagic/datasets/transforms/crop.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import random import cv2 as cv import mmcv import numpy as np import torch from mmcv.transforms import BaseTransform from mmengine.hub import get_config from mmengine.registry import DefaultScope from mmengine.utils import is_list_of, is_tuple_of from torch.nn.modules.utils import _pair from mmagic.registry import TRANSFORMS from mmagic.utils import get_box_info, random_choose_unknown, try_import mmdet_apis = try_import('mmdet.apis') @TRANSFORMS.register_module() class Crop(BaseTransform): """Crop data to specific size for training. Args: keys (Sequence[str]): The images to be cropped. crop_size (Tuple[int]): Target spatial size (h, w). random_crop (bool): If set to True, it will random crop image. Otherwise, it will work as center crop. Default: True. is_pad_zeros (bool, optional): Whether to pad the image with 0 if crop_size is greater than image size. Default: False. """ def __init__(self, keys, crop_size, random_crop=True, is_pad_zeros=False): if not is_tuple_of(crop_size, int): raise TypeError( 'Elements of crop_size must be int and crop_size must be' f' tuple, but got {type(crop_size[0])} in {type(crop_size)}') self.keys = keys self.crop_size = crop_size self.random_crop = random_crop self.is_pad_zeros = is_pad_zeros def _crop(self, data): """Crop the data. Args: data (Union[List, np.ndarray]): Input data to crop. Returns: tuple: cropped data and corresponding crop box. """ if not isinstance(data, list): data_list = [data] else: data_list = data crop_bbox_list = [] data_list_ = [] for item in data_list: data_h, data_w = item.shape[:2] crop_h, crop_w = self.crop_size if self.is_pad_zeros: crop_y_offset, crop_x_offset = 0, 0 if crop_h > data_h: crop_y_offset = (crop_h - data_h) // 2 if crop_w > data_w: crop_x_offset = (crop_w - data_w) // 2 if crop_y_offset > 0 or crop_x_offset > 0: pad_width = [(2 * crop_y_offset, 2 * crop_y_offset), (2 * crop_x_offset, 2 * crop_x_offset)] if item.ndim == 3: pad_width.append((0, 0)) item = np.pad( item, tuple(pad_width), mode='constant', constant_values=0) data_h, data_w = item.shape[:2] crop_h = min(data_h, crop_h) crop_w = min(data_w, crop_w) if self.random_crop: x_offset = np.random.randint(0, data_w - crop_w + 1) y_offset = np.random.randint(0, data_h - crop_h + 1) else: x_offset = max(0, (data_w - crop_w)) // 2 y_offset = max(0, (data_h - crop_h)) // 2 crop_bbox = [x_offset, y_offset, crop_w, crop_h] item_ = item[y_offset:y_offset + crop_h, x_offset:x_offset + crop_w, ...] crop_bbox_list.append(crop_bbox) data_list_.append(item_) if not isinstance(data, list): return data_list_[0], crop_bbox_list[0] return data_list_, crop_bbox_list def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for k in self.keys: data_, crop_bbox = self._crop(results[k]) results[k] = data_ results[k + '_crop_bbox'] = crop_bbox results['crop_size'] = self.crop_size return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'keys={self.keys}, crop_size={self.crop_size}, ' f'random_crop={self.random_crop}') return repr_str @TRANSFORMS.register_module() class CropLike(BaseTransform): """Crop/pad the image in the target_key according to the size of image in the reference_key . Args: target_key (str): The key needs to be cropped. reference_key (str | None): The reference key, need its size. Default: None. """ def __init__(self, target_key, reference_key=None): assert reference_key and target_key self.target_key = target_key self.reference_key = reference_key def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Require self.target_key and self.reference_key. Returns: dict: A dict containing the processed data and information. Modify self.target_key. """ size = results[self.reference_key].shape old_image = results[self.target_key] old_size = old_image.shape h, w = old_size[:2] new_size = size[:2] + old_size[2:] h_cover, w_cover = min(h, size[0]), min(w, size[1]) format_image = np.zeros(new_size, dtype=old_image.dtype) format_image[:h_cover, :w_cover] = old_image[:h_cover, :w_cover] results[self.target_key] = format_image return results def __repr__(self): return (self.__class__.__name__ + f' target_key={self.target_key}, ' + f'reference_key={self.reference_key}') @TRANSFORMS.register_module() class FixedCrop(BaseTransform): """Crop paired data (at a specific position) to specific size for training. Args: keys (Sequence[str]): The images to be cropped. crop_size (Tuple[int]): Target spatial size (h, w). crop_pos (Tuple[int]): Specific position (x, y). If set to None, random initialize the position to crop paired data batch. Default: None. """ def __init__(self, keys, crop_size, crop_pos=None): if not is_tuple_of(crop_size, int): raise TypeError( 'Elements of crop_size must be int and crop_size must be' f' tuple, but got {type(crop_size[0])} in {type(crop_size)}') if not is_tuple_of(crop_pos, int) and (crop_pos is not None): raise TypeError( 'Elements of crop_pos must be int and crop_pos must be' f' tuple or None, but got {type(crop_pos[0])} in ' f'{type(crop_pos)}') self.keys = keys self.crop_size = crop_size self.crop_pos = crop_pos def _crop(self, data, x_offset, y_offset, crop_w, crop_h): """Crop the data. Args: data (Union[List, np.ndarray]): Input data to crop. x_offset (int): The offset of x axis. y_offset (int): The offset of y axis. crop_w (int): The width of crop bbox. crop_h (int): The height of crop bbox. Returns: tuple: cropped data and corresponding crop box. """ crop_bbox = [x_offset, y_offset, crop_w, crop_h] data_ = data[y_offset:y_offset + crop_h, x_offset:x_offset + crop_w, ...] return data_, crop_bbox def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ if isinstance(results[self.keys[0]], list): data_h, data_w = results[self.keys[0]][0].shape[:2] else: data_h, data_w = results[self.keys[0]].shape[:2] crop_h, crop_w = self.crop_size crop_h = min(data_h, crop_h) crop_w = min(data_w, crop_w) if self.crop_pos is None: x_offset = np.random.randint(0, data_w - crop_w + 1) y_offset = np.random.randint(0, data_h - crop_h + 1) else: x_offset, y_offset = self.crop_pos crop_w = min(data_w - x_offset, crop_w) crop_h = min(data_h - y_offset, crop_h) for k in self.keys: images = results[k] is_list = isinstance(images, list) if not is_list: images = [images] cropped_images = [] crop_bbox = None for image in images: # In fixed crop for paired images, sizes should be the same if (image.shape[0] != data_h or image.shape[1] != data_w): raise ValueError( 'The sizes of paired images should be the same. ' f'Expected ({data_h}, {data_w}), ' f'but got ({image.shape[0]}, ' f'{image.shape[1]}).') data_, crop_bbox = self._crop(image, x_offset, y_offset, crop_w, crop_h) cropped_images.append(data_) results[k + '_crop_bbox'] = crop_bbox if not is_list: cropped_images = cropped_images[0] results[k] = cropped_images results['crop_size'] = self.crop_size results['crop_pos'] = self.crop_pos return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'keys={self.keys}, crop_size={self.crop_size}, ' f'crop_pos={self.crop_pos}') return repr_str @TRANSFORMS.register_module() class ModCrop(BaseTransform): """Mod crop images, used during testing. Required keys are "scale" and "KEY", added or modified keys are "KEY". Args: key (str): The key of image. Default: 'gt' """ def __init__(self, key='gt') -> None: super().__init__() self.key = key def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ img = results[self.key].copy() scale = results['scale'] if img.ndim in [2, 3]: h, w = img.shape[0], img.shape[1] h_remainder, w_remainder = h % scale, w % scale img = img[:h - h_remainder, :w - w_remainder, ...] else: raise ValueError(f'Wrong img ndim: {img.ndim}.') results[self.key] = img return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += f'(key={self.key})' return repr_str @TRANSFORMS.register_module() class PairedRandomCrop(BaseTransform): """Paired random crop. It crops a pair of img and gt images with corresponding locations. It also supports accepting img list and gt list. Required keys are "scale", "lq_key", and "gt_key", added or modified keys are "lq_key" and "gt_key". Args: gt_patch_size (int): cropped gt patch size. lq_key (str): Key of LQ img. Default: 'img'. gt_key (str): Key of GT img. Default: 'gt'. """ def __init__(self, gt_patch_size, lq_key='img', gt_key='gt'): self.gt_patch_size = gt_patch_size self.lq_key = lq_key self.gt_key = gt_key def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ scale = results['scale'] lq_patch_size = self.gt_patch_size // scale lq_is_list = isinstance(results[self.lq_key], list) if not lq_is_list: results[self.lq_key] = [results[self.lq_key]] gt_is_list = isinstance(results[self.gt_key], list) if not gt_is_list: results[self.gt_key] = [results[self.gt_key]] h_lq, w_lq, _ = results[self.lq_key][0].shape h_gt, w_gt, _ = results[self.gt_key][0].shape if h_gt != h_lq * scale or w_gt != w_lq * scale: raise ValueError( f'Scale mismatches. GT ({h_gt}, {w_gt}) is not {scale}x ' f'multiplication of LQ ({h_lq}, {w_lq}).') if h_lq < lq_patch_size or w_lq < lq_patch_size: raise ValueError( f'LQ ({h_lq}, {w_lq}) is smaller than patch size ' f'({lq_patch_size}, {lq_patch_size}). Please check ' f'{results[f"{self.lq_key}_path"]} and ' f'{results[f"{self.gt_key}_path"]}.') # randomly choose top and left coordinates for img patch top = np.random.randint(h_lq - lq_patch_size + 1) left = np.random.randint(w_lq - lq_patch_size + 1) # crop img patch results[self.lq_key] = [ v[top:top + lq_patch_size, left:left + lq_patch_size, ...] for v in results[self.lq_key] ] # crop corresponding gt patch top_gt, left_gt = int(top * scale), int(left * scale) results[self.gt_key] = [ v[top_gt:top_gt + self.gt_patch_size, left_gt:left_gt + self.gt_patch_size, ...] for v in results[self.gt_key] ] if not lq_is_list: results[self.lq_key] = results[self.lq_key][0] if not gt_is_list: results[self.gt_key] = results[self.gt_key][0] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(gt_patch_size={self.gt_patch_size}, ' f'lq_key={self.lq_key}, ' f'gt_key={self.gt_key})') return repr_str @TRANSFORMS.register_module() class RandomResizedCrop(BaseTransform): """Crop data to random size and aspect ratio. A crop of a random proportion of the original image and a random aspect ratio of the original aspect ratio is made. The cropped image is finally resized to a given size specified by 'crop_size'. Modified keys are the attributes specified in "keys". This code is partially adopted from torchvision.transforms.RandomResizedCrop: [https://pytorch.org/vision/stable/_modules/torchvision/transforms/\ transforms.html#RandomResizedCrop]. Args: keys (list[str]): The images to be resized and random-cropped. crop_size (int | tuple[int]): Target spatial size (h, w). scale (tuple[float], optional): Range of the proportion of the original image to be cropped. Default: (0.08, 1.0). ratio (tuple[float], optional): Range of aspect ratio of the crop. Default: (3. / 4., 4. / 3.). interpolation (str, optional): Algorithm used for interpolation. It can be only either one of the following: "nearest" | "bilinear" | "bicubic" | "area" | "lanczos". Default: "bilinear". """ def __init__(self, keys, crop_size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.), interpolation='bilinear'): assert keys, 'Keys should not be empty.' if isinstance(crop_size, int): crop_size = (crop_size, crop_size) elif not is_tuple_of(crop_size, int): raise TypeError('"crop_size" must be an integer ' 'or a tuple of integers, but got ' f'{type(crop_size)}') if not is_tuple_of(scale, float): raise TypeError('"scale" must be a tuple of float, ' f'but got {type(scale)}') if not is_tuple_of(ratio, float): raise TypeError('"ratio" must be a tuple of float, ' f'but got {type(ratio)}') self.keys = keys self.crop_size = crop_size self.scale = scale self.ratio = ratio self.interpolation = interpolation def get_params(self, data): """Get parameters for a random sized crop. Args: data (np.ndarray): Image of type numpy array to be cropped. Returns: A tuple containing the coordinates of the top left corner and the chosen crop size. """ data_h, data_w = data.shape[:2] area = data_h * data_w for _ in range(10): target_area = random.uniform(*self.scale) * area log_ratio = (math.log(self.ratio[0]), math.log(self.ratio[1])) aspect_ratio = math.exp(random.uniform(*log_ratio)) crop_w = int(round(math.sqrt(target_area * aspect_ratio))) crop_h = int(round(math.sqrt(target_area / aspect_ratio))) if 0 < crop_w <= data_w and 0 < crop_h <= data_h: top = random.randint(0, data_h - crop_h) left = random.randint(0, data_w - crop_w) return top, left, crop_h, crop_w # Fall back to center crop in_ratio = float(data_w) / float(data_h) if (in_ratio < min(self.ratio)): crop_w = data_w crop_h = int(round(crop_w / min(self.ratio))) elif (in_ratio > max(self.ratio)): crop_h = data_h crop_w = int(round(crop_h * max(self.ratio))) else: # whole image crop_w = data_w crop_h = data_h top = (data_h - crop_h) // 2 left = (data_w - crop_w) // 2 return top, left, crop_h, crop_w def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for k in self.keys: top, left, crop_h, crop_w = self.get_params(results[k]) crop_bbox = [top, left, crop_w, crop_h] results[k] = results[k][top:top + crop_h, left:left + crop_w, ...] results[k] = mmcv.imresize( results[k], self.crop_size, return_scale=False, interpolation=self.interpolation) results[k + '_crop_bbox'] = crop_bbox return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, crop_size={self.crop_size}, ' f'scale={self.scale}, ratio={self.ratio}, ' f'interpolation={self.interpolation})') return repr_str @TRANSFORMS.register_module() class CropAroundCenter(BaseTransform): """Randomly crop the images around unknown area in the center 1/4 images. This cropping strategy is adopted in GCA matting. The `unknown area` is the same as `semi-transparent area`. https://arxiv.org/pdf/2001.04069.pdf It retains the center 1/4 images and resizes the images to 'crop_size'. Required keys are "fg", "bg", "trimap" and "alpha", added or modified keys are "crop_bbox", "fg", "bg", "trimap" and "alpha". Args: crop_size (int | tuple): Desired output size. If int, square crop is applied. """ def __init__(self, crop_size): if is_tuple_of(crop_size, int): assert len(crop_size) == 2, 'length of crop_size must be 2.' elif not isinstance(crop_size, int): raise TypeError('crop_size must be int or a tuple of int, but got ' f'{type(crop_size)}') self.crop_size = _pair(crop_size) def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ fg = results['fg'] alpha = results['alpha'] trimap = results['trimap'] bg = results['bg'] h, w = fg.shape[:2] assert bg.shape == fg.shape, (f'shape of bg {bg.shape} should be the ' f'same as fg {fg.shape}.') crop_h, crop_w = self.crop_size # Make sure h >= crop_h, w >= crop_w. If not, rescale imgs rescale_ratio = max(crop_h / h, crop_w / w) if rescale_ratio > 1: assert alpha.ndim == trimap.ndim ext_dim = (alpha.ndim == 3) new_h = max(int(h * rescale_ratio), crop_h) new_w = max(int(w * rescale_ratio), crop_w) fg = mmcv.imresize(fg, (new_w, new_h), interpolation='nearest') alpha = mmcv.imresize( alpha, (new_w, new_h), interpolation='nearest') trimap = mmcv.imresize( trimap, (new_w, new_h), interpolation='nearest') bg = mmcv.imresize(bg, (new_w, new_h), interpolation='bicubic') h, w = new_h, new_w if ext_dim: # mmcv.imresize will squeeze alpha = alpha[..., None] trimap = trimap[..., None] # resize to 1/4 to ignore small unknown patches small_trimap = mmcv.imresize( trimap, (w // 4, h // 4), interpolation='nearest') assert small_trimap.ndim == 2 # find unknown area in center 1/4 region margin_h, margin_w = crop_h // 2, crop_w // 2 sample_area = small_trimap[margin_h // 4:(h - margin_h) // 4, margin_w // 4:(w - margin_w) // 4] unknown_xs, unknown_ys = np.where(sample_area == 128) unknown_num = len(unknown_xs) if unknown_num < 10: # too few unknown area in the center, crop from the whole image top = np.random.randint(0, h - crop_h + 1) left = np.random.randint(0, w - crop_w + 1) else: idx = np.random.randint(unknown_num) top = unknown_xs[idx] * 4 left = unknown_ys[idx] * 4 bottom = top + crop_h right = left + crop_w results['fg'] = fg[top:bottom, left:right] results['alpha'] = alpha[top:bottom, left:right] results['trimap'] = trimap[top:bottom, left:right] results['bg'] = bg[top:bottom, left:right] results['crop_bbox'] = (left, top, right, bottom) return results def __repr__(self): return self.__class__.__name__ + f'(crop_size={self.crop_size})' @TRANSFORMS.register_module() class CropAroundFg(BaseTransform): """Crop around the whole foreground in the segmentation mask. Required keys are "seg" and the keys in argument `keys`. Meanwhile, "seg" must be in argument `keys`. Added or modified keys are "crop_bbox" and the keys in argument `keys`. Args: keys (Sequence[str]): The images to be cropped. It must contain 'seg'. bd_ratio_range (tuple, optional): The range of the boundary (bd) ratio to select from. The boundary ratio is the ratio of the boundary to the minimal bbox that contains the whole foreground given by segmentation. Default to (0.1, 0.4). test_mode (bool): Whether use test mode. In test mode, the tight crop area of foreground will be extended to the a square. Default to False. """ def __init__(self, keys, bd_ratio_range=(0.1, 0.4), test_mode=False): if 'seg' not in keys: raise ValueError(f'"seg" must be in keys, but got {keys}') if (not is_tuple_of(bd_ratio_range, float) or len(bd_ratio_range) != 2): raise TypeError('bd_ratio_range must be a tuple of 2 int, but got ' f'{bd_ratio_range}') self.keys = keys self.bd_ratio_range = bd_ratio_range self.test_mode = test_mode def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ seg = results['seg'] height, width = seg.shape[:2] # get foreground bbox fg_coor = np.array(np.where(seg)) top, left = np.amin(fg_coor, axis=1) bottom, right = np.amax(fg_coor, axis=1) # enlarge bbox long_side = np.maximum(bottom - top, right - left) if self.test_mode: bottom = top + long_side right = left + long_side boundary_ratio = np.random.uniform(*self.bd_ratio_range) boundary = int(np.round(boundary_ratio * long_side)) # NOTE: Different from the original repo, we keep track of the four # corners of the bbox (left, top, right, bottom) while the original # repo use (top, left, height, width) to represent bbox. This may # introduce an difference of 1 pixel. top = max(top - boundary, 0) left = max(left - boundary, 0) bottom = min(bottom + boundary, height) right = min(right + boundary, width) for key in self.keys: results[key] = results[key][top:bottom, left:right] results['crop_bbox'] = (left, top, right, bottom) return results @TRANSFORMS.register_module() class CropAroundUnknown(BaseTransform): """Crop around unknown area with a randomly selected scale. Randomly select the w and h from a list of (w, h). Required keys are the keys in argument `keys`, added or modified keys are "crop_bbox" and the keys in argument `keys`. This class assumes value of "alpha" ranges from 0 to 255. Args: keys (Sequence[str]): The images to be cropped. It must contain 'alpha'. If unknown_source is set to 'trimap', then it must also contain 'trimap'. crop_sizes (list[int | tuple[int]]): List of (w, h) to be selected. unknown_source (str, optional): Unknown area to select from. It must be 'alpha' or 'trimap'. Default to 'alpha'. interpolations (str | list[str], optional): Interpolation method of mmcv.imresize. The interpolation operation will be applied when image size is smaller than the crop_size. If given as a list of str, it should have the same length as `keys`. Or if given as a str all the keys will be resized with the same method. Default to 'bilinear'. """ def __init__(self, keys, crop_sizes, unknown_source='alpha', interpolations='bilinear'): if 'alpha' not in keys: raise ValueError(f'"alpha" must be in keys, but got {keys}') self.keys = keys if not isinstance(crop_sizes, list): raise TypeError( f'Crop sizes must be list, but got {type(crop_sizes)}.') self.crop_sizes = [_pair(crop_size) for crop_size in crop_sizes] if not is_tuple_of(self.crop_sizes[0], int): raise TypeError('Elements of crop_sizes must be int or tuple of ' f'int, but got {type(self.crop_sizes[0][0])}.') if unknown_source not in ['alpha', 'trimap']: raise ValueError('unknown_source must be "alpha" or "trimap", ' f'but got {unknown_source}') if unknown_source not in keys: # it could only be trimap, since alpha is checked before raise ValueError( 'if unknown_source is "trimap", it must also be set in keys') self.unknown_source = unknown_source if isinstance(interpolations, str): self.interpolations = [interpolations] * len(self.keys) elif is_list_of(interpolations, str) and len(interpolations) == len( self.keys): self.interpolations = interpolations else: raise TypeError( 'interpolations must be a str or list of str with ' f'the same length as keys, but got {interpolations}') def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ h, w = results[self.keys[0]].shape[:2] rand_ind = np.random.randint(len(self.crop_sizes)) crop_h, crop_w = self.crop_sizes[rand_ind] # Make sure h >= crop_h, w >= crop_w. If not, rescale imgs rescale_ratio = max(crop_h / h, crop_w / w) if rescale_ratio > 1: h = max(int(h * rescale_ratio), crop_h) w = max(int(w * rescale_ratio), crop_w) for key, interpolation in zip(self.keys, self.interpolations): ext_dim = (results[key].ndim == 3) and (results[key].shape[-1] == 1) results[key] = mmcv.imresize( results[key], (w, h), interpolation=interpolation) if ext_dim: results[key] = results[key][..., None] # Select the cropping top-left point which is an unknown pixel if self.unknown_source == 'alpha': unknown = (results['alpha'] > 0) & (results['alpha'] < 255) else: unknown = results['trimap'] == 128 top, left = random_choose_unknown(unknown.squeeze(), (crop_h, crop_w)) bottom = top + crop_h right = left + crop_w for key in self.keys: results[key] = results[key][top:bottom, left:right] results['crop_bbox'] = (left, top, right, bottom) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, crop_sizes={self.crop_sizes}, ' f"unknown_source='{self.unknown_source}', " f'interpolations={self.interpolations})') return repr_str @TRANSFORMS.register_module() class RandomCropLongEdge(BaseTransform): """Random crop the given image by the long edge. Args: keys (list[str]): The images to be cropped. """ def __init__(self, keys='img'): assert keys, 'Keys should not be empty.' if not isinstance(keys, list): keys = [keys] self.keys = keys def transform(self, results): """Call function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: img = results[key] img_height, img_width = img.shape[:2] crop_size = min(img_height, img_width) y1 = 0 if img_height == crop_size else \ np.random.randint(0, img_height - crop_size) x1 = 0 if img_width == crop_size else \ np.random.randint(0, img_width - crop_size) y2, x2 = y1 + crop_size - 1, x1 + crop_size - 1 img = mmcv.imcrop(img, bboxes=np.array([x1, y1, x2, y2])) results[key] = img return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys})') return repr_str @TRANSFORMS.register_module() class CenterCropLongEdge(BaseTransform): """Center crop the given image by the long edge. Args: keys (list[str]): The images to be cropped. """ def __init__(self, keys='img'): assert keys, 'Keys should not be empty.' if not isinstance(keys, list): keys = [keys] self.keys = keys def transform(self, results): """Call function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: img = results[key] img_height, img_width = img.shape[:2] crop_size = min(img_height, img_width) y1 = 0 if img_height == crop_size else \ int(round(img_height - crop_size) / 2) x1 = 0 if img_width == crop_size else \ int(round(img_width - crop_size) / 2) y2 = y1 + crop_size - 1 x2 = x1 + crop_size - 1 img = mmcv.imcrop(img, bboxes=np.array([x1, y1, x2, y2])) results[key] = img return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys})') return repr_str @TRANSFORMS.register_module() class InstanceCrop(BaseTransform): """Use maskrcnn to detect instances on image. Mask R-CNN is used to detect the instance on the image pred_bbox is used to segment the instance on the image Args: config_file (str): config file name relative to detectron2's "configs/" key (str): Unused box_num_upbound (int):The upper limit on the number of instances in the figure """ def __init__(self, config_file, from_pretrained=None, key='img', box_num_upbound=-1, finesize=256): assert mmdet_apis is not None, ( "Cannot import 'mmdet'. Please install 'mmdet' via " "\"mim install 'mmdet >= 3.0.0'\".") cfg = get_config(config_file, pretrained=True) # loading checkpoint from local path if from_pretrained is not None: cfg.model.backbone.init_cfg.checkpoint = from_pretrained with DefaultScope.overwrite_default_scope('mmdet'): self.predictor = mmdet_apis.init_detector(cfg, cfg.model_path) self.key = key self.box_num_upbound = box_num_upbound self.final_size = finesize def transform(self, results: dict) -> dict: """The transform function of InstanceCrop. Args: results (dict): A dict containing the necessary information and data for Conversion Returns: results (dict): A dict containing the processed data and information. """ # get consistent box prediction based on L channel full_img = results['img'] full_img_size = results['ori_img_shape'][:-1][::-1] pred_bbox, pred_scores = self.predict_bbox(full_img) if self.box_num_upbound > 0 and pred_bbox.shape[ 0] > self.box_num_upbound: index_mask = np.argsort(pred_scores, axis=0) index_mask = index_mask[pred_scores.shape[0] - self.box_num_upbound:pred_scores.shape[0]] pred_bbox = pred_bbox[index_mask] # get cropped images and box info cropped_img_list = [] index_list = range(len(pred_bbox)) box_info, box_info_2x, box_info_4x, box_info_8x = np.zeros( (4, len(index_list), 6)) for i in index_list: startx, starty, endx, endy = pred_bbox[i] cropped_img = full_img[starty:endy, startx:endx, :] cropped_img_list.append(cropped_img) box_info[i] = np.array( get_box_info(pred_bbox[i], full_img_size, self.final_size)) box_info_2x[i] = np.array( get_box_info(pred_bbox[i], full_img_size, self.final_size // 2)) box_info_4x[i] = np.array( get_box_info(pred_bbox[i], full_img_size, self.final_size // 4)) box_info_8x[i] = np.array( get_box_info(pred_bbox[i], full_img_size, self.final_size // 8)) # update results if len(pred_bbox) > 0: results['cropped_img'] = cropped_img_list results['box_info'] = torch.from_numpy(box_info).type(torch.long) results['box_info_2x'] = torch.from_numpy(box_info_2x).type( torch.long) results['box_info_4x'] = torch.from_numpy(box_info_4x).type( torch.long) results['box_info_8x'] = torch.from_numpy(box_info_8x).type( torch.long) results['empty_box'] = False else: results['empty_box'] = True return results def predict_bbox(self, image): lab_image = cv.cvtColor(image, cv.COLOR_BGR2LAB) l_channel, _, _ = cv.split(lab_image) l_stack = np.stack([l_channel, l_channel, l_channel], axis=2) with DefaultScope.overwrite_default_scope('mmdet'): with torch.no_grad(): results = mmdet_apis.inference_detector( self.predictor, l_stack) bboxes = results.pred_instances.bboxes.cpu().numpy().astype(np.int32) scores = results.pred_instances.scores.cpu().numpy() index_mask = [i for i, x in enumerate(scores) if x >= 0.7] scores = np.array(scores[index_mask]) bboxes = np.array(bboxes[index_mask]) return bboxes, scores ================================================ FILE: mmagic/datasets/transforms/fgbg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Augmentation on foreground and background.""" import numbers import os.path as osp import mmcv import numpy as np from mmcv.transforms import BaseTransform from mmengine.fileio import get_file_backend from mmagic.registry import TRANSFORMS from mmagic.utils import add_gaussian_noise, adjust_gamma @TRANSFORMS.register_module() class CompositeFg(BaseTransform): """Composite foreground with a random foreground. This class composites the current training sample with additional data randomly (could be from the same dataset). With probability 0.5, the sample will be composited with a random sample from the specified directory. The composition is performed as: .. math:: fg_{new} = \\alpha_1 * fg_1 + (1 - \\alpha_1) * fg_2 \\alpha_{new} = 1 - (1 - \\alpha_1) * (1 - \\alpha_2) where :math:`(fg_1, \\alpha_1)` is from the current sample and :math:`(fg_2, \\alpha_2)` is the randomly loaded sample. With the above composition, :math:`\\alpha_{new}` is still in `[0, 1]`. Required keys are "alpha" and "fg". Modified keys are "alpha" and "fg". Args: fg_dirs (str | list[str]): Path of directories to load foreground images from. alpha_dirs (str | list[str]): Path of directories to load alpha mattes from. interpolation (str): Interpolation method of `mmcv.imresize` to resize the randomly loaded images. Default: 'nearest'. """ def __init__(self, fg_dirs, alpha_dirs, interpolation='nearest'): # TODO try fetch the path from dataset self.fg_dirs = fg_dirs if isinstance(fg_dirs, list) else [fg_dirs] self.alpha_dirs = alpha_dirs if isinstance(alpha_dirs, list) else [alpha_dirs] self.interpolation = interpolation self.file_backend = get_file_backend(uri=fg_dirs[0]) self.fg_list, self.alpha_list = self._get_file_list( self.fg_dirs, self.alpha_dirs) def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ fg = results['fg'] alpha = results['alpha'] / 255.0 # float64, H, W, 1 h, w = results['fg'].shape[:2] # randomly select fg if np.random.rand() < 0.5: idx = np.random.randint(len(self.fg_list)) fg2_bytes = self.file_backend.get(self.fg_list[idx]) fg2 = mmcv.imfrombytes(fg2_bytes) alpha2_bytes = self.file_backend.get(self.alpha_list[idx]) alpha2 = mmcv.imfrombytes(alpha2_bytes, flag='grayscale') alpha2 = alpha2 / 255.0 # float64 fg2 = mmcv.imresize(fg2, (w, h), interpolation=self.interpolation) alpha2 = mmcv.imresize( alpha2, (w, h), interpolation=self.interpolation) alpha2 = alpha2[..., None] # the overlap of two 50% transparency will be 75% alpha_tmp = 1 - (1 - alpha) * (1 - alpha2) # if the result alpha is all-one, then we avoid composition if np.any(alpha_tmp < 1): # composite fg with fg2 fg = fg * alpha + fg2 * (1 - alpha) alpha = alpha_tmp results['fg'] = fg results['alpha'] = alpha * 255 return results def _get_file_list(self, fg_dirs, alpha_dirs): all_fg_list = list() all_alpha_list = list() for fg_dir, alpha_dir in zip(fg_dirs, alpha_dirs): fg_list = sorted( self.file_backend.list_dir_or_file(fg_dir, list_dir=False)) alpha_list = sorted( self.file_backend.list_dir_or_file(alpha_dir, list_dir=False)) # we assume the file names for fg and alpha are the same assert len(fg_list) == len(alpha_list), ( f'{fg_dir} and {alpha_dir} should have the same number of ' f'images ({len(fg_list)} differs from ({len(alpha_list)})') fg_list = [osp.join(fg_dir, fg) for fg in fg_list] alpha_list = [osp.join(alpha_dir, alpha) for alpha in alpha_list] all_fg_list.extend(fg_list) all_alpha_list.extend(alpha_list) return all_fg_list, all_alpha_list def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(fg_dirs={repr(self.fg_dirs)}, ' f'alpha_dirs={repr(self.alpha_dirs)}, ' f'interpolation={repr(self.interpolation)})') return repr_str @TRANSFORMS.register_module() class MergeFgAndBg(BaseTransform): """Composite foreground image and background image with alpha. Required keys are "alpha", "fg" and "bg", added key is "merged". """ def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ alpha = results['alpha'].astype(np.float32) / 255. fg = results['fg'] bg = results['bg'] merged = fg * alpha + (1. - alpha) * bg results['merged'] = merged return results def __repr__(self) -> str: repr_str = f'{self.__class__.__name__}()' return repr_str @TRANSFORMS.register_module() class PerturbBg(BaseTransform): """Randomly add gaussian noise or gamma change to background image. Required key is "bg", added key is "noisy_bg". Args: gamma_ratio (float, optional): The probability to use gamma correction instead of gaussian noise. Defaults to 0.6. """ def __init__(self, gamma_ratio=0.6): if gamma_ratio < 0 or gamma_ratio > 1: raise ValueError('gamma_ratio must be a float between [0, 1], ' f'but got {gamma_ratio}') self.gamma_ratio = gamma_ratio def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ if np.random.rand() >= self.gamma_ratio: # generate gaussian noise with random gaussian N([-7, 7), [2, 6)) mu = np.random.randint(-7, 7) sigma = np.random.randint(2, 6) results['noisy_bg'] = add_gaussian_noise(results['bg'], mu, sigma) else: # adjust gamma in a range of N(1, 0.12) gamma = np.random.normal(1, 0.12) results['noisy_bg'] = adjust_gamma(results['bg'], gamma) return results def __repr__(self): return self.__class__.__name__ + f'(gamma_ratio={self.gamma_ratio})' @TRANSFORMS.register_module() class RandomJitter(BaseTransform): """Randomly jitter the foreground in hsv space. The jitter range of hue is adjustable while the jitter ranges of saturation and value are adaptive to the images. Side effect: the "fg" image will be converted to `np.float32`. Required keys are "fg" and "alpha", modified key is "fg". Args: hue_range (float | tuple[float]): Range of hue jittering. If it is a float instead of a tuple like (min, max), the range of hue jittering will be (-hue_range, +hue_range). Default: 40. """ def __init__(self, hue_range=40): if isinstance(hue_range, numbers.Number): assert hue_range >= 0, ('If hue_range is a single number, ' 'it must be positive.') self.hue_range = (-hue_range, hue_range) else: assert isinstance(hue_range, tuple) and len(hue_range) == 2, \ 'hue_range should be a tuple and it must be of length 2.' self.hue_range = hue_range def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ fg, alpha = results['fg'], results['alpha'] alpha = alpha[:, :, 0] # convert to HSV space; # convert to float32 image to keep precision during space conversion. fg = mmcv.bgr2hsv(fg.astype(np.float32) / 255) # Hue noise hue_jitter = np.random.randint(self.hue_range[0], self.hue_range[1]) fg[:, :, 0] = np.remainder(fg[:, :, 0] + hue_jitter, 360) # Saturation noise sat_mean = fg[:, :, 1][alpha > 0].mean() # jitter saturation within range (1.1 - sat_mean) * [-0.1, 0.1] sat_jitter = (1.1 - sat_mean) * (np.random.rand() * 0.2 - 0.1) sat = fg[:, :, 1] sat = np.abs(sat + sat_jitter) sat[sat > 1] = 2 - sat[sat > 1] fg[:, :, 1] = sat # Value noise val_mean = fg[:, :, 2][alpha > 0].mean() # jitter value within range (1.1 - val_mean) * [-0.1, 0.1] val_jitter = (1.1 - val_mean) * (np.random.rand() * 0.2 - 0.1) val = fg[:, :, 2] val = np.abs(val + val_jitter) val[val > 1] = 2 - val[val > 1] fg[:, :, 2] = val # convert back to BGR space fg = mmcv.hsv2bgr(fg) results['fg'] = fg * 255 return results def __repr__(self): return self.__class__.__name__ + f'hue_range={self.hue_range}' @TRANSFORMS.register_module() class RandomLoadResizeBg(BaseTransform): """Randomly load a background image and resize it. Required key is "fg", added key is "bg". Args: bg_dir (str): Path of directory to load background images from. flag (str): Loading flag for images. Default: 'color'. channel_order (str): Order of channel, candidates are 'bgr' and 'rgb'. Default: 'bgr'. kwargs (dict): Args for file client. """ def __init__(self, bg_dir, flag='color', channel_order='bgr'): self.bg_dir = bg_dir self.file_backend = get_file_backend(uri=bg_dir) self.bg_list = list( self.file_backend.list_dir_or_file(bg_dir, list_dir=False)) self.flag = flag self.channel_order = channel_order def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ h, w = results['fg'].shape[:2] idx = np.random.randint(len(self.bg_list)) filepath = f'{self.bg_dir}/{self.bg_list[idx]}' img_bytes = self.file_backend.get(filepath) img = mmcv.imfrombytes( img_bytes, flag=self.flag, channel_order=self.channel_order) # HWC bg = mmcv.imresize(img, (w, h), interpolation='bicubic') results['bg'] = bg return results def __repr__(self): return self.__class__.__name__ + f"(bg_dir='{self.bg_dir}')" ================================================ FILE: mmagic/datasets/transforms/formatting.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Tuple from mmcv.transforms.base import BaseTransform from mmagic.registry import TRANSFORMS from mmagic.structures import DataSample from mmagic.utils import all_to_tensor @TRANSFORMS.register_module() class PackInputs(BaseTransform): """Pack data into DataSample for training, evaluation and testing. MMagic follows the design of data structure from MMEngine. Data from the loader will be packed into data field of DataSample. More details of DataSample refer to the documentation of MMEngine: https://mmengine.readthedocs.io/en/latest/advanced_tutorials/data_element.html Args: keys Tuple[List[str], str, None]: The keys to saved in returned inputs, which are used as the input of models, default to ['img', 'noise', 'merged']. data_keys Tuple[List[str], str, None]: The keys to saved in `data_field` of the `data_samples`. meta_keys Tuple[List[str], str, None]: The meta keys to saved in `metainfo` of the `data_samples`. All the other data will be packed into the data of the `data_samples` """ def __init__( self, keys: Tuple[List[str], str] = ['merged', 'img'], meta_keys: Tuple[List[str], str] = [], data_keys: Tuple[List[str], str] = [], ) -> None: assert keys is not None, \ 'keys in PackInputs can not be None.' assert data_keys is not None, \ 'data_keys in PackInputs can not be None.' assert meta_keys is not None, \ 'meta_keys in PackInputs can not be None.' self.keys = keys if isinstance(keys, List) else [keys] self.data_keys = data_keys if isinstance(data_keys, List) else [data_keys] self.meta_keys = meta_keys if isinstance(meta_keys, List) else [meta_keys] def transform(self, results: dict) -> dict: """Method to pack the input data. Args: results (dict): Result dict from the data pipeline. Returns: dict: A dict contains - 'inputs' (obj:`dict`): The forward data of models. According to different tasks, the `inputs` may contain images, videos, labels, text, etc. - 'data_samples' (obj:`DataSample`): The annotation info of the sample. """ # prepare inputs inputs = dict() for k in self.keys: value = results.get(k, None) if value is not None: inputs[k] = all_to_tensor(value) # return the inputs as tensor, if it has only one item if len(inputs.values()) == 1: inputs = list(inputs.values())[0] data_sample = DataSample() # prepare metainfo and data in DataSample according to predefined keys predefined_data = { k: v for (k, v) in results.items() if k not in (self.data_keys + self.meta_keys) } data_sample.set_predefined_data(predefined_data) # prepare metainfo in DataSample according to user-provided meta_keys required_metainfo = { k: v for (k, v) in results.items() if k in self.meta_keys } data_sample.set_metainfo(required_metainfo) # prepare metainfo in DataSample according to user-provided data_keys required_data = { k: v for (k, v) in results.items() if k in self.data_keys } data_sample.set_tensor_data(required_data) return {'inputs': inputs, 'data_samples': data_sample} def __repr__(self) -> str: repr_str = self.__class__.__name__ return repr_str ================================================ FILE: mmagic/datasets/transforms/generate_assistant.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmcv.transforms.base import BaseTransform from mmagic.registry import TRANSFORMS from mmagic.utils import all_to_tensor, make_coord try: import face_alignment has_face_alignment = True except ImportError: has_face_alignment = False @TRANSFORMS.register_module() class GenerateCoordinateAndCell(BaseTransform): """Generate coordinate and cell. Generate coordinate from the desired size of SR image. Train or val: #. Generate coordinate from GT. #. Reshape GT image to (HgWg, 3) and transpose to (3, HgWg). where `Hg` and `Wg` represent the height and width of GT. Test: #. Generate coordinate from LQ and scale or target_size. #. Then generate cell from coordinate. Args: sample_quantity (int | None): The quantity of samples in coordinates. To ensure that the GT tensors in a batch have the same dimensions. Default: None. scale (float): Scale of upsampling. Default: None. target_size (tuple[int]): Size of target image. Default: None. reshape_gt (bool): Whether reshape gt to (-1, 3). Default: True If sample_quantity is not None, reshape_gt = True. The priority of getting 'size of target image' is: #. results['gt'].shape[-2:] #. results['lq'].shape[-2:] * scale #. target_size """ def __init__(self, sample_quantity=None, scale=None, target_size=None, reshape_gt=True): self.sample_quantity = sample_quantity self.scale = scale self.target_size = target_size self.reshape_gt = reshape_gt or sample_quantity is not None def transform(self, results): """Call function. Args: results (dict): A dict containing the necessary information and data for augmentation. Require either in results: 1. 'lq' (tensor), whose shape is similar as (3, H, W). 2. 'gt' (tensor), whose shape is similar as (3, H, W). 3. None, the premise is self.target_size and len(self.target_size) >= 2. Returns: dict: A dict containing the processed data and information. Reshape 'gt' to (-1, 3) and transpose to (3, -1) if 'gt' in results. Add 'coord' and 'cell'. """ # generate hr_coord (and hr_rgb) if 'gt' in results: crop_hr = results['gt'] crop_hr = all_to_tensor(crop_hr) self.target_size = crop_hr.shape if self.reshape_gt: hr_rgb = crop_hr.contiguous().view(3, -1).permute(1, 0) results['gt'] = hr_rgb elif self.scale is not None and 'img' in results: _, h_lr, w_lr = results['img'].shape self.target_size = (round(h_lr * self.scale), round(w_lr * self.scale)) else: assert self.target_size is not None assert len(self.target_size) >= 2 hr_coord = make_coord(self.target_size[-2:]) if self.sample_quantity is not None and 'gt' in results: sample_lst = np.random.choice( len(hr_coord), self.sample_quantity, replace=False) hr_coord = hr_coord[sample_lst] results['gt'] = results['gt'][sample_lst] # Preparations for cell decoding cell = torch.ones_like(hr_coord) cell[:, 0] *= 2 / self.target_size[-2] cell[:, 1] *= 2 / self.target_size[-1] results['coord'] = hr_coord results['cell'] = cell return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(sample_quantity={self.sample_quantity}, ' f'scale={self.scale}, target_size={self.target_size}, ' f'reshape_gt={self.reshape_gt})') return repr_str @TRANSFORMS.register_module() class GenerateFacialHeatmap(BaseTransform): """Generate heatmap from keypoint. Args: image_key (str): Key of facial image in dict. ori_size (int | Tuple[int]): Original image size of keypoint. target_size (int | Tuple[int]): Target size of heatmap. sigma (float): Sigma parameter of heatmap. Default: 1.0 use_cache (bool): If True, load all heatmap at once. Default: True. """ def __init__(self, image_key, ori_size, target_size, sigma=1.0, use_cache=True): if isinstance(ori_size, int): ori_size = (ori_size, ori_size) else: ori_size = ori_size[:2] if isinstance(target_size, int): target_size = (target_size, target_size) else: target_size = target_size[:2] self.size_ratio = (target_size[0] / ori_size[0], target_size[1] / ori_size[1]) self.image_key = image_key self.sigma = sigma self.target_size = target_size self.ori_size = ori_size self.use_cache = use_cache if use_cache: self.cache = dict() assert has_face_alignment, 'please import face-alignment.' device = 'cpu' self.face_alignment_model = face_alignment.FaceAlignment( face_alignment.LandmarksType._2D, device=device, flip_input=False) def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Require keypoint. Returns: dict: A dict containing the processed data and information. Add 'heatmap'. """ img = results[self.image_key] if self.use_cache: hash_key = f"{self.image_key}_{results['key']}" if hash_key in self.cache: heatmap = self.cache[hash_key] else: heatmap = self.generate_heatmap_from_img(img) self.cache[hash_key] = heatmap else: heatmap = self.generate_heatmap_from_img(img) results[f'{self.image_key}_heatmap'] = heatmap.astype(np.float32) return results def generate_heatmap_from_img(self, image): """Generate heatmap from img. Args: image (np.ndarray): Face image. results: heatmap (np.ndarray): Heatmap the face image. """ landmark = self._face_alignment_detector(image) keypoint_list = [(keypoint[0] * self.size_ratio[0], keypoint[1] * self.size_ratio[1]) for keypoint in landmark] heatmap_list = [ self._generate_one_heatmap(keypoint) for keypoint in keypoint_list ] return np.stack(heatmap_list, axis=2) def _face_alignment_detector(self, image): """Generate face landmark by face_alignment. Args: image (np.ndarray): Face image. Returns: landmark (Tuple[float]): Location of landmark. """ faces = self.face_alignment_model.get_landmarks(image) index = 0 max_size = 0 for i, face in enumerate(faces): size = face[8, 1] - face[19, 1] if size > max_size: max_size = size index = i landmark = faces[index] return landmark def _generate_one_heatmap(self, keypoint): """Generate One Heatmap. Args: keypoint (Tuple[float]): Location of a landmark. results: heatmap (np.ndarray): A heatmap of landmark. """ h, w = self.target_size x_range = np.arange(start=0, stop=w, dtype=int) y_range = np.arange(start=0, stop=h, dtype=int) grid_x, grid_y = np.meshgrid(x_range, y_range) dist2 = (grid_x - keypoint[0])**2 + (grid_y - keypoint[1])**2 exponent = dist2 / 2.0 / self.sigma / self.sigma heatmap = np.exp(-exponent) return heatmap def __repr__(self): return (f'{self.__class__.__name__}' f'(image_key={self.image_key}, ' f'ori_size={self.ori_size}, ' f'target_size={self.target_size}, ' f'sigma={self.sigma}, ' f'use_cache={self.use_cache})') ================================================ FILE: mmagic/datasets/transforms/generate_frame_indices.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import numpy as np from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class GenerateFrameIndices(BaseTransform): """Generate frame index for REDS datasets. It also performs temporal augmentation with random interval. Required Keys: - img_path - gt_path - key - num_input_frames Modified Keys: - img_path - gt_path Added Keys: - interval - reverse Args: interval_list (list[int]): Interval list for temporal augmentation. It will randomly pick an interval from interval_list and sample frame index with the interval. frames_per_clip(int): Number of frames per clips. Default: 99 for REDS dataset. """ def __init__(self, interval_list, frames_per_clip=99): self.interval_list = interval_list self.frames_per_clip = frames_per_clip def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ clip_name, frame_name = results['key'].split( os.sep) # key example: 000/00000000 center_frame_idx = int(frame_name) num_half_frames = results['num_input_frames'] // 2 sequence_length = results.get('sequence_length', self.frames_per_clip + 1) frames_per_clip = min(self.frames_per_clip, sequence_length - 1) interval = np.random.choice(self.interval_list) # ensure not exceeding the borders start_frame_idx = center_frame_idx - num_half_frames * interval end_frame_idx = center_frame_idx + num_half_frames * interval while (start_frame_idx < 0) or (end_frame_idx > frames_per_clip): center_frame_idx = np.random.randint(0, frames_per_clip + 1) start_frame_idx = center_frame_idx - num_half_frames * interval end_frame_idx = center_frame_idx + num_half_frames * interval frame_name = f'{center_frame_idx:08d}' neighbor_list = list( range(center_frame_idx - num_half_frames * interval, center_frame_idx + num_half_frames * interval + 1, interval)) img_path_root = results['img_path'] gt_path_root = results['gt_path'] img_path = [ osp.join(img_path_root, clip_name, f'{v:08d}.png') for v in neighbor_list ] gt_path = [osp.join(gt_path_root, clip_name, f'{frame_name}.png')] results['img_path'] = img_path results['gt_path'] = gt_path results['interval'] = interval return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(interval_list={self.interval_list}, ' f'frames_per_clip={self.frames_per_clip})') return repr_str @TRANSFORMS.register_module() class GenerateFrameIndiceswithPadding(BaseTransform): """Generate frame index with padding for REDS dataset and Vid4 dataset during testing. Required Keys: - img_path - gt_path - key - num_input_frames - sequence_length Modified Keys: - img_path - gt_path Args: padding (str): padding mode, one of 'replicate' | 'reflection' | 'reflection_circle' | 'circle'. Examples: current_idx = 0, num_input_frames = 5 The generated frame indices under different padding mode: replicate: [0, 0, 0, 1, 2] reflection: [2, 1, 0, 1, 2] reflection_circle: [4, 3, 0, 1, 2] circle: [3, 4, 0, 1, 2] filename_tmpl (str): Template for file name. Default: '{:08d}'. """ def __init__(self, padding, filename_tmpl='{:08d}'): if padding not in ('replicate', 'reflection', 'reflection_circle', 'circle'): raise ValueError(f'Wrong padding mode {padding}.' 'Should be "replicate", "reflection", ' '"reflection_circle", "circle"') self.padding = padding self.filename_tmpl = filename_tmpl def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ clip_name, frame_name = results['key'].split(os.sep) current_idx = int(frame_name) sequence_length = results['sequence_length'] - 1 # start from 0 num_input_frames = results['num_input_frames'] num_pad = num_input_frames // 2 frame_list = [] for i in range(current_idx - num_pad, current_idx + num_pad + 1): if i < 0: if self.padding == 'replicate': pad_idx = 0 elif self.padding == 'reflection': pad_idx = -i elif self.padding == 'reflection_circle': pad_idx = current_idx + num_pad - i else: pad_idx = num_input_frames + i elif i > sequence_length: if self.padding == 'replicate': pad_idx = sequence_length elif self.padding == 'reflection': pad_idx = sequence_length * 2 - i elif self.padding == 'reflection_circle': pad_idx = (current_idx - num_pad) - (i - sequence_length) else: pad_idx = i - num_input_frames else: pad_idx = i frame_list.append(pad_idx) img_path_root = results['img_path'] gt_path_root = results['gt_path'] img_paths = [ osp.join(img_path_root, clip_name, f'{self.filename_tmpl.format(idx)}.png') for idx in frame_list ] gt_paths = [osp.join(gt_path_root, clip_name, f'{frame_name}.png')] results['img_path'] = img_paths results['gt_path'] = gt_paths return results def __repr__(self): repr_str = self.__class__.__name__ + f"(padding='{self.padding}')" return repr_str @TRANSFORMS.register_module() class GenerateSegmentIndices(BaseTransform): """Generate frame indices for a segment. It also performs temporal augmentation with random interval. Required Keys: - img_path - gt_path - key - num_input_frames - sequence_length Modified Keys: - img_path - gt_path Added Keys: - interval - reverse Args: interval_list (list[int]): Interval list for temporal augmentation. It will randomly pick an interval from interval_list and sample frame index with the interval. start_idx (int): The index corresponds to the first frame in the sequence. Default: 0. filename_tmpl (str): Template for file name. Default: '{:08d}.png'. """ def __init__(self, interval_list, start_idx=0, filename_tmpl='{:08d}.png'): self.interval_list = interval_list self.filename_tmpl = filename_tmpl self.start_idx = start_idx def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ # key example: '000', 'calendar' (sequence name) clip_name = results['key'] interval = np.random.choice(self.interval_list) self.sequence_length = results['sequence_length'] num_input_frames = results.get('num_input_frames', self.sequence_length) if num_input_frames is None: num_input_frames = self.sequence_length # randomly select a frame as start if self.sequence_length - num_input_frames * interval < 0: raise ValueError('The input sequence is not long enough to ' 'support the current choice of [interval] or ' '[num_input_frames].') start_frame_idx = np.random.randint( 0, self.sequence_length - num_input_frames * interval + 1) end_frame_idx = start_frame_idx + num_input_frames * interval neighbor_list = list(range(start_frame_idx, end_frame_idx, interval)) neighbor_list = [v + self.start_idx for v in neighbor_list] # add the corresponding file paths img_path_root = results['img_path'] gt_path_root = results['gt_path'] img_path = [ osp.join(img_path_root, clip_name, self.filename_tmpl.format(v)) for v in neighbor_list ] gt_path = [ osp.join(gt_path_root, clip_name, self.filename_tmpl.format(v)) for v in neighbor_list ] results['img_path'] = img_path results['gt_path'] = gt_path results['interval'] = interval return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(interval_list={self.interval_list})') return repr_str ================================================ FILE: mmagic/datasets/transforms/get_masked_image.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np from mmcv.transforms.base import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class GetMaskedImage(BaseTransform): """Get masked image. Args: img_key (str): Key for clean image. Default: 'gt'. mask_key (str): Key for mask image. The mask shape should be (h, w, 1) while '1' indicate holes and '0' indicate valid regions. Default: 'mask'. img_key (str): Key for output image. Default: 'img'. zero_value (float): Pixel value of masked area. """ def __init__(self, img_key='gt', mask_key='mask', out_key='img', zero_value=127.5): self.img_key = img_key self.mask_key = mask_key self.out_key = out_key self.zero_value = zero_value def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ clean_img = results[self.img_key] # uint8 mask = results[self.mask_key] # uint8 masked_img = clean_img * (1.0 - mask) + self.zero_value * mask masked_img = masked_img.astype(np.float32) results[self.out_key] = masked_img # copy metainfo if f'ori_{self.img_key}_shape' in results: results[f'ori_{self.out_key}_shape'] = deepcopy( results[f'ori_{self.img_key}_shape']) if f'{self.img_key}_channel_order' in results: results[f'{self.out_key}_channel_order'] = deepcopy( results[f'{self.img_key}_channel_order']) if f'{self.img_key}_color_type' in results: results[f'{self.out_key}_color_type'] = deepcopy( results[f'{self.img_key}_color_type']) return results def __repr__(self): return self.__class__.__name__ + ( f'(img_key={repr(self.img_key)}, ' f'mask_key={repr(self.mask_key)}, ' f'out_key={repr(self.out_key)}, ' f'zero_value={repr(self.zero_value)})') ================================================ FILE: mmagic/datasets/transforms/loading.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from typing import List, Optional, Tuple import mmcv import numpy as np from mmcv.transforms import BaseTransform from mmengine.fileio import get_file_backend, list_from_file from mmagic.registry import TRANSFORMS from mmagic.utils import (bbox2mask, brush_stroke_mask, get_irregular_mask, random_bbox) @TRANSFORMS.register_module() class LoadImageFromFile(BaseTransform): """Load a single image or image frames from corresponding paths. Required Keys: - [Key]_path New Keys: - [KEY] - ori_[KEY]_shape - ori_[KEY] Args: key (str): Keys in results to find corresponding path. color_type (str): The flag argument for :func:``mmcv.imfrombytes``. Defaults to 'color'. channel_order (str): Order of channel, candidates are 'bgr' and 'rgb'. Default: 'bgr'. imdecode_backend (str): The image decoding backend type. The backend argument for :func:``mmcv.imfrombytes``. See :func:``mmcv.imfrombytes`` for details. candidates are 'cv2', 'turbojpeg', 'pillow', and 'tifffile'. Defaults to None. use_cache (bool): If True, load all images at once. Default: False. to_float32 (bool): Whether to convert the loaded image to a float32 numpy array. If set to False, the loaded image is an uint8 array. Defaults to False. to_y_channel (bool): Whether to convert the loaded image to y channel. Only support 'rgb2ycbcr' and 'rgb2ycbcr' Defaults to False. backend_args (dict, optional): Arguments to instantiate the prefix of uri corresponding backend. Defaults to None. """ def __init__( self, key: str, color_type: str = 'color', channel_order: str = 'bgr', imdecode_backend: Optional[str] = None, use_cache: bool = False, to_float32: bool = False, to_y_channel: bool = False, save_original_img: bool = False, backend_args: Optional[dict] = None, ) -> None: self.key = key self.color_type = color_type self.channel_order = channel_order self.imdecode_backend = imdecode_backend self.save_original_img = save_original_img if backend_args is None: # lasy init at loading self.backend_args = None self.file_backend = None else: self.backend_args = backend_args.copy() self.file_backend = get_file_backend(backend_args=backend_args) # cache self.use_cache = use_cache self.cache = dict() # convert self.to_float32 = to_float32 self.to_y_channel = to_y_channel def transform(self, results: dict) -> dict: """Functions to load image or frames. Args: results (dict): Result dict from :obj:``mmcv.BaseDataset``. Returns: dict: The dict contains loaded image and meta information. """ filenames = results[f'{self.key}_path'] if not isinstance(filenames, (List, Tuple)): filenames = [str(filenames)] is_frames = False else: filenames = [str(v) for v in filenames] is_frames = True images = [] shapes = [] if self.save_original_img: ori_imgs = [] for filename in filenames: img = self._load_image(filename) img = self._convert(img) images.append(img) shapes.append(img.shape) if self.save_original_img: ori_imgs.append(img.copy()) if not is_frames: images = images[0] shapes = shapes[0] if self.save_original_img: ori_imgs = ori_imgs[0] results[self.key] = images results[f'ori_{self.key}_shape'] = shapes results[f'{self.key}_channel_order'] = self.channel_order results[f'{self.key}_color_type'] = self.color_type if self.save_original_img: results[f'ori_{self.key}'] = ori_imgs return results def _load_image(self, filename): """Load an image from file. Args: filename (str): Path of image file. Returns: np.ndarray: Image. """ if self.file_backend is None: self.file_backend = get_file_backend( uri=filename, backend_args=self.backend_args) if (self.backend_args is not None) and (self.backend_args.get( 'backend', None) == 'lmdb'): filename, _ = osp.splitext(osp.basename(filename)) if filename in self.cache: img_bytes = self.cache[filename] else: img_bytes = self.file_backend.get(filename) if self.use_cache: self.cache[filename] = img_bytes img = mmcv.imfrombytes( content=img_bytes, flag=self.color_type, channel_order=self.channel_order, backend=self.imdecode_backend) return img def _convert(self, img: np.ndarray): """Convert an image to the require format. Args: img (np.ndarray): The original image. Returns: np.ndarray: The converted image. """ if self.to_y_channel: if self.channel_order.lower() == 'rgb': img = mmcv.rgb2ycbcr(img, y_only=True) elif self.channel_order.lower() == 'bgr': img = mmcv.bgr2ycbcr(img, y_only=True) else: raise ValueError('Currently support only "bgr2ycbcr" or ' '"bgr2ycbcr".') if img.ndim == 2: img = np.expand_dims(img, axis=2) if self.to_float32: img = img.astype(np.float32) return img def __repr__(self): repr_str = (f'{self.__class__.__name__}(' f'key={self.key}, ' f'color_type={self.color_type}, ' f'channel_order={self.channel_order}, ' f'imdecode_backend={self.imdecode_backend}, ' f'use_cache={self.use_cache}, ' f'to_float32={self.to_float32}, ' f'to_y_channel={self.to_y_channel}, ' f'save_original_img={self.save_original_img}, ' f'backend_args={self.backend_args})') return repr_str @TRANSFORMS.register_module() class LoadMask(BaseTransform): """Load Mask for multiple types. For different types of mask, users need to provide the corresponding config dict. Example config for bbox: .. code-block:: python config = dict(img_shape=(256, 256), max_bbox_shape=128) Example config for irregular: .. code-block:: python config = dict( img_shape=(256, 256), num_vertices=(4, 12), max_angle=4., length_range=(10, 100), brush_width=(10, 40), area_ratio_range=(0.15, 0.5)) Example config for ff: .. code-block:: python config = dict( img_shape=(256, 256), num_vertices=(4, 12), mean_angle=1.2, angle_range=0.4, brush_width=(12, 40)) Example config for set: .. code-block:: python config = dict( mask_list_file='xxx/xxx/ooxx.txt', prefix='/xxx/xxx/ooxx/', io_backend='local', color_type='unchanged', file_client_kwargs=dict() ) The mask_list_file contains the list of mask file name like this: test1.jpeg test2.jpeg ... ... The prefix gives the data path. Args: mask_mode (str): Mask mode in ['bbox', 'irregular', 'ff', 'set', 'file']. Default: 'bbox'. * bbox: square bounding box masks. * irregular: irregular holes. * ff: free-form holes from DeepFillv2. * set: randomly get a mask from a mask set. * file: get mask from 'mask_path' in results. mask_config (dict): Params for creating masks. Each type of mask needs different configs. Default: None. """ def __init__(self, mask_mode='bbox', mask_config=None): self.mask_mode = mask_mode self.mask_config = dict() if mask_config is None else mask_config assert isinstance(self.mask_config, dict) # set init info if needed in some modes self._init_info() def _init_info(self): if self.mask_mode == 'set': # get mask list information self.io_backend = self.mask_config['io_backend'] self.color_type = self.mask_config['color_type'] self.file_prefix = self.mask_config['prefix'] self.file_client_kwargs = self.mask_config['file_client_kwargs'] self.file_backend = None mask_list_file = self.mask_config['mask_list_file'] self.mask_list = list_from_file( mask_list_file, backend_args=self.file_client_kwargs) self.mask_list = [ osp.join(self.file_prefix, i) for i in self.mask_list ] self.mask_set_size = len(self.mask_list) elif self.mask_mode == 'file': self.io_backend = 'local' self.color_type = 'unchanged' self.file_client_kwargs = dict() self.file_backend = None def _get_random_mask_from_set(self): if self.file_backend is None: self.file_backend = get_file_backend( backend_args={'backend': self.io_backend}) # minus 1 to avoid out of range error mask_idx = np.random.randint(0, self.mask_set_size) mask_bytes = self.file_backend.get(self.mask_list[mask_idx]) mask = mmcv.imfrombytes(mask_bytes, flag=self.color_type) # HWC, BGR if mask.ndim == 2: mask = np.expand_dims(mask, axis=2) else: mask = mask[:, :, 0:1] mask[mask > 0] = 1. return mask def _get_mask_from_file(self, path): if self.file_backend is None: backend_args = self.file_client_kwargs.copy() backend_args['backend'] = self.io_backend self.file_backend = get_file_backend(backend_args=backend_args) mask_bytes = self.file_backend.get(path) mask = mmcv.imfrombytes(mask_bytes, flag=self.color_type) # HWC, BGR if mask.ndim == 2: mask = np.expand_dims(mask, axis=2) else: mask = mask[:, :, 0:1] mask[mask > 0] = 1. return mask def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ if self.mask_mode == 'bbox': mask_bbox = random_bbox(**self.mask_config) mask = bbox2mask(self.mask_config['img_shape'], mask_bbox) results['mask_bbox'] = mask_bbox elif self.mask_mode == 'irregular': mask = get_irregular_mask(**self.mask_config) elif self.mask_mode == 'set': mask = self._get_random_mask_from_set() elif self.mask_mode == 'ff': mask = brush_stroke_mask(**self.mask_config) elif self.mask_mode == 'file': mask = self._get_mask_from_file(results['mask_path']) else: raise NotImplementedError( f'Mask mode {self.mask_mode} has not been implemented.') results['mask'] = mask return results def __repr__(self): return self.__class__.__name__ + f"(mask_mode='{self.mask_mode}')" @TRANSFORMS.register_module() class GetSpatialDiscountMask(BaseTransform): """Get spatial discounting mask constant. Spatial discounting mask is first introduced in: Generative Image Inpainting with Contextual Attention. Args: gamma (float, optional): Gamma for computing spatial discounting. Defaults to 0.99. beta (float, optional): Beta for computing spatial discounting. Defaults to 1.5. """ def __init__(self, gamma=0.99, beta=1.5): self.gamma = gamma self.beta = beta def spatial_discount_mask(self, mask_width, mask_height): """Generate spatial discounting mask constant. Args: mask_width (int): The width of bbox hole. mask_height (int): The height of bbox height. Returns: np.ndarray: Spatial discounting mask. """ w, h = np.meshgrid(np.arange(mask_width), np.arange(mask_height)) grid_stack = np.stack([h, w], axis=2) mask_values = (self.gamma**(np.minimum( grid_stack, [mask_height - 1, mask_width - 1] - grid_stack) * self.beta)).max( axis=2, keepdims=True) return mask_values def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ mask_bbox = results['mask_bbox'] mask = results['mask'] mask_height, mask_width = mask_bbox[-2:] discount_hole = self.spatial_discount_mask(mask_width, mask_height) discount_mask = np.zeros_like(mask) discount_mask[mask_bbox[0]:mask_bbox[0] + mask_height, mask_bbox[1]:mask_bbox[1] + mask_width, ...] = discount_hole results['discount_mask'] = discount_mask return results def __repr__(self): return self.__class__.__name__ + (f'(gamma={self.gamma}, ' f'beta={self.beta})') @TRANSFORMS.register_module() class LoadPairedImageFromFile(LoadImageFromFile): """Load a pair of images from file. Each sample contains a pair of images, which are concatenated in the w dimension (a|b). This is a special loading class for generation paired dataset. It loads a pair of images as the common loader does and crops it into two images with the same shape in different domains. Required key is "pair_path". Added or modified keys are "pair", "pair_ori_shape", "ori_pair", "img_{domain_a}", "img_{domain_b}", "img_{domain_a}_path", "img_{domain_b}_path", "img_{domain_a}_ori_shape", "img_{domain_b}_ori_shape", "ori_img_{domain_a}" and "ori_img_{domain_b}". Args: key (str): Keys in results to find corresponding path. domain_a (str, Optional): One of the paired image domain. Defaults to 'A'. domain_b (str, Optional): The other of the paired image domain. Defaults to 'B'. color_type (str): The flag argument for :func:``mmcv.imfrombytes``. Defaults to 'color'. channel_order (str): Order of channel, candidates are 'bgr' and 'rgb'. Default: 'bgr'. imdecode_backend (str): The image decoding backend type. The backend argument for :func:``mmcv.imfrombytes``. See :func:``mmcv.imfrombytes`` for details. candidates are 'cv2', 'turbojpeg', 'pillow', and 'tifffile'. Defaults to None. use_cache (bool): If True, load all images at once. Default: False. to_float32 (bool): Whether to convert the loaded image to a float32 numpy array. If set to False, the loaded image is an uint8 array. Defaults to False. to_y_channel (bool): Whether to convert the loaded image to y channel. Only support 'rgb2ycbcr' and 'rgb2ycbcr' Defaults to False. backend_args (dict, optional): Arguments to instantiate the prefix of uri corresponding backend. Defaults to None. io_backend (str, optional): io backend where images are store. Defaults to None. """ def __init__(self, key: str, domain_a: str = 'A', domain_b: str = 'B', color_type: str = 'color', channel_order: str = 'bgr', imdecode_backend: Optional[str] = None, use_cache: bool = False, to_float32: bool = False, to_y_channel: bool = False, save_original_img: bool = False, backend_args: Optional[dict] = None): super().__init__(key, color_type, channel_order, imdecode_backend, use_cache, to_float32, to_y_channel, save_original_img, backend_args) assert isinstance(domain_a, str) assert isinstance(domain_b, str) self.domain_a = domain_a self.domain_b = domain_b def transform(self, results: dict) -> dict: """Functions to load paired images. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ filename = results[f'{self.key}_path'] image = self._load_image(filename) image = self._convert(image) if self.save_original_img: ori_image = image.copy() shape = image.shape # crop pair into a and b w = shape[1] if w % 2 != 0: raise ValueError( f'The width of image pair must be even number, but got {w}.') new_w = w // 2 image_a = image[:, :new_w, :] image_b = image[:, new_w:, :] results[f'img_{self.domain_a}'] = image_a results[f'img_{self.domain_b}'] = image_b results[f'img_{self.domain_a}_path'] = filename results[f'img_{self.domain_b}_path'] = filename results[f'img_{self.domain_a}_ori_shape'] = image_a.shape results[f'img_{self.domain_b}_ori_shape'] = image_b.shape if self.save_original_img: results[f'ori_img_{self.domain_a}'] = image_a.copy() results[f'ori_img_{self.domain_b}'] = image_b.copy() results[self.key] = image results[f'ori_{self.key}_shape'] = shape results[f'{self.key}_channel_order'] = self.channel_order results[f'{self.key}_color_type'] = self.color_type if self.save_original_img: results[f'ori_{self.key}'] = ori_image return results ================================================ FILE: mmagic/datasets/transforms/matlab_like_resize.py ================================================ # This code is referenced from matlab_imresize with modifications # Reference: # https://github.com/fatheral/matlab_imresize/blob/master/imresize.py # Original license: Copyright (c) 2020 fatheral, under the MIT License. import numpy as np from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS def get_size_from_scale(input_size, scale_factor): """Get the output size given input size and scale factor. Args: input_size (tuple): The size of the input image. scale_factor (float): The resize factor. Returns: output_shape (list[int]): The size of the output image. """ output_shape = [ int(np.ceil(scale * shape)) for (scale, shape) in zip(scale_factor, input_size) ] return output_shape def get_scale_from_size(input_size, output_size): """Get the scale factor given input size and output size. Args: input_size (tuple(int)): The size of the input image. output_size (tuple(int)): The size of the output image. Returns: scale (list[float]): The scale factor of each dimension. """ scale = [ 1.0 * output_shape / input_shape for (input_shape, output_shape) in zip(input_size, output_size) ] return scale def _cubic(x): """Cubic function. Args: x (np.ndarray): The distance from the center position. Returns: np.ndarray: The weight corresponding to a particular distance. """ x = np.array(x, dtype=np.float32) x_abs = np.abs(x) x_abs_sq = x_abs**2 x_abs_cu = x_abs_sq * x_abs # if |x| <= 1: y = 1.5|x|^3 - 2.5|x|^2 + 1 # if 1 < |x| <= 2: -0.5|x|^3 + 2.5|x|^2 - 4|x| + 2 f = (1.5 * x_abs_cu - 2.5 * x_abs_sq + 1) * (x_abs <= 1) + ( -0.5 * x_abs_cu + 2.5 * x_abs_sq - 4 * x_abs + 2) * ((1 < x_abs) & (x_abs <= 2)) return f def get_weights_indices(input_length, output_length, scale, kernel, kernel_width): """Get weights and indices for interpolation. Args: input_length (int): Length of the input sequence. output_length (int): Length of the output sequence. scale (float): Scale factor. kernel (func): The kernel used for resizing. kernel_width (int): The width of the kernel. Returns: tuple(list[np.ndarray], list[np.ndarray]): The weights and the indices for interpolation. """ if scale < 1: # modified kernel for antialiasing def h(x): return scale * kernel(scale * x) kernel_width = 1.0 * kernel_width / scale else: h = kernel kernel_width = kernel_width # coordinates of output x = np.arange(1, output_length + 1).astype(np.float32) # coordinates of input u = x / scale + 0.5 * (1 - 1 / scale) left = np.floor(u - kernel_width / 2) # leftmost pixel p = int(np.ceil(kernel_width)) + 2 # maximum number of pixels # indices of input pixels ind = left[:, np.newaxis, ...] + np.arange(p) indices = ind.astype(np.int32) # weights of input pixels weights = h(u[:, np.newaxis, ...] - indices - 1) weights = weights / np.sum(weights, axis=1)[:, np.newaxis, ...] # remove all-zero columns aux = np.concatenate( (np.arange(input_length), np.arange(input_length - 1, -1, step=-1))).astype(np.int32) indices = aux[np.mod(indices, aux.size)] ind2store = np.nonzero(np.any(weights, axis=0)) weights = weights[:, ind2store] indices = indices[:, ind2store] return weights, indices def resize_along_dim(img_in, weights, indices, dim): """Resize along a specific dimension. Args: img_in (np.ndarray): The input image. weights (ndarray): The weights used for interpolation, computed from [get_weights_indices]. indices (ndarray): The indices used for interpolation, computed from [get_weights_indices]. dim (int): Which dimension to undergo interpolation. Returns: np.ndarray: Interpolated (along one dimension) image. """ img_in = img_in.astype(np.float32) w_shape = weights.shape output_shape = list(img_in.shape) output_shape[dim] = w_shape[0] img_out = np.zeros(output_shape) if dim == 0: for i in range(w_shape[0]): w = weights[i, :][np.newaxis, ...] ind = indices[i, :] img_slice = img_in[ind, :] img_out[i] = np.sum(np.squeeze(img_slice, axis=0) * w.T, axis=0) elif dim == 1: for i in range(w_shape[0]): w = weights[i, :][:, :, np.newaxis] ind = indices[i, :] img_slice = img_in[:, ind] img_out[:, i] = np.sum(np.squeeze(img_slice, axis=1) * w.T, axis=1) if img_in.dtype == np.uint8: img_out = np.clip(img_out, 0, 255) return np.around(img_out).astype(np.uint8) else: return img_out @TRANSFORMS.register_module() class MATLABLikeResize(BaseTransform): """Resize the input image using MATLAB-like downsampling. Currently support bicubic interpolation only. Note that the output of this function is slightly different from the official MATLAB function. Required keys are the keys in attribute "keys". Added or modified keys are "scale" and "output_shape", and the keys in attribute "keys". Args: keys (list[str]): A list of keys whose values are modified. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. kernel (str, optional): The kernel for the resize operation. Currently support 'bicubic' only. Default: 'bicubic'. kernel_width (float): The kernel width. Currently support 4.0 only. Default: 4.0. """ def __init__(self, keys, scale=None, output_shape=None, kernel='bicubic', kernel_width=4.0): if kernel.lower() != 'bicubic': raise ValueError('Currently support bicubic kernel only.') if float(kernel_width) != 4.0: raise ValueError('Current support only width=4 only.') if scale is None and output_shape is None: raise ValueError('"scale" and "output_shape" cannot be both None') self.kernel_func = _cubic self.keys = keys self.scale = scale self.output_shape = output_shape self.kernel = kernel self.kernel_width = kernel_width def _resize(self, img): """resize an image to the require size. Args: img (np.ndarray): The original image. Returns: output (np.ndarray): The resized image. """ weights = {} indices = {} # compute scale and output_size if self.scale is not None: scale = float(self.scale) scale = [scale, scale] output_size = get_size_from_scale(img.shape, scale) else: scale = get_scale_from_size(img.shape, self.output_shape) output_size = list(self.output_shape) # apply cubic interpolation along two dimensions order = np.argsort(np.array(scale)) for k in range(2): key = (img.shape[k], output_size[k], scale[k], self.kernel_func, self.kernel_width) weight, index = get_weights_indices(img.shape[k], output_size[k], scale[k], self.kernel_func, self.kernel_width) weights[key] = weight indices[key] = index output = np.copy(img) if output.ndim == 2: # grayscale image output = output[:, :, np.newaxis] for k in range(2): dim = order[k] key = (img.shape[dim], output_size[dim], scale[dim], self.kernel_func, self.kernel_width) output = resize_along_dim(output, weights[key], indices[key], dim) return output def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: is_single_image = False if isinstance(results[key], np.ndarray): is_single_image = True results[key] = [results[key]] results[key] = [self._resize(img) for img in results[key]] if is_single_image: results[key] = results[key][0] results['scale'] = self.scale results['output_shape'] = self.output_shape return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += ( f'(keys={self.keys}, scale={self.scale}, ' f'output_shape={self.output_shape}, ' f'kernel={self.kernel}, kernel_width={self.kernel_width})') return repr_str ================================================ FILE: mmagic/datasets/transforms/normalization.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmcv import numpy as np from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class Normalize(BaseTransform): """Normalize images with the given mean and std value. Required keys are the keys in attribute "keys", added or modified keys are the keys in attribute "keys" and these keys with postfix '_norm_cfg'. It also supports normalizing a list of images. Args: keys (Sequence[str]): The images to be normalized. mean (np.ndarray): Mean values of different channels. std (np.ndarray): Std values of different channels. to_rgb (bool): Whether to convert channels from BGR to RGB. Default: False. save_original (bool): Whether to save original images. Default: False. """ def __init__(self, keys, mean, std, to_rgb=False, save_original=False): self.keys = keys self.mean = np.array(mean, dtype=np.float32) self.std = np.array(std, dtype=np.float32) self.to_rgb = to_rgb self.save_original = save_original def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: if isinstance(results[key], list): if self.save_original: results[key + '_unnormalised'] = [ v.copy() for v in results[key] ] results[key] = [ mmcv.imnormalize(v, self.mean, self.std, self.to_rgb) for v in results[key] ] else: if self.save_original: results[key + '_unnormalised'] = results[key].copy() results[key] = mmcv.imnormalize(results[key], self.mean, self.std, self.to_rgb) results['img_norm_cfg'] = dict( mean=self.mean, std=self.std, to_rgb=self.to_rgb) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(keys={self.keys}, mean={self.mean}, std={self.std}, ' f'to_rgb={self.to_rgb})') return repr_str @TRANSFORMS.register_module() class RescaleToZeroOne(BaseTransform): """Transform the images into a range between 0 and 1. Required keys are the keys in attribute "keys", added or modified keys are the keys in attribute "keys". It also supports rescaling a list of images. Args: keys (Sequence[str]): The images to be transformed. """ def __init__(self, keys): self.keys = keys def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ for key in self.keys: if isinstance(results[key], list): results[key] = [ v.astype(np.float32) / 255. for v in results[key] ] else: results[key] = results[key].astype(np.float32) / 255. return results def __repr__(self): return self.__class__.__name__ + f'(keys={self.keys})' ================================================ FILE: mmagic/datasets/transforms/random_degradations.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import io import logging import random import cv2 import numpy as np from mmagic.datasets.transforms import blur_kernels from mmagic.registry import TRANSFORMS try: import av has_av = True except ImportError: has_av = False @TRANSFORMS.register_module() class RandomBlur: """Apply random blur to the input. Modified keys are the attributed specified in "keys". Args: params (dict): A dictionary specifying the degradation settings. keys (list[str]): A list specifying the keys whose values are modified. """ def __init__(self, params, keys): self.keys = keys self.params = params def get_kernel(self, num_kernels: int): """This is the function to create kernel. Args: num_kernels (int): the number of kernels Returns: _type_: _description_ """ kernel_type = np.random.choice( self.params['kernel_list'], p=self.params['kernel_prob']) kernel_size = random.choice(self.params['kernel_size']) sigma_x_range = self.params.get('sigma_x', [0, 0]) sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1]) sigma_x_step = self.params.get('sigma_x_step', 0) sigma_y_range = self.params.get('sigma_y', [0, 0]) sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1]) sigma_y_step = self.params.get('sigma_y_step', 0) rotate_angle_range = self.params.get('rotate_angle', [-np.pi, np.pi]) rotate_angle = np.random.uniform(rotate_angle_range[0], rotate_angle_range[1]) rotate_angle_step = self.params.get('rotate_angle_step', 0) beta_gau_range = self.params.get('beta_gaussian', [0.5, 4]) beta_gau = np.random.uniform(beta_gau_range[0], beta_gau_range[1]) beta_gau_step = self.params.get('beta_gaussian_step', 0) beta_pla_range = self.params.get('beta_plateau', [1, 2]) beta_pla = np.random.uniform(beta_pla_range[0], beta_pla_range[1]) beta_pla_step = self.params.get('beta_plateau_step', 0) omega_range = self.params.get('omega', None) omega_step = self.params.get('omega_step', 0) if omega_range is None: # follow Real-ESRGAN settings if not specified if kernel_size < 13: omega_range = [np.pi / 3., np.pi] else: omega_range = [np.pi / 5., np.pi] omega = np.random.uniform(omega_range[0], omega_range[1]) # determine blurring kernel kernels = [] for _ in range(0, num_kernels): kernel = blur_kernels.random_mixed_kernels( [kernel_type], [1], kernel_size, [sigma_x, sigma_x], [sigma_y, sigma_y], [rotate_angle, rotate_angle], [beta_gau, beta_gau], [beta_pla, beta_pla], [omega, omega], None, ) kernels.append(kernel) # update kernel parameters sigma_x += np.random.uniform(-sigma_x_step, sigma_x_step) sigma_y += np.random.uniform(-sigma_y_step, sigma_y_step) rotate_angle += np.random.uniform(-rotate_angle_step, rotate_angle_step) beta_gau += np.random.uniform(-beta_gau_step, beta_gau_step) beta_pla += np.random.uniform(-beta_pla_step, beta_pla_step) omega += np.random.uniform(-omega_step, omega_step) sigma_x = np.clip(sigma_x, sigma_x_range[0], sigma_x_range[1]) sigma_y = np.clip(sigma_y, sigma_y_range[0], sigma_y_range[1]) rotate_angle = np.clip(rotate_angle, rotate_angle_range[0], rotate_angle_range[1]) beta_gau = np.clip(beta_gau, beta_gau_range[0], beta_gau_range[1]) beta_pla = np.clip(beta_pla, beta_pla_range[0], beta_pla_range[1]) omega = np.clip(omega, omega_range[0], omega_range[1]) return kernels def _apply_random_blur(self, imgs): """This is the function to apply blur operation on images. Args: imgs (Tensor): images Returns: Tensor: Images applied blur """ is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] # get kernel and blur the input kernels = self.get_kernel(num_kernels=len(imgs)) imgs = [ cv2.filter2D(img, -1, kernel) for img, kernel in zip(imgs, kernels) ] if is_single_image: imgs = imgs[0] return imgs def __call__(self, results): """Call this transform.""" if np.random.uniform() > self.params.get('prob', 1): return results for key in self.keys: results[key] = self._apply_random_blur(results[key]) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(params={self.params}, keys={self.keys})') return repr_str @TRANSFORMS.register_module() class RandomJPEGCompression: """Apply random JPEG compression to the input. Modified keys are the attributed specified in "keys". Args: params (dict): A dictionary specifying the degradation settings. keys (list[str]): A list specifying the keys whose values are modified. bgr2rgb (str): Whether change channel order. Default: False. """ def __init__(self, params, keys, color_type='color', bgr2rgb=False): self.keys = keys self.params = params self.color_type = color_type self.bgr2rgb = bgr2rgb def _apply_random_compression(self, imgs): is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] # determine initial compression level and the step size quality = self.params['quality'] quality_step = self.params.get('quality_step', 0) jpeg_param = round(np.random.uniform(quality[0], quality[1])) # apply jpeg compression outputs = [] for img in imgs: encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_param] if self.bgr2rgb and self.color_type == 'color': img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) _, img_encoded = cv2.imencode('.jpg', img, encode_param) if self.color_type == 'color': img_encoded = cv2.imdecode(img_encoded, 1) if self.bgr2rgb: img_encoded = cv2.cvtColor(img_encoded, cv2.COLOR_BGR2RGB) outputs.append(img_encoded) else: outputs.append(cv2.imdecode(img_encoded, 0)) # update compression level jpeg_param += np.random.uniform(-quality_step, quality_step) jpeg_param = round(np.clip(jpeg_param, quality[0], quality[1])) if is_single_image: outputs = outputs[0] return outputs def __call__(self, results): """Call this transform.""" if np.random.uniform() > self.params.get('prob', 1): return results for key in self.keys: results[key] = self._apply_random_compression(results[key]) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(params={self.params}, keys={self.keys})') return repr_str @TRANSFORMS.register_module() class RandomNoise: """Apply random noise to the input. Currently support Gaussian noise and Poisson noise. Modified keys are the attributed specified in "keys". Args: params (dict): A dictionary specifying the degradation settings. keys (list[str]): A list specifying the keys whose values are modified. """ def __init__(self, params, keys): self.keys = keys self.params = params def _apply_gaussian_noise(self, imgs): """This is the function used to apply gaussian noise on images. Args: imgs (Tensor): images Returns: Tensor: images applied gaussian noise """ sigma_range = self.params['gaussian_sigma'] sigma = np.random.uniform(sigma_range[0], sigma_range[1]) sigma_step = self.params.get('gaussian_sigma_step', 0) gray_noise_prob = self.params['gaussian_gray_noise_prob'] is_gray_noise = np.random.uniform() < gray_noise_prob outputs = [] for img in imgs: noise = np.float32(np.random.randn(*(img.shape))) * sigma if is_gray_noise: noise = noise[:, :, :1] outputs.append(img + noise) # update noise level sigma += np.random.uniform(-sigma_step, sigma_step) sigma = np.clip(sigma, sigma_range[0], sigma_range[1]) return outputs def _apply_poisson_noise(self, imgs): scale_range = self.params['poisson_scale'] scale = np.random.uniform(scale_range[0], scale_range[1]) scale_step = self.params.get('poisson_scale_step', 0) gray_noise_prob = self.params['poisson_gray_noise_prob'] is_gray_noise = np.random.uniform() < gray_noise_prob outputs = [] for img in imgs: noise = np.float32(img.copy()) if is_gray_noise: noise = cv2.cvtColor(noise[..., [2, 1, 0]], cv2.COLOR_BGR2GRAY) noise = noise[..., np.newaxis] noise = np.clip((noise).round(), 0, 255) unique_val = 2**np.ceil(np.log2(len(np.unique(noise)))) noise = np.random.poisson(noise * unique_val).astype(np.float32) \ / unique_val - noise outputs.append(img + noise * scale) # update noise level scale += np.random.uniform(-scale_step, scale_step) scale = np.clip(scale, scale_range[0], scale_range[1]) return outputs def _apply_random_noise(self, imgs): """This is the function used to apply random noise on images. Args: imgs (Tensor): training images Returns: _type_: _description_ """ noise_type = np.random.choice( self.params['noise_type'], p=self.params['noise_prob']) is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] if noise_type.lower() == 'gaussian': imgs = self._apply_gaussian_noise(imgs) elif noise_type.lower() == 'poisson': imgs = self._apply_poisson_noise(imgs) else: raise NotImplementedError(f'"noise_type" [{noise_type}] is ' 'not implemented.') if is_single_image: imgs = imgs[0] return imgs def __call__(self, results): """Call this transform.""" if np.random.uniform() > self.params.get('prob', 1): return results for key in self.keys: results[key] = self._apply_random_noise(results[key]) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(params={self.params}, keys={self.keys})') return repr_str @TRANSFORMS.register_module() class RandomResize: """Randomly resize the input. Modified keys are the attributed specified in "keys". Args: params (dict): A dictionary specifying the degradation settings. keys (list[str]): A list specifying the keys whose values are modified. """ def __init__(self, params, keys): self.keys = keys self.params = params self.resize_dict = dict( bilinear=cv2.INTER_LINEAR, bicubic=cv2.INTER_CUBIC, area=cv2.INTER_AREA, lanczos=cv2.INTER_LANCZOS4) def _random_resize(self, imgs): """This is the function used to randomly resize images for training augmentation. Args: imgs (Tensor): training images. Returns: Tensor: images after randomly resized """ is_single_image = False if isinstance(imgs, np.ndarray): is_single_image = True imgs = [imgs] h, w = imgs[0].shape[:2] resize_opt = self.params['resize_opt'] resize_prob = self.params['resize_prob'] resize_opt = np.random.choice(resize_opt, p=resize_prob).lower() if resize_opt not in self.resize_dict: raise NotImplementedError(f'resize_opt [{resize_opt}] is not ' 'implemented') resize_opt = self.resize_dict[resize_opt] resize_step = self.params.get('resize_step', 0) # determine the target size, if not provided target_size = self.params.get('target_size', None) if target_size is None: resize_mode = np.random.choice(['up', 'down', 'keep'], p=self.params['resize_mode_prob']) resize_scale = self.params['resize_scale'] if resize_mode == 'up': scale_factor = np.random.uniform(1, resize_scale[1]) elif resize_mode == 'down': scale_factor = np.random.uniform(resize_scale[0], 1) else: scale_factor = 1 # determine output size h_out, w_out = h * scale_factor, w * scale_factor if self.params.get('is_size_even', False): h_out, w_out = 2 * (h_out // 2), 2 * (w_out // 2) target_size = (int(h_out), int(w_out)) else: resize_step = 0 # resize the input if resize_step == 0: # same target_size for all input images outputs = [ cv2.resize(img, target_size[::-1], interpolation=resize_opt) for img in imgs ] else: # different target_size for each input image outputs = [] for img in imgs: img = cv2.resize( img, target_size[::-1], interpolation=resize_opt) outputs.append(img) # update scale scale_factor += np.random.uniform(-resize_step, resize_step) scale_factor = np.clip(scale_factor, resize_scale[0], resize_scale[1]) # determine output size h_out, w_out = h * scale_factor, w * scale_factor if self.params.get('is_size_even', False): h_out, w_out = 2 * (h_out // 2), 2 * (w_out // 2) target_size = (int(h_out), int(w_out)) if is_single_image: outputs = outputs[0] return outputs def __call__(self, results): """Call this transform.""" if np.random.uniform() > self.params.get('prob', 1): return results for key in self.keys: results[key] = self._random_resize(results[key]) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(params={self.params}, keys={self.keys})') return repr_str @TRANSFORMS.register_module() class RandomVideoCompression: """Apply random video compression to the input. Modified keys are the attributed specified in "keys". Args: params (dict): A dictionary specifying the degradation settings. keys (list[str]): A list specifying the keys whose values are modified. """ def __init__(self, params, keys): assert has_av, 'Please install av to use video compression.' self.keys = keys self.params = params logging.getLogger('libav').setLevel(50) def _apply_random_compression(self, imgs): """This is the function to apply random compression on images. Args: imgs (Tensor): training images Returns: Tensor: images after randomly compressed """ codec = random.choices(self.params['codec'], self.params['codec_prob'])[0] bitrate = self.params['bitrate'] bitrate = np.random.randint(bitrate[0], bitrate[1] + 1) buf = io.BytesIO() with av.open(buf, 'w', 'mp4') as container: stream = container.add_stream(codec, rate=1) stream.height = imgs[0].shape[0] stream.width = imgs[0].shape[1] stream.pix_fmt = 'yuv420p' stream.bit_rate = bitrate for img in imgs: img = img.astype(np.uint8) frame = av.VideoFrame.from_ndarray(img, format='rgb24') frame.pict_type = 'NONE' for packet in stream.encode(frame): container.mux(packet) # Flush stream for packet in stream.encode(): container.mux(packet) outputs = [] with av.open(buf, 'r', 'mp4') as container: if container.streams.video: for frame in container.decode(**{'video': 0}): outputs.append(frame.to_rgb().to_ndarray().astype( np.float32)) return outputs def __call__(self, results): """Call this transform.""" if np.random.uniform() > self.params.get('prob', 1): return results for key in self.keys: results[key] = self._apply_random_compression(results[key]) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(params={self.params}, keys={self.keys})') return repr_str allowed_degradations = { 'RandomBlur': RandomBlur, 'RandomResize': RandomResize, 'RandomNoise': RandomNoise, 'RandomJPEGCompression': RandomJPEGCompression, 'RandomVideoCompression': RandomVideoCompression, } @TRANSFORMS.register_module() class DegradationsWithShuffle: """Apply random degradations to input, with degradations being shuffled. Degradation groups are supported. The order of degradations within the same group is preserved. For example, if we have degradations = [a, b, [c, d]] and shuffle_idx = None, then the possible orders are :: [a, b, [c, d]] [a, [c, d], b] [b, a, [c, d]] [b, [c, d], a] [[c, d], a, b] [[c, d], b, a] Modified keys are the attributed specified in "keys". Args: degradations (list[dict]): The list of degradations. keys (list[str]): A list specifying the keys whose values are modified. shuffle_idx (list | None, optional): The degradations corresponding to these indices are shuffled. If None, all degradations are shuffled. Default: None. """ def __init__(self, degradations, keys, shuffle_idx=None): self.keys = keys self.degradations = self._build_degradations(degradations) if shuffle_idx is None: self.shuffle_idx = list(range(0, len(degradations))) else: self.shuffle_idx = shuffle_idx def _build_degradations(self, degradations): for i, degradation in enumerate(degradations): if isinstance(degradation, (list, tuple)): degradations[i] = self._build_degradations(degradation) else: degradation_ = allowed_degradations[degradation['type']] degradations[i] = degradation_(degradation['params'], self.keys) return degradations def __call__(self, results): """Call this transform.""" # shuffle degradations if len(self.shuffle_idx) > 0: shuffle_list = [self.degradations[i] for i in self.shuffle_idx] np.random.shuffle(shuffle_list) for i, idx in enumerate(self.shuffle_idx): self.degradations[idx] = shuffle_list[i] # apply degradations to input for degradation in self.degradations: if isinstance(degradation, (tuple, list)): for subdegrdation in degradation: results = subdegrdation(results) else: results = degradation(results) return results def __repr__(self): """Print the basic information of the transform.""" repr_str = self.__class__.__name__ repr_str += (f'(degradations={self.degradations}, ' f'keys={self.keys}, ' f'shuffle_idx={self.shuffle_idx})') return repr_str ================================================ FILE: mmagic/datasets/transforms/random_down_sampling.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import numpy as np import torch from mmcv import imresize from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class RandomDownSampling(BaseTransform): """Generate LQ image from GT (and crop), which will randomly pick a scale. Args: scale_min (float): The minimum of upsampling scale, inclusive. Default: 1.0. scale_max (float): The maximum of upsampling scale, exclusive. Default: 4.0. patch_size (int): The cropped lr patch size. Default: None, means no crop. interpolation (str): Interpolation method, accepted values are "nearest", "bilinear", "bicubic", "area", "lanczos" for 'cv2' backend, "nearest", "bilinear", "bicubic", "box", "lanczos", "hamming" for 'pillow' backend. Default: "bicubic". backend (str | None): The image resize backend type. Options are `cv2`, `pillow`, `None`. If backend is None, the global imread_backend specified by ``mmcv.use_backend()`` will be used. Default: "pillow". Scale will be picked in the range of [scale_min, scale_max). """ def __init__(self, scale_min=1.0, scale_max=4.0, patch_size=None, interpolation='bicubic', backend='pillow'): assert scale_max >= scale_min self.scale_min = scale_min self.scale_max = scale_max self.patch_size = patch_size self.interpolation = interpolation self.backend = backend def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. 'gt' is required. Returns: dict: A dict containing the processed data and information. modified 'gt', supplement 'lq' and 'scale' to keys. """ img = results['gt'] scale = np.random.uniform(self.scale_min, self.scale_max) if self.patch_size is None: h_lr = math.floor(img.shape[-3] / scale + 1e-9) w_lr = math.floor(img.shape[-2] / scale + 1e-9) img = img[:round(h_lr * scale), :round(w_lr * scale), :] img_down = resize_fn(img, (w_lr, h_lr), self.interpolation, self.backend) crop_lr, crop_hr = img_down, img else: w_lr = self.patch_size w_hr = round(w_lr * scale) x0 = np.random.randint(0, img.shape[-3] - w_hr) y0 = np.random.randint(0, img.shape[-2] - w_hr) crop_hr = img[x0:x0 + w_hr, y0:y0 + w_hr, :] crop_lr = resize_fn(crop_hr, w_lr, self.interpolation, self.backend) results['gt'] = crop_hr results['img'] = crop_lr results['scale'] = scale # copy metainfo to lr image if 'gt_channel_order' in results: results['img_channel_order'] = results['gt_channel_order'] if 'gt_color_type' in results: results['img_color_type'] = results['gt_color_type'] return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f' scale_min={self.scale_min}, ' f'scale_max={self.scale_max}, ' f'patch_size={self.patch_size}, ' f'interpolation={self.interpolation}, ' f'backend={self.backend}') return repr_str def resize_fn(img, size, interpolation='bicubic', backend='pillow'): """Resize the given image to a given size. Args: img (np.ndarray | torch.Tensor): The input image. size (int | tuple[int]): Target size w or (w, h). interpolation (str): Interpolation method, accepted values are "nearest", "bilinear", "bicubic", "area", "lanczos" for 'cv2' backend, "nearest", "bilinear", "bicubic", "box", "lanczos", "hamming" for 'pillow' backend. Default: "bicubic". backend (str | None): The image resize backend type. Options are `cv2`, `pillow`, `None`. If backend is None, the global imread_backend specified by ``mmcv.use_backend()`` will be used. Default: "pillow". Returns: np.ndarray | Tensor: `resized_img`, whose type is same as `img`. """ if isinstance(size, int): size = (size, size) if isinstance(img, np.ndarray): return imresize( img, size, interpolation=interpolation, backend=backend) elif isinstance(img, torch.Tensor): image = imresize( img.numpy(), size, interpolation=interpolation, backend=backend) return torch.from_numpy(image) else: raise TypeError('img should got np.ndarray or torch.Tensor,' f'but got {type(img)}') ================================================ FILE: mmagic/datasets/transforms/trimap.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Augmentation on trimaps.""" import cv2 import numpy as np from mmcv.transforms import BaseTransform from mmengine.utils import is_tuple_of from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class FormatTrimap(BaseTransform): """Convert trimap (tensor) to one-hot representation. It transforms the trimap label from (0, 128, 255) to (0, 1, 2). If ``to_onehot`` is set to True, the trimap will convert to one-hot tensor of shape (3, H, W). Required key is "trimap", added or modified key are "trimap" and "format_trimap_to_onehot". Args: to_onehot (bool): whether convert trimap to one-hot tensor. Default: ``False``. """ def __init__(self, to_onehot=False): self.to_onehot = to_onehot def transform(self, results): """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ trimap = results['trimap'].squeeze() assert trimap.ndim == 2 if self.to_onehot: trimap_one_hot = np.zeros((*trimap.shape, 3), dtype=np.uint8) trimap_one_hot[..., 0][trimap == 0] = 1 trimap_one_hot[..., 1][trimap == 128] = 1 trimap_one_hot[..., 2][trimap == 255] = 1 results['trimap'] = trimap_one_hot else: trimap[trimap == 128] = 1 trimap[trimap == 255] = 2 results['trimap'] = trimap results['format_trimap_to_onehot'] = self.to_onehot return results def __repr__(self): return self.__class__.__name__ + f'(to_onehot={self.to_onehot})' @TRANSFORMS.register_module() class GenerateTrimap(BaseTransform): """Using random erode/dilate to generate trimap from alpha matte. Required key is "alpha", added key is "trimap". Args: kernel_size (int | tuple[int]): The range of random kernel_size of erode/dilate; int indicates a fixed kernel_size. If `random` is set to False and kernel_size is a tuple of length 2, then it will be interpreted as (erode kernel_size, dilate kernel_size). It should be noted that the kernel of the erosion and dilation has the same height and width. iterations (int | tuple[int], optional): The range of random iterations of erode/dilate; int indicates a fixed iterations. If `random` is set to False and iterations is a tuple of length 2, then it will be interpreted as (erode iterations, dilate iterations). Default to 1. random (bool, optional): Whether use random kernel_size and iterations when generating trimap. See `kernel_size` and `iterations` for more information. Default to True. """ def __init__(self, kernel_size, iterations=1, random=True): if isinstance(kernel_size, int): kernel_size = kernel_size, kernel_size + 1 elif not is_tuple_of(kernel_size, int) or len(kernel_size) != 2: raise ValueError('kernel_size must be an int or a tuple of 2 int, ' f'but got {kernel_size}') if isinstance(iterations, int): iterations = iterations, iterations + 1 elif not is_tuple_of(iterations, int) or len(iterations) != 2: raise ValueError('iterations must be an int or a tuple of 2 int, ' f'but got {iterations}') self.random = random if self.random: min_kernel, max_kernel = kernel_size self.iterations = iterations self.kernels = [ cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (size, size)) for size in range(min_kernel, max_kernel) ] else: erode_ksize, dilate_ksize = kernel_size self.iterations = iterations self.kernels = [ cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (erode_ksize, erode_ksize)), cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate_ksize, dilate_ksize)) ] def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ alpha = results['alpha'] if self.random: kernel_num = len(self.kernels) erode_kernel_idx = np.random.randint(kernel_num) dilate_kernel_idx = np.random.randint(kernel_num) min_iter, max_iter = self.iterations erode_iter = np.random.randint(min_iter, max_iter) dilate_iter = np.random.randint(min_iter, max_iter) else: erode_kernel_idx, dilate_kernel_idx = 0, 1 erode_iter, dilate_iter = self.iterations eroded = cv2.erode( alpha, self.kernels[erode_kernel_idx], iterations=erode_iter) dilated = cv2.dilate( alpha, self.kernels[dilate_kernel_idx], iterations=dilate_iter) trimap = np.zeros_like(alpha) trimap.fill(128) trimap[eroded >= 255] = 255 trimap[dilated <= 0] = 0 results['trimap'] = trimap return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(kernels={self.kernels}, iterations={self.iterations}, ' f'random={self.random})') return repr_str @TRANSFORMS.register_module() class GenerateTrimapWithDistTransform(BaseTransform): """Generate trimap with distance transform function. Args: dist_thr (int, optional): Distance threshold. Area with alpha value between (0, 255) will be considered as initial unknown area. Then area with distance to unknown area smaller than the distance threshold will also be consider as unknown area. Defaults to 20. random (bool, optional): If True, use random distance threshold from [1, dist_thr). If False, use `dist_thr` as the distance threshold directly. Defaults to True. """ def __init__(self, dist_thr=20, random=True): if not (isinstance(dist_thr, int) and dist_thr >= 1): raise ValueError('dist_thr must be an int that is greater than 1, ' f'but got {dist_thr}') self.dist_thr = dist_thr self.random = random def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ alpha = results['alpha'] # image dilation implemented by Euclidean distance transform known = (alpha == 0) | (alpha == 255) dist_to_unknown = cv2.distanceTransform( known.astype(np.uint8), cv2.DIST_L2, cv2.DIST_MASK_PRECISE) dist_thr = np.random.randint( 1, self.dist_thr) if self.random else self.dist_thr unknown = dist_to_unknown <= dist_thr trimap = (alpha == 255).astype(np.uint8) * 255 trimap[unknown] = 128 results['trimap'] = trimap return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += f'(dist_thr={self.dist_thr}, random={self.random})' return repr_str @TRANSFORMS.register_module() class TransformTrimap(BaseTransform): """Transform trimap into two-channel and six-channel. This class will generate a two-channel trimap composed of definite foreground and background masks and encode it into a six-channel trimap using Gaussian blurs of the generated two-channel trimap at three different scales. The transformed trimap has 6 channels. Required key is "trimap", added key is "transformed_trimap" and "two_channel_trimap". Adopted from the following repository: https://github.com/MarcoForte/FBA_Matting/blob/master/networks/transforms.py. """ def transform(self, results: dict) -> dict: """Transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict containing the processed data and information. """ trimap = results['trimap'] assert len(trimap.shape) == 2 h, w = trimap.shape[:2] # generate two-channel trimap trimap2 = np.zeros((h, w, 2), dtype=np.uint8) trimap2[trimap == 0, 0] = 255 trimap2[trimap == 255, 1] = 255 trimap_trans = np.zeros((h, w, 6), dtype=np.float32) factor = np.array([[[0.02, 0.08, 0.16]]], dtype=np.float32) for k in range(2): if np.any(trimap2[:, :, k]): dt_mask = -cv2.distanceTransform(255 - trimap2[:, :, k], cv2.DIST_L2, 0)**2 dt_mask = dt_mask[..., None] L = 320 trimap_trans[..., 3 * k:3 * k + 3] = np.exp(dt_mask / (2 * ((factor * L)**2))) results['transformed_trimap'] = trimap_trans results['two_channel_trimap'] = trimap2 return results def __repr__(self): repr_str = self.__class__.__name__ return repr_str ================================================ FILE: mmagic/datasets/transforms/values.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict from mmcv.transforms import BaseTransform from mmagic.registry import TRANSFORMS @TRANSFORMS.register_module() class CopyValues(BaseTransform): """Copy the value of source keys to destination keys. # TODO Change to dict(dst=src) It does the following: results[dst_key] = results[src_key] for (src_key, dst_key) in zip(src_keys, dst_keys). Added keys are the keys in the attribute "dst_keys". Required Keys: - [SRC_KEYS] Added Keys: - [DST_KEYS] Args: src_keys (list[str]): The source keys. dst_keys (list[str]): The destination keys. """ def __init__(self, src_keys, dst_keys): if not isinstance(src_keys, list) or not isinstance(dst_keys, list): raise AssertionError('"src_keys" and "dst_keys" must be lists.') if len(src_keys) != len(dst_keys): raise ValueError('"src_keys" and "dst_keys" should have the same' 'number of elements.') self.src_keys = src_keys self.dst_keys = dst_keys def transform(self, results): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict with a key added/modified. """ for (src_key, dst_key) in zip(self.src_keys, self.dst_keys): results[dst_key] = deepcopy(results[src_key]) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(src_keys={self.src_keys})') repr_str += (f'(dst_keys={self.dst_keys})') return repr_str @TRANSFORMS.register_module() class SetValues(BaseTransform): """Set value to destination keys. It does the following: results[key] = value Added keys are the keys in the dictionary. Required Keys: - None Added or Modified Keys: - keys in the dictionary Args: dictionary (dict): The dictionary to update. """ def __init__(self, dictionary): self.dictionary = dictionary def transform(self, results: Dict): """transform function. Args: results (dict): A dict containing the necessary information and data for augmentation. Returns: dict: A dict with a key added/modified. """ dictionary = deepcopy(self.dictionary) results.update(dictionary) return results def __repr__(self): repr_str = self.__class__.__name__ repr_str += (f'(dictionary={self.dictionary})') return repr_str ================================================ FILE: mmagic/datasets/unpaired_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from typing import Optional import numpy as np from mmengine.dataset import BaseDataset, force_full_init from mmengine.fileio import get_file_backend from mmagic.registry import DATASETS IMG_EXTENSIONS = ('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tif', '.TIF', '.tiff', '.TIFF') @DATASETS.register_module() class UnpairedImageDataset(BaseDataset): """General unpaired image folder dataset for image generation. It assumes that the training directory of images from domain A is '/path/to/data/trainA', and that from domain B is '/path/to/data/trainB', respectively. '/path/to/data' can be initialized by args 'dataroot'. During test time, the directory is '/path/to/data/testA' and '/path/to/data/testB', respectively. Args: dataroot (str | :obj:`Path`): Path to the folder root of unpaired images. pipeline (List[dict | callable]): A sequence of data transformations. io_backend (str, optional): The storage backend type. Options are "disk", "ceph", "memcached", "lmdb", "http" and "petrel". Default: None. test_mode (bool): Store `True` when building test dataset. Default: `False`. domain_a (str, optional): Domain of images in trainA / testA. Defaults to 'A'. domain_b (str, optional): Domain of images in trainB / testB. Defaults to 'B'. """ def __init__(self, data_root, pipeline, io_backend: Optional[str] = None, test_mode=False, domain_a='A', domain_b='B'): phase = 'test' if test_mode else 'train' self.dataroot_a = osp.join(str(data_root), phase + 'A') self.dataroot_b = osp.join(str(data_root), phase + 'B') if io_backend is None: self.file_backend = get_file_backend(uri=data_root) else: self.file_backend = get_file_backend( backend_args={'backend': io_backend}) super().__init__( data_root=data_root, pipeline=pipeline, test_mode=test_mode, serialize_data=False) self.len_a = len(self.data_infos_a) self.len_b = len(self.data_infos_b) self.test_mode = test_mode assert isinstance(domain_a, str) assert isinstance(domain_b, str) self.domain_a = domain_a self.domain_b = domain_b def load_data_list(self): """Load the data list. Returns: list: The data info list of source and target domain. """ self.data_infos_a = self._load_domain_data_list(self.dataroot_a) self.data_infos_b = self._load_domain_data_list(self.dataroot_b) return [self.data_infos_a, self.data_infos_b] def _load_domain_data_list(self, dataroot): """Load unpaired image paths of one domain. Args: dataroot (str): Path to the folder root for unpaired images of one domain. Returns: list[dict]: List that contains unpaired image paths of one domain. """ data_infos = [] paths = sorted(self.scan_folder(dataroot)) for path in paths: data_infos.append(dict(path=path)) return data_infos @force_full_init def get_data_info(self, idx) -> dict: """Get annotation by index and automatically call ``full_init`` if the dataset has not been fully initialized. Args: idx (int): The index of data. Returns: dict: The idx-th annotation of the dataset. """ img_a_path = self.data_infos_a[idx % self.len_a]['path'] if not self.test_mode: idx_b = np.random.randint(0, self.len_b) img_b_path = self.data_infos_b[idx_b]['path'] else: img_b_path = self.data_infos_b[idx % self.len_b]['path'] data_info = dict() data_info[f'img_{self.domain_a}_path'] = img_a_path data_info[f'img_{self.domain_b}_path'] = img_b_path return data_info def __len__(self): """The length of the dataset.""" return max(self.len_a, self.len_b) def scan_folder(self, path): """Obtain image path list (including sub-folders) from a given folder. Args: path (str | :obj:`Path`): Folder path. Returns: list[str]: Image list obtained from the given folder. """ imgs_list = self.file_backend.list_dir_or_file( path, list_dir=False, suffix=IMG_EXTENSIONS, recursive=True) images = [self.file_backend.join_path(path, img) for img in imgs_list] assert images, f'{path} has no valid image file.' return images ================================================ FILE: mmagic/engine/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .hooks import * # noqa: F401, F403 from .optimizers import * # noqa: F401, F403 from .runner import * # noqa: F401, F403 from .schedulers import * # noqa: F401, F403 ================================================ FILE: mmagic/engine/hooks/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .ema import ExponentialMovingAverageHook from .iter_time_hook import IterTimerHook from .pggan_fetch_data_hook import PGGANFetchDataHook from .pickle_data_hook import PickleDataHook from .reduce_lr_scheduler_hook import ReduceLRSchedulerHook from .visualization_hook import BasicVisualizationHook, VisualizationHook __all__ = [ 'ReduceLRSchedulerHook', 'BasicVisualizationHook', 'VisualizationHook', 'ExponentialMovingAverageHook', 'IterTimerHook', 'PGGANFetchDataHook', 'PickleDataHook' ] ================================================ FILE: mmagic/engine/hooks/ema.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import warnings from copy import deepcopy from functools import partial from typing import Optional, Sequence import torch from mmengine.hooks import Hook from mmengine.model.wrappers import is_model_wrapper from mmengine.registry import HOOKS from mmengine.runner import Runner from mmengine.utils import is_tuple_of DATA_BATCH = Optional[Sequence[dict]] @HOOKS.register_module() class ExponentialMovingAverageHook(Hook): """Exponential Moving Average Hook. Exponential moving average is a trick that widely used in current GAN literature, e.g., PGGAN, StyleGAN, and BigGAN. This general idea of it is maintaining a model with the same architecture, but its parameters are updated as a moving average of the trained weights in the original model. In general, the model with moving averaged weights achieves better performance. Args: module_keys (str | tuple[str]): The name of the ema model. Note that we require these keys are followed by '_ema' so that we can easily find the original model by discarding the last four characters. interp_mode (str, optional): Mode of the interpolation method. Defaults to 'lerp'. interp_cfg (dict | None, optional): Set arguments of the interpolation function. Defaults to None. interval (int, optional): Evaluation interval (by iterations). Default: -1. start_iter (int, optional): Start iteration for ema. If the start iteration is not reached, the weights of ema model will maintain the same as the original one. Otherwise, its parameters are updated as a moving average of the trained weights in the original model. Default: 0. """ def __init__(self, module_keys, interp_mode='lerp', interp_cfg=None, interval=-1, start_iter=0): super().__init__() assert isinstance(module_keys, str) or is_tuple_of(module_keys, str) self.module_keys = (module_keys, ) if isinstance(module_keys, str) else module_keys # sanity check for the format of module keys for k in self.module_keys: assert k.endswith( '_ema'), 'You should give keys that end with "_ema".' self.interp_mode = interp_mode self.interp_cfg = dict() if interp_cfg is None else deepcopy( interp_cfg) self.interval = interval self.start_iter = start_iter assert hasattr( self, interp_mode ), f'Currently, we do not support {self.interp_mode} for EMA.' self.interp_func = partial( getattr(self, interp_mode), **self.interp_cfg) @staticmethod def lerp(a, b, momentum=0.001, momentum_nontrainable=1., trainable=True): """Does a linear interpolation of two parameters/ buffers. Args: a (torch.Tensor): Interpolation start point, refer to orig state. b (torch.Tensor): Interpolation end point, refer to ema state. momentum (float, optional): The weight for the interpolation formula. Defaults to 0.001. momentum_nontrainable (float, optional): The weight for the interpolation formula used for nontrainable parameters. Defaults to 1.. trainable (bool, optional): Whether input parameters is trainable. If set to False, momentum_nontrainable will be used. Defaults to True. Returns: torch.Tensor: Interpolation result. """ assert 0.0 < momentum < 1.0, 'momentum must be in range (0.0, 1.0)'\ f'but got {momentum}' assert 0.0 < momentum_nontrainable <= 1.0, ( 'momentum_nontrainable must be in range (0.0, 1.0] but got ' f'{momentum_nontrainable}') if momentum > 0.5: warnings.warn( 'The value of momentum in EMA is usually a small number,' 'which is different from the conventional notion of ' f'momentum but got {momentum}. Please make sure the ' f'value is correct.') m = momentum if trainable else momentum_nontrainable return b + (a - b) * m def every_n_iters(self, runner: Runner, n: int): """This is the function to perform every n iterations. Args: runner (Runner): runner used to drive the whole pipeline n (int): the number of iterations Returns: int: the latest iterations """ if runner.iter < self.start_iter: return True return (runner.iter + 1 - self.start_iter) % n == 0 if n > 0 else False @torch.no_grad() def after_train_iter(self, runner: Runner, batch_idx: int, data_batch: DATA_BATCH = None, outputs: Optional[dict] = None) -> None: """This is the function to perform after each training iteration. Args: runner (Runner): runner to drive the pipeline batch_idx (int): the id of batch data_batch (DATA_BATCH, optional): data batch. Defaults to None. outputs (Optional[dict], optional): output. Defaults to None. """ if not self.every_n_iters(runner, self.interval): return model = runner.model.module if is_model_wrapper( runner.model) else runner.model for key in self.module_keys: # get current ema states ema_net = getattr(model, key) states_ema = ema_net.state_dict(keep_vars=False) # get currently original states net = getattr(model, key[:-4]) states_orig = net.state_dict(keep_vars=True) for k, v in states_orig.items(): if runner.iter < self.start_iter: states_ema[k].data.copy_(v.data) else: states_ema[k] = self.interp_func( v, states_ema[k], trainable=v.requires_grad).detach() ema_net.load_state_dict(states_ema, strict=True) def before_run(self, runner: Runner): """This is the function perform before each run. Args: runner (Runner): runner used to drive the whole pipeline Raises: RuntimeError: error message """ model = runner.model.module if is_model_wrapper( runner.model) else runner.model # sanity check for ema model for k in self.module_keys: if not hasattr(model, k) and not hasattr(model, k[:-4]): raise RuntimeError( f'Cannot find both {k[:-4]} and {k} network for EMA hook.') if not hasattr(model, k) and hasattr(model, k[:-4]): setattr(model, k, deepcopy(getattr(model, k[:-4]))) warnings.warn( f'We do not suggest construct and initialize EMA model {k}' ' in hook. You may explicitly define it by yourself.') ================================================ FILE: mmagic/engine/hooks/iter_time_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import time from typing import Optional, Sequence, Union from mmengine.hooks import IterTimerHook as BaseIterTimerHook from mmengine.structures import BaseDataElement from mmagic.registry import HOOKS DATA_BATCH = Optional[Sequence[dict]] @HOOKS.register_module() class IterTimerHook(BaseIterTimerHook): """IterTimerHooks inherits from :class:`mmengine.hooks.IterTimerHook` and overwrites :meth:`self._after_iter`. This hooks should be used along with :class:`mmagic.engine.runner.MultiValLoop` and :class:`mmagic.engine.runner.MultiTestLoop`. """ def _after_iter(self, runner, batch_idx: int, data_batch: DATA_BATCH = None, outputs: Optional[Union[dict, Sequence[BaseDataElement]]] = None, mode: str = 'train') -> None: """Calculating time for an iteration and updating "time" ``HistoryBuffer`` of ``runner.message_hub``. If `mode` is 'train', we take `runner.max_iters` as the total iterations and calculate the rest time. If `mode` in `val` or `test`, we use `runner.val_loop.total_length` or `runner.test_loop.total_length` as total number of iterations. If you want to know how `total_length` is calculated, please refers to :meth:`mmagic.engine.runner.MultiValLoop.run` and :meth:`mmagic.engine.runner.MultiTestLoop.run`. Args: runner (Runner): The runner of the training validation and testing process. batch_idx (int): The index of the current batch in the loop. data_batch (Sequence[dict], optional): Data from dataloader. Defaults to None. outputs (dict or sequence, optional): Outputs from model. Defaults to None. mode (str): Current mode of runner. Defaults to 'train'. """ # Update iteration time in `runner.message_hub`. message_hub = runner.message_hub message_hub.update_scalar(f'{mode}/time', time.time() - self.t) self.t = time.time() window_size = runner.log_processor.window_size # Calculate eta every `window_size` iterations. Since test and val # loop will not update runner.iter, use `every_n_inner_iters`to check # the interval. if self.every_n_inner_iters(batch_idx, window_size): iter_time = message_hub.get_scalar(f'{mode}/time').mean( window_size) if mode == 'train': self.time_sec_tot += iter_time * window_size # Calculate average iterative time. time_sec_avg = self.time_sec_tot / ( runner.iter - self.start_iter + 1) # Calculate eta. eta_sec = time_sec_avg * (runner.max_iters - runner.iter - 1) runner.message_hub.update_info('eta', eta_sec) else: if mode == 'val': total_length = runner.val_loop.total_length else: total_length = runner.test_loop.total_length eta_sec = iter_time * (total_length - batch_idx - 1) runner.message_hub.update_info('eta', eta_sec) ================================================ FILE: mmagic/engine/hooks/pggan_fetch_data_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Sequence import torch from mmengine.dataset import DefaultSampler, InfiniteSampler, pseudo_collate from mmengine.hooks import Hook from mmengine.model import is_model_wrapper from mmengine.runner import IterBasedTrainLoop from mmengine.runner.loops import _InfiniteDataloaderIterator from torch.utils.data.dataloader import DataLoader from mmagic.registry import HOOKS DATA_BATCH = Optional[Sequence[dict]] @HOOKS.register_module() class PGGANFetchDataHook(Hook): """PGGAN Fetch Data Hook. Args: interval (int, optional): The interval of calling this hook. If set to -1, the visualization hook will not be called. Defaults to 1. """ def __init__(self): super().__init__() def before_train_iter(self, runner, batch_idx: int, data_batch: DATA_BATCH = None) -> None: _module = runner.model.module if is_model_wrapper( runner.model) else runner.model _next_scale_int = _module._next_scale_int if isinstance(_next_scale_int, torch.Tensor): _next_scale_int = _next_scale_int.item() dataloader_orig = runner.train_loop.dataloader new_dataloader = self.update_dataloader(dataloader_orig, _next_scale_int) if new_dataloader is not None: runner.train_loop.dataloader = new_dataloader if isinstance(runner.train_loop, IterBasedTrainLoop): runner.train_loop.dataloader_iterator = \ _InfiniteDataloaderIterator(new_dataloader) def update_dataloader(self, dataloader: DataLoader, curr_scale: int) -> Optional[DataLoader]: """Update the data loader. Args: dataloader (DataLoader): The dataloader to be updated. curr_scale (int): The current scale of the generated image. Returns: Optional[DataLoader]: The updated dataloader. If the dataloader do not need to update, return None. """ if hasattr(dataloader.dataset, 'update_annotations'): update_flag = dataloader.dataset.update_annotations(curr_scale) else: update_flag = False if update_flag: dataset = dataloader.dataset # build new sampler sampler_orig = dataloader.sampler if isinstance(sampler_orig, DefaultSampler): shuffle = sampler_orig.shuffle seed = sampler_orig.seed round_up = sampler_orig.round_up sampler = DefaultSampler(dataset, shuffle, seed, round_up) elif isinstance(sampler_orig, InfiniteSampler): shuffle = sampler_orig.shuffle seed = sampler_orig.seed sampler = InfiniteSampler(dataset, shuffle, seed) else: raise ValueError('MMagic only support \'DefaultSampler\' and ' '\'InfiniteSampler\' as sampler. But receive ' f'\'{type(sampler_orig)}\'.') num_workers = dataloader.num_workers worker_init_fn = dataloader.worker_init_fn dataloader = DataLoader( dataset, batch_size=dataloader.dataset.samples_per_gpu, sampler=sampler, num_workers=num_workers, collate_fn=pseudo_collate, shuffle=False, worker_init_fn=worker_init_fn) return dataloader return None ================================================ FILE: mmagic/engine/hooks/pickle_data_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import logging import os import pickle from typing import List, Optional, Sequence, Tuple import numpy as np import torch from mmengine import is_list_of, mkdir_or_exist, print_log from mmengine.dist import master_only from mmengine.hooks import Hook from mmengine.runner import Runner from torch import Tensor from mmagic.registry import HOOKS DATA_BATCH = Optional[Sequence[dict]] @HOOKS.register_module() class PickleDataHook(Hook): """Pickle Useful Data Hook. This hook will be used in SinGAN training for saving some important data that will be used in testing or inference. Args: output_dir (str): The output path for saving pickled data. data_name_list (list[str]): The list contains the name of results in outputs dict. interval (int): The interval of calling this hook. If set to -1, the PickleDataHook will not be called during training. Default: -1. before_run (bool, optional): Whether to save before running. Defaults to False. after_run (bool, optional): Whether to save after running. Defaults to False. filename_tmpl (str, optional): Format string used to save images. The output file name will be formatted as this args. Defaults to 'iter_{}.pkl'. """ def __init__(self, output_dir, data_name_list, interval=-1, before_run=False, after_run=False, filename_tmpl='iter_{}.pkl'): assert is_list_of(data_name_list, str) self.output_dir = output_dir self.data_name_list = data_name_list self.interval = interval self.filename_tmpl = filename_tmpl self._before_run = before_run self._after_run = after_run @master_only def after_run(self, runner): """The behavior after each train iteration. Args: runner (object): The runner. """ if self._after_run: self._pickle_data(runner) @master_only def before_run(self, runner): """The behavior after each train iteration. Args: runner (object): The runner. """ if self._before_run: self._pickle_data(runner) @master_only def after_train_iter(self, runner, batch_idx: int, data_batch: DATA_BATCH = None, outputs: Optional[dict] = None): """The behavior after each train iteration. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the train loop. data_batch (Sequence[dict], optional): Data from dataloader. Defaults to None. outputs (dict, optional): Outputs from model. Defaults to None. """ if not self.every_n_train_iters(runner, self.interval): return self._pickle_data(runner) def _pickle_data(self, runner: Runner): """Save target data to pickle file. Args: runner (Runner): The runner of the training process. """ filename = self.filename_tmpl.format(runner.iter + 1) if not hasattr(self, '_out_dir'): self._out_dir = os.path.join(runner.work_dir, self.output_dir) mkdir_or_exist(self._out_dir) file_path = os.path.join(self._out_dir, filename) with open(file_path, 'wb') as f: module = runner.model if hasattr(module, 'module'): module = module.module not_find_keys = [] data_dict = {} for k in self.data_name_list: if hasattr(module, k): data_dict[k] = self._get_numpy_data(getattr(module, k)) else: not_find_keys.append(k) pickle.dump(data_dict, f) print_log(f'Pickle data in {filename}', 'current') if len(not_find_keys) > 0: print_log( f'Cannot find keys for pickling: {not_find_keys}', 'current', level=logging.WARN) f.flush() def _get_numpy_data( self, data: Tuple[List[Tensor], Tensor, int] ) -> Tuple[List[np.ndarray], np.ndarray, int]: """Convert tensor or list of tensor to numpy or list of numpy. Args: data (Tuple[List[Tensor], Tensor, int]): Data to be converted. Returns: Tuple[List[np.ndarray], np.ndarray, int]: Converted data. """ if isinstance(data, list): return [self._get_numpy_data(x) for x in data] if isinstance(data, torch.Tensor): return data.cpu().numpy() return data ================================================ FILE: mmagic/engine/hooks/reduce_lr_scheduler_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Sequence from mmengine import MessageHub from mmengine.hooks import ParamSchedulerHook from mmengine.runner import Runner from mmagic.registry import HOOKS DATA_BATCH = Optional[Sequence[dict]] @HOOKS.register_module() class ReduceLRSchedulerHook(ParamSchedulerHook): """A hook to update learning rate. Args: val_metric (str): The metric of validation. If val_metric is not None, we check val_metric to reduce learning. Default: None. by_epoch (bool): Whether to update by epoch. Default: True. interval (int): The interval of iterations to update. Default: 1. """ def __init__(self, val_metric: str = None, by_epoch=True, interval=1) -> None: super().__init__() self.message_hub = MessageHub.get_instance('reduce_lr') self.val_metric = val_metric self.by_epoch = by_epoch self.interval = interval self.sum_value = 0 self.count = 0 def _calculate_average_value(self): value = self.sum_value / self.count self.sum_value = 0 self.count = 0 self.message_hub.update_scalar('value', value) def after_train_epoch(self, runner: Runner): """Call step function for each scheduler after each train epoch. Args: runner (Runner): The runner of the training process. """ if not self.by_epoch: return # If val_metric is not None, we check val_metric to reduce learning if self.val_metric is not None: return if self.every_n_epochs(runner, self.interval): self._calculate_average_value() super().after_train_epoch(runner=runner) def after_train_iter(self, runner: Runner, batch_idx: int, data_batch: DATA_BATCH = None, outputs: Optional[dict] = None) -> None: """Call step function for each scheduler after each iteration. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the train loop. data_batch (Sequence[dict], optional): Data from dataloader. In order to keep this interface consistent with other hooks, we keep ``data_batch`` here. Defaults to None. outputs (dict, optional): Outputs from model. In order to keep this interface consistent with other hooks, we keep ``data_batch`` here. Defaults to None. """ # If val_metric is not None, we check val_metric to reduce learning if self.val_metric is not None: return current = runner.message_hub.get_scalar('train/loss').current() self.sum_value += current * len(data_batch) self.count += len(data_batch) if self.by_epoch: return if self.every_n_train_iters(runner, self.interval): self._calculate_average_value() super().after_train_iter( runner=runner, batch_idx=batch_idx, data_batch=data_batch, outputs=outputs) def after_val_epoch(self, runner, metrics: Optional[Dict[str, float]] = None): """Call step function for each scheduler after each validation epoch. Args: runner (Runner): The runner of the training process. metrics (dict, optional): The metrics of validation. Default: None. """ # If val_metric is None, we check training loss to reduce learning # rate. if self.val_metric is None: return if self.val_metric not in metrics: raise KeyError(f'{self.val_metric} is not found in metrics') self.sum_value += metrics[self.val_metric] self.count += 1 if not self.by_epoch or self.every_n_epochs(runner, self.interval): # if self.by_epoch is False, # call val after several iter # and update LR in each ``after_val_epoch`` self._calculate_average_value() def step(param_schedulers): assert isinstance(param_schedulers, list) for scheduler in param_schedulers: scheduler.step() if isinstance(runner.param_schedulers, list): step(runner.param_schedulers) elif isinstance(runner.param_schedulers, dict): for param_schedulers in runner.param_schedulers.values(): step(param_schedulers) else: raise TypeError( 'runner.param_schedulers should be list of ParamScheduler ' 'or a dict containing list of ParamScheduler, ' f'but got {runner.param_schedulers}') ================================================ FILE: mmagic/engine/hooks/visualization_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import warnings from collections import defaultdict from copy import deepcopy from typing import Dict, List, Optional, Sequence, Tuple, Union import torch from mmengine import MessageHub from mmengine.dist import master_only from mmengine.hooks import Hook from mmengine.registry import HOOKS from mmengine.runner import Runner from mmengine.structures import BaseDataElement from mmengine.utils import is_list_of from mmengine.visualization import Visualizer from mmagic.structures import DataSample from mmagic.utils import get_sampler @HOOKS.register_module() class BasicVisualizationHook(Hook): """Basic hook that invoke visualizers during validation and test. Args: interval (int | dict): Visualization interval. Default: {}. on_train (bool): Whether to call hook during train. Default to False. on_val (bool): Whether to call hook during validation. Default to True. on_test (bool): Whether to call hook during test. Default to True. """ priority = 'NORMAL' def __init__(self, interval: dict = {}, on_train=False, on_val=True, on_test=True): self._interval = interval self._sample_counter = 0 self._vis_dir = None self._on_train = on_train self._on_val = on_val self._on_test = on_test def _after_iter( self, runner, batch_idx: int, data_batch: Optional[Sequence[dict]], outputs: Optional[Sequence[BaseDataElement]], mode=None, ) -> None: """Show or Write the predicted results. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the test loop. data_batch (Sequence[dict], optional): Data from dataloader. Defaults to None. outputs (Sequence[BaseDataElement], optional): Outputs from model. Defaults to None. """ if mode == 'train' and (not self._on_train): return elif mode == 'val' and (not self._on_val): return elif mode == 'test' and (not self._on_test): return if isinstance(self._interval, int): interval = self._interval else: interval = self._interval.get(mode, 1) if self.every_n_inner_iters(batch_idx, interval): for data_sample in outputs: runner.visualizer.add_datasample(data_sample, step=runner.iter) @HOOKS.register_module() class VisualizationHook(Hook): """MMagic Visualization Hook. Used to visual output samples in training, validation and testing. In this hook, we use a list called `sample_kwargs_list` to control how to generate samples and how to visualize them. Each element in `sample_kwargs_list`, called `sample_kwargs`, may contains the following keywords: - Required key words: - 'type': Value must be string. Denotes what kind of sampler is used to generate image. Refers to :meth:`~mmagic.utils.get_sampler`. - Optional key words (If not passed, will use the default value): - 'n_row': Value must be int. The number of images in one row. - 'num_samples': Value must be int. The number of samples to visualize. - 'vis_mode': Value must be string. How to visualize the generated samples (e.g. image, gif). - 'fixed_input': Value must be bool. Whether use the fixed input during the loop. - 'draw_gt': Value must be bool. Whether save the real images. - 'target_keys': Value must be string or list of string. The keys of the target image to visualize. - 'name': Value must be string. If not passed, will use `sample_kwargs['type']` as default. For convenience, we also define a group of alias of samplers' type for models supported in MMagic. Refers to `:attr:self.SAMPLER_TYPE_MAPPING`. Example: >>> # for GAN models >>> custom_hooks = [ >>> dict( >>> type='VisualizationHook', >>> interval=1000, >>> fixed_input=True, >>> vis_kwargs_list=dict(type='GAN', name='fake_img'))] >>> # for Translation models >>> custom_hooks = [ >>> dict( >>> type='VisualizationHook', >>> interval=10, >>> fixed_input=False, >>> vis_kwargs_list=[dict(type='Translation', >>> name='translation_train', >>> n_samples=6, draw_gt=True, >>> n_row=3), >>> dict(type='TranslationVal', >>> name='translation_val', >>> n_samples=16, draw_gt=True, >>> n_row=4)])] # NOTE: user-defined vis_kwargs > vis_kwargs_mapping > hook init args Args: interval (int): Visualization interval. Default: 1000. sampler_kwargs_list (Tuple[List[dict], dict]): The list of sampling behavior to generate images. fixed_input (bool): The default action of whether use fixed input to generate samples during the loop. Defaults to True. n_samples (Optional[int]): The default value of number of samples to visualize. Defaults to 64. n_row (Optional[int]): The default value of number of images in each row in the visualization results. Defaults to None. message_hub_vis_kwargs (Optional[Tuple[str, dict, List[str], List[Dict]]]): Key arguments visualize images in message hub. Defaults to None. save_at_test (bool): Whether save images during test. Defaults to True. max_save_at_test (int): Maximum number of samples saved at test time. If None is passed, all samples will be saved. Defaults to 100. show (bool): Whether to display the drawn image. Default to False. wait_time (float): The interval of show (s). Defaults to 0. """ priority = 'NORMAL' VIS_KWARGS_MAPPING = dict( GAN=dict(type='Noise'), SinGAN=dict(type='Arguments', forward_kwargs=dict(mode='rand')), Translation=dict(type='Data'), TranslationVal=dict(type='ValData'), TranslationTest=dict(type='TestData'), DDPMDenoising=dict( type='Arguments', name='ddpm_sample', n_samples=16, n_row=4, vis_mode='gif', n_skip=100, forward_kwargs=dict( forward_mode='sampling', sample_kwargs=dict(show_pbar=True, save_intermedia=True)))) def __init__(self, interval: int = 1000, vis_kwargs_list: Tuple[List[dict], dict] = None, fixed_input: bool = True, n_samples: Optional[int] = 64, n_row: Optional[int] = None, message_hub_vis_kwargs: Optional[Tuple[str, dict, List[str], List[Dict]]] = None, save_at_test: bool = True, max_save_at_test: int = 100, test_vis_keys: Optional[Union[str, List[str]]] = None, show: bool = False, wait_time: float = 0): self._visualizer: Visualizer = Visualizer.get_current_instance() self.interval = interval self.vis_kwargs_list = deepcopy(vis_kwargs_list) if isinstance(self.vis_kwargs_list, dict): self.vis_kwargs_list = [self.vis_kwargs_list] self.fixed_input = fixed_input self.inputs_buffer = defaultdict(list) self.n_samples = n_samples self.n_row = n_row self.show = show if self.show: # No need to think about vis backends. self._visualizer._vis_backends = {} warnings.warn('The show is True, it means that only ' 'the prediction results are visualized ' 'without storing data, so vis_backends ' 'needs to be excluded.') self.wait_time = wait_time self.save_at_test = save_at_test self.test_vis_keys_list = test_vis_keys self.max_save_at_test = max_save_at_test self.message_vis_kwargs = message_hub_vis_kwargs @master_only def after_val_iter(self, runner: Runner, batch_idx: int, data_batch: dict, outputs) -> None: """:class:`VisualizationHook` do not support visualize during validation. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the test loop. data_batch (Sequence[dict], optional): Data from dataloader. Defaults to None. outputs: outputs of the generation model """ return @master_only def after_test_iter(self, runner: Runner, batch_idx: int, data_batch: dict, outputs): """Visualize samples after test iteration. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the test loop. data_batch (dict, optional): Data from dataloader. Defaults to None. outputs: outputs of the generation model Defaults to None. """ if not self.save_at_test: return for idx, sample in enumerate(outputs): curr_idx = batch_idx * len(outputs) + idx if (self.max_save_at_test is not None and curr_idx >= self.max_save_at_test): continue # NOTE: only support visualize image tensors (ndim == 3) if self.test_vis_keys_list is None: target_keys = [ k for k, v in sample.items() if not k.startswith('_') and isinstance(v, torch.Tensor) and v.ndim == 3 ] assert len(target_keys), ( 'Cannot found Tensor in outputs. Please specific ' '\'vis_test_keys_list\'.') elif isinstance(self.test_vis_keys_list, str): target_keys = [self.test_vis_keys_list] else: assert is_list_of(self.test_vis_keys_list, str), ( 'test_vis_keys_list must be str or list of str or None.') target_keys = self.test_vis_keys_list for key in target_keys: name = key.replace('.', '_') self._visualizer.add_datasample( name=f'test_{name}', gen_samples=[sample], step=curr_idx, target_keys=key, n_row=1) @master_only def after_train_iter(self, runner: Runner, batch_idx: int, data_batch: dict = None, outputs: Optional[dict] = None) -> None: """Visualize samples after train iteration. Args: runner (Runner): The runner of the training process. batch_idx (int): The index of the current batch in the train loop. data_batch (dict): Data from dataloader. Defaults to None. outputs (dict, optional): Outputs from model. Defaults to None. """ if self.every_n_inner_iters(batch_idx, self.interval): self.vis_sample(runner, batch_idx, data_batch, outputs) @torch.no_grad() def vis_sample(self, runner: Runner, batch_idx: int, data_batch: dict, outputs: Optional[dict] = None) -> None: """Visualize samples. Args: runner (Runner): The runner contains model to visualize. batch_idx (int): The index of the current batch in loop. data_batch (dict): Data from dataloader. Defaults to None. outputs (dict, optional): Outputs from model. Defaults to None. """ # this function will only called in training process num_batches = runner.train_dataloader.batch_size module = runner.model module.eval() if hasattr(module, 'module'): module = module.module forward_func = module.val_step for vis_kwargs in self.vis_kwargs_list: # pop the sample-unrelated values vis_kwargs_ = deepcopy(vis_kwargs) sampler_type = vis_kwargs_['type'] # replace with alias for alias in self.VIS_KWARGS_MAPPING.keys(): if alias.upper() == sampler_type.upper(): sampler_alias = deepcopy(self.VIS_KWARGS_MAPPING[alias]) vis_kwargs_['type'] = sampler_alias.pop('type') for default_k, default_v in sampler_alias.items(): vis_kwargs_.setdefault(default_k, default_v) break # sampler_type = vis_kwargs_.pop('type') name = vis_kwargs_.pop('name', None) if not name: name = sampler_type.lower() n_samples = vis_kwargs_.pop('n_samples', self.n_samples) n_row = vis_kwargs_.pop('n_row', self.n_row) num_iters = math.ceil(n_samples / num_batches) vis_kwargs_['max_times'] = num_iters vis_kwargs_['num_batches'] = num_batches fixed_input = vis_kwargs_.pop('fixed_input', self.fixed_input) target_keys = vis_kwargs_.pop('target_keys', None) vis_mode = vis_kwargs_.pop('vis_mode', None) output_list = [] if fixed_input and self.inputs_buffer[sampler_type]: sampler = self.inputs_buffer[sampler_type] else: sampler = get_sampler(vis_kwargs_, runner) need_save = fixed_input and not self.inputs_buffer[sampler_type] for inputs in sampler: output = forward_func(inputs) if len(output) != num_batches: # one sample contains multiple elements output_list.append(output) contain_mul_elements = True else: output_list += [out for out in forward_func(inputs)] contain_mul_elements = False # save inputs if need_save: self.inputs_buffer[sampler_type].append(inputs) output_list = output_list[:n_samples] if contain_mul_elements: output_to_vis = [] for output in output_list: output_to_vis += output else: output_to_vis = output_list n_row = min(n_row, len(output_to_vis)) if n_row else None self._visualizer.add_datasample( name=name, gen_samples=output_to_vis, target_keys=target_keys, vis_mode=vis_mode, n_row=n_row, show=self.show, wait_time=self.wait_time, step=batch_idx + 1, **vis_kwargs_) # save images in message_hub self.vis_from_message_hub(batch_idx) module.train() def vis_from_message_hub(self, batch_idx: int): """Visualize samples from message hub. Args: batch_idx (int): The index of the current batch in the test loop. color_order (str): The color order of generated images. target_mean (Sequence[Union[float, int]]): The original mean of the image tensor before preprocessing. Image will be re-shifted to ``target_mean`` before visualizing. target_std (Sequence[Union[float, int]]): The original std of the image tensor before preprocessing. Image will be re-scaled to ``target_std`` before visualizing. """ # TODO: add destruct in this function if self.message_vis_kwargs is None: return message_hub = MessageHub.get_current_instance() if 'vis_results' not in message_hub.runtime_info: raise RuntimeError('Cannot find \'vis_results\' in ' '\'message_hub.runtime_info\'. Cannot perform ' 'visualization from messageHub.') vis_results = message_hub.get_info('vis_results') if isinstance(self.message_vis_kwargs, str): target_keys, vis_modes = [self.message_vis_kwargs], [None] elif isinstance(self.message_vis_kwargs, dict): target_keys = [self.message_vis_kwargs['key']] vis_modes = [self.message_vis_kwargs['vis_mode']] elif is_list_of(self.message_vis_kwargs, str): target_keys = self.message_vis_kwargs vis_modes = [None for _ in range(len(target_keys))] else: # list of dict target_keys = [kwargs['key'] for kwargs in self.message_vis_kwargs] vis_modes = [ kwargs.pop('vis_mode', None) for kwargs in deepcopy(self.message_vis_kwargs) ] for key, vis_mode in zip(target_keys, vis_modes): if key not in vis_results: raise RuntimeError( f'Cannot find \'{key}\' in ' 'message_hub.runtime_info[\'vis_results\'].') value = vis_results[key] # pack to list of DataSample if isinstance(value, torch.Tensor): gen_samples = [] num_batches = value.shape[0] for idx in range(num_batches): gen_sample = DataSample() setattr(gen_sample, key, value[idx]) gen_samples.append(gen_sample) elif is_list_of(value, BaseDataElement): # already packed gen_samples = value num_batches = len(gen_samples) else: raise TypeError( 'Only support to visualize Tensor or list of DataSample ' f'in MessageHub. But \'{key}\' is \'{type(value)}\'.') self._visualizer.add_datasample( name=f'train_{key}', gen_samples=gen_samples, target_keys=key, vis_mode=vis_mode, n_row=min(self.n_row, num_batches) if self.n_row else None, show=self.show, step=batch_idx) ================================================ FILE: mmagic/engine/optimizers/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .multi_optimizer_constructor import MultiOptimWrapperConstructor from .pggan_optimizer_constructor import PGGANOptimWrapperConstructor from .singan_optimizer_constructor import SinGANOptimWrapperConstructor __all__ = [ 'MultiOptimWrapperConstructor', 'PGGANOptimWrapperConstructor', 'SinGANOptimWrapperConstructor', ] ================================================ FILE: mmagic/engine/optimizers/multi_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import re from typing import Tuple, Union import torch.nn as nn from mmengine import print_log from mmengine.optim import (DefaultOptimWrapperConstructor, OptimWrapper, OptimWrapperDict) from mmagic.registry import (OPTIM_WRAPPER_CONSTRUCTORS, OPTIM_WRAPPERS, OPTIMIZERS) @OPTIM_WRAPPER_CONSTRUCTORS.register_module() class MultiOptimWrapperConstructor: """OptimizerConstructor for GAN models. This class construct optimizer for the submodules of the model separately, and return a :class:`mmengine.optim.OptimWrapperDict` or :class:`mmengine.optim.OptimWrapper`. Example 1: Build multi optimizers (e.g., GANs): >>> # build GAN model >>> model = dict( >>> type='GANModel', >>> num_classes=10, >>> generator=dict(type='Generator'), >>> discriminator=dict(type='Discriminator')) >>> gan_model = MODELS.build(model) >>> # build constructor >>> optim_wrapper = dict( >>> generator=dict( >>> type='OptimWrapper', >>> accumulative_counts=1, >>> optimizer=dict(type='Adam', lr=0.0002, >>> betas=(0.5, 0.999))), >>> discriminator=dict( >>> type='OptimWrapper', >>> accumulative_counts=1, >>> optimizer=dict(type='Adam', lr=0.0002, >>> betas=(0.5, 0.999)))) >>> optim_dict_builder = MultiOptimWrapperConstructor(optim_wrapper) >>> # build optim wrapper dict >>> optim_wrapper_dict = optim_dict_builder(gan_model) Example 2: Build multi optimizers for specific submodules: >>> # build model >>> class GAN(nn.Module): >>> def __init__(self) -> None: >>> super().__init__() >>> self.generator = nn.Conv2d(3, 3, 1) >>> self.discriminator = nn.Conv2d(3, 3, 1) >>> class TextEncoder(nn.Module): >>> def __init__(self): >>> super().__init__() >>> self.embedding = nn.Embedding(100, 100) >>> class ToyModel(nn.Module): >>> def __init__(self) -> None: >>> super().__init__() >>> self.m1 = GAN() >>> self.m2 = nn.Conv2d(3, 3, 1) >>> self.m3 = nn.Linear(2, 2) >>> self.text_encoder = TextEncoder() >>> model = ToyModel() >>> # build constructor >>> optim_wrapper = { >>> '.*embedding': { >>> 'type': 'OptimWrapper', >>> 'optimizer': { >>> 'type': 'Adam', >>> 'lr': 1e-4, >>> 'betas': (0.9, 0.99) >>> } >>> }, >>> 'm1.generator': { >>> 'type': 'OptimWrapper', >>> 'optimizer': { >>> 'type': 'Adam', >>> 'lr': 1e-5, >>> 'betas': (0.9, 0.99) >>> } >>> }, >>> 'm2': { >>> 'type': 'OptimWrapper', >>> 'optimizer': { >>> 'type': 'Adam', >>> 'lr': 1e-5, >>> } >>> } >>> } >>> optim_dict_builder = MultiOptimWrapperConstructor(optim_wrapper) >>> # build optim wrapper dict >>> optim_wrapper_dict = optim_dict_builder(model) Example 3: Build a single optimizer for multi modules (e.g., DreamBooth): >>> # build StableDiffusion model >>> model = dict( >>> type='StableDiffusion', >>> unet=dict(type='unet'), >>> vae=dict(type='vae'), text_encoder=dict(type='text_encoder')) >>> diffusion_model = MODELS.build(model) >>> # build constructor >>> optim_wrapper = dict( >>> modules=['unet', 'text_encoder'] >>> optimizer=dict(type='Adam', lr=0.0002), >>> accumulative_counts=1) >>> optim_dict_builder = MultiOptimWrapperConstructor(optim_wrapper) >>> # build optim wrapper dict >>> optim_wrapper_dict = optim_dict_builder(diffusion_model) Args: optim_wrapper_cfg_dict (dict): Config of the optimizer wrapper. paramwise_cfg (dict): Config of parameter-wise settings. Default: None. """ def __init__(self, optim_wrapper_cfg: dict, paramwise_cfg=None): if not isinstance(optim_wrapper_cfg, dict): raise TypeError('optimizer_cfg should be a dict', f'but got {type(optim_wrapper_cfg)}') assert paramwise_cfg is None, ( 'paramwise_cfg should be set in each optimizer separately') self.optim_cfg = optim_wrapper_cfg if 'modules' in optim_wrapper_cfg: # single optimizer with multi param groups cfg_ = optim_wrapper_cfg.copy() self.modules = cfg_.pop('modules') paramwise_cfg_ = cfg_.pop('paramwise_cfg', None) self.constructors = DefaultOptimWrapperConstructor( cfg_, paramwise_cfg_) else: self.constructors = {} self.modules = {} for key, cfg in self.optim_cfg.items(): cfg_ = cfg.copy() if 'modules' in cfg_: self.modules[key] = cfg_.pop('modules') paramwise_cfg_ = cfg_.pop('paramwise_cfg', None) self.constructors[key] = DefaultOptimWrapperConstructor( cfg_, paramwise_cfg_) def __call__(self, module: nn.Module) -> Union[OptimWrapperDict, OptimWrapper]: """Build optimizer and return a optimizer_wrapper_dict.""" optimizers = {} if hasattr(module, 'module'): module = module.module if isinstance(self.constructors, dict): for key, constructor in self.constructors.items(): module_names = self.modules[key] if self.modules else key if (isinstance(module_names, str) and module_names in module._modules): optimizers[key] = constructor( module._modules[module_names]) optim_wrapper_cfg = constructor.optimizer_cfg print_log( f'Add to optimizer \'{key}\' ' f'({optim_wrapper_cfg}): \'{key}\'.', 'current') else: assert not constructor.paramwise_cfg, ( 'Do not support paramwise_cfg for multi module ' 'optimizer.') params, found_names = get_params_by_names( module, module_names) # build optimizer optimizer_cfg = constructor.optimizer_cfg.copy() optimizer_cfg['params'] = params optimizer = OPTIMIZERS.build(optimizer_cfg) # build optimizer wrapper optim_wrapper_cfg = constructor.optim_wrapper_cfg.copy() optim_wrapper_cfg.setdefault('type', 'OptimWrapper') optim_wrapper = OPTIM_WRAPPERS.build( optim_wrapper_cfg, default_args=dict(optimizer=optimizer)) for name in found_names: print_log( f'Add to optimizer \'{key}\' ' f'({constructor.optimizer_cfg}): \'{name}\'.', 'current') optimizers[key] = optim_wrapper return OptimWrapperDict(**optimizers) else: params, found_names = get_params_by_names(module, self.modules) constructor = self.constructors assert not constructor.paramwise_cfg, ( 'Do not support paramwise_cfg for multi parameters') optimizer_cfg = constructor.optimizer_cfg.copy() optimizer_cfg['params'] = params optimizer = OPTIMIZERS.build(optimizer_cfg) for name in found_names: print_log( f'Add to optimizer ({constructor.optimizer_cfg}): ' f'\'{name}\'.', 'current') # build optimizer wrapper optim_wrapper_cfg = constructor.optim_wrapper_cfg.copy() optim_wrapper_cfg.setdefault('type', 'OptimWrapper') optim_wrapper = OPTIM_WRAPPERS.build( optim_wrapper_cfg, default_args=dict(optimizer=optimizer)) return optim_wrapper def get_params_by_names(module: nn.Module, names: Union[str, list]) -> Tuple[list, list]: """Support two kinds of name matching: 1. matching name from **first-level** submodule. 2. matching name by `re.fullmatch`. Args: module (nn.Module): The module to get parameters. names (Union[str, list]): The name or a list of names of the submodule parameters. Returns: Tuple[list]: A list of parameters and corresponding name for logging. """ if not isinstance(names, list): names = [names] params = [] found_names = [] for name in names: if name in module._modules: params.extend(module._modules[name].parameters()) found_names.append(name) else: for n, m in module.named_modules(): if re.fullmatch(name, n): params.extend(m.parameters()) found_names.append(n) return params, found_names ================================================ FILE: mmagic/engine/optimizers/pggan_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Optional import torch.nn as nn from mmengine.model import is_model_wrapper from mmengine.optim import DefaultOptimWrapperConstructor, OptimWrapperDict from mmagic.registry import OPTIM_WRAPPER_CONSTRUCTORS @OPTIM_WRAPPER_CONSTRUCTORS.register_module() class PGGANOptimWrapperConstructor: """OptimizerConstructor for PGGAN models. Set optimizers for each stage of PGGAN. All submodule must be contained in a :class:`torch.nn.ModuleList` named 'blocks'. And we access each submodule by `MODEL.blocks[SCALE]`, where `MODEL` is generator or discriminator, and the scale is the index of the resolution scale. More detail about the resolution scale and naming rule please refers to :class:`~mmagic.models.editors.pggan.PGGANGenerator` and :class:`~mmagic.models.editors.pggan.PGGANDiscriminator`. Example: >>> # build PGGAN model >>> model = dict( >>> type='ProgressiveGrowingGAN', >>> data_preprocessor=dict(type='GANDataPreprocessor'), >>> noise_size=512, >>> generator=dict(type='PGGANGenerator', out_scale=1024, >>> noise_size=512), >>> discriminator=dict(type='PGGANDiscriminator', in_scale=1024), >>> nkimgs_per_scale={ >>> '4': 600, >>> '8': 1200, >>> '16': 1200, >>> '32': 1200, >>> '64': 1200, >>> '128': 1200, >>> '256': 1200, >>> '512': 1200, >>> '1024': 12000, >>> }, >>> transition_kimgs=600, >>> ema_config=dict(interval=1)) >>> pggan = MODELS.build(model) >>> # build constructor >>> optim_wrapper = dict( >>> generator=dict(optimizer=dict(type='Adam', lr=0.001, >>> betas=(0., 0.99))), >>> discriminator=dict( >>> optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), >>> lr_schedule=dict( >>> generator={ >>> '128': 0.0015, >>> '256': 0.002, >>> '512': 0.003, >>> '1024': 0.003 >>> }, >>> discriminator={ >>> '128': 0.0015, >>> '256': 0.002, >>> '512': 0.003, >>> '1024': 0.003 >>> })) >>> optim_wrapper_dict_builder = PGGANOptimWrapperConstructor( >>> optim_wrapper) >>> # build optim wrapper dict >>> optim_wrapper_dict = optim_wrapper_dict_builder(pggan) Args: optim_wrapper_cfg (dict): Config of the optimizer wrapper. paramwise_cfg (Optional[dict]): Parameter-wise options. """ def __init__(self, optim_wrapper_cfg: dict, paramwise_cfg: Optional[dict] = None): if not isinstance(optim_wrapper_cfg, dict): raise TypeError('optimizer_cfg should be a dict', f'but got {type(optim_wrapper_cfg)}') assert paramwise_cfg is None, ( 'paramwise_cfg should be set in each optimizer separately') self.optim_cfg = deepcopy(optim_wrapper_cfg) self.reset_optim = self.optim_cfg.pop('reset_optim_for_new_scale', True) print(self.reset_optim) self.lr_schedule = self.optim_cfg.pop('lr_schedule', dict()) self.constructors = {} for key, cfg in self.optim_cfg.items(): cfg_ = cfg.copy() paramwise_cfg_ = cfg_.pop('paramwise_cfg', None) self.constructors[key] = DefaultOptimWrapperConstructor( cfg_, paramwise_cfg_) def __call__(self, module: nn.Module) -> OptimWrapperDict: """Build optimizer and return a optimizerwrapperdict.""" optimizers = {} if is_model_wrapper(module): module = module.module # module.scales: [int, int] scales = [s[0] for s in module.scales] for key, base_cfg in self.optim_cfg.items(): submodule = module._modules[key] cfg_ = base_cfg.copy() base_lr = cfg_['optimizer']['lr'] paramwise_cfg_ = base_cfg.pop('paramwise_cfg', None) default_constructor = self.constructors[key] default_optimizer = default_constructor(submodule) for idx, scale in enumerate(scales): if self.reset_optim: scale_cfg = cfg_.copy() scale_lr = self.lr_schedule[key].get(str(scale), base_lr) scale_cfg['optimizer']['lr'] = scale_lr constructor = DefaultOptimWrapperConstructor( scale_cfg, paramwise_cfg_) optimizers[f'{key}_{scale}'] = constructor(submodule) else: optimizers[f'{key}_{scale}'] = default_optimizer optimizers = OptimWrapperDict(**optimizers) return optimizers ================================================ FILE: mmagic/engine/optimizers/singan_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn from mmengine.optim import DefaultOptimWrapperConstructor, OptimWrapperDict from mmagic.registry import OPTIM_WRAPPER_CONSTRUCTORS @OPTIM_WRAPPER_CONSTRUCTORS.register_module() class SinGANOptimWrapperConstructor: """OptimizerConstructor for SinGAN models. Set optimizers for each submodule of SinGAN. All submodule must be contained in a :class:`torch.nn.ModuleList` named 'blocks'. And we access each submodule by `MODEL.blocks[SCALE]`, where `MODEL` is generator or discriminator, and the scale is the index of the resolution scale. More detail about the resolution scale and naming rule please refers to :class:`~mmagic.models.editors.singan.SinGANMultiScaleGenerator` and :class:`~mmagic.models.editors.singan.SinGANMultiScaleDiscriminator`. Example: >>> # build SinGAN model >>> model = dict( >>> type='SinGAN', >>> data_preprocessor=dict( >>> type='GANDataPreprocessor', >>> non_image_keys=['input_sample']), >>> generator=dict( >>> type='SinGANMultiScaleGenerator', >>> in_channels=3, >>> out_channels=3, >>> num_scales=2), >>> discriminator=dict( >>> type='SinGANMultiScaleDiscriminator', >>> in_channels=3, >>> num_scales=3)) >>> singan = MODELS.build(model) >>> # build constructor >>> optim_wrapper = dict( >>> generator=dict(optimizer=dict(type='Adam', lr=0.0005, >>> betas=(0.5, 0.999))), >>> discriminator=dict( >>> optimizer=dict(type='Adam', lr=0.0005, >>> betas=(0.5, 0.999)))) >>> optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( >>> optim_wrapper) >>> # build optim wrapper dict >>> optim_wrapper_dict = optim_wrapper_dict_builder(singan) Args: optim_wrapper_cfg (dict): Config of the optimizer wrapper. paramwise_cfg (Optional[dict]): Parameter-wise options. """ def __init__(self, optim_wrapper_cfg: dict, paramwise_cfg: Optional[dict] = None): if not isinstance(optim_wrapper_cfg, dict): raise TypeError('optimizer_cfg should be a dict', f'but got {type(optim_wrapper_cfg)}') assert paramwise_cfg is None, ( 'paramwise_cfg should be set in each optimizer separately') self.optim_cfg = optim_wrapper_cfg self.constructors = {} for key, cfg in self.optim_cfg.items(): cfg_ = cfg.copy() paramwise_cfg_ = cfg_.pop('paramwise_cfg', None) self.constructors[key] = DefaultOptimWrapperConstructor( cfg_, paramwise_cfg_) def __call__(self, module: nn.Module) -> OptimWrapperDict: """Build optimizer and return a optimizerwrapperdict.""" optimizers = {} if hasattr(module, 'module'): module = module.module num_scales = module.num_scales for key, constructor in self.constructors.items(): for idx in range(num_scales + 1): submodule = module._modules[key] if hasattr(submodule, 'module'): submodule = submodule.module optimizers[f'{key}_{idx}'] = constructor(submodule.blocks[idx]) optimizers = OptimWrapperDict(**optimizers) return optimizers ================================================ FILE: mmagic/engine/runner/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .log_processor import LogProcessor from .multi_loops import MultiTestLoop, MultiValLoop __all__ = ['MultiTestLoop', 'MultiValLoop', 'LogProcessor'] ================================================ FILE: mmagic/engine/runner/log_processor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.runner import LogProcessor as BaseLogProcessor from mmagic.registry import LOG_PROCESSORS @LOG_PROCESSORS.register_module() # type: ignore class LogProcessor(BaseLogProcessor): """LogProcessor inherits from :class:`mmengine.runner.LogProcessor` and overwrites :meth:`self.get_log_after_iter`. This log processor should be used along with :class:`mmagic.engine.runner.MultiValLoop` and :class:`mmagic.engine.runner.MultiTestLoop`. """ def _get_dataloader_size(self, runner, mode) -> int: """Get dataloader size of current loop. In `MultiValLoop` and `MultiTestLoop`, we use `total_length` instead of `len(dataloader)` to denote the total number of iterations. Args: runner (Runner): The runner of the training/validation/testing mode (str): Current mode of runner. Returns: int: The dataloader size of current loop. """ if hasattr(self._get_cur_loop(runner, mode), 'total_length'): return self._get_cur_loop(runner, mode).total_length else: return super()._get_dataloader_size(runner, mode) ================================================ FILE: mmagic/engine/runner/loop_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import WARNING from typing import Any, Dict, List, Union from mmengine import is_list_of, print_log from mmengine.evaluator import Evaluator EVALUATOR_TYPE = Union[Evaluator, Dict, List] def update_and_check_evaluator(evaluator: EVALUATOR_TYPE ) -> Union[Evaluator, dict]: """Check the whether the evaluator instance or dict config is Evaluator. If input is a dict config, attempt to set evaluator type as Evaluator and raised warning if it is not allowed. If input is a Evaluator instance, check whether it is a Evaluator class, otherwise, Args: evaluator (Union[Evaluator, dict, list]): The evaluator instance or config dict. """ # check Evaluator instance warning_template = ('Evaluator type for current config is \'{}\'. ' 'If you want to use MultiValLoop, we strongly ' 'recommend you to use \'Evaluator\' provided by ' '\'MMagic\'. Otherwise, there maybe some potential ' 'bugs.') if isinstance(evaluator, Evaluator): cls_name = evaluator.__class__.__name__ if cls_name != 'Evaluator': print_log(warning_template.format(cls_name), 'current', WARNING) return evaluator # add type for **single evaluator with list of metrics** if isinstance(evaluator, list): evaluator = dict(type='Evaluator', metrics=evaluator) return evaluator # check and update dict config assert isinstance(evaluator, dict), ( 'Can only conduct check and update for list of metrics, a config dict ' f'or a Evaluator object. But receives {type(evaluator)}.') evaluator.setdefault('type', 'Evaluator') evaluator.setdefault('metrics', None) # default as 'dummy evaluator' _type = evaluator['type'] if _type != 'Evaluator': print_log(warning_template.format(_type), 'current', WARNING) return evaluator def is_evaluator(evaluator: Any) -> bool: """Check whether the input is a valid evaluator config or Evaluator object. Args: evaluator (Any): The input to check. Returns: bool: Whether the input is a valid evaluator config or Evaluator object. """ # Single evaluator with type if isinstance(evaluator, dict) and 'metrics' in evaluator: return True # Single evaluator without type elif (is_list_of(evaluator, dict) and all(['metrics' not in cfg_ for cfg_ in evaluator])): return True elif isinstance(evaluator, Evaluator): return True else: return False ================================================ FILE: mmagic/engine/runner/multi_loops.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import warnings from typing import Dict, List, Sequence, Union import torch from mmengine.evaluator import BaseMetric, Evaluator from mmengine.runner.amp import autocast from mmengine.runner.base_loop import BaseLoop from torch.utils.data import DataLoader from mmagic.registry import LOOPS from .loop_utils import is_evaluator, update_and_check_evaluator DATALOADER_TYPE = Union[DataLoader, Dict, List] EVALUATOR_TYPE = Union[Evaluator, Dict, List] @LOOPS.register_module() class MultiValLoop(BaseLoop): """Validation loop for MMagic models which support evaluate multiply dataset at the same time. This class support evaluate: 1. Metrics (metric) on a single dataset (e.g. PSNR and SSIM on DIV2K dataset) 2. Different metrics on different datasets (e.g. PSNR on DIV2K and SSIM and PSNR on SET5) Use cases: Case 1: metrics on a single dataset >>> # add the following lines in your config >>> # 1. use `MultiValLoop` instead of `ValLoop` in MMEngine >>> val_cfg = dict(type='MultiValLoop') >>> # 2. specific MultiEvaluator instead of Evaluator in MMEngine >>> val_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=[ >>> dict(type='PSNR', crop_border=2, prefix='Set5'), >>> dict(type='SSIM', crop_border=2, prefix='Set5'), >>> ]) >>> # 3. define dataloader >>> val_dataloader = dict(...) Case 2: different metrics on different datasets >>> # add the following lines in your config >>> # 1. use `MultiValLoop` instead of `ValLoop` in MMEngine >>> val_cfg = dict(type='MultiValLoop') >>> # 2. specific a list MultiEvaluator >>> # do not forget to add prefix for each metric group >>> div2k_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=dict(type='SSIM', crop_border=2, prefix='DIV2K')) >>> set5_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=[ >>> dict(type='PSNR', crop_border=2, prefix='Set5'), >>> dict(type='SSIM', crop_border=2, prefix='Set5'), >>> ]) >>> # define evaluator config >>> val_evaluator = [div2k_evaluator, set5_evaluator] >>> # 3. specific a list dataloader for each metric groups >>> div2k_dataloader = dict(...) >>> set5_dataloader = dict(...) >>> # define dataloader config >>> val_dataloader = [div2k_dataloader, set5_dataloader] Args: runner (Runner): A reference of runner. dataloader (Dataloader or dict or list): A dataloader object or a dict to build a dataloader a list of dataloader object or a list of config dicts. evaluator (Evaluator or dict or list): A evaluator object or a dict to build the evaluator or a list of evaluator object or a list of config dicts. """ def __init__(self, runner, dataloader: DATALOADER_TYPE, evaluator: EVALUATOR_TYPE, fp16: bool = False): self._runner = runner self.dataloaders = self._build_dataloaders(dataloader) self.evaluators = self._build_evaluators(evaluator) self.fp16 = fp16 assert len(self.dataloaders) == len(self.evaluators), ( 'Length of dataloaders and evaluators must be same, but receive ' f'\'{len(self.dataloaders)}\' and \'{len(self.evaluators)}\'' 'respectively.') self._total_length = None # length for all dataloaders @property def total_length(self) -> int: if self._total_length is not None: return self._total_length warnings.warn('\'total_length\' has not been initialized and return ' '\'0\' for safety. This result is likely to be incorrect' ' and we recommend you to call \'total_length\' after ' '\'self.run\' is called.') return 0 def _build_dataloaders(self, dataloader: DATALOADER_TYPE) -> List[DataLoader]: """Build dataloaders. Args: dataloader (Dataloader or dict or list): A dataloader object or a dict to build a dataloader a list of dataloader object or a list of config dict. Returns: List[Dataloader]: List of dataloaders for compute metrics. """ runner = self._runner if not isinstance(dataloader, list): dataloader = [dataloader] dataloaders = [] for loader in dataloader: if isinstance(loader, dict): dataloaders.append( runner.build_dataloader(loader, seed=runner.seed)) else: dataloaders.append(loader) return dataloaders def _build_evaluators(self, evaluator: EVALUATOR_TYPE) -> List[Evaluator]: """Build evaluators. Args: evaluator (Evaluator or dict or list): A evaluator object or a dict to build the evaluator or a list of evaluator object or a list of config dicts. Returns: List[Evaluator]: List of evaluators for compute metrics. """ runner = self._runner # Input type checking and packing # 1. Single evaluator without type: [dict(), dict(), ...] # 2. Single evaluator with type: dict(type=xx, metrics=xx) # 3. Multi evaluator without type: [[dict, ...], [dict, ...]] # 4. Multi evaluator with type: [dict(type=xx, metrics=xx), dict(...)] if is_evaluator(evaluator): evaluator = [update_and_check_evaluator(evaluator)] else: assert all([ is_evaluator(cfg) for cfg in evaluator ]), ('Unsupported evaluator type, please check your input and ' 'the docstring.') evaluator = [update_and_check_evaluator(cfg) for cfg in evaluator] evaluators = [runner.build_evaluator(eval) for eval in evaluator] return evaluators def run(self): """Launch validation. The evaluation process consists of four steps. 1. Prepare pre-calculated items for all metrics by calling :meth:`self.evaluator.prepare_metrics`. 2. Get a list of metrics-sampler pair. Each pair contains a list of metrics with the same sampler mode and a shared sampler. 3. Generate images for the each metrics group. Loop for elements in each sampler and feed to the model as input by calling :meth:`self.run_iter`. 4. Evaluate all metrics by calling :meth:`self.evaluator.evaluate`. """ self._runner.call_hook('before_val') self._runner.call_hook('before_val_epoch') self._runner.model.eval() # access to the true model module = self._runner.model if hasattr(self.runner.model, 'module'): module = module.module multi_metric = dict() idx_counter = 0 self._total_length = 0 # 1. prepare all metrics and get the total length metrics_sampler_lists = [] meta_info_list = [] dataset_name_list = [] for evaluator, dataloader in zip(self.evaluators, self.dataloaders): # 1.1 prepare for metrics evaluator.prepare_metrics(module, dataloader) # 1.2 prepare for metric-sampler pair metrics_sampler_list = evaluator.prepare_samplers( module, dataloader) metrics_sampler_lists.append(metrics_sampler_list) # 1.3 update total length self._total_length += sum([ len(metrics_sampler[1]) for metrics_sampler in metrics_sampler_list ]) # 1.4 save metainfo and dataset's name meta_info_list.append( getattr(dataloader.dataset, 'metainfo', None)) dataset_name_list.append(dataloader.dataset.__class__.__name__) # 2. run evaluation for idx in range(len(self.evaluators)): # 2.1 set self.evaluator for run_iter self.evaluator = self.evaluators[idx] self.dataloader = self.dataloaders[idx] # 2.2 update metainfo for evaluator and visualizer meta_info = meta_info_list[idx] dataset_name = dataset_name_list[idx] if meta_info: self.evaluator.dataset_meta = meta_info self._runner.visualizer.dataset_meta = meta_info else: warnings.warn( f'Dataset {dataset_name} has no metainfo. `dataset_meta` ' 'in evaluator, metric and visualizer will be None.') # 2.3 generate images metrics_sampler_list = metrics_sampler_lists[idx] for metrics, sampler in metrics_sampler_list: for data in sampler: self.run_iter(idx_counter, data, metrics) idx_counter += 1 # 2.4 evaluate metrics and update multi_metric metrics = self.evaluator.evaluate() if multi_metric and metrics.keys() & multi_metric.keys(): raise ValueError('Please set different prefix for different' ' datasets in `val_evaluator`') else: multi_metric.update(metrics) # 3. finish evaluation and call hooks self._runner.call_hook('after_val_epoch', metrics=multi_metric) self._runner.call_hook('after_val') @torch.no_grad() def run_iter(self, idx, data_batch: dict, metrics: Sequence[BaseMetric]): """Iterate one mini-batch and feed the output to corresponding `metrics`. Args: idx (int): Current idx for the input data. data_batch (dict): Batch of data from dataloader. metrics (Sequence[BaseMetric]): Specific metrics to evaluate. """ self._runner.call_hook( 'before_val_iter', batch_idx=idx, data_batch=data_batch) # outputs should be sequence of BaseDataElement with autocast(enabled=self.fp16): outputs = self._runner.model.val_step(data_batch) self.evaluator.process(outputs, data_batch, metrics) self._runner.call_hook( 'after_val_iter', batch_idx=idx, data_batch=data_batch, outputs=outputs) @LOOPS.register_module() class MultiTestLoop(BaseLoop): """Test loop for MMagic models which support evaluate multiply dataset at the same time. This class support evaluate: 1. Metrics (metric) on a single dataset (e.g. PSNR and SSIM on DIV2K dataset) 2. Different metrics on different datasets (e.g. PSNR on DIV2K and SSIM and PSNR on SET5) Use cases: Case 1: metrics on a single dataset >>> # add the following lines in your config >>> # 1. use `MultiTestLoop` instead of `TestLoop` in MMEngine >>> val_cfg = dict(type='MultiTestLoop') >>> # 2. specific MultiEvaluator instead of Evaluator in MMEngine >>> test_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=[ >>> dict(type='PSNR', crop_border=2, prefix='Set5'), >>> dict(type='SSIM', crop_border=2, prefix='Set5'), >>> ]) >>> # 3. define dataloader >>> test_dataloader = dict(...) Case 2: different metrics on different datasets >>> # add the following lines in your config >>> # 1. use `MultiTestLoop` instead of `TestLoop` in MMEngine >>> Test_cfg = dict(type='MultiTestLoop') >>> # 2. specific a list MultiEvaluator >>> # do not forget to add prefix for each metric group >>> div2k_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=dict(type='SSIM', crop_border=2, prefix='DIV2K')) >>> set5_evaluator = dict( >>> type='MultiEvaluator', >>> metrics=[ >>> dict(type='PSNR', crop_border=2, prefix='Set5'), >>> dict(type='SSIM', crop_border=2, prefix='Set5'), >>> ]) >>> # define evaluator config >>> test_evaluator = [div2k_evaluator, set5_evaluator] >>> # 3. specific a list dataloader for each metric groups >>> div2k_dataloader = dict(...) >>> set5_dataloader = dict(...) >>> # define dataloader config >>> test_dataloader = [div2k_dataloader, set5_dataloader] Args: runner (Runner): A reference of runner. dataloader (Dataloader or dict or list): A dataloader object or a dict to build a dataloader a list of dataloader object or a list of config dicts. evaluator (Evaluator or dict or list): A evaluator object or a dict to build the evaluator or a list of evaluator object or a list of config dicts. """ def __init__(self, runner, dataloader, evaluator, fp16=False): self._runner = runner self.dataloaders = self._build_dataloaders(dataloader) self.evaluators = self._build_evaluators(evaluator) self.fp16 = fp16 assert len(self.dataloaders) == len(self.evaluators), ( 'Length of dataloaders and evaluators must be same, but receive ' f'\'{len(self.dataloaders)}\' and \'{len(self.evaluators)}\'' 'respectively.') self._total_length = None @property def total_length(self) -> int: if self._total_length is not None: return self._total_length warnings.warn('\'total_length\' has not been initialized and return ' '\'0\' for safety. This result is likely to be incorrect' ' and we recommend you to call \'total_length\' after ' '\'self.run\' is called.') return 0 def _build_dataloaders(self, dataloader: DATALOADER_TYPE) -> List[DataLoader]: """Build dataloaders. Args: dataloader (Dataloader or dict or list): A dataloader object or a dict to build a dataloader a list of dataloader object or a list of config dict. Returns: List[Dataloader]: List of dataloaders for compute metrics. """ runner = self._runner if not isinstance(dataloader, list): dataloader = [dataloader] dataloaders = [] for loader in dataloader: if isinstance(loader, dict): dataloaders.append( runner.build_dataloader(loader, seed=runner.seed)) else: dataloaders.append(loader) return dataloaders def _build_evaluators(self, evaluator: EVALUATOR_TYPE) -> List[Evaluator]: """Build evaluators. Args: evaluator (Evaluator or dict or list): A evaluator object or a dict to build the evaluator or a list of evaluator object or a list of config dicts. Returns: List[Evaluator]: List of evaluators for compute metrics. """ runner = self._runner # Input type checking and packing # 1. Single evaluator without type: [dict(), dict(), ...] # 2. Single evaluator with type: dict(type=xx, metrics=xx) # 3. Multi evaluator without type: [[dict, ...], [dict, ...]] # 4. Multi evaluator with type: [dict(type=xx, metrics=xx), dict(...)] if is_evaluator(evaluator): evaluator = [update_and_check_evaluator(evaluator)] else: assert all([ is_evaluator(cfg) for cfg in evaluator ]), ('Unsupported evaluator type, please check your input and ' 'the docstring.') evaluator = [update_and_check_evaluator(cfg) for cfg in evaluator] evaluators = [runner.build_evaluator(eval) for eval in evaluator] return evaluators def run(self): """Launch validation. The evaluation process consists of four steps. 1. Prepare pre-calculated items for all metrics by calling :meth:`self.evaluator.prepare_metrics`. 2. Get a list of metrics-sampler pair. Each pair contains a list of metrics with the same sampler mode and a shared sampler. 3. Generate images for the each metrics group. Loop for elements in each sampler and feed to the model as input by calling :meth:`self.run_iter`. 4. Evaluate all metrics by calling :meth:`self.evaluator.evaluate`. """ self._runner.call_hook('before_test') self._runner.call_hook('before_test_epoch') self._runner.model.eval() # access to the true model module = self._runner.model if hasattr(self._runner.model, 'module'): module = module.module multi_metric = dict() idx_counter = 0 self._total_length = 0 # 1. prepare all metrics and get the total length metrics_sampler_lists = [] meta_info_list = [] dataset_name_list = [] for evaluator, dataloader in zip(self.evaluators, self.dataloaders): # 1.1 prepare for metrics evaluator.prepare_metrics(module, dataloader) # 1.2 prepare for metric-sampler pair metrics_sampler_list = evaluator.prepare_samplers( module, dataloader) metrics_sampler_lists.append(metrics_sampler_list) # 1.3 update total length self._total_length += sum([ len(metrics_sampler[1]) for metrics_sampler in metrics_sampler_list ]) # 1.4 save metainfo and dataset's name meta_info_list.append( getattr(dataloader.dataset, 'metainfo', None)) dataset_name_list.append(dataloader.dataset.__class__.__name__) # 2. run evaluation for idx in range(len(self.evaluators)): # 2.1 set self.evaluator for run_iter self.evaluator = self.evaluators[idx] self.dataloader = self.dataloaders[idx] # 2.2 update metainfo for evaluator and visualizer meta_info = meta_info_list[idx] dataset_name = dataset_name_list[idx] if meta_info: self.evaluator.dataset_meta = meta_info self._runner.visualizer.dataset_meta = meta_info else: warnings.warn( f'Dataset {dataset_name} has no metainfo. `dataset_meta` ' 'in evaluator, metric and visualizer will be None.') # 2.3 generate images metrics_sampler_list = metrics_sampler_lists[idx] for metrics, sampler in metrics_sampler_list: for data in sampler: self.run_iter(idx_counter, data, metrics) idx_counter += 1 # 2.4 evaluate metrics and update multi_metric metrics = self.evaluator.evaluate() if multi_metric and metrics.keys() & multi_metric.keys(): raise ValueError('Please set different prefix for different' ' datasets in `test_evaluator`') else: multi_metric.update(metrics) # 3. finish evaluation and call hooks self._runner.call_hook('after_test_epoch', metrics=multi_metric) self._runner.call_hook('after_test') @torch.no_grad() def run_iter(self, idx, data_batch: dict, metrics: Sequence[BaseMetric]): """Iterate one mini-batch and feed the output to corresponding `metrics`. Args: idx (int): Current idx for the input data. data_batch (dict): Batch of data from dataloader. metrics (Sequence[BaseMetric]): Specific metrics to evaluate. """ self._runner.call_hook( 'before_test_iter', batch_idx=idx, data_batch=data_batch) # outputs should be sequence of BaseDataElement with autocast(enabled=self.fp16): outputs = self._runner.model.test_step(data_batch) self.evaluator.process(outputs, data_batch, metrics) self._runner.call_hook( 'after_test_iter', batch_idx=idx, data_batch=data_batch, outputs=outputs) ================================================ FILE: mmagic/engine/schedulers/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .linear_lr_scheduler_with_interval import LinearLrInterval from .reduce_lr_scheduler import ReduceLR __all__ = [ 'LinearLrInterval', 'ReduceLR', ] ================================================ FILE: mmagic/engine/schedulers/linear_lr_scheduler_with_interval.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine import MessageHub from mmengine.optim import LinearLR from mmagic.registry import PARAM_SCHEDULERS @PARAM_SCHEDULERS.register_module() class LinearLrInterval(LinearLR): """Linear learning rate scheduler for image generation. In the beginning, the learning rate is 'start_factor' defined in mmengine. We give a target learning rate 'end_factor' and a start point 'begin'. If :attr:self.by_epoch is True, 'begin' is calculated by epoch, otherwise, calculated by iteration." Before 'begin', we fix learning rate as 'start_factor'; After 'begin', we linearly update learning rate to 'end_factor'. Args: interval (int): The interval to update the learning rate. Default: 1. """ def __init__(self, *args, interval=1, **kwargs): self.interval = interval super().__init__(*args, **kwargs) def _get_value(self): """Compute value using chainable form of the scheduler.""" if self.last_step == 0: return [ group[self.param_name] * self.start_factor for group in self.optimizer.param_groups ] message_hub = MessageHub.get_current_instance() if self.by_epoch: progress = message_hub.get_info('epoch') else: progress = message_hub.get_info('iter') max_progress = self.end factor = (max(0, progress - self.begin) // self.interval) / ( (max_progress - self.begin) // self.interval) return [ self.start_factor + (self.end_factor - self.start_factor) * factor for group in self.optimizer.param_groups ] ================================================ FILE: mmagic/engine/schedulers/reduce_lr_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine import MessageHub from mmengine.optim import _ParamScheduler from mmagic.registry import PARAM_SCHEDULERS @PARAM_SCHEDULERS.register_module() class ReduceLR(_ParamScheduler): """Decays the learning rate of each parameter group by linearly changing small multiplicative factor until the number of epoch reaches a pre-defined milestone: ``end``. Notice that such decay can happen simultaneously with other changes to the learning rate from outside this scheduler. Note: The learning rate of each parameter group will be update at regular intervals. Args: optimizer (Optimizer or OptimWrapper): Wrapped optimizer. mode (str, optional): One of `min`, `max`. In `min` mode, lr will be reduced when the quantity monitored has stopped decreasing; in `max` mode it will be reduced when the quantity monitored has stopped increasing. Default: 'min'. factor (float, optional): Factor by which the learning rate will be reduced. new_lr = lr * factor. Default: 0.1. patience (int, optional): Number of epochs with no improvement after which learning rate will be reduced. For example, if `patience = 2`, then we will ignore the first 2 epochs with no improvement, and will only decrease the LR after the 3rd epoch if the loss still hasn't improved then. Default: 10. threshold (float, optional): Threshold for measuring the new optimum, to only focus on significant changes. Default: 1e-4. threshold_mode (str, optional): One of `rel`, `abs`. In `rel` mode, dynamic_threshold = best * ( 1 + threshold ) in 'max' mode or best * ( 1 - threshold ) in `min` mode. In `abs` mode, dynamic_threshold = best + threshold in `max` mode or best - threshold in `min` mode. Default: 'rel'. cooldown (int, optional): Number of epochs to wait before resuming normal operation after lr has been reduced. Default: 0. min_lr (float, optional): Minimum LR value to keep. If LR after decay is lower than `min_lr`, it will be clipped to this value. Default: 0. eps (float, optional): Minimal decay applied to lr. If the difference between new and old lr is smaller than eps, the update is ignored. Default: 1e-8. begin (int): Step at which to start updating the learning rate. Defaults to 0. end (int): Step at which to stop updating the learning rate. last_step (int): The index of last step. Used for resume without state dict. Defaults to -1. by_epoch (bool): Whether the scheduled learning rate is updated by epochs. Defaults to True. """ def __init__(self, optimizer, mode: str = 'min', factor: float = 0.1, patience: int = 10, threshold: float = 1e-4, threshold_mode: str = 'rel', cooldown: int = 0, min_lr: float = 0., eps: float = 1e-8, **kwargs): super().__init__(optimizer=optimizer, param_name='lr', **kwargs) self.message_hub = MessageHub.get_instance('reduce_lr') if mode not in ['min', 'max']: raise ValueError( 'mode must be one of "min" or "max", instead got {mode}') self.mode = mode if factor >= 1.0 or factor < 0: raise ValueError('Factor should be < 1.0 and >=0') self.factor = factor self.patience = patience self.threshold = threshold if threshold_mode not in ['rel', 'abs']: raise ValueError('thresh_mode must be one of "rel" or "abs",' f'instead got {threshold_mode}') self.threshold_mode = threshold_mode self.cooldown = cooldown self.cooldown_counter = 0 self.best = None self.num_bad_epochs = None self.mode_worse = None # the worse value for the chosen mode self.min_lr = min_lr self.eps = eps self.last_epoch = 0 self._init_is_better(self.mode) self._reset() def _get_value(self): """Compute value using chainable form of the scheduler.""" if self.last_step == 0: return [ group[self.param_name] for group in self.optimizer.param_groups ] current = self.message_hub.get_scalar('value').current() if self.is_better(current, self.best): self.best = current self.num_bad_epochs = 0 else: self.num_bad_epochs += 1 if self.in_cooldown: self.cooldown_counter -= 1 self.num_bad_epochs = 0 if self.num_bad_epochs > self.patience: self.cooldown_counter = self.cooldown self.num_bad_epochs = 0 results = [] for group in self.optimizer.param_groups: regular_lr = group[self.param_name] if regular_lr - regular_lr * self.factor > self.eps: regular_lr = max(regular_lr * self.factor, self.min_lr) results.append(regular_lr) return results else: return [ group[self.param_name] for group in self.optimizer.param_groups ] def _init_is_better(self, mode): if mode == 'min': self.mode_worse = float('inf') else: self.mode_worse = float('-inf') def _reset(self): self.best = self.mode_worse self.cooldown_counter = 0 self.num_bad_epochs = 0 def is_better(self, a, best): if self.mode == 'min' and self.threshold_mode == 'rel': rel_epsilon = 1. - self.threshold return a < best * rel_epsilon elif self.mode == 'min' and self.threshold_mode == 'abs': return a < best - self.threshold elif self.mode == 'max' and self.threshold_mode == 'rel': rel_epsilon = 1. + self.threshold return a > best * rel_epsilon else: return a > best + self.threshold @property def in_cooldown(self): return self.cooldown_counter > 0 ================================================ FILE: mmagic/evaluation/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .evaluator import Evaluator from .functional import gauss_gradient from .metrics import (MAE, MSE, NIQE, PSNR, SAD, SNR, SSIM, ConnectivityError, Equivariance, FrechetInceptionDistance, GradientError, InceptionScore, MattingMSE, MultiScaleStructureSimilarity, PerceptualPathLength, PrecisionAndRecall, SlicedWassersteinDistance, TransFID, TransIS, niqe, psnr, snr, ssim) __all__ = [ 'Evaluator', 'gauss_gradient', 'ConnectivityError', 'GradientError', 'MAE', 'MattingMSE', 'MSE', 'NIQE', 'niqe', 'PSNR', 'psnr', 'SAD', 'SNR', 'snr', 'SSIM', 'ssim', 'Equivariance', 'FrechetInceptionDistance', 'InceptionScore', 'MultiScaleStructureSimilarity', 'PerceptualPathLength', 'MultiScaleStructureSimilarity', 'PrecisionAndRecall', 'SlicedWassersteinDistance', 'TransFID', 'TransIS', ] ================================================ FILE: mmagic/evaluation/evaluator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import hashlib from collections import defaultdict from typing import Any, Iterator, List, Optional, Sequence, Tuple, Union from mmengine.evaluator import BaseMetric, Evaluator from mmengine.model import BaseModel from torch.utils.data.dataloader import DataLoader from mmagic.registry import EVALUATORS from mmagic.structures import DataSample from .metrics.base_gen_metric import GenMetric @EVALUATORS.register_module() class Evaluator(Evaluator): """Evaluator for generative models. Unlike high-level vision tasks, metrics for generative models have various input types. For example, Inception Score (IS, :class:`~mmagic.evaluation.InceptionScore`) only needs to take fake images as input. However, Frechet Inception Distance (FID, :class:`~mmagic.evaluation.FrechetInceptionDistance`) needs to take both real images and fake images as input, and the numbers of real images and fake images can be set arbitrarily. For Perceptual path length (PPL, :class:`~mmagic.evaluation.PerceptualPathLength`), generator need to sample images along a latent path. In order to be compatible with different metrics, we designed two critical functions, :meth:`prepare_metrics` and :meth:`prepare_samplers` to support those requirements. - :meth:`prepare_metrics` set the image images' color order and pass the dataloader to all metrics. Therefore metrics need pre-processing to prepare the corresponding feature. - :meth:`prepare_samplers` pass the dataloader and model to the metrics, and get the corresponding sampler of each kind of metrics. Metrics with same sample mode can share the sampler. The whole evaluation process can be found in :meth:`mmagic.engine.runner.MultiValLoop.run` and :meth:`mmagic.engine.runner.MultiTestLoop.run`. Args: metrics (dict or BaseMetric or Sequence): The config of metrics. """ def __init__(self, metrics: Union[dict, BaseMetric, Sequence]): if metrics is not None: super().__init__(metrics) else: self.metrics = None self.is_ready = False def prepare_metrics(self, module: BaseModel, dataloader: DataLoader): """Prepare for metrics before evaluation starts. Some metrics use pretrained model to extract feature. Some metrics use pretrained model to extract feature and input channel order may vary among those models. Therefore, we first parse the output color order from data preprocessor and set the color order for each metric. Then we pass the dataloader to each metrics to prepare pre-calculated items. (e.g. inception feature of the real images). If metric has no pre-calculated items, :meth:`metric.prepare` will be ignored. Once the function has been called, :attr:`self.is_ready` will be set as `True`. If :attr:`self.is_ready` is `True`, this function will directly return to avoid duplicate computation. Args: module (BaseModel): Model to evaluate. dataloader (DataLoader): The dataloader for real images. """ if self.metrics is None: self.is_ready = True return if self.is_ready: return # prepare metrics for metric in self.metrics: metric.prepare(module, dataloader) self.is_ready = True @staticmethod def _cal_metric_hash(metric: GenMetric): """Calculate a unique hash value based on the `SAMPLER_MODE` and `sample_model`.""" sampler_mode = metric.SAMPLER_MODE sample_model = metric.sample_model metric_dict = { 'SAMPLER_MODE': sampler_mode, 'sample_model': sample_model } if hasattr(metric, 'need_cond_input'): metric_dict['need_cond_input'] = metric.need_cond_input md5 = hashlib.md5(repr(metric_dict).encode('utf-8')).hexdigest() return md5 def prepare_samplers(self, module: BaseModel, dataloader: DataLoader ) -> List[Tuple[List[BaseMetric], Iterator]]: """Prepare for the sampler for metrics whose sampling mode are different. For generative models, different metric need image generated with different inputs. For example, FID, KID and IS need images generated with random noise, and PPL need paired images on the specific noise interpolation path. Therefore, we first group metrics with respect to their sampler's mode (refers to :attr:~`GenMetrics.SAMPLER_MODE`), and build a shared sampler for each metric group. To be noted that, the length of the shared sampler depends on the metric of the most images required in each group. Args: module (BaseModel): Model to evaluate. Some metrics (e.g. PPL) require `module` in their sampler. dataloader (DataLoader): The dataloader for real image. Returns: List[Tuple[List[BaseMetric], Iterator]]: A list of "metrics-shared sampler" pair. """ if self.metrics is None: return [[[None], []]] # grouping metrics based on `SAMPLER_MODE` and `sample_mode` metric_mode_dict = defaultdict(list) for metric in self.metrics: metric_md5 = self._cal_metric_hash(metric) metric_mode_dict[metric_md5].append(metric) metrics_sampler_list = [] for metrics in metric_mode_dict.values(): first_metric = metrics[0] metrics_sampler_list.append([ metrics, first_metric.get_metric_sampler(module, dataloader, metrics) ]) return metrics_sampler_list def process(self, data_samples: Sequence[DataSample], data_batch: Optional[Any], metrics: Sequence[BaseMetric]) -> None: """Pass `data_batch` from dataloader and `predictions` (generated results) to corresponding `metrics`. Args: data_samples (Sequence[DataSample]): A batch of generated results from model. data_batch (Optional[Any]): A batch of data from the metrics specific sampler or the dataloader. metrics (Optional[Sequence[BaseMetric]]): Metrics to evaluate. """ if self.metrics is None: return _data_samples = [] for data_sample in data_samples: if isinstance(data_sample, DataSample): _data_samples.append(data_sample.to_dict()) else: _data_samples.append(data_sample) # feed to the specifics metrics for metric in metrics: metric.process(data_batch, _data_samples) def evaluate(self) -> dict: """Invoke ``evaluate`` method of each metric and collect the metrics dictionary. Different from `Evaluator.evaluate`, this function does not take `size` as input, and elements in `self.metrics` will call their own `evaluate` method to calculate the metric. Returns: dict: Evaluation results of all metrics. The keys are the names of the metrics, and the values are corresponding results. """ if self.metrics is None: return {'No Metric': 'Nan'} metrics = {} for metric in self.metrics: _results = metric.evaluate() # Check metric name conflicts for name in _results.keys(): if name in metrics: raise ValueError( 'There are multiple evaluation results with the same ' f'metric name {name}. Please make sure all metrics ' 'have different prefixes.') metrics.update(_results) return metrics ================================================ FILE: mmagic/evaluation/functional/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .fid_inception import InceptionV3 from .gaussian_funcs import gauss_gradient from .inception_utils import (disable_gpu_fuser_on_pt19, load_inception, prepare_inception_feat, prepare_vgg_feat) __all__ = [ 'gauss_gradient', 'InceptionV3', 'disable_gpu_fuser_on_pt19', 'load_inception', 'prepare_vgg_feat', 'prepare_inception_feat' ] ================================================ FILE: mmagic/evaluation/functional/fid_inception.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Inception networks used in calculating FID and Inception metrics. This code is modified from: https://github.com/rosinality/stylegan2-pytorch/blob/master/inception.py """ import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.model_zoo import load_url from torchvision import models # Inception weights ported to PyTorch from # https://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz FID_WEIGHTS_URL = 'https://github.com/mseitzer/pytorch-fid/releases/download/fid_weights/pt_inception-2015-12-05-6726825d.pth' # noqa: E501 class InceptionV3(nn.Module): """Pretrained InceptionV3 network returning feature maps.""" # Index of default block of inception to return, # corresponds to output of final average pooling DEFAULT_BLOCK_INDEX = 3 # Maps feature dimensionality to their output blocks indices BLOCK_INDEX_BY_DIM = { 64: 0, # First max pooling features 192: 1, # Second max pooling features 768: 2, # Pre-aux classifier features 2048: 3 # Final average pooling features } def __init__(self, output_blocks=[DEFAULT_BLOCK_INDEX], resize_input=True, normalize_input=True, requires_grad=False, use_fid_inception=True, load_fid_inception=True): """Build pretrained InceptionV3. Args: output_blocks (list[int]): Indices of blocks to return features of. Possible values are: - 0: corresponds to output of first max pooling - 1: corresponds to output of second max pooling - 2: corresponds to output which is fed to aux classifier - 3: corresponds to output of final average pooling resize_input (bool): If true, bilinearly resizes input to width and height 299 before feeding input to model. As the network without fully connected layers is fully convolutional, it should be able to handle inputs of arbitrary size, so resizing might not be strictly needed. normalize_input (bool): If true, scales the input from range (0, 1) to the range the pretrained Inception network expects, namely (-1, 1). requires_grad (bool): If true, parameters of the model require gradients. Possibly useful for finetuning the network. use_fid_inception (bool): If true, uses the pretrained Inception model used in Tensorflow's FID implementation. If false, uses the pretrained Inception model available in torchvision. The FID Inception model has different weights and a slightly different structure from torchvision's Inception model. If you want to compute FID scores, you are strongly advised to set this parameter to true to get comparable results. """ super().__init__() self.resize_input = resize_input self.normalize_input = normalize_input self.output_blocks = sorted(output_blocks) self.last_needed_block = max(output_blocks) assert self.last_needed_block <= 3, \ 'Last possible output block index is 3' self.blocks = nn.ModuleList() if use_fid_inception: inception = fid_inception_v3(load_fid_inception) else: inception = models.inception_v3(pretrained=True) # Block 0: input to maxpool1 block0 = [ inception.Conv2d_1a_3x3, inception.Conv2d_2a_3x3, inception.Conv2d_2b_3x3, nn.MaxPool2d(kernel_size=3, stride=2) ] self.blocks.append(nn.Sequential(*block0)) # Block 1: maxpool1 to maxpool2 if self.last_needed_block >= 1: block1 = [ inception.Conv2d_3b_1x1, inception.Conv2d_4a_3x3, nn.MaxPool2d(kernel_size=3, stride=2) ] self.blocks.append(nn.Sequential(*block1)) # Block 2: maxpool2 to aux classifier if self.last_needed_block >= 2: block2 = [ inception.Mixed_5b, inception.Mixed_5c, inception.Mixed_5d, inception.Mixed_6a, inception.Mixed_6b, inception.Mixed_6c, inception.Mixed_6d, inception.Mixed_6e, ] self.blocks.append(nn.Sequential(*block2)) # Block 3: aux classifier to final avgpool if self.last_needed_block >= 3: block3 = [ inception.Mixed_7a, inception.Mixed_7b, inception.Mixed_7c, nn.AdaptiveAvgPool2d(output_size=(1, 1)) ] self.blocks.append(nn.Sequential(*block3)) for param in self.parameters(): param.requires_grad = requires_grad def forward(self, inp): """Get Inception feature maps. Args: inp (torch.Tensor): Input tensor of shape Bx3xHxW. Values are expected to be in range (0, 1) Returns: list(torch.Tensor): Corresponding to the selected output \ block, sorted ascending by index. """ outp = [] x = inp if self.resize_input: x = F.interpolate( x, size=(299, 299), mode='bilinear', align_corners=False) if self.normalize_input: x = 2 * x - 1 # Scale from range (0, 1) to range (-1, 1) for idx, block in enumerate(self.blocks): x = block(x) if idx in self.output_blocks: outp.append(x) if idx == self.last_needed_block: break return outp def fid_inception_v3(load_ckpt=True): """Build pretrained Inception model for FID computation. The Inception model for FID computation uses a different set of weights and has a slightly different structure than torchvision's Inception. This method first constructs torchvision's Inception and then patches the necessary parts that are different in the FID Inception model. """ inception = models.inception_v3( num_classes=1008, aux_logits=False, pretrained=False) inception.Mixed_5b = FIDInceptionA(192, pool_features=32) inception.Mixed_5c = FIDInceptionA(256, pool_features=64) inception.Mixed_5d = FIDInceptionA(288, pool_features=64) inception.Mixed_6b = FIDInceptionC(768, channels_7x7=128) inception.Mixed_6c = FIDInceptionC(768, channels_7x7=160) inception.Mixed_6d = FIDInceptionC(768, channels_7x7=160) inception.Mixed_6e = FIDInceptionC(768, channels_7x7=192) inception.Mixed_7b = FIDInceptionE_1(1280) inception.Mixed_7c = FIDInceptionE_2(2048) if load_ckpt: state_dict = load_url(FID_WEIGHTS_URL, progress=True) inception.load_state_dict(state_dict) return inception class FIDInceptionA(models.inception.InceptionA): """InceptionA block patched for FID computation.""" def __init__(self, in_channels, pool_features): super().__init__(in_channels, pool_features) def forward(self, x): """Get InceptionA feature maps. Args: x (torch.Tensor): Input tensor of shape BxCxHxW. Returns: torch.Tensor: Feature Maps of x outputted by this block. """ branch1x1 = self.branch1x1(x) branch5x5 = self.branch5x5_1(x) branch5x5 = self.branch5x5_2(branch5x5) branch3x3dbl = self.branch3x3dbl_1(x) branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl) # Patch: Tensorflow's average pool does not use the padded zero's in # its average calculation branch_pool = F.avg_pool2d( x, kernel_size=3, stride=1, padding=1, count_include_pad=False) branch_pool = self.branch_pool(branch_pool) outputs = [branch1x1, branch5x5, branch3x3dbl, branch_pool] return torch.cat(outputs, 1) class FIDInceptionC(models.inception.InceptionC): """InceptionC block patched for FID computation.""" def __init__(self, in_channels, channels_7x7): super().__init__(in_channels, channels_7x7) def forward(self, x): """Get InceptionC feature maps. Args: x (torch.Tensor): Input tensor of shape BxCxHxW. Returns: torch.Tensor: Feature Maps of x outputted by this block. """ branch1x1 = self.branch1x1(x) branch7x7 = self.branch7x7_1(x) branch7x7 = self.branch7x7_2(branch7x7) branch7x7 = self.branch7x7_3(branch7x7) branch7x7dbl = self.branch7x7dbl_1(x) branch7x7dbl = self.branch7x7dbl_2(branch7x7dbl) branch7x7dbl = self.branch7x7dbl_3(branch7x7dbl) branch7x7dbl = self.branch7x7dbl_4(branch7x7dbl) branch7x7dbl = self.branch7x7dbl_5(branch7x7dbl) # Patch: Tensorflow's average pool does not use the padded zero's in # its average calculation branch_pool = F.avg_pool2d( x, kernel_size=3, stride=1, padding=1, count_include_pad=False) branch_pool = self.branch_pool(branch_pool) outputs = [branch1x1, branch7x7, branch7x7dbl, branch_pool] return torch.cat(outputs, 1) class FIDInceptionE_1(models.inception.InceptionE): """First InceptionE block patched for FID computation.""" def __init__(self, in_channels): super().__init__(in_channels) def forward(self, x): """Get first InceptionE feature maps. Args: x (torch.Tensor): Input tensor of shape BxCxHxW. Returns: torch.Tensor: Feature Maps of x outputted by this block. """ branch1x1 = self.branch1x1(x) branch3x3 = self.branch3x3_1(x) branch3x3 = [ self.branch3x3_2a(branch3x3), self.branch3x3_2b(branch3x3), ] branch3x3 = torch.cat(branch3x3, 1) branch3x3dbl = self.branch3x3dbl_1(x) branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) branch3x3dbl = [ self.branch3x3dbl_3a(branch3x3dbl), self.branch3x3dbl_3b(branch3x3dbl), ] branch3x3dbl = torch.cat(branch3x3dbl, 1) # Patch: Tensorflow's average pool does not use the padded zero's in # its average calculation branch_pool = F.avg_pool2d( x, kernel_size=3, stride=1, padding=1, count_include_pad=False) branch_pool = self.branch_pool(branch_pool) outputs = [branch1x1, branch3x3, branch3x3dbl, branch_pool] return torch.cat(outputs, 1) class FIDInceptionE_2(models.inception.InceptionE): """Second InceptionE block patched for FID computation.""" def __init__(self, in_channels): super().__init__(in_channels) def forward(self, x): """Get second InceptionE feature maps. Args: x (torch.Tensor): Input tensor of shape BxCxHxW. Returns: torch.Tensor: Feature Maps of x outputted by this block. """ branch1x1 = self.branch1x1(x) branch3x3 = self.branch3x3_1(x) branch3x3 = [ self.branch3x3_2a(branch3x3), self.branch3x3_2b(branch3x3), ] branch3x3 = torch.cat(branch3x3, 1) branch3x3dbl = self.branch3x3dbl_1(x) branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) branch3x3dbl = [ self.branch3x3dbl_3a(branch3x3dbl), self.branch3x3dbl_3b(branch3x3dbl), ] branch3x3dbl = torch.cat(branch3x3dbl, 1) # Patch: The FID Inception model uses max pooling instead of average # pooling. This is likely an error in this specific Inception # implementation, as other Inception models use average pooling here # (which matches the description in the paper). branch_pool = F.max_pool2d(x, kernel_size=3, stride=1, padding=1) branch_pool = self.branch_pool(branch_pool) outputs = [branch1x1, branch3x3, branch3x3dbl, branch_pool] return torch.cat(outputs, 1) ================================================ FILE: mmagic/evaluation/functional/gaussian_funcs.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import cv2 import numpy as np def gaussian(x, sigma): """Gaussian function. Args: x (array_like): The independent variable. sigma (float): Standard deviation of the gaussian function. Return: np.ndarray or scalar: Gaussian value of `x`. """ return np.exp(-x**2 / (2 * sigma**2)) / (sigma * np.sqrt(2 * np.pi)) def dgaussian(x, sigma): """Gradient of gaussian. Args: x (array_like): The independent variable. sigma (float): Standard deviation of the gaussian function. Return: np.ndarray or scalar: Gradient of gaussian of `x`. """ return -x * gaussian(x, sigma) / sigma**2 def gauss_filter(sigma, epsilon=1e-2): """Gradient of gaussian. Args: sigma (float): Standard deviation of the gaussian kernel. epsilon (float): Small value used when calculating kernel size. Default: 1e-2. Return: filter_x (np.ndarray): Gaussian filter along x axis. filter_y (np.ndarray): Gaussian filter along y axis. """ half_size = np.ceil( sigma * np.sqrt(-2 * np.log(np.sqrt(2 * np.pi) * sigma * epsilon))) size = int(2 * half_size + 1) # create filter in x axis filter_x = np.zeros((size, size)) for i in range(size): for j in range(size): filter_x[i, j] = gaussian(i - half_size, sigma) * dgaussian( j - half_size, sigma) # normalize filter norm = np.sqrt((filter_x**2).sum()) filter_x = filter_x / norm filter_y = np.transpose(filter_x) return filter_x, filter_y def gauss_gradient(img, sigma): """Gaussian gradient. From https://www.mathworks.com/matlabcentral/mlc-downloads/downloads/ submissions/8060/versions/2/previews/gaussgradient/gaussgradient.m/ index.html Args: img (np.ndarray): Input image. sigma (float): Standard deviation of the gaussian kernel. Return: np.ndarray: Gaussian gradient of input `img`. """ filter_x, filter_y = gauss_filter(sigma) img_filtered_x = cv2.filter2D( img, -1, filter_x, borderType=cv2.BORDER_REPLICATE) img_filtered_y = cv2.filter2D( img, -1, filter_y, borderType=cv2.BORDER_REPLICATE) return np.sqrt(img_filtered_x**2 + img_filtered_y**2) ================================================ FILE: mmagic/evaluation/functional/inception_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import hashlib import os import os.path as osp import pickle import sys from contextlib import contextmanager from copy import deepcopy from typing import Optional, Tuple import mmengine import numpy as np import torch import torch.nn as nn from mmengine import is_filepath, print_log from mmengine.dataset import BaseDataset, Compose, pseudo_collate from mmengine.dist import (all_gather, get_dist_info, get_world_size, is_main_process) from mmengine.evaluator import BaseMetric from torch.utils.data.dataloader import DataLoader from torch.utils.data.dataset import Dataset from torchvision.models.inception import inception_v3 from mmagic.utils import MMAGIC_CACHE_DIR, download_from_url from . import InceptionV3 ALLOWED_INCEPTION = ['StyleGAN', 'PyTorch'] TERO_INCEPTION_URL = 'https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt' # noqa @contextmanager def disable_gpu_fuser_on_pt19(): """On PyTorch 1.9 a CUDA fuser bug prevents the Inception JIT model to run. Refers to: https://github.com/GaParmar/clean-fid/blob/5e1e84cdea9654b9ac7189306dfa4057ea2213d8/cleanfid/inception_torchscript.py#L9 # noqa https://github.com/GaParmar/clean-fid/issues/5 https://github.com/pytorch/pytorch/issues/64062 """ if torch.__version__.startswith('1.9.'): old_val = torch._C._jit_can_fuse_on_gpu() torch._C._jit_override_can_fuse_on_gpu(False) yield if torch.__version__.startswith('1.9.'): torch._C._jit_override_can_fuse_on_gpu(old_val) def load_inception(inception_args, metric): """Load Inception Model from given ``inception_args`` and ``metric``. This function would try to load Inception under the guidance of 'type' given in `inception_args`, if not given, we would try best to load Tero's ones. In detail, we would first try to load the model from disk with the given 'inception_path', and then try to download the checkpoint from 'inception_url'. If both method are failed, pytorch version of Inception would be loaded. Args: inception_args (dict): Keyword args for inception net. metric (string): Metric to use the Inception. This argument would influence the pytorch's Inception loading. Returns: model (torch.nn.Module): Loaded Inception model. style (string): The version of the loaded Inception. """ if not isinstance(inception_args, dict): raise TypeError('Receive invalid \'inception_args\': ' f'\'{inception_args}\'') _inception_args = deepcopy(inception_args) inception_type = _inception_args.pop('type', None) if torch.__version__ < '1.6.0': print_log( 'Current Pytorch Version not support script module, load ' 'Inception Model from torch model zoo. If you want to use ' 'Tero\' script model, please update your Pytorch higher ' f'than \'1.6\' (now is {torch.__version__})', 'current') return _load_inception_torch(_inception_args, metric), 'pytorch' # load pytorch version is specific if inception_type != 'StyleGAN': return _load_inception_torch(_inception_args, metric), 'pytorch' # try to load Tero's version path = _inception_args.get('inception_path', TERO_INCEPTION_URL) if path is None: path = TERO_INCEPTION_URL # try to parse `path` as web url and download if 'http' not in path: model = _load_inception_from_path(path) if isinstance(model, torch.nn.Module): return model, 'StyleGAN' # try to parse `path` as path on disk model = _load_inception_from_url(path) if isinstance(model, torch.nn.Module): return model, 'StyleGAN' raise RuntimeError('Cannot Load Inception Model, please check the input ' f'`inception_args`: {inception_args}') def _load_inception_from_path(inception_path): """Load inception from passed path. Args: inception_path (str): The path of inception. Returns: nn.Module: The loaded inception. """ print_log( 'Try to load Tero\'s Inception Model from ' f'\'{inception_path}\'.', 'current') try: model = torch.jit.load(inception_path) print_log('Load Tero\'s Inception Model successfully.', 'current') except Exception as e: model = None print_log('Load Tero\'s Inception Model failed. ' f'\'{e}\' occurs.', 'current') return model def _load_inception_from_url(inception_url: str) -> nn.Module: """Load Inception network from the give `inception_url`""" inception_url = inception_url if inception_url else TERO_INCEPTION_URL print_log(f'Try to download Inception Model from {inception_url}...', 'current') try: path = download_from_url(inception_url, dest_dir=MMAGIC_CACHE_DIR) print_log('Download Finished.', 'current') return _load_inception_from_path(path) except Exception as e: print_log(f'Download Failed. {e} occurs.', 'current') return None def _load_inception_torch(inception_args, metric) -> nn.Module: """Load Inception network from PyTorch's model zoo.""" assert metric in ['FID', 'IS'] if metric == 'FID': inception_model = InceptionV3([3], **inception_args) elif metric == 'IS': inception_model = inception_v3(pretrained=True, transform_input=False) print_log( 'Load Inception V3 Network from Pytorch Model Zoo ' 'for IS calculation. The results can only used ' 'for monitoring purposes. To get more accuracy IS, ' 'please use Tero\'s Inception V3 checkpoints ' 'and use Bicubic Interpolation with Pillow backend ' 'for image resizing. More details may refer to ' 'https://github.com/open-mmlab/MMEditing/blob/master/docs/en/quick_run.md#is.', # noqa 'current') return inception_model def get_inception_feat_cache_name_and_args(dataloader: DataLoader, metric: BaseMetric, real_nums: int, capture_mean_cov: bool, capture_all: bool ) -> Tuple[str, dict]: """Get the name and meta info of the inception feature cache file corresponding to the input dataloader and metric. The meta info includes 'data_root', 'data_prefix', 'meta_info' and 'pipeline' of the dataset, and 'inception_style' and 'inception_args' of the metric. Then we calculate the hash value of the meta info dict with md5, and the name of the inception feature cache will be 'inception_feat_{HASH}.pkl'. Args: dataloader (Dataloader): The dataloader of real images. metric (BaseMetric): The metric which needs inception features. real_nums (int): Number of images used to extract inception feature. capture_mean_cov (bool): Whether save the mean and covariance of inception feature. Defaults to False. capture_all (bool): Whether save the raw inception feature. Defaults to False. Returns: Tuple[str, dict]: Filename and meta info dict of the inception feature cache. """ dataset: BaseDataset = dataloader.dataset assert isinstance(dataset, Dataset), ( f'Only support normal dataset, but receive {type(dataset)}.') # get dataset info data_root = deepcopy(dataset.data_root) data_prefix = deepcopy(dataset.data_prefix) metainfo = dataset.metainfo pipeline = repr(dataset.pipeline) # get metric info inception_style = metric.inception_style inception_args = getattr(metric, 'inception_args', None) real_key = 'gt_img' if metric.real_key is None else metric.real_key args = dict( data_root=data_root, data_prefix=data_prefix, metainfo=metainfo, pipeline=pipeline, inception_style=inception_style, inception_args=inception_args, # save `num_gpus` because this may influence the data loading order num_gpus=get_world_size(), capture_mean_cov=capture_mean_cov, capture_all=capture_all, real_keys=real_key, real_nums=real_nums) real_nums_str = 'full' if real_nums == -1 else str(real_nums) md5 = hashlib.md5(repr(sorted(args.items())).encode('utf-8')) if capture_all: prefix = 'inception_state-capture_all' elif capture_mean_cov: prefix = 'inception_state-capture_mean_cov' else: prefix = 'inception_state-capture_all_mean_cov' cache_tag = f'{prefix}-{real_nums_str}-{md5.hexdigest()}.pkl' return cache_tag, args def get_vgg_feat_cache_name_and_args(dataloader: DataLoader, metric: BaseMetric) -> Tuple[str, dict]: """Get the name and meta info of the vgg feature cache file corresponding to the input dataloader and metric. The meta info includes 'data_root', 'data_prefix', 'meta_info' and 'pipeline' of the dataset, and 'use_tero_scirpt' of the metric. Then we calculate the hash value of the meta info dict with md5, and the name of the vgg feature cache will be 'vgg_feat_{HASH}.pkl'. Args: dataloader (Dataloader): The dataloader of real images. metric (BaseMetric): The metric which needs inception features. Returns: Tuple[str, dict]: Filename and meta info dict of the inception feature cache. """ dataset: BaseDataset = dataloader.dataset assert isinstance(dataset, Dataset), ( f'Only support normal dataset, but receive {type(dataset)}.') # get dataset info data_root = deepcopy(dataset.data_root) data_prefix = deepcopy(dataset.data_prefix) metainfo = dataset.metainfo pipeline = dataset.pipeline if isinstance(pipeline, Compose): pipeline_str = repr(pipeline) else: pipeline_str = '' # get metric info use_tero_scirpt = metric.use_tero_scirpt args = dict( data_root=data_root, data_prefix=data_prefix, metainfo=metainfo, pipeline=pipeline_str, use_tero_scirpt=use_tero_scirpt) md5 = hashlib.md5(repr(sorted(args.items())).encode('utf-8')) cache_tag = f'vgg_state-{md5.hexdigest()}.pkl' return cache_tag, args def prepare_inception_feat(dataloader: DataLoader, metric: BaseMetric, data_preprocessor: Optional[nn.Module] = None, capture_mean_cov: bool = False, capture_all: bool = False) -> dict: """Prepare inception feature for the input metric. - If `metric.inception_pkl` is an online path, try to download and load it. If cannot download or load, corresponding error will be raised. - If `metric.inception_pkl` is local path and file exists, try to load the file. If cannot load, corresponding error will be raised. - If `metric.inception_pkl` is local path and file not exists, we will extract the inception feature manually and save to 'inception_pkl'. - If `metric.inception_pkl` is not defined, we will extract the inception feature and save it to default cache dir with default name. Args: dataloader (Dataloader): The dataloader of real images. metric (BaseMetric): The metric which needs inception features. data_preprocessor (Optional[nn.Module]): Data preprocessor of the module. Used to preprocess the real images. If not passed, real images will automatically normalized to [-1, 1]. Defaults to None. capture_mean_cov (bool): Whether save the mean and covariance of inception feature. Defaults to False. capture_all (bool): Whether save the raw inception feature. If true, it will take a lot of time to save the inception feature. Defaults to False. Returns: dict: Dict contains inception feature. """ assert capture_mean_cov or capture_all, ( 'At least one of \'capture_mean_cov\' and \'capture_all\' is True.') if not hasattr(metric, 'inception_pkl'): return inception_pkl: Optional[str] = metric.inception_pkl if isinstance(inception_pkl, str): if is_filepath(inception_pkl) and osp.exists(inception_pkl): with open(inception_pkl, 'rb') as file: inception_state = pickle.load(file) print_log( f'\'{metric.prefix}\' successful load inception feature ' f'from \'{inception_pkl}\'', 'current') return inception_state elif inception_pkl.startswith('s3'): try: raise NotImplementedError( 'Not support download from Ceph currently') except Exception as exp: raise exp('Not support download from Ceph currently') elif inception_pkl.startswith('http'): try: raise NotImplementedError( 'Not support download from url currently') except Exception as exp: # cannot download, raise error raise exp('Not support download from url currently') # cannot load or download from file, extract manually assert hasattr(metric, 'real_nums'), ( f'Metric \'{metric.name}\' must have attribute \'real_nums\'.') real_nums = metric.real_nums if inception_pkl is None: inception_pkl, args = get_inception_feat_cache_name_and_args( dataloader, metric, real_nums, capture_mean_cov, capture_all) inception_pkl = osp.join(MMAGIC_CACHE_DIR, inception_pkl) else: args = dict() if osp.exists(inception_pkl): with open(inception_pkl, 'rb') as file: real_feat = pickle.load(file) print_log(f'load preprocessed feat from {inception_pkl}', 'current') return real_feat assert hasattr(metric, 'inception'), ( 'Metric must have a inception network to extract inception features.') real_feat = [] print_log( f'Inception pkl \'{inception_pkl}\' is not found, extract ' 'manually.', 'current') import rich.progress dataset, batch_size = dataloader.dataset, dataloader.batch_size if real_nums == -1: num_items = len(dataset) else: num_items = min(len(dataset), real_nums) rank, num_gpus = get_dist_info() item_subset = [(i * num_gpus + rank) % num_items for i in range((num_items - 1) // num_gpus + 1)] inception_dataloader = DataLoader( dataset, batch_size=batch_size, sampler=item_subset, collate_fn=pseudo_collate, shuffle=False, drop_last=False) # init rich pbar for the main process if is_main_process(): # check the launcher slurm_env_name = ['SLURM_PROCID', 'SLURM_NTASKS', 'SLURM_NODELIST'] if all([n in os.environ for n in slurm_env_name]): is_slurm = True pbar = mmengine.ProgressBar(len(inception_dataloader)) else: is_slurm = False columns = [ rich.progress.TextColumn('[bold blue]{task.description}'), rich.progress.BarColumn(bar_width=40), rich.progress.TaskProgressColumn(), rich.progress.TimeRemainingColumn(), ] pbar = rich.progress.Progress(*columns) pbar.start() task = pbar.add_task( 'Calculate Inception Feature.', total=len(inception_dataloader), visible=True) for data in inception_dataloader: # set training = False to avoid norm + convert to BGR data_samples = data_preprocessor(data, False)['data_samples'] real_key = 'gt_img' if metric.real_key is None else metric.real_key img = getattr(data_samples, real_key) real_feat_ = metric.forward_inception(img).cpu() real_feat.append(real_feat_) if is_main_process(): if is_slurm: pbar.update(1) else: pbar.update(task, advance=1) # stop the pbar if is_main_process(): if is_slurm: sys.stdout.write('\n') else: pbar.stop() # collect results real_feat = torch.cat(real_feat) # use `all_gather` here, gather tensor is much quicker than gather object. real_feat = all_gather(real_feat) # only cat on the main process if is_main_process(): inception_state = dict(**args) if capture_mean_cov: real_feat = torch.cat(real_feat, dim=0)[:num_items].numpy() real_mean = np.mean(real_feat, 0) real_cov = np.cov(real_feat, rowvar=False) inception_state['real_mean'] = real_mean inception_state['real_cov'] = real_cov if capture_all: inception_state['raw_feature'] = real_feat dir_name = osp.dirname(inception_pkl) os.makedirs(dir_name, exist_ok=True) print_log( f'Saving inception pkl to {inception_pkl}. Please be patient.', 'current') with open(inception_pkl, 'wb') as file: pickle.dump(inception_state, file) print_log('Inception pkl Finished.', 'current') return inception_state def prepare_vgg_feat(dataloader: DataLoader, metric: BaseMetric, data_preprocessor: Optional[nn.Module] = None, auto_save=True) -> np.ndarray: """Prepare vgg feature for the input metric. - If `metric.vgg_pkl` is an online path, try to download and load it. If cannot download or load, corresponding error will be raised. - If `metric.vgg_pkl` is local path and file exists, try to load the file. If cannot load, corresponding error will be raised. - If `metric.vgg_pkl` is local path and file not exists, we will extract the vgg feature manually and save to 'vgg_pkl'. - If `metric.vgg_pkl` is not defined, we will extract the vgg feature and save it to default cache dir with default name. Args: dataloader (Dataloader): The dataloader of real images. metric (BaseMetric): The metric which needs vgg features. data_preprocessor (Optional[nn.Module]): Data preprocessor of the module. Used to preprocess the real images. If not passed, real images will automatically normalized to [-1, 1]. Defaults to None. Returns: np.ndarray: Loaded vgg feature. """ if not hasattr(metric, 'vgg16_pkl'): return vgg_pkl: Optional[str] = metric.vgg16_pkl if isinstance(vgg_pkl, str): if is_filepath(vgg_pkl) and osp.exists(vgg_pkl): with open(vgg_pkl, 'rb') as file: vgg_state = pickle.load(file) print_log( f'\'{metric.prefix}\' successful load VGG feature ' f'from \'{vgg_pkl}\'', 'current') return vgg_state['vgg_feat'] elif vgg_pkl.startswith('s3'): try: raise NotImplementedError( 'Not support download from Ceph currently') except Exception as exp: raise exp('Not support download from Ceph currently') elif vgg_pkl.startswith('http'): try: raise NotImplementedError( 'Not support download from url currently') except Exception as exp: # cannot download, raise error raise exp('Not support download from url currently') # cannot load or download from file, extract manually if vgg_pkl is None: vgg_pkl, args = get_vgg_feat_cache_name_and_args(dataloader, metric) vgg_pkl = osp.join(MMAGIC_CACHE_DIR, vgg_pkl) else: args = dict() if osp.exists(vgg_pkl): with open(vgg_pkl, 'rb') as file: real_feat = pickle.load(file)['vgg_feat'] print(f'load preprocessed feat from {vgg_pkl}') return real_feat assert hasattr( metric, 'vgg16'), ('Metric must have a vgg16 network to extract vgg features.') real_feat = [] print_log(f'Vgg pkl \'{vgg_pkl}\' is not found, extract ' 'manually.', 'current') import rich.progress # init rich pbar for the main process if is_main_process(): columns = [ rich.progress.TextColumn('[bold blue]{task.description}'), rich.progress.BarColumn(bar_width=40), rich.progress.TaskProgressColumn(), rich.progress.TimeRemainingColumn(), ] pbar = rich.progress.Progress(*columns) pbar.start() task = pbar.add_task( 'Calculate VGG16 Feature.', total=len(dataloader.dataset), visible=True) for data in dataloader: # set training = False to avoid norm + convert to BGR data_samples = data_preprocessor(data, False)['data_samples'] real_key = 'gt_img' if metric.real_key is None else metric.real_key img = getattr(data_samples, real_key) real_feat_ = metric.extract_features(img) real_feat.append(real_feat_) if is_main_process(): pbar.update(task, advance=len(real_feat_) * get_world_size()) # stop the pbar if is_main_process(): pbar.stop() # collect results real_feat = torch.cat(real_feat) # use `all_gather` here, gather tensor is much quicker than gather object. real_feat = all_gather(real_feat) # only cat on the main process if is_main_process(): real_feat = torch.cat(real_feat, dim=0)[:len(dataloader.dataset)].cpu() if auto_save: vgg_state = dict(vgg_feat=real_feat, **args) with open(vgg_pkl, 'wb') as file: pickle.dump(vgg_state, file) return real_feat ================================================ FILE: mmagic/evaluation/metrics/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .connectivity_error import ConnectivityError from .equivariance import Equivariance from .fid import FrechetInceptionDistance, TransFID from .gradient_error import GradientError from .inception_score import InceptionScore, TransIS from .mae import MAE from .matting_mse import MattingMSE from .ms_ssim import MultiScaleStructureSimilarity from .mse import MSE from .niqe import NIQE, niqe from .ppl import PerceptualPathLength from .precision_and_recall import PrecisionAndRecall from .psnr import PSNR, psnr from .sad import SAD from .snr import SNR, snr from .ssim import SSIM, ssim from .swd import SlicedWassersteinDistance __all__ = [ 'MAE', 'MSE', 'PSNR', 'psnr', 'SNR', 'snr', 'SSIM', 'ssim', 'MultiScaleStructureSimilarity', 'FrechetInceptionDistance', 'TransFID', 'InceptionScore', 'TransIS', 'SAD', 'MattingMSE', 'ConnectivityError', 'GradientError', 'PerceptualPathLength', 'PrecisionAndRecall', 'SlicedWassersteinDistance', 'NIQE', 'niqe', 'Equivariance', ] ================================================ FILE: mmagic/evaluation/metrics/base_gen_metric.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import warnings from typing import Any, Iterator, List, Optional import numpy as np import torch import torch.nn as nn from mmengine import is_list_of, print_log from mmengine.dataset import pseudo_collate from mmengine.dist import (all_gather, broadcast_object_list, collect_results, get_dist_info, get_world_size, is_main_process) from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch import Tensor from torch.utils.data.dataloader import DataLoader from mmagic.structures import DataSample class GenMetric(BaseMetric): """Metric for MMagic. Args: fake_nums (int): Numbers of the generated image need for the metric. real_nums (int): Numbers of the real image need for the metric. If `-1` is passed means all images from the dataset is need. Defaults to 0. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. real_key (Optional[str]): Key for get real images from the input dict. Defaults to 'img'. sample_model (str): Sampling model for the generative model. Support 'orig' and 'ema'. Defaults to 'ema'. collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ SAMPLER_MODE = 'normal' def __init__(self, fake_nums: int, real_nums: int = 0, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None) -> None: super().__init__(collect_device, prefix) self.sample_model = sample_model self.fake_nums = fake_nums self.real_nums = real_nums self.real_key = real_key self.fake_key = fake_key self.real_results: List[Any] = [] self.fake_results: List[Any] = [] @property def real_nums_per_device(self): """Number of real images need for current device.""" return math.ceil(self.real_nums / get_world_size()) @property def fake_nums_per_device(self): """Number of fake images need for current device.""" return math.ceil(self.fake_nums / get_world_size()) def _collect_target_results(self, target: str) -> Optional[list]: """Collected results in distributed environments. Args: target (str): Target results to collect. Returns: Optional[list]: The collected results. """ assert target in [ 'fake', 'real' ], ('Only support to collect \'fake\' or \'real\' results.') results = getattr(self, f'{target}_results') size = getattr(self, f'{target}_nums') size = len(results) * get_world_size() if size == -1 else size if len(results) == 0: warnings.warn( f'{self.__class__.__name__} got empty `self.{target}_results`.' ' Please ensure that the processed results are properly added ' f'into `self.{target}_results` in `process` method.') if is_list_of(results, Tensor): # apply all_gather for tensor results results = torch.cat(results, dim=0) results = torch.cat(all_gather(results), dim=0)[:size] results = torch.split(results, 1) else: # apply collect_results (all_gather_object) for non-tensor results results = collect_results(results, size, self.collect_device) # on non-main process, results should be `None` if is_main_process() and len(results) != size: raise ValueError(f'Length of results is \'{len(results)}\', not ' f'equals to target size \'{size}\'.') return results def evaluate(self) -> dict: """Evaluate the model performance of the whole dataset after processing all batches. Different like :class:`~mmengine.evaluator.BaseMetric`, this function evaluate the metric with paired results (`results_fake` and `results_real`). Returns: dict: Evaluation metrics dict on the val dataset. The keys are the names of the metrics, and the values are corresponding results. """ results_fake = self._collect_target_results(target='fake') results_real = self._collect_target_results(target='real') if is_main_process(): # pack to list, align with BaseMetrics _metrics = self.compute_metrics(results_fake, results_real) # Add prefix to metric names if self.prefix: _metrics = { '/'.join((self.prefix, k)): v for k, v in _metrics.items() } metrics = [_metrics] else: metrics = [None] # type: ignore broadcast_object_list(metrics) # reset the results list self.real_results.clear() self.fake_results.clear() return metrics[0] def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: List['GenMetric']) -> DataLoader: """Get sampler for normal metrics. Directly returns the dataloader. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. metrics (List['GenMetric']): Metrics with the same sample mode. Returns: DataLoader: Default sampler for normal metrics. """ batch_size = dataloader.batch_size dataset_length = len(dataloader.dataset) rank, num_gpus = get_dist_info() assert self.real_nums <= dataset_length, ( f'\'real_nums\'({self.real_nums}) can not larger than length of ' f'dataset ({dataset_length}).') nums = dataset_length if self.real_nums == -1 else self.real_nums item_subset = [(i * num_gpus + rank) % nums for i in range((nums - 1) // num_gpus + 1)] metric_dataloader = DataLoader( dataloader.dataset, batch_size=batch_size, sampler=item_subset, collate_fn=pseudo_collate, shuffle=False, drop_last=False) return metric_dataloader def compute_metrics(self, results_fake, results_real) -> dict: """Compute the metrics from processed results. Args: results (list): The processed results of each batch. Returns: dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: """Prepare for the pre-calculating items of the metric. Defaults to do nothing. Args: module (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for the real images. """ if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor class GenerativeMetric(GenMetric): """Metric for generative metrics. Except for the preparation phase (:meth:`prepare`), generative metrics do not need extra real images. Args: fake_nums (int): Numbers of the generated image need for the metric. real_nums (int): Numbers of the real image need for the metric. If `-1` is passed means all images from the dataset is need. Defaults to 0. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. real_key (Optional[str]): Key for get real images from the input dict. Defaults to 'img'. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'ema'. collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. sample_kwargs(dict): Sampling arguments for model test. """ SAMPLER_MODE = 'Generative' def __init__(self, fake_nums: int, real_nums: int = 0, fake_key: Optional[str] = None, real_key: Optional[str] = 'img', need_cond_input: bool = False, sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None, sample_kwargs: dict = dict()): super().__init__(fake_nums, real_nums, fake_key, real_key, sample_model, collect_device, prefix) self.need_cond_input = need_cond_input self.sample_kwargs = sample_kwargs if self.need_cond_input: print_log('Set \'need_cond_input\' as True, this may influence ' 'the evaluation results of conditional models.') def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: GenMetric): """Get sampler for generative metrics. Returns a dummy iterator, whose return value of each iteration is a dict containing batch size and sample mode to generate images. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. Used to get batch size during generate fake images. metrics (List['GenMetric']): Metrics with the same sampler mode. Returns: :class:`dummy_iterator`: Sampler for generative metrics. """ batch_size = dataloader.batch_size dataset = dataloader.dataset sample_model = metrics[0].sample_model assert all([metric.sample_model == sample_model for metric in metrics ]), ('\'sample_model\' between metrics is inconsistency.') class dummy_iterator: def __init__(self, batch_size, max_length, sample_model, dataset, need_cond, sample_kwargs) -> None: self.batch_size = batch_size self.max_length = max_length self.sample_model = sample_model self.dataset = dataset self.need_cond = need_cond self.sample_kwargs = sample_kwargs def __iter__(self) -> Iterator: self.idx = 0 return self def __len__(self) -> int: return math.ceil(self.max_length / self.batch_size) def get_cond(self) -> List[DataSample]: data_sample_list = [] for _ in range(self.batch_size): data_sample = DataSample() cond = self.dataset.get_data_info( np.random.randint(len(self.dataset)))['gt_label'] data_sample.set_gt_label(torch.Tensor(cond)) data_sample_list.append(data_sample) return data_sample_list def __next__(self) -> dict: if self.idx > self.max_length: raise StopIteration self.idx += batch_size output_dict = dict( inputs=dict( sample_model=self.sample_model, num_batches=self.batch_size, sample_kwargs=self.sample_kwargs)) if self.need_cond: output_dict['data_samples'] = self.get_cond() return output_dict return dummy_iterator( batch_size=batch_size, max_length=max([metric.fake_nums_per_device for metric in metrics]), sample_model=sample_model, dataset=dataset, need_cond=self.need_cond_input, sample_kwargs=self.sample_kwargs) def evaluate(self) -> dict(): """Evaluate generative metric. In this function we only collect :attr:`fake_results` because generative metrics do not need real images. Returns: dict: Evaluation metrics dict on the val dataset. The keys are the names of the metrics, and the values are corresponding results. """ results_fake = self._collect_target_results(target='fake') if is_main_process(): # pack to list, align with BaseMetrics _metrics = self.compute_metrics(results_fake) # Add prefix to metric names if self.prefix: _metrics = { '/'.join((self.prefix, k)): v for k, v in _metrics.items() } metrics = [_metrics] else: metrics = [None] # type: ignore broadcast_object_list(metrics) # reset the results list self.fake_results.clear() return metrics[0] def compute_metrics(self, results) -> dict: """Compute the metrics from processed results. Args: results (list): The processed results of each batch. Returns: dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ ================================================ FILE: mmagic/evaluation/metrics/base_sample_wise_metric.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Evaluation metrics based on each sample.""" from typing import List, Optional, Sequence import torch.nn as nn from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from .metrics_utils import average, obtain_data @METRICS.register_module() class BaseSampleWiseMetric(BaseMetric): """Base sample wise metric of edit. Subclass must provide process function. Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' mask_key (str, optional): Key of mask, if mask_key is None, calculate all regions. Default: None collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. device (str): Device used to place torch tensors to compute metrics. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None scaling (float, optional): Scaling factor for final metric. E.g. scaling=100 means the final metric will be amplified by 100 for output. Default: 1 """ SAMPLER_MODE = 'normal' sample_model = 'orig' # TODO: low-level models only support origin model metric = None # the name of metric def __init__(self, gt_key: str = 'gt_img', pred_key: str = 'pred_img', mask_key: Optional[str] = None, scaling=1, device='cpu', collect_device: str = 'cpu', prefix: Optional[str] = None) -> None: assert self.metric is not None, ( '\'metric\' must be defined for \'BaseSampleWiseMetric\'.') super().__init__(collect_device, prefix) self.gt_key = gt_key self.pred_key = pred_key self.mask_key = mask_key self.scaling = scaling self.device = device self.channel_order = 'BGR' def compute_metrics(self, results: List): """Compute the metrics from processed results. Args: results (List): The processed results of each batch. Returns: Dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ result = average(results, self.metric) * self.scaling return {self.metric: result} def process(self, data_batch: Sequence[dict], data_samples: Sequence[dict]) -> None: """Process one batch of data and predictions. Args: data_batch (Sequence[dict]): A batch of data from the dataloader. predictions (Sequence[dict]): A batch of outputs from the model. """ for data in data_samples: prediction = data['output'] gt = obtain_data(data, self.gt_key, self.device) pred = obtain_data(prediction, self.pred_key, self.device) if self.mask_key is not None: mask = obtain_data(data, self.mask_key) mask[mask != 0] = 1 else: mask = 1 - pred * 0 if len(gt.shape) <= 3: result = self.process_image(gt, pred, mask) else: result_sum = 0 for i in range(gt.shape[0]): result_sum += self.process_image(gt[i], pred[i], mask[i]) result = result_sum / gt.shape[0] self.results.append({self.metric: result}) def process_image(self, gt, pred, mask): raise NotImplementedError def evaluate(self) -> dict: assert hasattr(self, 'size'), ( 'Cannot find \'size\', please make sure \'self.prepare\' is ' 'called correctly.') return super().evaluate(self.size) def prepare(self, module: nn.Module, dataloader: DataLoader): self.size = len(dataloader.dataset) if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics) -> DataLoader: """Get sampler for normal metrics. Directly returns the dataloader. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. metrics (List['GenMetric']): Metrics with the same sample mode. Returns: DataLoader: Default sampler for normal metrics. """ return dataloader ================================================ FILE: mmagic/evaluation/metrics/connectivity_error.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Evaluation metrics used in Image Matting.""" from typing import List, Sequence import cv2 import numpy as np import torch.nn as nn from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() class ConnectivityError(BaseSampleWiseMetric): """Connectivity error for evaluating alpha matte prediction. .. note:: Current implementation assume image / alpha / trimap array in numpy format and with pixel value ranging from 0 to 255. .. note:: pred_alpha should be masked by trimap before passing into this metric Args: step (float): Step of threshold when computing intersection between `alpha` and `pred_alpha`. Default to 0.1 . norm_const (int): Divide the result to reduce its magnitude. Default to 1000. Default prefix: '' Metrics: - ConnectivityError (float): Connectivity Error """ metric = 'ConnectivityError' def __init__( self, step=0.1, norm_constant=1000, **kwargs, ) -> None: self.step = step self.norm_constant = norm_constant super().__init__(**kwargs) def prepare(self, module: nn.Module, dataloader: DataLoader): self.size = len(dataloader.dataset) if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor def process(self, data_batch: Sequence[dict], data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (Sequence[dict]): A batch of data from the dataloader. predictions (Sequence[dict]): A batch of outputs from the model. """ for data_sample in data_samples: pred_alpha, gt_alpha, trimap = _fetch_data_and_check(data_sample) thresh_steps = np.arange(0, 1 + self.step, self.step) round_down_map = -np.ones_like(gt_alpha) for i in range(1, len(thresh_steps)): gt_alpha_thresh = gt_alpha >= thresh_steps[i] pred_alpha_thresh = pred_alpha >= thresh_steps[i] intersection = gt_alpha_thresh & pred_alpha_thresh intersection = intersection.astype(np.uint8) # connected components _, output, stats, _ = cv2.connectedComponentsWithStats( intersection, connectivity=4) # start from 1 in dim 0 to exclude background size = stats[1:, -1] # largest connected component of the intersection omega = np.zeros_like(gt_alpha) if len(size) != 0: max_id = np.argmax(size) # plus one to include background omega[output == max_id + 1] = 1 mask = (round_down_map == -1) & (omega == 0) round_down_map[mask] = thresh_steps[i - 1] round_down_map[round_down_map == -1] = 1 gt_alpha_diff = gt_alpha - round_down_map pred_alpha_diff = pred_alpha - round_down_map # only calculate difference larger than or equal to 0.15 gt_alpha_phi = 1 - gt_alpha_diff * (gt_alpha_diff >= 0.15) pred_alpha_phi = 1 - pred_alpha_diff * (pred_alpha_diff >= 0.15) connectivity_error = np.sum( np.abs(gt_alpha_phi - pred_alpha_phi) * (trimap == 128)) # divide by 1000 to reduce the magnitude of the result connectivity_error /= self.norm_constant self.results.append({'conn_err': connectivity_error}) def compute_metrics(self, results: List): """Compute the metrics from processed results. Args: results (dict): The processed results of each batch. Returns: Dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ conn_err = average(results, 'conn_err') return {'ConnectivityError': conn_err} ================================================ FILE: mmagic/evaluation/metrics/equivariance.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from collections import defaultdict from copy import deepcopy from typing import Iterator, List, Optional, Sequence import numpy as np import torch import torch.nn as nn from mmengine.dist import all_gather from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from .base_gen_metric import GenerativeMetric @METRICS.register_module('EQ') @METRICS.register_module() class Equivariance(GenerativeMetric): name = 'Equivariance' def __init__(self, fake_nums: int, real_nums: int = 0, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', need_cond_input: bool = False, sample_mode: str = 'ema', sample_kwargs: dict = dict(), collect_device: str = 'cpu', prefix: Optional[str] = None, eq_cfg=dict()): super().__init__(fake_nums, real_nums, fake_key, real_key, need_cond_input, sample_mode, collect_device, prefix) # set default sampler config self._eq_cfg = deepcopy(eq_cfg) self._eq_cfg.setdefault('compute_eqt_int', False) self._eq_cfg.setdefault('compute_eqt_frac', False) self._eq_cfg.setdefault('compute_eqr', False) self._eq_cfg.setdefault('translate_max', 0.125) self._eq_cfg.setdefault('rotate_max', 1) self.SAMPLER_MODE = 'EqSampler' self.sample_kwargs = sample_kwargs # compute numbers of eq self.n_sub_metric = 0 if self._eq_cfg['compute_eqt_int']: self.n_sub_metric += 1 if self._eq_cfg['compute_eqt_frac']: self.n_sub_metric += 1 if self._eq_cfg['compute_eqr']: self.n_sub_metric += 1 self.fake_results = defaultdict(list) @torch.no_grad() def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ cfg_key_list = ['compute_eqt_int', 'compute_eqt_frac', 'compute_eqr'] sample_key_list = ['eqt_int', 'eqt_frac', 'eqr'] for pred in data_samples: for cfg_key, sample_key in zip(cfg_key_list, sample_key_list): if self._eq_cfg[cfg_key]: assert sample_key in pred # assert hasattr(pred, sample_key) eq_sample = pred[sample_key] diff = eq_sample['diff'].to(torch.float64).sum() mask = eq_sample['mask'].to(torch.float64).sum() self.fake_results[sample_key] += [diff, mask] def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: List[GenerativeMetric]): """Get sampler for generative metrics. Returns a dummy iterator, whose return value of each iteration is a dict containing batch size and sample mode to generate images. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. Used to get batch size during generate fake images. metrics (List['GenerativeMetric']): Metrics with the same sampler mode. Returns: :class:`dummy_iterator`: Sampler for generative metrics. """ batch_size = dataloader.batch_size sample_model = metrics[0].sample_model assert all([metric.sample_model == sample_model for metric in metrics ]), ('\'sample_model\' between metrics is inconsistency.') return eq_iterator( batch_size=batch_size, max_length=max([metric.fake_nums_per_device for metric in metrics]), sample_mode=sample_model, eq_cfg=self._eq_cfg, sample_kwargs=self.sample_kwargs) def compute_metrics(self, results) -> dict: """Compute the metrics from processed results. Args: results (list): The processed results of each batch. Returns: dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ results = dict() for key in ['eqt_int', 'eqt_frac', 'eqr']: if key not in self.fake_results: continue sums = torch.stack(self.fake_results[key], dim=0) mses = (sums[0::2] / sums[1::2]).mean() psnrs = np.log10(2) * 20 - mses.log10() * 10 psnrs = psnrs.cpu().numpy() results[key] = psnrs return results def _collect_target_results(self, target: str) -> Optional[list]: """Collect function for Eq metric. This function support collect results typing as Dict[List[Tensor]]`. Args: target (str): Target results to collect. Returns: Optional[list]: The collected results. """ if target == 'real': return results = getattr(self, f'{target}_results') results_collected = [] results_collected = dict() for key, result in results.items(): result_collected = torch.stack(result) result_collected = torch.cat(all_gather(result_collected), dim=0) results_collected[key] = torch.split(result_collected, len(result_collected)) return results_collected class eq_iterator: def __init__(self, batch_size, max_length, sample_mode, eq_cfg, sample_kwargs) -> None: self.batch_size = batch_size self.max_length = max_length self.sample_mode = sample_mode self.eq_cfg = deepcopy(eq_cfg) self.sample_kwargs = sample_kwargs def __iter__(self) -> Iterator: self.idx = 0 return self def __len__(self) -> int: return self.max_length // self.batch_size def __next__(self) -> dict: if self.idx >= self.max_length: raise StopIteration self.idx += self.batch_size mode = dict( sample_mode=self.sample_mode, eq_cfg=self.eq_cfg, sample_kwargs=self.sample_kwargs) # StyleGAN3 forward will receive eq config from mode return dict(inputs=dict(mode=mode, num_batches=self.batch_size)) ================================================ FILE: mmagic/evaluation/metrics/fid.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Sequence, Tuple import numpy as np import torch import torch.nn as nn from mmengine.dist import is_main_process from scipy import linalg from torch import Tensor from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from ..functional import (disable_gpu_fuser_on_pt19, load_inception, prepare_inception_feat) from .base_gen_metric import GenerativeMetric @METRICS.register_module('FID-Full') @METRICS.register_module('FID') @METRICS.register_module() class FrechetInceptionDistance(GenerativeMetric): """FID metric. In this metric, we calculate the distance between real distributions and fake distributions. The distributions are modeled by the real samples and fake samples, respectively. `Inception_v3` is adopted as the feature extractor, which is widely used in StyleGAN and BigGAN. Args: fake_nums (int): Numbers of the generated image need for the metric. real_nums (int): Numbers of the real images need for the metric. If -1 is passed, means all real images in the dataset will be used. Defaults to -1. inception_style (str): The target inception style want to load. If the given style cannot be loaded successful, will attempt to load a valid one. Defaults to 'StyleGAN'. inception_path (str, optional): Path the the pretrain Inception network. Defaults to None. inception_pkl (str, optional): Path to reference inception pickle file. If `None`, the statistical value of real distribution will be calculated at running time. Defaults to None. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. real_key (Optional[str]): Key for get real images from the input dict. Defaults to 'img'. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'orig'. collect_device (str, optional): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ name = 'FID' def __init__(self, fake_nums: int, real_nums: int = -1, inception_style='StyleGAN', inception_path: Optional[str] = None, inception_pkl: Optional[str] = None, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', need_cond_input: bool = False, sample_model: str = 'orig', collect_device: str = 'cpu', prefix: Optional[str] = None, sample_kwargs: dict = dict()): super().__init__(fake_nums, real_nums, fake_key, real_key, need_cond_input, sample_model, collect_device, prefix, sample_kwargs) self.real_mean = None self.real_cov = None self.device = 'cpu' self.inception, self.inception_style = self._load_inception( inception_style, inception_path) self.inception_pkl = inception_pkl def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: """Preparing inception feature for the real images. Args: module (nn.Module): The model to evaluate. dataloader (DataLoader): The dataloader for real images. """ self.device = module.data_preprocessor.device self.inception.to(self.device) self.inception.eval() inception_feat_dict = prepare_inception_feat( dataloader, self, module.data_preprocessor, capture_mean_cov=True) if is_main_process(): self.real_mean = inception_feat_dict['real_mean'] self.real_cov = inception_feat_dict['real_cov'] def _load_inception(self, inception_style: str, inception_path: Optional[str] ) -> Tuple[nn.Module, str]: """Load inception and return the successful loaded style. Args: inception_style (str): Target style of Inception network want to load. inception_path (Optional[str]): The path to the inception. Returns: Tuple[nn.Module, str]: The actually loaded inception network and corresponding style. """ if inception_style == 'StyleGAN': args = dict(type='StyleGAN', inception_path=inception_path) else: args = dict(type='Pytorch', normalize_input=False) inception, style = load_inception(args, 'FID') inception.eval() return inception, style def forward_inception(self, image: Tensor) -> Tensor: """Feed image to inception network and get the output feature. Args: data_samples (Sequence[dict]): A batch of data sample dict used to extract inception feature. Returns: Tensor: Image feature extracted from inception. """ # image must passed with 'bgr' image = image[:, [2, 1, 0]].to(self.device) if self.inception_style == 'StyleGAN': image = image.to(torch.uint8) with disable_gpu_fuser_on_pt19(): feat = self.inception(image, return_features=True) else: image = (image - 127.5) / 127.5 # to [-1, 1] feat = self.inception(image)[0].view(image.shape[0], -1) return feat def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ if len(self.fake_results) >= self.fake_nums_per_device: return fake_imgs = [] for pred in data_samples: fake_img_ = pred # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) # check whether shape in fake_imgs are same img_shape = fake_imgs[0].shape if all([img.shape == img_shape for img in fake_imgs]): # all images have the same shape, forward inception altogether fake_imgs = torch.stack(fake_imgs, dim=0) feat = self.forward_inception(fake_imgs) feat_list = list(torch.split(feat, 1)) else: # images have different shape, forward separately feat_list = [ self.forward_inception(img[None, ...]) for img in fake_imgs ] self.fake_results += feat_list @staticmethod def _calc_fid(sample_mean: np.ndarray, sample_cov: np.ndarray, real_mean: np.ndarray, real_cov: np.ndarray, eps: float = 1e-6) -> Tuple[float]: """Refer to the implementation from: https://github.com/rosinality/stylegan2-pytorch/blob/master/fid.py#L34 """ cov_sqrt, _ = linalg.sqrtm(sample_cov @ real_cov, disp=False) if not np.isfinite(cov_sqrt).all(): print('product of cov matrices is singular') offset = np.eye(sample_cov.shape[0]) * eps cov_sqrt = linalg.sqrtm( (sample_cov + offset) @ (real_cov + offset)) if np.iscomplexobj(cov_sqrt): if not np.allclose(np.diagonal(cov_sqrt).imag, 0, atol=1e-3): m = np.max(np.abs(cov_sqrt.imag)) raise ValueError(f'Imaginary component {m}') cov_sqrt = cov_sqrt.real mean_diff = sample_mean - real_mean mean_norm = mean_diff @ mean_diff trace = np.trace(sample_cov) + np.trace( real_cov) - 2 * np.trace(cov_sqrt) fid = mean_norm + trace return float(fid), float(mean_norm), float(trace) def compute_metrics(self, fake_results: list) -> dict: """Compute the result of FID metric. Args: fake_results (list): List of image feature of fake images. Returns: dict: A dict of the computed FID metric and its mean and covariance. """ fake_feats = torch.cat(fake_results, dim=0) fake_feats_np = fake_feats.cpu().numpy() fake_mean = np.mean(fake_feats_np, 0) fake_cov = np.cov(fake_feats_np, rowvar=False) fid, mean, cov = self._calc_fid(fake_mean, fake_cov, self.real_mean, self.real_cov) return {'fid': fid, 'mean': mean, 'cov': cov} @METRICS.register_module() class TransFID(FrechetInceptionDistance): def __init__(self, fake_nums: int, real_nums: int = -1, inception_style='StyleGAN', inception_path: Optional[str] = None, inception_pkl: Optional[str] = None, fake_key: Optional[str] = None, real_key: Optional[str] = 'img', sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None): # NOTE: set `need_cond` as False since we direct return the original # dataloader as sampler super().__init__(fake_nums, real_nums, inception_style, inception_path, inception_pkl, fake_key, real_key, False, sample_model, collect_device, prefix) self.SAMPLER_MODE = 'normal' def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: List['GenerativeMetric']) -> DataLoader: """Get sampler for normal metrics. Directly returns the dataloader. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. metrics (List['GenMetric']): Metrics with the same sample mode. Returns: DataLoader: Default sampler for normal metrics. """ return dataloader ================================================ FILE: mmagic/evaluation/metrics/gradient_error.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Sequence import cv2 import numpy as np import torch.nn as nn from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from ..functional import gauss_gradient from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() class GradientError(BaseSampleWiseMetric): """Gradient error for evaluating alpha matte prediction. .. note:: Current implementation assume image / alpha / trimap array in numpy format and with pixel value ranging from 0 to 255. .. note:: pred_alpha should be masked by trimap before passing into this metric Args: sigma (float): Standard deviation of the gaussian kernel. Defaults to 1.4 . norm_const (int): Divide the result to reduce its magnitude. Defaults to 1000 . Default prefix: '' Metrics: - GradientError (float): Gradient Error """ metric = 'GradientError' def __init__( self, sigma=1.4, norm_constant=1000, **kwargs, ) -> None: self.sigma = sigma self.norm_constant = norm_constant super().__init__(**kwargs) def prepare(self, module: nn.Module, dataloader: DataLoader): self.size = len(dataloader.dataset) if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor def process(self, data_batch: Sequence[dict], data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (Sequence[dict]): A batch of data from the dataloader. predictions (Sequence[dict]): A batch of outputs from the model. """ for data_sample in data_samples: pred_alpha, gt_alpha, trimap = _fetch_data_and_check(data_sample) gt_alpha_normed = np.zeros_like(gt_alpha) pred_alpha_normed = np.zeros_like(pred_alpha) cv2.normalize(gt_alpha, gt_alpha_normed, 1.0, 0.0, cv2.NORM_MINMAX) cv2.normalize(pred_alpha, pred_alpha_normed, 1.0, 0.0, cv2.NORM_MINMAX) gt_alpha_grad = gauss_gradient(gt_alpha_normed, self.sigma) pred_alpha_grad = gauss_gradient(pred_alpha_normed, self.sigma) # this is the sum over n samples grad_loss = ((gt_alpha_grad - pred_alpha_grad)**2 * (trimap == 128)).sum() # divide by 1000 to reduce the magnitude of the result grad_loss /= self.norm_constant self.results.append({'grad_err': grad_loss}) def compute_metrics(self, results: List): """Compute the metrics from processed results. Args: results (dict): The processed results of each batch. Returns: Dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ grad_err = average(results, 'grad_err') return {'GradientError': grad_err} ================================================ FILE: mmagic/evaluation/metrics/inception_score.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Sequence, Tuple import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from PIL import Image from scipy.stats import entropy from torch import Tensor from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS # from .inception_utils import disable_gpu_fuser_on_pt19, load_inception from ..functional import disable_gpu_fuser_on_pt19, load_inception from .base_gen_metric import GenerativeMetric @METRICS.register_module('IS') @METRICS.register_module() class InceptionScore(GenerativeMetric): """IS (Inception Score) metric. The images are split into groups, and the inception score is calculated on each group of images, then the mean and standard deviation of the score is reported. The calculation of the inception score on a group of images involves first using the inception v3 model to calculate the conditional probability for each image (p(y|x)). The marginal probability is then calculated as the average of the conditional probabilities for the images in the group (p(y)). The KL divergence is then calculated for each image as the conditional probability multiplied by the log of the conditional probability minus the log of the marginal probability. The KL divergence is then summed over all images and averaged over all classes and the exponent of the result is calculated to give the final score. Ref: https://github.com/sbarratt/inception-score-pytorch/blob/master/inception_score.py # noqa Note that we highly recommend that users should download the Inception V3 script module from the following address. Then, the `inception_pkl` can be set with user's local path. If not given, we will use the Inception V3 from pytorch model zoo. However, this may bring significant different in the final results. Tero's Inception V3: https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt # noqa Args: fake_nums (int): Numbers of the generated image need for the metric. resize (bool, optional): Whether resize image to 299x299. Defaults to True. splits (int, optional): The number of groups. Defaults to 10. inception_style (str): The target inception style want to load. If the given style cannot be loaded successful, will attempt to load a valid one. Defaults to 'StyleGAN'. inception_path (str, optional): Path the the pretrain Inception network. Defaults to None. resize_method (str): Resize method. If `resize` is False, this will be ignored. Defaults to 'bicubic'. use_pil_resize (bool): Whether use Bicubic interpolation with Pillow's backend. If set as True, the evaluation process may be a little bit slow, but achieve a more accurate IS result. Defaults to False. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'orig'. collect_device (str, optional): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ name = 'IS' pil_resize_method_mapping = { 'bicubic': Image.BICUBIC, 'bilinear': Image.BILINEAR, 'nearest': Image.NEAREST, 'box': Image.BOX } def __init__(self, fake_nums: int = 5e4, resize: bool = True, splits: int = 10, inception_style: str = 'StyleGAN', inception_path: Optional[str] = None, resize_method='bicubic', use_pillow_resize: bool = True, fake_key: Optional[str] = None, need_cond_input: bool = False, sample_model='orig', collect_device: str = 'cpu', prefix: str = None): super().__init__(fake_nums, 0, fake_key, None, need_cond_input, sample_model, collect_device, prefix) self.resize = resize self.splits = splits self.device = 'cpu' if not use_pillow_resize: print_log( 'We strongly recommend to use the bicubic resize with ' 'Pillow backend. Otherwise, the results maybe ' 'unreliable', 'current') self.use_pillow_resize = use_pillow_resize if self.use_pillow_resize: allowed_resize_method = list(self.pil_resize_method_mapping.keys()) assert resize_method in self.pil_resize_method_mapping, ( f'\'resize_method\' (\'{resize_method}\') is not supported ' 'for PIL resize. Please select resize method in ' f'{allowed_resize_method}.') self.resize_method = self.pil_resize_method_mapping[resize_method] else: self.resize_method = resize_method self.inception, self.inception_style = self._load_inception( inception_style, inception_path) def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: """Prepare for the pre-calculating items of the metric. Defaults to do nothing. Args: module (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for the real images. """ self.device = module.data_preprocessor.device self.inception.to(self.device) def _load_inception(self, inception_style: str, inception_path: Optional[str] ) -> Tuple[nn.Module, str]: """Load pretrain model of inception network. Args: inception_style (str): Target style of Inception network want to load. inception_path (Optional[str]): The path to the inception. Returns: Tuple[nn.Module, str]: The actually loaded inception network and corresponding style. """ inception, style = load_inception( dict(type=inception_style, inception_path=inception_path), 'IS') inception.eval() return inception, style def _preprocess(self, image: Tensor) -> Tensor: """Preprocess image before pass to the Inception. Preprocess operations contain channel conversion and resize. Args: image (Tensor): Image tensor before preprocess. Returns: Tensor: Image tensor after resize and channel conversion (if need.) """ # image must passed in 'bgr' image = image[:, [2, 1, 0]] if not self.resize: return image if self.use_pillow_resize: image = image.to(torch.uint8) x_np = [x_.permute(1, 2, 0).detach().cpu().numpy() for x_ in image] # use bicubic resize as default x_pil = [ Image.fromarray(x_).resize((299, 299), resample=self.resize_method) for x_ in x_np ] x_ten = torch.cat( [torch.FloatTensor(np.array(x_)[None, ...]) for x_ in x_pil]) return x_ten.permute(0, 3, 1, 2) else: return F.interpolate( image, size=(299, 299), mode=self.resize_method) def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ if len(self.fake_results) >= self.fake_nums_per_device: return fake_imgs = [] for pred in data_samples: fake_img_ = pred # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) fake_imgs = torch.stack(fake_imgs, dim=0) fake_imgs = self._preprocess(fake_imgs).to(self.device) if self.inception_style == 'StyleGAN': fake_imgs = fake_imgs.to(torch.uint8) with disable_gpu_fuser_on_pt19(): feat = self.inception(fake_imgs, no_output_bias=True) else: fake_imgs = (fake_imgs - 127.5) / 127.5 feat = F.softmax(self.inception(fake_imgs), dim=1) # NOTE: feat is shape like (bz, 1000), convert to a list self.fake_results += list(torch.split(feat, 1)) def compute_metrics(self, fake_results: list) -> dict: """Compute the results of Inception Score metric. Args: fake_results (list): List of image feature of fake images. Returns: dict: A dict of the computed IS metric and its standard error """ split_scores = [] preds = torch.cat(fake_results, dim=0).cpu().numpy() # check for the size assert preds.shape[0] >= self.fake_nums preds = preds[:self.fake_nums] for k in range(self.splits): part = preds[k * (self.fake_nums // self.splits):(k + 1) * (self.fake_nums // self.splits), :] py = np.mean(part, axis=0) scores = [] for i in range(part.shape[0]): pyx = part[i, :] scores.append(entropy(pyx, py)) split_scores.append(np.exp(np.mean(scores))) mean, std = np.mean(split_scores), np.std(split_scores) return {'is': float(mean), 'is_std': float(std)} @METRICS.register_module() class TransIS(InceptionScore): """IS (Inception Score) metric. The images are split into groups, and the inception score is calculated on each group of images, then the mean and standard deviation of the score is reported. The calculation of the inception score on a group of images involves first using the inception v3 model to calculate the conditional probability for each image (p(y|x)). The marginal probability is then calculated as the average of the conditional probabilities for the images in the group (p(y)). The KL divergence is then calculated for each image as the conditional probability multiplied by the log of the conditional probability minus the log of the marginal probability. The KL divergence is then summed over all images and averaged over all classes and the exponent of the result is calculated to give the final score. Ref: https://github.com/sbarratt/inception-score-pytorch/blob/master/inception_score.py # noqa Note that we highly recommend that users should download the Inception V3 script module from the following address. Then, the `inception_pkl` can be set with user's local path. If not given, we will use the Inception V3 from pytorch model zoo. However, this may bring significant different in the final results. Tero's Inception V3: https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt # noqa Args: fake_nums (int): Numbers of the generated image need for the metric. resize (bool, optional): Whether resize image to 299x299. Defaults to True. splits (int, optional): The number of groups. Defaults to 10. inception_style (str): The target inception style want to load. If the given style cannot be loaded successful, will attempt to load a valid one. Defaults to 'StyleGAN'. inception_path (str, optional): Path the the pretrain Inception network. Defaults to None. resize_method (str): Resize method. If `resize` is False, this will be ignored. Defaults to 'bicubic'. use_pil_resize (bool): Whether use Bicubic interpolation with Pillow's backend. If set as True, the evaluation process may be a little bit slow, but achieve a more accurate IS result. Defaults to False. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'ema'. collect_device (str, optional): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ def __init__(self, fake_nums: int = 50000, resize: bool = True, splits: int = 10, inception_style: str = 'StyleGAN', inception_path: Optional[str] = None, resize_method='bicubic', use_pillow_resize: bool = True, fake_key: Optional[str] = None, sample_model='ema', collect_device: str = 'cpu', prefix: str = None): # NOTE: set `need_cond` as False since we direct return the original # dataloader as sampler super().__init__(fake_nums, resize, splits, inception_style, inception_path, resize_method, use_pillow_resize, fake_key, False, sample_model, collect_device, prefix) self.SAMPLER_MODE = 'normal' def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: List['GenerativeMetric']) -> DataLoader: """Get sampler for normal metrics. Directly returns the dataloader. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. metrics (List['GenMetric']): Metrics with the same sample mode. Returns: DataLoader: Default sampler for normal metrics. """ return dataloader ================================================ FILE: mmagic/evaluation/metrics/mae.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Evaluation metrics based on pixels.""" import numpy as np from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric @METRICS.register_module() class MAE(BaseSampleWiseMetric): """Mean Absolute Error metric for image. mean(abs(a-b)) Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' mask_key (str, optional): Key of mask, if mask_key is None, calculate all regions. Default: None collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None Metrics: - MAE (float): Mean of Absolute Error """ metric = 'MAE' def process_image(self, gt, pred, mask): """Process an image. Args: gt (Tensor | np.ndarray): GT image. pred (Tensor | np.ndarray): Pred image. mask (Tensor | np.ndarray): Mask of evaluation. Returns: result (np.ndarray): MAE result. """ gt = gt / 255. pred = pred / 255. diff = gt - pred diff = abs(diff) if self.mask_key is not None: diff *= mask # broadcast for channel dimension scale = np.prod(diff.shape) / np.prod(mask.shape) result = diff.sum() / (mask.sum() * scale + 1e-12) else: result = diff.mean() return result ================================================ FILE: mmagic/evaluation/metrics/matting_mse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Sequence import torch.nn as nn from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() class MattingMSE(BaseSampleWiseMetric): """Mean Squared Error metric for image matting. This metric compute per-pixel squared error average across all pixels. i.e. mean((a-b)^2) / norm_const .. note:: Current implementation assume image / alpha / trimap array in numpy format and with pixel value ranging from 0 to 255. .. note:: pred_alpha should be masked by trimap before passing into this metric Default prefix: '' Args: norm_const (int): Divide the result to reduce its magnitude. Default to 1000. Metrics: - MattingMSE (float): Mean of Squared Error """ default_prefix = '' metric = 'MattingMSE' def __init__( self, norm_const=1000, **kwargs, ) -> None: self.norm_const = norm_const super().__init__(**kwargs) def prepare(self, module: nn.Module, dataloader: DataLoader): self.size = len(dataloader.dataset) if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor def process(self, data_batch: Sequence[dict], data_samples: Sequence[dict]) -> None: """Process one batch of data and predictions. Args: data_batch (Sequence[dict]): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ for data_sample in data_samples: pred_alpha, gt_alpha, trimap = _fetch_data_and_check(data_sample) weight_sum = (trimap == 128).sum() if weight_sum != 0: mse_result = ((pred_alpha - gt_alpha)**2).sum() / weight_sum else: mse_result = 0 self.results.append({'mse': mse_result}) def compute_metrics(self, results: List): """Compute the metrics from processed results. Args: results (dict): The processed results of each batch. Returns: Dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ mse = average(results, 'mse') return {'MattingMSE': mse} ================================================ FILE: mmagic/evaluation/metrics/metrics_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmcv import numpy as np import torch from mmagic.utils import reorder_image def _assert_ndim(input, name, ndim, shape_hint): if input.ndim != ndim: raise ValueError( f'{name} should be of shape {shape_hint}, but got {input.shape}.') def _assert_masked(pred_alpha, trimap): if (pred_alpha[trimap == 0] != 0).any() or (pred_alpha[trimap == 255] != 255).any(): raise ValueError( 'pred_alpha should be masked by trimap before evaluation') def _fetch_data_and_check(data_samples): """Fetch and check data from one item of data_batch and predictions. Args: data_batch (dict): One item of data_batch. predictions (dict): One item of predictions. Returns: pred_alpha (Tensor): Pred_alpha data of predictions. ori_alpha (Tensor): Ori_alpha data of data_batch. ori_trimap (Tensor): Ori_trimap data of data_batch. """ ori_trimap = data_samples['ori_trimap'][0, :, :].cpu().numpy() ori_alpha = data_samples['ori_alpha'][0, :, :].cpu().numpy() pred_alpha = data_samples['output']['pred_alpha'] # 2D tensor pred_alpha = pred_alpha.cpu().numpy() _assert_ndim(ori_trimap, 'trimap', 2, 'HxW') _assert_ndim(ori_alpha, 'gt_alpha', 2, 'HxW') _assert_ndim(pred_alpha, 'pred_alpha', 2, 'HxW') _assert_masked(pred_alpha, ori_trimap) # dtype uint8 -> float64 pred_alpha = pred_alpha / 255.0 ori_alpha = ori_alpha / 255.0 # test shows that using float32 vs float64 differs final results at 1e-4 # speed are comparable, so we choose float64 for accuracy return pred_alpha, ori_alpha, ori_trimap def average(results, key): """Average of key in results(list[dict]). Args: results (list[dict]): A list of dict containing the necessary data. key (str): The key of target data. Returns: result: The average result. """ total = 0 n = 0 for batch_result in results: batch_size = batch_result.get('batch_size', 1) total += batch_result[key] * batch_size n += batch_size return total / n def img_transform(img, crop_border=0, input_order='HWC', convert_to=None, channel_order='rgb'): """Image transform. Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: img (np.ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. channel_order (str): The channel order of image. Default: 'rgb' Returns: float: PSNR result. """ if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are ' '"HWC" and "CHW"') img = reorder_image(img, input_order=input_order) if isinstance(img, torch.Tensor): img = img.numpy() img = img.astype(np.float32) if isinstance(convert_to, str) and convert_to.lower() == 'y': if channel_order.upper() == 'RGB': img = mmcv.rgb2ycbcr(img / 255., y_only=True) * 255. elif channel_order.upper() == 'BGR': img = mmcv.bgr2ycbcr(img / 255., y_only=True) * 255. else: raise ValueError( 'Only support `rgb2y` and `bgr2`, but the channel_order ' f'is {channel_order}') img = np.expand_dims(img, axis=2) elif convert_to is not None: raise ValueError('Wrong color model. Supported values are ' '"Y" and None.') if crop_border != 0: img = img[crop_border:-crop_border, crop_border:-crop_border, ...] return img def obtain_data(data_sample, key, device='cpu'): """Obtain data of key from data_sample and converse data to device. Args: data_sample (dict): A dict of data sample. key (str): The key of data to obtain. device (str): Which device the data will deploy. Default: 'cpu'. Returns: result (Tensor | np.ndarray): The data of key. """ candidates = ['data_samples', key, 'data'] for k in candidates: if k in data_sample: result = data_sample[k] if isinstance(result, dict): return obtain_data(result, key, device) else: if isinstance(result, torch.Tensor): result = result.to(device) return result raise KeyError('Mapping key was not found') ================================================ FILE: mmagic/evaluation/metrics/ms_ssim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import warnings from typing import List, Optional, Sequence import numpy as np import torch from mmengine.dist import all_gather, get_world_size, is_main_process from scipy import signal from mmagic.registry import METRICS from .base_gen_metric import GenerativeMetric def _f_special_gauss(size, sigma): r"""Return a circular symmetric gaussian kernel. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py # noqa Args: size (int): Size of Gaussian kernel. sigma (float): Standard deviation for Gaussian blur kernel. Returns: ndarray: Gaussian kernel. """ radius = size // 2 offset = 0.0 start, stop = -radius, radius + 1 if size % 2 == 0: offset = 0.5 stop -= 1 x, y = np.mgrid[offset + start:stop, offset + start:stop] assert len(x) == size g = np.exp(-((x**2 + y**2) / (2.0 * sigma**2))) return g / g.sum() def _hox_downsample(img): r"""Downsample images with factor equal to 0.5. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py # noqa Args: img (ndarray): Images with order "NHWC". Returns: ndarray: Downsampled images with order "NHWC". """ return (img[:, 0::2, 0::2, :] + img[:, 1::2, 0::2, :] + img[:, 0::2, 1::2, :] + img[:, 1::2, 1::2, :]) * 0.25 def _ssim_for_multi_scale(img1, img2, max_val=255, filter_size=11, filter_sigma=1.5, k1=0.01, k2=0.03): """Calculate SSIM (structural similarity) and contrast sensitivity. Ref: Image quality assessment: From error visibility to structural similarity. The results are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. For three-channel images, SSIM is calculated for each channel and then averaged. This function attempts to match the functionality of ssim_index_new.m by Zhou Wang: http://www.cns.nyu.edu/~lcv/ssim/msssim.zip Args: img1 (ndarray): Images with range [0, 255] and order "NHWC". img2 (ndarray): Images with range [0, 255] and order "NHWC". max_val (int): the dynamic range of the images (i.e., the difference between the maximum the and minimum allowed values). Default to 255. filter_size (int): Size of blur kernel to use (will be reduced for small images). Default to 11. filter_sigma (float): Standard deviation for Gaussian blur kernel (will be reduced for small images). Default to 1.5. k1 (float): Constant used to maintain stability in the SSIM calculation (0.01 in the original paper). Default to 0.01. k2 (float): Constant used to maintain stability in the SSIM calculation (0.03 in the original paper). Default to 0.03. Returns: tuple: Pair containing the mean SSIM and contrast sensitivity between `img1` and `img2`. """ if img1.shape != img2.shape: raise RuntimeError( 'Input images must have the same shape (%s vs. %s).' % (img1.shape, img2.shape)) if img1.ndim != 4: raise RuntimeError('Input images must have four dimensions, not %d' % img1.ndim) img1 = img1.astype(np.float32) img2 = img2.astype(np.float32) _, height, width, _ = img1.shape # Filter size can't be larger than height or width of images. size = min(filter_size, height, width) # Scale down sigma if a smaller filter size is used. sigma = size * filter_sigma / filter_size if filter_size else 0 if filter_size: window = np.reshape(_f_special_gauss(size, sigma), (1, size, size, 1)) mu1 = signal.fftconvolve(img1, window, mode='valid') mu2 = signal.fftconvolve(img2, window, mode='valid') sigma11 = signal.fftconvolve(img1 * img1, window, mode='valid') sigma22 = signal.fftconvolve(img2 * img2, window, mode='valid') sigma12 = signal.fftconvolve(img1 * img2, window, mode='valid') else: # Empty blur kernel so no need to convolve. mu1, mu2 = img1, img2 sigma11 = img1 * img1 sigma22 = img2 * img2 sigma12 = img1 * img2 mu11 = mu1 * mu1 mu22 = mu2 * mu2 mu12 = mu1 * mu2 sigma11 -= mu11 sigma22 -= mu22 sigma12 -= mu12 # Calculate intermediate values used by both ssim and cs_map. c1 = (k1 * max_val)**2 c2 = (k2 * max_val)**2 v1 = 2.0 * sigma12 + c2 v2 = sigma11 + sigma22 + c2 ssim = np.mean((((2.0 * mu12 + c1) * v1) / ((mu11 + mu22 + c1) * v2)), axis=(1, 2, 3)) # Return for each image individually. cs = np.mean(v1 / v2, axis=(1, 2, 3)) return ssim, cs def ms_ssim(img1, img2, max_val=255, filter_size=11, filter_sigma=1.5, k1=0.01, k2=0.03, weights=None, reduce_mean=True) -> np.ndarray: """Calculate MS-SSIM (multi-scale structural similarity). Ref: This function implements Multi-Scale Structural Similarity (MS-SSIM) Image Quality Assessment according to Zhou Wang's paper, "Multi-scale structural similarity for image quality assessment" (2003). Link: https://ece.uwaterloo.ca/~z70wang/publications/msssim.pdf Author's MATLAB implementation: http://www.cns.nyu.edu/~lcv/ssim/msssim.zip PGGAN's implementation: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py Args: img1 (ndarray): Images with range [0, 255] and order "NHWC". img2 (ndarray): Images with range [0, 255] and order "NHWC". max_val (int): the dynamic range of the images (i.e., the difference between the maximum the and minimum allowed values). Default to 255. filter_size (int): Size of blur kernel to use (will be reduced for small images). Default to 11. filter_sigma (float): Standard deviation for Gaussian blur kernel (will be reduced for small images). Default to 1.5. k1 (float): Constant used to maintain stability in the SSIM calculation (0.01 in the original paper). Default to 0.01. k2 (float): Constant used to maintain stability in the SSIM calculation (0.03 in the original paper). Default to 0.03. weights (list): List of weights for each level; if none, use five levels and the weights from the original paper. Default to None. Returns: np.ndarray: MS-SSIM score between `img1` and `img2`. """ if img1.shape != img2.shape: raise RuntimeError( 'Input images must have the same shape (%s vs. %s).' % (img1.shape, img2.shape)) if img1.ndim != 4: raise RuntimeError('Input images must have four dimensions, not %d' % img1.ndim) # Note: default weights don't sum to 1.0 but do match the paper / matlab # code. weights = np.array( weights if weights else [0.0448, 0.2856, 0.3001, 0.2363, 0.1333]) levels = weights.size im1, im2 = [x.astype(np.float32) for x in [img1, img2]] mssim = [] mcs = [] for _ in range(levels): ssim, cs = _ssim_for_multi_scale( im1, im2, max_val=max_val, filter_size=filter_size, filter_sigma=filter_sigma, k1=k1, k2=k2) mssim.append(ssim) mcs.append(cs) im1, im2 = [_hox_downsample(x) for x in [im1, im2]] # Clip to zero. Otherwise we get NaNs. mssim = np.clip(np.asarray(mssim), 0.0, np.inf) mcs = np.clip(np.asarray(mcs), 0.0, np.inf) results = np.prod(mcs[:-1, :]**weights[:-1, np.newaxis], axis=0) * \ (mssim[-1, :]**weights[-1]) if reduce_mean: # Average over images only at the end. results = np.mean(results) return results @METRICS.register_module('MS_SSIM') @METRICS.register_module() class MultiScaleStructureSimilarity(GenerativeMetric): """MS-SSIM (Multi-Scale Structure Similarity) metric. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py # noqa Args: fake_nums (int): Numbers of the generated image need for the metric. fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. real_key (Optional[str]): Key for get real images from the input dict. Defaults to 'img'. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'ema'. collect_device (str, optional): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ name = 'MS-SSIM' def __init__(self, fake_nums: int, fake_key: Optional[str] = None, need_cond_input: bool = False, sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None) -> None: super().__init__(fake_nums, 0, fake_key, None, need_cond_input, sample_model, collect_device, prefix) assert fake_nums % 2 == 0 self.num_pairs = fake_nums // 2 def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Feed data to the metric. Args: data_batch (dict): Real images from dataloader. Do not be used in this metric. data_samples (Sequence[dict]): Generated images. """ if len(self.fake_results) >= (self.fake_nums_per_device // 2): return fake_imgs = [] for pred in data_samples: fake_img_ = pred # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) minibatch = torch.stack(fake_imgs, dim=0) assert minibatch.shape[0] % 2 == 0, 'batch size must be divided by 2.' half1 = minibatch[0::2].cpu().data.numpy().transpose((0, 2, 3, 1)) half2 = minibatch[1::2].cpu().data.numpy().transpose((0, 2, 3, 1)) scores = ms_ssim(half1, half2, reduce_mean=False) self.fake_results += [torch.Tensor([s]) for s in scores.tolist()] def _collect_target_results(self, target: str) -> Optional[list]: """Collected results for MS-SSIM metric. Size of `self.fake_results` in MS-SSIM does not relay on `self.fake_nums` but `self.num_pairs`. Args: target (str): Target results to collect. Returns: Optional[list]: The collected results. """ assert target in 'fake', 'Only support to collect \'fake\' results.' results = getattr(self, f'{target}_results') size = self.num_pairs size = len(results) * get_world_size() if size == -1 else size if len(results) == 0: warnings.warn( f'{self.__class__.__name__} got empty `self.{target}_results`.' ' Please ensure that the processed results are properly added ' f'into `self.{target}_results` in `process` method.') # apply all_gather for tensor results results = torch.cat(results, dim=0) results = torch.cat(all_gather(results), dim=0)[:size] results = torch.split(results, 1) # on non-main process, results should be `None` if is_main_process() and len(results) != size: raise ValueError(f'Length of results is \'{len(results)}\', not ' f'equals to target size \'{size}\'.') return results def compute_metrics(self, results_fake: List): """Computed the result of MS-SSIM. Returns: dict: Calculated MS-SSIM result. """ results = torch.cat(results_fake, dim=0) avg = results.sum() / self.num_pairs return {'avg': round(avg.item(), 4)} ================================================ FILE: mmagic/evaluation/metrics/mse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Evaluation metrics based on pixels.""" from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric @METRICS.register_module() class MSE(BaseSampleWiseMetric): """Mean Squared Error metric for image. mean((a-b)^2) Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' mask_key (str, optional): Key of mask, if mask_key is None, calculate all regions. Default: None collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None Metrics: - MSE (float): Mean of Squared Error """ metric = 'MSE' def process_image(self, gt, pred, mask): """Process an image. Args: gt (Torch | np.ndarray): GT image. pred (Torch | np.ndarray): Pred image. mask (Torch | np.ndarray): Mask of evaluation. Returns: result (np.ndarray): MSE result. """ gt = gt / 255. pred = pred / 255. diff = gt - pred diff *= diff if self.mask_key is not None: diff *= mask result = diff.sum() / mask.sum() else: result = diff.mean() return result ================================================ FILE: mmagic/evaluation/metrics/niqe.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import os from typing import Optional import cv2 import mmcv import numpy as np from scipy.ndimage import convolve from scipy.special import gamma from mmagic.datasets.transforms import MATLABLikeResize from mmagic.registry import METRICS from mmagic.utils import reorder_image, to_numpy from .base_sample_wise_metric import BaseSampleWiseMetric @METRICS.register_module() class NIQE(BaseSampleWiseMetric): """Calculate NIQE (Natural Image Quality Evaluator) metric. Ref: Making a "Completely Blind" Image Quality Analyzer. This implementation could produce almost the same results as the official MATLAB codes: http://live.ece.utexas.edu/research/quality/niqe_release.zip We use the official params estimated from the pristine dataset. We use the recommended block size (96, 96) without overlaps. Args: key (str): Key of image. Default: 'pred_img' is_predicted (bool): If the image is predicted, it will be picked from predictions; otherwise, it will be picked from data_batch. Default: True collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: 'gray'. Metrics: - NIQE (float): Natural Image Quality Evaluator """ metric = 'NIQE' def __init__(self, key: str = 'pred_img', is_predicted: bool = True, collect_device: str = 'cpu', prefix: Optional[str] = None, crop_border=0, input_order='HWC', convert_to='gray') -> None: super().__init__(collect_device=collect_device, prefix=prefix) convert_to = convert_to.lower() assert convert_to in [ 'y', 'gray' ], ('Only support gray image, ' "``convert_to`` should be selected from ['y', 'gray']") self.key = key self.is_predicted = is_predicted self.crop_border = crop_border self.input_order = input_order self.convert_to = convert_to def process_image(self, gt, pred, mask) -> None: """Process an image. Args: gt (np.ndarray): GT image. pred (np.ndarray): Pred image. mask (np.ndarray): Mask of evaluation. Returns: result (np.ndarray): NIQE result. """ result = niqe( img=pred, crop_border=self.crop_border, input_order=self.input_order, convert_to=self.convert_to) return result def estimate_aggd_param(block): """Estimate AGGD (Asymmetric Generalized Gaussian Distribution) parameters. Args: block (np.ndarray): 2D Image block. Returns: tuple: alpha (float), beta_l (float) and beta_r (float) for the AGGD distribution (Estimating the parames in Equation 7 in the paper). """ block = block.flatten() gam = np.arange(0.2, 10.001, 0.001) # len = 9801 gam_reciprocal = np.reciprocal(gam) r_gam = np.square(gamma(gam_reciprocal * 2)) / ( gamma(gam_reciprocal) * gamma(gam_reciprocal * 3)) left_std = np.sqrt(np.mean(block[block < 0]**2)) right_std = np.sqrt(np.mean(block[block > 0]**2)) gammahat = left_std / right_std rhat = (np.mean(np.abs(block)))**2 / np.mean(block**2) rhatnorm = (rhat * (gammahat**3 + 1) * (gammahat + 1)) / ((gammahat**2 + 1)**2) array_position = np.argmin((r_gam - rhatnorm)**2) alpha = gam[array_position] beta_l = left_std * np.sqrt(gamma(1 / alpha) / gamma(3 / alpha)) beta_r = right_std * np.sqrt(gamma(1 / alpha) / gamma(3 / alpha)) return (alpha, beta_l, beta_r) def compute_feature(block): """Compute features. Args: block (np.ndarray): 2D Image block. Returns: feat (List): Features with length of 18. """ feat = [] alpha, beta_l, beta_r = estimate_aggd_param(block) feat.extend([alpha, (beta_l + beta_r) / 2]) # distortions disturb the fairly regular structure of natural images. # This deviation can be captured by analyzing the sample distribution of # the products of pairs of adjacent coefficients computed along # horizontal, vertical and diagonal orientations. shifts = [[0, 1], [1, 0], [1, 1], [1, -1]] for shift in shifts: shifted_block = np.roll(block, shift, axis=(0, 1)) alpha, beta_l, beta_r = estimate_aggd_param(block * shifted_block) mean = (beta_r - beta_l) * (gamma(2 / alpha) / gamma(1 / alpha)) feat.extend([alpha, mean, beta_l, beta_r]) return feat def niqe_core(img, mu_pris_param, cov_pris_param, gaussian_window, block_size_h=96, block_size_w=96): """Calculate NIQE (Natural Image Quality Evaluator) metric. Ref: Making a "Completely Blind" Image Quality Analyzer. This implementation could produce almost the same results as the official MATLAB codes: http://live.ece.utexas.edu/research/quality/niqe_release.zip Note that we do not include block overlap height and width, since they are always 0 in the official implementation. For good performance, it is advisable by the official implementation to divide the distorted image in to the same size patched as used for the construction of multivariate Gaussian model. Args: img (np.ndarray): Input image whose quality needs to be computed. The image must be a gray or Y (of YCbCr) image with shape (h, w). Range [0, 255] with float type. mu_pris_param (np.ndarray): Mean of a pre-defined multivariate Gaussian model calculated on the pristine dataset. cov_pris_param (np.ndarray): Covariance of a pre-defined multivariate Gaussian model calculated on the pristine dataset. gaussian_window (ndarray): A 7x7 Gaussian window used for smoothing the image. block_size_h (int): Height of the blocks in to which image is divided. Default: 96 (the official recommended value). Default: 96. block_size_w (int): Width of the blocks in to which image is divided. Default: 96 (the official recommended value). Default: 96. Returns: np.ndarray: NIQE quality. """ # crop image h, w = img.shape num_block_h = math.floor(h / block_size_h) num_block_w = math.floor(w / block_size_w) img = img[0:num_block_h * block_size_h, 0:num_block_w * block_size_w] distparam = [] # dist param is actually the multiscale features for scale in (1, 2): # perform on two scales (1, 2) mu = convolve(img, gaussian_window, mode='nearest') sigma = np.sqrt( np.abs( convolve(np.square(img), gaussian_window, mode='nearest') - np.square(mu))) # normalize, as in Eq. 1 in the paper img_nomalized = (img - mu) / (sigma + 1) feat = [] for idx_w in range(num_block_w): for idx_h in range(num_block_h): # process each block block = img_nomalized[idx_h * block_size_h // scale:(idx_h + 1) * block_size_h // scale, idx_w * block_size_w // scale:(idx_w + 1) * block_size_w // scale] feat.append(compute_feature(block)) distparam.append(np.array(feat)) # matlab-like bicubic downsample with anti-aliasing if scale == 1: resize = MATLABLikeResize(keys=None, scale=0.5) img = resize._resize(img[:, :, np.newaxis] / 255.)[:, :, 0] * 255. distparam = np.concatenate(distparam, axis=1) # fit a MVG (multivariate Gaussian) model to distorted patch features mu_distparam = np.nanmean(distparam, axis=0) distparam_no_nan = distparam[~np.isnan(distparam).any(axis=1)] cov_distparam = np.cov(distparam_no_nan, rowvar=False) # compute niqe quality, Eq. 10 in the paper invcov_param = np.linalg.pinv((cov_pris_param + cov_distparam) / 2) quality = np.matmul( np.matmul((mu_pris_param - mu_distparam), invcov_param), np.transpose((mu_pris_param - mu_distparam))) return np.squeeze(np.sqrt(quality)) def niqe(img, crop_border, input_order='HWC', convert_to='y'): """Calculate NIQE (Natural Image Quality Evaluator) metric. Ref: Making a "Completely Blind" Image Quality Analyzer. This implementation could produce almost the same results as the official MATLAB codes: http://live.ece.utexas.edu/research/quality/niqe_release.zip We use the official params estimated from the pristine dataset. We use the recommended block size (96, 96) without overlaps. Args: img (np.ndarray): Input image whose quality needs to be computed. The input image must be in range [0, 255] with float/int type. The input_order of image can be 'HW' or 'HWC' or 'CHW'. (BGR order) If the input order is 'HWC' or 'CHW', it will be converted to gray or Y (of YCbCr) image according to the ``convert_to`` argument. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the metric calculation. input_order (str): Whether the input order is 'HW', 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether converted to 'y' (of MATLAB YCbCr) or 'gray'. Default: 'y'. Returns: niqe_result (float): NIQE result. """ # we use the official params estimated from the pristine dataset. niqe_pris_params = np.load( os.path.join(os.path.dirname(__file__), 'niqe_pris_params.npz')) mu_pris_param = niqe_pris_params['mu_pris_param'] cov_pris_param = niqe_pris_params['cov_pris_param'] gaussian_window = niqe_pris_params['gaussian_window'] img = to_numpy(img, np.float32) if input_order != 'HW': img = reorder_image(img, input_order=input_order) if convert_to == 'y': img = mmcv.bgr2ycbcr(img / 255., y_only=True) * 255. elif convert_to == 'gray': img = mmcv.bgr2gray(img / 255., cv2.COLOR_BGR2GRAY) * 255. img = np.squeeze(img) if crop_border != 0: img = img[crop_border:-crop_border, crop_border:-crop_border] # round to follow official implementation img = img.round() niqe_result = niqe_core(img, mu_pris_param, cov_pris_param, gaussian_window) return niqe_result ================================================ FILE: mmagic/evaluation/metrics/ppl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Sequence import lpips import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data.dataloader import DataLoader from mmagic.models.utils import get_module_device, normalize_vecs from mmagic.registry import METRICS from .base_gen_metric import GenerativeMetric def slerp(a, b, percent): """Spherical linear interpolation between two unnormalized vectors. Args: a (Tensor): Tensor with shape [N, C]. b (Tensor): Tensor with shape [N, C]. percent (float|Tensor): A float or tensor with shape broadcastable to the shape of input Tensors. Returns: Tensor: Spherical linear interpolation result with shape [N, C]. """ a = normalize_vecs(a) b = normalize_vecs(b) d = (a * b).sum(-1, keepdim=True) p = percent * torch.acos(d) c = normalize_vecs(b - d * a) d = a * torch.cos(p) + c * torch.sin(p) return normalize_vecs(d) @METRICS.register_module('PPL') @METRICS.register_module() class PerceptualPathLength(GenerativeMetric): r"""Perceptual path length. Measure the difference between consecutive images (their VGG16 embeddings) when interpolating between two random inputs. Drastic changes mean that multiple features have changed together and that they might be entangled. Ref: https://github.com/rosinality/stylegan2-pytorch/blob/master/ppl.py # noqa Args: num_images (int): The number of evaluated generated samples. image_shape (tuple, optional): Image shape in order "CHW". Defaults to None. crop (bool, optional): Whether crop images. Defaults to True. epsilon (float, optional): Epsilon parameter for path sampling. Defaults to 1e-4. space (str, optional): Latent space. Defaults to 'W'. sampling (str, optional): Sampling mode, whether sampling in full path or endpoints. Defaults to 'end'. latent_dim (int, optional): Latent dimension of input noise. Defaults to 512. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. """ SAMPLER_MODE = 'path' def __init__(self, fake_nums: int, real_nums: int = 0, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', need_cond_input: bool = False, sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None, crop=True, epsilon=1e-4, space='W', sampling='end', latent_dim=512): super().__init__(fake_nums, real_nums, fake_key, real_key, need_cond_input, sample_model, collect_device, prefix) self.crop = crop self.epsilon = epsilon self.space = space self.sampling = sampling self.latent_dim = latent_dim @torch.no_grad() def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ fake_imgs = [] for pred in data_samples: fake_img_ = pred # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) fake_imgs = torch.stack(fake_imgs, dim=0) fake_imgs = (fake_imgs - 127.5) / 127.5 # [0, 255] to [-1, 1] feat = self._compute_distance(fake_imgs) feat_list = list(torch.split(feat, 1)) self.fake_results += feat_list @torch.no_grad() def _compute_distance(self, images): """Feed data to the metric. Args: images (Tensor): Input tensor. """ # use minibatch's device type to initialize a lpips calculator if not hasattr(self, 'percept'): self.percept = lpips.LPIPS(net='vgg').to(images.device) # crop and resize images if self.crop: c = images.shape[2] // 8 minibatch = images[:, :, c * 3:c * 7, c * 2:c * 6] factor = minibatch.shape[2] // 256 if factor > 1: minibatch = F.interpolate( minibatch, size=(256, 256), mode='bilinear', align_corners=False) # calculator and store lpips score distance = self.percept(minibatch[::2], minibatch[1::2]).view( minibatch.shape[0] // 2) / ( self.epsilon**2) return distance.to('cpu') @torch.no_grad() def compute_metrics(self, fake_results: list) -> dict: """Summarize the results. Returns: dict | list: Summarized results. """ distances = torch.cat(self.fake_results, dim=0).numpy() lo = np.percentile(distances, 1, interpolation='lower') hi = np.percentile(distances, 99, interpolation='higher') filtered_dist = np.extract( np.logical_and(lo <= distances, distances <= hi), distances) ppl_score = float(filtered_dist.mean()) return {'ppl_score': ppl_score} def get_metric_sampler(self, model: nn.Module, dataloader: DataLoader, metrics: list): """Get sampler for generative metrics. Returns a dummy iterator, whose return value of each iteration is a dict containing batch size and sample mode to generate images. Args: model (nn.Module): Model to evaluate. dataloader (DataLoader): Dataloader for real images. Used to get batch size during generate fake images. metrics (list): Metrics with the same sampler mode. Returns: :class:`dummy_iterator`: Sampler for generative metrics. """ batch_size = dataloader.batch_size sample_model = metrics[0].sample_model assert all([metric.sample_model == sample_model for metric in metrics ]), ('\'sample_model\' between metrics is inconsistency.') class PPLSampler: """StyleGAN series generator's sampling iterator for PPL metric. Args: generator (nn.Module): StyleGAN series' generator. num_images (int): The number of evaluated generated samples. batch_size (int): Batch size of generated images. space (str, optional): Latent space. Defaults to 'W'. sampling (str, optional): Sampling mode, whether sampling in full path or endpoints. Defaults to 'end'. epsilon (float, optional): Epsilon parameter for path sampling. Defaults to 1e-4. latent_dim (int, optional): Latent dimension of input noise. Defaults to 512. """ def __init__(self, generator, num_images, batch_size, space='W', sampling='end', epsilon=1e-4, latent_dim=512): assert space in ['Z', 'W'] assert sampling in ['full', 'end'] n_batch = num_images // batch_size resid = num_images - (n_batch * batch_size) self.batch_sizes = [batch_size] * n_batch + ([resid] if resid > 0 else []) self.device = get_module_device(generator) self.generator = generator.module if hasattr( generator, 'module') else generator self.latent_dim = latent_dim self.space = space self.sampling = sampling self.epsilon = epsilon def __iter__(self): self.idx = 0 return self def __len__(self): return len(self.batch_sizes) @torch.no_grad() def __next__(self): if self.idx >= len(self.batch_sizes): raise StopIteration batch = self.batch_sizes[self.idx] injected_noise = self.generator.make_injected_noise() inputs = torch.randn([batch * 2, self.latent_dim], device=self.device) if self.sampling == 'full': lerp_t = torch.rand(batch, device=self.device) else: lerp_t = torch.zeros(batch, device=self.device) if self.space == 'W': assert hasattr(self.generator, 'style_mapping') latent = self.generator.style_mapping(inputs) latent_t0, latent_t1 = latent[::2], latent[1::2] latent_e0 = torch.lerp(latent_t0, latent_t1, lerp_t[:, None]) latent_e1 = torch.lerp(latent_t0, latent_t1, lerp_t[:, None] + self.epsilon) latent_e = torch.stack([latent_e0, latent_e1], 1).view(*latent.shape) else: latent_t0, latent_t1 = inputs[::2], inputs[1::2] latent_e0 = slerp(latent_t0, latent_t1, lerp_t[:, None]) latent_e1 = slerp(latent_t0, latent_t1, lerp_t[:, None] + self.epsilon) latent_e = torch.stack([latent_e0, latent_e1], 1).view(*inputs.shape) self.idx += 1 return dict( inputs=dict( noise=latent_e, sample_kwargs=dict( injected_noise=injected_noise, input_is_latent=(self.space == 'W')))) ppl_sampler = PPLSampler( model.generator_ema if self.sample_model == 'ema' else model.generator, num_images=max([metric.fake_nums_per_device for metric in metrics]), batch_size=batch_size, space=self.space, sampling=self.sampling, epsilon=self.epsilon, latent_dim=self.latent_dim) return ppl_sampler ================================================ FILE: mmagic/evaluation/metrics/precision_and_recall.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from typing import Optional, Sequence, Tuple import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from torch.utils.data.dataloader import DataLoader from torchvision import models as torchvision_models from mmagic.models.utils import get_module_device from mmagic.registry import METRICS from ..functional import prepare_vgg_feat from .base_gen_metric import GenerativeMetric def compute_pr_distances(row_features, col_features, num_gpus=1, rank=0, col_batch_size=10000): r"""Compute distances between real images and fake images. This function is used for calculate Precision and Recall metric. Refer to:https://github.com/NVlabs/stylegan2-ada-pytorch/blob/main/metrics/precision_recall.py # noqa """ assert 0 <= rank < num_gpus num_cols = col_features.shape[0] num_batches = ((num_cols - 1) // col_batch_size // num_gpus + 1) * num_gpus col_batches = torch.nn.functional.pad(col_features, [0, 0, 0, -num_cols % num_batches ]).chunk(num_batches) dist_batches = [] for col_batch in col_batches[rank::num_gpus]: dist_batch = torch.cdist( row_features.unsqueeze(0), col_batch.unsqueeze(0))[0] for src in range(num_gpus): dist_broadcast = dist_batch.clone() if num_gpus > 1: torch.distributed.broadcast(dist_broadcast, src=src) dist_batches.append(dist_broadcast.cpu() if rank == 0 else None) return torch.cat(dist_batches, dim=1)[:, :num_cols] if rank == 0 else None @METRICS.register_module('PR') @METRICS.register_module() class PrecisionAndRecall(GenerativeMetric): r"""Improved Precision and recall metric. In this metric, we draw real and generated samples respectively, and embed them into a high-dimensional feature space using a pre-trained classifier network. We use these features to estimate the corresponding manifold. We obtain the estimation by calculating pairwise Euclidean distances between all feature vectors in the set and, for each feature vector, construct a hypersphere with radius equal to the distance to its kth nearest neighbor. Together, these hyperspheres define a volume in the feature space that serves as an estimate of the true manifold. Precision is quantified by querying for each generated image whether the image is within the estimated manifold of real images. Symmetrically, recall is calculated by querying for each real image whether the image is within estimated manifold of generated image. Ref: https://github.com/NVlabs/stylegan2-ada-pytorch/blob/main/metrics/precision_recall.py # noqa Note that we highly recommend that users should download the vgg16 script module from the following address. Then, the `vgg16_script` can be set with user's local path. If not given, we will use the vgg16 from pytorch model zoo. However, this may bring significant different in the final results. Tero's vgg16: https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt Args: num_images (int): The number of evaluated generated samples. image_shape (tuple): Image shape in order "CHW". Defaults to None. num_real_need (int | None, optional): The number of real images. Defaults to None. full_dataset (bool, optional): Whether to use full dataset for evaluation. Defaults to False. k (int, optional): Kth nearest parameter. Defaults to 3. bgr2rgb (bool, optional): Whether to change the order of image channel. Defaults to True. vgg16_script (str, optional): Path for the Tero's vgg16 module. Defaults to 'work_dirs/cache/vgg16.pt'. row_batch_size (int, optional): The batch size of row data. Defaults to 10000. col_batch_size (int, optional): The batch size of col data. Defaults to 10000. auto_save (bool, optional): Whether save vgg feature automatically. need_cond_input (bool): If true, the sampler will return the conditional input randomly sampled from the original dataset. This require the dataset implement `get_data_info` and field `gt_label` must be contained in the return value of `get_data_info`. Noted that, for unconditional models, set `need_cond_input` as True may influence the result of evaluation results since the conditional inputs are sampled from the dataset distribution; otherwise will be sampled from the uniform distribution. Defaults to False. """ name = 'PR' def __init__(self, fake_nums, real_nums=-1, k=3, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', need_cond_input: bool = False, sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None, vgg16_script='work_dirs/cache/vgg16.pt', vgg16_pkl=None, row_batch_size=10000, col_batch_size=10000, auto_save=True): super().__init__(fake_nums, real_nums, fake_key, real_key, need_cond_input, sample_model, collect_device, prefix) print_log('loading vgg16 for improved precision and recall...', 'current') self.vgg16_pkl = vgg16_pkl self.vgg16, self.use_tero_scirpt = self._load_vgg(vgg16_script) self.k = k self.auto_save = auto_save self.row_batch_size = row_batch_size self.col_batch_size = col_batch_size def _load_vgg(self, vgg16_script: Optional[str]) -> Tuple[nn.Module, bool]: """Load VGG network from the given path. Args: vgg16_script: The path of script model of VGG network. If None, will load the pytorch version. Returns: Tuple[nn.Module, str]: The actually loaded VGG network and corresponding style. """ if os.path.isfile(vgg16_script): vgg16 = torch.jit.load('work_dirs/cache/vgg16.pt').eval() use_tero_scirpt = True else: print_log( 'Cannot load Tero\'s script module. Use official ' 'vgg16 instead', 'current') vgg16 = torchvision_models.vgg16(pretrained=True).eval() use_tero_scirpt = False return vgg16, use_tero_scirpt @torch.no_grad() def extract_features(self, images: torch.Tensor) -> torch.Tensor: """Extracting image features. Args: images (torch.Tensor): Images tensor. Returns: torch.Tensor: Vgg16 features of input images. """ # image must passed in 'bgr' images = images[:, [2, 1, 0], ...] if self.use_tero_scirpt: images = images.to(torch.uint8) feature = self.vgg16(images, return_features=True) else: images = (images - 127.5) / 127.5 batch = F.interpolate(images, size=(224, 224)) before_fc = self.vgg16.features(batch) before_fc = before_fc.view(-1, 7 * 7 * 512) feature = self.vgg16.classifier[:4](before_fc) return feature @torch.no_grad() def compute_metrics(self, results_fake) -> dict: """compute_metrics. Returns: dict: Summarized results. """ gen_features = torch.cat(results_fake, dim=0).to(self.collect_device) real_features = self.results_real self._result_dict = {} for name, manifold, probes in [ ('precision', real_features, gen_features), ('recall', gen_features, real_features) ]: kth = [] for manifold_batch in manifold.split(self.row_batch_size): distance = compute_pr_distances( row_features=manifold_batch, col_features=manifold, col_batch_size=self.col_batch_size) kth.append( distance.to(torch.float32).kthvalue(self.k + 1).values.to( torch.float16)) kth = torch.cat(kth) pred = [] for probes_batch in probes.split(self.row_batch_size): distance = compute_pr_distances( row_features=probes_batch, col_features=manifold, col_batch_size=self.col_batch_size) pred.append((distance <= kth).any(dim=1)) self._result_dict[name] = float( torch.cat(pred).to(torch.float32).mean()) precision = self._result_dict['precision'] recall = self._result_dict['recall'] self._result_str = f'precision: {precision}, recall:{recall}' return self._result_dict @torch.no_grad() def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ fake_imgs = [] for pred in data_samples: fake_img_ = pred # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) fake_imgs = torch.stack(fake_imgs, dim=0) feat = self.extract_features(fake_imgs) feat_list = list(torch.split(feat, 1)) self.fake_results += feat_list @torch.no_grad() def prepare(self, module: nn.Module, dataloader: DataLoader) -> None: # move to corresponding device device = get_module_device(module) self.vgg16.to(device) vgg_feat = prepare_vgg_feat(dataloader, self, module.data_preprocessor, self.auto_save) if self.real_nums != -1: assert self.real_nums <= vgg_feat.shape[0], ( f'Need \'{self.real_nums}\' of real nums, but only ' f'\'{vgg_feat.shape[0]}\' images be found in the ' 'inception feature.') vgg_feat = vgg_feat[np.random.choice( vgg_feat.shape[0], size=self.real_nums, replace=True)] self.results_real = vgg_feat ================================================ FILE: mmagic/evaluation/metrics/psnr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import numpy as np from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import img_transform @METRICS.register_module() class PSNR(BaseSampleWiseMetric): """Peak Signal-to-Noise Ratio. Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'CHW'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. Metrics: - PSNR (float): Peak Signal-to-Noise Ratio """ metric = 'PSNR' def __init__(self, gt_key: str = 'gt_img', pred_key: str = 'pred_img', collect_device: str = 'cpu', prefix: Optional[str] = None, crop_border=0, input_order='CHW', convert_to=None) -> None: super().__init__( gt_key=gt_key, pred_key=pred_key, mask_key=None, collect_device=collect_device, prefix=prefix) self.crop_border = crop_border self.input_order = input_order self.convert_to = convert_to def process_image(self, gt, pred, mask): """Process an image. Args: gt (Torch | np.ndarray): GT image. pred (Torch | np.ndarray): Pred image. mask (Torch | np.ndarray): Mask of evaluation. Returns: np.ndarray: PSNR result. """ return psnr( img1=gt, img2=pred, crop_border=self.crop_border, input_order=self.input_order, convert_to=self.convert_to, channel_order=self.channel_order) def psnr(img1, img2, crop_border=0, input_order='HWC', convert_to=None, channel_order='rgb'): """Calculate PSNR (Peak Signal-to-Noise Ratio). Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: img1 (ndarray): Images with range [0, 255]. img2 (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. channel_order (str): The channel order of image. Default: 'rgb'. Returns: result (float): PSNR result. """ assert img1.shape == img2.shape, ( f'Image shapes are different: {img1.shape}, {img2.shape}.') img1 = img_transform( img1, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) img2 = img_transform( img2, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) mse_value = ((img1 - img2)**2).mean() if mse_value == 0: result = float('inf') else: result = 20. * np.log10(255. / np.sqrt(mse_value)) return result ================================================ FILE: mmagic/evaluation/metrics/sad.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Sequence import numpy as np import torch.nn as nn from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() class SAD(BaseSampleWiseMetric): """Sum of Absolute Differences metric for image matting. This metric compute per-pixel absolute difference and sum across all pixels. i.e. sum(abs(a-b)) / norm_const .. note:: Current implementation assume image / alpha / trimap array in numpy format and with pixel value ranging from 0 to 255. .. note:: pred_alpha should be masked by trimap before passing into this metric Default prefix: '' Args: norm_const (int): Divide the result to reduce its magnitude. Default to 1000. Metrics: - SAD (float): Sum of Absolute Differences """ default_prefix = '' metric = 'SAD' def __init__( self, norm_const=1000, **kwargs, ) -> None: self.norm_const = norm_const super().__init__(**kwargs) def prepare(self, module: nn.Module, dataloader: DataLoader): self.size = len(dataloader.dataset) if is_model_wrapper(module): module = module.module self.data_preprocessor = module.data_preprocessor def process(self, data_batch: Sequence[dict], data_samples: Sequence[dict]) -> None: """Process one batch of data and predictions. Args: data_batch (Sequence[Tuple[Any, dict]]): A batch of data from the dataloader. predictions (Sequence[dict]): A batch of outputs from the model. """ for data_sample in data_samples: pred_alpha, gt_alpha, _ = _fetch_data_and_check(data_sample) # divide by 1000 to reduce the magnitude of the result sad_sum = np.abs(pred_alpha - gt_alpha).sum() / self.norm_const result = {'sad': sad_sum} self.results.append(result) def compute_metrics(self, results: List): """Compute the metrics from processed results. Args: results (dict): The processed results of each batch. Returns: Dict: The computed metrics. The keys are the names of the metrics, and the values are corresponding results. """ sad = average(results, 'sad') return {'SAD': sad} ================================================ FILE: mmagic/evaluation/metrics/snr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import numpy as np from mmagic.registry import METRICS from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import img_transform @METRICS.register_module() class SNR(BaseSampleWiseMetric): """Signal-to-Noise Ratio. Ref: https://en.wikipedia.org/wiki/Signal-to-noise_ratio Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the SNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'CHW'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. Metrics: - SNR (float): Signal-to-Noise Ratio """ metric = 'SNR' def __init__(self, gt_key: str = 'gt_img', pred_key: str = 'pred_img', collect_device: str = 'cpu', prefix: Optional[str] = None, crop_border=0, input_order='CHW', convert_to=None) -> None: super().__init__( gt_key=gt_key, pred_key=pred_key, mask_key=None, collect_device=collect_device, prefix=prefix) self.crop_border = crop_border self.input_order = input_order self.convert_to = convert_to def process_image(self, gt, pred, mask): """Process an image. Args: gt (Torch | np.ndarray): GT image. pred (Torch | np.ndarray): Pred image. mask (Torch | np.ndarray): Mask of evaluation. Returns: np.ndarray: SNR result. """ return snr( gt=gt, pred=pred, crop_border=self.crop_border, input_order=self.input_order, convert_to=self.convert_to, channel_order=self.channel_order) def snr(gt, pred, crop_border=0, input_order='HWC', convert_to=None, channel_order='rgb'): """Calculate PSNR (Peak Signal-to-Noise Ratio). Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: gt (ndarray): Images with range [0, 255]. pred (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. channel_order (str): The channel order of image. Default: 'rgb'. Returns: float: SNR result. """ assert gt.shape == pred.shape, ( f'Image shapes are different: {gt.shape}, {pred.shape}.') gt = img_transform( gt, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) pred = img_transform( pred, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) signal = ((gt)**2).mean() noise = ((gt - pred)**2).mean() result = 10. * np.log10(signal / noise) return result ================================================ FILE: mmagic/evaluation/metrics/ssim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import cv2 import numpy as np from mmagic.registry import METRICS from mmagic.utils import to_numpy from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import img_transform @METRICS.register_module() class SSIM(BaseSampleWiseMetric): """Calculate SSIM (structural similarity). Ref: Image quality assessment: From error visibility to structural similarity The results are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. For three-channel images, SSIM is calculated for each channel and then averaged. Args: gt_key (str): Key of ground-truth. Default: 'gt_img' pred_key (str): Key of prediction. Default: 'pred_img' collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Default: None crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the PSNR calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. Metrics: - SSIM (float): Structural similarity """ metric = 'SSIM' def __init__(self, gt_key: str = 'gt_img', pred_key: str = 'pred_img', collect_device: str = 'cpu', prefix: Optional[str] = None, crop_border=0, input_order='CHW', convert_to=None) -> None: super().__init__( gt_key=gt_key, pred_key=pred_key, mask_key=None, collect_device=collect_device, prefix=prefix) self.crop_border = crop_border self.input_order = input_order self.convert_to = convert_to def process_image(self, gt, pred, mask): """Process an image. Args: gt (Torch | np.ndarray): GT image. pred (Torch | np.ndarray): Pred image. mask (Torch | np.ndarray): Mask of evaluation. Returns: np.ndarray: SSIM result. """ return ssim( img1=gt, img2=pred, crop_border=self.crop_border, input_order=self.input_order, convert_to=self.convert_to, channel_order=self.channel_order) def _ssim(img1, img2): """Calculate SSIM (structural similarity) for one channel images. It is called by func:`ssim`. Args: img1, img2 (np.ndarray): Images with range [0, 255] with order 'HWC'. Returns: float: SSIM result. """ C1 = (0.01 * 255)**2 C2 = (0.03 * 255)**2 kernel = cv2.getGaussianKernel(11, 1.5) window = np.outer(kernel, kernel.transpose()) mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5] mu1_sq = mu1**2 mu2_sq = mu2**2 mu1_mu2 = mu1 * mu2 sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2 ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) return ssim_map.mean() def ssim(img1, img2, crop_border=0, input_order='HWC', convert_to=None, channel_order='rgb'): """Calculate SSIM (structural similarity). Ref: Image quality assessment: From error visibility to structural similarity The results are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. For three-channel images, SSIM is calculated for each channel and then averaged. Args: img1 (ndarray): Images with range [0, 255]. img2 (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edges of an image. These pixels are not involved in the SSIM calculation. Default: 0. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether to convert the images to other color models. If None, the images are not altered. When computing for 'Y', the images are assumed to be in BGR order. Options are 'Y' and None. Default: None. channel_order (str): The channel order of image. Default: 'rgb' Returns: float: SSIM result. """ assert img1.shape == img2.shape, ( f'Image shapes are different: {img1.shape}, {img2.shape}.') img1 = img_transform( img1, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) img2 = img_transform( img2, crop_border=crop_border, input_order=input_order, convert_to=convert_to, channel_order=channel_order) img1 = to_numpy(img1) img2 = to_numpy(img2) ssims = [] for i in range(img1.shape[2]): ssims.append(_ssim(img1[..., i], img2[..., i])) return np.array(ssims).mean() ================================================ FILE: mmagic/evaluation/metrics/swd.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Sequence import numpy as np import torch import torch.nn.functional as F from mmengine.dist import all_gather, get_world_size from mmagic.registry import METRICS from .base_gen_metric import GenMetric def sliced_wasserstein(distribution_a, distribution_b, dir_repeats=4, dirs_per_repeat=128): r"""sliced Wasserstein distance of two sets of patches. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/ms_ssim.py # noqa Args: distribution_a (Tensor): Descriptors of first distribution. distribution_b (Tensor): Descriptors of second distribution. dir_repeats (int): The number of projection times. Default to 4. dirs_per_repeat (int): The number of directions per projection. Default to 128. Returns: float: sliced Wasserstein distance. """ if torch.cuda.is_available(): distribution_b = distribution_b.cuda() assert distribution_a.ndim == 2 assert distribution_a.shape == distribution_b.shape assert dir_repeats > 0 and dirs_per_repeat > 0 distribution_a = distribution_a.to(distribution_b.device) results = [] for _ in range(dir_repeats): dirs = torch.randn(distribution_a.shape[1], dirs_per_repeat) dirs /= torch.sqrt(torch.sum((dirs**2), dim=0, keepdim=True)) dirs = dirs.to(distribution_b.device) proj_a = torch.matmul(distribution_a, dirs) proj_b = torch.matmul(distribution_b, dirs) # To save cuda memory, we perform sort in cpu proj_a, _ = torch.sort(proj_a.cpu(), dim=0) proj_b, _ = torch.sort(proj_b.cpu(), dim=0) dists = torch.abs(proj_a - proj_b) results.append(torch.mean(dists).item()) torch.cuda.empty_cache() return sum(results) / dir_repeats # Gaussian blur kernel def get_gaussian_kernel(): """Get the gaussian blur kernel. Returns: Tensor: Blur kernel. """ kernel = np.array([[1, 4, 6, 4, 1], [4, 16, 24, 16, 4], [6, 24, 36, 24, 6], [4, 16, 24, 16, 4], [1, 4, 6, 4, 1]], np.float32) / 256.0 gaussian_k = torch.as_tensor(kernel.reshape(1, 1, 5, 5)) return gaussian_k def get_pyramid_layer(image, gaussian_k, direction='down'): """Get the pyramid layer. Args: image (Tensor): Input image. gaussian_k (Tensor): Gaussian kernel direction (str, optional): The direction of pyramid. Defaults to 'down'. Returns: Tensor: The output of the pyramid. """ gaussian_k = gaussian_k.to(image.device) if direction == 'up': image = F.interpolate(image, scale_factor=2) multiband = [ F.conv2d( image[:, i:i + 1, :, :], gaussian_k, padding=2, stride=1 if direction == 'up' else 2) for i in range(3) ] image = torch.cat(multiband, dim=1) return image def gaussian_pyramid(original, n_pyramids, gaussian_k): """Get a group of gaussian pyramid. Args: original (Tensor): The input image. n_pyramids (int): The number of pyramids. gaussian_k (Tensor): The gaussian kernel. Returns: List[Tensor]: The list of output of gaussian pyramid. """ x = original # pyramid down pyramids = [original] for _ in range(n_pyramids): x = get_pyramid_layer(x, gaussian_k) pyramids.append(x) return pyramids def laplacian_pyramid(original, n_pyramids, gaussian_k): """Calculate Laplacian pyramid. Ref: https://github.com/koshian2/swd-pytorch/blob/master/swd.py Args: original (Tensor): Batch of Images with range [0, 1] and order "NCHW" n_pyramids (int): Levels of pyramids minus one. gaussian_k (Tensor): Gaussian kernel with shape (1, 1, 5, 5). Return: list[Tensor]. Laplacian pyramids of original. """ # create gaussian pyramid pyramids = gaussian_pyramid(original, n_pyramids, gaussian_k) # pyramid up - diff laplacian = [] for i in range(len(pyramids) - 1): diff = pyramids[i] - get_pyramid_layer(pyramids[i + 1], gaussian_k, 'up') laplacian.append(diff) # Add last gaussian pyramid laplacian.append(pyramids[len(pyramids) - 1]) return laplacian def get_descriptors_for_minibatch(minibatch, nhood_size, nhoods_per_image): r"""Get descriptors of one level of pyramids. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/sliced_wasserstein.py # noqa Args: minibatch (Tensor): Pyramids of one level with order "NCHW". nhood_size (int): Pixel neighborhood size. nhoods_per_image (int): The number of descriptors per image. Return: Tensor: Descriptors of images from one level batch. """ S = minibatch.shape # (minibatch, channel, height, width) assert len(S) == 4 and S[1] == 3 N = nhoods_per_image * S[0] H = nhood_size // 2 nhood, chan, x, y = np.ogrid[0:N, 0:3, -H:H + 1, -H:H + 1] img = nhood // nhoods_per_image x = x + np.random.randint(H, S[3] - H, size=(N, 1, 1, 1)) y = y + np.random.randint(H, S[2] - H, size=(N, 1, 1, 1)) idx = ((img * S[1] + chan) * S[2] + y) * S[3] + x return minibatch.view(-1)[idx] def finalize_descriptors(desc): r"""Normalize and reshape descriptors. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/sliced_wasserstein.py # noqa Args: desc (list or Tensor): List of descriptors of one level. Return: Tensor: Descriptors after normalized along channel and flattened. """ if isinstance(desc, list): desc = torch.cat(desc, dim=0) assert desc.ndim == 4 # (neighborhood, channel, height, width) desc -= torch.mean(desc, dim=(0, 2, 3), keepdim=True) desc /= torch.std(desc, dim=(0, 2, 3), keepdim=True) desc = desc.reshape(desc.shape[0], -1) return desc @METRICS.register_module('SWD') @METRICS.register_module() class SlicedWassersteinDistance(GenMetric): """SWD (Sliced Wasserstein distance) metric. We calculate the SWD of two sets of images in the following way. In every 'feed', we obtain the Laplacian pyramids of every images and extract patches from the Laplacian pyramids as descriptors. In 'summary', we normalize these descriptors along channel, and reshape them so that we can use these descriptors to represent the distribution of real/fake images. And we can calculate the sliced Wasserstein distance of the real and fake descriptors as the SWD of the real and fake images. Ref: https://github.com/tkarras/progressive_growing_of_gans/blob/master/metrics/sliced_wasserstein.py # noqa Args: fake_nums (int): Numbers of the generated image need for the metric. image_shape (tuple): Image shape in order "CHW". fake_key (Optional[str]): Key for get fake images of the output dict. Defaults to None. real_key (Optional[str]): Key for get real images from the input dict. Defaults to 'gt_img'. sample_model (str): Sampling mode for the generative model. Support 'orig' and 'ema'. Defaults to 'ema'. collect_device (str): Device name used for collecting results from different ranks during distributed training. Must be 'cpu' or 'gpu'. Defaults to 'cpu'. prefix (str, optional): The prefix that will be added in the metric names to disambiguate homonymous metrics of different evaluators. If prefix is not provided in the argument, self.default_prefix will be used instead. Defaults to None. """ name = 'SWD' def __init__(self, fake_nums: int, image_shape: tuple, fake_key: Optional[str] = None, real_key: Optional[str] = 'gt_img', sample_model: str = 'ema', collect_device: str = 'cpu', prefix: Optional[str] = None): super().__init__(fake_nums, fake_nums, fake_key, real_key, sample_model, collect_device, prefix) self.nhood_size = 7 # height and width of the extracted patches self.nhoods_per_image = 128 # number of extracted patches per image self.dir_repeats = 4 # times of sampling directions self.dirs_per_repeat = 128 # number of directions per sampling self.resolutions = [] res = image_shape[1] self.image_shape = image_shape while res >= 16 and len(self.resolutions) < 4: self.resolutions.append(res) res //= 2 self.n_pyramids = len(self.resolutions) self.gaussian_k = get_gaussian_kernel() self.real_results = [[] for res in self.resolutions] self.fake_results = [[] for res in self.resolutions] self._num_processed = 0 def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None: """Process one batch of data samples and predictions. The processed results should be stored in ``self.fake_results`` and ``self.real_results``, which will be used to compute the metrics when all batches have been processed. Args: data_batch (dict): A batch of data from the dataloader. data_samples (Sequence[dict]): A batch of outputs from the model. """ if self.fake_nums != -1 and (self._num_processed >= self.fake_nums_per_device): return real_imgs, fake_imgs = [], [] for data in data_samples: # parse real images real_imgs.append(data['gt_img']) # parse fake images fake_img_ = data # get ema/orig results if self.sample_model in fake_img_: fake_img_ = fake_img_[self.sample_model] # get specific fake_keys if (self.fake_key is not None and self.fake_key in fake_img_): fake_img_ = fake_img_[self.fake_key] else: # get img tensor fake_img_ = fake_img_['fake_img'] fake_imgs.append(fake_img_) real_imgs = torch.stack(real_imgs, dim=0) fake_imgs = torch.stack(fake_imgs, dim=0) # [0, 255] -> [-1, 1] real_imgs = (real_imgs - 127.5) / 127.5 fake_imgs = (fake_imgs - 127.5) / 127.5 # real images assert real_imgs.shape[1:] == self.image_shape if real_imgs.shape[1] == 1: real_imgs = real_imgs.repeat(1, 3, 1, 1) real_pyramid = laplacian_pyramid(real_imgs, self.n_pyramids - 1, self.gaussian_k) # lod: layer_of_descriptors if self.real_results == []: self.real_results = [[] for res in self.resolutions] for lod, level in enumerate(real_pyramid): desc = get_descriptors_for_minibatch(level, self.nhood_size, self.nhoods_per_image) self.real_results[lod].append(desc.cpu()) # fake images assert fake_imgs.shape[1:] == self.image_shape if fake_imgs.shape[1] == 1: fake_imgs = fake_imgs.repeat(1, 3, 1, 1) fake_pyramid = laplacian_pyramid(fake_imgs, self.n_pyramids - 1, self.gaussian_k) # lod: layer_of_descriptors if self.fake_results == []: self.fake_results = [[] for res in self.resolutions] for lod, level in enumerate(fake_pyramid): desc = get_descriptors_for_minibatch(level, self.nhood_size, self.nhoods_per_image) self.fake_results[lod].append(desc.cpu()) self._num_processed += real_imgs.shape[0] def _collect_target_results(self, target: str) -> Optional[list]: """Collect function for SWD metric. This function support collect results typing as `List[List[Tensor]]`. Args: target (str): Target results to collect. Returns: Optional[list]: The collected results. """ assert target in [ 'fake', 'real' ], ('Only support to collect \'fake\' or \'real\' results.') results = getattr(self, f'{target}_results') results_collected = [] world_size = get_world_size() for result in results: # save the original tensor size results_size_list = [res.shape[0] for res in result] * world_size result_collected = torch.cat(result, dim=0) result_collected = torch.cat(all_gather(result_collected), dim=0) # split to tuple result_collected = torch.split(result_collected, results_size_list) # convert to list result_collected = [res for res in result_collected] results_collected.append(result_collected) self._num_processed = 0 return results_collected def compute_metrics(self, results_fake, results_real) -> dict: """Compute the result of SWD metric. Args: fake_results (list): List of image feature of fake images. real_results (list): List of image feature of real images. Returns: dict: A dict of the computed SWD metric. """ fake_descs = [finalize_descriptors(d) for d in results_fake] real_descs = [finalize_descriptors(d) for d in results_real] distance = [ sliced_wasserstein(dreal, dfake, self.dir_repeats, self.dirs_per_repeat) for dreal, dfake in zip(real_descs, fake_descs) ] del real_descs del fake_descs distance = [d * 1e3 for d in distance] # multiply by 10^3 result = distance + [np.mean(distance)] return { f'{resolution}': round(d, 4) for resolution, d in zip(self.resolutions + ['avg'], result) } ================================================ FILE: mmagic/models/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .base_models import (BaseConditionalGAN, BaseEditModel, BaseGAN, BaseMattor, BaseTranslationModel, BasicInterpolator, ExponentialMovingAverage) from .data_preprocessors import DataPreprocessor, MattorPreprocessor from .editors import * # noqa: F401, F403 from .losses import * # noqa: F401, F403 __all__ = [ 'BaseGAN', 'BaseTranslationModel', 'BaseEditModel', 'MattorPreprocessor', 'DataPreprocessor', 'BasicInterpolator', 'BaseMattor', 'BasicInterpolator', 'ExponentialMovingAverage', 'BaseConditionalGAN' ] ================================================ FILE: mmagic/models/archs/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # To register Deconv import warnings from typing import List from mmagic.utils import try_import from .all_gather_layer import AllGatherLayer from .aspp import ASPP from .attention_injection import AttentionInjection from .conv import * # noqa: F401, F403 from .downsample import pixel_unshuffle from .ensemble import SpatialTemporalEnsemble from .gated_conv_module import SimpleGatedConvModule from .img_normalize import ImgNormalize from .linear_module import LinearModule from .lora import (LoRAWrapper, set_lora, set_lora_disable, set_lora_enable, set_only_lora_trainable) from .multi_layer_disc import MultiLayerDiscriminator from .patch_disc import PatchDiscriminator from .resnet import ResNet from .separable_conv_module import DepthwiseSeparableConvModule from .simple_encoder_decoder import SimpleEncoderDecoder from .smpatch_disc import SoftMaskPatchDiscriminator from .sr_backbone import ResidualBlockNoBN from .tokenizer import TokenizerWrapper from .upsample import PixelShufflePack from .vgg import VGG16 from .wrapper import DiffusersWrapper def register_diffusers_models() -> List[str]: """Register models in ``diffusers.models`` to the ``MODELS`` registry. Specifically, the registered models from diffusers only defines the network forward without training. See more details about diffusers in: https://huggingface.co/docs/diffusers/api/models. Returns: List[str]: A list of registered DIFFUSION_MODELS' name. """ import inspect from mmagic.registry import MODELS diffusers = try_import('diffusers') if diffusers is None: warnings.warn('Diffusion Models are not registered as expect. ' 'If you want to use diffusion models, ' 'please install diffusers>=0.12.0.') return None def gen_wrapped_cls(module, module_name): return type( module_name, (DiffusersWrapper, ), dict( _module_cls=module, _module_name=module_name, __module__=__name__)) DIFFUSERS_MODELS = [] for module_name in dir(diffusers.models): module = getattr(diffusers.models, module_name) if inspect.isclass(module): wrapped_module = gen_wrapped_cls(module, module_name) MODELS.register_module(name=module_name, module=wrapped_module) DIFFUSERS_MODELS.append(module_name) DIFFUSERS_PIPELINES = [] for pipeline_name in dir(diffusers.pipelines): pipeline = getattr(diffusers.pipelines, pipeline_name) if (inspect.isclass(pipeline) and issubclass(pipeline, diffusers.DiffusionPipeline)): wrapped_pipeline = gen_wrapped_cls(pipeline, pipeline_name) MODELS.register_module(name=pipeline_name, module=wrapped_pipeline) DIFFUSERS_PIPELINES.append(pipeline_name) return DIFFUSERS_MODELS, DIFFUSERS_PIPELINES REGISTERED_DIFFUSERS_MODELS, REGISTERED_DIFFUSERS_PIPELINES = \ register_diffusers_models() __all__ = [ 'ASPP', 'DepthwiseSeparableConvModule', 'SimpleGatedConvModule', 'LinearModule', 'pixel_unshuffle', 'PixelShufflePack', 'ImgNormalize', 'SpatialTemporalEnsemble', 'SoftMaskPatchDiscriminator', 'SimpleEncoderDecoder', 'MultiLayerDiscriminator', 'PatchDiscriminator', 'VGG16', 'ResNet', 'AllGatherLayer', 'ResidualBlockNoBN', 'LoRAWrapper', 'set_lora', 'set_lora_disable', 'set_lora_enable', 'set_only_lora_trainable', 'TokenizerWrapper', 'AttentionInjection' ] ================================================ FILE: mmagic/models/archs/all_gather_layer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.autograd as autograd import torch.distributed as dist class AllGatherLayer(autograd.Function): """All gather layer with backward propagation path. Indeed, this module is to make ``dist.all_gather()`` in the backward graph. Such kind of operation has been widely used in Moco and other contrastive learning algorithms. """ @staticmethod def forward(ctx, x): """Forward function.""" ctx.save_for_backward(x) output = [torch.zeros_like(x) for _ in range(dist.get_world_size())] dist.all_gather(output, x) return tuple(output) @staticmethod def backward(ctx, *grad_outputs): """Backward function.""" x, = ctx.saved_tensors grad_out = torch.zeros_like(x) grad_out = grad_outputs[dist.get_rank()] return grad_out ================================================ FILE: mmagic/models/archs/aspp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Sequence import torch from mmcv.cnn import ConvModule from torch import Tensor, nn from torch.nn import functional as F from .separable_conv_module import DepthwiseSeparableConvModule class ASPPPooling(nn.Sequential): """ASPP Pooling module. The code is adopted from https://github.com/pytorch/vision/blob/master/torchvision/models/ segmentation/deeplabv3.py Args: in_channels (int): Input channels of the module. out_channels (int): Output channels of the module. conv_cfg (dict): Config dict for convolution layer. If "None", nn.Conv2d will be applied. norm_cfg (dict): Config dict for normalization layer. act_cfg (dict): Config dict for activation layer. """ def __init__(self, in_channels: int, out_channels: int, conv_cfg: Optional[dict], norm_cfg: Optional[dict], act_cfg: Optional[dict]): super().__init__( nn.AdaptiveAvgPool2d(1), ConvModule( in_channels, out_channels, 1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg)) def forward(self, x: Tensor) -> Tensor: """Forward function for ASPP Pooling module. Args: x (Tensor): Input tensor. Returns: Tensor: Output tensor. """ size = x.shape[-2:] for mod in self: x = mod(x) return F.interpolate( x, size=size, mode='bilinear', align_corners=False) class ASPP(nn.Module): """ASPP module from DeepLabV3. The code is adopted from https://github.com/pytorch/vision/blob/master/torchvision/models/ segmentation/deeplabv3.py For more information about the module: `"Rethinking Atrous Convolution for Semantic Image Segmentation" `_. Args: in_channels (int): Input channels of the module. out_channels (int): Output channels of the module. Default: 256. mid_channels (int): Output channels of the intermediate ASPP conv modules. Default: 256. dilations (Sequence[int]): Dilation rate of three ASPP conv module. Default: [12, 24, 36]. conv_cfg (dict): Config dict for convolution layer. If "None", nn.Conv2d will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. Default: dict(type='BN'). act_cfg (dict): Config dict for activation layer. Default: dict(type='ReLU'). separable_conv (bool): Whether replace normal conv with depthwise separable conv which is faster. Default: False. """ def __init__(self, in_channels: int, out_channels: int = 256, mid_channels: int = 256, dilations: Sequence[int] = (12, 24, 36), conv_cfg: Optional[dict] = None, norm_cfg: Optional[dict] = dict(type='BN'), act_cfg: Optional[dict] = dict(type='ReLU'), separable_conv: bool = False): super().__init__() if separable_conv: conv_module = DepthwiseSeparableConvModule else: conv_module = ConvModule modules = [] modules.append( ConvModule( in_channels, mid_channels, 1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg)) for dilation in dilations: modules.append( conv_module( in_channels, mid_channels, 3, padding=dilation, dilation=dilation, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg)) modules.append( ASPPPooling(in_channels, mid_channels, conv_cfg, norm_cfg, act_cfg)) self.convs = nn.ModuleList(modules) self.project = nn.Sequential( ConvModule( 5 * mid_channels, out_channels, 1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg), nn.Dropout(0.5)) def forward(self, x: Tensor) -> Tensor: """Forward function for ASPP module. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ res = [] for conv in self.convs: res.append(conv(x)) res = torch.cat(res, dim=1) return self.project(res) ================================================ FILE: mmagic/models/archs/attention_injection.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from enum import Enum import torch import torch.nn as nn from diffusers.models.attention import BasicTransformerBlock from torch import Tensor AttentionStatus = Enum('ATTENTION_STATUS', 'READ WRITE DISABLE') def torch_dfs(model: torch.nn.Module): result = [model] for child in model.children(): result += torch_dfs(child) return result class AttentionInjection(nn.Module): """Wrapper for stable diffusion unet. Args: module (nn.Module): The module to be wrapped. """ def __init__(self, module: nn.Module, injection_weight=5): super().__init__() self.attention_status = AttentionStatus.READ self.style_cfgs = [] self.unet = module attn_inject = self def transformer_forward_replacement( self, hidden_states, attention_mask=None, encoder_hidden_states=None, encoder_attention_mask=None, timestep=None, cross_attention_kwargs=None, class_labels=None, ): if self.use_ada_layer_norm: norm_hidden_states = self.norm1(hidden_states, timestep) elif self.use_ada_layer_norm_zero: norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1( # noqa hidden_states, timestep, class_labels, hidden_dtype=hidden_states.dtype) else: norm_hidden_states = self.norm1(hidden_states) attn_output = None self_attention_context = norm_hidden_states if attn_inject.attention_status == AttentionStatus.WRITE: self.bank.append(self_attention_context.detach().clone()) if attn_inject.attention_status == AttentionStatus.READ: if len(self.bank) > 0: self.bank = self.bank * injection_weight attn_output = self.attn1( norm_hidden_states, encoder_hidden_states=torch.cat( [self_attention_context] + self.bank, dim=1)) # attn_output = self.attn1( # norm_hidden_states, # encoder_hidden_states=self.bank[0]) self.bank = [] if attn_output is None: attn_output = self.attn1(norm_hidden_states) if self.use_ada_layer_norm_zero: attn_output = gate_msa.unsqueeze(1) * attn_output hidden_states = attn_output + hidden_states cross_attention_kwargs = cross_attention_kwargs if \ cross_attention_kwargs is not None else {} if self.attn2 is not None: norm_hidden_states = ( self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states)) # 2. Cross-Attention attn_output = self.attn2( norm_hidden_states, encoder_hidden_states=encoder_hidden_states, attention_mask=encoder_attention_mask, **cross_attention_kwargs, ) hidden_states = attn_output + hidden_states # 3. Feed-forward norm_hidden_states = self.norm3(hidden_states) if self.use_ada_layer_norm_zero: norm_hidden_states = norm_hidden_states * \ (1 + scale_mlp[:, None]) + shift_mlp[:, None] ff_output = self.ff(norm_hidden_states) if self.use_ada_layer_norm_zero: ff_output = gate_mlp.unsqueeze(1) * ff_output hidden_states = ff_output + hidden_states return hidden_states all_modules = torch_dfs(self.unet) attn_modules = [ module for module in all_modules if isinstance(module, BasicTransformerBlock) ] for i, module in enumerate(attn_modules): if getattr(module, '_original_inner_forward', None) is None: module._original_inner_forward = module.forward module.forward = transformer_forward_replacement.__get__( module, BasicTransformerBlock) module.bank = [] def forward(self, x: Tensor, t, encoder_hidden_states=None, down_block_additional_residuals=None, mid_block_additional_residual=None, ref_x=None) -> Tensor: """Forward and add LoRA mapping. Args: x (Tensor): The input tensor. Returns: Tensor: The output tensor. """ if ref_x is not None: self.attention_status = AttentionStatus.WRITE self.unet( ref_x, t, encoder_hidden_states=encoder_hidden_states, down_block_additional_residuals= # noqa down_block_additional_residuals, mid_block_additional_residual=mid_block_additional_residual) self.attention_status = AttentionStatus.READ output = self.unet( x, t, encoder_hidden_states=encoder_hidden_states, down_block_additional_residuals= # noqa down_block_additional_residuals, mid_block_additional_residual=mid_block_additional_residual) return output ================================================ FILE: mmagic/models/archs/conv.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from torch import nn from mmagic.registry import MODELS MODELS.register_module('Deconv', module=nn.ConvTranspose2d) # TODO: octave conv ================================================ FILE: mmagic/models/archs/downsample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from torch import Tensor def pixel_unshuffle(x: Tensor, scale: int) -> Tensor: """Down-sample by pixel unshuffle. Args: x (Tensor): Input tensor. scale (int): Scale factor. Returns: Tensor: Output tensor. """ b, c, h, w = x.shape if h % scale != 0 or w % scale != 0: raise AssertionError( f'Invalid scale ({scale}) of pixel unshuffle for tensor ' f'with shape: {x.shape}') h = int(h / scale) w = int(w / scale) x = x.view(b, c, h, scale, w, scale) x = x.permute(0, 1, 3, 5, 2, 4) return x.reshape(b, -1, h, w) ================================================ FILE: mmagic/models/archs/ensemble.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn class SpatialTemporalEnsemble(nn.Module): """Apply spatial and temporal ensemble and compute outputs. Args: is_temporal_ensemble (bool, optional): Whether to apply ensemble temporally. If True, the sequence will also be flipped temporally. If the input is an image, this argument must be set to False. Default: False. """ def __init__(self, is_temporal_ensemble: Optional[bool] = False): super().__init__() self.is_temporal_ensemble = is_temporal_ensemble def _transform(self, imgs: torch.Tensor, mode: str) -> torch.Tensor: """Apply spatial transform (flip, rotate) to the images. Args: imgs (torch.Tensor): The images to be transformed/ mode (str): The mode of transform. Supported values are 'vertical', 'horizontal', and 'transpose', corresponding to vertical flip, horizontal flip, and rotation, respectively. Returns: torch.Tensor: Output of the model with spatial ensemble applied. """ is_single_image = False if imgs.ndim == 4: if self.is_temporal_ensemble: raise ValueError('"is_temporal_ensemble" must be False if ' 'the input is an image.') is_single_image = True imgs = imgs.unsqueeze(1) if mode == 'vertical': imgs = imgs.flip(4).clone() elif mode == 'horizontal': imgs = imgs.flip(3).clone() elif mode == 'transpose': imgs = imgs.permute(0, 1, 2, 4, 3).clone() if is_single_image: imgs = imgs.squeeze(1) return imgs def spatial_ensemble(self, imgs: torch.Tensor, model: nn.Module) -> torch.Tensor: """Apply spatial ensemble. Args: imgs (torch.Tensor): The images to be processed by the model. Its size should be either (n, t, c, h, w) or (n, c, h, w). model (nn.Module): The model to process the images. Returns: torch.Tensor: Output of the model with spatial ensemble applied. """ img_list = [imgs.cpu()] for mode in ['vertical', 'horizontal', 'transpose']: img_list.extend([self._transform(t, mode) for t in img_list]) output_list = [model(t.to(imgs.device)).cpu() for t in img_list] for i in range(len(output_list)): if i > 3: output_list[i] = self._transform(output_list[i], 'transpose') if i % 4 > 1: output_list[i] = self._transform(output_list[i], 'horizontal') if (i % 4) % 2 == 1: output_list[i] = self._transform(output_list[i], 'vertical') outputs = torch.stack(output_list, dim=0) outputs = outputs.mean(dim=0, keepdim=False) return outputs.to(imgs.device) def forward(self, imgs: torch.Tensor, model: nn.Module) -> torch.Tensor: """Apply spatial and temporal ensemble. Args: imgs (torch.Tensor): The images to be processed by the model. Its size should be either (n, t, c, h, w) or (n, c, h, w). model (nn.Module): The model to process the images. Returns: torch.Tensor: Output of the model with spatial ensemble applied. """ outputs = self.spatial_ensemble(imgs, model) if self.is_temporal_ensemble: outputs += self.spatial_ensemble(imgs.flip(1), model).flip(1) outputs *= 0.5 return outputs ================================================ FILE: mmagic/models/archs/gated_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from typing import Optional, Tuple, Union import torch import torch.nn as nn from mmcv.cnn import ConvModule, build_activation_layer class SimpleGatedConvModule(nn.Module): """Simple Gated Convolutional Module. This module is a simple gated convolutional module. The detailed formula is: .. math:: y = \\phi(conv1(x)) * \\sigma(conv2(x)), where `phi` is the feature activation function and `sigma` is the gate activation function. In default, the gate activation function is sigmoid. Args: in_channels (int): Same as nn.Conv2d. out_channels (int): The number of channels of the output feature. Note that `out_channels` in the conv module is doubled since this module contains two convolutions for feature and gate separately. kernel_size (int or tuple[int]): Same as nn.Conv2d. feat_act_cfg (dict): Config dict for feature activation layer. Default: dict(type='ELU'). gate_act_cfg (dict): Config dict for gate activation layer. Default: dict(type='Sigmoid'). kwargs (keyword arguments): Same as `ConvModule`. """ def __init__(self, in_channels: int, out_channels: int, kernel_size: Union[int, Tuple[int, int]], feat_act_cfg: Optional[dict] = dict(type='ELU'), gate_act_cfg: Optional[dict] = dict(type='Sigmoid'), **kwargs): super().__init__() # the activation function should specified outside conv module kwargs_ = copy.deepcopy(kwargs) kwargs_['act_cfg'] = None self.with_feat_act = feat_act_cfg is not None self.with_gate_act = gate_act_cfg is not None self.conv = ConvModule(in_channels, out_channels * 2, kernel_size, **kwargs_) if self.with_feat_act: self.feat_act = build_activation_layer(feat_act_cfg) if self.with_gate_act: self.gate_act = build_activation_layer(gate_act_cfg) def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ x = self.conv(x) x, gate = torch.split(x, x.size(1) // 2, dim=1) if self.with_feat_act: x = self.feat_act(x) if self.with_gate_act: gate = self.gate_act(gate) x = x * gate return x ================================================ FILE: mmagic/models/archs/img_normalize.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Tuple import torch import torch.nn as nn class ImgNormalize(nn.Conv2d): """Normalize images with the given mean and std value. Based on Conv2d layer, can work in GPU. Args: pixel_range (float): Pixel range of feature. img_mean (Tuple[float]): Image mean of each channel. img_std (Tuple[float]): Image std of each channel. sign (int): Sign of bias. Default -1. """ def __init__(self, pixel_range: float, img_mean: Tuple[float, float, float], img_std: Tuple[float, float, float], sign: int = -1): assert len(img_mean) == len(img_std) num_channels = len(img_mean) super().__init__(num_channels, num_channels, kernel_size=1) std = torch.Tensor(img_std) self.weight.data = torch.eye(num_channels).view( num_channels, num_channels, 1, 1) self.weight.data.div_(std.view(num_channels, 1, 1, 1)) self.bias.data = sign * pixel_range * torch.Tensor(img_mean) self.bias.data.div_(std) self.weight.requires_grad = False self.bias.requires_grad = False ================================================ FILE: mmagic/models/archs/linear_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Tuple import torch.nn as nn from mmcv.cnn import build_activation_layer from mmengine.model.weight_init import kaiming_init from torch import Tensor class LinearModule(nn.Module): """A linear block that contains linear/norm/activation layers. For low level vision, we add spectral norm and padding layer. Args: in_features (int): Same as nn.Linear. out_features (int): Same as nn.Linear. bias (bool): Same as nn.Linear. Default: True. act_cfg (dict): Config dict for activation layer, "relu" by default. inplace (bool): Whether to use inplace mode for activation. Default: True. with_spectral_norm (bool): Whether use spectral norm in linear module. Default: False. order (tuple[str]): The order of linear/activation layers. It is a sequence of "linear", "norm" and "act". Examples are ("linear", "act") and ("act", "linear"). """ def __init__(self, in_features: int, out_features: int, bias: bool = True, act_cfg: Optional[dict] = dict(type='ReLU'), inplace: bool = True, with_spectral_norm: bool = False, order: Tuple[str, str] = ('linear', 'act')): super().__init__() assert act_cfg is None or isinstance(act_cfg, dict) self.act_cfg = act_cfg self.inplace = inplace self.with_spectral_norm = with_spectral_norm self.order = order assert isinstance(self.order, tuple) and len(self.order) == 2 assert set(order) == set(['linear', 'act']) self.with_activation = act_cfg is not None self.with_bias = bias # build linear layer self.linear = nn.Linear(in_features, out_features, bias=bias) # export the attributes of self.linear to a higher level for # convenience self.in_features = self.linear.in_features self.out_features = self.linear.out_features if self.with_spectral_norm: self.linear = nn.utils.spectral_norm(self.linear) # build activation layer if self.with_activation: act_cfg_ = act_cfg.copy() act_cfg_.setdefault('inplace', inplace) self.activate = build_activation_layer(act_cfg_) # Use msra init by default self.init_weights() def init_weights(self) -> None: """Init weights for the model.""" if self.with_activation and self.act_cfg['type'] == 'LeakyReLU': nonlinearity = 'leaky_relu' a = self.act_cfg.get('negative_slope', 0.01) else: nonlinearity = 'relu' a = 0 kaiming_init(self.linear, a=a, nonlinearity=nonlinearity) def forward(self, x: Tensor, activate: Optional[bool] = True) -> Tensor: """Forward Function. Args: x (torch.Tensor): Input tensor with shape of :math:`(n, *, c)`. Same as ``torch.nn.Linear``. activate (bool, optional): Whether to use activation layer. Defaults to True. Returns: torch.Tensor: Same as ``torch.nn.Linear``. """ for layer in self.order: if layer == 'linear': x = self.linear(x) elif layer == 'act' and activate and self.with_activation: x = self.activate(x) return x ================================================ FILE: mmagic/models/archs/lora.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import re from typing import Any, List, Optional, Union import torch.nn as nn from mmengine import print_log from torch import Tensor class LoRALinear(nn.Module): """Linear layer for LoRA. Args: in_feat (int): Number of input features. out_feat (int): Number of output features. rank (int): The rank of LoRA. """ def __init__(self, in_feat: int, out_feat: int, rank: int = 4): super().__init__() self.rank = rank assert rank < min(in_feat, out_feat) self.down = nn.Linear(in_feat, rank, bias=False) self.up = nn.Linear(rank, out_feat, bias=False) nn.init.normal_(self.down.weight, std=1 / rank) nn.init.zeros_(self.up.weight) def forward(self, x: Tensor) -> Tensor: ori_type = x.dtype dtype = self.down.weight.dtype out = self.down(x.to(dtype)) out = self.up(out) return out.to(ori_type) class LoRAWrapper(nn.Module): """Wrapper for LoRA layer. Args: module (nn.Module): The module to be wrapped. in_feat (int): Number of input features. out_feat (int): Number of output features. rank (int): The rank of LoRA. scale (float): The scale of LoRA feature. names (Union[str, List[str]], optional): The name of LoRA layers. If you want to add multi LoRA for one module, names for each LoRA mapping must be defined. """ def __init__(self, module: nn.Module, in_feat: int, out_feat: int, rank: int, scale: float = 1, names: Optional[Union[str, List[str]]] = None): super().__init__() # NOTE: LoRA for linear layer, LoCON will coming soon~ assert isinstance( module, nn.Linear), ('Only Support LoRA for linear layer currently. ' 'LoCON will coming soon~') self.wrapped = module if names is not None: # set a list of LoRAs if not isinstance(names, list): names = [names] if isinstance(rank, list): assert len(rank) == len(names) else: rank = [rank] * len(names) if isinstance(scale, list): assert len(scale) == len(names) else: scale = [scale] * len(names) self.names = names self.lora_mapping = dict() self.scale = dict() self.enable = dict() self.rank = dict() for n, r, s in zip(names, rank, scale): self.lora_mapping[n] = LoRALinear(in_feat, out_feat, r) self.scale_dict[n] = s self.enable[n] = True self.rank[n] = r self.lora_mapping = nn.ModuleDict(self.lora_mapping) else: # set single LoRA self.names = None self.lora_mapping = LoRALinear(in_feat, out_feat, rank) self.scale = scale self.enable = True self.rank = rank self.in_feat, self.out_feat = in_feat, out_feat def add_lora(self, name: str, rank: int, scale: float = 1, state_dict: Optional[dict] = None): """Add LoRA mapping. Args: name (str): The name of added LoRA. rank (int): The rank of added LoRA. scale (float, optional): The scale of added LoRA. Defaults to 1. state_dict (dict, optional): The state dict of added LoRA. Defaults to None. """ mapping_to_add = LoRALinear(self.in_feat, self.out_feat, rank) if state_dict is not None: mapping_to_add.load_state_dict(mapping_to_add) # move to device and type mapping_to_add.to(self.lora_mapping.weight.dtype) if isinstance(self.names, list): self.names.append(name) self.lora_mapping[name] = mapping_to_add self.scale[name] = scale self.enable[name] = True self.rank[name] = rank else: self.names = ['orig', name] self.lora_mapping = nn.ModuleDict({ 'orig': self.lora_mapping, name: mapping_to_add }) self.scale = {'orig': self.scale, name: scale} self.enable = {'orig': self.enable, name: True} self.rank = {'orig': self.rank, name: rank} print_log( 'The original LoRA mapping do not have name, ' 'save as \'orig\'.', 'current') print_log(f'Add LoRA \'{name}\' with rank {rank} and scale {scale}.', 'current') def _set_value(self, attr_name: str, value: Any, name: Optional[str] = None): """Set value of attribute. Args: attr_name (str): The name of attribute to be set value. value (Any): The value to be set. name (str, optional): The name of field in `attr_name`. If passed, will set value to `attr_name[name]`. Defaults to None. """ attr = getattr(self, attr_name) if isinstance(attr, dict): if name is None: attr = {k: value for k in self.names} print_log(f'Set all value in \'{attr_name}\' as \'{value}\'.', 'current') else: attr[name] = value print_log(f'Set \'{attr_name}[{name}]\' as \'{value}\'.', 'current') else: attr = value print_log(f'Set \'{attr_name}\' as \'{value}\'.', 'current') setattr(self, attr_name, attr) def set_scale(self, scale: float, name: Optional[str] = None): """Set LoRA scale. Args: scale (float): The scale to be set. name (str, optional): The name of LoRA to be set. Defaults to None. """ self._set_value('scale', scale, name) def set_enable(self, name: Optional[str] = None): """Enable LoRA for the current layer. Args: name (str, optional): The name of LoRA to be set. Defaults to None. """ self._set_value('enable', True, name) def set_disable(self, name: Optional[str] = None): """Disable LoRA for the current layer. Args: name (str, optional): The name of LoRA to be set. Defaults to None. """ self._set_value('enable', False, name) def forward_lora_mapping(self, x: Tensor) -> Tensor: """Forward LoRA mapping. Args: x (Tensor): The input tensor. Returns: Tensor: The output tensor. """ mapping_out = 0 if isinstance(self.lora_mapping, dict): for name in self.names: scale = self.scale[name] mapping_layer = self.lora_mapping[name] enable = self.enable[name] if enable: mapping_out = scale * mapping_layer(x) else: if self.enable: mapping_out = self.scale * self.lora_mapping(x) return mapping_out def forward(self, x: Tensor, *args, **kwargs) -> Tensor: """Forward and add LoRA mapping. Args: x (Tensor): The input tensor. Returns: Tensor: The output tensor. """ mapping_out = self.forward_lora_mapping(x) return mapping_out + self.wrapped(x) @classmethod def wrap_lora(cls, module, rank=4, scale=1, names=None, state_dict=None): """Wrap LoRA. Use case: >>> linear = nn.Linear(2, 4) >>> lora_linear = LoRAWrapper.wrap_lora(linear, 4, 1) Args: module (nn.Module): The module to add LoRA. rank (int): The rank for LoRA. scale (float): Returns: LoRAWrapper: """ assert isinstance(module, nn.Linear), 'Only support LoRA for Linear Layer' in_feat = module.weight.shape[1] out_feat = module.weight.shape[0] lora = LoRAWrapper(module, in_feat, out_feat, rank, scale, names) return lora def replace_module(parent_module: nn.Module, child_name: str, new_module: nn.Module): """Replace module in parent module.""" setattr(parent_module, child_name, new_module) def get_submodule(module: nn.Module, key: str): """Get submodule by key.""" target_name = key.split('.')[-1] parent = module.get_submodule('.'.join(key.split('.')[:-1])) target = module.get_submodule(key) return parent, target, target_name def set_lora(module: nn.Module, config: dict, verbose: bool = True) -> nn.Module: """Set LoRA for module. Use case: >>> 1. set all lora with same parameters >>> lora_config = dict( >>> rank=4, >>> scale=1, >>> target_modules=['to_q', 'to_k', 'to_v']) >>> 2. set lora with different parameters >>> lora_config = dict( >>> rank=4, >>> scale=1, >>> target_modules=[ >>> # set `to_q` the default parameters >>> 'to_q', >>> # set `to_k` the defined parameters >>> dict(target_module='to_k', rank=8, scale=1), >>> # set `to_v` the defined `rank` and default `scale` >>> dict(target_module='to_v', rank=16) >>> ]) Args: module (nn.Module): The module to set LoRA. config (dict): The config dict. verbose (bool): Whether to print log. Defaults to True. """ default_rank = config.get('rank', 4) default_scale = config.get('scale', 1) target_modules = config['target_modules'] if not isinstance(target_modules, list): target_modules = [target_modules] keys = [k for k, _ in module.named_modules()] for k in keys: for target_module in target_modules: if isinstance(target_module, str): module_name = target_module rank = default_rank scale = default_scale # pretrained_path = None elif isinstance(target_module, dict): module_name = target_module['target_module'] rank = target_module.get('rank', default_rank) scale = target_module.get('scale', default_scale) # pretrained_path = target_module.get('pretrained_path', None) else: raise TypeError('Only support dict or string type for ' 'target_modules') # match keys if re.fullmatch(module_name, k): if verbose: print_log( f'Set LoRA for \'{k}\' with ' f'regularization expression match \'{module_name}\'.', 'current') elif k.endswith(module_name): if verbose: print_log( f'Set LoRA for \'{k}\' with ' f'suffix match \'{module_name}\'.', 'current') else: continue parent, target, target_name = get_submodule(module, k) new_module = LoRAWrapper.wrap_lora(target, rank=rank, scale=scale) replace_module(parent, target_name, new_module) return module def set_only_lora_trainable(module: nn.Module) -> nn.Module: """Set only LoRA modules trainable.""" for n, m in module.named_children(): if isinstance(m, LoRAWrapper): m.lora_mapping.requires_grad_(True) elif isinstance(m, nn.Module): m.requires_grad_(False) set_only_lora_trainable(m) return module def set_lora_enable(module: nn.Module) -> nn.Module: """Enable LoRA modules.""" for n, m in module.named_children(): if isinstance(m, LoRAWrapper): m.set_enable() elif isinstance(m, nn.Module): set_lora_enable(m) return module def set_lora_disable(module: nn.Module) -> nn.Module: """Disable LoRA modules.""" for n, m in module.named_children(): if isinstance(m, LoRAWrapper): m.set_disable() elif isinstance(m, nn.Module): set_lora_disable(m) return module ================================================ FILE: mmagic/models/archs/multi_layer_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn from mmcv.cnn import ConvModule from mmengine import MMLogger from mmengine.runner import load_checkpoint from torch import Tensor from mmagic.models.archs import LinearModule from mmagic.registry import MODELS @MODELS.register_module() class MultiLayerDiscriminator(nn.Module): """Multilayer Discriminator. This is a commonly used structure with stacked multiply convolution layers. Args: in_channels (int): Input channel of the first input convolution. max_channels (int): The maximum channel number in this structure. num_conv (int): Number of stacked intermediate convs (including input conv but excluding output conv). Default to 5. fc_in_channels (int | None): Input dimension of the fully connected layer. If `fc_in_channels` is None, the fully connected layer will be removed. Default to None. fc_out_channels (int): Output dimension of the fully connected layer. Default to 1024. kernel_size (int): Kernel size of the conv modules. Default to 5. conv_cfg (dict): Config dict to build conv layer. norm_cfg (dict): Config dict to build norm layer. act_cfg (dict): Config dict for activation layer, "relu" by default. out_act_cfg (dict): Config dict for output activation, "relu" by default. with_input_norm (bool): Whether add normalization after the input conv. Default to True. with_out_convs (bool): Whether add output convs to the discriminator. The output convs contain two convs. The first out conv has the same setting as the intermediate convs but a stride of 1 instead of 2. The second out conv is a conv similar to the first out conv but reduces the number of channels to 1 and has no activation layer. Default to False. with_spectral_norm (bool): Whether use spectral norm after the conv layers. Default to False. kwargs (keyword arguments). """ def __init__(self, in_channels: int, max_channels: int, num_convs: int = 5, fc_in_channels: Optional[int] = None, fc_out_channels: int = 1024, kernel_size: int = 5, conv_cfg: Optional[dict] = None, norm_cfg: Optional[dict] = None, act_cfg: Optional[dict] = dict(type='ReLU'), out_act_cfg: Optional[dict] = dict(type='ReLU'), with_input_norm: bool = True, with_out_convs: bool = False, with_spectral_norm: bool = False, **kwargs): super().__init__() if fc_in_channels is not None: assert fc_in_channels > 0 self.max_channels = max_channels self.with_fc = fc_in_channels is not None self.num_convs = num_convs self.with_out_act = out_act_cfg is not None self.with_out_convs = with_out_convs cur_channels = in_channels for i in range(num_convs): out_ch = min(64 * 2**i, max_channels) norm_cfg_ = norm_cfg act_cfg_ = act_cfg if i == 0 and not with_input_norm: norm_cfg_ = None elif (i == num_convs - 1 and not self.with_fc and not self.with_out_convs): norm_cfg_ = None act_cfg_ = out_act_cfg self.add_module( f'conv{i + 1}', ConvModule( cur_channels, out_ch, kernel_size=kernel_size, stride=2, padding=kernel_size // 2, norm_cfg=norm_cfg_, act_cfg=act_cfg_, with_spectral_norm=with_spectral_norm, **kwargs)) cur_channels = out_ch if self.with_out_convs: cur_channels = min(64 * 2**(num_convs - 1), max_channels) out_ch = min(64 * 2**num_convs, max_channels) self.add_module( f'conv{num_convs + 1}', ConvModule( cur_channels, out_ch, kernel_size, stride=1, padding=kernel_size // 2, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, **kwargs)) self.add_module( f'conv{num_convs + 2}', ConvModule( out_ch, 1, kernel_size, stride=1, padding=kernel_size // 2, act_cfg=None, with_spectral_norm=with_spectral_norm, **kwargs)) if self.with_fc: self.fc = LinearModule( fc_in_channels, fc_out_channels, bias=True, act_cfg=out_act_cfg, with_spectral_norm=with_spectral_norm) def forward(self, x: Tensor) -> Tensor: """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w') or (n, c). """ input_size = x.size() # out_convs has two additional ConvModules num_convs = self.num_convs + 2 * self.with_out_convs for i in range(num_convs): x = getattr(self, f'conv{i + 1}')(x) if self.with_fc: x = x.view(input_size[0], -1) x = self.fc(x) return x def init_weights(self, pretrained: Optional[str] = None) -> None: """Init weights for models. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): # Here, we only initialize the module with fc layer since the # conv and norm layers has been initialized in `ConvModule`. if isinstance(m, nn.Linear): nn.init.normal_(m.weight.data, 0.0, 0.02) nn.init.constant_(m.bias.data, 0.0) else: raise TypeError('pretrained must be a str or None') ================================================ FILE: mmagic/models/archs/patch_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn from mmcv.cnn import ConvModule, build_conv_layer from mmengine.model import BaseModule from torch import Tensor from mmagic.models.utils import generation_init_weights from mmagic.registry import MODELS @MODELS.register_module() class PatchDiscriminator(BaseModule): """A PatchGAN discriminator. Args: in_channels (int): Number of channels in input images. base_channels (int): Number of channels at the first conv layer. Default: 64. num_conv (int): Number of stacked intermediate convs (excluding input and output conv). Default: 3. norm_cfg (dict): Config dict to build norm layer. Default: `dict(type='BN')`. init_cfg (dict): Config dict for initialization. `type`: The name of our initialization method. Default: 'normal'. `gain`: Scaling factor for normal, xavier and orthogonal. Default: 0.02. """ def __init__(self, in_channels: int, base_channels: int = 64, num_conv: int = 3, norm_cfg: dict = dict(type='BN'), init_cfg: Optional[dict] = dict(type='normal', gain=0.02)): super().__init__(init_cfg=init_cfg) assert isinstance(norm_cfg, dict), ("'norm_cfg' should be dict, but" f'got {type(norm_cfg)}') assert 'type' in norm_cfg, "'norm_cfg' must have key 'type'" # We use norm layers in the patch discriminator. # Only for IN, use bias since it does not have affine parameters. use_bias = norm_cfg['type'] == 'IN' kernel_size = 4 padding = 1 # input layer sequence = [ ConvModule( in_channels=in_channels, out_channels=base_channels, kernel_size=kernel_size, stride=2, padding=padding, bias=True, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) ] # stacked intermediate layers, # gradually increasing the number of filters multiple_now = 1 multiple_prev = 1 for n in range(1, num_conv): multiple_prev = multiple_now multiple_now = min(2**n, 8) sequence += [ ConvModule( in_channels=base_channels * multiple_prev, out_channels=base_channels * multiple_now, kernel_size=kernel_size, stride=2, padding=padding, bias=use_bias, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) ] multiple_prev = multiple_now multiple_now = min(2**num_conv, 8) sequence += [ ConvModule( in_channels=base_channels * multiple_prev, out_channels=base_channels * multiple_now, kernel_size=kernel_size, stride=1, padding=padding, bias=use_bias, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) ] # output one-channel prediction map sequence += [ build_conv_layer( dict(type='Conv2d'), base_channels * multiple_now, 1, kernel_size=kernel_size, stride=1, padding=padding) ] self.model = nn.Sequential(*sequence) self.init_type = 'normal' if init_cfg is None else init_cfg.get( 'type', 'normal') self.init_gain = 0.02 if init_cfg is None else init_cfg.get( 'gain', 0.02) def forward(self, x: Tensor) -> Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ return self.model(x) def init_weights(self) -> None: """Initialize weights for the model. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Default: None. """ if self.init_cfg is None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return generation_init_weights( self, init_type=self.init_type, init_gain=self.init_gain) self._is_init = True ================================================ FILE: mmagic/models/archs/resnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Sequence import torch.nn as nn import torch.utils.checkpoint as cp from mmcv.cnn import build_activation_layer, build_conv_layer, build_norm_layer from mmengine import MMLogger from mmengine.model.weight_init import constant_init, kaiming_init from mmengine.runner import load_checkpoint from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from torch import Tensor class BasicBlock(nn.Module): """Basic block for ResNet. Args: inplanes (int): Number of input channels. planes (int): Number of output channels. stride (int): Stride of the first block of one stage. Default: 1. dilation (int): Dilation of one stage. Default: 1. downsample (nn.Module): Downsample module. Default: None. act_cfg (dict): Dictionary to construct and config activation layer. Default: dict(type='ReLU'). conv_cfg (dict): Dictionary to construct and config convolution layer. Default: None. norm_cfg (dict): Dictionary to construct and config norm layer. Default: dict(type='BN'). with_cp (bool): Use checkpoint or not. Using checkpoint will save some memory while slowing down the training speed. Default: False. """ expansion = 1 def __init__(self, inplanes: int, planes: int, stride: int = 1, dilation: int = 1, downsample: Optional[nn.Module] = None, act_cfg: dict = dict(type='ReLU'), conv_cfg: Optional[dict] = None, norm_cfg: dict = dict(type='BN'), with_cp: bool = False): super(BasicBlock, self).__init__() self.norm1_name, norm1 = build_norm_layer(norm_cfg, planes, postfix=1) self.norm2_name, norm2 = build_norm_layer(norm_cfg, planes, postfix=2) self.conv1 = build_conv_layer( conv_cfg, inplanes, planes, 3, stride=stride, padding=dilation, dilation=dilation, bias=False) self.add_module(self.norm1_name, norm1) self.conv2 = build_conv_layer( conv_cfg, planes, planes, 3, padding=1, bias=False) self.add_module(self.norm2_name, norm2) self.activate = build_activation_layer(act_cfg) self.downsample = downsample self.stride = stride self.dilation = dilation self.with_cp = with_cp @property def norm1(self) -> nn.Module: """nn.Module: normalization layer after the first convolution layer""" return getattr(self, self.norm1_name) @property def norm2(self) -> nn.Module: """nn.Module: normalization layer after the second convolution layer""" return getattr(self, self.norm2_name) def forward(self, x: Tensor) -> Tensor: """Forward function.""" def _inner_forward(x: Tensor) -> Tensor: identity = x out = self.conv1(x) out = self.norm1(out) out = self.activate(out) out = self.conv2(out) out = self.norm2(out) if self.downsample is not None: identity = self.downsample(x) out += identity return out if self.with_cp and x.requires_grad: out = cp.checkpoint(_inner_forward, x) else: out = _inner_forward(x) out = self.activate(out) return out class Bottleneck(nn.Module): """Bottleneck block for ResNet. Args: inplanes (int): Number of input channels. planes (int): Number of output channels. stride (int): Stride of the first block of one stage. Default: 1. dilation (int): Dilation of one stage. Default: 1. downsample (nn.Module): Downsample module. Default: None. act_cfg (dict): Dictionary to construct and config activation layer. Default: dict(type='ReLU'). conv_cfg (dict): Dictionary to construct and config convolution layer. Default: None. norm_cfg (dict): Dictionary to construct and config norm layer. Default: dict(type='BN'). with_cp (bool): Use checkpoint or not. Using checkpoint will save some memory while slowing down the training speed. Default: False. """ expansion = 4 def __init__(self, inplanes: int, planes: int, stride: int = 1, dilation: int = 1, downsample: Optional[nn.Module] = None, act_cfg: dict = dict(type='ReLU'), conv_cfg: Optional[dict] = None, norm_cfg: dict = dict(type='BN'), with_cp: bool = False): super(Bottleneck, self).__init__() self.inplanes = inplanes self.planes = planes self.stride = stride self.dilation = dilation self.act_cfg = act_cfg self.conv_cfg = conv_cfg self.norm_cfg = norm_cfg self.conv1_stride = 1 self.conv2_stride = stride self.with_cp = with_cp self.norm1_name, norm1 = build_norm_layer(norm_cfg, planes, postfix=1) self.norm2_name, norm2 = build_norm_layer(norm_cfg, planes, postfix=2) self.norm3_name, norm3 = build_norm_layer( norm_cfg, planes * self.expansion, postfix=3) self.conv1 = build_conv_layer( conv_cfg, inplanes, planes, kernel_size=1, stride=self.conv1_stride, bias=False) self.add_module(self.norm1_name, norm1) self.conv2 = build_conv_layer( conv_cfg, planes, planes, kernel_size=3, stride=self.conv2_stride, padding=dilation, dilation=dilation, bias=False) self.add_module(self.norm2_name, norm2) self.conv3 = build_conv_layer( conv_cfg, planes, planes * self.expansion, kernel_size=1, bias=False) self.add_module(self.norm3_name, norm3) self.activate = build_activation_layer(act_cfg) self.downsample = downsample @property def norm1(self) -> nn.Module: """nn.Module: normalization layer after the first convolution layer""" return getattr(self, self.norm1_name) @property def norm2(self) -> nn.Module: """nn.Module: normalization layer after the second convolution layer""" return getattr(self, self.norm2_name) @property def norm3(self) -> nn.Module: """nn.Module: normalization layer after the second convolution layer""" return getattr(self, self.norm3_name) def forward(self, x: Tensor) -> Tensor: identity = x out = self.conv1(x) out = self.norm1(out) out = self.activate(out) out = self.conv2(out) out = self.norm2(out) out = self.activate(out) out = self.conv3(out) out = self.norm3(out) if self.downsample is not None: identity = self.downsample(x) out += identity out = self.activate(out) return out class ResNet(nn.Module): """General ResNet. This class is adopted from https://github.com/open-mmlab/mmsegmentation/blob/master/mmseg/models/backbones/resnet.py. Args: depth (int): Depth of resnet, from {18, 34, 50, 101, 152}. in_channels (int): Number of input image channels. Default" 3. stem_channels (int): Number of stem channels. Default: 64. base_channels (int): Number of base channels of res layer. Default: 64. num_stages (int): Resnet stages, normally 4. strides (Sequence[int]): Strides of the first block of each stage. Default: (1, 2, 2, 2). dilations (Sequence[int]): Dilation of each stage. Default: (1, 1, 2, 4). deep_stem (bool): Replace 7x7 conv in input stem with 3 3x3 conv. Default: False. avg_down (bool): Use AvgPool instead of stride conv when downsampling in the bottleneck. Default: False. frozen_stages (int): Stages to be frozen (stop grad and set eval mode). -1 means not freezing any parameters. Default: -1. act_cfg (dict): Dictionary to construct and config activation layer. Default: dict(type='ReLU'). conv_cfg (dict): Dictionary to construct and config convolution layer. Default: None. norm_cfg (dict): Dictionary to construct and config norm layer. Default: dict(type='BN'). with_cp (bool): Use checkpoint or not. Using checkpoint will save some memory while slowing down the training speed. Default: False. multi_grid (Sequence[int]|None): Multi grid dilation rates of last stage. Default: None. contract_dilation (bool): Whether contract first dilation of each layer Default: False. zero_init_residual (bool): Whether to use zero init for last norm layer in resblocks to let them behave as identity. Default: True. """ arch_settings = { 18: (BasicBlock, (2, 2, 2, 2)), 34: (BasicBlock, (3, 4, 6, 3)), 50: (Bottleneck, (3, 4, 6, 3)), 101: (Bottleneck, (3, 4, 23, 3)), 152: (Bottleneck, (3, 8, 36, 3)) } def __init__(self, depth: int, in_channels: int = 3, stem_channels: int = 64, base_channels: int = 64, num_stages: int = 4, strides: Sequence[int] = (1, 2, 2, 2), dilations: Sequence[int] = (1, 1, 2, 4), deep_stem: bool = False, avg_down: bool = False, frozen_stages: int = -1, act_cfg: dict = dict(type='ReLU'), conv_cfg: Optional[dict] = None, norm_cfg: dict = dict(type='BN'), with_cp: bool = False, multi_grid: Optional[Sequence[int]] = None, contract_dilation: bool = False, zero_init_residual: bool = True): super(ResNet, self).__init__() from functools import partial if depth not in self.arch_settings: raise KeyError(f'invalid depth {depth} for resnet') self.block, stage_blocks = self.arch_settings[depth] self.depth = depth self.inplanes = stem_channels self.stem_channels = stem_channels self.base_channels = base_channels self.num_stages = num_stages assert num_stages >= 1 and num_stages <= 4 self.strides = strides self.dilations = dilations assert len(strides) == len(dilations) == num_stages self.deep_stem = deep_stem self.avg_down = avg_down self.frozen_stages = frozen_stages self.conv_cfg = conv_cfg self.act_cfg = act_cfg self.norm_cfg = norm_cfg self.with_cp = with_cp self.multi_grid = multi_grid self.contract_dilation = contract_dilation self.zero_init_residual = zero_init_residual self._make_stem_layer(in_channels, stem_channels) self.layer1 = self._make_layer( self.block, 64, stage_blocks[0], stride=strides[0]) self.layer2 = self._make_layer( self.block, 128, stage_blocks[1], stride=strides[1]) self.layer3 = self._make_layer( self.block, 256, stage_blocks[2], stride=strides[2]) self.layer4 = self._make_layer( self.block, 512, stage_blocks[3], stride=strides[3]) self.layer1.apply(partial(self._nostride_dilate, dilate=dilations[0])) self.layer2.apply(partial(self._nostride_dilate, dilate=dilations[1])) self.layer3.apply(partial(self._nostride_dilate, dilate=dilations[2])) self.layer4.apply(partial(self._nostride_dilate, dilate=dilations[3])) self._freeze_stages() def _make_stem_layer(self, in_channels: int, stem_channels: int) -> None: """Make stem layer for ResNet.""" if self.deep_stem: self.stem = nn.Sequential( build_conv_layer( self.conv_cfg, in_channels, stem_channels // 2, kernel_size=3, stride=2, padding=1, bias=False), build_norm_layer(self.norm_cfg, stem_channels // 2)[1], build_activation_layer(self.act_cfg), build_conv_layer( self.conv_cfg, stem_channels // 2, stem_channels // 2, kernel_size=3, stride=1, padding=1, bias=False), build_norm_layer(self.norm_cfg, stem_channels // 2)[1], build_activation_layer(self.act_cfg), build_conv_layer( self.conv_cfg, stem_channels // 2, stem_channels, kernel_size=3, stride=1, padding=1, bias=False), build_norm_layer(self.norm_cfg, stem_channels)[1], build_activation_layer(self.act_cfg)) else: self.conv1 = build_conv_layer( self.conv_cfg, in_channels, stem_channels, kernel_size=7, stride=2, padding=3, bias=False) self.norm1_name, norm1 = build_norm_layer( self.norm_cfg, stem_channels, postfix=1) self.add_module(self.norm1_name, norm1) self.activate = build_activation_layer(self.act_cfg) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) @property def norm1(self) -> nn.Module: """nn.Module: normalization layer after the second convolution layer""" return getattr(self, self.norm1_name) def _make_layer(self, block: BasicBlock, planes: int, blocks: int, stride: int = 1, dilation: int = 1) -> nn.Module: downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( build_conv_layer( self.conv_cfg, self.inplanes, planes * block.expansion, stride=stride, kernel_size=1, dilation=dilation, bias=False), build_norm_layer(self.norm_cfg, planes * block.expansion)[1]) layers = [] layers.append( block( self.inplanes, planes, stride, downsample=downsample, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg, conv_cfg=self.conv_cfg)) self.inplanes = planes * block.expansion for _ in range(1, blocks): layers.append( block( self.inplanes, planes, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg, conv_cfg=self.conv_cfg)) return nn.Sequential(*layers) def _nostride_dilate(self, m: nn.Module, dilate: int) -> None: classname = m.__class__.__name__ if classname.find('Conv') != -1 and dilate > 1: # the convolution with stride if m.stride == (2, 2): m.stride = (1, 1) if m.kernel_size == (3, 3): m.dilation = (dilate // 2, dilate // 2) m.padding = (dilate // 2, dilate // 2) # other convolutions else: if m.kernel_size == (3, 3): m.dilation = (dilate, dilate) m.padding = (dilate, dilate) def init_weights(self, pretrained: Optional[str] = None) -> None: """Init weights for the model. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, nn.Conv2d): kaiming_init(m) elif isinstance(m, (_BatchNorm, nn.GroupNorm)): constant_init(m, 1) if self.zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): constant_init(m.norm3, 0) elif isinstance(m, BasicBlock): constant_init(m.norm2, 0) else: raise TypeError('pretrained must be a str or None') def _freeze_stages(self) -> None: """Freeze stages param and norm stats.""" if self.frozen_stages >= 0: if self.deep_stem: self.stem.eval() for param in self.stem.parameters(): param.requires_grad = False else: self.norm1.eval() for m in [self.conv1, self.norm1]: for param in m.parameters(): param.requires_grad = False for i in range(1, self.frozen_stages + 1): m = getattr(self, f'layer{i}') m.eval() for param in m.parameters(): param.requires_grad = False def forward(self, x: Tensor) -> List[Tensor]: """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ conv_out = [x] if self.deep_stem: x = self.stem(x) else: x = self.conv1(x) x = self.norm1(x) x = self.activate(x) conv_out.append(x) x = self.maxpool(x) x = self.layer1(x) conv_out.append(x) x = self.layer2(x) conv_out.append(x) x = self.layer3(x) conv_out.append(x) x = self.layer4(x) conv_out.append(x) return conv_out ================================================ FILE: mmagic/models/archs/separable_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Tuple, Union import torch.nn as nn from mmcv.cnn import ConvModule from torch import Tensor class DepthwiseSeparableConvModule(nn.Module): """Depthwise separable convolution module. See https://arxiv.org/pdf/1704.04861.pdf for details. This module can replace a ConvModule with the conv block replaced by two conv block: depthwise conv block and pointwise conv block. The depthwise conv block contains depthwise-conv/norm/activation layers. The pointwise conv block contains pointwise-conv/norm/activation layers. It should be noted that there will be norm/activation layer in the depthwise conv block if ``norm_cfg`` and ``act_cfg`` are specified. Args: in_channels (int): Same as nn.Conv2d. out_channels (int): Same as nn.Conv2d. kernel_size (int or tuple[int]): Same as nn.Conv2d. stride (int or tuple[int]): Same as nn.Conv2d. Default: 1. padding (int or tuple[int]): Same as nn.Conv2d. Default: 0. dilation (int or tuple[int]): Same as nn.Conv2d. Default: 1. norm_cfg (dict): Default norm config for both depthwise ConvModule and pointwise ConvModule. Default: None. act_cfg (dict): Default activation config for both depthwise ConvModule and pointwise ConvModule. Default: dict(type='ReLU'). dw_norm_cfg (dict): Norm config of depthwise ConvModule. If it is 'default', it will be the same as ``norm_cfg``. Default: 'default'. dw_act_cfg (dict): Activation config of depthwise ConvModule. If it is 'default', it will be the same as ``act_cfg``. Default: 'default'. pw_norm_cfg (dict): Norm config of pointwise ConvModule. If it is 'default', it will be the same as `norm_cfg`. Default: 'default'. pw_act_cfg (dict): Activation config of pointwise ConvModule. If it is 'default', it will be the same as ``act_cfg``. Default: 'default'. kwargs (optional): Other shared arguments for depthwise and pointwise ConvModule. See ConvModule for ref. """ def __init__(self, in_channels: int, out_channels: int, kernel_size: Union[int, Tuple[int, int]], stride: Union[int, Tuple[int, int]] = 1, padding: Union[int, Tuple[int, int]] = 0, dilation: Union[int, Tuple[int, int]] = 1, norm_cfg: Optional[dict] = None, act_cfg: Optional[dict] = dict(type='ReLU'), dw_norm_cfg: Union[dict, str] = 'default', dw_act_cfg: Union[dict, str] = 'default', pw_norm_cfg: Union[dict, str] = 'default', pw_act_cfg: Union[dict, str] = 'default', **kwargs): super().__init__() assert 'groups' not in kwargs, 'groups should not be specified' # if norm/activation config of depthwise/pointwise ConvModule is not # specified, use default config. dw_norm_cfg = dw_norm_cfg if dw_norm_cfg != 'default' else norm_cfg dw_act_cfg = dw_act_cfg if dw_act_cfg != 'default' else act_cfg pw_norm_cfg = pw_norm_cfg if pw_norm_cfg != 'default' else norm_cfg pw_act_cfg = pw_act_cfg if pw_act_cfg != 'default' else act_cfg # depthwise convolution self.depthwise_conv = ConvModule( in_channels, in_channels, kernel_size, stride=stride, padding=padding, dilation=dilation, groups=in_channels, norm_cfg=dw_norm_cfg, act_cfg=dw_act_cfg, **kwargs) self.pointwise_conv = ConvModule( in_channels, out_channels, 1, norm_cfg=pw_norm_cfg, act_cfg=pw_act_cfg, **kwargs) def forward(self, x: Tensor) -> Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ x = self.depthwise_conv(x) x = self.pointwise_conv(x) return x ================================================ FILE: mmagic/models/archs/simple_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional from mmengine.model import BaseModule from torch import Tensor from mmagic.registry import MODELS @MODELS.register_module() class SimpleEncoderDecoder(BaseModule): """Simple encoder-decoder model from matting. Args: encoder (dict): Config of the encoder. decoder (dict): Config of the decoder. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, encoder: dict, decoder: dict, init_cfg: Optional[dict] = None): super().__init__(init_cfg) self.encoder = MODELS.build(encoder) if hasattr(self.encoder, 'out_channels'): decoder['in_channels'] = self.encoder.out_channels self.decoder = MODELS.build(decoder) def forward(self, *args, **kwargs) -> Tensor: """Forward function. Returns: Tensor: The output tensor of the decoder. """ out = self.encoder(*args, **kwargs) out = self.decoder(out) return out ================================================ FILE: mmagic/models/archs/smpatch_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from torch import Tensor from mmagic.models.utils import generation_init_weights from mmagic.registry import MODELS @MODELS.register_module() class SoftMaskPatchDiscriminator(BaseModule): """A Soft Mask-Guided PatchGAN discriminator. Args: in_channels (int): Number of channels in input images. base_channels (int, optional): Number of channels at the first conv layer. Default: 64. num_conv (int, optional): Number of stacked intermediate convs (excluding input and output conv). Default: 3. norm_cfg (dict, optional): Config dict to build norm layer. Default: None. init_cfg (dict, optional): Config dict for initialization. `type`: The name of our initialization method. Default: 'normal'. `gain`: Scaling factor for normal, xavier and orthogonal. Default: 0.02. with_spectral_norm (bool, optional): Whether use spectral norm after the conv layers. Default: False. """ def __init__(self, in_channels: int, base_channels: Optional[int] = 64, num_conv: Optional[int] = 3, norm_cfg: Optional[dict] = None, init_cfg: Optional[dict] = dict(type='normal', gain=0.02), with_spectral_norm: Optional[bool] = False): super().__init__() kernel_size = 4 padding = 1 # input layer sequence = [ ConvModule( in_channels=in_channels, out_channels=base_channels, kernel_size=kernel_size, stride=2, padding=padding, bias=False, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=with_spectral_norm) ] # stacked intermediate layers, # gradually increasing the number of filters multiplier_in = 1 multiplier_out = 1 for n in range(1, num_conv): multiplier_in = multiplier_out multiplier_out = min(2**n, 8) sequence += [ ConvModule( in_channels=base_channels * multiplier_in, out_channels=base_channels * multiplier_out, kernel_size=kernel_size, stride=2, padding=padding, bias=False, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=with_spectral_norm) ] multiplier_in = multiplier_out multiplier_out = min(2**num_conv, 8) sequence += [ ConvModule( in_channels=base_channels * multiplier_in, out_channels=base_channels * multiplier_out, kernel_size=kernel_size, stride=1, padding=padding, bias=False, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=with_spectral_norm) ] # output one-channel prediction map sequence += [ nn.Conv2d( base_channels * multiplier_out, 1, kernel_size=kernel_size, stride=1, padding=padding) ] self.model = nn.Sequential(*sequence) self.init_type = 'normal' if init_cfg is None else init_cfg.get( 'type', 'normal') self.init_gain = 0.02 if init_cfg is None else init_cfg.get( 'gain', 0.02) def forward(self, x: Tensor) -> Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ return self.model(x) def init_weights(self) -> None: """Initialize weights for the model.""" generation_init_weights( self, init_type=self.init_type, init_gain=self.init_gain) self._is_init = True ================================================ FILE: mmagic/models/archs/sr_backbone.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from torch import Tensor from ..utils import default_init_weights # def default_init_weights(module, scale=1): # """Initialize network weights. # Args: # modules (nn.Module): Modules to be initialized. # scale (float): Scale initialized weights, especially for residual # blocks. Default: 1. # """ # for m in module.modules(): # if isinstance(m, nn.Conv2d): # kaiming_init(m, a=0, mode='fan_in', bias=0) # m.weight.data *= scale # elif isinstance(m, nn.Linear): # kaiming_init(m, a=0, mode='fan_in', bias=0) # m.weight.data *= scale # elif isinstance(m, _BatchNorm): # constant_init(m.weight, val=1, bias=0) # def make_layer(block, num_blocks, **kwarg): # """Make layers by stacking the same blocks. # Args: # block (nn.module): nn.module class for basic block. # num_blocks (int): number of blocks. # Returns: # nn.Sequential: Stacked blocks in nn.Sequential. # """ # layers = [] # for _ in range(num_blocks): # layers.append(block(**kwarg)) # return nn.Sequential(*layers) class ResidualBlockNoBN(nn.Module): """Residual block without BN. It has a style of: :: ---Conv-ReLU-Conv-+- |________________| Args: mid_channels (int): Channel number of intermediate features. Default: 64. res_scale (float): Used to scale the residual before addition. Default: 1.0. """ def __init__(self, mid_channels: int = 64, res_scale: float = 1.0): super().__init__() self.res_scale = res_scale self.conv1 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, bias=True) self.conv2 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, bias=True) self.relu = nn.ReLU(inplace=True) # if res_scale < 1.0, use the default initialization, as in EDSR. # if res_scale = 1.0, use scaled kaiming_init, as in MSRResNet. if res_scale == 1.0: self.init_weights() def init_weights(self) -> None: """Initialize weights for ResidualBlockNoBN. Initialization methods like `kaiming_init` are for VGG-style modules. For modules with residual paths, using smaller std is better for stability and performance. We empirically use 0.1. See more details in "ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks" """ for m in [self.conv1, self.conv2]: default_init_weights(m, 0.1) def forward(self, x: Tensor) -> Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ identity = x out = self.conv2(self.relu(self.conv1(x))) return identity + out * self.res_scale ================================================ FILE: mmagic/models/archs/tokenizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """This a wrapper for tokenizer.""" import copy import os import random from logging import WARNING from typing import Any, List, Optional, Union from mmengine import print_log from mmagic.utils import try_import class TokenizerWrapper: """Tokenizer wrapper for CLIPTokenizer. Only support CLIPTokenizer currently. This wrapper is modified from https://github.com/huggingface/dif fusers/blob/e51f19aee82c8dd874b715a09dbc521d88835d68/src/diffusers/loaders. py#L358 # noqa. Args: from_pretrained (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Defaults to None. from_config (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Defaults to None. *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs will be passed to `from_pretrained` function. Otherwise, *args and **kwargs will be used to initialize the model by `self._module_cls(*args, **kwargs)`. """ def __init__(self, from_pretrained: Optional[Union[str, os.PathLike]] = None, from_config: Optional[Union[str, os.PathLike]] = None, *args, **kwargs): transformers = try_import('transformers') module_cls = transformers.CLIPTokenizer assert not (from_pretrained and from_config), ( '\'from_pretrained\' and \'from_config\' should not be passed ' 'at the same time.') if from_config: print_log( 'Tokenizers from Huggingface transformers do not support ' '\'from_config\'. Will call \'from_pretrained\' instead ' 'with the same argument.', 'current', WARNING) from_pretrained = from_config if from_pretrained: self.wrapped = module_cls.from_pretrained(from_pretrained, *args, **kwargs) else: self.wrapper = module_cls(*args, **kwargs) self._from_pretrained = from_pretrained self.token_map = {} def __getattr__(self, name: str) -> Any: if name == 'wrapped': return super().__getattr__('wrapped') try: return getattr(self.wrapped, name) except AttributeError: try: return super().__getattr__(name) except AttributeError: raise AttributeError( '\'name\' cannot be found in both ' f'\'{self.__class__.__name__}\' and ' f'\'{self.__class__.__name__}.tokenizer\'.') def try_adding_tokens(self, tokens: Union[str, List[str]], *args, **kwargs): """Attempt to add tokens to the tokenizer. Args: tokens (Union[str, List[str]]): The tokens to be added. """ num_added_tokens = self.wrapped.add_tokens(tokens, *args, **kwargs) assert num_added_tokens != 0, ( f'The tokenizer already contains the token {tokens}. Please pass ' 'a different `placeholder_token` that is not already in the ' 'tokenizer.') def get_token_info(self, token: str) -> dict: """Get the information of a token, including its start and end index in the current tokenizer. Args: token (str): The token to be queried. Returns: dict: The information of the token, including its start and end index in current tokenizer. """ token_ids = self.__call__(token).input_ids start, end = token_ids[1], token_ids[-2] + 1 return {'name': token, 'start': start, 'end': end} def add_placeholder_token(self, placeholder_token: str, *args, num_vec_per_token: int = 1, **kwargs): """Add placeholder tokens to the tokenizer. Args: placeholder_token (str): The placeholder token to be added. num_vec_per_token (int, optional): The number of vectors of the added placeholder token. *args, **kwargs: The arguments for `self.wrapped.add_tokens`. """ output = [] if num_vec_per_token == 1: self.try_adding_tokens(placeholder_token, *args, **kwargs) output.append(placeholder_token) else: output = [] for i in range(num_vec_per_token): ith_token = placeholder_token + f'_{i}' self.try_adding_tokens(ith_token, *args, **kwargs) output.append(ith_token) for token in self.token_map: if token in placeholder_token: raise ValueError( f'The tokenizer already has placeholder token {token} ' f'that can get confused with {placeholder_token} ' 'keep placeholder tokens independent') self.token_map[placeholder_token] = output def replace_placeholder_tokens_in_text(self, text: Union[str, List[str]], vector_shuffle: bool = False, prop_tokens_to_load: float = 1.0 ) -> Union[str, List[str]]: """Replace the keywords in text with placeholder tokens. This function will be called in `self.__call__` and `self.encode`. Args: text (Union[str, List[str]]): The text to be processed. vector_shuffle (bool, optional): Whether to shuffle the vectors. Defaults to False. prop_tokens_to_load (float, optional): The proportion of tokens to be loaded. If 1.0, all tokens will be loaded. Defaults to 1.0. Returns: Union[str, List[str]]: The processed text. """ if isinstance(text, list): output = [] for i in range(len(text)): output.append( self.replace_placeholder_tokens_in_text( text[i], vector_shuffle=vector_shuffle)) return output for placeholder_token in self.token_map: if placeholder_token in text: tokens = self.token_map[placeholder_token] tokens = tokens[:1 + int(len(tokens) * prop_tokens_to_load)] if vector_shuffle: tokens = copy.copy(tokens) random.shuffle(tokens) text = text.replace(placeholder_token, ' '.join(tokens)) return text def replace_text_with_placeholder_tokens(self, text: Union[str, List[str]] ) -> Union[str, List[str]]: """Replace the placeholder tokens in text with the original keywords. This function will be called in `self.decode`. Args: text (Union[str, List[str]]): The text to be processed. Returns: Union[str, List[str]]: The processed text. """ if isinstance(text, list): output = [] for i in range(len(text)): output.append( self.replace_text_with_placeholder_tokens(text[i])) return output for placeholder_token, tokens in self.token_map.items(): merged_tokens = ' '.join(tokens) if merged_tokens in text: text = text.replace(merged_tokens, placeholder_token) return text def __call__(self, text: Union[str, List[str]], *args, vector_shuffle: bool = False, prop_tokens_to_load: float = 1.0, **kwargs): """The call function of the wrapper. Args: text (Union[str, List[str]]): The text to be tokenized. vector_shuffle (bool, optional): Whether to shuffle the vectors. Defaults to False. prop_tokens_to_load (float, optional): The proportion of tokens to be loaded. If 1.0, all tokens will be loaded. Defaults to 1.0 *args, **kwargs: The arguments for `self.wrapped.__call__`. """ replaced_text = self.replace_placeholder_tokens_in_text( text, vector_shuffle=vector_shuffle, prop_tokens_to_load=prop_tokens_to_load) return self.wrapped.__call__(replaced_text, *args, **kwargs) def encode(self, text: Union[str, List[str]], *args, **kwargs): """Encode the passed text to token index. Args: text (Union[str, List[str]]): The text to be encode. *args, **kwargs: The arguments for `self.wrapped.__call__`. """ replaced_text = self.replace_placeholder_tokens_in_text(text) return self.wrapped(replaced_text, *args, **kwargs) def decode(self, token_ids, return_raw: bool = False, *args, **kwargs) -> Union[str, List[str]]: """Decode the token index to text. Args: token_ids: The token index to be decoded. return_raw: Whether keep the placeholder token in the text. Defaults to False. *args, **kwargs: The arguments for `self.wrapped.decode`. Returns: Union[str, List[str]]: The decoded text. """ text = self.wrapped.decode(token_ids, *args, **kwargs) if return_raw: return text replaced_text = self.replace_text_with_placeholder_tokens(text) return replaced_text def __repr__(self): """The representation of the wrapper.""" s = super().__repr__() prefix = f'Wrapped Module Class: {self._module_cls}\n' prefix += f'Wrapped Module Name: {self._module_name}\n' if self._from_pretrained: prefix += f'From Pretrained: {self._from_pretrained}\n' s = prefix + s return s ================================================ FILE: mmagic/models/archs/upsample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn import torch.nn.functional as F from torch import Tensor from .sr_backbone import default_init_weights class PixelShufflePack(nn.Module): """Pixel Shuffle upsample layer. Args: in_channels (int): Number of input channels. out_channels (int): Number of output channels. scale_factor (int): Upsample ratio. upsample_kernel (int): Kernel size of Conv layer to expand channels. Returns: Upsampled feature map. """ def __init__(self, in_channels: int, out_channels: int, scale_factor: int, upsample_kernel: int): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.scale_factor = scale_factor self.upsample_kernel = upsample_kernel self.upsample_conv = nn.Conv2d( self.in_channels, self.out_channels * scale_factor * scale_factor, self.upsample_kernel, padding=(self.upsample_kernel - 1) // 2) self.init_weights() def init_weights(self) -> None: """Initialize weights for PixelShufflePack.""" default_init_weights(self, 1) def forward(self, x: Tensor) -> Tensor: """Forward function for PixelShufflePack. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.upsample_conv(x) x = F.pixel_shuffle(x, self.scale_factor) return x ================================================ FILE: mmagic/models/archs/vgg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Optional import torch.nn as nn from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init, xavier_init from torch import Tensor from mmagic.registry import MODELS from ..archs.aspp import ASPP @MODELS.register_module() class VGG16(BaseModule): """Customized VGG16 Encoder. A 1x1 conv is added after the original VGG16 conv layers. The indices of max pooling layers are returned for unpooling layers in decoders. Args: in_channels (int): Number of input channels. batch_norm (bool, optional): Whether use ``nn.BatchNorm2d``. Default to False. aspp (bool, optional): Whether use ASPP module after the last conv layer. Default to False. dilations (list[int], optional): Atrous rates of ASPP module. Default to None. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, in_channels: int, batch_norm: Optional[bool] = False, aspp: Optional[bool] = False, dilations: Optional[List[int]] = None, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) self.batch_norm = batch_norm self.aspp = aspp self.dilations = dilations self.layer1 = self._make_layer(in_channels, 64, 2) self.layer2 = self._make_layer(64, 128, 2) self.layer3 = self._make_layer(128, 256, 3) self.layer4 = self._make_layer(256, 512, 3) self.layer5 = self._make_layer(512, 512, 3) self.conv6 = nn.Conv2d(512, 512, kernel_size=1) if self.batch_norm: self.bn = nn.BatchNorm2d(512) self.relu = nn.ReLU(inplace=True) if self.aspp: self.aspp = ASPP(512, dilations=self.dilations) self.out_channels = 256 else: self.out_channels = 512 def _make_layer(self, inplanes: int, planes: int, convs_layers: int) -> nn.Module: layers = [] for _ in range(convs_layers): conv2d = nn.Conv2d(inplanes, planes, kernel_size=3, padding=1) if self.batch_norm: bn = nn.BatchNorm2d(planes) layers += [conv2d, bn, nn.ReLU(inplace=True)] else: layers += [conv2d, nn.ReLU(inplace=True)] inplanes = planes layers += [nn.MaxPool2d(kernel_size=2, stride=2, return_indices=True)] return nn.Sequential(*layers) def init_weights(self) -> None: """Init weights for the model.""" if self.init_cfg is not None: super().init_weights() else: # Default initialization for m in self.modules(): if isinstance(m, nn.Conv2d): xavier_init(m) elif isinstance(m, nn.BatchNorm2d): constant_init(m, 1) def forward(self, x: Tensor) -> Dict[str, Tensor]: """Forward function for ASPP module. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: dict: Dict containing output tensor and maxpooling indices. """ out, max_idx_1 = self.layer1(x) out, max_idx_2 = self.layer2(out) out, max_idx_3 = self.layer3(out) out, max_idx_4 = self.layer4(out) out, max_idx_5 = self.layer5(out) out = self.conv6(out) if self.batch_norm: out = self.bn(out) out = self.relu(out) if self.aspp: out = self.aspp(out) return { 'out': out, 'max_idx_1': max_idx_1, 'max_idx_2': max_idx_2, 'max_idx_3': max_idx_3, 'max_idx_4': max_idx_4, 'max_idx_5': max_idx_5 } ================================================ FILE: mmagic/models/archs/wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from logging import WARNING from typing import Any, List, Optional, Union import torch from mmengine import print_log from mmengine.model import BaseModule from torch import dtype as TORCH_DTYPE dtype_mapping = { 'float32': torch.float32, 'float16': torch.float16, 'fp32': torch.float32, 'fp16': torch.float16, 'half': torch.float16, } class DiffusersWrapper(BaseModule): """Wrapper for models from HuggingFace Diffusers. This wrapper will be set a attribute called `_module_cls` by wrapping function and will be used to initialize the model structure. Example: >>> 1. Load pretrained model from HuggingFace Space. >>> config = dict( >>> type='ControlNetModel', # has been registered in `MODELS` >>> from_pretrained='lllyasviel/sd-controlnet-canny', >>> torch_dtype=torch.float16) >>> controlnet = MODELS.build(config) >>> 2. Initialize model with pre-defined configs. >>> config = dict( >>> type='ControlNetModel', # has been registered in `MODELS` >>> from_config='lllyasviel/sd-controlnet-canny', >>> cache_dir='~/.cache/OpenMMLab') >>> controlnet = MODELS.build(config) >>> 3. Initialize model with own defined arguments >>> config = dict( >>> type='ControlNetModel', # has been registered in `MODELS` >>> in_channels=3, >>> down_block_types=['DownBlock2D'], >>> block_out_channels=(32, ), >>> conditioning_embedding_out_channels=(16, )) >>> controlnet = MODELS.build(config) Args: from_pretrained (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Please refers to `diffusers.model.modeling_utils.ModelMixin.from_pretrained` for more detail. Defaults to None. from_config (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Please refers to `diffusers.configuration_utils.ConfigMixin.load_config` for more detail. Defaults to None. init_cfg (dict or List[dict], optional): Initialization config dict. Noted that, in `DiffuserWrapper`, if you want to load pretrained weight from HuggingFace space, please use `from_pretrained` argument instead of using `init_cfg`. Defaults to None. *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs will be passed to `from_pretrained` function. If `from_config` is passed, *args and **kwargs will be passed to `load_config` function. Otherwise, *args and **kwargs will be used to initialize the model by `self._module_cls(*args, **kwargs)`. """ def __init__(self, from_pretrained: Optional[Union[str, os.PathLike]] = None, from_config: Optional[Union[str, os.PathLike]] = None, dtype: Optional[Union[str, TORCH_DTYPE]] = None, init_cfg: Union[dict, List[dict], None] = None, *args, **kwargs): super().__init__(init_cfg) module_cls = self._module_cls assert not (from_pretrained and from_config), ( '\'from_pretrained\' and \'from_config\' should not be passed ' 'at the same time.') self._from_pretrained = from_pretrained self._from_config = from_config if from_pretrained is not None: self.model = module_cls.from_pretrained(from_pretrained, *args, **kwargs) # weight has been initialized from pretrained, therefore we # `self._is_init` as True manually self._is_init = True elif from_config is not None: _config = module_cls.load_config(from_config, *args, **kwargs) self.model = module_cls(**_config) else: self.model = module_cls(*args, **kwargs) if dtype is not None: if isinstance(dtype, str): assert dtype in dtype_mapping, ( 'Only support following dtype string: ' f'{list(dtype_mapping.keys())}, but receive {dtype}.') dtype = dtype_mapping[dtype] self.model.to(dtype) print_log(f'Set model dtype to \'{dtype}\'.', 'current') self.config = self.model.config def init_weights(self): """Initialize the weights. If type is 'Pretrained' but the model has be loaded from `repo_id`, a warning will be raised. """ if self.init_cfg and self.init_cfg['type'] == 'Pretrained': if self._from_pretrained is not None: print_log( 'Has been loaded from pretrained model from ' f'\'{self._from_pretrained}\'. Your behavior is ' 'very dangerous.', 'current', WARNING) super().init_weights() def __getattr__(self, name: str) -> Any: """This function provide a way to access the attributes of the wrapped model. Args: name (str): The name of the attribute. Returns: Any: The got attribute. """ # Q: why we need end of recursion for 'model'? # A: In `nn.Module.__setattr__`, if value is instance of `nn.Module`, # it will be removed from `__dict__` and added to # `__dict__._modules`. Therefore, `model` cannot be found in # `self.__dict__`. When we call `self.model`, python cannot found # 'model' in `self.__dict__` and then `self.__getattr__('model')` # will be called. If we call `self.model` in `self.__getattr__` # which does not have any exit about 'model',`RecursionError` # will be raised. if name == 'model': return super().__getattr__('model') try: return getattr(self.model, name) except AttributeError: try: return super().__getattr__(name) except AttributeError: raise AttributeError('\'name\' cannot be found in both ' f'\'{self.__class__.__name__}\' and ' f'\'{self.__class__.__name__}.model\'.') def __repr__(self): """The representation of the wrapper.""" s = super().__repr__() prefix = f'Wrapped Module Class: {self._module_cls}\n' prefix += f'Wrapped Module Name: {self._module_name}\n' if self._from_pretrained: prefix += f'From Pretrained: {self._from_pretrained}\n' if self._from_config: prefix += f'From Config: {self._from_config}\n' s = prefix + s return s def forward(self, *args, **kwargs) -> Any: """Forward function of wrapped module. Args: *args, **kwargs: The arguments of the wrapped module. Returns: Any: The output of wrapped module's forward function. """ return self.model(*args, **kwargs) def to( self, torch_device: Optional[Union[str, torch.device]] = None, torch_dtype: Optional[torch.dtype] = None, ): """Put wrapped module to device or convert it to torch_dtype. There are two to() function. One is nn.module.to() and the other is diffusers.pipeline.to(), if both args are passed, diffusers.pipeline.to() is called. Args: torch_device: The device to put to. torch_dtype: The type to convert to. Returns: self: the wrapped module itself. """ if torch_dtype is None: self.model.to(torch_device) else: self.model.to(torch_device, torch_dtype) return self ================================================ FILE: mmagic/models/base_models/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .average_model import ExponentialMovingAverage, RampUpEMA from .base_conditional_gan import BaseConditionalGAN from .base_edit_model import BaseEditModel from .base_gan import BaseGAN from .base_mattor import BaseMattor from .base_translation_model import BaseTranslationModel from .basic_interpolator import BasicInterpolator from .one_stage import OneStageInpaintor from .two_stage import TwoStageInpaintor __all__ = [ 'BaseEditModel', 'BaseGAN', 'BaseConditionalGAN', 'BaseMattor', 'BasicInterpolator', 'BaseTranslationModel', 'OneStageInpaintor', 'TwoStageInpaintor', 'ExponentialMovingAverage', 'RampUpEMA', ] ================================================ FILE: mmagic/models/base_models/average_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import itertools import warnings from typing import List, Optional import torch import torch.nn as nn from mmengine.model import BaseAveragedModel from torch import Tensor from mmagic.registry import MODELS # NOTICE: Since mmengine do not support loading ``state_dict`` without wrap # ema module with ``BaseAveragedModel`` currently, we rewrite # ``ExponentialMovingAverage`` and add ``_load_from_state_dict`` temporarily @MODELS.register_module() class ExponentialMovingAverage(BaseAveragedModel): r"""Implements the exponential moving average (EMA) of the model. All parameters are updated by the formula as below: .. math:: Xema_{t+1} = (1 - momentum) * Xema_{t} + momentum * X_t Args: model (nn.Module): The model to be averaged. momentum (float): The momentum used for updating ema parameter. Defaults to 0.0002. Ema's parameter are updated with the formula :math:`averaged\_param = (1-momentum) * averaged\_param + momentum * source\_param`. interval (int): Interval between two updates. Defaults to 1. device (torch.device, optional): If provided, the averaged model will be stored on the :attr:`device`. Defaults to None. update_buffers (bool): if True, it will compute running averages for both the parameters and the buffers of the model. Defaults to False. """ # noqa: W605 def __init__(self, model: nn.Module, momentum: float = 0.0002, interval: int = 1, device: Optional[torch.device] = None, update_buffers: bool = False) -> None: super().__init__(model, interval, device, update_buffers) assert 0.0 < momentum < 1.0, 'momentum must be in range (0.0, 1.0)'\ f'but got {momentum}' if momentum > 0.5: warnings.warn( 'The value of momentum in EMA is usually a small number,' 'which is different from the conventional notion of ' f'momentum but got {momentum}. Please make sure the ' f'value is correct.') self.momentum = momentum def avg_func(self, averaged_param: Tensor, source_param: Tensor, steps: int) -> None: """Compute the moving average of the parameters using exponential moving average. Args: averaged_param (Tensor): The averaged parameters. source_param (Tensor): The source parameters. steps (int): The number of times the parameters have been updated. """ averaged_param.mul_(1 - self.momentum).add_( source_param, alpha=self.momentum) def _load_from_state_dict(self, state_dict: dict, prefix: str, local_metadata: dict, strict: bool, missing_keys: list, unexpected_keys: list, error_msgs: List[str]) -> None: """Overrides ``nn.Module._load_from_state_dict`` to support loading ``state_dict`` without wrap ema module with ``BaseAveragedModel``. In OpenMMLab 1.0, model will not wrap ema submodule with ``BaseAveragedModel``, and the ema weight key in `state_dict` will miss `module` prefix. Therefore, ``BaseAveragedModel`` need to automatically add the ``module`` prefix if the corresponding key in ``state_dict`` misses it. Args: state_dict (dict): A dict containing parameters and persistent buffers. prefix (str): The prefix for parameters and buffers used in this module local_metadata (dict): a dict containing the metadata for this module. strict (bool): Whether to strictly enforce that the keys in :attr:`state_dict` with :attr:`prefix` match the names of parameters and buffers in this module missing_keys (List[str]): if ``strict=True``, add missing keys to this list unexpected_keys (List[str]): if ``strict=True``, add unexpected keys to this list error_msgs (List[str]): error messages should be added to this list, and will be reported together in :meth:`~torch.nn.Module.load_state_dict`. """ for key, value in list(state_dict.items()): # To support load the pretrained model, which does not wrap ema # module with `BaseAveragedModel`, `BaseAveragedModel` will # automatically add `module` prefix to the `state_dict` which # key starts with the custom prefix. For example, the old # checkpoint with `state_dict` with keys: # ['layer.weight', 'layer.bias', 'ema.steps', 'ema.weight', 'ema.bias'] # noqa: E501 # will be replaced with: # ['layer.weight', 'layer.bias', 'ema.steps', 'ema.module.weight', 'ema.module.bias'] # noqa: E501 # The key added with `module` prefix needs to satisfy # three conditions. # 1. key starts with current prefix, such as `model.ema`. # 2. The content after the prefix does not start with the `module` # 3. Key does not end with steps. if key.startswith(prefix) and not key[len(prefix):].startswith( 'module') and not key.endswith('steps'): new_key = key[:len(prefix)] + 'module.' + key[len(prefix):] state_dict[new_key] = value state_dict.pop(key) state_dict.setdefault(prefix + 'steps', torch.tensor(0)) super()._load_from_state_dict(state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs) def sync_buffers(self, model: nn.Module) -> None: """Copy buffer from model to averaged model. Args: model (nn.Module): The model whose parameters will be averaged. """ # if not update buffer, copy buffer from orig model if self.update_buffers: warnings.warn( '`update_buffers` is set to True in this ema model, and ' 'buffers will be updated in `update_parameters`.') avg_buffer = itertools.chain(self.module.buffers()) orig_buffer = itertools.chain(model.buffers()) for b_avg, b_orig in zip(avg_buffer, orig_buffer): b_avg.data.copy_(b_orig.data) def sync_parameters(self, model: nn.Module) -> None: """Copy buffer and parameters from model to averaged model. Args: model (nn.Module): The model whose parameters will be averaged. """ # before ema, copy weights from orig avg_param = ( itertools.chain(self.module.parameters(), self.module.buffers())) src_param = (itertools.chain(model.parameters(), model.buffers())) for p_avg, p_src in zip(avg_param, src_param): p_avg.data.copy_(p_src.data) @MODELS.register_module() class RampUpEMA(BaseAveragedModel): r"""Implements the exponential moving average with ramping up momentum. Ref: https://github.com/NVlabs/stylegan3/blob/master/training/training_loop.py # noqa Args: model (nn.Module): The model to be averaged. interval (int): Interval between two updates. Defaults to 1. ema_kimg (int, optional): EMA kimgs. Defaults to 10. ema_rampup (float, optional): Ramp up rate. Defaults to 0.05. batch_size (int, optional): Global batch size. Defaults to 32. eps (float, optional): Ramp up epsilon. Defaults to 1e-8. start_iter (int, optional): EMA start iter. Defaults to 0. device (torch.device, optional): If provided, the averaged model will be stored on the :attr:`device`. Defaults to None. update_buffers (bool): if True, it will compute running averages for both the parameters and the buffers of the model. Defaults to False. """ # noqa: W605 def __init__(self, model: nn.Module, interval: int = 1, ema_kimg: int = 10, ema_rampup: float = 0.05, batch_size: int = 32, eps: float = 1e-8, start_iter: int = 0, device: Optional[torch.device] = None, update_buffers: bool = False) -> None: """_summary_""" super().__init__(model, interval, device, update_buffers) self.interval = interval self.ema_kimg = ema_kimg self.ema_rampup = ema_rampup self.batch_size = batch_size self.eps = eps @staticmethod def rampup(steps, ema_kimg=10, ema_rampup=0.05, batch_size=4, eps=1e-8): """Ramp up ema momentum. Ref: https://github.com/NVlabs/stylegan3/blob/a5a69f58294509598714d1e88c9646c3d7c6ec94/training/training_loop.py#L300-L308 # noqa Args: steps: ema_kimg (int, optional): Half-life of the exponential moving average of generator weights. Defaults to 10. ema_rampup (float, optional): EMA ramp-up coefficient.If set to None, then rampup will be disabled. Defaults to 0.05. batch_size (int, optional): Total batch size for one training iteration. Defaults to 4. eps (float, optional): Epsiolon to avoid ``batch_size`` divided by zero. Defaults to 1e-8. Returns: dict: Updated momentum. """ cur_nimg = (steps + 1) * batch_size ema_nimg = ema_kimg * 1000 if ema_rampup is not None: ema_nimg = min(ema_nimg, cur_nimg * ema_rampup) ema_beta = 0.5**(batch_size / max(ema_nimg, eps)) return ema_beta def avg_func(self, averaged_param: Tensor, source_param: Tensor, steps: int) -> None: """Compute the moving average of the parameters using exponential moving average. Args: averaged_param (Tensor): The averaged parameters. source_param (Tensor): The source parameters. steps (int): The number of times the parameters have been updated. """ momentum = 1. - self.rampup(self.steps, self.ema_kimg, self.ema_rampup, self.batch_size, self.eps) if not (0.0 < momentum < 1.0): warnings.warn('RampUp momentum must be in range (0.0, 1.0)' f'but got {momentum}') averaged_param.mul_(1 - momentum).add_(source_param, alpha=momentum) def _load_from_state_dict(self, state_dict: dict, prefix: str, local_metadata: dict, strict: bool, missing_keys: list, unexpected_keys: list, error_msgs: List[str]) -> None: """Overrides ``nn.Module._load_from_state_dict`` to support loading ``state_dict`` without wrap ema module with ``BaseAveragedModel``. In OpenMMLab 1.0, model will not wrap ema submodule with ``BaseAveragedModel``, and the ema weight key in `state_dict` will miss `module` prefix. Therefore, ``BaseAveragedModel`` need to automatically add the ``module`` prefix if the corresponding key in ``state_dict`` misses it. Args: state_dict (dict): A dict containing parameters and persistent buffers. prefix (str): The prefix for parameters and buffers used in this module local_metadata (dict): a dict containing the metadata for this module. strict (bool): Whether to strictly enforce that the keys in :attr:`state_dict` with :attr:`prefix` match the names of parameters and buffers in this module missing_keys (List[str]): if ``strict=True``, add missing keys to this list unexpected_keys (List[str]): if ``strict=True``, add unexpected keys to this list error_msgs (List[str]): error messages should be added to this list, and will be reported together in :meth:`~torch.nn.Module.load_state_dict`. """ for key, value in list(state_dict.items()): # To support load the pretrained model, which does not wrap ema # module with `BaseAveragedModel`, `BaseAveragedModel` will # automatically add `module` prefix to the `state_dict` which # key starts with the custom prefix. For example, the old # checkpoint with `state_dict` with keys: # ['layer.weight', 'layer.bias', 'ema.steps', 'ema.weight', 'ema.bias'] # noqa: E501 # will be replaced with: # ['layer.weight', 'layer.bias', 'ema.steps', 'ema.module.weight', 'ema.module.bias'] # noqa: E501 # The key added with `module` prefix needs to satisfy # three conditions. # 1. key starts with current prefix, such as `model.ema`. # 2. The content after the prefix does not start with the `module` # 3. Key does not end with steps. if key.startswith(prefix) and not key[len(prefix):].startswith( 'module') and not key.endswith('steps'): new_key = key[:len(prefix)] + 'module.' + key[len(prefix):] state_dict[new_key] = value state_dict.pop(key) state_dict.setdefault(prefix + 'steps', torch.tensor(0)) super()._load_from_state_dict(state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs) def sync_buffers(self, model: nn.Module) -> None: """Copy buffer from model to averaged model. Args: model (nn.Module): The model whose parameters will be averaged. """ # if not update buffer, copy buffer from orig model if self.update_buffers: warnings.warn( '`update_buffers` is set to True in this ema model, and ' 'buffers will be updated in `update_parameters`.') avg_buffer = itertools.chain(self.module.buffers()) orig_buffer = itertools.chain(model.buffers()) for b_avg, b_orig in zip(avg_buffer, orig_buffer): b_avg.data.copy_(b_orig.data) def sync_parameters(self, model: nn.Module) -> None: """Copy buffer and parameters from model to averaged model. Args: model (nn.Module): The model whose parameters will be averaged. """ # before ema, copy weights from orig avg_param = ( itertools.chain(self.module.parameters(), self.module.buffers())) src_param = (itertools.chain(model.parameters(), model.buffers())) for p_avg, p_src in zip(avg_param, src_param): p_avg.data.copy_(p_src.data) ================================================ FILE: mmagic/models/base_models/base_conditional_gan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn from mmengine import Config from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, LabelVar from ..utils import get_valid_num_batches, label_sample_fn from .base_gan import BaseGAN ModelType = Union[Dict, nn.Module] class BaseConditionalGAN(BaseGAN): """Base class for Conditional GAM models. Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): The number of times the generator is completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): The number of times the discriminator is completely updated before the generator is updated. Defaults to 1. noise_size (Optional[int]): Size of the input noise vector. Default to None. num_classes (Optional[int]): The number classes you would like to generate. Defaults to None. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, noise_size: Optional[int] = None, num_classes: Optional[int] = None, ema_config: Optional[Dict] = None, loss_config: Optional[Dict] = None): self.num_classes = self._get_valid_num_classes(num_classes, generator, discriminator) super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, noise_size, ema_config, loss_config) def label_fn(self, label: LabelVar = None, num_batches: int = 1) -> Tensor: """Sampling function for label. There are three scenarios in this function: - If `label` is a callable function, sample `num_batches` of labels with passed `label`. - If `label` is `None`, sample `num_batches` of labels in range of `[0, self.num_classes-1]` uniformly. - If `label` is a `torch.Tensor`, check the range of the tensor is in `[0, self.num_classes-1]`. If all values are in valid range, directly return `label`. Args: label (Union[Tensor, Callable, List[int], None]): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. Defaults to `None`. num_batches (int, optional): The number of batches label want to sample. If `label` is a Tensor, this will be ignored. Defaults to 1. Returns: Tensor: Sampled label tensor. """ return label_sample_fn( label=label, num_batches=num_batches, num_classes=self.num_classes, device=self.device) def data_sample_to_label(self, data_sample: DataSample ) -> Optional[torch.Tensor]: """Get labels from input `data_sample` and pack to `torch.Tensor`. If no label is found in the passed `data_sample`, `None` would be returned. Args: data_sample (DataSample): Input data samples. Returns: Optional[torch.Tensor]: Packed label tensor. """ # assume all data_sample have the same data fields if not data_sample or 'gt_label' not in data_sample.keys(): return None gt_labels = data_sample.gt_label.label return gt_labels @staticmethod def _get_valid_num_classes(num_classes: Optional[int], generator: ModelType, discriminator: Optional[ModelType]) -> int: """Try to get the value of `num_classes` from input, `generator` and `discriminator` and check the consistency of these values. If no conflict is found, return the `num_classes`. Args: num_classes (Optional[int]): `num_classes` passed to `BaseConditionalGAN_refactor`'s initialize function. generator (ModelType): The config or the model of generator. discriminator (Optional[ModelType]): The config or model of discriminator. Returns: int: The number of classes to be generated. """ if isinstance(generator, dict): num_classes_gen = generator.get('num_classes', None) else: num_classes_gen = getattr(generator, 'num_classes', None) num_classes_disc = None if discriminator is not None: if isinstance(discriminator, dict): num_classes_disc = discriminator.get('num_classes', None) else: num_classes_disc = getattr(discriminator, 'num_classes', None) # check consistency between gen and disc if num_classes_gen is not None and num_classes_disc is not None: assert num_classes_disc == num_classes_gen, ( '\'num_classes\' is inconsistent between generator and ' f'discriminator. Receive \'{num_classes_gen}\' and ' f'\'{num_classes_disc}\'.') model_num_classes = num_classes_gen or num_classes_disc if num_classes is not None and model_num_classes is not None: assert num_classes == model_num_classes, ( 'Input \'num_classes\' is inconsistent with ' f'model\'s ones. Receive \'{num_classes}\' and ' f'\'{model_num_classes}\'.') num_classes = num_classes or model_num_classes return num_classes def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: """Sample images with the given inputs. If forward mode is 'ema' or 'orig', the image generated by corresponding generator will be returned. If forward mode is 'ema/orig', images generated by original generator and EMA generator will both be returned in a dict. Args: inputs (ForwardInputs): Dict containing the necessary information (e.g. noise, num_batches, mode) to generate image. data_samples (Optional[list]): Data samples collated by :attr:`data_preprocessor`. Defaults to None. mode (Optional[str]): `mode` is not used in :class:`BaseConditionalGAN`. Defaults to None. Returns: List[DataSample]: Generated images or image dict. """ if isinstance(inputs, Tensor): noise = inputs sample_kwargs = {} else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) sample_kwargs = inputs.get('sample_kwargs', dict()) num_batches = noise.shape[0] labels = self.data_sample_to_label(data_samples) if labels is None: labels = self.label_fn(num_batches=num_batches) sample_model = self._get_valid_model(inputs) batch_sample_list = [] if sample_model in ['ema', 'orig']: if sample_model == 'ema': generator = self.generator_ema else: generator = self.generator outputs = generator(noise, label=labels, return_noise=False) outputs = self.data_preprocessor.destruct(outputs, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.fake_img = outputs gen_sample.noise = noise gen_sample.set_gt_label(labels) gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = sample_model batch_sample_list = gen_sample.split(allow_nonseq_value=True) else: # sample model in 'ema/orig' outputs_orig = self.generator( noise, label=labels, return_noise=False, **sample_kwargs) outputs_ema = self.generator_ema( noise, label=labels, return_noise=False, **sample_kwargs) outputs_orig = self.data_preprocessor.destruct( outputs_orig, data_samples) outputs_ema = self.data_preprocessor.destruct( outputs_ema, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.ema = DataSample(fake_img=outputs_ema) gen_sample.orig = DataSample(fake_img=outputs_orig) gen_sample.noise = noise gen_sample.set_gt_label(labels) gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = 'ema/orig' batch_sample_list = gen_sample.split(allow_nonseq_value=True) return batch_sample_list def train_generator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Training function for discriminator. All GANs should implement this function by themselves. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = inputs['img'].shape[0] noise = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) fake_imgs = self.generator( noise=noise, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) data_dict_ = dict( gen=self.generator, disc=self.discriminator, fake_imgs=fake_imgs, disc_pred_fake_g=disc_pred_fake, # iteration=curr_iter, batch_size=num_batches, fake_label=fake_labels, loss_scaler=getattr(optimizer_wrapper, 'loss_scaler', None)) parsed_loss, log_vars = self._get_gen_loss(data_dict_) optimizer_wrapper.update_params(parsed_loss) return log_vars def train_discriminator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Training function for discriminator. All GANs should implement this function by themselves. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = inputs['img'] real_labels = self.data_sample_to_label(data_samples) assert real_labels is not None, ( 'Cannot found \'gt_label\' in \'data_sample\'.') num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise=noise_batch, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) disc_pred_real = self.discriminator(real_imgs, label=real_labels) data_dict_ = dict( gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs, # iteration=curr_iter, batch_size=num_batches, gt_label=real_labels, fake_label=fake_labels, loss_scaler=setattr(optimizer_wrapper, 'loss_scaler', None)) loss, log_vars = self._get_disc_loss(data_dict_) optimizer_wrapper.update_params(loss) return log_vars ================================================ FILE: mmagic/models/base_models/base_edit_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Optional, Union import torch from mmengine.model import BaseModel from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class BaseEditModel(BaseModel): """Base model for image and video editing. It must contain a generator that takes frames as inputs and outputs an interpolated frame. It also has a pixel-wise loss for training. Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. Default: None. """ def __init__(self, generator: dict, pixel_loss: dict, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None, init_cfg: Optional[dict] = None, data_preprocessor: Optional[dict] = None): super().__init__( init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.train_cfg = train_cfg self.test_cfg = test_cfg # generator self.generator = MODELS.build(generator) # loss self.pixel_loss = MODELS.build(pixel_loss) def forward(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs) -> Union[torch.Tensor, List[DataSample], dict]: """Returns losses or predictions of training, validation, testing, and simple inference process. ``forward`` method of BaseModel is an abstract method, its subclasses must implement this method. Accepts ``inputs`` and ``data_samples`` processed by :attr:`data_preprocessor`, and returns results according to mode arguments. During non-distributed training, validation, and testing process, ``forward`` will be called by ``BaseModel.train_step``, ``BaseModel.val_step`` and ``BaseModel.val_step`` directly. During distributed data parallel training process, ``MMSeparateDistributedDataParallel.train_step`` will first call ``DistributedDataParallel.forward`` to enable automatic gradient synchronization, and then call ``forward`` to get training loss. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor``. Default: 'tensor'. - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict`` or tensor for custom use. """ if isinstance(inputs, dict): inputs = inputs['img'] if mode == 'tensor': return self.forward_tensor(inputs, data_samples, **kwargs) elif mode == 'predict': predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'loss': return self.forward_train(inputs, data_samples, **kwargs) def convert_to_datasample(self, predictions: DataSample, data_samples: DataSample, inputs: Optional[torch.Tensor] ) -> List[DataSample]: """Add predictions and destructed inputs (if passed) to data samples. Args: predictions (DataSample): The predictions of the model. data_samples (DataSample): The data samples loaded from dataloader. inputs (Optional[torch.Tensor]): The input of model. Defaults to None. Returns: List[DataSample]: Modified data samples. """ if inputs is not None: destructed_input = self.data_preprocessor.destruct( inputs, data_samples, 'img') data_samples.set_tensor_data({'input': destructed_input}) # split to list of data samples data_samples = data_samples.split() predictions = predictions.split() for data_sample, pred in zip(data_samples, predictions): data_sample.output = pred return data_samples def forward_tensor(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, **kwargs) -> torch.Tensor: """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: result of simple forward. """ feats = self.generator(inputs, **kwargs) return feats def forward_inference(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, **kwargs) -> DataSample: """Forward inference. Returns predictions of validation, testing, and simple inference. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: DataSample: predictions. """ feats = self.forward_tensor(inputs, data_samples, **kwargs) feats = self.data_preprocessor.destruct(feats, data_samples) # create a stacked data sample here predictions = DataSample(pred_img=feats.cpu()) return predictions def forward_train(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, **kwargs) -> Dict[str, torch.Tensor]: """Forward training. Returns dict of losses of training. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ feats = self.forward_tensor(inputs, data_samples, **kwargs) batch_gt_data = data_samples.gt_img loss = self.pixel_loss(feats, batch_gt_data) return dict(loss=loss) ================================================ FILE: mmagic/models/base_models/base_gan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from abc import ABCMeta from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn from mmengine import Config, MessageHub from mmengine.model import BaseModel, is_model_wrapper from mmengine.optim import OptimWrapper, OptimWrapperDict from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, NoiseVar, SampleList from ..utils import (get_valid_noise_size, get_valid_num_batches, noise_sample_fn, set_requires_grad) ModelType = Union[Dict, nn.Module] class BaseGAN(BaseModel, metaclass=ABCMeta): """Base class for GAN models. Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): The number of times the generator is completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): The number of times the discriminator is completely updated before the generator is updated. Defaults to 1. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, noise_size: Optional[int] = None, ema_config: Optional[Dict] = None, loss_config: Optional[Dict] = None): super().__init__(data_preprocessor=data_preprocessor) # get valid noise_size noise_size = get_valid_noise_size(noise_size, generator) # build generator if isinstance(generator, dict): self._gen_cfg = deepcopy(generator) # build generator with default `noise_size` and `num_classes` gen_args = dict() if noise_size: gen_args['noise_size'] = noise_size if hasattr(self, 'num_classes') and self.num_classes is not None: gen_args['num_classes'] = self.num_classes generator = MODELS.build(generator, default_args=gen_args) self.generator = generator # get noise_size from generator because generator may have default # `noise_size` value self.noise_size = getattr(self.generator, 'noise_size', noise_size) # build discriminator if discriminator: if isinstance(discriminator, dict): self._disc_cfg = deepcopy(discriminator) # build discriminator with default `num_classes` disc_args = dict() if hasattr(self, 'num_classes'): disc_args['num_classes'] = self.num_classes discriminator = MODELS.build( discriminator, default_args=disc_args) self.discriminator = discriminator self._gen_steps = generator_steps self._disc_steps = discriminator_steps if ema_config is None: self._ema_config = None self._with_ema_gen = False else: self._ema_config = deepcopy(ema_config) self._init_ema_model(self._ema_config) self._with_ema_gen = True self._init_loss(loss_config) @staticmethod def gather_log_vars(log_vars_list: List[Dict[str, Tensor]] ) -> Dict[str, Tensor]: """Gather a list of log_vars. Args: log_vars_list: List[Dict[str, Tensor]] Returns: Dict[str, Tensor] """ if len(log_vars_list) == 1: return log_vars_list[0] log_keys = log_vars_list[0].keys() log_vars = dict() for k in log_keys: assert all([k in log_vars for log_vars in log_vars_list ]), (f'\'{k}\' not in some of the \'log_vars\'.') log_vars[k] = torch.mean( torch.stack([log_vars[k] for log_vars in log_vars_list], dim=0)) return log_vars def _init_loss(self, loss_config: Optional[Dict] = None) -> None: """Initialize customized loss modules. If loss_config is a dict, we allow kinds of value for each field. 1. `loss_config` is None: Users will implement all loss calculations in their own function. Weights for each loss terms are hard coded. 2. `loss_config` is dict of scalar or string: Users will implement all loss calculations and use passed `loss_config` to control the weight or behavior of the loss calculation. Users will unpack and use each field in this dict by themselves. loss_config = dict(gp_norm_mode='HWC', gp_loss_weight=10) 3. `loss_config` is dict of dict: Each field in `loss_config` will used to build a corresponding loss module. And use loss calculation function predefined by :class:`BaseGAN` to calculate the loss. loss_config = dict() Example: loss_config = dict( # `BaseGAN` pre-defined fields gan_loss=dict(type='GANLoss', gan_type='wgan-logistic-ns'), disc_auxiliary_loss=dict( type='R1GradientPenalty', loss_weight=10. / 2., interval=2, norm_mode='HWC', data_info=dict( real_data='real_imgs', discriminator='disc')), gen_auxiliary_loss=dict( type='GeneratorPathRegularizer', loss_weight=2, pl_batch_shrink=2, interval=g_reg_interval, data_info=dict( generator='gen', num_batches='batch_size')), # user-defined field for loss weights or loss calculation my_loss_2=dict(weight=2, norm_mode='L1'), my_loss_3=2, my_loss_4_norm_type='L2') Args: loss_config (Optional[Dict], optional): Loss config used to build loss modules or define the loss weights. Defaults to None. """ if loss_config is None: self.gan_loss = None self.gen_auxiliary_losses = None self.disc_auxiliary_losses = None self.loss_config = dict() return self.loss_config = deepcopy(loss_config) # build pre-defined losses gan_loss = loss_config.get('gan_loss', None) if gan_loss is not None: self.gan_loss = MODELS.build(gan_loss) else: self.gan_loss = None disc_auxiliary_loss = loss_config.get('disc_auxiliary_loss', None) if disc_auxiliary_loss: if not isinstance(disc_auxiliary_loss, list): disc_auxiliary_loss = [disc_auxiliary_loss] self.disc_auxiliary_losses = nn.ModuleList( [MODELS.build(loss) for loss in disc_auxiliary_loss]) else: self.disc_auxiliary_losses = None gen_auxiliary_loss = loss_config.get('gen_auxiliary_loss', None) if gen_auxiliary_loss: if not isinstance(gen_auxiliary_loss, list): gen_auxiliary_loss = [gen_auxiliary_loss] self.gen_auxiliary_losses = nn.ModuleList( [MODELS.build(loss) for loss in gen_auxiliary_loss]) else: self.gen_auxiliary_losses = None def noise_fn(self, noise: NoiseVar = None, num_batches: int = 1): """Sampling function for noise. There are three scenarios in this function: - If `noise` is a callable function, sample `num_batches` of noise with passed `noise`. - If `noise` is `None`, sample `num_batches` of noise from gaussian distribution. - If `noise` is a `torch.Tensor`, directly return `noise`. Args: noise (Union[Tensor, Callable, List[int], None]): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default noise sampler. Defaults to `None`. num_batches (int, optional): The number of batches label want to sample. If `label` is a Tensor, this will be ignored. Defaults to 1. Returns: Tensor: Sampled noise tensor. """ return noise_sample_fn( noise=noise, num_batches=num_batches, noise_size=self.noise_size, device=self.device) @property def generator_steps(self) -> int: """int: The number of times the generator is completely updated before the discriminator is updated.""" return self._gen_steps @property def discriminator_steps(self) -> int: """int: The number of times the discriminator is completely updated before the generator is updated.""" return self._disc_steps @property def device(self) -> torch.device: """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device @property def with_ema_gen(self) -> bool: """Whether the GAN adopts exponential moving average. Returns: bool: If `True`, means this GAN model is adopted to exponential moving average and vice versa. """ return self._with_ema_gen def _init_ema_model(self, ema_config: dict): """Initialize a EMA model corresponding to the given `ema_config`. If `ema_config` is an empty dict or `None`, EMA model will not be initialized. Args: ema_config (dict): Config to initialize the EMA model. """ ema_config.setdefault('type', 'ExponentialMovingAverage') self.ema_start = ema_config.pop('start_iter', 0) src_model = self.generator.module if is_model_wrapper( self.generator) else self.generator self.generator_ema = MODELS.build( ema_config, default_args=dict(model=src_model)) def _get_valid_model(self, batch_inputs: ForwardInputs) -> str: """Try to get the valid forward model from inputs. - If forward model is defined in `batch_inputs`, it will be used as forward model. - If forward model is not defined in `batch_inputs`, 'ema' will returned if :property:`with_ema_gen` is true. Otherwise, 'orig' will be returned. Args: batch_inputs (ForwardInputs): Inputs passed to :meth:`forward`. Returns: str: Forward model to generate image. ('orig', 'ema' or 'ema/orig'). """ if isinstance(batch_inputs, dict): sample_model = batch_inputs.get('sample_model', None) else: # batch_inputs is a Tensor sample_model = None # set default value if sample_model is None: if self.with_ema_gen: sample_model = 'ema' else: sample_model = 'orig' # security checking for mode assert sample_model in [ 'ema', 'ema/orig', 'orig' ], ('Only support \'ema\', \'ema/orig\', \'orig\' ' f'in {self.__class__.__name__}\'s image sampling.') if sample_model in ['ema', 'ema/orig']: assert self.with_ema_gen, ( f'\'{self.__class__.__name__}\' do not have EMA model.') return sample_model def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> SampleList: """Sample images with the given inputs. If forward mode is 'ema' or 'orig', the image generated by corresponding generator will be returned. If forward mode is 'ema/orig', images generated by original generator and EMA generator will both be returned in a dict. Args: batch_inputs (ForwardInputs): Dict containing the necessary information (e.g. noise, num_batches, mode) to generate image. data_samples (Optional[list]): Data samples collated by :attr:`data_preprocessor`. Defaults to None. mode (Optional[str]): `mode` is not used in :class:`BaseGAN`. Defaults to None. Returns: SampleList: A list of ``DataSample`` contain generated results. """ if isinstance(inputs, Tensor): noise = inputs sample_kwargs = {} else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) sample_kwargs = inputs.get('sample_kwargs', dict()) num_batches = noise.shape[0] sample_model = self._get_valid_model(inputs) batch_sample_list = [] if sample_model in ['ema', 'orig']: if sample_model == 'ema': generator = self.generator_ema else: generator = self.generator if sample_kwargs: if 'return_noise' in sample_kwargs.keys(): outputs = generator(noise, **sample_kwargs) else: outputs = generator( noise, return_noise=False, **sample_kwargs) # yapf: disable else: sample_kwargs = {} outputs = generator( noise, return_noise=False, **sample_kwargs) # no need to be False all time if isinstance(outputs, dict): if 'latent' in outputs.keys(): latent = outputs['latent'] if 'feats' in outputs.keys(): feats = outputs['feats'] outputs = outputs['fake_img'] outputs = self.data_preprocessor.destruct(outputs, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.fake_img = outputs gen_sample.noise = noise if 'latent' in locals(): gen_sample.latent = latent if 'feats' in locals(): gen_sample.feats = feats gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = sample_model batch_sample_list = gen_sample.split(allow_nonseq_value=True, ) else: # sample model is 'ema/orig outputs_orig = self.generator( noise, return_noise=False, **sample_kwargs) outputs_ema = self.generator_ema( noise, return_noise=False, **sample_kwargs) outputs_orig = self.data_preprocessor.destruct( outputs_orig, data_samples) outputs_ema = self.data_preprocessor.destruct( outputs_ema, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.ema = DataSample(fake_img=outputs_ema) gen_sample.orig = DataSample(fake_img=outputs_orig) gen_sample.noise = noise gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = 'ema/orig' batch_sample_list = gen_sample.split(allow_nonseq_value=True) return batch_sample_list def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor(data)`` and ``self(inputs, data_sample, mode=None)`` in order. Return the generated results which will be passed to evaluator. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: List[DataSample]: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: """Train GAN model. In the training of GAN models, generator and discriminator are updated alternatively. In MMagic's design, `self.train_step` is called with data input. Therefore we always update discriminator, whose updating is relay on real data, and then determine if the generator needs to be updated based on the current number of iterations. More details about whether to update generator can be found in :meth:`should_gen_update`. Args: data (dict): Data sampled from dataloader. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts with disc_optimizer_wrapper.optim_context(self.discriminator): log_vars = self.train_discriminator( **data, optimizer_wrapper=disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): log_vars_gen = self.train_generator( **data, optimizer_wrapper=gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = self.gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) # if not update buffer, copy buffer from orig model if not self.generator_ema.update_buffers: self.generator_ema.sync_buffers( self.generator.module if is_model_wrapper( self.generator) else self.generator) elif self.with_ema_gen: # before ema, copy weights from orig self.generator_ema.sync_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) return log_vars def _get_gen_loss(self, out_dict): losses_dict = {} # gan loss losses_dict['loss_disc_fake_g'] = self.gan_loss( out_dict['disc_pred_fake_g'], target_is_real=True, is_disc=False) # gen auxiliary loss if self.gen_auxiliary_losses is not None: for loss_module in self.gen_auxiliary_losses: loss_ = loss_module(out_dict) if loss_ is None: continue # the `loss_name()` function return name as 'loss_xxx' if loss_module.loss_name() in losses_dict: losses_dict[loss_module.loss_name( )] = losses_dict[loss_module.loss_name()] + loss_ else: losses_dict[loss_module.loss_name()] = loss_ loss, log_var = self.parse_losses(losses_dict) return loss, log_var def _get_disc_loss(self, out_dict): # Construct losses dict. If you hope some items to be included in the # computational graph, you have to add 'loss' in its name. Otherwise, # items without 'loss' in their name will just be used to print # information. losses_dict = {} # gan loss losses_dict['loss_disc_fake'] = self.gan_loss( out_dict['disc_pred_fake'], target_is_real=False, is_disc=True) losses_dict['loss_disc_real'] = self.gan_loss( out_dict['disc_pred_real'], target_is_real=True, is_disc=True) # disc auxiliary loss if self.disc_auxiliary_losses is not None: for loss_module in self.disc_auxiliary_losses: loss_ = loss_module(out_dict) if loss_ is None: continue # the `loss_name()` function return name as 'loss_xxx' if loss_module.loss_name() in losses_dict: losses_dict[loss_module.loss_name( )] = losses_dict[loss_module.loss_name()] + loss_ else: losses_dict[loss_module.loss_name()] = loss_ loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_generator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Training function for discriminator. All GANs should implement this function by themselves. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = inputs['img'].shape[0] noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise) disc_pred_fake_g = self.discriminator(fake_imgs) data_dict_ = dict( gen=self.generator, disc=self.discriminator, fake_imgs=fake_imgs, disc_pred_fake_g=disc_pred_fake_g, # iteration=curr_iter, batch_size=num_batches, loss_scaler=getattr(optimizer_wrapper, 'loss_scaler', None)) loss, log_vars = self._get_gen_loss(data_dict_) optimizer_wrapper.update_params(loss) return log_vars def train_discriminator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Training function for discriminator. All GANs should implement this function by themselves. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs, num_batches = inputs['img'], inputs['img'].shape[0] noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise) # disc pred for fake imgs and real_imgs disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) # get data dict to compute losses for disc data_dict_ = dict( gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs, # iteration=curr_iter, batch_size=num_batches, loss_scaler=getattr(optimizer_wrapper, 'loss_scaler', None)) loss, log_vars = self._get_disc_loss(data_dict_) optimizer_wrapper.update_params(loss) return log_vars ================================================ FILE: mmagic/models/base_models/base_mattor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from abc import ABCMeta from typing import Dict, List, Optional, Tuple, Union import torch import torch.nn.functional as F from mmengine.config import Config, ConfigDict from mmengine.model import BaseModel from mmagic.registry import MODELS from mmagic.structures import DataSample DataSamples = Optional[Union[list, torch.Tensor]] ForwardResults = Union[Dict[str, torch.Tensor], List[DataSample], Tuple[torch.Tensor], torch.Tensor] def _pad(batch_image: torch.Tensor, ds_factor: int, mode: str = 'reflect') -> Tuple[torch.Tensor, Tuple[int, int]]: """Pad image to a multiple of give down-sampling factor.""" h, w = batch_image.shape[-2:] # NCHW new_h = ds_factor * ((h - 1) // ds_factor + 1) new_w = ds_factor * ((w - 1) // ds_factor + 1) pad_h = new_h - h pad_w = new_w - w pad = (pad_h, pad_w) if new_h != h or new_w != w: pad_width = (0, pad_w, 0, pad_h) # torch.pad in reverse order batch_image = F.pad(batch_image, pad_width, mode) return batch_image, pad def _interpolate(batch_image: torch.Tensor, ds_factor: int, mode: str = 'bicubic' ) -> Tuple[torch.Tensor, Tuple[int, int]]: """Resize image to multiple of give down-sampling factor.""" h, w = batch_image.shape[-2:] # NCHW new_h = h - (h % ds_factor) new_w = w - (w % ds_factor) size = (new_h, new_w) if new_h != h or new_w != w: batch_image = F.interpolate(batch_image, size=size, mode=mode) return batch_image, size class BaseMattor(BaseModel, metaclass=ABCMeta): """Base class for trimap-based matting models. A matting model must contain a backbone which produces `pred_alpha`, a dense prediction with the same height and width of input image. In some cases (such as DIM), the model has a refiner which refines the prediction of the backbone. Subclasses should overwrite the following functions: - :meth:`_forward_train`, to return a loss - :meth:`_forward_test`, to return a prediction - :meth:`_forward`, to return raw tensors For test, this base class provides functions to resize inputs and post-process pred_alphas to get predictions Args: backbone (dict): Config of backbone. data_preprocessor (dict): Config of data_preprocessor. See :class:`MattorPreprocessor` for details. init_cfg (dict, optional): Initialization config dict. train_cfg (dict): Config of training. Customized by subclassesCustomized bu In ``train_cfg``, ``train_backbone`` should be specified. If the model has a refiner, ``train_refiner`` should be specified. test_cfg (dict): Config of testing. In ``test_cfg``, If the model has a refiner, ``train_refiner`` should be specified. """ def __init__(self, data_preprocessor: Union[dict, Config], backbone: dict, init_cfg: Optional[dict] = None, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None): # Build data_preprocessor in BaseModel # Initialize weights in BaseModule super().__init__( data_preprocessor=data_preprocessor, init_cfg=init_cfg) self.train_cfg = ConfigDict( train_cfg) if train_cfg is not None else ConfigDict() self.test_cfg = ConfigDict( test_cfg) if test_cfg is not None else ConfigDict() self.backbone = MODELS.build(backbone) def resize_inputs(self, batch_inputs: torch.Tensor) -> torch.Tensor: """Pad or interpolate images and trimaps to multiple of given factor.""" resize_method = self.test_cfg['resize_method'] resize_mode = self.test_cfg['resize_mode'] size_divisor = self.test_cfg['size_divisor'] batch_images = batch_inputs[:, :3, :, :] batch_trimaps = batch_inputs[:, 3:, :, :] if resize_method == 'pad': batch_images, _ = _pad(batch_images, size_divisor, resize_mode) batch_trimaps, _ = _pad(batch_trimaps, size_divisor, resize_mode) elif resize_method == 'interp': batch_images, _ = _interpolate(batch_images, size_divisor, resize_mode) batch_trimaps, _ = _interpolate(batch_trimaps, size_divisor, 'nearest') else: raise NotImplementedError return torch.cat((batch_images, batch_trimaps), dim=1) def restore_size(self, pred_alpha: torch.Tensor, data_sample: DataSample) -> torch.Tensor: """Restore the predicted alpha to the original shape. The shape of the predicted alpha may not be the same as the shape of original input image. This function restores the shape of the predicted alpha. Args: pred_alpha (torch.Tensor): A single predicted alpha of shape (1, H, W). data_sample (DataSample): Data sample containing original shape as meta data. Returns: torch.Tensor: The reshaped predicted alpha. """ resize_method = self.test_cfg['resize_method'] resize_mode = self.test_cfg['resize_mode'] ori_h, ori_w = data_sample.ori_merged_shape[:2] if resize_method == 'pad': pred_alpha = pred_alpha[:, :ori_h, :ori_w] elif resize_method == 'interp': pred_alpha = F.interpolate( pred_alpha.unsqueeze(0), size=(ori_h, ori_w), mode=resize_mode) pred_alpha = pred_alpha[0] # 1,H,W return pred_alpha def postprocess( self, batch_pred_alpha: torch.Tensor, # N, 1, H, W, float32 data_samples: DataSample, ) -> List[DataSample]: """Post-process alpha predictions. This function contains the following steps: 1. Restore padding or interpolation 2. Mask alpha prediction with trimap 3. Clamp alpha prediction to 0-1 4. Convert alpha prediction to uint8 5. Pack alpha prediction into DataSample Currently only batch_size 1 is actually supported. Args: batch_pred_alpha (torch.Tensor): A batch of predicted alpha of shape (N, 1, H, W). data_samples (List[DataSample]): List of data samples. Returns: List[DataSample]: A list of predictions. Each data sample contains a pred_alpha, which is a torch.Tensor with dtype=uint8, device=cuda:0 """ assert batch_pred_alpha.ndim == 4 # N, 1, H, W, float32 assert len(batch_pred_alpha) == 1 # NOTE: for mattors, we split datasamples here, not in # `convert_to_datasample` data_samples = data_samples.split() predictions = [] for pa, ds in zip(batch_pred_alpha, data_samples): pa = self.restore_size(pa, ds) # 1, H, W pa = pa[0] # H, W pa.clamp_(min=0, max=1) ori_trimap = ds.ori_trimap[0, :, :] # H, W pa[ori_trimap == 255] = 1 pa[ori_trimap == 0] = 0 pa *= 255 pa.round_() pa = pa.to(dtype=torch.uint8) # pa = pa.cpu().numpy() pa_sample = DataSample(pred_alpha=pa) predictions.append(pa_sample) return predictions def forward(self, inputs: torch.Tensor, data_samples: DataSamples = None, mode: str = 'tensor') -> List[DataSample]: """General forward function. Args: inputs (torch.Tensor): A batch of inputs. with image and trimap concatenated alone channel dimension. data_samples (List[DataSample], optional): A list of data samples, containing: - Ground-truth alpha / foreground / background to compute loss - other meta information mode (str): mode should be one of ``loss``, ``predict`` and ``tensor``. Default: 'tensor'. - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: List[DataElement]: Sequence of predictions packed into DataElement """ if mode == 'tensor': raw = self._forward(inputs) return raw elif mode == 'predict': # Pre-process runs in runner inputs = self.resize_inputs(inputs) batch_pred_alpha = self._forward_test(inputs) predictions = self.postprocess(batch_pred_alpha, data_samples) predictions = self.convert_to_datasample(predictions, data_samples) return predictions elif mode == 'loss': loss = self._forward_train(inputs, data_samples) return loss else: raise ValueError('Invalid forward mode.') def convert_to_datasample(self, predictions: List[DataSample], data_samples: DataSample) -> List[DataSample]: """Add predictions to data samples. Args: predictions (List[DataSample]): The predictions of the model. data_samples (DataSample): The data samples loaded from dataloader. Returns: List[DataSample]: Modified data samples. """ data_samples = data_samples.split() for data_sample, pred in zip(data_samples, predictions): data_sample.output = pred return data_samples ================================================ FILE: mmagic/models/base_models/base_translation_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from abc import ABCMeta from collections import defaultdict from copy import deepcopy from typing import List, Optional import torch.nn as nn from mmengine.model import BaseModel, is_model_wrapper from mmagic.registry import MODELS @MODELS.register_module() class BaseTranslationModel(BaseModel, metaclass=ABCMeta): """Base Translation Model. Translation models can transfer images from one domain to another. Domain information like `default_domain`, `reachable_domains` are needed to initialize the class. And we also provide query functions like `is_domain_reachable`, `get_other_domains`. You can get a specific generator based on the domain, and by specifying `target_domain` in the forward function, you can decide the domain of generated images. Considering the difference among different image translation models, we only provide the external interfaces mentioned above. When you implement image translation with a specific method, you can inherit both `BaseTranslationModel` and the method (e.g BaseGAN) and implement abstract methods. Args: default_domain (str): Default output domain. reachable_domains (list[str]): Domains that can be generated by the model. related_domains (list[str]): Domains involved in training and testing. `reachable_domains` must be contained in `related_domains`. However, related_domains may contain source domains that are used to retrieve source images from data_batch but not in reachable_domains. discriminator_steps (int): The number of times the discriminator is completely updated before the generator is updated. Defaults to 1. disc_init_steps (int): The number of initial steps used only to train discriminators. """ def __init__(self, generator, discriminator, default_domain: str, reachable_domains: List[str], related_domains: List[str], data_preprocessor, discriminator_steps: int = 1, disc_init_steps: int = 0, real_img_key: str = 'real_img', loss_config: Optional[dict] = None): super().__init__(data_preprocessor) self._default_domain = default_domain self._reachable_domains = reachable_domains self._related_domains = related_domains assert self._default_domain in self._reachable_domains assert set(self._reachable_domains) <= set(self._related_domains) self.discriminator_steps = discriminator_steps self.disc_init_steps = disc_init_steps self.real_img_key = real_img_key self._gen_cfg = deepcopy(generator) # build domain generators self.generators = nn.ModuleDict() for domain in self._reachable_domains: self.generators[domain] = MODELS.build(generator) self._disc_cfg = deepcopy(discriminator) # build domain discriminators if discriminator is not None: self.discriminators = nn.ModuleDict() for domain in self._reachable_domains: self.discriminators[domain] = MODELS.build(discriminator) # support no discriminator in testing else: self.discriminators = None self.loss_config = dict() if loss_config is None else loss_config def init_weights(self): """Initialize weights for the module dict. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Default: None. """ self._params_init_info = defaultdict(dict) for _, param in self.named_parameters(): self._params_init_info[param][ 'init_info'] = f'The value is the same before and ' \ f'after calling `init_weights` ' \ f'of {self.__class__.__name__} ' mean = param.data.mean().cpu() self._params_init_info[param]['tmp_mean_value'] = mean for domain in self._reachable_domains: if is_model_wrapper(self.generators): gen = self.generators.module[domain] else: gen = self.generators[domain] gen._params_init_info = self._params_init_info gen.init_weights() if self.discriminators is not None: if is_model_wrapper(self.discriminators): disc = self.discriminators.module[domain] else: disc = self.discriminators[domain] disc._params_init_info = self._params_init_info disc.init_weights() super()._dump_init_info() for m in self.modules(): if hasattr(m, '_params_init_info'): del m._params_init_info def get_module(self, module): """Get `nn.ModuleDict` to fit the `MMDistributedDataParallel` interface. Args: module (MMDistributedDataParallel | nn.ModuleDict): The input module that needs processing. Returns: nn.ModuleDict: The ModuleDict of multiple networks. """ if is_model_wrapper(module): return module.module return module def forward(self, img, test_mode=False, **kwargs): """Forward function. Args: img (tensor): Input image tensor. test_mode (bool): Whether in test mode or not. Default: False. kwargs (dict): Other arguments. """ if not test_mode: return self.forward_train(img, **kwargs) return self.forward_test(img, **kwargs) def forward_train(self, img, target_domain, **kwargs): """Forward function for training. Args: img (tensor): Input image tensor. target_domain (str): Target domain of output image. kwargs (dict): Other arguments. Returns: dict: Forward results. """ target = self.translation(img, target_domain=target_domain, **kwargs) results = dict(source=img, target=target) return results def forward_test(self, img, target_domain, **kwargs): """Forward function for testing. Args: img (tensor): Input image tensor. target_domain (str): Target domain of output image. kwargs (dict): Other arguments. Returns: dict: Forward results. """ target = self.translation(img, target_domain=target_domain, **kwargs) results = dict(source=img.cpu(), target=target.cpu()) return results def is_domain_reachable(self, domain): """Whether image of this domain can be generated.""" return domain in self._reachable_domains def get_other_domains(self, domain): """get other domains.""" return list(set(self._related_domains) - set([domain])) def _get_target_generator(self, domain): """get target generator.""" assert self.is_domain_reachable( domain ), f'{domain} domain is not reachable, available domain list is\ {self._reachable_domains}' return self.get_module(self.generators)[domain] def _get_target_discriminator(self, domain): """get target discriminator.""" assert self.is_domain_reachable( domain ), f'{domain} domain is not reachable, available domain list is\ {self._reachable_domains}' return self.get_module(self.discriminators)[domain] def translation(self, image, target_domain=None, **kwargs): """Translation Image to target style. Args: image (tensor): Image tensor with a shape of (N, C, H, W). target_domain (str, optional): Target domain of output image. Default to None. Returns: dict: Image tensor of target style. """ if target_domain is None: target_domain = self._default_domain _model = self._get_target_generator(target_domain) outputs = _model(image, **kwargs) return outputs ================================================ FILE: mmagic/models/base_models/basic_interpolator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch from mmagic.registry import MODELS from mmagic.utils import tensor2img from .base_edit_model import BaseEditModel # TODO tensor2img will be move @MODELS.register_module() class BasicInterpolator(BaseEditModel): """Basic model for video interpolation. It must contain a generator that takes frames as inputs and outputs an interpolated frame. It also has a pixel-wise loss for training. Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. required_frames (int): Required frames in each process. Default: 2 step_frames (int): Step size of video frame interpolation. Default: 1 init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. """ def __init__(self, generator: dict, pixel_loss: dict, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None, required_frames: int = 2, step_frames: int = 1, init_cfg: Optional[dict] = None, data_preprocessor: Optional[dict] = None): super().__init__( generator=generator, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) # Required frames in each process self.required_frames = required_frames # Step size of video frame interpolation self.step_frames = step_frames def split_frames(self, input_tensors: torch.Tensor) -> torch.Tensor: """split input tensors for inference. Args: input_tensors (Tensor): Tensor of input frames with shape [1, t, c, h, w] Returns: Tensor: Split tensor with shape [t-1, 2, c, h, w] """ num_frames = input_tensors.shape[1] result = [ input_tensors[:, i:i + self.required_frames] for i in range(0, num_frames - self.required_frames + 1, self.step_frames) ] result = torch.cat(result, dim=0) return result @staticmethod def merge_frames(input_tensors: torch.Tensor, output_tensors: torch.Tensor) -> list: """merge input frames and output frames. Interpolate a frame between the given two frames. Merged from [[in1, in2], [in2, in3], [in3, in4], ...] [[out1], [out2], [out3], ...] to [in1, out1, in2, out2, in3, out3, in4, ...] Args: input_tensors (Tensor): The input frames with shape [n, 2, c, h, w] output_tensors (Tensor): The output frames with shape [n, 1, c, h, w]. Returns: list[np.array]: The final frames. """ num_frames = input_tensors.shape[0] result = [] for i in range(num_frames): result.append(tensor2img(input_tensors[i, 0])) result.append(tensor2img(output_tensors[i, 0])) result.append(tensor2img(input_tensors[-1, 1])) return result ================================================ FILE: mmagic/models/base_models/one_stage.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Tuple, Union import torch from mmengine.config import Config from mmengine.model import BaseModel from mmengine.optim import OptimWrapperDict from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import SampleList from ..utils import set_requires_grad FORWARD_RETURN_TYPE = Union[dict, torch.Tensor, Tuple[torch.Tensor, torch.Tensor], SampleList] @MODELS.register_module() class OneStageInpaintor(BaseModel): """Standard one-stage inpaintor with commonly used losses. An inpaintor must contain an encoder-decoder style generator to inpaint masked regions. A discriminator will be adopted when adversarial training is needed. In this class, we provide a common interface for inpaintors. For other inpaintors, only some funcs may be modified to fit the input style or training schedule. Args: data_preprocessor (dict): Config of data_preprocessor. encdec (dict): Config for encoder-decoder style generator. disc (dict): Config for discriminator. loss_gan (dict): Config for adversarial loss. loss_gp (dict): Config for gradient penalty loss. loss_disc_shift (dict): Config for discriminator shift loss. loss_composed_percep (dict): Config for perceptual and style loss with composed image as input. loss_out_percep (dict): Config for perceptual and style loss with direct output as input. loss_l1_hole (dict): Config for l1 loss in the hole. loss_l1_valid (dict): Config for l1 loss in the valid region. loss_tv (dict): Config for total variation loss. train_cfg (dict): Configs for training scheduler. `disc_step` must be contained for indicates the discriminator updating steps in each training step. test_cfg (dict): Configs for testing scheduler. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, data_preprocessor: Union[dict, Config], encdec: dict, disc: Optional[dict] = None, loss_gan: Optional[dict] = None, loss_gp: Optional[dict] = None, loss_disc_shift: Optional[dict] = None, loss_composed_percep: Optional[dict] = None, loss_out_percep: bool = False, loss_l1_hole: Optional[dict] = None, loss_l1_valid: Optional[dict] = None, loss_tv: Optional[dict] = None, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None, init_cfg: Optional[dict] = None): super().__init__( data_preprocessor=data_preprocessor, init_cfg=init_cfg) self.with_l1_hole_loss = loss_l1_hole is not None self.with_l1_valid_loss = loss_l1_valid is not None self.with_tv_loss = loss_tv is not None self.with_composed_percep_loss = loss_composed_percep is not None self.with_out_percep_loss = loss_out_percep self.with_gan = disc is not None and loss_gan is not None self.with_gp_loss = loss_gp is not None self.with_disc_shift_loss = loss_disc_shift is not None self.is_train = train_cfg is not None self.train_cfg = train_cfg self.test_cfg = test_cfg self.generator = MODELS.build(encdec) # build loss modules if self.with_gan: self.disc = MODELS.build(disc) self.loss_gan = MODELS.build(loss_gan) if self.with_l1_hole_loss: self.loss_l1_hole = MODELS.build(loss_l1_hole) if self.with_l1_valid_loss: self.loss_l1_valid = MODELS.build(loss_l1_valid) if self.with_composed_percep_loss: self.loss_percep = MODELS.build(loss_composed_percep) if self.with_gp_loss: self.loss_gp = MODELS.build(loss_gp) if self.with_disc_shift_loss: self.loss_disc_shift = MODELS.build(loss_disc_shift) if self.with_tv_loss: self.loss_tv = MODELS.build(loss_tv) self.disc_step_count = 0 def forward(self, inputs: torch.Tensor, data_samples: Optional[SampleList], mode: str = 'tensor') -> FORWARD_RETURN_TYPE: """Forward function. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor``. Default: 'tensor'. - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict`` or tensor for custom use. """ if mode == 'tensor': raw = self.forward_tensor(inputs, data_samples) return raw elif mode == 'predict': # Pre-process runs in BaseModel.val_step / test_step predictions = self.forward_test(inputs, data_samples) predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'loss': raise NotImplementedError('This mode should not be used in ' 'current training schedule. Please use ' '`train_step` for training.') else: raise ValueError('Invalid forward mode.') def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> dict: """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. optimize discriminator (if have) 3. optimize generator If `self.train_cfg.disc_step > 1`, the train step will contain multiple iterations for optimizing discriminator with different input data and only one iteration for optimizing generator after `disc_step` iterations for discriminator. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} masked_img = batch_inputs # float # gt_img: float [-1, 1], mask: uint8 [0/1] gt_img, mask = data_samples.gt_img, data_samples.mask mask = mask.float() # get common output from encdec input_x = torch.cat([masked_img, mask], dim=1) fake_res = self.generator(input_x) fake_img = gt_img * (1. - mask) + fake_res * mask # discriminator training step if self.train_cfg.disc_step > 0: set_requires_grad(self.disc, True) disc_losses = self.forward_train_d( fake_img.detach(), False, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].zero_grad() loss_disc.backward() disc_losses = self.forward_train_d(gt_img, True, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) loss_disc.backward() if self.with_gp_loss: loss_d_gp = self.loss_gp( self.disc, gt_img, fake_img, mask=mask) loss_disc, log_vars_d = self.parse_losses( dict(loss_gp=loss_d_gp)) log_vars.update(log_vars_d) loss_disc.backward() optim_wrapper['disc'].step() self.disc_step_count = (self.disc_step_count + 1) % self.train_cfg.disc_step if self.disc_step_count != 0: # results contain the data for visualization results = dict( gt_img=gt_img.cpu(), masked_img=masked_img.cpu(), fake_res=fake_res.cpu(), fake_img=fake_img.cpu()) # outputs = dict( # log_vars=log_vars, # num_samples=len(data_batch['gt_img'].data), # results=results) return log_vars # generator (encdec) training step, results contain the data # for visualization if self.with_gan: set_requires_grad(self.disc, False) results, g_losses = self.generator_loss(fake_res, fake_img, gt_img, mask, masked_img) loss_g, log_vars_g = self.parse_losses(g_losses) log_vars.update(log_vars_g) optim_wrapper['generator'].zero_grad() loss_g.backward() optim_wrapper['generator'].step() # outputs = dict( # log_vars=log_vars, # num_samples=len(data_batch['gt_img'].data), # results=results) return log_vars def forward_train(self, *args, **kwargs) -> None: """Forward function for training. In this version, we do not use this interface. """ raise NotImplementedError('This interface should not be used in ' 'current training schedule. Please use ' '`train_step` for training.') def forward_train_d(self, data_batch: torch.Tensor, is_real: bool, is_disc: bool) -> dict: """Forward function in discriminator training step. In this function, we compute the prediction for each data batch (real or fake). Meanwhile, the standard gan loss will be computed with several proposed losses for stable training. Args: data_batch (torch.Tensor): Batch of real data or fake data. is_real (bool): If True, the gan loss will regard this batch as real data. Otherwise, the gan loss will regard this batch as fake data. is_disc (bool): If True, this function is called in discriminator training step. Otherwise, this function is called in generator training step. This will help us to compute different types of adversarial loss, like LSGAN. Returns: dict: Contains the loss items computed in this function. """ pred = self.disc(data_batch) loss_ = self.loss_gan(pred, is_real, is_disc) loss = dict(real_loss=loss_) if is_real else dict(fake_loss=loss_) if self.with_disc_shift_loss: loss_d_shift = self.loss_disc_shift(loss_) # 0.5 for average the fake and real data loss.update(loss_disc_shift=loss_d_shift * 0.5) return loss def generator_loss(self, fake_res: torch.Tensor, fake_img: torch.Tensor, gt: torch.Tensor, mask: torch.Tensor, masked_img: torch.Tensor) -> Tuple[dict, dict]: """Forward function in generator training step. In this function, we mainly compute the loss items for generator with the given (fake_res, fake_img). In general, the `fake_res` is the direct output of the generator and the `fake_img` is the composition of direct output and ground-truth image. Args: fake_res (torch.Tensor): Direct output of the generator. fake_img (torch.Tensor): Composition of `fake_res` and ground-truth image. gt (torch.Tensor): Ground-truth image. mask (torch.Tensor): Mask image. masked_img (torch.Tensor): Composition of mask image and ground-truth image. Returns: tuple(dict): Dict contains the results computed within this \ function for visualization and dict contains the loss items \ computed in this function. """ loss = dict() if self.with_gan: g_fake_pred = self.disc(fake_img) loss_g_fake = self.loss_gan(g_fake_pred, True, is_disc=False) loss['loss_g_fake'] = loss_g_fake if self.with_l1_hole_loss: loss_l1_hole = self.loss_l1_hole(fake_res, gt, weight=mask) loss['loss_l1_hole'] = loss_l1_hole if self.with_l1_valid_loss: loss_loss_l1_valid = self.loss_l1_valid( fake_res, gt, weight=1. - mask) loss['loss_l1_valid'] = loss_loss_l1_valid if self.with_composed_percep_loss: loss_pecep, loss_style = self.loss_percep(fake_img, gt) if loss_pecep is not None: loss['loss_composed_percep'] = loss_pecep if loss_style is not None: loss['loss_composed_style'] = loss_style if self.with_out_percep_loss: loss_out_percep, loss_out_style = self.loss_percep(fake_res, gt) if loss_out_percep is not None: loss['loss_out_percep'] = loss_out_percep if loss_out_style is not None: loss['loss_out_style'] = loss_out_style if self.with_tv_loss: loss_tv = self.loss_tv(fake_img, mask=mask) loss['loss_tv'] = loss_tv res = dict( gt_img=gt.cpu(), masked_img=masked_img.cpu(), fake_res=fake_res.cpu(), fake_img=fake_img.cpu()) return res, loss def forward_tensor(self, inputs: torch.Tensor, data_samples: SampleList ) -> Tuple[torch.Tensor, torch.Tensor]: """Forward function in tensor mode. Args: inputs (torch.Tensor): Input tensor. data_samples (List[dict]): List of data sample dict. Returns: tuple: Direct output of the generator and composition of `fake_res` and ground-truth image. """ # Pre-process runs in BaseModel.val_step / test_step masked_imgs = inputs # N,3,H,W masks = data_samples.mask # N,1,H,W input_xs = torch.cat([masked_imgs, masks], dim=1) # N,4,H,W fake_reses = self.generator(input_xs) fake_imgs = fake_reses * masks + masked_imgs * (1. - masks) return fake_reses, fake_imgs def forward_test(self, inputs: torch.Tensor, data_samples: SampleList) -> DataSample: """Forward function for testing. Args: inputs (torch.Tensor): Input tensor. data_samples (List[dict]): List of data sample dict. Returns: predictions (List[DataSample]): List of prediction saved in DataSample. """ fake_reses, fake_imgs = self.forward_tensor(inputs, data_samples) predictions = [] fake_reses = self.data_preprocessor.destruct(fake_reses, data_samples) fake_imgs = self.data_preprocessor.destruct(fake_imgs, data_samples) # create a stacked data sample here predictions = DataSample( fake_res=fake_reses, fake_img=fake_imgs, pred_img=fake_imgs) return predictions def convert_to_datasample(self, predictions: DataSample, data_samples: DataSample, inputs: Optional[torch.Tensor] ) -> List[DataSample]: """Add predictions and destructed inputs (if passed) to data samples. Args: predictions (DataSample): The predictions of the model. data_samples (DataSample): The data samples loaded from dataloader. inputs (Optional[torch.Tensor]): The input of model. Defaults to None. Returns: List[DataSample]: Modified data samples. """ if inputs is not None: destructed_input = self.data_preprocessor.destruct( inputs, data_samples, 'img') data_samples.set_tensor_data({'input': destructed_input}) data_samples = data_samples.split() predictions = predictions.split() for data_sample, pred in zip(data_samples, predictions): data_sample.output = pred return data_samples def forward_dummy(self, x: torch.Tensor) -> torch.Tensor: """Forward dummy function for getting flops. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Results tensor with shape of (n, 3, h, w). """ res = self.generator(x) return res ================================================ FILE: mmagic/models/base_models/two_stage.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Sequence, Tuple, Union import torch from mmengine.config import Config from mmengine.optim import OptimWrapperDict from mmagic.registry import MODELS from mmagic.utils import SampleList from ..utils import set_requires_grad from .one_stage import OneStageInpaintor @MODELS.register_module() class TwoStageInpaintor(OneStageInpaintor): """Standard two-stage inpaintor with commonly used losses. A two-stage inpaintor contains two encoder-decoder style generators to inpaint masked regions. Currently, we support these loss types in each of two stage inpaintors: ['loss_gan', 'loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep',\ 'loss_out_percep', 'loss_tv'] The `stage1_loss_type` and `stage2_loss_type` should be chosen from these loss types. Args: data_preprocessor (dict): Config of data_preprocessor. encdec (dict): Config for encoder-decoder style generator. disc (dict): Config for discriminator. loss_gan (dict): Config for adversarial loss. loss_gp (dict): Config for gradient penalty loss. loss_disc_shift (dict): Config for discriminator shift loss. loss_composed_percep (dict): Config for perceptual and style loss with composed image as input. loss_out_percep (dict): Config for perceptual and style loss with direct output as input. loss_l1_hole (dict): Config for l1 loss in the hole. loss_l1_valid (dict): Config for l1 loss in the valid region. loss_tv (dict): Config for total variation loss. train_cfg (dict): Configs for training scheduler. `disc_step` must be contained for indicates the discriminator updating steps in each training step. test_cfg (dict): Configs for testing scheduler. init_cfg (dict, optional): Initialization config dict. stage1_loss_type (tuple[str]): Contains the loss names used in the first stage model. Default: ('loss_l1_hole'). stage2_loss_type (tuple[str]): Contains the loss names used in the second stage model. Default: ('loss_l1_hole', 'loss_gan'). input_with_ones (bool): Whether to concatenate an extra ones tensor in input. Default: True. disc_input_with_mask (bool): Whether to add mask as input in discriminator. Default: False. """ def __init__( self, data_preprocessor: Union[dict, Config], encdec: dict, disc: Optional[dict] = None, loss_gan: Optional[dict] = None, loss_gp: Optional[dict] = None, loss_disc_shift: Optional[dict] = None, loss_composed_percep: Optional[dict] = None, loss_out_percep: bool = False, loss_l1_hole: Optional[dict] = None, loss_l1_valid: Optional[dict] = None, loss_tv: Optional[dict] = None, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None, init_cfg: Optional[dict] = None, stage1_loss_type: Optional[Sequence[str]] = ('loss_l1_hole', ), stage2_loss_type: Optional[Sequence[str]] = ('loss_l1_hole', 'loss_gan'), input_with_ones: bool = True, disc_input_with_mask: bool = False): super().__init__( data_preprocessor=data_preprocessor, encdec=encdec, disc=disc, loss_gan=loss_gan, loss_gp=loss_gp, loss_disc_shift=loss_disc_shift, loss_composed_percep=loss_composed_percep, loss_out_percep=loss_out_percep, loss_l1_hole=loss_l1_hole, loss_l1_valid=loss_l1_valid, loss_tv=loss_tv, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg) self.stage1_loss_type = stage1_loss_type self.stage2_loss_type = stage2_loss_type self.input_with_ones = input_with_ones self.disc_input_with_mask = disc_input_with_mask if self.train_cfg is not None: self.cur_iter = self.train_cfg.start_iter def forward_tensor(self, inputs: torch.Tensor, data_samples: SampleList ) -> Tuple[torch.Tensor, torch.Tensor]: """Forward function in tensor mode. Args: inputs (torch.Tensor): Input tensor. data_samples (List[dict]): List of data sample dict. Returns: dict: Dict contains output results. """ # Pre-process runs in BaseModel.val_step / test_step masked_imgs = inputs # N,3,H,W masks = data_samples.mask if self.input_with_ones: tmp_ones = torch.ones_like(masks) input_xs = torch.cat([masked_imgs, tmp_ones, masks], dim=1) else: input_xs = torch.cat([masked_imgs, masks], dim=1) # N,4,H,W stage1_fake_res, stage2_fake_res = self.generator(input_xs) fake_imgs = stage2_fake_res * masks + masked_imgs * (1. - masks) return stage2_fake_res, fake_imgs def two_stage_loss(self, stage1_data: dict, stage2_data: dict, gt: torch.Tensor, mask: torch.Tensor, masked_img: torch.Tensor) -> Tuple[dict, dict]: """Calculate two-stage loss. Args: stage1_data (dict): Contain stage1 results. stage2_data (dict): Contain stage2 results.. gt (torch.Tensor): Ground-truth image. mask (torch.Tensor): Mask image. masked_img (torch.Tensor): Composition of mask image and ground-truth image. Returns: tuple(dict): Dict contains the results computed within this \ function for visualization and dict contains the loss items \ computed in this function. """ loss = dict() results = dict( gt_img=gt.cpu(), mask=mask.cpu(), masked_img=masked_img.cpu()) # calculate losses for stage1 if self.stage1_loss_type is not None: fake_res = stage1_data['fake_res'] fake_img = stage1_data['fake_img'] for type_key in self.stage1_loss_type: tmp_loss = self.calculate_loss_with_type( type_key, fake_res, fake_img, gt, mask, prefix='stage1_') loss.update(tmp_loss) results.update( dict( stage1_fake_res=stage1_data['fake_res'].cpu(), stage1_fake_img=stage1_data['fake_img'].cpu())) if self.stage2_loss_type is not None: fake_res = stage2_data['fake_res'] fake_img = stage2_data['fake_img'] for type_key in self.stage2_loss_type: tmp_loss = self.calculate_loss_with_type( type_key, fake_res, fake_img, gt, mask, prefix='stage2_') loss.update(tmp_loss) results.update( dict( stage2_fake_res=stage2_data['fake_res'].cpu(), stage2_fake_img=stage2_data['fake_img'].cpu())) return results, loss def calculate_loss_with_type(self, loss_type: str, fake_res: torch.Tensor, fake_img: torch.Tensor, gt: torch.Tensor, mask: torch.Tensor, prefix: Optional[str] = 'stage1_') -> dict: """Calculate multiple types of losses. Args: loss_type (str): Type of the loss. fake_res (torch.Tensor): Direct results from model. fake_img (torch.Tensor): Composited results from model. gt (torch.Tensor): Ground-truth tensor. mask (torch.Tensor): Mask tensor. prefix (str, optional): Prefix for loss name. Defaults to 'stage1\_'. # noqa Returns: dict: Contain loss value with its name. """ loss_dict = dict() if loss_type == 'loss_gan': if self.disc_input_with_mask: disc_input_x = torch.cat([fake_img, mask], dim=1) else: disc_input_x = fake_img g_fake_pred = self.disc(disc_input_x) loss_g_fake = self.loss_gan(g_fake_pred, True, is_disc=False) loss_dict[prefix + 'loss_g_fake'] = loss_g_fake elif 'percep' in loss_type: loss_pecep, loss_style = self.loss_percep(fake_img, gt) if loss_pecep is not None: loss_dict[prefix + loss_type] = loss_pecep if loss_style is not None: loss_dict[prefix + loss_type[:-6] + 'style'] = loss_style elif 'tv' in loss_type: loss_tv = self.loss_tv(fake_img, mask=mask) loss_dict[prefix + loss_type] = loss_tv elif 'l1' in loss_type: weight = 1. - mask if 'valid' in loss_type else mask loss_l1 = getattr(self, loss_type)(fake_res, gt, weight=weight) loss_dict[prefix + loss_type] = loss_l1 else: raise NotImplementedError( f'Please check your loss type {loss_type}' f' and the config dict in init function. ' f'We cannot find the related loss function.') return loss_dict def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> dict: """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. optimize discriminator (if have) 3. optimize generator If `self.train_cfg.disc_step > 1`, the train step will contain multiple iterations for optimizing discriminator with different input data and only one iteration for optimizing generator after `disc_step` iterations for discriminator. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of \ samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} masked_img = batch_inputs # float gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() # get common output from encdec if self.input_with_ones: tmp_ones = torch.ones_like(mask) input_x = torch.cat([masked_img, tmp_ones, mask], dim=1) else: input_x = torch.cat([masked_img, mask], dim=1) stage1_fake_res, stage2_fake_res = self.generator(input_x) stage1_fake_img = masked_img * (1. - mask) + stage1_fake_res * mask stage2_fake_img = masked_img * (1. - mask) + stage2_fake_res * mask # discriminator training step # In this version, we only use the results from the second stage to # train discriminators, which is a commonly used setting. This can be # easily modified to your custom training schedule. if self.train_cfg.disc_step > 0: set_requires_grad(self.disc, True) if self.disc_input_with_mask: disc_input_x = torch.cat([stage2_fake_img.detach(), mask], dim=1) else: disc_input_x = stage2_fake_img.detach() disc_losses = self.forward_train_d( disc_input_x, False, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].zero_grad() optim_wrapper['disc'].backward(loss_disc) if self.disc_input_with_mask: disc_input_x = torch.cat([gt_img, mask], dim=1) else: disc_input_x = gt_img disc_losses = self.forward_train_d( disc_input_x, True, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].backward(loss_disc) if self.with_gp_loss: # gradient penalty loss should not be used with mask as input assert not self.disc_input_with_mask loss_d_gp = self.loss_gp( self.disc, gt_img, stage2_fake_img, mask=mask) loss_disc, log_vars_d = self.parse_losses( dict(loss_gp=loss_d_gp)) log_vars.update(log_vars_d) optim_wrapper['disc'].backward(loss_disc) optim_wrapper['disc'].step() self.disc_step_count = (self.disc_step_count + 1) % self.train_cfg.disc_step if self.disc_step_count != 0: # results contain the data for visualization results = dict( gt_img=gt_img.cpu(), masked_img=masked_img.cpu(), fake_res=stage2_fake_res.cpu(), fake_img=stage2_fake_img.cpu()) return log_vars # prepare stage1 results and stage2 results dict for calculating losses stage1_results = dict( fake_res=stage1_fake_res, fake_img=stage1_fake_img) stage2_results = dict( fake_res=stage2_fake_res, fake_img=stage2_fake_img) # generator (encdec) and refiner training step, results contain the # data for visualization if self.with_gan: set_requires_grad(self.disc, False) results, two_stage_losses = self.two_stage_loss( stage1_results, stage2_results, gt_img, mask, masked_img) loss_two_stage, log_vars_two_stage = self.parse_losses( two_stage_losses) log_vars.update(log_vars_two_stage) optim_wrapper['generator'].zero_grad() optim_wrapper['generator'].backward(loss_two_stage) optim_wrapper['generator'].step() return log_vars ================================================ FILE: mmagic/models/data_preprocessors/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .data_preprocessor import DataPreprocessor from .mattor_preprocessor import MattorPreprocessor __all__ = ['DataPreprocessor', 'MattorPreprocessor'] ================================================ FILE: mmagic/models/data_preprocessors/data_preprocessor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from logging import WARNING from typing import List, Optional, Sequence, Tuple, Union import torch import torch.nn.functional as F from mmengine import print_log from mmengine.model import ImgDataPreprocessor from mmengine.utils import is_seq_of from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList CastData = Union[tuple, dict, DataSample, Tensor, list] @MODELS.register_module() class DataPreprocessor(ImgDataPreprocessor): """Image pre-processor for generative models. This class provide normalization and bgr to rgb conversion for image tensor inputs. The input of this classes should be dict which keys are `inputs` and `data_samples`. Besides to process tensor `inputs`, this class support dict as `inputs`. - If the value is `Tensor` and the corresponding key is not contained in :attr:`_NON_IMAGE_KEYS`, it will be processed as image tensor. - If the value is `Tensor` and the corresponding key belongs to :attr:`_NON_IMAGE_KEYS`, it will not remains unchanged. - If value is string or integer, it will not remains unchanged. Args: mean (Sequence[float or int], float or int, optional): The pixel mean of image channels. Noted that normalization operation is performed *after channel order conversion*. If it is not specified, images will not be normalized. Defaults None. std (Sequence[float or int], float or int, optional): The pixel standard deviation of image channels. Noted that normalization operation is performed *after channel order conversion*. If it is not specified, images will not be normalized. Defaults None. pad_size_divisor (int): The size of padded image should be divisible by ``pad_size_divisor``. Defaults to 1. pad_value (float or int): The padded pixel value. Defaults to 0. pad_mode (str): Padding mode for ``torch.nn.functional.pad``. Defaults to 'constant'. non_image_keys (List[str] or str): Keys for fields that not need to be processed (padding, channel conversion and normalization) as images. If not passed, the keys in :attr:`_NON_IMAGE_KEYS` will be used. This argument will only work when `inputs` is dict or list of dict. Defaults to None. non_concatenate_keys (List[str] or str): Keys for fields that not need to be concatenated. If not passed, the keys in :attr:`_NON_CONCATENATE_KEYS` will be used. This argument will only work when `inputs` is dict or list of dict. Defaults to None. output_channel_order (str, optional): The desired image channel order of output the data preprocessor. This is also the desired input channel order of model (and this most likely to be the output order of model). If not passed, no channel order conversion will be performed. Defaults to None. data_keys (List[str] or str): Keys to preprocess in data samples. Defaults to 'gt_img'. input_view (tuple, optional): The view of input tensor. This argument maybe deleted in the future. Defaults to None. output_view (tuple, optional): The view of output tensor. This argument maybe deleted in the future. Defaults to None. stack_data_sample (bool): Whether stack a list of data samples to one data sample. Only support with input data samples are `DataSamples`. Defaults to True. """ _NON_IMAGE_KEYS = ['noise'] _NON_CONCATENATE_KEYS = ['num_batches', 'mode', 'sample_kwargs', 'eq_cfg'] def __init__(self, mean: Union[Sequence[Union[float, int]], float, int] = 127.5, std: Union[Sequence[Union[float, int]], float, int] = 127.5, pad_size_divisor: int = 1, pad_value: Union[float, int] = 0, pad_mode: str = 'constant', non_image_keys: Optional[Tuple[str, List[str]]] = None, non_concentate_keys: Optional[Tuple[str, List[str]]] = None, output_channel_order: Optional[str] = None, data_keys: Union[List[str], str] = 'gt_img', input_view: Optional[tuple] = None, output_view: Optional[tuple] = None, stack_data_sample=True): if not isinstance(mean, (list, tuple)) and mean is not None: mean = [mean] if not isinstance(std, (list, tuple)) and std is not None: std = [std] super().__init__(mean, std, pad_size_divisor, pad_value) # get channel order assert (output_channel_order is None or output_channel_order in ['RGB', 'BGR']), ( 'Only support \'RGB\', \'BGR\' or None for ' '\'output_channel_order\', but receive ' f'\'{output_channel_order}\'.') self.output_channel_order = output_channel_order # add user defined keys if non_image_keys is not None: if not isinstance(non_image_keys, list): non_image_keys = [non_image_keys] self._NON_IMAGE_KEYS += non_image_keys if non_concentate_keys is not None: if not isinstance(non_concentate_keys, list): non_concentate_keys = [non_concentate_keys] self._NON_CONCATENATE_KEYS += non_concentate_keys self.pad_mode = pad_mode self.pad_size_dict = dict() if data_keys is not None and not isinstance(data_keys, list): self.data_keys = [data_keys] else: self.data_keys = data_keys # TODO: can be removed since only be used in LIIF self.input_view = input_view self.output_view = output_view self._done_padding = False # flag for padding checking self._conversion_warning_raised = False # flag for conversion warning self.stack_data_sample = stack_data_sample def cast_data(self, data: CastData) -> CastData: """Copying data to the target device. Args: data (dict): Data returned by ``DataLoader``. Returns: CollatedResult: Inputs and data sample at target device. """ if isinstance(data, (str, int, float)): return data return super().cast_data(data) @staticmethod def _parse_channel_index(inputs) -> int: """Parse channel index of inputs.""" channel_index_mapping = {2: 1, 3: 0, 4: 1, 5: 2} if isinstance(inputs, dict): ndim = inputs['fake_img'].ndim assert ndim in channel_index_mapping, ( 'Only support (H*W, C), (C, H, W), (N, C, H, W) or ' '(N, t, C, H, W) inputs. But received ' f'\'({inputs.shape})\'.') channel_index = channel_index_mapping[ndim] else: assert inputs.ndim in channel_index_mapping, ( 'Only support (H*W, C), (C, H, W), (N, C, H, W) or ' '(N, t, C, H, W) inputs. But received ' f'\'({inputs.shape})\'.') channel_index = channel_index_mapping[inputs.ndim] return channel_index def _parse_channel_order(self, key: str, inputs: Tensor, data_sample: Optional[DataSample] = None) -> str: channel_index = self._parse_channel_index(inputs) if isinstance(inputs, dict): num_color_channels = inputs['fake_img'].shape[channel_index] else: num_color_channels = inputs.shape[channel_index] # data sample is None, attempt to infer from input tensor if data_sample is None: if num_color_channels == 1: return 'single' else: # default as BGR return 'BGR' # data sample is not None, infer from metainfo channel_order_key = 'gt_channel_order' if key == 'gt_img' \ else f'{key}_channel_order' color_type_key = 'gt_color_type' if key == 'gt_img' \ else f'{key}_color_type' # TODO: raise warning here, we can build a dict which fields are keys # have been parsed. color_flag = data_sample.metainfo.get(color_type_key, None) channel_order = data_sample.metainfo.get(channel_order_key, None) # handle stacked data sample, refers to `DataSample.stack` if isinstance(color_flag, list): assert all([c == color_flag[0] for c in color_flag]) color_flag = color_flag[0] if isinstance(channel_order, list): assert all([c == channel_order[0] for c in channel_order]) channel_order = channel_order[0] # NOTE: to handle inputs such as Y, users may modify the following code if color_flag == 'grayscale': assert num_color_channels == 1 return 'single' elif color_flag == 'unchanged': # if inputs is not None: return 'single' if num_color_channels == 1 else 'BGR' else: # inference from channel_order if channel_order: return channel_order else: # no channel order, infer from num channels return 'single' if num_color_channels == 1 else 'BGR' def _parse_batch_channel_order(self, key: str, inputs: Sequence, data_samples: Optional[Sequence[DataSample]] ) -> str: """Parse channel order of inputs in batch.""" assert len(inputs) == len(data_samples) batch_inputs_orders = [ self._parse_channel_order(key, inp, data_sample) for inp, data_sample in zip(inputs, data_samples) ] inputs_order = batch_inputs_orders[0] # security checking for channel order assert all([ inputs_order == order for order in batch_inputs_orders ]), (f'Channel order ({batch_inputs_orders}) of input targets ' f'(\'{key}\') are inconsistent.') return inputs_order def _update_metainfo(self, padding_info: Tensor, channel_order_info: Optional[dict] = None, data_samples: Optional[SampleList] = None ) -> SampleList: """Update `padding_info` and `channel_order` to metainfo of. *a batch of `data_samples`*. For channel order, we consider same field among data samples share the same channel order. Therefore `channel_order` is passed as a dict, which key and value are field name and corresponding channel order. For padding info, we consider padding info is same among all field of a sample, but can vary between samples. Therefore, we pass `padding_info` as Tensor shape like (B, 1, 1). Args: padding_info (Tensor): The padding info of each sample. Shape like (B, 1, 1). channel_order (dict, Optional): The channel order of target field. Key and value are field name and corresponding channel order respectively. data_samples (List[DataSample], optional): The data samples to be updated. If not passed, will initialize a list of empty data samples. Defaults to None. Returns: List[DataSample]: The updated data samples. """ n_samples = padding_info.shape[0] if data_samples is None: data_samples = [DataSample() for _ in range(n_samples)] else: assert len(data_samples) == n_samples, ( f'The length of \'data_samples\'({len(data_samples)}) and ' f'\'padding_info\'({n_samples}) are inconsistent. Please ' 'check your inputs.') # update padding info for pad_size, data_sample in zip(padding_info, data_samples): data_sample.set_metainfo({'padding_size': pad_size}) # update channel order if channel_order_info is not None: for data_sample in data_samples: for key, channel_order in channel_order_info.items(): data_sample.set_metainfo( {f'{key}_output_channel_order': channel_order}) self._done_padding = padding_info.sum() != 0 return data_samples def _do_conversion(self, inputs: Tensor, inputs_order: str = 'BGR', target_order: Optional[str] = None ) -> Tuple[Tensor, str]: """Conduct channel order conversion for *a batch of inputs*, and return the converted inputs and order after conversion. inputs_order: * RGB / RGB: Convert to target order. * SINGLE: Do not change """ if (target_order is None or inputs_order.upper() == target_order.upper()): # order is not changed, return the input one return inputs, inputs_order def conversion(inputs, channel_index): if inputs.shape[channel_index] == 4: new_index = [2, 1, 0, 3] else: new_index = [2, 1, 0] # do conversion inputs = torch.index_select( inputs, channel_index, torch.LongTensor(new_index).to(inputs.device)) return inputs channel_index = self._parse_channel_index(inputs) if inputs_order.upper() in ['RGB', 'BGR']: inputs = conversion(inputs, channel_index) return inputs, target_order elif inputs_order.upper() == 'SINGLE': if not self._conversion_warning_raised: print_log( 'Cannot convert inputs with \'single\' channel order ' f'to \'output_channel_order\' ({self.output_channel_order}' '). Return without conversion.', 'current', WARNING) self._conversion_warning_raised = True return inputs, inputs_order else: raise ValueError(f'Unsupported inputs order \'{inputs_order}\'.') def _do_norm(self, inputs: Tensor, do_norm: Optional[bool] = None) -> Tensor: do_norm = self._enable_normalize if do_norm is None else do_norm if do_norm: if self.input_view is None: if inputs.ndim == 2: # special case for (H*W, C) tensor target_shape = [1, -1] else: target_shape = [1 for _ in range(inputs.ndim - 3) ] + [-1, 1, 1] else: target_shape = self.input_view mean = self.mean.view(target_shape) std = self.std.view(target_shape) # shape checking to avoid broadcast a single channel tensor to 3 channel_idx = self._parse_channel_index(inputs) n_channel_inputs = inputs.shape[channel_idx] n_channel_mean = mean.shape[channel_idx] n_channel_std = std.shape[channel_idx] assert n_channel_mean == 1 or n_channel_mean == n_channel_inputs assert n_channel_std == 1 or n_channel_std == n_channel_inputs inputs = (inputs - mean) / std return inputs def _preprocess_image_tensor(self, inputs: Tensor, data_samples: Optional[SampleList] = None, key: str = 'img' ) -> Tuple[Tensor, SampleList]: """Preprocess a batch of image tensor and update metainfo to corresponding data samples. Args: inputs (Tensor): Image tensor with shape (C, H, W), (N, C, H, W) or (N, t, C, H, W) to preprocess. data_samples (List[DataSample], optional): The data samples of corresponding inputs. If not passed, a list of empty data samples will be initialized to save metainfo. Defaults to None. key (str): The key of image tensor in data samples. Defaults to 'img'. Returns: Tuple[Tensor, List[DataSample]]: The preprocessed image tensor and updated data samples. """ if not data_samples: # none or empty list data_samples = [DataSample() for _ in range(inputs.shape[0])] assert inputs.dim() in [ 3, 4, 5 ], ('The input of `_preprocess_image_tensor` should be a (C, H, W), ' '(N, C, H, W) or (N, t, C, H, W)tensor, but got a tensor with ' f'shape: {inputs.shape}') channel_order = self._parse_batch_channel_order( key, inputs, data_samples) inputs, output_channel_order = self._do_conversion( inputs, channel_order, self.output_channel_order) inputs = self._do_norm(inputs) h, w = inputs.shape[-2:] target_h = math.ceil(h / self.pad_size_divisor) * self.pad_size_divisor target_w = math.ceil(w / self.pad_size_divisor) * self.pad_size_divisor pad_h = target_h - h pad_w = target_w - w batch_inputs = F.pad(inputs, (0, pad_w, 0, pad_h), self.pad_mode, self.pad_value) padding_size = torch.FloatTensor((0, pad_h, pad_w))[None, ...] padding_size = padding_size.repeat(inputs.shape[0], 1) data_samples = self._update_metainfo(padding_size, {key: output_channel_order}, data_samples) return batch_inputs, data_samples def _preprocess_image_list(self, tensor_list: List[Tensor], data_samples: Optional[SampleList], key: str = 'img') -> Tuple[Tensor, SampleList]: """Preprocess a list of image tensor and update metainfo to corresponding data samples. Args: tensor_list (List[Tensor]): Image tensor list to be preprocess. data_samples (List[DataSample], optional): The data samples of corresponding inputs. If not passed, a list of empty data samples will be initialized to save metainfo. Defaults to None. key (str): The key of tensor list in data samples. Defaults to 'img'. Returns: Tuple[Tensor, List[DataSample]]: The preprocessed image tensor and updated data samples. """ if not data_samples: # none or empty list data_samples = [DataSample() for _ in range(len(tensor_list))] channel_order = self._parse_batch_channel_order( key, tensor_list, data_samples) dim = tensor_list[0].dim() assert all([ tensor.ndim == dim for tensor in tensor_list ]), ('Expected the dimensions of all tensors must be the same, ' f'but got {[tensor.ndim for tensor in tensor_list]}') num_img = len(tensor_list) all_sizes: torch.Tensor = torch.Tensor( [tensor.shape for tensor in tensor_list]) max_sizes = torch.ceil( torch.max(all_sizes, dim=0)[0] / self.pad_size_divisor) * self.pad_size_divisor padding_sizes = max_sizes - all_sizes # The dim of channel and frame index should not be padded. padding_sizes[:, :-2] = 0 if padding_sizes.sum() == 0: stacked_tensor = torch.stack(tensor_list) stacked_tensor, output_channel_order = self._do_conversion( stacked_tensor, channel_order, self.output_channel_order) stacked_tensor = self._do_norm(stacked_tensor) data_samples = self._update_metainfo(padding_sizes, {key: output_channel_order}, data_samples) return stacked_tensor, data_samples # `pad` is the second arguments of `F.pad`. If pad is (1, 2, 3, 4), # it means that padding the last dim with 1(left) 2(right), padding the # penultimate dim to 3(top) 4(bottom). The order of `pad` is opposite # of the `padded_sizes`. Therefore, the `padded_sizes` needs to be # reversed, and only odd index of pad should be assigned to keep # padding "right" and "bottom". pad = torch.zeros(num_img, 2 * dim, dtype=torch.int) pad[:, 1::2] = padding_sizes[:, range(dim - 1, -1, -1)] batch_tensor = [] for idx, tensor in enumerate(tensor_list): paded_tensor = F.pad(tensor, tuple(pad[idx].tolist()), self.pad_mode, self.pad_value) batch_tensor.append(paded_tensor) stacked_tensor = torch.stack(batch_tensor) stacked_tensor, output_channel_order = self._do_conversion( stacked_tensor, channel_order, self.output_channel_order) stacked_tensor = self._do_norm(stacked_tensor) data_samples = self._update_metainfo(padding_sizes, {key: output_channel_order}, data_samples) # return stacked_tensor, padding_sizes return stacked_tensor, data_samples def _preprocess_dict_inputs(self, batch_inputs: dict, data_samples: Optional[SampleList] = None ) -> Tuple[dict, SampleList]: """Preprocess dict type inputs. Args: batch_inputs (dict): Input dict. data_samples (List[DataSample], optional): The data samples of corresponding inputs. If not passed, a list of empty data samples will be initialized to save metainfo. Defaults to None. Returns: Tuple[dict, List[DataSample]]: The preprocessed dict and updated data samples. """ pad_size_dict = dict() for k, inputs in batch_inputs.items(): # handle concentrate for values in list if isinstance(inputs, list): if k in self._NON_CONCATENATE_KEYS: # use the first value assert all([ inputs[0] == inp for inp in inputs ]), (f'NON_CONCENTATE_KEY \'{k}\' should be consistency ' 'among the data list.') batch_inputs[k] = inputs[0] else: assert all([ isinstance(inp, torch.Tensor) for inp in inputs ]), ('Only support stack list of Tensor in inputs dict. ' f'But \'{k}\' is list of \'{type(inputs[0])}\'.') if k not in self._NON_IMAGE_KEYS: # preprocess as image inputs, data_samples = self._preprocess_image_list( inputs, data_samples, k) pad_size_dict[k] = [ data.metainfo.get('padding_size') for data in data_samples ] else: # only stack inputs = torch.stack(inputs) batch_inputs[k] = inputs elif isinstance(inputs, Tensor) and k not in self._NON_IMAGE_KEYS: batch_inputs[k], data_samples = \ self._preprocess_image_tensor(inputs, data_samples, k) pad_size_dict[k] = [ data.metainfo.get('padding_size') for data in data_samples ] # NOTE: we only support all key shares the same padding size if pad_size_dict: padding_sizes = list(pad_size_dict.values())[0] padding_key = list(pad_size_dict.keys())[0] for idx, tar_size in enumerate(padding_sizes): for k, sizes in pad_size_dict.items(): if (tar_size != sizes[idx]).any(): raise ValueError( f'All fields of a data sample should share the ' 'same padding size, but got different size for ' f'\'{k}\'(\'{sizes[idx]}\') and \'{padding_key}\'' f'(\'{tar_size}\') at index {idx}.Please check ' 'your data carefully.') return batch_inputs, data_samples def _preprocess_data_sample(self, data_samples: SampleList, training: bool) -> DataSample: """Preprocess data samples. When `training` is True, fields belong to :attr:`self.data_keys` will be converted to :attr:`self.output_channel_order` and then normalized by `self.mean` and `self.std`. When `training` is False, fields belongs to :attr:`self.data_keys` will be attempted to convert to 'BGR' without normalization. The corresponding metainfo related to normalization, channel order conversion will be updated to data sample as well. Args: data_samples (List[DataSample]): A list of data samples to preprocess. training (bool): Whether in training mode. Returns: list: The list of processed data samples. """ if not training: # set default order to BGR in test stage target_order, do_norm = 'BGR', False else: # norm in training, conversion as default (None) target_order, do_norm = self.output_channel_order, True for data_sample in data_samples: if not self.data_keys: break for key in self.data_keys: if not hasattr(data_sample, key): # do not raise error here print_log(f'Cannot find key \'{key}\' in data sample.', 'current', WARNING) break data = data_sample.get(key) data_channel_order = self._parse_channel_order( key, data, data_sample) data, channel_order = self._do_conversion( data, data_channel_order, target_order) data = self._do_norm(data, do_norm) data_sample.set_data({f'{key}': data}) data_process_meta = { f'{key}_enable_norm': self._enable_normalize, f'{key}_output_channel_order': channel_order, f'{key}_mean': self.mean, f'{key}_std': self.std } data_sample.set_metainfo(data_process_meta) if self.stack_data_sample: assert is_seq_of(data_samples, DataSample), ( 'Only support \'stack_data_sample\' for DataSample ' 'object. Please refer to \'DataSample.stack\'.') return DataSample.stack(data_samples) return data_samples def forward(self, data: dict, training: bool = False) -> dict: """Performs normalization、padding and channel order conversion. Args: data (dict): Input data to process. training (bool): Whether to in training mode. Default: False. Returns: dict: Data in the same format as the model input. """ data = self.cast_data(data) _batch_inputs = data['inputs'] _batch_data_samples = data.get('data_samples', None) # process input if isinstance(_batch_inputs, torch.Tensor): _batch_inputs, _batch_data_samples = \ self._preprocess_image_tensor( _batch_inputs, _batch_data_samples) elif is_seq_of(_batch_inputs, torch.Tensor): _batch_inputs, _batch_data_samples = \ self._preprocess_image_list( _batch_inputs, _batch_data_samples) elif isinstance(_batch_inputs, dict): _batch_inputs, _batch_data_samples = \ self._preprocess_dict_inputs( _batch_inputs, _batch_data_samples) elif is_seq_of(_batch_inputs, dict): # convert list of dict to dict of list keys = _batch_inputs[0].keys() dict_input = {k: [inp[k] for inp in _batch_inputs] for k in keys} _batch_inputs, _batch_data_samples = \ self._preprocess_dict_inputs( dict_input, _batch_data_samples) else: raise ValueError('Only support following inputs types: ' '\'torch.Tensor\', \'List[torch.Tensor]\', ' '\'dict\', \'List[dict]\'. But receive ' f'\'{type(_batch_inputs)}\'.') data['inputs'] = _batch_inputs # process data samples if _batch_data_samples: _batch_data_samples = self._preprocess_data_sample( _batch_data_samples, training) data['data_samples'] = _batch_data_samples return data def destruct(self, outputs: Tensor, data_samples: Union[SampleList, DataSample, None] = None, key: str = 'img') -> Union[list, Tensor]: """Destruct padding, normalization and convert channel order to BGR if could. If `data_samples` is a list, outputs will be destructed as a batch of tensor. If `data_samples` is a `DataSample`, `outputs` will be destructed as a single tensor. Before feed model outputs to visualizer and evaluator, users should call this function for model outputs and inputs. Use cases: >>> # destruct model outputs. >>> # model outputs share the same preprocess information with inputs >>> # ('img') therefore use 'img' as key >>> feats = self.forward_tensor(inputs, data_samples, **kwargs) >>> feats = self.data_preprocessor.destruct(feats, data_samples, 'img') >>> # destruct model inputs for visualization >>> for idx, data_sample in enumerate(data_samples): >>> destructed_input = self.data_preprocessor.destruct( >>> inputs[idx], data_sample, key='img') >>> data_sample.set_data({'input': destructed_input}) Args: outputs (Tensor): Tensor to destruct. data_samples (Union[SampleList, DataSample], optional): Data samples (or data sample) corresponding to `outputs`. Defaults to None key (str): The key of field in data sample. Defaults to 'img'. Returns: Union[list, Tensor]: Destructed outputs. """ # NOTE: only support passing tensor sample, if the output of model is # a dict, users should call this manually. # Since we do not know whether the outputs is image tensor. _batch_outputs = self._destruct_norm_and_conversion( outputs, data_samples, key) _batch_outputs = self._destruct_padding(_batch_outputs, data_samples) _batch_outputs = _batch_outputs.clamp_(0, 255) return _batch_outputs def _destruct_norm_and_conversion(self, batch_tensor: Tensor, data_samples: Union[SampleList, DataSample, None], key: str) -> Tensor: """De-norm and de-convert channel order. Noted that, we de-norm first, and then de-conversion, since mean and std used in normalization is based on channel order after conversion. Args: batch_tensor (Tensor): Tensor to destruct. data_samples (Union[SampleList, DataSample], optional): Data samples (or data sample) corresponding to `outputs`. key (str): The key of field in data sample. Returns: Tensor: Destructed tensor. """ output_key = f'{key}_output' # get channel order from data sample if isinstance(data_samples, list): inputs_order = self._parse_batch_channel_order( output_key, batch_tensor, data_samples) else: inputs_order = self._parse_channel_order(output_key, batch_tensor, data_samples) if self._enable_normalize: if self.output_view is None: if batch_tensor.ndim == 2: # special case for (H*W, C) tensor target_shape = [1, -1] else: target_shape = [1 for _ in range(batch_tensor.ndim - 3) ] + [-1, 1, 1] else: target_shape = self.output_view mean = self.mean.view(target_shape) std = self.std.view(target_shape) batch_tensor = batch_tensor * std + mean # convert output to 'BGR' if able batch_tensor, _ = self._do_conversion( batch_tensor, inputs_order=inputs_order, target_order='BGR') return batch_tensor def _destruct_padding(self, batch_tensor: Tensor, data_samples: Union[SampleList, DataSample, None], same_padding: bool = True) -> Union[list, Tensor]: """Destruct padding of the input tensor. Args: batch_tensor (Tensor): Tensor to destruct. data_samples (Union[SampleList, DataSample], optional): Data samples (or data sample) corresponding to `outputs`. If same_padding (bool): Whether all samples will un-padded with the padding info of the first sample, and return a stacked un-padded tensor. Otherwise each sample will be unpadded with padding info saved in corresponding data samples, and return a list of un-padded tensor, since each un-padded tensor may have the different shape. Defaults to True. Returns: Union[list, Tensor]: Destructed outputs. """ # NOTE: If same padding, batch_tensor will un-padded with the padding # info # of the first sample and return a Unpadded tensor. Otherwise, # input tensor # will un-padded with the corresponding padding info # saved in data samples and return a list of tensor. if data_samples is None: return batch_tensor if isinstance(data_samples, list): is_batch_data = True if 'padding_size' in data_samples[0].metainfo_keys(): pad_infos = [ sample.metainfo['padding_size'] for sample in data_samples ] else: pad_infos = None else: if 'padding_size' in data_samples.metainfo_keys(): pad_infos = data_samples.metainfo['padding_size'] else: pad_infos = None # NOTE: here we assume padding size in metainfo are saved as tensor if not isinstance(pad_infos, list): pad_infos = [pad_infos] is_batch_data = False else: is_batch_data = True if all([pad_info is None for pad_info in pad_infos]): pad_infos = None if not is_batch_data: batch_tensor = batch_tensor[None, ...] if pad_infos is None: if self._done_padding: print_log( 'Cannot find padding information (\'padding_size\') in ' 'meta info of \'data_samples\'. Please check whether ' 'you have called \'self.forward\' properly.', 'current', WARNING) return batch_tensor if is_batch_data else batch_tensor[0] if same_padding: # un-pad with the padding info of the first sample padded_h, padded_w = pad_infos[0][-2:] padded_h, padded_w = int(padded_h), int(padded_w) h, w = batch_tensor.shape[-2:] batch_tensor = batch_tensor[..., :h - padded_h, :w - padded_w] return batch_tensor if is_batch_data else batch_tensor[0] else: # un-pad with the corresponding padding info unpadded_tensors = [] for idx, pad_info in enumerate(pad_infos): padded_h, padded_w = pad_info[-2:] padded_h = int(padded_h) padded_w = int(padded_w) h, w = batch_tensor[idx].shape[-2:] unpadded_tensor = batch_tensor[idx][..., :h - padded_h, :w - padded_w] unpadded_tensors.append(unpadded_tensor) return unpadded_tensors if is_batch_data else unpadded_tensors[0] ================================================ FILE: mmagic/models/data_preprocessors/mattor_preprocessor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import WARNING from typing import Dict, List, Optional, Sequence, Tuple, Union import torch from mmengine import print_log from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from .data_preprocessor import DataPreprocessor DataSamples = Optional[Union[list, torch.Tensor]] ForwardResults = Union[Dict[str, torch.Tensor], List[DataSample], Tuple[torch.Tensor], torch.Tensor] MEAN_STD_TYPE = Union[Sequence[Union[float, int]], float, int] @MODELS.register_module() class MattorPreprocessor(DataPreprocessor): """DataPreprocessor for matting models. See base class ``DataPreprocessor`` for detailed information. Workflow as follow : - Collate and move data to the target device. - Convert inputs from bgr to rgb if the shape of input is (3, H, W). - Normalize image with defined std and mean. - Stack inputs to batch_inputs. Args: mean (Sequence[float or int], float or int, optional): The pixel mean of image channels. Noted that normalization operation is performed *after channel order conversion*. If it is not specified, images will not be normalized. Defaults None. std (Sequence[float or int], float or int, optional): The pixel standard deviation of image channels. Noted that normalization operation is performed *after channel order conversion*. If it is not specified, images will not be normalized. Defaults None. proc_trimap (str): Methods to process gt tensors. Default: 'rescale_to_zero_one'. Available options are ``rescale_to_zero_one`` and ``as-is``. stack_data_sample (bool): Whether stack a list of data samples to one data sample. Only support with input data samples are `DataSamples`. Defaults to True. """ def __init__(self, mean: MEAN_STD_TYPE = [123.675, 116.28, 103.53], std: MEAN_STD_TYPE = [58.395, 57.12, 57.375], output_channel_order: str = 'RGB', proc_trimap: str = 'rescale_to_zero_one', stack_data_sample=True): # specific data_keys for matting task data_keys = ['gt_fg', 'gt_bg', 'gt_merged', 'gt_alpha'] super().__init__( mean, std, output_channel_order=output_channel_order, data_keys=data_keys, stack_data_sample=stack_data_sample) self.proc_trimap = proc_trimap # self.proc_gt = proc_gt def _proc_batch_trimap(self, batch_trimaps: torch.Tensor): if self.proc_trimap == 'rescale_to_zero_one': batch_trimaps = batch_trimaps / 255.0 # uint8->float32 elif self.proc_trimap == 'as_is': batch_trimaps = batch_trimaps.to(torch.float32) else: raise ValueError( f'proc_trimap = {self.proc_trimap} is not supported.') return batch_trimaps def _preprocess_data_sample(self, data_samples: SampleList, training: bool) -> list: """Preprocess data samples. When `training` is True, fields belong to :attr:`self.data_keys` will be converted to :attr:`self.output_channel_order` and *divided by 255*. When `training` is False, fields belongs to :attr:`self.data_keys` will be attempted to convert to 'BGR' without normalization. The corresponding metainfo related to normalization, channel order conversion will be updated to data sample as well. Args: data_samples (List[DataSample]): A list of data samples to preprocess. training (bool): Whether in training mode. Returns: list: The list of processed data samples. """ if not training: # set default order to BGR in test stage target_order = 'BGR' else: # conversion as default (None) target_order = self.output_channel_order for data_sample in data_samples: for key in self.data_keys: if not hasattr(data_sample, key): # do not raise error here if key != 'gt_fg' and not training: # gt_fg is not required in test stage, therefore do # not print log print_log(f'Cannot find key \'{key}\' in data sample.', 'current', WARNING) break data = data_sample.get(key) data_channel_order = self._parse_channel_order( key, data, data_sample) data, channel_order = self._do_conversion( data, data_channel_order, target_order) if training: data = data / 255. # NOTE: divided by 255 data_sample.set_data({f'{key}': data}) data_process_meta = { f'{key}_enable_norm': self._enable_normalize, f'{key}_output_channel_order': channel_order, f'{key}_mean': self.mean, f'{key}_std': self.std } data_sample.set_metainfo(data_process_meta) if self.stack_data_sample: return DataSample.stack(data_samples) return data_samples def forward(self, data: Sequence[dict], training: bool = False) -> Tuple[torch.Tensor, list]: """Pre-process input images, trimaps, ground-truth as configured. Args: data (Sequence[dict]): data sampled from dataloader. training (bool): Whether to enable training time augmentation. Default: False. Returns: Tuple[torch.Tensor, list]: Batched inputs and list of data samples. """ if not training: # Image may of different size when testing assert len(data['data_samples']) == 1, ( 'only batch_size=1 is supported for testing.') data = super().forward(data, training=training) batch_images = data['inputs'] batch_trimaps = data['data_samples'].trimap batch_trimaps = self._proc_batch_trimap(batch_trimaps) # Stack image and trimap along channel dimension # All existing models do concat at the start of forwarding # and data_sample is a very complex data structure # so this is a simple work-around to make codes simpler # print(f"batch_trimap.dtype = {batch_trimap.dtype}") assert batch_images.ndim == batch_trimaps.ndim == 4 assert batch_images.shape[-2:] == batch_trimaps.shape[-2:], ( 'Expect merged.shape[-2:] == trimap.shape[-2:], ' f'but got {batch_images.shape[-2:]} vs {batch_trimaps.shape[-2:]}') # N, (4/6), H, W batch_inputs = torch.cat((batch_images, batch_trimaps), dim=1) data['inputs'] = batch_inputs return data ================================================ FILE: mmagic/models/diffusion_schedulers/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import warnings from typing import Any, List from mmagic.utils import try_import from .ddim_scheduler import EditDDIMScheduler from .ddpm_scheduler import EditDDPMScheduler class SchedulerWrapper: """Wrapper for schedulers from HuggingFace Diffusers. This wrapper will be set a attribute called `_scheduler_cls` by wrapping function and will be used to initialize the model structure. Example: >>> 1. Load pretrained model from HuggingFace Space. >>> config = dict( >>> type='DDPMScheduler', >>> from_pretrained='lllyasviel/sd-controlnet-canny', >>> subfolder='scheduler') >>> ddpm_scheduler = DIFFUSION_SCHEDULERS.build(config) >>> 2. Initialize model with own defined arguments >>> config = dict( >>> type='EulerDiscreteScheduler', >>> num_train_timesteps=2000, >>> beta_schedule='scaled_linear') >>> euler_scheduler = DIFFUSION_SCHEDULERS.build(config) Args: from_pretrained (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Please refers to `diffusers.model.modeling_utils.ModelMixin.from_pretrained` for more detail. Defaults to None. *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs will be passed to `from_pretrained` function. Otherwise, *args and **kwargs will be used to initialize the model by `self._module_cls(*args, **kwargs)`. """ def __init__(self, from_pretrained=None, from_config=None, *args, **kwargs): scheduler_cls = self._scheduler_cls self._from_pretrained = from_pretrained self._from_config = from_config if self._from_pretrained: self.scheduler = scheduler_cls.from_pretrained( from_pretrained, *args, **kwargs) elif self._from_config: self.scheduler = scheduler_cls.from_config(from_config, *args, **kwargs) else: self.scheduler = scheduler_cls(*args, **kwargs) def __getattr__(self, name: str) -> Any: """This function provide a way to access the attributes of the wrapped scheduler. Args: name (str): The name of the attribute. Returns: Any: The got attribute. """ try: return getattr(self.scheduler, name) except AttributeError: raise AttributeError(f'{name} cannot be found in both ' f'\'{self.__class__.__name__}\' and ' f'\'{self.__class__.__name__}.scheduler\'.') def __repr__(self): """The representation of the wrapper.""" s = super().__repr__() prefix = f'Wrapped Scheduler Class: {self._scheduler_cls}\n' prefix += f'Wrapped Scheduler Name: {self._scheduler_name}\n' if self._from_pretrained: prefix += f'From Pretrained: {self._from_pretrained}\n' if self._from_config: prefix += f'From Config: {self._from_config}\n' s = prefix + s return s def register_diffusers_schedulers() -> List[str]: """Register schedulers in ``diffusers.schedulers`` to the ``DIFFUSION_SCHEDULERS`` registry. Specifically, the registered schedulers from diffusers define the methodology for iteratively adding noise to an image or for updating a sample based on model outputs. See more details about schedulers in diffusers here: https://huggingface.co/docs/diffusers/api/schedulers/overview. Returns: List[str]: A list of registered DIFFUSION_SCHEDULERS' name. """ import inspect from mmagic.registry import DIFFUSION_SCHEDULERS diffusers = try_import('diffusers') if diffusers is None: warnings.warn('Diffusion Schedulers are not registered as expect. ' 'If you want to use diffusion models, ' 'please install diffusers>=0.12.0.') return None def gen_wrapped_cls(scheduler, scheduler_name): return type( scheduler_name, (SchedulerWrapper, ), dict( _scheduler_cls=scheduler, _scheduler_name=scheduler_name, __module__=__name__)) DIFFUSERS_SCHEDULERS = [] for module_name in dir(diffusers.schedulers): if module_name.startswith('Flax'): continue elif module_name.endswith('Scheduler'): _scheduler = getattr(diffusers.schedulers, module_name) if inspect.isclass(_scheduler): wrapped_scheduler = gen_wrapped_cls(_scheduler, module_name) DIFFUSION_SCHEDULERS.register_module( name=module_name, module=wrapped_scheduler) DIFFUSERS_SCHEDULERS.append(module_name) return DIFFUSERS_SCHEDULERS REGISTERED_DIFFUSERS_SCHEDULERS = register_diffusers_schedulers() __all__ = ['EditDDIMScheduler', 'EditDDPMScheduler'] ================================================ FILE: mmagic/models/diffusion_schedulers/ddim_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Union import numpy as np import torch from mmagic.models.utils.diffusion_utils import betas_for_alpha_bar from mmagic.registry import DIFFUSION_SCHEDULERS @DIFFUSION_SCHEDULERS.register_module() class EditDDIMScheduler: """```EditDDIMScheduler``` support the diffusion and reverse process formulated in https://arxiv.org/abs/2010.02502. The code is heavily influenced by https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_ddim.py. # noqa The difference is that we ensemble gradient-guided sampling in step function. Args: num_train_timesteps (int, optional): _description_. Defaults to 1000. beta_start (float, optional): _description_. Defaults to 0.0001. beta_end (float, optional): _description_. Defaults to 0.02. beta_schedule (str, optional): _description_. Defaults to "linear". variance_type (str, optional): _description_. Defaults to 'learned_range'. timestep_values (_type_, optional): _description_. Defaults to None. clip_sample (bool, optional): _description_. Defaults to True. set_alpha_to_one (bool, optional): _description_. Defaults to True. """ def __init__( self, num_train_timesteps=1000, beta_start=0.0001, beta_end=0.02, beta_schedule='linear', variance_type='learned_range', timestep_values=None, clip_sample=True, set_alpha_to_one=True, ): self.num_train_timesteps = num_train_timesteps self.beta_start = beta_start self.beta_end = beta_end self.beta_schedule = beta_schedule self.variance_type = variance_type self.timestep_values = timestep_values self.clip_sample = clip_sample self.set_alpha_to_one = set_alpha_to_one if beta_schedule == 'linear': self.betas = np.linspace( beta_start, beta_end, num_train_timesteps, dtype=np.float32) elif beta_schedule == 'scaled_linear': # this schedule is very specific to the latent diffusion model. self.betas = np.linspace( beta_start**0.5, beta_end**0.5, num_train_timesteps, dtype=np.float32)**2 elif beta_schedule == 'squaredcos_cap_v2': # Glide cosine schedule self.betas = betas_for_alpha_bar(num_train_timesteps) else: raise NotImplementedError( f'{beta_schedule} does is not implemented for {self.__class__}' ) self.alphas = 1.0 - self.betas self.alphas_cumprod = np.cumprod(self.alphas, axis=0) # At every step in ddim, we are looking into the # previous alphas_cumprod. For the final step, # there is no previous alphas_cumprod because we are already # at 0 `set_alpha_to_one` decides whether we set this parameter # simply to one or whether we use the final alpha of the # "non-previous" one. self.final_alpha_cumprod = np.array( 1.0) if set_alpha_to_one else self.alphas_cumprod[0] # standard deviation of the initial noise distribution self.init_noise_sigma = 1.0 # setable values self.num_inference_steps = None self.timesteps = np.arange(0, num_train_timesteps)[::-1].copy() def set_timesteps(self, num_inference_steps, offset=0): """set time steps.""" self.num_inference_steps = num_inference_steps self.timesteps = np.arange( 0, self.num_train_timesteps, self.num_train_timesteps // self.num_inference_steps)[::-1].copy() self.timesteps += offset def scale_model_input(self, sample: torch.FloatTensor, timestep: Optional[int] = None) -> torch.FloatTensor: """Ensures interchangeability with schedulers that need to scale the denoising model input depending on the current timestep. Args: sample (`torch.FloatTensor`): input sample timestep (`int`, optional): current timestep Returns: `torch.FloatTensor`: scaled input sample """ return sample def _get_variance(self, timestep, prev_timestep): """get variance.""" alpha_prod_t = self.alphas_cumprod[timestep] alpha_prod_t_prev = self.alphas_cumprod[ prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod beta_prod_t = 1 - alpha_prod_t beta_prod_t_prev = 1 - alpha_prod_t_prev variance = (beta_prod_t_prev / beta_prod_t) * (1 - alpha_prod_t / alpha_prod_t_prev) return variance def step( self, model_output: Union[torch.FloatTensor, np.ndarray], timestep: int, sample: Union[torch.FloatTensor, np.ndarray], cond_fn=None, cond_kwargs={}, eta: float = 0.0, use_clipped_model_output: bool = False, generator=None, ): """step forward.""" output = {} if self.num_inference_steps is None: raise ValueError("Number of inference steps is 'None', '\ 'you need to run 'set_timesteps' '\ 'after creating the scheduler") pred = None if isinstance(model_output, dict): pred = model_output['pred'] model_output = model_output['eps'] elif model_output.shape[1] == sample.shape[ 1] * 2 and self.variance_type in ['learned', 'learned_range']: model_output, _ = torch.split(model_output, sample.shape[1], dim=1) else: if not model_output.shape == sample.shape: raise TypeError # See formulas (12) and (16) of DDIM paper https://arxiv.org/pdf/2010.02502.pdf # noqa # Ideally, read DDIM paper in-detail understanding # Notation ( -> # - pred_noise_t -> e_theta(x_t, t) # - pred_original_sample -> f_theta(x_t, t) or x_0 # - std_dev_t -> sigma_t # - eta -> η # - pred_sample_direction -> "direction pointingc to x_t" # - pred_prev_sample -> "x_t-1" # 1. get previous step value (=t-1) prev_timestep = ( timestep - self.num_train_timesteps // self.num_inference_steps) # 2. compute alphas, betas alpha_prod_t = self.alphas_cumprod[timestep] alpha_prod_t_prev = self.alphas_cumprod[ prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod beta_prod_t = 1 - alpha_prod_t # 3. compute predicted original sample from predicted noise also called # "predicted x_0" of formula (12) from https://arxiv.org/pdf/2010.02502.pdf # noqa pred_original_sample = (sample - ( (beta_prod_t)**(0.5)) * model_output) / alpha_prod_t**(0.5) if pred is not None: pred_original_sample = pred gradient = 0. if cond_fn is not None: if cond_fn.__name__ == 'classifier_grad': y = cond_kwargs['y'] classifier = cond_kwargs['classifier'] classifier_scale = cond_kwargs['classifier_scale'] gradient = cond_fn( classifier, sample, timestep, y=y, classifier_scale=classifier_scale) else: gradient = cond_fn( cond_kwargs.pop('unet'), self, sample, timestep, beta_prod_t, cond_kwargs.pop('model_stats'), **cond_kwargs) model_output = model_output - (beta_prod_t**0.5) * gradient pred_original_sample = ( sample - (beta_prod_t**(0.5)) * model_output) / alpha_prod_t**(0.5) # 4. Clip "predicted x_0" if self.clip_sample: pred_original_sample = torch.clamp(pred_original_sample, -1, 1) # 5. compute variance: "sigma_t(η)" -> see formula (16) # σ_t = sqrt((1 − α_t−1)/(1 − α_t)) * sqrt(1 − α_t/α_t−1) variance = self._get_variance(timestep, prev_timestep) std_dev_t = eta * variance**(0.5) output.update(dict(sigma=std_dev_t)) if use_clipped_model_output: # the model_output is always # re-derived from the clipped x_0 in Glide model_output = (sample - (alpha_prod_t**(0.5)) * pred_original_sample) / beta_prod_t**(0.5) # 6. compute "direction pointing to x_t" of formula (12) from https://arxiv.org/pdf/2010.02502.pdf # noqa pred_sample_direction = (1 - alpha_prod_t_prev - std_dev_t**2)**(0.5) * model_output # 7. compute x_t without "random noise" of # formula (12) from https://arxiv.org/pdf/2010.02502.pdf prev_mean = alpha_prod_t_prev**( 0.5) * pred_original_sample + pred_sample_direction output.update(dict(mean=prev_mean, prev_sample=prev_mean)) if eta > 0: device = model_output.device if torch.is_tensor( model_output) else 'cpu' noise = torch.randn( model_output.shape, generator=generator).to(device) variance = std_dev_t * noise if not torch.is_tensor(model_output): variance = variance.numpy() prev_sample = prev_mean + variance output.update({'prev_sample': prev_sample}) # NOTE: this x0 is twice computed output.update({ 'original_sample': pred_original_sample, 'beta_prod_t': beta_prod_t }) return output def add_noise(self, original_samples, noise, timesteps): """add noise.""" sqrt_alpha_prod = self.alphas_cumprod[timesteps]**0.5 sqrt_one_minus_alpha_prod = (1 - self.alphas_cumprod[timesteps])**0.5 noisy_samples = ( sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise) return noisy_samples def __len__(self): return self.num_train_timesteps ================================================ FILE: mmagic/models/diffusion_schedulers/ddpm_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Union import numpy as np import torch from mmagic.models.utils.diffusion_utils import betas_for_alpha_bar from mmagic.registry import DIFFUSION_SCHEDULERS @DIFFUSION_SCHEDULERS.register_module() class EditDDPMScheduler: def __init__(self, num_train_timesteps: int = 1000, beta_start: float = 0.0001, beta_end: float = 0.02, beta_schedule: str = 'linear', trained_betas: Optional[Union[np.array, list]] = None, variance_type='fixed_small', clip_sample=True): """```EditDDPMScheduler``` support the diffusion and reverse process formulated in https://arxiv.org/abs/2006.11239. The code is heavily influenced by https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_ddpm.py. # noqa Args: num_train_timesteps (int, optional): The timesteps for training process. Defaults to 1000. beta_start (float, optional): The beta value at start. The beta values will be interpolated from beta_start to beta_end. Defaults to 0.0001. beta_end (float, optional): The beta value at the end. The beta values will be interpolated from beta_start to beta_end. Defaults to 0.02. beta_schedule (str, optional): The interpolation schedule for beta values. Supported choices are 'linear', 'scaled_linear', and 'squaredcos_cap_v2'. Defaults to 'linear'. trained_betas (list, np.array, optional): betas directly to the constructor to bypass `beta_start`, `beta_end` etc. Defaults to None. variance_type (str, optional): How denoising unet output variance value. Supported choices are 'fixed_small', 'fixed_small_log', 'fixed_large', 'fixed_large_log', 'learned', and 'leanred_range'. Defaults to 'fixed_small'. clip_sample (bool, optional): Whether clip the value of predicted original image (x0) to [-1, 1]. Defaults to True. """ self.num_train_timesteps = num_train_timesteps if trained_betas is not None: self.betas = np.asarray(trained_betas) elif beta_schedule == 'linear': self.betas = np.linspace( beta_start, beta_end, num_train_timesteps, dtype=np.float64) elif beta_schedule == 'scaled_linear': # this schedule is very specific to the latent diffusion model. self.betas = np.linspace( beta_start**0.5, beta_end**0.5, num_train_timesteps, dtype=np.float32)**2 elif beta_schedule == 'squaredcos_cap_v2': # Glide cosine schedule self.betas = betas_for_alpha_bar(num_train_timesteps) else: raise NotImplementedError( f'{beta_schedule} does is not implemented for {self.__class__}' ) self.alphas = 1.0 - self.betas self.alphas_cumprod = np.cumprod(self.alphas, axis=0) self.one = np.array(1.0) # setable values self.num_inference_steps = None self.timesteps = np.arange(0, num_train_timesteps)[::-1].copy() self.variance_type = variance_type self.clip_sample = clip_sample def set_timesteps(self, num_inference_steps): """set timesteps.""" num_inference_steps = min(self.num_train_timesteps, num_inference_steps) self.num_inference_steps = num_inference_steps self.timesteps = np.arange( 0, self.num_train_timesteps, self.num_train_timesteps // self.num_inference_steps)[::-1].copy() def _get_variance(self, t, predicted_variance=None, variance_type=None): """get variance.""" alpha_prod_t = self.alphas_cumprod[t] alpha_prod_t_prev = self.alphas_cumprod[t - 1] if t > 0 else self.one # For t > 0, compute predicted variance βt (see formula (6) and (7) from https://arxiv.org/pdf/2006.11239.pdf) # noqa # and sample from it to get previous sample # x_{t-1} ~ N(pred_prev_sample, variance) == add variance to pred_sample # noqa variance = (1 - alpha_prod_t_prev) / (1 - alpha_prod_t) * self.betas[t] if t == 0: log_variance = (1 - alpha_prod_t_prev) / ( 1 - alpha_prod_t) * self.betas[1] else: log_variance = np.log(variance) if variance_type is None: variance_type = self.variance_type # hacks - were probs added for training stability if variance_type == 'fixed_small': variance = np.clip(variance, a_min=1e-20, a_max=10000) # for rl-diffusion_scheduler https://arxiv.org/abs/2205.09991 elif variance_type == 'fixed_small_log': variance = np.log(np.clip(variance, a_min=1e-20, a_max=10000)) elif variance_type == 'fixed_large': variance = self.betas[t] elif variance_type == 'fixed_large_log': # Glide max_log variance = np.log(self.betas[t]) elif variance_type == 'learned': return predicted_variance elif variance_type == 'learned_range': min_log = log_variance max_log = np.log(self.betas[t]) frac = (predicted_variance + 1) / 2 log_variance = frac * max_log + (1 - frac) * min_log variance = torch.exp(log_variance) return variance def step(self, model_output: torch.FloatTensor, timestep: int, sample: torch.FloatTensor, predict_epsilon=True, cond_fn=None, cond_kwargs={}, generator=None): t = timestep """step forward""" if model_output.shape[1] == sample.shape[ 1] * 2 and self.variance_type in ['learned', 'learned_range']: model_output, predicted_variance = torch.split( model_output, sample.shape[1], dim=1) else: predicted_variance = None # 1. compute alphas, betas alpha_prod_t = self.alphas_cumprod[t] alpha_prod_t_prev = self.alphas_cumprod[t - 1] if t > 0 else self.one beta_prod_t = 1 - alpha_prod_t beta_prod_t_prev = 1 - alpha_prod_t_prev # 2. compute predicted original sample from predicted noise also called # "predicted x_0" of formula (15) from https://arxiv.org/pdf/2006.11239.pdf # noqa if predict_epsilon: pred_original_sample = ( (sample - beta_prod_t**(0.5) * model_output) / alpha_prod_t**(0.5)) else: pred_original_sample = model_output # 3. Clip "predicted x_0" if self.clip_sample: pred_original_sample = torch.clamp(pred_original_sample, -1, 1) # 4. Compute coefficients for pred_original_sample x_0 and current sample x_t # noqa # See formula (7) from https://arxiv.org/pdf/2006.11239.pdf pred_original_sample_coeff = (alpha_prod_t_prev**(0.5) * self.betas[t]) / beta_prod_t current_sample_coeff = self.alphas[t]**( 0.5) * beta_prod_t_prev / beta_prod_t # 5. Compute predicted previous sample µ_t # See formula (7) from https://arxiv.org/pdf/2006.11239.pdf pred_prev_mean = ( pred_original_sample_coeff * pred_original_sample + current_sample_coeff * sample) # 6. Add noise noise = torch.randn_like(model_output) sigma = 0 if t > 0: sigma = self._get_variance( t, predicted_variance=predicted_variance)**0.5 pred_prev_sample = pred_prev_mean + sigma * noise gradient = 0. if cond_fn is not None: y = cond_kwargs['y'] classifier = cond_kwargs['classifier'] classifier_scale = cond_kwargs['classifier_scale'] gradient = cond_fn( classifier, sample, timestep, y=y, classifier_scale=classifier_scale) guided_mean = pred_prev_mean + sigma * gradient pred_prev_sample = guided_mean + sigma * noise return { 'prev_sample': pred_prev_sample, 'mean': pred_prev_mean, 'sigma': sigma, 'noise': noise } def add_noise(self, original_samples, noise, timesteps): """add noise.""" sqrt_alpha_prod = self.alphas_cumprod[timesteps]**0.5 sqrt_one_minus_alpha_prod = (1 - self.alphas_cumprod[timesteps])**0.5 noisy_samples = ( sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise) return noisy_samples def training_loss(self, model, x_0, t): raise NotImplementedError( 'This function is supposed to return ' 'a dict containing loss items giving sampled x0 and timestep.') def sample_timestep(self): raise NotImplementedError def __len__(self): return self.num_train_timesteps ================================================ FILE: mmagic/models/editors/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .animatediff import AnimateDiff, UNet3DConditionMotionModel from .aotgan import AOTBlockNeck, AOTEncoderDecoder, AOTInpaintor from .arcface import IDLossModel from .basicvsr import BasicVSR, BasicVSRNet from .basicvsr_plusplus_net import BasicVSRPlusPlusNet from .biggan import BigGAN from .cain import CAIN, CAINNet from .controlnet import ControlStableDiffusion from .cyclegan import CycleGAN from .dcgan import DCGAN from .ddpm import DenoisingUnet from .deblurganv2 import (DeblurGanV2, DeblurGanV2Discriminator, DeblurGanV2Generator) from .deepfillv1 import (ContextualAttentionModule, ContextualAttentionNeck, DeepFillDecoder, DeepFillEncoder, DeepFillRefiner, DeepFillv1Discriminators, DeepFillv1Inpaintor) from .deepfillv2 import DeepFillEncoderDecoder from .dic import (DIC, DICNet, FeedbackBlock, FeedbackBlockCustom, FeedbackBlockHeatmapAttention, LightCNN, MaxFeature) from .dim import DIM from .disco_diffusion import ClipWrapper, DiscoDiffusion from .dreambooth import DreamBooth from .edsr import EDSRNet from .edvr import EDVR, EDVRNet from .eg3d import EG3D from .esrgan import ESRGAN, RRDBNet from .fastcomposer import FastComposer from .fba import FBADecoder, FBAResnetDilated from .flavr import FLAVR, FLAVRNet from .gca import GCA from .ggan import GGAN from .glean import GLEANStyleGANv2 from .global_local import (GLDecoder, GLDilationNeck, GLEncoder, GLEncoderDecoder) from .guided_diffusion import AblatedDiffusionModel from .iconvsr import IconVSRNet from .indexnet import (DepthwiseIndexBlock, HolisticIndexBlock, IndexedUpsample, IndexNet, IndexNetDecoder, IndexNetEncoder) from .inst_colorization import InstColorization from .liif import LIIF, MLPRefiner from .lsgan import LSGAN from .mspie import MSPIEStyleGAN2, PESinGAN from .nafnet import NAFBaseline, NAFBaselineLocal, NAFNet, NAFNetLocal from .pconv import (MaskConvModule, PartialConv2d, PConvDecoder, PConvEncoder, PConvEncoderDecoder, PConvInpaintor) from .pggan import ProgressiveGrowingGAN from .pix2pix import Pix2Pix from .plain import PlainDecoder, PlainRefiner from .rdn import RDNNet from .real_basicvsr import RealBasicVSR, RealBasicVSRNet from .real_esrgan import RealESRGAN, UNetDiscriminatorWithSpectralNorm from .restormer import Restormer from .sagan import SAGAN from .singan import SinGAN from .srcnn import SRCNNNet from .srgan import SRGAN, ModifiedVGG, MSRResNet from .stable_diffusion import StableDiffusion, StableDiffusionInpaint from .stable_diffusion_xl import StableDiffusionXL from .stylegan1 import StyleGAN1 from .stylegan2 import StyleGAN2 from .stylegan3 import StyleGAN3, StyleGAN3Generator from .swinir import SwinIRNet from .tdan import TDAN, TDANNet from .textual_inversion import TextualInversion from .tof import TOFlowVFINet, TOFlowVSRNet, ToFResBlock from .ttsr import LTE, TTSR, SearchTransformer, TTSRDiscriminator, TTSRNet from .vico import ViCo from .wgan_gp import WGANGP __all__ = [ 'AOTEncoderDecoder', 'AOTBlockNeck', 'AOTInpaintor', 'ContextualAttentionNeck', 'ContextualAttentionModule', 'CAIN', 'CAINNet', 'DIM', 'DIC', 'DICNet', 'LightCNN', 'FeedbackBlock', 'FeedbackBlockHeatmapAttention', 'FeedbackBlockCustom', 'MaxFeature', 'FLAVR', 'FLAVRNet', 'ToFResBlock', 'TOFlowVFINet', 'TOFlowVSRNet', 'DeepFillEncoder', 'DeepFillEncoderDecoder', 'DeepFillDecoder', 'DeepFillRefiner', 'DeepFillv1Inpaintor', 'DeepFillv1Discriminators', 'EDSRNet', 'ESRGAN', 'DepthwiseIndexBlock', 'HolisticIndexBlock', 'IndexNet', 'IndexNetEncoder', 'IndexedUpsample', 'IndexNetDecoder', 'GCA', 'GLEncoderDecoder', 'GLEncoder', 'GLDecoder', 'GLDilationNeck', 'PartialConv2d', 'PConvEncoderDecoder', 'PConvEncoder', 'PConvDecoder', 'PConvInpaintor', 'MaskConvModule', 'RRDBNet', 'SRCNNNet', 'RRDBNet', 'RealESRGAN', 'UNetDiscriminatorWithSpectralNorm', 'EDVR', 'EDVRNet', 'TDAN', 'TDANNet', 'BasicVSR', 'BasicVSRNet', 'BasicVSRPlusPlusNet', 'IconVSRNet', 'RealBasicVSR', 'RealBasicVSRNet', 'SRGAN', 'MaxFeature', 'ModifiedVGG', 'MSRResNet', 'RDNNet', 'LTE', 'TTSR', 'TTSRNet', 'TTSRDiscriminator', 'TTSRNet', 'SearchTransformer', 'GLEANStyleGANv2', 'LIIF', 'MLPRefiner', 'PlainRefiner', 'PlainDecoder', 'FBAResnetDilated', 'FBADecoder', 'WGANGP', 'CycleGAN', 'SAGAN', 'LSGAN', 'GGAN', 'Pix2Pix', 'StyleGAN1', 'StyleGAN2', 'StyleGAN3', 'BigGAN', 'DCGAN', 'ProgressiveGrowingGAN', 'SinGAN', 'AblatedDiffusionModel', 'DiscoDiffusion', 'IDLossModel', 'PESinGAN', 'MSPIEStyleGAN2', 'StyleGAN3Generator', 'InstColorization', 'NAFBaseline', 'NAFBaselineLocal', 'NAFNet', 'NAFNetLocal', 'DenoisingUnet', 'ClipWrapper', 'EG3D', 'Restormer', 'SwinIRNet', 'StableDiffusion', 'ControlStableDiffusion', 'DreamBooth', 'TextualInversion', 'DeblurGanV2', 'DeblurGanV2Generator', 'DeblurGanV2Discriminator', 'StableDiffusionInpaint', 'ViCo', 'FastComposer', 'AnimateDiff', 'UNet3DConditionMotionModel', 'StableDiffusionXL' ] ================================================ FILE: mmagic/models/editors/animatediff/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .animatediff import AnimateDiff from .animatediff_utils import save_videos_grid from .unet_3d import UNet3DConditionMotionModel __all__ = ['AnimateDiff', 'save_videos_grid', 'UNet3DConditionMotionModel'] ================================================ FILE: mmagic/models/editors/animatediff/animatediff.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import inspect from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn from einops import rearrange from mmengine import print_log from mmengine.logging import MMLogger from mmengine.model import BaseModel from safetensors import safe_open from tqdm import tqdm from mmagic.models.archs import TokenizerWrapper, set_lora from mmagic.models.utils import build_module, set_tomesd, set_xformers from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from .animatediff_utils import (convert_ldm_clip_checkpoint, convert_ldm_unet_checkpoint, convert_ldm_vae_checkpoint) logger = MMLogger.get_current_instance() ModelType = Union[Dict, nn.Module] @MODELS.register_module('animatediff') @MODELS.register_module() class AnimateDiff(BaseModel): """Implementation of `AnimateDiff. `_ (AnimateDiff). Args: vae (Union[dict, nn.Module]): The config or module for VAE model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. tokenizer (str): The **name** for CLIP tokenizer. unet (Union[dict, nn.Module]): The config or module for Unet model. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. lora_config (dict, optional): The config for LoRA finetuning. Defaults to None. val_prompts (Union[str, List[str]], optional): The prompts for validation. Defaults to None. class_prior_prompt (str, optional): The prompt for class prior loss. num_class_images (int, optional): The number of images for class prior. Defaults to 3. prior_loss_weight (float, optional): The weight for class prior loss. Defaults to 0. fine_tune_text_encoder (bool, optional): Whether to fine-tune text encoder. Defaults to False. dtype (str, optional): The dtype for the model. Defaults to 'fp16'. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise # noqa Defaults to 0. tomesd_cfg (dict, optional): The config for TOMESD. Please refers to https://github.com/dbolya/tomesd and https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/utils/tome_utils.py for detail. # noqa Defaults to None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Defaults to dict(type='DataPreprocessor'). init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Defaults to None/ """ def __init__( self, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: str = 'fp32', enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor=dict(type='DataPreprocessor'), motion_module_cfg: Optional[dict] = None, dream_booth_lora_cfg: Optional[dict] = None, ): super().__init__(data_preprocessor) default_args = dict() if dtype is not None: default_args['dtype'] = dtype self.dtype = torch.float32 if dtype in ['float16', 'fp16', 'half']: self.dtype = torch.float16 elif dtype == 'bf16': self.dtype = torch.bfloat16 else: assert dtype in [ 'fp32', None ], ('dtype must be one of \'fp32\', \'fp16\', \'bf16\' or None.') self.vae = build_module(vae, MODELS, default_args=default_args) self.unet = build_module(unet, MODELS) # NOTE: initialize unet as fp32 self._unet_ori_dtype = next(self.unet.parameters()).dtype print_log(f'Set UNet dtype to \'{self._unet_ori_dtype}\'.', 'current') self.init_motion_module(motion_module_cfg) self.scheduler = build_module(scheduler, DIFFUSION_SCHEDULERS) if test_scheduler is None: self.test_scheduler = deepcopy(self.scheduler) else: self.test_scheduler = build_module(test_scheduler, DIFFUSION_SCHEDULERS) self.text_encoder = build_module(text_encoder, MODELS) if not isinstance(tokenizer, str): self.tokenizer = tokenizer else: # NOTE: here we assume tokenizer is an string self.tokenizer = TokenizerWrapper(tokenizer, subfolder='tokenizer') self.unet_sample_size = self.unet.sample_size self.vae_scale_factor = 2**(len(self.vae.block_out_channels) - 1) self.enable_noise_offset = noise_offset_weight > 0 self.noise_offset_weight = noise_offset_weight self.enable_xformers = enable_xformers self.unet.set_use_memory_efficient_attention_xformers(True) self.tomesd_cfg = tomesd_cfg self.set_tomesd() self.init_dreambooth_lora(dream_booth_lora_cfg) self.prepare_model() def set_xformers(self, module: Optional[nn.Module] = None) -> nn.Module: """Set xformers for the model. Returns: nn.Module: The model with xformers. """ if self.enable_xformers: if module is None: set_xformers(self) else: set_xformers(module) def set_tomesd(self) -> nn.Module: """Set ToMe for the stable diffusion model. Returns: nn.Module: The model with ToMe. """ if self.tomesd_cfg is not None: set_tomesd(self, **self.tomesd_cfg) @property def device(self): """Set device for the model.""" return next(self.parameters()).device def init_motion_module(self, motion_module_cfg): if motion_module_cfg is not None: if 'path' in motion_module_cfg.keys(): motion_module_state_dict = torch.load( motion_module_cfg['path'], map_location='cpu') # if "global_step" in motion_module_state_dict: # func_args.update({"global_step": # motion_module_state_dict["global_step"]}) missing, unexpected = self.unet.load_state_dict( motion_module_state_dict, strict=False) assert len(unexpected) == 0 def init_dreambooth_lora(self, dream_booth_lora_cfg): # TODO: finish if dream_booth_lora_cfg is not None: if 'path' in dream_booth_lora_cfg.keys(): state_dict = {} with safe_open( dream_booth_lora_cfg['path'], framework='pt', device='cpu') as f: for key in f.keys(): state_dict[key] = f.get_tensor(key) # vae converted_vae_checkpoint = convert_ldm_vae_checkpoint( state_dict, self.vae.config) self.vae.load_state_dict(converted_vae_checkpoint) # unet converted_unet_checkpoint = convert_ldm_unet_checkpoint( state_dict, self.unet.config) self.unet.load_state_dict( converted_unet_checkpoint, strict=False) # text_model self.text_encoder = convert_ldm_clip_checkpoint(state_dict) # self.convert_lora(state_dict) def _encode_prompt(self, prompt, device, num_videos_per_prompt, do_classifier_free_guidance, negative_prompt): """Encodes the prompt into text encoder hidden states.""" batch_size = len(prompt) if isinstance(prompt, list) else 1 text_inputs = self.tokenizer( prompt, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_input_ids = text_inputs.input_ids untruncated_ids = self.tokenizer( prompt, padding='longest', return_tensors='pt').input_ids if untruncated_ids.shape[-1] >= text_input_ids.shape[ -1] and not torch.equal(text_input_ids, untruncated_ids): removed_text = self.tokenizer.batch_decode( untruncated_ids[:, self.tokenizer.model_max_length - 1:-1]) logger.warning( 'The following part of your input was truncated ' f'because CLIP can only handle sequences up to' f' {self.tokenizer.model_max_length} tokens: {removed_text}') text_encoder = self.text_encoder.module if hasattr( self.text_encoder, 'module') else self.text_encoder if hasattr(text_encoder.config, 'use_attention_mask' ) and text_encoder.config.use_attention_mask: attention_mask = text_inputs.attention_mask.to(device) else: attention_mask = None text_embeddings = self.text_encoder( text_input_ids.to(device), attention_mask=attention_mask, ) text_embeddings = text_embeddings[0] # duplicate text embeddings for each generation # per prompt, using mps friendly method bs_embed, seq_len, _ = text_embeddings.shape text_embeddings = text_embeddings.repeat(1, num_videos_per_prompt, 1) text_embeddings = text_embeddings.view( bs_embed * num_videos_per_prompt, seq_len, -1) # get unconditional embeddings for classifier free guidance if do_classifier_free_guidance: uncond_tokens: List[str] if negative_prompt is None: uncond_tokens = [''] * batch_size elif type(prompt) is not type(negative_prompt): raise TypeError( f'`negative_prompt` should be the same type ' f'to `prompt`, but got {type(negative_prompt)} !=' f' {type(prompt)}.') elif isinstance(negative_prompt, str): uncond_tokens = [negative_prompt] elif batch_size != len(negative_prompt): raise ValueError( f'`negative_prompt`: {negative_prompt} has ' f'batch size {len(negative_prompt)}, but `prompt`:' f' {prompt} has batch size {batch_size}. Please ' f'make sure that passed `negative_prompt` matches' ' the batch size of `prompt`.') else: uncond_tokens = negative_prompt max_length = text_input_ids.shape[-1] uncond_input = self.tokenizer( uncond_tokens, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) if hasattr(text_encoder.config, 'use_attention_mask' ) and text_encoder.config.use_attention_mask: attention_mask = uncond_input.attention_mask.to(device) else: attention_mask = None uncond_embeddings = self.text_encoder( uncond_input.input_ids.to(device), attention_mask=attention_mask, ) uncond_embeddings = uncond_embeddings[0] # duplicate unconditional embeddings for each generation # per prompt, using mps friendly method seq_len = uncond_embeddings.shape[1] uncond_embeddings = uncond_embeddings.repeat( 1, num_videos_per_prompt, 1) uncond_embeddings = uncond_embeddings.view( batch_size * num_videos_per_prompt, seq_len, -1) # For classifier free guidance, we need to do two forward passes. # Here we concatenate the unconditional and text embeddings # into a single batch to avoid doing two forward passes text_embeddings = torch.cat([uncond_embeddings, text_embeddings]) return text_embeddings def decode_latents(self, latents): """latents decoder.""" video_length = latents.shape[2] latents = 1 / 0.18215 * latents latents = rearrange(latents, 'b c f h w -> (b f) c h w') # video = self.vae.decode(latents).sample video = [] for frame_idx in tqdm(range(latents.shape[0])): video.append( self.vae.decode(latents[frame_idx:frame_idx + 1]).sample) video = torch.cat(video) video = rearrange(video, '(b f) c h w -> b c f h w', f=video_length) video = (video / 2 + 0.5).clamp(0, 1) # we always cast to float32 as this does not cause significant # overhead and is compatible with bfloa16 video = video.cpu().float().numpy() return video def prepare_extra_step_kwargs(self, generator, eta): """Prepare extra kwargs for the scheduler step, since not all schedulers have the same signature eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.""" # prepare extra kwargs for the scheduler step, since not all # schedulers have the same signature # eta (η) is only used with the DDIMScheduler, it will # be ignored for other schedulers. # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 # and should be between [0, 1] accepts_eta = 'eta' in set( inspect.signature(self.scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def check_inputs(self, prompt, height, width): """Check inputs. Raise error if not correct """ if not isinstance(prompt, str) and not isinstance(prompt, list): raise ValueError(f'`prompt` has to be of type `str`' f' or `list` but is {type(prompt)}') if height % 8 != 0 or width % 8 != 0: raise ValueError(f'`height` and `width` have to be divisible' f' by 8 but are {height} and {width}.') # if (callback_steps is None) or ( # callback_steps is not None and (not isinstance(callback_steps, # int) or callback_steps <= 0) # ): # raise ValueError( # f"`callback_steps` has to be a positive integer but # is {callback_steps} of type" # f" {type(callback_steps)}." # ) def convert_lora(self, state_dict, LORA_PREFIX_UNET='lora_unet', LORA_PREFIX_TEXT_ENCODER='lora_te', alpha=0.6): """ Convert lora for unet and text_encoder TODO: use this function to convert lora Args: state_dict (_type_): _description_ LORA_PREFIX_UNET (str, optional): _description_. Defaults to 'lora_unet'. LORA_PREFIX_TEXT_ENCODER (str, optional): _description_. Defaults to 'lora_te'. alpha (float, optional): _description_. Defaults to 0.6. Returns: TODO: check each output type _type_: unet && text_encoder """ # load base model # pipeline = StableDiffusionPipeline.from_pretrained(base_model_path, # torch_dtype=torch.float32) # load LoRA weight from .safetensors # state_dict = load_file(checkpoint_path) visited = [] # directly update weight in diffusers model for key in state_dict: # it is suggested to print out the key, it usually # will be something like below # "lora_te_text_model_encoder_layers_0_self_attn_k_proj.lora_down.weight" # as we have set the alpha beforehand, so just skip if '.alpha' in key or key in visited: continue if 'text' in key: layer_infos = key.split('.')[0].split( LORA_PREFIX_TEXT_ENCODER + '_')[-1].split('_') curr_layer = self.text_encoder else: layer_infos = key.split('.')[0].split(LORA_PREFIX_UNET + '_')[-1].split('_') curr_layer = self.unet # find the target layer temp_name = layer_infos.pop(0) while len(layer_infos) > -1: try: curr_layer = curr_layer.__getattr__(temp_name) if len(layer_infos) > 0: temp_name = layer_infos.pop(0) elif len(layer_infos) == 0: break except Exception: if len(temp_name) > 0: temp_name += '_' + layer_infos.pop(0) else: temp_name = layer_infos.pop(0) pair_keys = [] if 'lora_down' in key: pair_keys.append(key.replace('lora_down', 'lora_up')) pair_keys.append(key) else: pair_keys.append(key) pair_keys.append(key.replace('lora_up', 'lora_down')) # update weight if len(state_dict[pair_keys[0]].shape) == 4: weight_up = state_dict[pair_keys[0]].squeeze(3).squeeze(2).to( torch.float32) weight_down = state_dict[pair_keys[1]].squeeze(3).squeeze( 2).to(torch.float32) curr_layer.weight.data += alpha * torch.mm( weight_up, weight_down).unsqueeze(2).unsqueeze(3).to( curr_layer.weight.data.device) else: weight_up = state_dict[pair_keys[0]].to(torch.float32) weight_down = state_dict[pair_keys[1]].to(torch.float32) curr_layer.weight.data += alpha * torch.mm( weight_up, weight_down).to(curr_layer.weight.data.device) # update visited list for item in pair_keys: visited.append(item) return self.unet, self.text_encoder def prepare_latents(self, batch_size, num_channels_latents, video_length, height, width, dtype, device, generator, latents=None): """Prepare latent variables.""" shape = (batch_size, num_channels_latents, video_length, height // self.vae_scale_factor, width // self.vae_scale_factor) if isinstance(generator, list) and len(generator) != batch_size: raise ValueError( f'You have passed a list of generators of length ' f'{len(generator)}, but requested an effective batch' f' size of {batch_size}. Make sure the batch size matches the' f' length of the generators.') if latents is None: rand_device = 'cpu' if device.type == 'mps' else device if isinstance(generator, list): shape = shape # shape = (1,) + shape[1:] latents = [ torch.randn( shape, generator=generator[i], device=rand_device, dtype=dtype) for i in range(batch_size) ] latents = torch.cat(latents, dim=0).to(device) else: latents = torch.randn( shape, generator=generator, device=rand_device, dtype=dtype).to(device) else: if latents.shape != shape: raise ValueError(f'Unexpected latents shape, got ' f'{latents.shape}, expected {shape}') latents = latents.to(device) # scale the initial noise by the standard deviation # required by the scheduler latents = latents * self.scheduler.init_noise_sigma return latents def prepare_model(self): """Prepare model for training. Move model to target dtype and disable gradient for some models. """ self.vae.requires_grad_(False) print_log('Set VAE untrainable.', 'current') self.vae.to(self.dtype) print_log(f'Move VAE to {self.dtype}.', 'current') # if not self.finetune_text_encoder or self.lora_config: if 1: self.text_encoder.requires_grad_(False) print_log('Set Text Encoder untrainable.', 'current') self.text_encoder.to(self.dtype) print_log(f'Move Text Encoder to {self.dtype}.', 'current') # if self.lora_config: if 1: self.unet.requires_grad_(False) print_log('Set Unet untrainable.', 'current') def set_lora(self): """Set LORA for model.""" if self.lora_config: set_lora(self.unet, self.lora_config) @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) data_samples = data['data_samples'] if self.val_prompts is None: prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples.split() * len(prompt) data_samples = DataSample.stack(data_samples.split() * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ if self.val_prompts is None: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples = DataSample.stack(data['data_samples'] * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def infer(self, prompt: Union[str, List[str]], video_length: Optional[int] = 16, height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_videos_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, latents: Optional[torch.FloatTensor] = None, return_type: Optional[str] = 'tensor', show_progress: bool = True, seed: Optional[int] = 1007): """Function invoked when calling the pipeline for generation. Args: prompt (str or List[str]): The prompt or prompts to guide the video generation. video_length (int, Option): The number of frames of the generated video. Defaults to 16. height (int, Optional): The height in pixels of the generated image. If not passed, the height will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. width (int, Optional): The width in pixels of the generated image. If not passed, the width will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. num_inference_steps (int): The number of denoising steps. More denoising steps usually lead to a higher quality video at the expense of slower inference. Defaults to 50. guidance_scale (float): Guidance scale as defined in Classifier- Free Diffusion Guidance (https://arxiv.org/abs/2207.12598). Defaults to 7.5 negative_prompt (str or List[str], optional): The prompt or prompts not to guide the video generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than 1). Defaults to None. num_videos_per_prompt (int): The number of videos to generate per prompt. Defaults to 1. eta (float): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to DDIMScheduler, will be ignored for others. Defaults to 0.0. generator (torch.Generator, optional): A torch generator to make generation deterministic. Defaults to None. latents (torch.FloatTensor, optional): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for video generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. Defaults to None. return_type (str): The return type of the inference results. Supported types are 'video', 'numpy', 'tensor'. If 'video' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. #TODO Returns: dict: A dict containing the generated video """ assert return_type in ['image', 'tensor', 'numpy'] # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor if seed != -1: torch.manual_seed(seed) print_log(f'current seed: {torch.initial_seed()}') print_log(f'sampling {prompt} ...') # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # NOTE: aligned with origin repo # 2. Define call parameters batch_size = 1 if latents is not None: batch_size = latents.shape[0] if isinstance(prompt, list): batch_size = len(prompt) device = self.device # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 video_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype # 3. Encode input prompt prompt = prompt if isinstance(prompt, list) else [prompt] * batch_size if negative_prompt is not None: negative_prompt = negative_prompt if isinstance( negative_prompt, list) else [negative_prompt] * batch_size text_embeddings = self._encode_prompt( prompt, device, num_videos_per_prompt, do_classifier_free_guidance, negative_prompt) # NOTE aligned with origin repo # 4. Prepare timesteps # self.scheduler.set_timesteps(num_inference_steps, device=device) self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare latent variables num_channels_latents = self.unet.config.in_channels latents = self.prepare_latents( batch_size * num_videos_per_prompt, num_channels_latents, video_length, height, width, text_embeddings.dtype, device, generator, latents, ) # NOTE aligned with origin repo latents_dtype = latents.dtype # 6. Prepare extra step kwargs. extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) # predict the noise residual noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings, )['sample'].to(dtype=latents_dtype) # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] # FIXME: not aligned # FIXME: revise config thresholding=False # scheduler pred_original_sample not aligned # fixed clip_sample=False # 8. Post-processing video = self.decode_latents(latents.to(video_dtype)) if return_type == 'tensor': video = torch.from_numpy(video) return {'samples': video} def forward(self, inputs: torch.Tensor, data_samples: Optional[list] = None, mode: str = 'tensor') -> Union[Dict[str, torch.Tensor], list]: """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') ================================================ FILE: mmagic/models/editors/animatediff/animatediff_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import re from typing import Optional import imageio import numpy as np import torch import torchvision from diffusers.pipelines.paint_by_example import PaintByExampleImageEncoder from diffusers.pipelines.stable_diffusion import StableUnCLIPImageNormalizer from diffusers.schedulers import DDPMScheduler from einops import rearrange from transformers import (CLIPImageProcessor, CLIPTextModel, CLIPVisionConfig, CLIPVisionModelWithProjection) def shave_segments(path, n_shave_prefix_segments=1): """Removes segments. Positive values shave the first segments, negative shave the last segments. """ if n_shave_prefix_segments >= 0: return '.'.join(path.split('.')[n_shave_prefix_segments:]) else: return '.'.join(path.split('.')[:n_shave_prefix_segments]) def renew_resnet_paths(old_list, n_shave_prefix_segments=0): """Updates paths inside resnets to the new naming scheme (local renaming)""" mapping = [] for old_item in old_list: new_item = old_item.replace('in_layers.0', 'norm1') new_item = new_item.replace('in_layers.2', 'conv1') new_item = new_item.replace('out_layers.0', 'norm2') new_item = new_item.replace('out_layers.3', 'conv2') new_item = new_item.replace('emb_layers.1', 'time_emb_proj') new_item = new_item.replace('skip_connection', 'conv_shortcut') new_item = shave_segments( new_item, n_shave_prefix_segments=n_shave_prefix_segments) mapping.append({'old': old_item, 'new': new_item}) return mapping def renew_vae_resnet_paths(old_list, n_shave_prefix_segments=0): """Updates paths inside resnets to the new naming scheme (local renaming)""" mapping = [] for old_item in old_list: new_item = old_item new_item = new_item.replace('nin_shortcut', 'conv_shortcut') new_item = shave_segments( new_item, n_shave_prefix_segments=n_shave_prefix_segments) mapping.append({'old': old_item, 'new': new_item}) return mapping def renew_attention_paths(old_list, n_shave_prefix_segments=0): """Updates paths inside attentions to the new naming scheme (local renaming)""" mapping = [] for old_item in old_list: new_item = old_item mapping.append({'old': old_item, 'new': new_item}) return mapping def renew_vae_attention_paths(old_list, n_shave_prefix_segments=0): """Updates paths inside attentions to the new naming scheme (local renaming)""" mapping = [] for old_item in old_list: new_item = old_item new_item = new_item.replace('norm.weight', 'group_norm.weight') new_item = new_item.replace('norm.bias', 'group_norm.bias') new_item = new_item.replace('q.weight', 'query.weight') new_item = new_item.replace('q.bias', 'query.bias') new_item = new_item.replace('k.weight', 'key.weight') new_item = new_item.replace('k.bias', 'key.bias') new_item = new_item.replace('v.weight', 'value.weight') new_item = new_item.replace('v.bias', 'value.bias') new_item = new_item.replace('proj_out.weight', 'proj_attn.weight') new_item = new_item.replace('proj_out.bias', 'proj_attn.bias') new_item = shave_segments( new_item, n_shave_prefix_segments=n_shave_prefix_segments) mapping.append({'old': old_item, 'new': new_item}) return mapping def assign_to_checkpoint(paths, checkpoint, old_checkpoint, attention_paths_to_split=None, additional_replacements=None, config=None): """This does the final conversion step: take locally converted weights and apply a global renaming to them. It splits attention layers, and takes into account additional replacements that may arise. Assigns the weights to the new checkpoint. """ assert isinstance( paths, list ), "Paths should be a list of dicts containing 'old' and 'new' keys." # Splits the attention layers into three variables. if attention_paths_to_split is not None: for path, path_map in attention_paths_to_split.items(): old_tensor = old_checkpoint[path] channels = old_tensor.shape[0] // 3 target_shape = (-1, channels) if len(old_tensor.shape) == 3 else (-1) num_heads = old_tensor.shape[0] // config['num_head_channels'] // 3 old_tensor = old_tensor.reshape((num_heads, 3 * channels // num_heads) + old_tensor.shape[1:]) query, key, value = old_tensor.split(channels // num_heads, dim=1) checkpoint[path_map['query']] = query.reshape(target_shape) checkpoint[path_map['key']] = key.reshape(target_shape) checkpoint[path_map['value']] = value.reshape(target_shape) for path in paths: new_path = path['new'] # These have already been assigned if attention_paths_to_split is not None and ( new_path in attention_paths_to_split): continue # Global renaming happens here new_path = new_path.replace('middle_block.0', 'mid_block.resnets.0') new_path = new_path.replace('middle_block.1', 'mid_block.attentions.0') new_path = new_path.replace('middle_block.2', 'mid_block.resnets.1') if additional_replacements is not None: for replacement in additional_replacements: new_path = new_path.replace(replacement['old'], replacement['new']) # proj_attn.weight has to be converted from conv 1D to linear if 'proj_attn.weight' in new_path: checkpoint[new_path] = old_checkpoint[path['old']][:, :, 0] else: checkpoint[new_path] = old_checkpoint[path['old']] def conv_attn_to_linear(checkpoint): keys = list(checkpoint.keys()) attn_keys = ['query.weight', 'key.weight', 'value.weight'] for key in keys: if '.'.join(key.split('.')[-2:]) in attn_keys: if checkpoint[key].ndim > 2: checkpoint[key] = checkpoint[key][:, :, 0, 0] elif 'proj_attn.weight' in key: if checkpoint[key].ndim > 2: checkpoint[key] = checkpoint[key][:, :, 0] def create_unet_diffusers_config(original_config, image_size: int, controlnet=False): """Creates a config for the diffusers based on the config of the LDM model.""" if controlnet: unet_params = original_config.model.params.control_stage_config.params else: unet_params = original_config.model.params.unet_config.params vae_params = \ original_config.model.params.first_stage_config.params.ddconfig block_out_channels = [ unet_params.model_channels * mult for mult in unet_params.channel_mult ] down_block_types = [] resolution = 1 for i in range(len(block_out_channels)): block_type = 'CrossAttnDownBlock2D' \ if resolution in unet_params.attention_resolutions \ else 'DownBlock2D' down_block_types.append(block_type) if i != len(block_out_channels) - 1: resolution *= 2 up_block_types = [] for i in range(len(block_out_channels)): block_type = 'CrossAttnUpBlock2D' \ if resolution in unet_params.attention_resolutions \ else 'UpBlock2D' up_block_types.append(block_type) resolution //= 2 vae_scale_factor = 2**(len(vae_params.ch_mult) - 1) head_dim = unet_params.num_heads if 'num_heads' in unet_params else None use_linear_projection = ( unet_params.use_linear_in_transformer if 'use_linear_in_transformer' in unet_params else False) if use_linear_projection: # stable diffusion 2-base-512 and 2-768 if head_dim is None: head_dim = [5, 10, 20, 20] class_embed_type = None projection_class_embeddings_input_dim = None if 'num_classes' in unet_params: if unet_params.num_classes == 'sequential': class_embed_type = 'projection' assert 'adm_in_channels' in unet_params projection_class_embeddings_input_dim = unet_params.adm_in_channels else: raise NotImplementedError( f'Unknown conditional unet num_classes config: ' f'{unet_params.num_classes}') config = { 'sample_size': image_size // vae_scale_factor, 'in_channels': unet_params.in_channels, 'down_block_types': tuple(down_block_types), 'block_out_channels': tuple(block_out_channels), 'layers_per_block': unet_params.num_res_blocks, 'cross_attention_dim': unet_params.context_dim, 'attention_head_dim': head_dim, 'use_linear_projection': use_linear_projection, 'class_embed_type': class_embed_type, 'projection_class_embeddings_input_dim': projection_class_embeddings_input_dim, } if not controlnet: config['out_channels'] = unet_params.out_channels config['up_block_types'] = tuple(up_block_types) return config def create_vae_diffusers_config(original_config, image_size: int): """Creates a config for the diffusers based on the config of the LDM model.""" vae_params = \ original_config.model.params.first_stage_config.params.ddconfig _ = original_config.model.params.first_stage_config.params.embed_dim block_out_channels = [vae_params.ch * mult for mult in vae_params.ch_mult] down_block_types = ['DownEncoderBlock2D'] * len(block_out_channels) up_block_types = ['UpDecoderBlock2D'] * len(block_out_channels) config = { 'sample_size': image_size, 'in_channels': vae_params.in_channels, 'out_channels': vae_params.out_ch, 'down_block_types': tuple(down_block_types), 'up_block_types': tuple(up_block_types), 'block_out_channels': tuple(block_out_channels), 'latent_channels': vae_params.z_channels, 'layers_per_block': vae_params.num_res_blocks, } return config def convert_ldm_unet_checkpoint(checkpoint, config, path=None, extract_ema=False, controlnet=False): """Takes a state dict and a config, and returns a converted checkpoint.""" # extract state_dict for UNet unet_state_dict = {} keys = list(checkpoint.keys()) if controlnet: unet_key = 'control_model.' else: unet_key = 'model.diffusion_model.' # at least a 100 parameters have to start with `model_ema` # in order for the checkpoint to be EMA if sum(k.startswith('model_ema') for k in keys) > 100 and extract_ema: print(f'Checkpoint {path} has both EMA and non-EMA weights.') print('In this conversion only the EMA weights are extracted. ' 'If you want to instead extract the non-EMA' ' weights (useful to continue fine-tuning), please make sure to ' 'remove the `--extract_ema` flag.') for key in keys: if key.startswith('model.diffusion_model'): flat_ema_key = 'model_ema.' + ''.join(key.split('.')[1:]) unet_state_dict[key.replace(unet_key, '')] = checkpoint.pop(flat_ema_key) else: if sum(k.startswith('model_ema') for k in keys) > 100: print('In this conversion only the non-EMA weights ' 'are extracted. If you want to instead extract the EMA' ' weights (usually better for inference), please' ' make sure to add the `--extract_ema` flag.') for key in keys: if key.startswith(unet_key): unet_state_dict[key.replace(unet_key, '')] = checkpoint.pop(key) new_checkpoint = {} new_checkpoint['time_embedding.linear_1.weight'] = unet_state_dict[ 'time_embed.0.weight'] new_checkpoint['time_embedding.linear_1.bias'] = unet_state_dict[ 'time_embed.0.bias'] new_checkpoint['time_embedding.linear_2.weight'] = unet_state_dict[ 'time_embed.2.weight'] new_checkpoint['time_embedding.linear_2.bias'] = unet_state_dict[ 'time_embed.2.bias'] if config['class_embed_type'] is None: # No parameters to port ... elif config['class_embed_type'] == 'timestep' or config[ 'class_embed_type'] == 'projection': new_checkpoint['class_embedding.linear_1.weight'] = unet_state_dict[ 'label_emb.0.0.weight'] new_checkpoint['class_embedding.linear_1.bias'] = unet_state_dict[ 'label_emb.0.0.bias'] new_checkpoint['class_embedding.linear_2.weight'] = unet_state_dict[ 'label_emb.0.2.weight'] new_checkpoint['class_embedding.linear_2.bias'] = unet_state_dict[ 'label_emb.0.2.bias'] else: raise NotImplementedError( f"Not implemented `class_embed_type`: {config['class_embed_type']}" ) new_checkpoint['conv_in.weight'] = unet_state_dict[ 'input_blocks.0.0.weight'] new_checkpoint['conv_in.bias'] = unet_state_dict['input_blocks.0.0.bias'] if not controlnet: new_checkpoint['conv_norm_out.weight'] = unet_state_dict[ 'out.0.weight'] new_checkpoint['conv_norm_out.bias'] = unet_state_dict['out.0.bias'] new_checkpoint['conv_out.weight'] = unet_state_dict['out.2.weight'] new_checkpoint['conv_out.bias'] = unet_state_dict['out.2.bias'] # Retrieves the keys for the input blocks only num_input_blocks = len({ '.'.join(layer.split('.')[:2]) for layer in unet_state_dict if 'input_blocks' in layer }) input_blocks = { layer_id: [key for key in unet_state_dict if f'input_blocks.{layer_id}' in key] for layer_id in range(num_input_blocks) } # Retrieves the keys for the middle blocks only num_middle_blocks = len({ '.'.join(layer.split('.')[:2]) for layer in unet_state_dict if 'middle_block' in layer }) middle_blocks = { layer_id: [key for key in unet_state_dict if f'middle_block.{layer_id}' in key] for layer_id in range(num_middle_blocks) } # Retrieves the keys for the output blocks only num_output_blocks = len({ '.'.join(layer.split('.')[:2]) for layer in unet_state_dict if 'output_blocks' in layer }) output_blocks = { layer_id: [key for key in unet_state_dict if f'output_blocks.{layer_id}' in key] for layer_id in range(num_output_blocks) } for i in range(1, num_input_blocks): block_id = (i - 1) // (config['layers_per_block'] + 1) layer_in_block_id = (i - 1) % (config['layers_per_block'] + 1) resnets = [ key for key in input_blocks[i] if f'input_blocks.{i}.0' in key and f'input_blocks.{i}.0.op' not in key ] attentions = [ key for key in input_blocks[i] if f'input_blocks.{i}.1' in key ] if f'input_blocks.{i}.0.op.weight' in unet_state_dict: new_checkpoint[ f'down_blocks.{block_id}.downsamplers.0.conv.weight'] = \ unet_state_dict.pop(f'input_blocks.{i}.0.op.weight') new_checkpoint[ f'down_blocks.{block_id}.downsamplers.0.conv.bias'] = \ unet_state_dict.pop(f'input_blocks.{i}.0.op.bias') paths = renew_resnet_paths(resnets) meta_path = { 'old': f'input_blocks.{i}.0', 'new': f'down_blocks.{block_id}.resnets.{layer_in_block_id}' } assign_to_checkpoint( paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config) if len(attentions): paths = renew_attention_paths(attentions) meta_path = { 'old': f'input_blocks.{i}.1', 'new': f'down_blocks.{block_id}.attentions.{layer_in_block_id}' } assign_to_checkpoint( paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config) resnet_0 = middle_blocks[0] attentions = middle_blocks[1] resnet_1 = middle_blocks[2] resnet_0_paths = renew_resnet_paths(resnet_0) assign_to_checkpoint( resnet_0_paths, new_checkpoint, unet_state_dict, config=config) resnet_1_paths = renew_resnet_paths(resnet_1) assign_to_checkpoint( resnet_1_paths, new_checkpoint, unet_state_dict, config=config) attentions_paths = renew_attention_paths(attentions) meta_path = {'old': 'middle_block.1', 'new': 'mid_block.attentions.0'} assign_to_checkpoint( attentions_paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config) for i in range(num_output_blocks): block_id = i // (config['layers_per_block'] + 1) layer_in_block_id = i % (config['layers_per_block'] + 1) output_block_layers = [ shave_segments(name, 2) for name in output_blocks[i] ] output_block_list = {} for layer in output_block_layers: layer_id, layer_name = layer.split('.')[0], shave_segments( layer, 1) if layer_id in output_block_list: output_block_list[layer_id].append(layer_name) else: output_block_list[layer_id] = [layer_name] if len(output_block_list) > 1: resnets = [ key for key in output_blocks[i] if f'output_blocks.{i}.0' in key ] attentions = [ key for key in output_blocks[i] if f'output_blocks.{i}.1' in key ] resnet_0_paths = renew_resnet_paths(resnets) paths = renew_resnet_paths(resnets) meta_path = { 'old': f'output_blocks.{i}.0', 'new': f'up_blocks.{block_id}.resnets.{layer_in_block_id}' } assign_to_checkpoint( paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config) output_block_list = { k: sorted(v) for k, v in output_block_list.items() } if ['conv.bias', 'conv.weight'] in output_block_list.values(): index = list(output_block_list.values()).index( ['conv.bias', 'conv.weight']) new_checkpoint[ f'up_blocks.{block_id}.upsamplers.0.conv.weight'] = \ unet_state_dict[ f'output_blocks.{i}.{index}.conv.weight'] new_checkpoint[ f'up_blocks.{block_id}.upsamplers.0.conv.bias'] = \ unet_state_dict[ f'output_blocks.{i}.{index}.conv.bias'] # Clear attentions as they have been attributed above. if len(attentions) == 2: attentions = [] if len(attentions): paths = renew_attention_paths(attentions) meta_path = { 'old': f'output_blocks.{i}.1', 'new': f'up_blocks.{block_id}.attentions.{layer_in_block_id}', } assign_to_checkpoint( paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config) else: resnet_0_paths = renew_resnet_paths( output_block_layers, n_shave_prefix_segments=1) for path in resnet_0_paths: old_path = '.'.join(['output_blocks', str(i), path['old']]) new_path = '.'.join([ 'up_blocks', str(block_id), 'resnets', str(layer_in_block_id), path['new'] ]) new_checkpoint[new_path] = unet_state_dict[old_path] if controlnet: # conditioning embedding orig_index = 0 new_checkpoint[ 'controlnet_cond_embedding.conv_in.weight'] = unet_state_dict.pop( f'input_hint_block.{orig_index}.weight') new_checkpoint[ 'controlnet_cond_embedding.conv_in.bias'] = unet_state_dict.pop( f'input_hint_block.{orig_index}.bias') orig_index += 2 diffusers_index = 0 while diffusers_index < 6: new_checkpoint[f'controlnet_cond_embedding.blocks' f'.{diffusers_index}.weight'] = ( unet_state_dict.pop( f'input_hint_block.{orig_index}.weight')) new_checkpoint[ f'controlnet_cond_embedding.blocks.{diffusers_index}.bias'] = ( unet_state_dict.pop(f'input_hint_block.{orig_index}.bias')) diffusers_index += 1 orig_index += 2 new_checkpoint[ 'controlnet_cond_embedding.conv_out.weight'] = unet_state_dict.pop( f'input_hint_block.{orig_index}.weight') new_checkpoint[ 'controlnet_cond_embedding.conv_out.bias'] = unet_state_dict.pop( f'input_hint_block.{orig_index}.bias') # down blocks for i in range(num_input_blocks): new_checkpoint[ f'controlnet_down_blocks.{i}.weight'] = unet_state_dict.pop( f'zero_convs.{i}.0.weight') new_checkpoint[ f'controlnet_down_blocks.{i}.bias'] = unet_state_dict.pop( f'zero_convs.{i}.0.bias') # mid block new_checkpoint['controlnet_mid_block.weight'] = unet_state_dict.pop( 'middle_block_out.0.weight') new_checkpoint['controlnet_mid_block.bias'] = unet_state_dict.pop( 'middle_block_out.0.bias') return new_checkpoint def convert_ldm_vae_checkpoint(checkpoint, config): # extract state dict for VAE vae_state_dict = {} vae_key = 'first_stage_model.' keys = list(checkpoint.keys()) for key in keys: if key.startswith(vae_key): vae_state_dict[key.replace(vae_key, '')] = checkpoint.get(key) new_checkpoint = {} new_checkpoint['encoder.conv_in.weight'] = vae_state_dict[ 'encoder.conv_in.weight'] new_checkpoint['encoder.conv_in.bias'] = vae_state_dict[ 'encoder.conv_in.bias'] new_checkpoint['encoder.conv_out.weight'] = vae_state_dict[ 'encoder.conv_out.weight'] new_checkpoint['encoder.conv_out.bias'] = vae_state_dict[ 'encoder.conv_out.bias'] new_checkpoint['encoder.conv_norm_out.weight'] = vae_state_dict[ 'encoder.norm_out.weight'] new_checkpoint['encoder.conv_norm_out.bias'] = vae_state_dict[ 'encoder.norm_out.bias'] new_checkpoint['decoder.conv_in.weight'] = vae_state_dict[ 'decoder.conv_in.weight'] new_checkpoint['decoder.conv_in.bias'] = vae_state_dict[ 'decoder.conv_in.bias'] new_checkpoint['decoder.conv_out.weight'] = vae_state_dict[ 'decoder.conv_out.weight'] new_checkpoint['decoder.conv_out.bias'] = vae_state_dict[ 'decoder.conv_out.bias'] new_checkpoint['decoder.conv_norm_out.weight'] = vae_state_dict[ 'decoder.norm_out.weight'] new_checkpoint['decoder.conv_norm_out.bias'] = vae_state_dict[ 'decoder.norm_out.bias'] new_checkpoint['quant_conv.weight'] = vae_state_dict['quant_conv.weight'] new_checkpoint['quant_conv.bias'] = vae_state_dict['quant_conv.bias'] new_checkpoint['post_quant_conv.weight'] = vae_state_dict[ 'post_quant_conv.weight'] new_checkpoint['post_quant_conv.bias'] = vae_state_dict[ 'post_quant_conv.bias'] # Retrieves the keys for the encoder down blocks only num_down_blocks = len({ '.'.join(layer.split('.')[:3]) for layer in vae_state_dict if 'encoder.down' in layer }) down_blocks = { layer_id: [key for key in vae_state_dict if f'down.{layer_id}' in key] for layer_id in range(num_down_blocks) } # Retrieves the keys for the decoder up blocks only num_up_blocks = len({ '.'.join(layer.split('.')[:3]) for layer in vae_state_dict if 'decoder.up' in layer }) up_blocks = { layer_id: [key for key in vae_state_dict if f'up.{layer_id}' in key] for layer_id in range(num_up_blocks) } for i in range(num_down_blocks): resnets = [ key for key in down_blocks[i] if f'down.{i}' in key and f'down.{i}.downsample' not in key ] if f'encoder.down.{i}.downsample.conv.weight' in vae_state_dict: new_checkpoint[ f'encoder.down_blocks.{i}.downsamplers.0.conv.weight'] = \ vae_state_dict.pop(f'encoder.down.{i}.downsample.conv.weight') new_checkpoint[ f'encoder.down_blocks.{i}.downsamplers.0.conv.bias'] = \ vae_state_dict.pop(f'encoder.down.{i}.downsample.conv.bias') paths = renew_vae_resnet_paths(resnets) meta_path = { 'old': f'down.{i}.block', 'new': f'down_blocks.{i}.resnets' } assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) mid_resnets = [key for key in vae_state_dict if 'encoder.mid.block' in key] num_mid_res_blocks = 2 for i in range(1, num_mid_res_blocks + 1): resnets = [ key for key in mid_resnets if f'encoder.mid.block_{i}' in key ] paths = renew_vae_resnet_paths(resnets) meta_path = { 'old': f'mid.block_{i}', 'new': f'mid_block.resnets.{i - 1}' } assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) mid_attentions = [ key for key in vae_state_dict if 'encoder.mid.attn' in key ] paths = renew_vae_attention_paths(mid_attentions) meta_path = {'old': 'mid.attn_1', 'new': 'mid_block.attentions.0'} assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) conv_attn_to_linear(new_checkpoint) for i in range(num_up_blocks): block_id = num_up_blocks - 1 - i resnets = [ key for key in up_blocks[block_id] if f'up.{block_id}' in key and f'up.{block_id}.upsample' not in key ] if f'decoder.up.{block_id}.upsample.conv.weight' in vae_state_dict: new_checkpoint[ f'decoder.up_blocks.{i}.upsamplers.0.conv.weight'] = \ vae_state_dict[f'decoder.up.{block_id}.upsample.conv.weight'] new_checkpoint[ f'decoder.up_blocks.{i}.upsamplers.0.conv.bias'] = \ vae_state_dict[f'decoder.up.{block_id}.upsample.conv.bias'] paths = renew_vae_resnet_paths(resnets) meta_path = { 'old': f'up.{block_id}.block', 'new': f'up_blocks.{i}.resnets' } assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) mid_resnets = [key for key in vae_state_dict if 'decoder.mid.block' in key] num_mid_res_blocks = 2 for i in range(1, num_mid_res_blocks + 1): resnets = [ key for key in mid_resnets if f'decoder.mid.block_{i}' in key ] paths = renew_vae_resnet_paths(resnets) meta_path = { 'old': f'mid.block_{i}', 'new': f'mid_block.resnets.{i - 1}' } assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) mid_attentions = [ key for key in vae_state_dict if 'decoder.mid.attn' in key ] paths = renew_vae_attention_paths(mid_attentions) meta_path = {'old': 'mid.attn_1', 'new': 'mid_block.attentions.0'} assign_to_checkpoint( paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config) conv_attn_to_linear(new_checkpoint) new_checkpoint = { 'model.' + key: value for key, value in new_checkpoint.items() } new_checkpoint = { key.replace('query', 'to_q'): value for key, value in new_checkpoint.items() } new_checkpoint = { key.replace('key', 'to_k'): value for key, value in new_checkpoint.items() } new_checkpoint = { key.replace('value', 'to_v'): value for key, value in new_checkpoint.items() } new_checkpoint = { key.replace('proj_attn', 'to_out.0'): value for key, value in new_checkpoint.items() } return new_checkpoint def convert_ldm_clip_checkpoint(checkpoint): text_model = CLIPTextModel.from_pretrained('openai/clip-vit-large-patch14') keys = list(checkpoint.keys()) text_model_dict = {} for key in keys: if key.startswith('cond_stage_model.transformer'): text_model_dict[ key[len('cond_stage_model.transformer.'):]] = checkpoint[key] # Certain text transformers no longer # expect position_ids after transformers==4.31 position_id_key = 'text_model.embeddings.position_ids' if position_id_key in text_model_dict and \ position_id_key not in text_model.state_dict(): del text_model_dict[position_id_key] text_model.load_state_dict(text_model_dict) return text_model textenc_conversion_lst = [ ('cond_stage_model.model.positional_embedding', 'text_model.embeddings.position_embedding.weight'), ('cond_stage_model.model.token_embedding.weight', 'text_model.embeddings.token_embedding.weight'), ('cond_stage_model.model.ln_final.weight', 'text_model.final_layer_norm.weight'), ('cond_stage_model.model.ln_final.bias', 'text_model.final_layer_norm.bias'), ] textenc_conversion_map = {x[0]: x[1] for x in textenc_conversion_lst} textenc_transformer_conversion_lst = [ # (stable-diffusion, HF Diffusers) ('resblocks.', 'text_model.encoder.layers.'), ('ln_1', 'layer_norm1'), ('ln_2', 'layer_norm2'), ('.c_fc.', '.fc1.'), ('.c_proj.', '.fc2.'), ('.attn', '.self_attn'), ('ln_final.', 'transformer.text_model.final_layer_norm.'), ('token_embedding.weight', 'transformer.text_model.embeddings.token_embedding.weight'), ('positional_embedding', 'transformer.text_model.embeddings.position_embedding.weight'), ] protected = {re.escape(x[0]): x[1] for x in textenc_transformer_conversion_lst} textenc_pattern = re.compile('|'.join(protected.keys())) def convert_paint_by_example_checkpoint(checkpoint): config = CLIPVisionConfig.from_pretrained('openai/clip-vit-large-patch14') model = PaintByExampleImageEncoder(config) keys = list(checkpoint.keys()) text_model_dict = {} for key in keys: if key.startswith('cond_stage_model.transformer'): text_model_dict[ key[len('cond_stage_model.transformer.'):]] = checkpoint[key] # load clip vision model.model.load_state_dict(text_model_dict) # load mapper keys_mapper = { k[len('cond_stage_model.mapper.res'):]: v for k, v in checkpoint.items() if k.startswith('cond_stage_model.mapper') } MAPPING = { 'attn.c_qkv': ['attn1.to_q', 'attn1.to_k', 'attn1.to_v'], 'attn.c_proj': ['attn1.to_out.0'], 'ln_1': ['norm1'], 'ln_2': ['norm3'], 'mlp.c_fc': ['ff.net.0.proj'], 'mlp.c_proj': ['ff.net.2'], } mapped_weights = {} for key, value in keys_mapper.items(): prefix = key[:len('blocks.i')] suffix = key.split(prefix)[-1].split('.')[-1] name = key.split(prefix)[-1].split(suffix)[0][1:-1] mapped_names = MAPPING[name] num_splits = len(mapped_names) for i, mapped_name in enumerate(mapped_names): new_name = '.'.join([prefix, mapped_name, suffix]) shape = value.shape[0] // num_splits mapped_weights[new_name] = value[i * shape:(i + 1) * shape] model.mapper.load_state_dict(mapped_weights) # load final layer norm model.final_layer_norm.load_state_dict({ 'bias': checkpoint['cond_stage_model.final_ln.bias'], 'weight': checkpoint['cond_stage_model.final_ln.weight'], }) # load final proj model.proj_out.load_state_dict({ 'bias': checkpoint['proj_out.bias'], 'weight': checkpoint['proj_out.weight'], }) # load uncond vector model.uncond_vector.data = torch.nn.Parameter( checkpoint['learnable_vector']) return model def convert_open_clip_checkpoint(checkpoint): text_model = CLIPTextModel.from_pretrained( 'stabilityai/stable-diffusion-2', subfolder='text_encoder') keys = list(checkpoint.keys()) text_model_dict = {} if 'cond_stage_model.model.text_projection' in checkpoint: d_model = int( checkpoint['cond_stage_model.model.text_projection'].shape[0]) else: d_model = 1024 text_model_dict[ 'text_model.embeddings.position_ids'] = \ text_model.text_model.embeddings.get_buffer('position_ids') for key in keys: # Diffusers drops the final layer and # only uses the penultimate layer if 'resblocks.23' in key: continue if key in textenc_conversion_map: text_model_dict[textenc_conversion_map[key]] = checkpoint[key] if key.startswith('cond_stage_model.model.transformer.'): new_key = key[len('cond_stage_model.model.transformer.'):] if new_key.endswith('.in_proj_weight'): new_key = new_key[:-len('.in_proj_weight')] new_key = textenc_pattern.sub( lambda m: protected[re.escape(m.group(0))], new_key) text_model_dict[ new_key + '.q_proj.weight'] = checkpoint[key][:d_model, :] text_model_dict[new_key + '.k_proj.weight'] = checkpoint[key][ d_model:d_model * 2, :] text_model_dict[new_key + '.v_proj.weight'] = checkpoint[key][d_model * 2:, :] elif new_key.endswith('.in_proj_bias'): new_key = new_key[:-len('.in_proj_bias')] new_key = textenc_pattern.sub( lambda m: protected[re.escape(m.group(0))], new_key) text_model_dict[new_key + '.q_proj.bias'] = checkpoint[key][:d_model] text_model_dict[ new_key + '.k_proj.bias'] = checkpoint[key][d_model:d_model * 2] text_model_dict[new_key + '.v_proj.bias'] = checkpoint[key][d_model * 2:] else: new_key = textenc_pattern.sub( lambda m: protected[re.escape(m.group(0))], new_key) text_model_dict[new_key] = checkpoint[key] text_model.load_state_dict(text_model_dict) return text_model def stable_unclip_image_encoder(original_config): """Returns the image processor and clip image encoder for the img2img unclip pipeline. We currently know of two types of stable unclip models which separately use the clip and the openclip image encoders. """ image_embedder_config = original_config.model.params.embedder_config sd_clip_image_embedder_class = image_embedder_config.target sd_clip_image_embedder_class = sd_clip_image_embedder_class.split('.')[-1] if sd_clip_image_embedder_class == 'ClipImageEmbedder': clip_model_name = image_embedder_config.params.model if clip_model_name == 'ViT-L/14': feature_extractor = CLIPImageProcessor() image_encoder = CLIPVisionModelWithProjection.from_pretrained( 'openai/clip-vit-large-patch14') else: raise NotImplementedError( f'Unknown CLIP checkpoint name in stable ' f'diffusion checkpoint {clip_model_name}') elif sd_clip_image_embedder_class == 'FrozenOpenCLIPImageEmbedder': feature_extractor = CLIPImageProcessor() image_encoder = CLIPVisionModelWithProjection.from_pretrained( 'laion/CLIP-ViT-H-14-laion2B-s32B-b79K') else: raise NotImplementedError( f'Unknown CLIP image embedder class in ' f'stable diffusion checkpoint {sd_clip_image_embedder_class}') return feature_extractor, image_encoder def stable_unclip_image_noising_components( original_config, clip_stats_path: Optional[str] = None, device: Optional[str] = None): """Returns the noising components for the img2img and txt2img unclip pipelines. Converts the stability noise augmentor into 1. a `StableUnCLIPImageNormalizer` for holding the CLIP stats 2. a `DDPMScheduler` for holding the noise schedule If the noise augmentor config specifies a clip stats path, the `clip_stats_path` must be provided. """ noise_aug_config = original_config.model.params.noise_aug_config noise_aug_class = noise_aug_config.target noise_aug_class = noise_aug_class.split('.')[-1] if noise_aug_class == 'CLIPEmbeddingNoiseAugmentation': noise_aug_config = noise_aug_config.params embedding_dim = noise_aug_config.timestep_dim max_noise_level = noise_aug_config.noise_schedule_config.timesteps beta_schedule = noise_aug_config.noise_schedule_config.beta_schedule image_normalizer = StableUnCLIPImageNormalizer( embedding_dim=embedding_dim) image_noising_scheduler = DDPMScheduler( num_train_timesteps=max_noise_level, beta_schedule=beta_schedule) if 'clip_stats_path' in noise_aug_config: if clip_stats_path is None: raise ValueError( 'This stable unclip config requires a `clip_stats_path`') clip_mean, clip_std = torch.load( clip_stats_path, map_location=device) clip_mean = clip_mean[None, :] clip_std = clip_std[None, :] clip_stats_state_dict = { 'mean': clip_mean, 'std': clip_std, } image_normalizer.load_state_dict(clip_stats_state_dict) else: raise NotImplementedError( f'Unknown noise augmentor class: {noise_aug_class}') return image_normalizer, image_noising_scheduler def save_videos_grid(videos: torch.Tensor, path: str, rescale=False, n_rows=6, fps=8): videos = rearrange(videos, 'b c t h w -> t b c h w') outputs = [] for x in videos: x = torchvision.utils.make_grid(x, nrow=n_rows) x = x.transpose(0, 1).transpose(1, 2).squeeze(-1) if rescale: x = (x + 1.0) / 2.0 # -1,1 -> 0,1 x = (x * 255).numpy().astype(np.uint8) outputs.append(x) os.makedirs(os.path.dirname(path), exist_ok=True) # imageio v3 doesn't support fps if imageio.__version__ < '2.28.0': imageio.mimsave(path, outputs, fps=fps) else: imageio.mimsave(path, outputs, duration=1000 * 1 / fps, loop=10) ================================================ FILE: mmagic/models/editors/animatediff/attention_3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Adapted from https://github.com/huggingface/diffusers/blob/main/ # src/diffusers/models/attention.py from dataclasses import dataclass from typing import Optional import torch import torch.nn.functional as F from diffusers.configuration_utils import ConfigMixin, register_to_config from diffusers.models.attention import AdaLayerNorm, FeedForward # from diffusers.models.cross_attention import CrossAttention # from diffusers.models.attention_processor import Attention as CrossAttention from diffusers.models.modeling_utils import ModelMixin from diffusers.utils import BaseOutput from diffusers.utils.import_utils import is_xformers_available from einops import rearrange, repeat from torch import nn @dataclass class Transformer3DModelOutput(BaseOutput): """Output of Transformer3DModel.""" sample: torch.FloatTensor if is_xformers_available(): """Check xformer. If available use xformers to save memory """ import xformers import xformers.ops else: xformers = None class Transformer3DModel(ModelMixin, ConfigMixin): """Transformer model for image-like data. Takes either discrete (classes of vector embeddings) or continuous (actual embeddings) inputs. When input is continuous: First, project the input (aka embedding) and reshape to b, t, d. Then apply standard transformer action. Finally, reshape to image. When input is discrete: First, input (classes of latent pixels) is converted to embeddings and has positional embeddings applied, see `ImagePositionalEmbeddings`. Then apply standard transformer action. Finally, predict classes of unnoised image. Note that it is assumed one of the input classes is the masked latent pixel. The predicted classes of the unnoised image do not contain a prediction for the masked pixel as the unnoised image cannot be masked. Args: num_attention_heads (`int`, *optional*, defaults to 16): The number of heads to use for multi-head attention. attention_head_dim (`int`, *optional*, defaults to 88): The number of channels in each head. in_channels (`int`, *optional*): Pass if the input is continuous. The number of channels in the input and output. num_layers (`int`, *optional*, defaults to 1): The number of layers of Transformer blocks to use. dropout (`float`, *optional*, defaults to 0.1): The dropout probability to use. norm_num_groups (int): Norm group num, defaults to 32. cross_attention_dim (`int`, *optional*): The number of context dimensions to use. attention_bias (`bool`, *optional*): Configure if the TransformerBlocks' attention should contain a bias parameter. sample_size (`int`, *optional*): Pass if the input is discrete. The width of the latent images. Note that this is fixed at training time as it is used for learning a number of position embeddings. See `ImagePositionalEmbeddings`. num_vector_embeds (`int`, *optional*): Pass if the input is discrete. The number of classes of the vector embeddings of the latent pixels. Includes the class for the masked latent pixel. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. use_linear_projection (bool): Whether to use linear projection, defaults to False. only_cross_attention (bool): whether only use cross attention, defaults to False. unet_use_temporal_attention (bool): whether use temporal attention, defaults to False. upcast_attention (bool): whether use upcast attention, defaults to False. unet_use_cross_frame_attention (bool): whether use cross frame attention, defaults to False. unet_use_temporal_attention (bool): whether use temporal attention, defaults to False. """ @register_to_config def __init__( self, num_attention_heads: int = 16, attention_head_dim: int = 88, in_channels: Optional[int] = None, num_layers: int = 1, dropout: float = 0.0, norm_num_groups: int = 32, cross_attention_dim: Optional[int] = None, attention_bias: bool = False, activation_fn: str = 'geglu', num_embeds_ada_norm: Optional[int] = None, use_linear_projection: bool = False, only_cross_attention: bool = False, upcast_attention: bool = False, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, ): super().__init__() self.use_linear_projection = use_linear_projection self.num_attention_heads = num_attention_heads self.attention_head_dim = attention_head_dim inner_dim = num_attention_heads * attention_head_dim # Define input layers self.in_channels = in_channels self.norm = torch.nn.GroupNorm( num_groups=norm_num_groups, num_channels=in_channels, eps=1e-6, affine=True) if use_linear_projection: self.proj_in = nn.Linear(in_channels, inner_dim) else: self.proj_in = nn.Conv2d( in_channels, inner_dim, kernel_size=1, stride=1, padding=0) # Define transformers blocks self.transformer_blocks = nn.ModuleList([ BasicTransformerBlock( inner_dim, num_attention_heads, attention_head_dim, dropout=dropout, cross_attention_dim=cross_attention_dim, activation_fn=activation_fn, num_embeds_ada_norm=num_embeds_ada_norm, attention_bias=attention_bias, only_cross_attention=only_cross_attention, upcast_attention=upcast_attention, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, ) for d in range(num_layers) ]) # 4. Define output layers if use_linear_projection: self.proj_out = nn.Linear(in_channels, inner_dim) else: self.proj_out = nn.Conv2d( inner_dim, in_channels, kernel_size=1, stride=1, padding=0) def forward(self, hidden_states, encoder_hidden_states=None, timestep=None, return_dict: bool = True): """forward function. Args: hidden_states ( When discrete, `torch.LongTensor` of shape `(batch size, num latent pixels)`. When continuous, `torch.FloatTensor` of shape ` (batch size, channel, height, width)`): Input hidden_states encoder_hidden_states ( `torch.LongTensor` of shape `(batch size, context dim)`, *optional*): Conditional embeddings for cross attention layer. If not given, cross-attention defaults to self-attention. timestep ( `torch.long`, *optional*): Optional timestep to be applied as an embedding in AdaLayerNorm's. Used to indicate denoising step. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`Transformer3DModelOutput`] instead of a plain tuple. Returns: Dict if `return_dict` is True, otherwise a `tuple`. When returning a tuple, the first element is the sample tensor. """ # Input assert hidden_states.dim( ) == 5, f'{"Expected hidden_states to have ndim=5, "}' f'but got ndim={hidden_states.dim()}.' video_length = hidden_states.shape[2] hidden_states = rearrange(hidden_states, 'b c f h w -> (b f) c h w') if encoder_hidden_states is not None: encoder_hidden_states = repeat( encoder_hidden_states, 'b n c -> (b f) n c', f=video_length) batch, channel, height, weight = hidden_states.shape residual = hidden_states hidden_states = self.norm(hidden_states) if not self.use_linear_projection: hidden_states = self.proj_in(hidden_states) inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * weight, inner_dim) else: inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * weight, inner_dim) hidden_states = self.proj_in(hidden_states) # Blocks for block in self.transformer_blocks: hidden_states = block( hidden_states, encoder_hidden_states=encoder_hidden_states, timestep=timestep, video_length=video_length) # Output if not self.use_linear_projection: hidden_states = ( hidden_states.reshape(batch, height, weight, inner_dim).permute(0, 3, 1, 2).contiguous()) hidden_states = self.proj_out(hidden_states) else: hidden_states = self.proj_out(hidden_states) hidden_states = ( hidden_states.reshape(batch, height, weight, inner_dim).permute(0, 3, 1, 2).contiguous()) output = hidden_states + residual output = rearrange(output, '(b f) c h w -> b c f h w', f=video_length) if not return_dict: return (output, ) return Transformer3DModelOutput(sample=output) class BasicTransformerBlock(nn.Module): """A basic Transformer block. Args: dim (int): The number of channels in the input and output. num_attention_heads (int): The number of heads to use for multi-head attention. attention_head_dim (int): The number of channels in each head. dropout (float, *optional*, defaults to 0.0): The dropout probability to use. cross_attention_dim (int, *optional*): The size of the context vector for cross attention. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. attention_bias (bool, *optional*, defaults to `False`): Configure if the attentions should contain a bias parameter. only_cross_attention (bool, defaults to False): whether to use cross attention only. upcast_attention (bool): whether use upcast attention, defaults to False. unet_use_cross_frame_attention (bool): whether use cross frame attention, defaults to False. unet_use_temporal_attention (bool): whether use temporal attention, defaults to False. """ def __init__( self, dim: int, num_attention_heads: int, attention_head_dim: int, dropout=0.0, cross_attention_dim: Optional[int] = None, activation_fn: str = 'geglu', num_embeds_ada_norm: Optional[int] = None, attention_bias: bool = False, only_cross_attention: bool = False, upcast_attention: bool = False, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, ): super().__init__() self.only_cross_attention = only_cross_attention self.use_ada_layer_norm = num_embeds_ada_norm is not None self.unet_use_cross_frame_attention = unet_use_cross_frame_attention self.unet_use_temporal_attention = unet_use_temporal_attention # SC-Attn assert unet_use_cross_frame_attention is not None if unet_use_cross_frame_attention: # TODO: cross_frame_attention pass # self.attn1 = SparseCausalAttention2D( # query_dim=dim, # heads=num_attention_heads, # dim_head=attention_head_dim, # dropout=dropout, # bias=attention_bias, # cross_attention_dim=cross_attention_dim # if only_cross_attention else None, # upcast_attention=upcast_attention, # ) else: # TODO: Check whether replace this with models.editors # .ddpm.attention.CrossAttention self.attn1 = CrossAttention( query_dim=dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, upcast_attention=upcast_attention, ) self.norm1 = AdaLayerNorm( dim, num_embeds_ada_norm ) if self.use_ada_layer_norm else nn.LayerNorm(dim) # Cross-Attn if cross_attention_dim is not None: self.attn2 = CrossAttention( query_dim=dim, cross_attention_dim=cross_attention_dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, upcast_attention=upcast_attention, ) else: self.attn2 = None if cross_attention_dim is not None: self.norm2 = AdaLayerNorm( dim, num_embeds_ada_norm ) if self.use_ada_layer_norm else nn.LayerNorm(dim) else: self.norm2 = None # Feed-forward self.ff = FeedForward( dim, dropout=dropout, activation_fn=activation_fn) self.norm3 = nn.LayerNorm(dim) # Temp-Attn assert unet_use_temporal_attention is not None if unet_use_temporal_attention: self.attn_temp = CrossAttention( query_dim=dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, upcast_attention=upcast_attention, ) nn.init.zeros_(self.attn_temp.to_out[0].weight.data) self.norm_temp = AdaLayerNorm( dim, num_embeds_ada_norm ) if self.use_ada_layer_norm else nn.LayerNorm(dim) def forward(self, hidden_states, encoder_hidden_states=None, timestep=None, attention_mask=None, video_length=None): """forward with hidden states, context and timestep.""" # SparseCausal-Attention norm_hidden_states = ( self.norm1(hidden_states, timestep) if self.use_ada_layer_norm else self.norm1(hidden_states)) if self.unet_use_cross_frame_attention: hidden_states = self.attn1( norm_hidden_states, attention_mask=attention_mask, video_length=video_length) + hidden_states else: hidden_states = self.attn1( norm_hidden_states, attention_mask=attention_mask) + hidden_states if self.attn2 is not None: # Cross-Attention norm_hidden_states = ( self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states)) hidden_states = ( self.attn2( norm_hidden_states, encoder_hidden_states=encoder_hidden_states, attention_mask=attention_mask) + hidden_states) # Feed-forward hidden_states = self.ff(self.norm3(hidden_states)) + hidden_states # Temporal-Attention if self.unet_use_temporal_attention: d = hidden_states.shape[1] hidden_states = rearrange( hidden_states, '(b f) d c -> (b d) f c', f=video_length) norm_hidden_states = ( self.norm_temp(hidden_states, timestep) if self.use_ada_layer_norm else self.norm_temp(hidden_states)) hidden_states = self.attn_temp(norm_hidden_states) + hidden_states hidden_states = rearrange( hidden_states, '(b d) f c -> (b f) d c', d=d) return hidden_states class CrossAttention(nn.Module): r""" A cross attention layer. Parameters: query_dim (`int`): The number of channels in the query. cross_attention_dim (`int`, *optional*): The number of channels in the encoder_hidden_states. If not given, defaults to `query_dim`. heads (`int`, *optional*, defaults to 8): The number of heads to use for multi-head attention. dim_head (`int`, *optional*, defaults to 64): The number of channels in each head. dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. bias (`bool`, *optional*, defaults to False): Set to `True` for the query, key, and value linear layers to contain a bias parameter. """ def __init__( self, query_dim: int, cross_attention_dim: Optional[int] = None, heads: int = 8, dim_head: int = 64, dropout: float = 0.0, bias=False, upcast_attention: bool = False, upcast_softmax: bool = False, added_kv_proj_dim: Optional[int] = None, norm_num_groups: Optional[int] = None, ): super().__init__() inner_dim = dim_head * heads cross_attention_dim = cross_attention_dim \ if cross_attention_dim is not None else query_dim self.upcast_attention = upcast_attention self.upcast_softmax = upcast_softmax self.scale = dim_head**-0.5 self.heads = heads # for slice_size > 0 the attention score computation # is split across the batch axis to save memory # You can set slice_size with `set_attention_slice` self.sliceable_head_dim = heads self._slice_size = None if xformers is not None: self._use_memory_efficient_attention_xformers = True else: self._use_memory_efficient_attention_xformers = False self.added_kv_proj_dim = added_kv_proj_dim if norm_num_groups is not None: self.group_norm = nn.GroupNorm( num_channels=inner_dim, num_groups=norm_num_groups, eps=1e-5, affine=True) else: self.group_norm = None self.to_q = nn.Linear(query_dim, inner_dim, bias=bias) self.to_k = nn.Linear(cross_attention_dim, inner_dim, bias=bias) self.to_v = nn.Linear(cross_attention_dim, inner_dim, bias=bias) if self.added_kv_proj_dim is not None: self.add_k_proj = nn.Linear(added_kv_proj_dim, cross_attention_dim) self.add_v_proj = nn.Linear(added_kv_proj_dim, cross_attention_dim) self.to_out = nn.ModuleList([]) self.to_out.append(nn.Linear(inner_dim, query_dim)) self.to_out.append(nn.Dropout(dropout)) def reshape_heads_to_batch_dim(self, tensor): batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size, seq_len, head_size, dim // head_size) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size * head_size, seq_len, dim // head_size) return tensor def reshape_batch_dim_to_heads(self, tensor): batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size // head_size, head_size, seq_len, dim) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size // head_size, seq_len, dim * head_size) return tensor def set_attention_slice(self, slice_size): if slice_size is not None and slice_size > self.sliceable_head_dim: raise ValueError(f'slice_size {slice_size} has to be smaller \ or equal to {self.sliceable_head_dim}.') self._slice_size = slice_size def forward(self, hidden_states, encoder_hidden_states=None, attention_mask=None): batch_size, sequence_length, _ = hidden_states.shape encoder_hidden_states = encoder_hidden_states if self.group_norm is not None: hidden_states = self.group_norm(hidden_states.transpose( 1, 2)).transpose(1, 2) query = self.to_q(hidden_states) dim = query.shape[-1] query = self.reshape_heads_to_batch_dim(query) if self.added_kv_proj_dim is not None: key = self.to_k(hidden_states) value = self.to_v(hidden_states) encoder_hidden_states_key_proj = \ self.add_k_proj(encoder_hidden_states) encoder_hidden_states_value_proj = \ self.add_v_proj(encoder_hidden_states) key = self.reshape_heads_to_batch_dim(key) value = self.reshape_heads_to_batch_dim(value) encoder_hidden_states_key_proj = \ self.reshape_heads_to_batch_dim( encoder_hidden_states_key_proj ) encoder_hidden_states_value_proj = \ self.reshape_heads_to_batch_dim( encoder_hidden_states_value_proj ) key = torch.concat([encoder_hidden_states_key_proj, key], dim=1) value = torch.concat([encoder_hidden_states_value_proj, value], dim=1) else: encoder_hidden_states = encoder_hidden_states \ if encoder_hidden_states is not None else hidden_states key = self.to_k(encoder_hidden_states) value = self.to_v(encoder_hidden_states) key = self.reshape_heads_to_batch_dim(key) value = self.reshape_heads_to_batch_dim(value) if attention_mask is not None: if attention_mask.shape[-1] != query.shape[1]: target_length = query.shape[1] attention_mask = F.pad( attention_mask, (0, target_length), value=0.0) attention_mask = attention_mask.repeat_interleave( self.heads, dim=0) # attention, what we cannot get enough of if self._use_memory_efficient_attention_xformers and\ 'cuda' in query.device.type: # hidden_states = xformers.ops.memory_efficient_attention( # query, key, value, attn_bias=attention_mask, # op=self.attention_op, scale=self.scale # ) hidden_states = self._memory_efficient_attention_xformers( query, key, value, attention_mask) # Some versions of xformers return output in fp32, cast it # back to the dtype of the input hidden_states = hidden_states.to(query.dtype) else: if self._slice_size is None or query.shape[ 0] // self._slice_size == 1: hidden_states = self._attention(query, key, value, attention_mask) else: hidden_states = self._sliced_attention(query, key, value, sequence_length, dim, attention_mask) # linear proj hidden_states = self.to_out[0](hidden_states) # dropout hidden_states = self.to_out[1](hidden_states) return hidden_states def _attention(self, query, key, value, attention_mask=None): if self.upcast_attention: query = query.float() key = key.float() attention_scores = torch.baddbmm( torch.empty( query.shape[0], query.shape[1], key.shape[1], dtype=query.dtype, device=query.device), query, key.transpose(-1, -2), beta=0, alpha=self.scale, ) if attention_mask is not None: attention_scores = attention_scores + attention_mask if self.upcast_softmax: attention_scores = attention_scores.float() attention_probs = attention_scores.softmax(dim=-1) # cast back to the original dtype attention_probs = attention_probs.to(value.dtype) # compute attention output hidden_states = torch.bmm(attention_probs, value) # reshape hidden_states hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states def _sliced_attention(self, query, key, value, sequence_length, dim, attention_mask): batch_size_attention = query.shape[0] hidden_states = torch.zeros( (batch_size_attention, sequence_length, dim // self.heads), device=query.device, dtype=query.dtype) slice_size = self._slice_size \ if self._slice_size is not None else hidden_states.shape[0] for i in range(hidden_states.shape[0] // slice_size): start_idx = i * slice_size end_idx = (i + 1) * slice_size query_slice = query[start_idx:end_idx] key_slice = key[start_idx:end_idx] if self.upcast_attention: query_slice = query_slice.float() key_slice = key_slice.float() attn_slice = torch.baddbmm( torch.empty( slice_size, query.shape[1], key.shape[1], dtype=query_slice.dtype, device=query.device), query_slice, key_slice.transpose(-1, -2), beta=0, alpha=self.scale, ) if attention_mask is not None: attn_slice = attn_slice + attention_mask[start_idx:end_idx] if self.upcast_softmax: attn_slice = attn_slice.float() attn_slice = attn_slice.softmax(dim=-1) # cast back to the original dtype attn_slice = attn_slice.to(value.dtype) attn_slice = torch.bmm(attn_slice, value[start_idx:end_idx]) hidden_states[start_idx:end_idx] = attn_slice # reshape hidden_states hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states def _memory_efficient_attention_xformers(self, query, key, value, attention_mask): # TODO attention_mask query = query.contiguous() key = key.contiguous() value = value.contiguous() hidden_states = xformers.ops.memory_efficient_attention( query, key, value, attn_bias=attention_mask) hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states ================================================ FILE: mmagic/models/editors/animatediff/motion_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Adapted from https://github.com/huggingface/diffusers import math from dataclasses import dataclass from typing import Optional import torch import torch.nn.functional as F from diffusers.utils import BaseOutput from diffusers.utils.import_utils import is_xformers_available from einops import rearrange, repeat from torch import nn from mmagic.models.editors.ddpm.attention import GEGLU, ApproximateGELU from .attention_3d import CrossAttention def zero_module(module): """Zero out the parameters of a module and return it.""" for p in module.parameters(): p.detach().zero_() return module @dataclass class TemporalTransformer3DModelOutput(BaseOutput): """Output of TemporalTransformer3DModel.""" sample: torch.FloatTensor if is_xformers_available(): import xformers import xformers.ops else: xformers = None def get_motion_module(in_channels, motion_module_type: str, motion_module_kwargs: dict): """Get motion module.""" if motion_module_type == 'Vanilla': return VanillaTemporalModule( in_channels=in_channels, **motion_module_kwargs, ) else: raise ValueError class VanillaTemporalModule(nn.Module): """Module which uses transformer to handle 3d motion.""" def __init__( self, in_channels, num_attention_heads=8, num_transformer_block=2, attention_block_types=('Temporal_Self', 'Temporal_Self'), cross_frame_attention_mode=None, temporal_position_encoding=False, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1, zero_initialize=True, ): super().__init__() temp_pos_max_len = temporal_position_encoding_max_len self.temporal_transformer = TemporalTransformer3DModel( in_channels=in_channels, num_attention_heads=num_attention_heads, attention_head_dim=in_channels // num_attention_heads // temporal_attention_dim_div, num_layers=num_transformer_block, attention_block_types=attention_block_types, cross_frame_attention_mode=cross_frame_attention_mode, temporal_position_encoding=temporal_position_encoding, temporal_position_encoding_max_len=temp_pos_max_len, ) if zero_initialize: self.temporal_transformer.proj_out = zero_module( self.temporal_transformer.proj_out) def forward(self, input_tensor, temb, encoder_hidden_states, attention_mask=None, anchor_frame_idx=None): """forward with sample.""" hidden_states = input_tensor hidden_states = self.temporal_transformer(hidden_states, encoder_hidden_states, attention_mask) output = hidden_states return output class TemporalTransformer3DModel(nn.Module): """Module which uses implement 3D Transformer.""" def __init__( self, in_channels, num_attention_heads, attention_head_dim, num_layers, attention_block_types=( 'Temporal_Self', 'Temporal_Self', ), dropout=0.0, norm_num_groups=32, cross_attention_dim=768, activation_fn='geglu', attention_bias=False, upcast_attention=False, cross_frame_attention_mode=None, temporal_position_encoding=False, temporal_position_encoding_max_len=24, ): super().__init__() inner_dim = num_attention_heads * attention_head_dim self.norm = torch.nn.GroupNorm( num_groups=norm_num_groups, num_channels=in_channels, eps=1e-6, affine=True) self.proj_in = nn.Linear(in_channels, inner_dim) temp_pos_max_len = temporal_position_encoding_max_len self.transformer_blocks = nn.ModuleList([ TemporalTransformerBlock( dim=inner_dim, num_attention_heads=num_attention_heads, attention_head_dim=attention_head_dim, attention_block_types=attention_block_types, dropout=dropout, norm_num_groups=norm_num_groups, cross_attention_dim=cross_attention_dim, activation_fn=activation_fn, attention_bias=attention_bias, upcast_attention=upcast_attention, cross_frame_attention_mode=cross_frame_attention_mode, temporal_position_encoding=temporal_position_encoding, temporal_position_encoding_max_len=temp_pos_max_len, ) for d in range(num_layers) ]) self.proj_out = nn.Linear(inner_dim, in_channels) def forward(self, hidden_states, encoder_hidden_states=None, attention_mask=None): """forward with hidden states, encoder_hidden_states and attention_mask.""" assert hidden_states.dim( ) == 5, f'{"Expected hidden_states to have ndim=5, "}' f'but got ndim={hidden_states.dim()}.' video_length = hidden_states.shape[2] hidden_states = rearrange(hidden_states, 'b c f h w -> (b f) c h w') batch, channel, height, weight = hidden_states.shape residual = hidden_states hidden_states = self.norm(hidden_states) inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * weight, inner_dim) hidden_states = self.proj_in(hidden_states) # Transformer Blocks for block in self.transformer_blocks: hidden_states = block( hidden_states, encoder_hidden_states=encoder_hidden_states, video_length=video_length) # output hidden_states = self.proj_out(hidden_states) hidden_states = hidden_states.reshape(batch, height, weight, inner_dim).permute( 0, 3, 1, 2).contiguous() output = hidden_states + residual output = rearrange(output, '(b f) c h w -> b c f h w', f=video_length) return output class TemporalTransformerBlock(nn.Module): """Module which is a component of Temporal 3D Transformer.""" def __init__( self, dim, num_attention_heads, attention_head_dim, attention_block_types=( 'Temporal_Self', 'Temporal_Self', ), dropout=0.0, norm_num_groups=32, cross_attention_dim=768, activation_fn='geglu', attention_bias=False, upcast_attention=False, cross_frame_attention_mode=None, temporal_position_encoding=False, temporal_position_encoding_max_len=24, ): super().__init__() attention_blocks = [] norms = [] temp_pos_max_len = temporal_position_encoding_max_len for block_name in attention_block_types: attention_blocks.append( VersatileAttention( attention_mode=block_name.split('_')[0], cross_attention_dim=cross_attention_dim if block_name.endswith('_Cross') else None, query_dim=dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, upcast_attention=upcast_attention, cross_frame_attention_mode=cross_frame_attention_mode, temporal_position_encoding=temporal_position_encoding, temporal_position_encoding_max_len=temp_pos_max_len, )) norms.append(nn.LayerNorm(dim)) self.attention_blocks = nn.ModuleList(attention_blocks) self.norms = nn.ModuleList(norms) self.ff = FeedForward( dim, dropout=dropout, activation_fn=activation_fn) self.ff_norm = nn.LayerNorm(dim) def forward(self, hidden_states, encoder_hidden_states=None, attention_mask=None, video_length=None): """forward with hidden states, encoder_hidden_states and attention_mask.""" for attention_block, norm in zip(self.attention_blocks, self.norms): norm_hidden_states = norm(hidden_states) hidden_states = attention_block( norm_hidden_states, encoder_hidden_states=encoder_hidden_states if attention_block.is_cross_attention else None, video_length=video_length, ) + hidden_states hidden_states = self.ff(self.ff_norm(hidden_states)) + hidden_states output = hidden_states return output class PositionalEncoding(nn.Module): """a implementation of PositionEncoding.""" def __init__(self, d_model, dropout=0., max_len=24): super().__init__() self.dropout = nn.Dropout(p=dropout) position = torch.arange(max_len).unsqueeze(1) div_term = torch.exp( torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model)) pe = torch.zeros(1, max_len, d_model) pe[0, :, 0::2] = torch.sin(position * div_term) pe[0, :, 1::2] = torch.cos(position * div_term) self.register_buffer('pe', pe) def forward(self, x): """forward function.""" x = x + self.pe[:, :x.size(1)] return self.dropout(x) class VersatileAttention(CrossAttention): """a implementation of VersatileAttention.""" def __init__(self, attention_mode=None, cross_frame_attention_mode=None, temporal_position_encoding=False, temporal_position_encoding_max_len=24, *args, **kwargs): super().__init__(*args, **kwargs) assert attention_mode == 'Temporal' self.attention_mode = attention_mode self.is_cross_attention = kwargs['cross_attention_dim'] is not None self.pos_encoder = PositionalEncoding( kwargs['query_dim'], dropout=0., max_len=temporal_position_encoding_max_len) if ( temporal_position_encoding and attention_mode == 'Temporal') else None self._use_memory_efficient_attention_xformers = False def extra_repr(self): """return module information.""" return f'(Module Info) Attention_Mode: {self.attention_mode},\ Is_Cross_Attention: {self.is_cross_attention}' def reshape_heads_to_batch_dim(self, tensor): """reshape heads num to batch dim.""" batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size, seq_len, head_size, dim // head_size) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size * head_size, seq_len, dim // head_size) return tensor def reshape_batch_dim_to_heads(self, tensor): """reshape batch dim to heads num.""" batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size // head_size, head_size, seq_len, dim) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size // head_size, seq_len, dim * head_size) return tensor def _memory_efficient_attention_xformers(self, query, key, value, attention_mask): """use xformers to save memory.""" # TODO attention_mask query = query.contiguous() key = key.contiguous() value = value.contiguous() hidden_states = xformers.ops.memory_efficient_attention( query, key, value, attn_bias=attention_mask) hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states def forward(self, hidden_states, encoder_hidden_states=None, attention_mask=None, video_length=None): """forward with hidden states, encoder_hidden_states and attention_mask.""" batch_size, sequence_length, _ = hidden_states.shape if self.attention_mode == 'Temporal': d = hidden_states.shape[1] hidden_states = rearrange( hidden_states, '(b f) d c -> (b d) f c', f=video_length) if self.pos_encoder is not None: hidden_states = self.pos_encoder(hidden_states) encoder_hidden_states = repeat( encoder_hidden_states, 'b n c -> (b d) n c', d=d ) if encoder_hidden_states is not None else encoder_hidden_states else: raise NotImplementedError encoder_hidden_states = encoder_hidden_states if self.group_norm is not None: hidden_states = self.group_norm(hidden_states.transpose( 1, 2)).transpose(1, 2) query = self.to_q(hidden_states) dim = query.shape[-1] query = self.reshape_heads_to_batch_dim(query) if self.added_kv_proj_dim is not None: raise NotImplementedError encoder_hidden_states = encoder_hidden_states \ if encoder_hidden_states is not None else hidden_states key = self.to_k(encoder_hidden_states) value = self.to_v(encoder_hidden_states) key = self.reshape_heads_to_batch_dim(key) value = self.reshape_heads_to_batch_dim(value) if attention_mask is not None: if attention_mask.shape[-1] != query.shape[1]: target_length = query.shape[1] attention_mask = F.pad( attention_mask, (0, target_length), value=0.0) attention_mask = attention_mask.repeat_interleave( self.heads, dim=0) # attention, what we cannot get enough of if self._use_memory_efficient_attention_xformers: hidden_states = self._memory_efficient_attention_xformers( query, key, value, attention_mask) # Some versions of xformers return output in fp32, # cast it back to the dtype of the input hidden_states = hidden_states.to(query.dtype) else: if self._slice_size is None or query.shape[ 0] // self._slice_size == 1: hidden_states = self._attention(query, key, value, attention_mask) else: hidden_states = self._sliced_attention(query, key, value, sequence_length, dim, attention_mask) # linear proj hidden_states = self.to_out[0](hidden_states) # dropout hidden_states = self.to_out[1](hidden_states) if self.attention_mode == 'Temporal': hidden_states = rearrange( hidden_states, '(b d) f c -> (b f) d c', d=d) return hidden_states class FeedForward(nn.Module): r""" A feed-forward layer. Parameters: dim (`int`): The number of channels in the input. dim_out (`int`, *optional*): The number of channels in the output. If not given, defaults to `dim`. mult (`int`, *optional*, defaults to 4): The multiplier to use for the hidden dimension. dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. """ def __init__( self, dim: int, dim_out: Optional[int] = None, mult: int = 4, dropout: float = 0.0, activation_fn: str = 'geglu', ): super().__init__() inner_dim = int(dim * mult) dim_out = dim_out if dim_out is not None else dim if activation_fn == 'gelu': act_fn = GELU(dim, inner_dim) elif activation_fn == 'geglu': act_fn = GEGLU(dim, inner_dim) elif activation_fn == 'geglu-approximate': act_fn = ApproximateGELU(dim, inner_dim) self.net = nn.ModuleList([]) # project in self.net.append(act_fn) # project dropout self.net.append(nn.Dropout(dropout)) # project out self.net.append(nn.Linear(inner_dim, dim_out)) def forward(self, hidden_states): for module in self.net: hidden_states = module(hidden_states) return hidden_states class GELU(nn.Module): r""" GELU activation function """ def __init__(self, dim_in: int, dim_out: int): super().__init__() self.proj = nn.Linear(dim_in, dim_out) def gelu(self, gate): if gate.device.type != 'mps': return F.gelu(gate) # mps: gelu is not implemented for float16 return F.gelu(gate.to(dtype=torch.float32)).to(dtype=gate.dtype) def forward(self, hidden_states): hidden_states = self.proj(hidden_states) hidden_states = self.gelu(hidden_states) return hidden_states ================================================ FILE: mmagic/models/editors/animatediff/resnet_3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Adapted from https://github.com/huggingface/diffusers/blob/main/ # src/diffusers/models/resnet.py import torch import torch.nn as nn import torch.nn.functional as F from einops import rearrange class InflatedConv3d(nn.Conv2d): """An implementation of InflatedConv3d.""" def forward(self, x): """forward function.""" video_length = x.shape[2] x = rearrange(x, 'b c f h w -> (b f) c h w') x = super().forward(x) x = rearrange(x, '(b f) c h w -> b c f h w', f=video_length) return x class InflatedGroupNorm(nn.GroupNorm): def forward(self, x): video_length = x.shape[2] x = rearrange(x, 'b c f h w -> (b f) c h w') x = super().forward(x) x = rearrange(x, '(b f) c h w -> b c f h w', f=video_length) return x class Upsample3D(nn.Module): """An 3D upsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. use_conv_transpose (bool): whether to use conv transpose. out_channels (int): output channels. """ def __init__(self, channels, use_conv=False, use_conv_transpose=False, out_channels=None, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.use_conv_transpose = use_conv_transpose self.name = name if use_conv_transpose: raise NotImplementedError elif use_conv: self.conv = InflatedConv3d( self.channels, self.out_channels, 3, padding=1) def forward(self, hidden_states, output_size=None): """forward with hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv_transpose: raise NotImplementedError # Cast to float32 to as 'upsample_nearest2d_out_frame' # op does not support bfloat16 dtype = hidden_states.dtype if dtype == torch.bfloat16: hidden_states = hidden_states.to(torch.float32) # upsample_nearest_nhwc fails with large batch sizes. # see https://github.com/huggingface/diffusers/issues/984 if hidden_states.shape[0] >= 64: hidden_states = hidden_states.contiguous() # if `output_size` is passed we force the interpolation output # size and do not make use of `scale_factor=2` if output_size is None: hidden_states = F.interpolate( hidden_states, scale_factor=[1.0, 2.0, 2.0], mode='nearest') else: hidden_states = F.interpolate( hidden_states, size=output_size, mode='nearest') # If the input is bfloat16, we cast back to bfloat16 if dtype == torch.bfloat16: hidden_states = hidden_states.to(dtype) # if self.use_conv: # if self.name == "conv": # hidden_states = self.conv(hidden_states) # else: # hidden_states = self.Conv2d_0(hidden_states) hidden_states = self.conv(hidden_states) return hidden_states class Downsample3D(nn.Module): """A 3D downsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. out_channels (int): output channels padding (int): padding num """ def __init__(self, channels, use_conv=False, out_channels=None, padding=1, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.padding = padding stride = 2 self.name = name if use_conv: self.conv = InflatedConv3d( self.channels, self.out_channels, 3, stride=stride, padding=padding) else: raise NotImplementedError def forward(self, hidden_states): """forward with hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv and self.padding == 0: raise NotImplementedError assert hidden_states.shape[1] == self.channels hidden_states = self.conv(hidden_states) return hidden_states class ResnetBlock3D(nn.Module): """3D resnet block support down sample and up sample. Args: in_channels (int): input channels. out_channels (int): output channels. conv_shortcut (bool): whether to use conv shortcut. dropout (float): dropout rate. temb_channels (int): time embedding channels. groups (int): conv groups. groups_out (int): conv out groups. pre_norm (bool): whether to norm before conv. Todo: remove. eps (float): eps for groupnorm. non_linearity (str): non linearity type. time_embedding_norm (str): time embedding norm type. output_scale_factor (float): factor to scale input and output. use_in_shortcut (bool): whether to use conv in shortcut. """ def __init__( self, *, in_channels, out_channels=None, conv_shortcut=False, dropout=0.0, temb_channels=512, groups=32, groups_out=None, pre_norm=True, eps=1e-6, non_linearity='swish', time_embedding_norm='default', output_scale_factor=1.0, use_in_shortcut=None, use_inflated_groupnorm=None, ): super().__init__() self.pre_norm = pre_norm self.pre_norm = True self.in_channels = in_channels out_channels = in_channels if out_channels is None else out_channels self.out_channels = out_channels self.use_conv_shortcut = conv_shortcut self.time_embedding_norm = time_embedding_norm self.output_scale_factor = output_scale_factor if groups_out is None: groups_out = groups if use_inflated_groupnorm: self.norm1 = InflatedGroupNorm( num_groups=groups, num_channels=in_channels, eps=eps, affine=True) else: self.norm1 = torch.nn.GroupNorm( num_groups=groups, num_channels=in_channels, eps=eps, affine=True) self.conv1 = InflatedConv3d( in_channels, out_channels, kernel_size=3, stride=1, padding=1) if temb_channels is not None: if self.time_embedding_norm == 'default': time_emb_proj_out_channels = out_channels elif self.time_embedding_norm == 'scale_shift': time_emb_proj_out_channels = out_channels * 2 else: raise ValueError(f'unknown time_embedding_norm : ' f'{self.time_embedding_norm} ') self.time_emb_proj = torch.nn.Linear(temb_channels, time_emb_proj_out_channels) else: self.time_emb_proj = None if use_inflated_groupnorm: self.norm2 = InflatedGroupNorm( num_groups=groups_out, num_channels=out_channels, eps=eps, affine=True) else: self.norm2 = torch.nn.GroupNorm( num_groups=groups_out, num_channels=out_channels, eps=eps, affine=True) self.dropout = torch.nn.Dropout(dropout) self.conv2 = InflatedConv3d( out_channels, out_channels, kernel_size=3, stride=1, padding=1) if non_linearity == 'swish': self.nonlinearity = lambda x: F.silu(x) elif non_linearity == 'mish': self.nonlinearity = Mish() elif non_linearity == 'silu': self.nonlinearity = nn.SiLU() self.use_in_shortcut = self.in_channels != self.out_channels \ if use_in_shortcut is None else use_in_shortcut self.conv_shortcut = None if self.use_in_shortcut: self.conv_shortcut = InflatedConv3d( in_channels, out_channels, kernel_size=1, stride=1, padding=0) def forward(self, input_tensor, temb): """forward with hidden states and time embeddings.""" hidden_states = input_tensor hidden_states = self.norm1(hidden_states) hidden_states = self.nonlinearity(hidden_states) hidden_states = self.conv1(hidden_states) if temb is not None: temb = self.time_emb_proj(self.nonlinearity(temb))[:, :, None, None, None] if temb is not None and self.time_embedding_norm == 'default': hidden_states = hidden_states + temb hidden_states = self.norm2(hidden_states) if temb is not None and self.time_embedding_norm == 'scale_shift': scale, shift = torch.chunk(temb, 2, dim=1) hidden_states = hidden_states * (1 + scale) + shift hidden_states = self.nonlinearity(hidden_states) hidden_states = self.dropout(hidden_states) hidden_states = self.conv2(hidden_states) if self.conv_shortcut is not None: input_tensor = self.conv_shortcut(input_tensor) output_tensor = (input_tensor + hidden_states) / self.output_scale_factor return output_tensor class Mish(torch.nn.Module): """Mish activation function.""" def forward(self, hidden_states): """forward with hidden states.""" return hidden_states * torch.tanh( torch.nn.functional.softplus(hidden_states)) ================================================ FILE: mmagic/models/editors/animatediff/unet_3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Adapted from https://github.com/huggingface/diffusers/ # blob/main/src/diffusers/models/unet_2d_condition.py import json import os from dataclasses import dataclass from typing import List, Optional, Tuple, Union import torch import torch.nn as nn import torch.utils.checkpoint from diffusers.configuration_utils import ConfigMixin, register_to_config from diffusers.models.embeddings import TimestepEmbedding, Timesteps from diffusers.models.modeling_utils import ModelMixin from diffusers.utils import BaseOutput from huggingface_hub import snapshot_download from mmengine.logging import MMLogger from mmengine.model import constant_init from safetensors import safe_open from mmagic.registry import MODELS from .resnet_3d import InflatedConv3d, InflatedGroupNorm from .unet_block import (CrossAttnDownBlock3D, CrossAttnUpBlock3D, DownBlock3D, UNetMidBlock3DCrossAttn, UpBlock3D, get_down_block, get_up_block) logger = MMLogger.get_current_instance() @dataclass class UNet3DConditionOutput(BaseOutput): """Output of UNet3DCondtion.""" sample: torch.FloatTensor @MODELS.register_module() class UNet3DConditionMotionModel(ModelMixin, ConfigMixin): _supports_gradient_checkpointing = True """ Implementation of UNet3DConditionMotionModel""" @register_to_config def __init__( self, sample_size: Optional[int] = None, in_channels: int = 4, out_channels: int = 4, center_input_sample: bool = False, flip_sin_to_cos: bool = True, freq_shift: int = 0, down_block_types: Tuple[str] = ( 'CrossAttnDownBlock3D', 'CrossAttnDownBlock3D', 'CrossAttnDownBlock3D', 'DownBlock3D', ), mid_block_type: str = 'UNetMidBlock3DCrossAttn', up_block_types: Tuple[str] = ('UpBlock3D', 'CrossAttnUpBlock3D', 'CrossAttnUpBlock3D', 'CrossAttnUpBlock3D'), only_cross_attention: Union[bool, Tuple[bool]] = False, block_out_channels: Tuple[int] = (320, 640, 1280, 1280), layers_per_block: int = 2, downsample_padding: int = 1, mid_block_scale_factor: float = 1, act_fn: str = 'silu', norm_num_groups: int = 32, norm_eps: float = 1e-5, cross_attention_dim: int = 768, attention_head_dim: Union[int, Tuple[int]] = 8, dual_cross_attention: bool = False, use_linear_projection: bool = False, class_embed_type: Optional[str] = None, num_class_embeds: Optional[int] = None, upcast_attention: bool = False, resnet_time_scale_shift: str = 'default', # Additional use_inflated_groupnorm=False, use_motion_module=False, motion_module_resolutions=(1, 2, 4, 8), motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type=None, motion_module_kwargs={}, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, subfolder=None, from_pretrained=None, unet_addtion_kwargs=None, ): super().__init__() self.sample_size = sample_size time_embed_dim = block_out_channels[0] * 4 # input self.conv_in = InflatedConv3d( in_channels, block_out_channels[0], kernel_size=3, padding=(1, 1)) # time self.time_proj = Timesteps(block_out_channels[0], flip_sin_to_cos, freq_shift) timestep_input_dim = block_out_channels[0] self.time_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim) # class embedding if class_embed_type is None and num_class_embeds is not None: self.class_embedding = nn.Embedding(num_class_embeds, time_embed_dim) elif class_embed_type == 'timestep': self.class_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim) elif class_embed_type == 'identity': self.class_embedding = nn.Identity(time_embed_dim, time_embed_dim) else: self.class_embedding = None self.down_blocks = nn.ModuleList([]) self.mid_block = None self.up_blocks = nn.ModuleList([]) if isinstance(only_cross_attention, bool): only_cross_attention = [only_cross_attention ] * len(down_block_types) if isinstance(attention_head_dim, int): attention_head_dim = (attention_head_dim, ) * len(down_block_types) # down output_channel = block_out_channels[0] for i, down_block_type in enumerate(down_block_types): res = 2**i input_channel = output_channel output_channel = block_out_channels[i] is_final_block = i == len(block_out_channels) - 1 down_block = get_down_block( down_block_type, num_layers=layers_per_block, in_channels=input_channel, out_channels=output_channel, temb_channels=time_embed_dim, add_downsample=not is_final_block, resnet_eps=norm_eps, resnet_act_fn=act_fn, resnet_groups=norm_num_groups, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attention_head_dim[i], downsample_padding=downsample_padding, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention[i], upcast_attention=upcast_attention, resnet_time_scale_shift=resnet_time_scale_shift, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module and (res in motion_module_resolutions) and (not motion_module_decoder_only), motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) self.down_blocks.append(down_block) # mid if mid_block_type == 'UNetMidBlock3DCrossAttn': self.mid_block = UNetMidBlock3DCrossAttn( in_channels=block_out_channels[-1], temb_channels=time_embed_dim, resnet_eps=norm_eps, resnet_act_fn=act_fn, output_scale_factor=mid_block_scale_factor, resnet_time_scale_shift=resnet_time_scale_shift, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attention_head_dim[-1], resnet_groups=norm_num_groups, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, upcast_attention=upcast_attention, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module and motion_module_mid_block, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) else: raise ValueError(f'unknown mid_block_type : {mid_block_type}') # count how many layers upsample the videos self.num_upsamplers = 0 # up reversed_block_out_channels = list(reversed(block_out_channels)) reversed_attention_head_dim = list(reversed(attention_head_dim)) only_cross_attention = list(reversed(only_cross_attention)) output_channel = reversed_block_out_channels[0] for i, up_block_type in enumerate(up_block_types): res = 2**(3 - i) is_final_block = i == len(block_out_channels) - 1 prev_output_channel = output_channel output_channel = reversed_block_out_channels[i] input_channel = reversed_block_out_channels[min( i + 1, len(block_out_channels) - 1)] # add upsample block for all BUT final layer if not is_final_block: add_upsample = True self.num_upsamplers += 1 else: add_upsample = False up_block = get_up_block( up_block_type, num_layers=layers_per_block + 1, in_channels=input_channel, out_channels=output_channel, prev_output_channel=prev_output_channel, temb_channels=time_embed_dim, add_upsample=add_upsample, resnet_eps=norm_eps, resnet_act_fn=act_fn, resnet_groups=norm_num_groups, cross_attention_dim=cross_attention_dim, attn_num_head_channels=reversed_attention_head_dim[i], dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention[i], upcast_attention=upcast_attention, resnet_time_scale_shift=resnet_time_scale_shift, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module and (res in motion_module_resolutions), motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) self.up_blocks.append(up_block) prev_output_channel = output_channel # out if use_inflated_groupnorm: self.conv_norm_out = InflatedGroupNorm( num_channels=block_out_channels[0], num_groups=norm_num_groups, eps=norm_eps) else: self.conv_norm_out = nn.GroupNorm( num_channels=block_out_channels[0], num_groups=norm_num_groups, eps=norm_eps) self.conv_norm_out = nn.GroupNorm( num_channels=block_out_channels[0], num_groups=norm_num_groups, eps=norm_eps) self.conv_act = nn.SiLU() self.conv_out = InflatedConv3d( block_out_channels[0], out_channels, kernel_size=3, padding=1) self.init_weights(subfolder, from_pretrained) def init_weights(self, subfolder=None, from_pretrained=None): """Init weights for models. We just use the initialization method proposed in the original paper. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if isinstance(from_pretrained, str): from diffusers.utils import WEIGHTS_NAME model_file = os.path.join(from_pretrained, subfolder, WEIGHTS_NAME) if not os.path.isfile(model_file): cache_file = snapshot_download( 'runwayml/stable-diffusion-v1-5', allow_patterns=['*.json', '*unet*safetensors'], ignore_patterns=[ '*.fp16.safetensors', '*v1-5*', '*ema.safetensors' ]) from diffusers.utils import SAFETENSORS_WEIGHTS_NAME model_file = os.path.join(cache_file, subfolder, SAFETENSORS_WEIGHTS_NAME) state_dict = {} with safe_open(model_file, framework='pt', device='cpu') as f: for key in f.keys(): state_dict[key] = f.get_tensor(key) else: state_dict = torch.load(model_file, map_location='cpu') m, u = self.load_state_dict(state_dict, strict=False) logger.info( f'### missing keys: {len(m)}; \n### unexpected keys: {len(u)};' ) params = [ p.numel() if 'temporal' in n else 0 for n, p in self.named_parameters() ] logger.info( f'### Temporal Module Parameters: {sum(params) / 1e6} M') elif from_pretrained is None: # As Improved-DDPM, we apply zero-initialization to # second conv block in ResBlock (keywords: conv_2) # the output layer of the Unet (keywords: 'out' but # not 'out_blocks') # projection layer in Attention layer (keywords: proj) for n, m in self.named_modules(): if isinstance(m, nn.Conv2d) and ('conv2' in n or ('out' in n and 'out_blocks' not in n)): constant_init(m, 0) if isinstance(m, nn.Conv1d) and 'proj' in n: constant_init(m, 0) else: raise TypeError('from_pretrained must be a str or None but' f' got {type(from_pretrained)} instead.') def set_attention_slice(self, slice_size): r""" Enable sliced attention computation. When this option is enabled, the attention module will split the input tensor in slices, to compute attention in several steps. This is useful to save some memory in exchange for a small speed decrease. Args: slice_size (`str` or `int` or `list(int)`, *optional*, defaults to `"auto"`): When `"auto"`, halves the input to the attention heads, so attention will be computed in two steps. If `"max"`, maximum amount of memory will be saved by running only one slice at a time. If a number is provided, uses as many slices as `attention_head_dim // slice_size`. In this case, `attention_head_dim' must be a multiple of `slice_size`. """ sliceable_head_dims = [] def fn_recursive_retrieve_slicable_dims(module: torch.nn.Module): """set attention slice recursively.""" if hasattr(module, 'set_attention_slice'): sliceable_head_dims.append(module.sliceable_head_dim) for child in module.children(): fn_recursive_retrieve_slicable_dims(child) # retrieve number of attention layers for module in self.children(): fn_recursive_retrieve_slicable_dims(module) num_slicable_layers = len(sliceable_head_dims) if slice_size == 'auto': # half the attention head size is usually a good trade-off between # speed and memory slice_size = [dim // 2 for dim in sliceable_head_dims] elif slice_size == 'max': # make smallest slice possible slice_size = num_slicable_layers * [1] slice_size = num_slicable_layers * [slice_size] if not isinstance( slice_size, list) else slice_size if len(slice_size) != len(sliceable_head_dims): raise ValueError( f'You have provided {len(slice_size)}, but ' f'{self.config} has {len(sliceable_head_dims)} different' f' attention layers. Make sure to match ' f'`len(slice_size)` to be {len(sliceable_head_dims)}.') for i in range(len(slice_size)): size = slice_size[i] dim = sliceable_head_dims[i] if size is not None and size > dim: raise ValueError( f'size {size} has to be smaller or equal to {dim}.') # Recursively walk through all the children. # Any children which exposes the set_attention_slice method # gets the message def fn_recursive_set_attention_slice(module: torch.nn.Module, slice_size: List[int]): """set attention slice recursively.""" if hasattr(module, 'set_attention_slice'): module.set_attention_slice(slice_size.pop()) for child in module.children(): fn_recursive_set_attention_slice(child, slice_size) reversed_slice_size = list(reversed(slice_size)) for module in self.children(): fn_recursive_set_attention_slice(module, reversed_slice_size) def _set_gradient_checkpointing(self, module, value=False): """set gradient checkpoint.""" if isinstance(module, (CrossAttnDownBlock3D, DownBlock3D, CrossAttnUpBlock3D, UpBlock3D)): module.gradient_checkpointing = value def forward( self, sample: torch.FloatTensor, timestep: Union[torch.Tensor, float, int], encoder_hidden_states: torch.Tensor, class_labels: Optional[torch.Tensor] = None, attention_mask: Optional[torch.Tensor] = None, return_dict: bool = True, ) -> Union[UNet3DConditionOutput, Tuple]: r""" Args: sample (`torch.FloatTensor`): (batch, channel, height, width) noisy inputs tensor timestep (`torch.FloatTensor` or `float` or `int`): (batch) timesteps encoder_hidden_states (`torch.FloatTensor`): (batch, sequence_length, feature_dim) encoder hidden states return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`UNet3DConditionOutput`] instead of a plain tuple. Returns: [`UNet3DConditionOutput`] or `tuple`: [`UNet3DConditionOutput`] if `return_dict` is True, otherwise a `tuple`. When returning a tuple, the first element is the sample tensor. """ # By default samples have to be AT least a multiple of the # overall upsampling factor. he overall upsampling factor is equal # T to 2 ** (# num of upsampling layears). # However, the upsampling interpolation output size # can be forced to fit any upsampling size # on the fly if necessary. default_overall_up_factor = 2**self.num_upsamplers # upsample size should be forwarded when sample is # not a multiple of `default_overall_up_factor` forward_upsample_size = False upsample_size = None if any(s % default_overall_up_factor != 0 for s in sample.shape[-2:]): logger.info( 'Forward upsample size to force interpolation output size.') forward_upsample_size = True # prepare attention_mask if attention_mask is not None: attention_mask = (1 - attention_mask.to(sample.dtype)) * -10000.0 attention_mask = attention_mask.unsqueeze(1) # center input if necessary if self.config.center_input_sample: sample = 2 * sample - 1.0 # time timesteps = timestep if not torch.is_tensor(timesteps): # This would be a good case for the `match` # statement (Python 3.10+) is_mps = sample.device.type == 'mps' if isinstance(timestep, float): dtype = torch.float32 if is_mps else torch.float64 else: dtype = torch.int32 if is_mps else torch.int64 timesteps = torch.tensor([timesteps], dtype=dtype, device=sample.device) elif len(timesteps.shape) == 0: timesteps = timesteps[None].to(sample.device) # broadcast to batch dimension in a way # that's compatible with ONNX/Core ML timesteps = timesteps.expand(sample.shape[0]) t_emb = self.time_proj(timesteps) # timesteps does not contain any weights and will # always return f32 tensors # but time_embedding might actually be running in fp16. # so we need to cast here. # there might be better ways to encapsulate this. t_emb = t_emb.to(dtype=self.dtype) emb = self.time_embedding(t_emb) if self.class_embedding is not None: if class_labels is None: raise ValueError( 'class_labels should be provided when num_class_embeds > 0' ) if self.config.class_embed_type == 'timestep': class_labels = self.time_proj(class_labels) class_emb = self.class_embedding(class_labels).to(dtype=self.dtype) emb = emb + class_emb # pre-process sample = self.conv_in(sample) # down down_block_res_samples = (sample, ) for downsample_block in self.down_blocks: if hasattr(downsample_block, 'has_cross_attention' ) and downsample_block.has_cross_attention: sample, res_samples = downsample_block( hidden_states=sample, temb=emb, encoder_hidden_states=encoder_hidden_states, attention_mask=attention_mask, ) else: sample, res_samples = downsample_block( hidden_states=sample, temb=emb, encoder_hidden_states=encoder_hidden_states) down_block_res_samples += res_samples # mid sample = self.mid_block( sample, emb, encoder_hidden_states=encoder_hidden_states, attention_mask=attention_mask) # up for i, upsample_block in enumerate(self.up_blocks): is_final_block = i == len(self.up_blocks) - 1 res_samples = down_block_res_samples[-len(upsample_block.resnets):] down_block_res_samples = down_block_res_samples[:-len( upsample_block.resnets)] # if we have not reached the final block and need to forward the # upsample size, we do it here if not is_final_block and forward_upsample_size: upsample_size = down_block_res_samples[-1].shape[2:] if hasattr(upsample_block, 'has_cross_attention' ) and upsample_block.has_cross_attention: sample = upsample_block( hidden_states=sample, temb=emb, res_hidden_states_tuple=res_samples, encoder_hidden_states=encoder_hidden_states, upsample_size=upsample_size, attention_mask=attention_mask, ) else: sample = upsample_block( hidden_states=sample, temb=emb, res_hidden_states_tuple=res_samples, upsample_size=upsample_size, encoder_hidden_states=encoder_hidden_states, ) # post-process sample = self.conv_norm_out(sample) sample = self.conv_act(sample) sample = self.conv_out(sample) if not return_dict: return (sample, ) return UNet3DConditionOutput(sample=sample) @classmethod def from_pretrained_2d(cls, pretrained_model_path, subfolder=None, unet_additional_kwargs=None): """a class method for initialization.""" if subfolder is not None: pretrained_model_path = os.path.join(pretrained_model_path, subfolder) logger.info(f"loaded temporal unet's pretrained weights \ from {pretrained_model_path} ...") config_file = os.path.join(pretrained_model_path, 'config.json') if not os.path.isfile(config_file): raise RuntimeError(f'{config_file} does not exist') with open(config_file, 'r') as f: config = json.load(f) config['_class_name'] = cls.__name__ config['down_block_types'] = [ 'CrossAttnDownBlock3D', 'CrossAttnDownBlock3D', 'CrossAttnDownBlock3D', 'DownBlock3D' ] config['up_block_types'] = [ 'UpBlock3D', 'CrossAttnUpBlock3D', 'CrossAttnUpBlock3D', 'CrossAttnUpBlock3D' ] from diffusers.utils import WEIGHTS_NAME model = cls.from_config(config, **unet_additional_kwargs) model_file = os.path.join(pretrained_model_path, WEIGHTS_NAME) if not os.path.isfile(model_file): raise RuntimeError(f'{model_file} does not exist') state_dict = torch.load(model_file, map_location='cpu') m, u = model.load_state_dict(state_dict, strict=False) logger.info( f'### missing keys: {len(m)}; \n### unexpected keys: {len(u)};') # print(f"### missing keys:\n{m}\n### unexpected keys:\n{u}\n") params = [ p.numel() if 'temporal' in n else 0 for n, p in model.named_parameters() ] logger.info(f'### Temporal Module Parameters: {sum(params) / 1e6} M') return model ================================================ FILE: mmagic/models/editors/animatediff/unet_block.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Adapted from https://github.com/huggingface/diffusers/blob/ # main/src/diffusers/models/unet_2d_blocks.py import torch from torch import nn from .attention_3d import Transformer3DModel from .motion_module import get_motion_module from .resnet_3d import Downsample3D, ResnetBlock3D, Upsample3D def get_down_block( down_block_type, num_layers, in_channels, out_channels, temb_channels, add_downsample, resnet_eps, resnet_act_fn, attn_num_head_channels, resnet_groups=None, cross_attention_dim=None, downsample_padding=None, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, upcast_attention=False, resnet_time_scale_shift='default', unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): """get unet down path block.""" down_block_type = down_block_type[7:] if down_block_type.startswith( 'UNetRes') else down_block_type if down_block_type == 'DownBlock3D': return DownBlock3D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, add_downsample=add_downsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, downsample_padding=downsample_padding, resnet_time_scale_shift=resnet_time_scale_shift, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) elif down_block_type == 'CrossAttnDownBlock3D': if cross_attention_dim is None: raise ValueError('cross_attention_dim must be specified \ for CrossAttnDownBlock3D') return CrossAttnDownBlock3D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, add_downsample=add_downsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, downsample_padding=downsample_padding, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attn_num_head_channels, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, upcast_attention=upcast_attention, resnet_time_scale_shift=resnet_time_scale_shift, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) raise ValueError(f'{down_block_type} does not exist.') def get_up_block( up_block_type, num_layers, in_channels, out_channels, prev_output_channel, temb_channels, add_upsample, resnet_eps, resnet_act_fn, attn_num_head_channels, resnet_groups=None, cross_attention_dim=None, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, upcast_attention=False, resnet_time_scale_shift='default', unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): """get unet up path block.""" up_block_type = up_block_type[7:] if up_block_type.startswith( 'UNetRes') else up_block_type if up_block_type == 'UpBlock3D': return UpBlock3D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, prev_output_channel=prev_output_channel, temb_channels=temb_channels, add_upsample=add_upsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, resnet_time_scale_shift=resnet_time_scale_shift, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) elif up_block_type == 'CrossAttnUpBlock3D': if cross_attention_dim is None: raise ValueError( 'cross_attention_dim must be specified for CrossAttnUpBlock3D') return CrossAttnUpBlock3D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, prev_output_channel=prev_output_channel, temb_channels=temb_channels, add_upsample=add_upsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attn_num_head_channels, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, upcast_attention=upcast_attention, resnet_time_scale_shift=resnet_time_scale_shift, unet_use_cross_frame_attention=unet_use_cross_frame_attention, unet_use_temporal_attention=unet_use_temporal_attention, use_inflated_groupnorm=use_inflated_groupnorm, use_motion_module=use_motion_module, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) raise ValueError(f'{up_block_type} does not exist.') class UNetMidBlock3DCrossAttn(nn.Module): """3D unet mid block built by cross attention.""" def __init__( self, in_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, output_scale_factor=1.0, cross_attention_dim=1280, dual_cross_attention=False, use_linear_projection=False, upcast_attention=False, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): super().__init__() self.has_cross_attention = True self.attn_num_head_channels = attn_num_head_channels resnet_groups = resnet_groups if resnet_groups is not None else min( in_channels // 4, 32) # there is always at least one resnet resnets = [ ResnetBlock3D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, ) ] attentions = [] motion_modules = [] for _ in range(num_layers): if dual_cross_attention: raise NotImplementedError cfa = unet_use_cross_frame_attention attentions.append( Transformer3DModel( attn_num_head_channels, in_channels // attn_num_head_channels, in_channels=in_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, upcast_attention=upcast_attention, unet_use_cross_frame_attention=cfa, unet_use_temporal_attention=unet_use_temporal_attention, )) motion_modules.append( get_motion_module( in_channels=in_channels, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) if use_motion_module else None) resnets.append( ResnetBlock3D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, )) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) self.motion_modules = nn.ModuleList(motion_modules) def forward(self, hidden_states, temb=None, encoder_hidden_states=None, attention_mask=None): """forward with hidden states.""" hidden_states = self.resnets[0](hidden_states, temb) for attn, resnet, motion_module in zip(self.attentions, self.resnets[1:], self.motion_modules): hidden_states = attn( hidden_states, encoder_hidden_states=encoder_hidden_states).sample hidden_states = motion_module( hidden_states, temb, encoder_hidden_states=encoder_hidden_states ) if motion_module is not None else hidden_states hidden_states = resnet(hidden_states, temb) return hidden_states class CrossAttnDownBlock3D(nn.Module): """Down block built by 3D cross attention.""" def __init__( self, in_channels: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, cross_attention_dim=1280, output_scale_factor=1.0, downsample_padding=1, add_downsample=True, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, upcast_attention=False, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): super().__init__() resnets = [] attentions = [] motion_modules = [] self.has_cross_attention = True self.attn_num_head_channels = attn_num_head_channels for i in range(num_layers): in_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock3D( in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, )) if dual_cross_attention: raise NotImplementedError cfa = unet_use_cross_frame_attention attentions.append( Transformer3DModel( attn_num_head_channels, out_channels // attn_num_head_channels, in_channels=out_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, upcast_attention=upcast_attention, unet_use_cross_frame_attention=cfa, unet_use_temporal_attention=unet_use_temporal_attention, )) motion_modules.append( get_motion_module( in_channels=out_channels, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) if use_motion_module else None) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) self.motion_modules = nn.ModuleList(motion_modules) if add_downsample: self.downsamplers = nn.ModuleList([ Downsample3D( out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name='op') ]) else: self.downsamplers = None self.gradient_checkpointing = False def forward(self, hidden_states, temb=None, encoder_hidden_states=None, attention_mask=None): """forward with hidden states.""" output_states = () for resnet, attn, motion_module in zip(self.resnets, self.attentions, self.motion_modules): if self.training and self.gradient_checkpointing: def create_custom_forward(module, return_dict=None): def custom_forward(*inputs): if return_dict is not None: return module(*inputs, return_dict=return_dict) else: return module(*inputs) return custom_forward hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb) hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(attn, return_dict=False), hidden_states, encoder_hidden_states, )[0] if motion_module is not None: hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(motion_module), hidden_states.requires_grad_(), temb, encoder_hidden_states) else: hidden_states = resnet(hidden_states, temb) hidden_states = attn( hidden_states, encoder_hidden_states=encoder_hidden_states).sample # add motion module hidden_states = motion_module( hidden_states, temb, encoder_hidden_states=encoder_hidden_states ) if motion_module is not None else hidden_states output_states += (hidden_states, ) if self.downsamplers is not None: for downsampler in self.downsamplers: hidden_states = downsampler(hidden_states) output_states += (hidden_states, ) return hidden_states, output_states class DownBlock3D(nn.Module): """Down block built by 3D resnet.""" def __init__( self, in_channels: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_downsample=True, downsample_padding=1, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): super().__init__() resnets = [] motion_modules = [] for i in range(num_layers): in_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock3D( in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, )) motion_modules.append( get_motion_module( in_channels=out_channels, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) if use_motion_module else None) self.resnets = nn.ModuleList(resnets) self.motion_modules = nn.ModuleList(motion_modules) if add_downsample: self.downsamplers = nn.ModuleList([ Downsample3D( out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name='op') ]) else: self.downsamplers = None self.gradient_checkpointing = False def forward(self, hidden_states, temb=None, encoder_hidden_states=None): """forward with hidden states.""" output_states = () for resnet, motion_module in zip(self.resnets, self.motion_modules): if self.training and self.gradient_checkpointing: def create_custom_forward(module): def custom_forward(*inputs): return module(*inputs) return custom_forward hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb) if motion_module is not None: hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(motion_module), hidden_states.requires_grad_(), temb, encoder_hidden_states) else: hidden_states = resnet(hidden_states, temb) # add motion module hidden_states = motion_module( hidden_states, temb, encoder_hidden_states=encoder_hidden_states ) if motion_module is not None else hidden_states output_states += (hidden_states, ) if self.downsamplers is not None: for downsampler in self.downsamplers: hidden_states = downsampler(hidden_states) output_states += (hidden_states, ) return hidden_states, output_states class CrossAttnUpBlock3D(nn.Module): """Up block built by 3D cross attention.""" def __init__( self, in_channels: int, out_channels: int, prev_output_channel: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, cross_attention_dim=1280, output_scale_factor=1.0, add_upsample=True, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, upcast_attention=False, unet_use_cross_frame_attention=None, unet_use_temporal_attention=None, use_inflated_groupnorm=None, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, ): super().__init__() resnets = [] attentions = [] motion_modules = [] self.has_cross_attention = True self.attn_num_head_channels = attn_num_head_channels for i in range(num_layers): res_skip_channels = in_channels if (i == num_layers - 1) else out_channels resnet_in_channels = prev_output_channel if i == 0 \ else out_channels resnets.append( ResnetBlock3D( in_channels=resnet_in_channels + res_skip_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, )) if dual_cross_attention: raise NotImplementedError cfa = unet_use_cross_frame_attention attentions.append( Transformer3DModel( attn_num_head_channels, out_channels // attn_num_head_channels, in_channels=out_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, upcast_attention=upcast_attention, unet_use_cross_frame_attention=cfa, unet_use_temporal_attention=unet_use_temporal_attention, )) motion_modules.append( get_motion_module( in_channels=out_channels, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) if use_motion_module else None) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) self.motion_modules = nn.ModuleList(motion_modules) if add_upsample: self.upsamplers = nn.ModuleList([ Upsample3D( out_channels, use_conv=True, out_channels=out_channels) ]) else: self.upsamplers = None self.gradient_checkpointing = False def forward( self, hidden_states, res_hidden_states_tuple, temb=None, encoder_hidden_states=None, upsample_size=None, attention_mask=None, ): """forward with hidden states and res hidden states.""" for resnet, attn, motion_module in zip(self.resnets, self.attentions, self.motion_modules): # pop res hidden states res_hidden_states = res_hidden_states_tuple[-1] res_hidden_states_tuple = res_hidden_states_tuple[:-1] hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) if self.training and self.gradient_checkpointing: def create_custom_forward(module, return_dict=None): def custom_forward(*inputs): if return_dict is not None: return module(*inputs, return_dict=return_dict) else: return module(*inputs) return custom_forward hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb) hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(attn, return_dict=False), hidden_states, encoder_hidden_states, )[0] if motion_module is not None: hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(motion_module), hidden_states.requires_grad_(), temb, encoder_hidden_states) else: hidden_states = resnet(hidden_states, temb) hidden_states = attn( hidden_states, encoder_hidden_states=encoder_hidden_states).sample # add motion module hidden_states = motion_module( hidden_states, temb, encoder_hidden_states=encoder_hidden_states ) if motion_module is not None else hidden_states if self.upsamplers is not None: for upsampler in self.upsamplers: hidden_states = upsampler(hidden_states, upsample_size) return hidden_states class UpBlock3D(nn.Module): """Up block built by 3D resnet.""" def __init__( self, in_channels: int, prev_output_channel: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_upsample=True, use_motion_module=None, motion_module_type=None, motion_module_kwargs=None, use_inflated_groupnorm=None, ): super().__init__() resnets = [] motion_modules = [] for i in range(num_layers): res_skip_channels = in_channels if (i == num_layers - 1) else out_channels resnet_in_channels = prev_output_channel if i == 0 \ else out_channels resnets.append( ResnetBlock3D( in_channels=resnet_in_channels + res_skip_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, use_inflated_groupnorm=use_inflated_groupnorm, )) motion_modules.append( get_motion_module( in_channels=out_channels, motion_module_type=motion_module_type, motion_module_kwargs=motion_module_kwargs, ) if use_motion_module else None) self.resnets = nn.ModuleList(resnets) self.motion_modules = nn.ModuleList(motion_modules) if add_upsample: self.upsamplers = nn.ModuleList([ Upsample3D( out_channels, use_conv=True, out_channels=out_channels) ]) else: self.upsamplers = None self.gradient_checkpointing = False def forward( self, hidden_states, res_hidden_states_tuple, temb=None, upsample_size=None, encoder_hidden_states=None, ): """forward with hidden states and res hidden states.""" for resnet, motion_module in zip(self.resnets, self.motion_modules): # pop res hidden states res_hidden_states = res_hidden_states_tuple[-1] res_hidden_states_tuple = res_hidden_states_tuple[:-1] hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) if self.training and self.gradient_checkpointing: def create_custom_forward(module): def custom_forward(*inputs): return module(*inputs) return custom_forward hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb) if motion_module is not None: hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(motion_module), hidden_states.requires_grad_(), temb, encoder_hidden_states) else: hidden_states = resnet(hidden_states, temb) hidden_states = motion_module( hidden_states, temb, encoder_hidden_states=encoder_hidden_states ) if motion_module is not None else hidden_states if self.upsamplers is not None: for upsampler in self.upsamplers: hidden_states = upsampler(hidden_states, upsample_size) return hidden_states ================================================ FILE: mmagic/models/editors/aotgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .aot_decoder import AOTDecoder from .aot_encoder import AOTEncoder from .aot_encoder_decoder import AOTEncoderDecoder from .aot_inpaintor import AOTInpaintor from .aot_neck import AOTBlockNeck __all__ = [ 'AOTEncoderDecoder', 'AOTBlockNeck', 'AOTInpaintor', 'AOTEncoder', 'AOTDecoder' ] ================================================ FILE: mmagic/models/editors/aotgan/aot_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class AOTDecoder(BaseModule): """Decoder used in AOT-GAN model. This implementation follows: Aggregated Contextual Transformations for High-Resolution Image Inpainting Args: in_channels (int, optional): Channel number of input feature. Default: 256. mid_channels (int, optional): Channel number of middle feature. Default: 128. out_channels (int, optional): Channel number of output feature. Default 3. act_cfg (dict, optional): Config dict for activation layer, "relu" by default. """ def __init__(self, in_channels=256, mid_channels=128, out_channels=3, act_cfg=dict(type='ReLU')): super().__init__() self.decoder = nn.ModuleList([ ConvModule( in_channels, mid_channels, kernel_size=3, stride=1, padding=1, act_cfg=act_cfg), ConvModule( mid_channels, mid_channels // 2, kernel_size=3, stride=1, padding=1, act_cfg=act_cfg), ConvModule( mid_channels // 2, out_channels, kernel_size=3, stride=1, padding=1, act_cfg=None) ]) self.output_act = nn.Tanh() def forward(self, x): """Forward Function. Args: x (Tensor): Input tensor with shape of (n, c, h, w). Returns: Tensor: Output tensor with shape of (n, c, h', w'). """ for i in range(0, len(self.decoder)): if i <= 1: x = F.interpolate( x, scale_factor=2, mode='bilinear', align_corners=True) x = self.decoder[i](x) return self.output_act(x) ================================================ FILE: mmagic/models/editors/aotgan/aot_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class AOTEncoder(BaseModule): """Encoder used in AOT-GAN model. This implementation follows: Aggregated Contextual Transformations for High-Resolution Image Inpainting Args: in_channels (int, optional): Channel number of input feature. Default: 4. mid_channels (int, optional): Channel number of middle feature. Default: 64. out_channels (int, optional): Channel number of output feature. Default: 256. act_cfg (dict, optional): Config dict for activation layer, "relu" by default. """ def __init__(self, in_channels=4, mid_channels=64, out_channels=256, act_cfg=dict(type='ReLU')): super().__init__() self.encoder = nn.Sequential( nn.ReflectionPad2d(3), ConvModule( in_channels, mid_channels, kernel_size=7, stride=1, act_cfg=act_cfg), ConvModule( mid_channels, mid_channels * 2, kernel_size=4, stride=2, padding=1, act_cfg=act_cfg), ConvModule( mid_channels * 2, out_channels, kernel_size=4, stride=2, padding=1, act_cfg=act_cfg)) def forward(self, x): """Forward Function. Args: x (Tensor): Input tensor with shape of (n, c, h, w). Returns: Tensor: Output tensor with shape of (n, c, h', w'). """ return self.encoder(x) ================================================ FILE: mmagic/models/editors/aotgan/aot_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.registry import MODELS from ..global_local import GLEncoderDecoder @MODELS.register_module() class AOTEncoderDecoder(GLEncoderDecoder): """Encoder-Decoder used in AOT-GAN model. This implementation follows: Aggregated Contextual Transformations for High-Resolution Image Inpainting The architecture of the encoder-decoder is: (conv2d x 3) --> (dilated conv2d x 8) --> (conv2d or deconv2d x 3). Args: encoder (dict): Config dict to encoder. decoder (dict): Config dict to build decoder. dilation_neck (dict): Config dict to build dilation neck. """ def __init__(self, encoder=dict(type='AOTEncoder'), decoder=dict(type='AOTDecoder'), dilation_neck=dict(type='AOTBlockNeck')): super().__init__() self.encoder = MODELS.build(encoder) self.decoder = MODELS.build(decoder) self.dilation_neck = MODELS.build(dilation_neck) ================================================ FILE: mmagic/models/editors/aotgan/aot_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List import torch from mmagic.models.base_models import OneStageInpaintor from mmagic.registry import MODELS from ...utils import set_requires_grad @MODELS.register_module() class AOTInpaintor(OneStageInpaintor): """Inpaintor for AOT-GAN method. This inpaintor is implemented according to the paper: Aggregated Contextual Transformations for High-Resolution Image Inpainting """ def forward_train_d(self, data_batch, is_real, is_disc, mask): """Forward function in discriminator training step. In this function, we compute the prediction for each data batch (real or fake). Meanwhile, the standard gan loss will be computed with several proposed losses for stable training. Args: data_batch (torch.Tensor): Batch of real data or fake data. is_real (bool): If True, the gan loss will regard this batch as real data. Otherwise, the gan loss will regard this batch as fake data. is_disc (bool): If True, this function is called in discriminator training step. Otherwise, this function is called in generator training step. This will help us to compute different types of adversarial loss, like LSGAN. mask (torch.Tensor): Mask of data. Returns: dict: Contains the loss items computed in this function. """ pred = self.disc(data_batch) loss_ = self.loss_gan(pred, is_real, is_disc, mask=mask) loss = dict(real_loss=loss_) if is_real else dict(fake_loss=loss_) if self.with_disc_shift_loss: loss_d_shift = self.loss_disc_shift(loss_) # 0.5 for average the fake and real data loss.update(loss_disc_shift=loss_d_shift * 0.5) return loss def generator_loss(self, fake_res, fake_img, gt, mask, masked_img): """Forward function in generator training step. In this function, we mainly compute the loss items for generator with the given (fake_res, fake_img). In general, the `fake_res` is the direct output of the generator and the `fake_img` is the composition of direct output and ground-truth image. Args: fake_res (torch.Tensor): Direct output of the generator. fake_img (torch.Tensor): Composition of `fake_res` and ground-truth image. gt (torch.Tensor): Ground-truth image. mask (torch.Tensor): Mask image. masked_img (torch.Tensor): Composition of mask image and ground-truth image. Returns: tuple(dict): Dict contains the results computed within this function for visualization and dict contains the loss items computed in this function. """ loss = dict() if self.with_gan: pred = self.disc(fake_img) loss_g_fake = self.loss_gan(pred, True, False, mask=mask) loss['loss_g_fake'] = loss_g_fake if self.with_l1_valid_loss: loss_l1_valid = self.loss_l1_valid(fake_res, gt) loss['loss_l1_valid'] = loss_l1_valid if self.with_out_percep_loss: loss_out_percep, loss_out_style = self.loss_percep(fake_res, gt) if loss_out_percep is not None: loss['loss_out_percep'] = loss_out_percep if loss_out_style is not None: loss['loss_out_style'] = loss_out_style res = dict( gt_img=gt.cpu(), masked_img=masked_img.cpu(), fake_res=fake_res.cpu(), fake_img=fake_img.cpu()) return res, loss def forward_tensor(self, inputs, data_samples): """Forward function in tensor mode. Args: inputs (torch.Tensor): Input tensor. data_samples (List[dict]): List of data sample dict. Returns: tuple: Direct output of the generator and composition of `fake_res` and ground-truth image. """ # Pre-process runs in BaseModel.val_step / test_step masks = data_samples.mask masked_imgs = inputs # N,3,H,W masked_imgs = masked_imgs.float() + masks input_xs = torch.cat([masked_imgs, masks], dim=1) # N,4,H,W fake_reses = self.generator(input_xs) fake_imgs = fake_reses * masks + masked_imgs * (1. - masks) return fake_reses, fake_imgs def train_step(self, data: List[dict], optim_wrapper): """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. compute reconstruction losses for generator 3. compute adversarial loss for discriminator 4. optimize generator 5. optimize discriminator Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} # prepare data for training gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() masked_img = batch_inputs masked_img = masked_img.float() + mask # get common output from encdec input_x = torch.cat([masked_img, mask], dim=1) fake_res = self.generator(input_x) fake_img = gt_img * (1. - mask) + fake_res * mask # discriminator training step if self.train_cfg.disc_step > 0: set_requires_grad(self.disc, True) disc_losses_real = self.forward_train_d( gt_img, True, True, mask=mask) disc_losses_fake = self.forward_train_d( fake_img.detach(), False, True, mask=mask) disc_losses_ = disc_losses_real['real_loss'] + disc_losses_fake[ 'fake_loss'] disc_losses = dict(disc_losses=disc_losses_) loss_disc, log_vars_d = self.parse_losses(disc_losses) optim_wrapper['disc'].backward(loss_disc) optim_wrapper['disc'].step() optim_wrapper['disc'].zero_grad() log_vars.update(log_vars_d) self.disc_step_count = (self.disc_step_count + 1) % self.train_cfg.disc_step if self.disc_step_count != 0: return log_vars # generator (encdec) training step, results contain the data # for visualization if self.with_gan: set_requires_grad(self.disc, False) results, g_losses = self.generator_loss(fake_res, fake_img, gt_img, mask, masked_img) loss_g, log_vars_g = self.parse_losses(g_losses) log_vars.update(log_vars_g) optim_wrapper['generator'].backward(loss_g) optim_wrapper['generator'].step() optim_wrapper['generator'].zero_grad() return log_vars ================================================ FILE: mmagic/models/editors/aotgan/aot_neck.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class AOTBlockNeck(BaseModule): """Dilation backbone used in AOT-GAN model. This implementation follows: Aggregated Contextual Transformations for High-Resolution Image Inpainting Args: in_channels (int, optional): Channel number of input feature. Default: 256. dilation_rates (Tuple[int], optional): The dilation rates used for AOT block. Default: (1, 2, 4, 8). num_aotblock (int, optional): Number of AOT blocks. Default: 8. act_cfg (dict, optional): Config dict for activation layer, "relu" by default. kwargs (keyword arguments). """ def __init__(self, in_channels=256, dilation_rates=(1, 2, 4, 8), num_aotblock=8, act_cfg=dict(type='ReLU'), **kwargs): super().__init__() self.dilation_rates = list(dilation_rates) self.model = nn.Sequential(*[(AOTBlock( in_channels=in_channels, dilation_rates=self.dilation_rates, act_cfg=act_cfg, )) for _ in range(0, num_aotblock)]) def forward(self, x): x = self.model(x) return x class AOTBlock(BaseModule): """AOT Block which constitutes the dilation backbone. This implementation follows: Aggregated Contextual Transformations for High-Resolution Image Inpainting The AOT Block adopts the split-transformation-merge strategy: Splitting: A kernel with 256 output channels is split into four 64-channel sub-kernels. Transforming: Each sub-kernel performs a different transformation with a different dilation rate. Splitting: Sub-kernels with different receptive fields are merged. Args: in_channels (int, optional): Channel number of input feature. Default: 256. dilation_rates (Tuple[int]): The dilation rates used for AOT block. Default (1, 2, 4, 8). act_cfg (dict, optional): Config dict for activation layer, "relu" by default. kwargs (keyword arguments). """ def __init__(self, in_channels=256, dilation_rates=(1, 2, 4, 8), act_cfg=dict(type='ReLU'), **kwargs): super().__init__() self.dilation_rates = dilation_rates self.blocks = nn.ModuleList([ nn.Sequential( nn.ReflectionPad2d(dilation_rate), ConvModule( in_channels, in_channels // 4, kernel_size=3, dilation=dilation_rate, act_cfg=act_cfg)) for dilation_rate in self.dilation_rates ]) self.fuse = nn.Sequential( nn.ReflectionPad2d(1), ConvModule(in_channels, in_channels, 3, dilation=1, act_cfg=None)) self.gate = nn.Sequential( nn.ReflectionPad2d(1), ConvModule(in_channels, in_channels, 3, dilation=1, act_cfg=None)) def normalize(self, x): mean = x.mean((2, 3), keepdim=True) std = x.std((2, 3), keepdim=True) + 1e-9 x = 2 * (x - mean) / std - 1 x = 5 * x return x def forward(self, x): dilate_x = [ self.blocks[i](x) for i in range(0, len(self.dilation_rates)) ] dilate_x = torch.cat(dilate_x, 1) dilate_x = self.fuse(dilate_x) mask = self.normalize(self.gate(x)) mask = torch.sigmoid(mask) return x * (1 - mask) + dilate_x * mask ================================================ FILE: mmagic/models/editors/arcface/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .id_loss import IDLossModel __all__ = ['IDLossModel'] ================================================ FILE: mmagic/models/editors/arcface/arcface_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from collections import namedtuple import torch from torch.nn import (AdaptiveAvgPool2d, BatchNorm2d, Conv2d, MaxPool2d, Module, PReLU, ReLU, Sequential, Sigmoid) # yapf: disable """ ArcFace implementation from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch) # isort:skip # noqa """ # yapf: enable class Flatten(Module): """Flatten Module.""" def forward(self, input): return input.view(input.size(0), -1) def l2_norm(input, axis=1): """l2 normalization. Args: input (torch.Tensor): The input tensor. axis (int, optional): Specifies which axis of input to calculate the norm across. Defaults to 1. Returns: Tensor: Tensor after L2 normalization per-instance. """ norm = torch.norm(input, 2, axis, True) output = torch.div(input, norm) return output class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])): """A named tuple describing a ResNet block.""" def get_block(in_channel, depth, num_units, stride=2): """Get a single block config. Args: in_channel (int): Input channels. depth (int): Output channels. num_units (int): Number of unit modules. stride (int, optional): Conv2d stride. Defaults to 2. Returns: list: A list of unit modules' config. """ return [Bottleneck(in_channel, depth, stride) ] + [Bottleneck(depth, depth, 1) for i in range(num_units - 1)] def get_blocks(num_layers): """Get block configs of backbone. Args: num_layers (int): Number of ConvBlock layers in backbone. Raises: ValueError: `num_layers` must be one of [50, 100, 152]. Returns: list: A list of block configs. """ if num_layers == 50: blocks = [ get_block(in_channel=64, depth=64, num_units=3), get_block(in_channel=64, depth=128, num_units=4), get_block(in_channel=128, depth=256, num_units=14), get_block(in_channel=256, depth=512, num_units=3) ] elif num_layers == 100: blocks = [ get_block(in_channel=64, depth=64, num_units=3), get_block(in_channel=64, depth=128, num_units=13), get_block(in_channel=128, depth=256, num_units=30), get_block(in_channel=256, depth=512, num_units=3) ] elif num_layers == 152: blocks = [ get_block(in_channel=64, depth=64, num_units=3), get_block(in_channel=64, depth=128, num_units=8), get_block(in_channel=128, depth=256, num_units=36), get_block(in_channel=256, depth=512, num_units=3) ] else: raise ValueError( 'Invalid number of layers: {}. Must be one of [50, 100, 152]'. format(num_layers)) return blocks class SEModule(Module): """Squeeze-and-Excitation Modules. Args: channels (int): Input channels. reduction (int): Intermediate channels reduction ratio. """ def __init__(self, channels, reduction): super(SEModule, self).__init__() self.avg_pool = AdaptiveAvgPool2d(1) self.fc1 = Conv2d( channels, channels // reduction, kernel_size=1, padding=0, bias=False) self.relu = ReLU(inplace=True) self.fc2 = Conv2d( channels // reduction, channels, kernel_size=1, padding=0, bias=False) self.sigmoid = Sigmoid() def forward(self, x): """Forward Function.""" module_input = x x = self.avg_pool(x) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) x = self.sigmoid(x) return module_input * x class bottleneck_IR(Module): """Intermediate Resblock of bottleneck. Args: in_channel (int): Input channels. depth (int): Output channels. stride (int): Conv2d stride. """ def __init__(self, in_channel, depth, stride): """Intermediate Resblock of bottleneck. Args: in_channel (int): Input channels. depth (int): Output channels. stride (int): Conv2d stride. """ super(bottleneck_IR, self).__init__() if in_channel == depth: self.shortcut_layer = MaxPool2d(1, stride) else: self.shortcut_layer = Sequential( Conv2d(in_channel, depth, (1, 1), stride, bias=False), BatchNorm2d(depth)) self.res_layer = Sequential( BatchNorm2d(in_channel), Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False), PReLU(depth), Conv2d(depth, depth, (3, 3), stride, 1, bias=False), BatchNorm2d(depth)) def forward(self, x): """Forward function.""" shortcut = self.shortcut_layer(x) res = self.res_layer(x) return res + shortcut class bottleneck_IR_SE(Module): """Intermediate Resblock of bottleneck with SEModule. Args: in_channel (int): Input channels. depth (int): Output channels. stride (int): Conv2d stride. """ def __init__(self, in_channel, depth, stride): super(bottleneck_IR_SE, self).__init__() if in_channel == depth: self.shortcut_layer = MaxPool2d(1, stride) else: self.shortcut_layer = Sequential( Conv2d(in_channel, depth, (1, 1), stride, bias=False), BatchNorm2d(depth)) self.res_layer = Sequential( BatchNorm2d(in_channel), Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False), PReLU(depth), Conv2d(depth, depth, (3, 3), stride, 1, bias=False), BatchNorm2d(depth), SEModule(depth, 16)) def forward(self, x): """Forward function.""" shortcut = self.shortcut_layer(x) res = self.res_layer(x) return res + shortcut ================================================ FILE: mmagic/models/editors/arcface/id_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmengine import torch from torch import nn from mmagic.registry import MODELS from .model_irse import Backbone @MODELS.register_module('ArcFace') class IDLossModel(nn.Module): """Face id loss model. Args: ir_se50_weights (str, optional): Url of ir-se50 weights. Defaults to None. """ # ir se50 weight download link _ir_se50_url = 'https://download.openxlab.org.cn/models/rangoliu/Arcface-IR-SE50/weight/Arcface-IR-SE50' # noqa def __init__(self, ir_se50_weights=None): super(IDLossModel, self).__init__() mmengine.print_log('Loading ResNet ArcFace', 'current') self.facenet = Backbone( input_size=112, num_layers=50, drop_ratio=0.6, mode='ir_se') if ir_se50_weights is None: ir_se50_weights = self._ir_se50_url self.facenet.load_state_dict( torch.hub.load_state_dict_from_url( ir_se50_weights, map_location='cpu')) self.pool = torch.nn.AdaptiveAvgPool2d((256, 256)) self.face_pool = torch.nn.AdaptiveAvgPool2d((112, 112)) self.facenet = self.facenet.eval() def extract_feats(self, x): """Extracting face features. Args: x (torch.Tensor): Image tensor of faces. Returns: torch.Tensor: Face features. """ if x.shape[2] != 256: x = self.pool(x) x = x[:, :, 35:223, 32:220] # Crop interesting region x = self.face_pool(x) x_feats = self.facenet(x) return x_feats def forward(self, pred=None, gt=None): """Calculate face loss. Args: pred (torch.Tensor, optional): Predictions of face images. Defaults to None. gt (torch.Tensor, optional): Ground truth of face images. Defaults to None. Returns: Tuple(float, float): A tuple contain face similarity loss and improvement. """ n_samples = gt.shape[0] y_feats = self.extract_feats( gt) # Otherwise use the feature from there y_hat_feats = self.extract_feats(pred) y_feats = y_feats.detach() loss = 0 sim_improvement = 0 count = 0 for i in range(n_samples): diff_target = y_hat_feats[i].dot(y_feats[i]) loss += 1 - diff_target count += 1 return loss / count, sim_improvement / count ================================================ FILE: mmagic/models/editors/arcface/model_irse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from torch.nn import (BatchNorm1d, BatchNorm2d, Conv2d, Dropout, Linear, Module, PReLU, Sequential) from .arcface_modules import (Flatten, bottleneck_IR, bottleneck_IR_SE, get_blocks, l2_norm) # yapf: disable """ Modified Backbone implementation from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch) # isort:skip # noqa """ # yapf: enable class Backbone(Module): ''' Arcface backbone. There are many repos follow this codes for facial recognition, and we also follow this routine. Ref: https://github.com/orpatashnik/StyleCLIP/blob/main/models/facial_recognition/helpers.py # noqa Args: input_size (int): Input size of image. num_layers (int): Number of layer in backbone. mode (str, optional): Bottle neck mode. If set to 'ir_se', then SEModule will be applied. Defaults to 'ir'. drop_ratio (float, optional): Drop out ratio. Defaults to 0.4. affine (bool, optional): Whether use affine in BatchNorm1d. Defaults to True. ''' def __init__(self, input_size, num_layers, mode='ir', drop_ratio=0.4, affine=True): super(Backbone, self).__init__() assert input_size in [112, 224], 'input_size should be 112 or 224' assert num_layers in [50, 100, 152], 'num_layers should be 50, 100 or 152' assert mode in ['ir', 'ir_se'], 'mode should be ir or ir_se' blocks = get_blocks(num_layers) if mode == 'ir': unit_module = bottleneck_IR elif mode == 'ir_se': unit_module = bottleneck_IR_SE self.input_layer = Sequential( Conv2d(3, 64, (3, 3), 1, 1, bias=False), BatchNorm2d(64), PReLU(64)) if input_size == 112: self.output_layer = Sequential( BatchNorm2d(512), Dropout(drop_ratio), Flatten(), Linear(512 * 7 * 7, 512), BatchNorm1d(512, affine=affine)) else: self.output_layer = Sequential( BatchNorm2d(512), Dropout(drop_ratio), Flatten(), Linear(512 * 14 * 14, 512), BatchNorm1d(512, affine=affine)) modules = [] for block in blocks: for bottleneck in block: modules.append( unit_module(bottleneck.in_channel, bottleneck.depth, bottleneck.stride)) self.body = Sequential(*modules) def forward(self, x): """Forward function.""" x = self.input_layer(x) x = self.body(x) x = self.output_layer(x) return l2_norm(x) def IR_50(input_size): """Constructs a ir-50 model.""" model = Backbone( input_size, num_layers=50, mode='ir', drop_ratio=0.4, affine=False) return model def IR_101(input_size): """Constructs a ir-101 model.""" model = Backbone( input_size, num_layers=100, mode='ir', drop_ratio=0.4, affine=False) return model def IR_152(input_size): """Constructs a ir-152 model.""" model = Backbone( input_size, num_layers=152, mode='ir', drop_ratio=0.4, affine=False) return model def IR_SE_50(input_size): """Constructs a ir_se-50 model.""" model = Backbone( input_size, num_layers=50, mode='ir_se', drop_ratio=0.4, affine=False) return model def IR_SE_101(input_size): """Constructs a ir_se-101 model.""" model = Backbone( input_size, num_layers=100, mode='ir_se', drop_ratio=0.4, affine=False) return model def IR_SE_152(input_size): """Constructs a ir_se-152 model.""" model = Backbone( input_size, num_layers=152, mode='ir_se', drop_ratio=0.4, affine=False) return model ================================================ FILE: mmagic/models/editors/basicvsr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .basicvsr import BasicVSR from .basicvsr_net import BasicVSRNet __all__ = ['BasicVSR', 'BasicVSRNet'] ================================================ FILE: mmagic/models/editors/basicvsr/basicvsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models import BaseEditModel from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class BasicVSR(BaseEditModel): """BasicVSR model for video super-resolution. Note that this model is used for IconVSR. Paper: BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond, CVPR, 2021 Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. ensemble (dict): Config for ensemble. Default: None. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. """ def __init__(self, generator, pixel_loss, ensemble=None, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) # fix pre-trained networks self.fix_iter = train_cfg.get('fix_iter', 0) if train_cfg else 0 self.is_weight_fixed = False # count training steps self.register_buffer('step_counter', torch.zeros(1)) # ensemble self.forward_ensemble = None if ensemble is not None: if ensemble['type'] == 'SpatialTemporalEnsemble': from mmagic.models.archs import SpatialTemporalEnsemble is_temporal = ensemble.get('is_temporal_ensemble', False) self.forward_ensemble = SpatialTemporalEnsemble(is_temporal) else: raise NotImplementedError( 'Currently support only ' '"SpatialTemporalEnsemble", but got type ' f'[{ensemble["type"]}]') def check_if_mirror_extended(self, lrs): """Check whether the input is a mirror-extended sequence. If mirror-extended, the i-th (i=0, ..., t-1) frame is equal to the (t-1-i)-th frame. Args: lrs (tensor): Input LR images with shape (n, t, c, h, w) """ is_mirror_extended = False if lrs.size(1) % 2 == 0: lrs_1, lrs_2 = torch.chunk(lrs, 2, dim=1) if torch.norm(lrs_1 - lrs_2.flip(1)) == 0: is_mirror_extended = True return is_mirror_extended def forward_train(self, inputs, data_samples=None, **kwargs): """Forward training. Returns dict of losses of training. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ # fix SPyNet and EDVR at the beginning if self.step_counter < self.fix_iter: if not self.is_weight_fixed: self.is_weight_fixed = True for k, v in self.generator.named_parameters(): if 'spynet' in k or 'edvr' in k: v.requires_grad_(False) elif self.step_counter == self.fix_iter: # train all the parameters self.generator.requires_grad_(True) feats = self.forward_tensor(inputs, data_samples, **kwargs) batch_gt_data = data_samples.gt_img loss = self.pixel_loss(feats, batch_gt_data) self.step_counter += 1 return dict(loss=loss) def forward_inference(self, inputs, data_samples=None, **kwargs): """Forward inference. Returns predictions of validation, testing. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: DataSample: predictions. """ feats = self.forward_tensor(inputs, data_samples, **kwargs) # feats.shape = [b, t, c, h, w] feats = self.data_preprocessor.destruct(feats, data_samples) # If the GT is an image (i.e. the center frame), the output sequence is # turned to an image. gt = data_samples.gt_img[0] if gt is not None and gt.data.ndim == 3: t = feats.size(1) if self.check_if_mirror_extended(inputs): # with mirror extension feats = 0.5 * (feats[:, t // 4] + feats[:, -1 - t // 4]) else: # without mirror extension feats = feats[:, t // 2] # create a stacked data sample predictions = DataSample( pred_img=feats.cpu(), metainfo=data_samples.metainfo) return predictions ================================================ FILE: mmagic/models/editors/basicvsr/basicvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import WARNING import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine import MMLogger, print_log from mmengine.model import BaseModule from mmengine.runner import load_checkpoint from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import flow_warp, make_layer from mmagic.registry import MODELS @MODELS.register_module() class BasicVSRNet(BaseModule): """BasicVSR network structure for video super-resolution. Support only x4 upsampling. Paper: BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond, CVPR, 2021 Args: mid_channels (int): Channel number of the intermediate features. Default: 64. num_blocks (int): Number of residual blocks in each propagation branch. Default: 30. spynet_pretrained (str): Pre-trained model path of SPyNet. Default: None. """ def __init__(self, mid_channels=64, num_blocks=30, spynet_pretrained=None): super().__init__() self.mid_channels = mid_channels # optical flow network for feature alignment self.spynet = SPyNet(pretrained=spynet_pretrained) # propagation branches self.backward_resblocks = ResidualBlocksWithInputConv( mid_channels + 3, mid_channels, num_blocks) self.forward_resblocks = ResidualBlocksWithInputConv( mid_channels + 3, mid_channels, num_blocks) # upsample self.fusion = nn.Conv2d( mid_channels * 2, mid_channels, 1, 1, 0, bias=True) self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, 64, 2, upsample_kernel=3) self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1) self.conv_last = nn.Conv2d(64, 3, 3, 1, 1) self.img_upsample = nn.Upsample( scale_factor=4, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self._raised_warning = False def check_if_mirror_extended(self, lrs): """Check whether the input is a mirror-extended sequence. If mirror-extended, the i-th (i=0, ..., t-1) frame is equal to the (t-1-i)-th frame. Args: lrs (tensor): Input LR images with shape (n, t, c, h, w) """ self.is_mirror_extended = False if lrs.size(1) % 2 == 0: lrs_1, lrs_2 = torch.chunk(lrs, 2, dim=1) if torch.norm(lrs_1 - lrs_2.flip(1)) == 0: self.is_mirror_extended = True def compute_flow(self, lrs): """Compute optical flow using SPyNet for feature warping. Note that if the input is an mirror-extended sequence, 'flows_forward' is not needed, since it is equal to 'flows_backward.flip(1)'. Args: lrs (tensor): Input LR images with shape (n, t, c, h, w) Return: tuple(Tensor): Optical flow. 'flows_forward' corresponds to the flows used for forward-time propagation (current to previous). 'flows_backward' corresponds to the flows used for backward-time propagation (current to next). """ n, t, c, h, w = lrs.size() lrs_1 = lrs[:, :-1, :, :, :].reshape(-1, c, h, w) lrs_2 = lrs[:, 1:, :, :, :].reshape(-1, c, h, w) flows_backward = self.spynet(lrs_1, lrs_2).view(n, t - 1, 2, h, w) if self.is_mirror_extended: # flows_forward = flows_backward.flip(1) flows_forward = None else: flows_forward = self.spynet(lrs_2, lrs_1).view(n, t - 1, 2, h, w) return flows_forward, flows_backward def forward(self, lrs): """Forward function for BasicVSR. Args: lrs (Tensor): Input LR sequence with shape (n, t, c, h, w). Returns: Tensor: Output HR sequence with shape (n, t, c, 4h, 4w). """ n, t, c, h, w = lrs.size() if (h < 64 or w < 64) and not self._raised_warning: print_log( f'{self.__class__.__name__} is designed for input ' 'larger than 64x64, but the resolution of current image ' f'is {h}x{w}. We recommend you to check your input.', 'current', WARNING) self._raised_warning = True # check whether the input is an extended sequence self.check_if_mirror_extended(lrs) # compute optical flow flows_forward, flows_backward = self.compute_flow(lrs) # backward-time propagation outputs = [] feat_prop = lrs.new_zeros(n, self.mid_channels, h, w) for i in range(t - 1, -1, -1): if i < t - 1: # no warping required for the last timestep flow = flows_backward[:, i, :, :, :] feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1)) feat_prop = torch.cat([lrs[:, i, :, :, :], feat_prop], dim=1) feat_prop = self.backward_resblocks(feat_prop) outputs.append(feat_prop) outputs = outputs[::-1] # forward-time propagation and upsampling feat_prop = torch.zeros_like(feat_prop) for i in range(0, t): lr_curr = lrs[:, i, :, :, :] if i > 0: # no warping required for the first timestep if flows_forward is not None: flow = flows_forward[:, i - 1, :, :, :] else: flow = flows_backward[:, -i, :, :, :] feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1)) feat_prop = torch.cat([lr_curr, feat_prop], dim=1) feat_prop = self.forward_resblocks(feat_prop) # upsampling given the backward and forward features out = torch.cat([outputs[i], feat_prop], dim=1) out = self.lrelu(self.fusion(out)) out = self.lrelu(self.upsample1(out)) out = self.lrelu(self.upsample2(out)) out = self.lrelu(self.conv_hr(out)) out = self.conv_last(out) base = self.img_upsample(lr_curr) out += base outputs[i] = out return torch.stack(outputs, dim=1) class ResidualBlocksWithInputConv(BaseModule): """Residual blocks with a convolution in front. Args: in_channels (int): Number of input channels of the first conv. out_channels (int): Number of channels of the residual blocks. Default: 64. num_blocks (int): Number of residual blocks. Default: 30. """ def __init__(self, in_channels, out_channels=64, num_blocks=30): super().__init__() main = [] # a convolution used to match the channels of the residual blocks main.append(nn.Conv2d(in_channels, out_channels, 3, 1, 1, bias=True)) main.append(nn.LeakyReLU(negative_slope=0.1, inplace=True)) # residual blocks main.append( make_layer( ResidualBlockNoBN, num_blocks, mid_channels=out_channels)) self.main = nn.Sequential(*main) def forward(self, feat): """Forward function for ResidualBlocksWithInputConv. Args: feat (Tensor): Input feature with shape (n, in_channels, h, w) Returns: Tensor: Output feature with shape (n, out_channels, h, w) """ return self.main(feat) class SPyNet(BaseModule): """SPyNet network structure. The difference to the SPyNet in [tof.py] is that 1. more SPyNetBasicModule is used in this version, and 2. no batch normalization is used in this version. Paper: Optical Flow Estimation using a Spatial Pyramid Network, CVPR, 2017 Args: pretrained (str): path for pre-trained SPyNet. Default: None. """ def __init__(self, pretrained): super().__init__() self.basic_module = nn.ModuleList( [SPyNetBasicModule() for _ in range(6)]) if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=True, logger=logger) elif pretrained is not None: raise TypeError('[pretrained] should be str or None, ' f'but got {type(pretrained)}.') self.register_buffer( 'mean', torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1)) self.register_buffer( 'std', torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1)) def compute_flow(self, ref, supp): """Compute flow from ref to supp. Note that in this function, the images are already resized to a multiple of 32. Args: ref (Tensor): Reference image with shape of (n, 3, h, w). supp (Tensor): Supporting image with shape of (n, 3, h, w). Returns: Tensor: Estimated optical flow: (n, 2, h, w). """ n, _, h, w = ref.size() # normalize the input images ref = [(ref - self.mean) / self.std] supp = [(supp - self.mean) / self.std] # generate downsampled frames for level in range(5): ref.append( F.avg_pool2d( input=ref[-1], kernel_size=2, stride=2, count_include_pad=False)) supp.append( F.avg_pool2d( input=supp[-1], kernel_size=2, stride=2, count_include_pad=False)) ref = ref[::-1] supp = supp[::-1] # flow computation flow = ref[0].new_zeros(n, 2, h // 32, w // 32) for level in range(len(ref)): if level == 0: flow_up = flow else: flow_up = F.interpolate( input=flow, scale_factor=2, mode='bilinear', align_corners=True) * 2.0 # add the residue to the upsampled flow flow = flow_up + self.basic_module[level]( torch.cat([ ref[level], flow_warp( supp[level], flow_up.permute(0, 2, 3, 1), padding_mode='border'), flow_up ], 1)) return flow def forward(self, ref, supp): """Forward function of SPyNet. This function computes the optical flow from ref to supp. Args: ref (Tensor): Reference image with shape of (n, 3, h, w). supp (Tensor): Supporting image with shape of (n, 3, h, w). Returns: Tensor: Estimated optical flow: (n, 2, h, w). """ # upsize to a multiple of 32 h, w = ref.shape[2:4] w_up = w if (w % 32) == 0 else 32 * (w // 32 + 1) h_up = h if (h % 32) == 0 else 32 * (h // 32 + 1) ref = F.interpolate( input=ref, size=(h_up, w_up), mode='bilinear', align_corners=False) supp = F.interpolate( input=supp, size=(h_up, w_up), mode='bilinear', align_corners=False) # compute flow, and resize back to the original resolution flow = F.interpolate( input=self.compute_flow(ref, supp), size=(h, w), mode='bilinear', align_corners=False) # adjust the flow values flow[:, 0, :, :] *= float(w) / float(w_up) flow[:, 1, :, :] *= float(h) / float(h_up) return flow class SPyNetBasicModule(BaseModule): """Basic Module for SPyNet. Paper: Optical Flow Estimation using a Spatial Pyramid Network, CVPR, 2017 """ def __init__(self): super().__init__() self.basic_module = nn.Sequential( ConvModule( in_channels=8, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=64, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=dict(type='ReLU')), ConvModule( in_channels=64, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=16, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=dict(type='ReLU')), ConvModule( in_channels=16, out_channels=2, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=None)) def forward(self, tensor_input): """ Args: tensor_input (Tensor): Input tensor with shape (b, 8, h, w). 8 channels contain: [reference image (3), neighbor image (3), initial flow (2)]. Returns: Tensor: Refined flow with shape (b, 2, h, w) """ return self.basic_module(tensor_input) ================================================ FILE: mmagic/models/editors/basicvsr_plusplus_net/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .basicvsr_plusplus_net import BasicVSRPlusPlusNet __all__ = ['BasicVSRPlusPlusNet'] ================================================ FILE: mmagic/models/editors/basicvsr_plusplus_net/basicvsr_plusplus_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmcv.ops import ModulatedDeformConv2d, modulated_deform_conv2d from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init from mmagic.models.archs import PixelShufflePack from mmagic.models.utils import flow_warp from mmagic.registry import MODELS from ..basicvsr.basicvsr_net import ResidualBlocksWithInputConv, SPyNet @MODELS.register_module() class BasicVSRPlusPlusNet(BaseModule): """BasicVSR++ network structure. Support either x4 upsampling or same size output. Paper: BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment Args: mid_channels (int, optional): Channel number of the intermediate features. Default: 64. num_blocks (int, optional): The number of residual blocks in each propagation branch. Default: 7. max_residue_magnitude (int): The maximum magnitude of the offset residue (Eq. 6 in paper). Default: 10. is_low_res_input (bool, optional): Whether the input is low-resolution or not. If False, the output resolution is equal to the input resolution. Default: True. spynet_pretrained (str, optional): Pre-trained model path of SPyNet. Default: None. cpu_cache_length (int, optional): When the length of sequence is larger than this value, the intermediate features are sent to CPU. This saves GPU memory, but slows down the inference speed. You can increase this number if you have a GPU with large memory. Default: 100. """ def __init__(self, mid_channels=64, num_blocks=7, max_residue_magnitude=10, is_low_res_input=True, spynet_pretrained=None, cpu_cache_length=100): super().__init__() self.mid_channels = mid_channels self.is_low_res_input = is_low_res_input self.cpu_cache_length = cpu_cache_length # optical flow self.spynet = SPyNet(pretrained=spynet_pretrained) # feature extraction module if is_low_res_input: self.feat_extract = ResidualBlocksWithInputConv(3, mid_channels, 5) else: self.feat_extract = nn.Sequential( nn.Conv2d(3, mid_channels, 3, 2, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True), nn.Conv2d(mid_channels, mid_channels, 3, 2, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True), ResidualBlocksWithInputConv(mid_channels, mid_channels, 5)) # propagation branches self.deform_align = nn.ModuleDict() self.backbone = nn.ModuleDict() modules = ['backward_1', 'forward_1', 'backward_2', 'forward_2'] for i, module in enumerate(modules): self.deform_align[module] = SecondOrderDeformableAlignment( 2 * mid_channels, mid_channels, 3, padding=1, deform_groups=16, max_residue_magnitude=max_residue_magnitude) self.backbone[module] = ResidualBlocksWithInputConv( (2 + i) * mid_channels, mid_channels, num_blocks) # upsampling module self.reconstruction = ResidualBlocksWithInputConv( 5 * mid_channels, mid_channels, 5) self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, 64, 2, upsample_kernel=3) self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1) self.conv_last = nn.Conv2d(64, 3, 3, 1, 1) self.img_upsample = nn.Upsample( scale_factor=4, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) def check_if_mirror_extended(self, lqs): """Check whether the input is a mirror-extended sequence. If mirror-extended, the i-th (i=0, ..., t-1) frame is equal to the (t-1-i)-th frame. Args: lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w). """ # check if the sequence is augmented by flipping self.is_mirror_extended = False if lqs.size(1) % 2 == 0: lqs_1, lqs_2 = torch.chunk(lqs, 2, dim=1) if torch.norm(lqs_1 - lqs_2.flip(1)) == 0: self.is_mirror_extended = True def compute_flow(self, lqs): """Compute optical flow using SPyNet for feature alignment. Note that if the input is an mirror-extended sequence, 'flows_forward' is not needed, since it is equal to 'flows_backward.flip(1)'. Args: lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w). Return: tuple(Tensor): Optical flow. 'flows_forward' corresponds to the flows used for forward-time propagation (current to previous). 'flows_backward' corresponds to the flows used for backward-time propagation (current to next). """ n, t, c, h, w = lqs.size() lqs_1 = lqs[:, :-1, :, :, :].reshape(-1, c, h, w) lqs_2 = lqs[:, 1:, :, :, :].reshape(-1, c, h, w) flows_backward = self.spynet(lqs_1, lqs_2).view(n, t - 1, 2, h, w) if self.is_mirror_extended: # flows_forward = flows_backward.flip(1) flows_forward = None else: flows_forward = self.spynet(lqs_2, lqs_1).view(n, t - 1, 2, h, w) if self.cpu_cache: flows_backward = flows_backward.cpu() flows_forward = flows_forward.cpu() return flows_forward, flows_backward def propagate(self, feats, flows, module_name): """Propagate the latent features throughout the sequence. Args: feats dict(list[tensor]): Features from previous branches. Each component is a list of tensors with shape (n, c, h, w). flows (tensor): Optical flows with shape (n, t - 1, 2, h, w). module_name (str): The name of the propagation branches. Can either be 'backward_1', 'forward_1', 'backward_2', 'forward_2'. Return: dict(list[tensor]): A dictionary containing all the propagated features. Each key in the dictionary corresponds to a propagation branch, which is represented by a list of tensors. """ n, t, _, h, w = flows.size() # PyTorch 2.0 could not compile data type of 'range' # frame_idx = range(0, t + 1) # flow_idx = range(-1, t) frame_idx = list(range(0, t + 1)) flow_idx = list(range(-1, t)) mapping_idx = list(range(0, len(feats['spatial']))) mapping_idx += mapping_idx[::-1] if 'backward' in module_name: frame_idx = frame_idx[::-1] flow_idx = frame_idx feat_prop = flows.new_zeros(n, self.mid_channels, h, w) for i, idx in enumerate(frame_idx): feat_current = feats['spatial'][mapping_idx[idx]] if self.cpu_cache: feat_current = feat_current.cuda() feat_prop = feat_prop.cuda() # second-order deformable alignment if i > 0: flow_n1 = flows[:, flow_idx[i], :, :, :] if self.cpu_cache: flow_n1 = flow_n1.cuda() cond_n1 = flow_warp(feat_prop, flow_n1.permute(0, 2, 3, 1)) # initialize second-order features feat_n2 = torch.zeros_like(feat_prop) flow_n2 = torch.zeros_like(flow_n1) cond_n2 = torch.zeros_like(cond_n1) if i > 1: # second-order features feat_n2 = feats[module_name][-2] if self.cpu_cache: feat_n2 = feat_n2.cuda() flow_n2 = flows[:, flow_idx[i - 1], :, :, :] if self.cpu_cache: flow_n2 = flow_n2.cuda() flow_n2 = flow_n1 + flow_warp(flow_n2, flow_n1.permute(0, 2, 3, 1)) cond_n2 = flow_warp(feat_n2, flow_n2.permute(0, 2, 3, 1)) # flow-guided deformable convolution cond = torch.cat([cond_n1, feat_current, cond_n2], dim=1) feat_prop = torch.cat([feat_prop, feat_n2], dim=1) feat_prop = self.deform_align[module_name](feat_prop, cond, flow_n1, flow_n2) # concatenate and residual blocks feat = [feat_current] + [ feats[k][idx] for k in feats if k not in ['spatial', module_name] ] + [feat_prop] if self.cpu_cache: feat = [f.cuda() for f in feat] feat = torch.cat(feat, dim=1) feat_prop = feat_prop + self.backbone[module_name](feat) feats[module_name].append(feat_prop) if self.cpu_cache: feats[module_name][-1] = feats[module_name][-1].cpu() torch.cuda.empty_cache() if 'backward' in module_name: feats[module_name] = feats[module_name][::-1] return feats def upsample(self, lqs, feats): """Compute the output image given the features. Args: lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w). feats (dict): The features from the propagation branches. Returns: Tensor: Output HR sequence with shape (n, t, c, 4h, 4w). """ outputs = [] num_outputs = len(feats['spatial']) mapping_idx = list(range(0, num_outputs)) mapping_idx += mapping_idx[::-1] for i in range(0, lqs.size(1)): hr = [feats[k].pop(0) for k in feats if k != 'spatial'] hr.insert(0, feats['spatial'][mapping_idx[i]]) hr = torch.cat(hr, dim=1) if self.cpu_cache: hr = hr.cuda() hr = self.reconstruction(hr) hr = self.lrelu(self.upsample1(hr)) hr = self.lrelu(self.upsample2(hr)) hr = self.lrelu(self.conv_hr(hr)) hr = self.conv_last(hr) if self.is_low_res_input: hr += self.img_upsample(lqs[:, i, :, :, :]) else: hr += lqs[:, i, :, :, :] if self.cpu_cache: hr = hr.cpu() torch.cuda.empty_cache() outputs.append(hr) return torch.stack(outputs, dim=1) def forward(self, lqs): """Forward function for BasicVSR++. Args: lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w). Returns: Tensor: Output HR sequence with shape (n, t, c, 4h, 4w). """ n, t, c, h, w = lqs.size() # whether to cache the features in CPU (no effect if using CPU) if t > self.cpu_cache_length and lqs.is_cuda: self.cpu_cache = True else: self.cpu_cache = False if self.is_low_res_input: lqs_downsample = lqs.clone() else: lqs_downsample = F.interpolate( lqs.view(-1, c, h, w), scale_factor=0.25, mode='bicubic').view(n, t, c, h // 4, w // 4) # check whether the input is an extended sequence self.check_if_mirror_extended(lqs) feats = {} # compute spatial features if self.cpu_cache: feats['spatial'] = [] for i in range(0, t): feat = self.feat_extract(lqs[:, i, :, :, :]).cpu() feats['spatial'].append(feat) torch.cuda.empty_cache() else: feats_ = self.feat_extract(lqs.view(-1, c, h, w)) h, w = feats_.shape[2:] feats_ = feats_.view(n, t, -1, h, w) feats['spatial'] = [feats_[:, i, :, :, :] for i in range(0, t)] # compute optical flow using the low-res inputs assert lqs_downsample.size(3) >= 64 and lqs_downsample.size(4) >= 64, ( 'The height and width of low-res inputs must be at least 64, ' f'but got {h} and {w}.') flows_forward, flows_backward = self.compute_flow(lqs_downsample) # feature propagation for iter_ in [1, 2]: for direction in ['backward', 'forward']: module = f'{direction}_{iter_}' feats[module] = [] if direction == 'backward': flows = flows_backward elif flows_forward is not None: flows = flows_forward else: flows = flows_backward.flip(1) feats = self.propagate(feats, flows, module) if self.cpu_cache: del flows torch.cuda.empty_cache() return self.upsample(lqs, feats) class SecondOrderDeformableAlignment(ModulatedDeformConv2d): """Second-order deformable alignment module. Args: in_channels (int): Same as nn.Conv2d. out_channels (int): Same as nn.Conv2d. kernel_size (int or tuple[int]): Same as nn.Conv2d. stride (int or tuple[int]): Same as nn.Conv2d. padding (int or tuple[int]): Same as nn.Conv2d. dilation (int or tuple[int]): Same as nn.Conv2d. groups (int): Same as nn.Conv2d. bias (bool or str): If specified as `auto`, it will be decided by the norm_cfg. Bias will be set as True if norm_cfg is None, otherwise False. max_residue_magnitude (int): The maximum magnitude of the offset residue (Eq. 6 in paper). Default: 10. """ def __init__(self, *args, **kwargs): self.max_residue_magnitude = kwargs.pop('max_residue_magnitude', 10) super(SecondOrderDeformableAlignment, self).__init__(*args, **kwargs) self.conv_offset = nn.Sequential( nn.Conv2d(3 * self.out_channels + 4, self.out_channels, 3, 1, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True), nn.Conv2d(self.out_channels, self.out_channels, 3, 1, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True), nn.Conv2d(self.out_channels, self.out_channels, 3, 1, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True), nn.Conv2d(self.out_channels, 27 * self.deform_groups, 3, 1, 1), ) self.init_offset() def init_offset(self): """Init constant offset.""" constant_init(self.conv_offset[-1], val=0, bias=0) def forward(self, x, extra_feat, flow_1, flow_2): """Forward function.""" extra_feat = torch.cat([extra_feat, flow_1, flow_2], dim=1) out = self.conv_offset(extra_feat) o1, o2, mask = torch.chunk(out, 3, dim=1) # offset offset = self.max_residue_magnitude * torch.tanh( torch.cat((o1, o2), dim=1)) offset_1, offset_2 = torch.chunk(offset, 2, dim=1) offset_1 = offset_1 + flow_1.flip(1).repeat(1, offset_1.size(1) // 2, 1, 1) offset_2 = offset_2 + flow_2.flip(1).repeat(1, offset_2.size(1) // 2, 1, 1) offset = torch.cat([offset_1, offset_2], dim=1) # mask mask = torch.sigmoid(mask) return modulated_deform_conv2d(x, offset, mask, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups, self.deform_groups) ================================================ FILE: mmagic/models/editors/biggan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .biggan import BigGAN from .biggan_deep_discriminator import BigGANDeepDiscriminator from .biggan_deep_generator import BigGANDeepGenerator from .biggan_discriminator import BigGANDiscriminator from .biggan_generator import BigGANGenerator # from .generator_discriminator import BigGANDiscriminator, BigGANGenerator from .biggan_modules import (BigGANConditionBN, BigGANDeepDiscResBlock, BigGANDeepGenResBlock, BigGANDiscResBlock, BigGANGenResBlock, SelfAttentionBlock, SNConvModule) __all__ = [ 'BigGAN', 'BigGANGenerator', 'BigGANDiscriminator', 'BigGANGenResBlock', 'BigGANConditionBN', 'SelfAttentionBlock', 'BigGANDiscResBlock', 'BigGANDeepDiscriminator', 'BigGANDeepGenerator', 'BigGANDeepDiscResBlock', 'BigGANDeepGenResBlock', 'SNConvModule', ] ================================================ FILE: mmagic/models/editors/biggan/biggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import Config from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseConditionalGAN ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module() class BigGAN(BaseConditionalGAN): """Implementation of `Large Scale GAN Training for High Fidelity Natural Image Synthesis `_ (BigGAN). Detailed architecture can be found in :class:`~mmagic.models.editors.biggan.BigGANGenerator` and :class:`~mmagic.models.editors.biggan.BigGANDiscriminator` Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): Number of times the generator was completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): Number of times the discriminator was completely updated before the generator is updated. Defaults to 1. noise_size (Optional[int]): Size of the input noise vector. Default to 128. num_classes (Optional[int]): The number classes you would like to generate. Defaults to None. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, noise_size: Optional[int] = None, num_classes: Optional[int] = None, ema_config: Optional[Dict] = None): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, noise_size, num_classes, ema_config) def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: r"""Get disc loss. BigGAN use hinge loss to train the discriminator. .. math: L_{D} = -\mathbb{E}_{\left(x, y\right)\sim{p}_{data}} \left[\min\left(0, -1 + D\left(x, y\right)\right)\right] -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}}\left[\min \left(0, -1 - D\left(G\left(z\right), y\right)\right)\right] Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.relu(1 + disc_pred_fake).mean() losses_dict['loss_disc_real'] = F.relu(1 - disc_pred_real).mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake): r"""Get disc loss. BigGAN use hinge loss to train the generator. .. math: L_{G} = -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}} D\left(G\left(z\right), y\right) Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img real_labels = self.data_sample_to_label(data_samples) assert real_labels is not None, ( 'Cannot found \'gt_label\' in \'data_sample\'.') num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise=noise_batch, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) disc_pred_real = self.discriminator(real_imgs, label=real_labels) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) fake_imgs = self.generator( noise=noise, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/biggan/biggan_deep_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import mmengine import torch import torch.nn as nn from mmengine.logging import MMLogger from mmengine.model import normal_init, xavier_init from mmengine.runner import load_checkpoint from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from torch.nn.utils import spectral_norm from mmagic.registry import MODELS from .biggan_modules import SelfAttentionBlock, SNConvModule from .biggan_snmodule import SNEmbedding, SNLinear @MODELS.register_module() class BigGANDeepDiscriminator(nn.Module): """BigGAN-Deep Discriminator. The implementation refers to https://github.com/ajbrock/BigGAN-PyTorch/blob/master/BigGANdeep.py # noqa. The overall structure of BigGAN's discriminator is the same with the projection discriminator. The main difference between BigGAN and BigGAN-deep is that BigGAN-deep use more deeper residual blocks to construct the whole model. More details can be found in: Large Scale GAN Training for High Fidelity Natural Image Synthesis (ICLR2019). The design of the model structure is highly corresponding to the output resolution. For origin BigGAN-Deep's generator, you can set ``output_scale`` as you need and use the default value of ``arch_cfg`` and ``blocks_cfg``. If you want to customize the model, you can set the arguments in this way: ``arch_cfg``: Config for the architecture of this generator. You can refer the ``_default_arch_cfgs`` in the ``_get_default_arch_cfg`` function to see the format of the ``arch_cfg``. Basically, you need to provide information of each block such as the numbers of input and output channels, whether to perform upsampling etc. ``blocks_cfg``: Config for the convolution block. You can adjust block params like ``channel_ratio`` here. You can also replace the block type to your registered customized block. However, you should notice that some params are shared between these blocks like ``act_cfg``, ``with_spectral_norm``, ``sn_eps`` etc. Args: input_scale (int): The scale of the input image. num_classes (int, optional): The number of conditional classes. Defaults to 0. in_channels (int, optional): The channel number of the input image. Defaults to 3. out_channels (int, optional): The channel number of the final output. Defaults to 1. base_channels (int, optional): The basic channel number of the discriminator. The other layers contains channels based on this number. Defaults to 96. block_depth (int, optional): The repeat times of Residual Blocks in each level of architecture. Defaults to 2. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. init_type (str, optional): The name of an initialization method: ortho | N02 | xavier. Defaults to 'ortho'. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. blocks_cfg (dict, optional): Config for the convolution block. Defaults to dict(type='BigGANDiscResBlock'). arch_cfg (dict, optional): Config for the architecture of this discriminator. Defaults to None. pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ def __init__(self, input_scale, num_classes=0, in_channels=3, out_channels=1, base_channels=96, block_depth=2, sn_eps=1e-6, sn_style='ajbrock', init_type='ortho', act_cfg=dict(type='ReLU', inplace=False), with_spectral_norm=True, blocks_cfg=dict(type='BigGANDeepDiscResBlock'), arch_cfg=None, pretrained=None): super().__init__() self.num_classes = num_classes self.out_channels = out_channels self.input_scale = input_scale self.in_channels = in_channels self.base_channels = base_channels self.block_depth = block_depth self.arch = arch_cfg if arch_cfg else self._get_default_arch_cfg( self.input_scale, self.base_channels) self.blocks_cfg = deepcopy(blocks_cfg) self.blocks_cfg.update( dict( act_cfg=act_cfg, sn_eps=sn_eps, sn_style=sn_style, with_spectral_norm=with_spectral_norm)) self.input_conv = SNConvModule( 3, self.arch['in_channels'][0], kernel_size=3, padding=1, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), act_cfg=None) self.conv_blocks = nn.ModuleList() for index, out_ch in enumerate(self.arch['out_channels']): for depth in range(self.block_depth): # change args to adapt to current block block_cfg_ = deepcopy(self.blocks_cfg) block_cfg_.update( dict( in_channels=self.arch['in_channels'][index] if depth == 0 else out_ch, out_channels=out_ch, with_downsample=self.arch['downsample'][index] and depth == 0)) self.conv_blocks.append(MODELS.build(block_cfg_)) if self.arch['attention'][index]: self.conv_blocks.append( SelfAttentionBlock( out_ch, with_spectral_norm=with_spectral_norm, sn_eps=sn_eps, sn_style=sn_style)) self.activate = MODELS.build(act_cfg) self.decision = nn.Linear(self.arch['out_channels'][-1], out_channels) if with_spectral_norm: if sn_style == 'torch': self.decision = spectral_norm(self.decision, eps=sn_eps) elif sn_style == 'ajbrock': self.decision = SNLinear( self.arch['out_channels'][-1], out_channels, eps=sn_eps) else: raise NotImplementedError( f'{sn_style} style SN is not supported yet') if self.num_classes > 0: self.proj_y = nn.Embedding(self.num_classes, self.arch['out_channels'][-1]) if with_spectral_norm: if sn_style == 'torch': self.proj_y = spectral_norm(self.proj_y, eps=sn_eps) elif sn_style == 'ajbrock': self.proj_y = SNEmbedding( self.num_classes, self.arch['out_channels'][-1], eps=sn_eps) else: raise NotImplementedError( f'{sn_style} style SN is not supported yet') self.init_weights(pretrained=pretrained, init_type=init_type) def _get_default_arch_cfg(self, input_scale, base_channels): assert input_scale in [32, 64, 128, 256, 512] _default_arch_cfgs = { '32': { 'in_channels': [base_channels * item for item in [4, 4, 4]], 'out_channels': [base_channels * item for item in [4, 4, 4]], 'downsample': [True, True, False, False], 'resolution': [16, 8, 8, 8], 'attention': [False, False, False, False] }, '64': { 'in_channels': [base_channels * item for item in [1, 2, 4, 8]], 'out_channels': [base_channels * item for item in [2, 4, 8, 16]], 'downsample': [True] * 4 + [False], 'resolution': [32, 16, 8, 4, 4], 'attention': [False, False, False, False, False] }, '128': { 'in_channels': [base_channels * item for item in [1, 2, 4, 8, 16]], 'out_channels': [base_channels * item for item in [2, 4, 8, 16, 16]], 'downsample': [True] * 5 + [False], 'resolution': [64, 32, 16, 8, 4, 4], 'attention': [True, False, False, False, False, False] }, '256': { 'in_channels': [base_channels * item for item in [1, 2, 4, 8, 8, 16]], 'out_channels': [base_channels * item for item in [2, 4, 8, 8, 16, 16]], 'downsample': [True] * 6 + [False], 'resolution': [128, 64, 32, 16, 8, 4, 4], 'attention': [False, True, False, False, False, False] }, '512': { 'in_channels': [base_channels * item for item in [1, 1, 2, 4, 8, 8, 16]], 'out_channels': [base_channels * item for item in [1, 2, 4, 8, 8, 16, 16]], 'downsample': [True] * 7 + [False], 'resolution': [256, 128, 64, 32, 16, 8, 4, 4], 'attention': [False, False, False, True, False, False, False] } } return _default_arch_cfgs[str(input_scale)] def forward(self, x, label=None): """Forward function. Args: x (torch.Tensor): Fake or real image tensor. label (torch.Tensor | None): Label Tensor. Defaults to None. Returns: torch.Tensor: Prediction for the reality of the input image with given label. """ x0 = self.input_conv(x) for conv_block in self.conv_blocks: x0 = conv_block(x0) x0 = self.activate(x0) x0 = torch.sum(x0, dim=[2, 3]) out = self.decision(x0) if self.num_classes > 0: w_y = self.proj_y(label) out = out + torch.sum(w_y * x0, dim=1, keepdim=True) return out def init_weights(self, pretrained=None, init_type='ortho'): """Init weights for models. Args: pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. init_type (str, optional): The name of an initialization method: ortho | N02 | xavier. Defaults to 'ortho'. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif isinstance(pretrained, dict): ckpt_path = pretrained.get('ckpt_path', None) assert ckpt_path is not None prefix = pretrained.get('prefix', '') map_location = pretrained.get('map_location', 'cpu') strict = pretrained.get('strict', True) state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained model from {ckpt_path}') elif pretrained is None: for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): if init_type == 'ortho': nn.init.orthogonal_(m.weight) elif init_type == 'N02': normal_init(m, 0.0, 0.02) elif init_type == 'xavier': xavier_init(m) else: raise NotImplementedError( f'{init_type} initialization \ not supported now.') else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') ================================================ FILE: mmagic/models/editors/biggan/biggan_deep_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import mmengine import torch import torch.nn as nn from mmengine.logging import MMLogger from mmengine.model import normal_init, xavier_init from mmengine.runner import load_checkpoint from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from torch.nn.utils import spectral_norm from mmagic.registry import MODELS from ...utils import get_module_device from .biggan_modules import SelfAttentionBlock, SNConvModule from .biggan_snmodule import SNLinear @MODELS.register_module() class BigGANDeepGenerator(nn.Module): """BigGAN-Deep Generator. The implementation refers to https://github.com/ajbrock/BigGAN-PyTorch/blob/master/BigGANdeep.py # noqa. In BigGAN, we use a SAGAN-based architecture composing of an self-attention block and number of convolutional residual blocks with spectral normalization. BigGAN-deep follow the same architecture. The main difference between BigGAN and BigGAN-deep is that BigGAN-deep uses deeper residual blocks to construct the whole model. More details can be found in: Large Scale GAN Training for High Fidelity Natural Image Synthesis (ICLR2019). The design of the model structure is highly corresponding to the output resolution. For the original BigGAN-Deep's generator, you can set ``output_scale`` as you need and use the default value of ``arch_cfg`` and ``blocks_cfg``. If you want to customize the model, you can set the arguments in this way: ``arch_cfg``: Config for the architecture of this generator. You can refer the ``_default_arch_cfgs`` in the ``_get_default_arch_cfg`` function to see the format of the ``arch_cfg``. Basically, you need to provide information of each block such as the numbers of input and output channels, whether to perform upsampling, etc. ``blocks_cfg``: Config for the convolution block. You can adjust block params like ``channel_ratio`` here. You can also replace the block type to your registered customized block. However, you should notice that some params are shared among these blocks like ``act_cfg``, ``with_spectral_norm``, ``sn_eps``, etc. Args: output_scale (int): Output scale for the generated image. noise_size (int, optional): Size of the input noise vector. Defaults to 120. num_classes (int, optional): The number of conditional classes. If set to 0, this model will be degraded to an unconditional model. Defaults to 0. out_channels (int, optional): Number of channels in output images. Defaults to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 96. block_depth (int, optional): The repeat times of Residual Blocks in each level of architecture. Defaults to 2. input_scale (int, optional): The scale of the input 2D feature map. Defaults to 4. with_shared_embedding (bool, optional): Whether to use shared embedding. Defaults to True. shared_dim (int, optional): The output channels of shared embedding. Defaults to 128. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. init_type (str, optional): The name of an initialization method: ortho | N02 | xavier. Defaults to 'ortho'. concat_noise (bool, optional): Whether to concat input noise vector with class vector. Defaults to True. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to dict(type='nearest', scale_factor=2). with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. auto_sync_bn (bool, optional): Whether to use synchronized batch normalization. Defaults to True. blocks_cfg (dict, optional): Config for the convolution block. Defaults to dict(type='BigGANGenResBlock'). arch_cfg (dict, optional): Config for the architecture of this generator. Defaults to None. out_norm_cfg (dict, optional): Config for the norm of output layer. Defaults to dict(type='BN'). pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. rgb2bgr (bool, optional): Whether to reformat the output channels with order `bgr`. We provide several pre-trained BigGAN-Deep weights whose output channels order is `rgb`. You can set this argument to True to use the weights. """ def __init__(self, output_scale, noise_size=120, num_classes=0, out_channels=3, base_channels=96, block_depth=2, input_scale=4, with_shared_embedding=True, shared_dim=128, sn_eps=1e-6, sn_style='ajbrock', init_type='ortho', concat_noise=True, act_cfg=dict(type='ReLU', inplace=False), upsample_cfg=dict(type='nearest', scale_factor=2), with_spectral_norm=True, auto_sync_bn=True, blocks_cfg=dict(type='BigGANDeepGenResBlock'), arch_cfg=None, out_norm_cfg=dict(type='BN'), pretrained=None, rgb2bgr=False): super().__init__() self.noise_size = noise_size self.num_classes = num_classes self.shared_dim = shared_dim self.with_shared_embedding = with_shared_embedding self.output_scale = output_scale self.arch = arch_cfg if arch_cfg else self._get_default_arch_cfg( self.output_scale, base_channels) self.input_scale = input_scale self.concat_noise = concat_noise self.blocks_cfg = deepcopy(blocks_cfg) self.upsample_cfg = deepcopy(upsample_cfg) self.block_depth = block_depth self.rgb2bgr = rgb2bgr self.sn_style = sn_style # Validity Check # If 'num_classes' equals to zero, we shall set 'with_shared_embedding' # to False. if num_classes == 0: assert not self.with_shared_embedding assert not self.concat_noise elif not self.with_shared_embedding: # If not `with_shared_embedding`, we will use `nn.Embedding` to # replace the original `Linear` layer in conditional BN. # Meanwhile, we do not adopt split noises. assert not self.concat_noise # First linear layer if self.concat_noise: self.noise2feat = nn.Linear( self.noise_size + self.shared_dim, self.arch['in_channels'][0] * (self.input_scale**2)) else: self.noise2feat = nn.Linear( self.noise_size, self.arch['in_channels'][0] * (self.input_scale**2)) if with_spectral_norm: if sn_style == 'torch': self.noise2feat = spectral_norm(self.noise2feat, eps=sn_eps) elif sn_style == 'ajbrock': self.noise2feat = SNLinear( self.noise_size + (self.shared_dim if self.concat_noise else 0), self.arch['in_channels'][0] * (self.input_scale**2), eps=sn_eps) else: NotImplementedError(f'{sn_style} style SN is not supported') # If using 'shared_embedding', we will get an unified embedding of # label for all blocks. If not, we just pass the label to each # block. if with_shared_embedding: self.shared_embedding = nn.Embedding(num_classes, shared_dim) else: self.shared_embedding = nn.Identity() if num_classes > 0: if self.concat_noise: self.dim_after_concat = ( self.shared_dim + self.noise_size if self.with_shared_embedding else self.num_classes) else: self.dim_after_concat = ( self.shared_dim if self.with_shared_embedding else self.num_classes) else: self.dim_after_concat = 0 self.blocks_cfg.update( dict( dim_after_concat=self.dim_after_concat, act_cfg=act_cfg, sn_eps=sn_eps, sn_style=sn_style, input_is_label=(num_classes > 0) and (not with_shared_embedding), with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn)) self.conv_blocks = nn.ModuleList() for index, out_ch in enumerate(self.arch['out_channels']): for depth in range(self.block_depth): # change args to adapt to current block block_cfg_ = deepcopy(self.blocks_cfg) block_cfg_.update( dict( in_channels=self.arch['in_channels'][index], out_channels=out_ch if depth == (self.block_depth - 1) else self.arch['in_channels'][index], upsample_cfg=self.upsample_cfg if self.arch['upsample'][index] and depth == (self.block_depth - 1) else None)) self.conv_blocks.append(MODELS.build(block_cfg_)) if self.arch['attention'][index]: self.conv_blocks.append( SelfAttentionBlock( out_ch, with_spectral_norm=with_spectral_norm, sn_eps=sn_eps, sn_style=sn_style)) self.output_layer = SNConvModule( self.arch['out_channels'][-1], out_channels, kernel_size=3, padding=1, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), act_cfg=act_cfg, norm_cfg=out_norm_cfg, bias=True, order=('norm', 'act', 'conv')) self.init_weights(pretrained=pretrained, init_type=init_type) def _get_default_arch_cfg(self, output_scale, base_channels): assert output_scale in [32, 64, 128, 256, 512] _default_arch_cfgs = { '32': { 'in_channels': [base_channels * item for item in [4, 4, 4]], 'out_channels': [base_channels * item for item in [4, 4, 4]], 'upsample': [True] * 3, 'resolution': [8, 16, 32], 'attention': [False, False, False] }, '64': { 'in_channels': [base_channels * item for item in [16, 16, 8, 4]], 'out_channels': [base_channels * item for item in [16, 8, 4, 2]], 'upsample': [True] * 4, 'resolution': [8, 16, 32, 64], 'attention': [False, False, False, True] }, '128': { 'in_channels': [base_channels * item for item in [16, 16, 8, 4, 2]], 'out_channels': [base_channels * item for item in [16, 8, 4, 2, 1]], 'upsample': [True] * 5, 'resolution': [8, 16, 32, 64, 128], 'attention': [False, False, False, True, False] }, '256': { 'in_channels': [base_channels * item for item in [16, 16, 8, 8, 4, 2]], 'out_channels': [base_channels * item for item in [16, 8, 8, 4, 2, 1]], 'upsample': [True] * 6, 'resolution': [8, 16, 32, 64, 128, 256], 'attention': [False, False, False, True, False, False] }, '512': { 'in_channels': [base_channels * item for item in [16, 16, 8, 8, 4, 2, 1]], 'out_channels': [base_channels * item for item in [16, 8, 8, 4, 2, 1, 1]], 'upsample': [True] * 7, 'resolution': [8, 16, 32, 64, 128, 256, 512], 'attention': [False, False, False, True, False, False, False] } } return _default_arch_cfgs[str(output_scale)] def forward(self, noise, label=None, num_batches=0, return_noise=False, truncation=-1.0, use_outside_embedding=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. label (torch.Tensor | callable | None): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` and ``label`` will be returned in a dict with ``fake_img``. Defaults to False. truncation (float, optional): Truncation factor. Give value not less than 0., the truncation trick will be adopted. Otherwise, the truncation trick will not be adopted. Defaults to -1.. use_outside_embedding (bool, optional): Whether to use outside embedding or use `shared_embedding`. Set to `True` if embedding has already be performed outside this function. Default to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img``, ``noise_batch`` and ``label`` will be returned. """ if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size)) # perform truncation if truncation >= 0.0: noise_batch = torch.clamp(noise_batch, -1. * truncation, 1. * truncation) if self.num_classes == 0: label_batch = None elif isinstance(label, torch.Tensor): if not use_outside_embedding: assert label.ndim == 1, ( 'The label should be in shape of (n, )' f'but got {label.shape}.') label_batch = label elif callable(label): label_generator = label assert num_batches > 0 label_batch = label_generator((num_batches, )) else: assert num_batches > 0 label_batch = torch.randint(0, self.num_classes, (num_batches, )) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) if label_batch is not None: label_batch = label_batch.to(get_module_device(self)) if not use_outside_embedding: class_vector = self.shared_embedding(label_batch) else: class_vector = label_batch else: class_vector = None # If 'concat noise', concat class vector and noise batch if self.concat_noise: if class_vector is not None: z = torch.cat([noise_batch, class_vector], dim=1) y = z elif self.num_classes > 0: z = noise_batch y = class_vector else: z = noise_batch y = None # First linear layer x = self.noise2feat(z) # Reshape # We use this conversion step to allow for loading TF weights # TF convention on shape is [batch, height, width, channels] # PT convention on shape is [batch, channels, height, width] x = x.view(x.size(0), self.input_scale, self.input_scale, -1) x = x.permute(0, 3, 1, 2).contiguous() # Loop over blocks for idx, conv_block in enumerate(self.conv_blocks): if isinstance(conv_block, SelfAttentionBlock): x = conv_block(x) else: x = conv_block(x, y) # Apply batchnorm-relu-conv-tanh at output x = self.output_layer(x) out_img = torch.tanh(x) if self.rgb2bgr: out_img = out_img[:, [2, 1, 0], ...] if return_noise: output = dict( fake_img=out_img, noise_batch=noise_batch, label=label_batch) return output return out_img def init_weights(self, pretrained=None, init_type='ortho'): """Init weights for models. Args: pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. init_type (str, optional): The name of an initialization method: ortho | N02 | xavier. Defaults to 'ortho'. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif isinstance(pretrained, dict): ckpt_path = pretrained.get('ckpt_path', None) assert ckpt_path is not None prefix = pretrained.get('prefix', '') map_location = pretrained.get('map_location', 'cpu') strict = pretrained.get('strict', True) state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained model from {ckpt_path}') elif pretrained is None: for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): if init_type == 'ortho': nn.init.orthogonal_(m.weight) elif init_type == 'N02': normal_init(m, 0.0, 0.02) elif init_type == 'xavier': xavier_init(m) else: raise NotImplementedError( f'{init_type} initialization \ not supported now.') else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') ================================================ FILE: mmagic/models/editors/biggan/biggan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch import torch.nn as nn from mmengine.model import (BaseModule, normal_init, update_init_info, xavier_init) from torch.nn.utils import spectral_norm from mmagic.registry import MODELS from .biggan_modules import SelfAttentionBlock from .biggan_snmodule import SNEmbedding, SNLinear @MODELS.register_module() class BigGANDiscriminator(BaseModule): """BigGAN Discriminator. The implementation refers to https://github.com/ajbrock/BigGAN-PyTorch/blob/master/BigGAN.py # noqa. In BigGAN, we use a SAGAN-based architecture composing of an self-attention block and number of convolutional residual blocks with spectral normalization. More details can be found in: Large Scale GAN Training for High Fidelity Natural Image Synthesis (ICLR2019). The design of the model structure is highly corresponding to the output resolution. For the original BigGAN's generator, you can set ``output_scale`` as you need and use the default value of ``arch_cfg`` and ``blocks_cfg``. If you want to customize the model, you can set the arguments in this way: ``arch_cfg``: Config for the architecture of this generator. You can refer the ``_default_arch_cfgs`` in the ``_get_default_arch_cfg`` function to see the format of the ``arch_cfg``. Basically, you need to provide information of each block such as the numbers of input and output channels, whether to perform upsampling, etc. ``blocks_cfg``: Config for the convolution block. You can replace the block type to your registered customized block and adjust block params here. However, you should notice that some params are shared among these blocks like ``act_cfg``, ``with_spectral_norm``, ``sn_eps``, etc. Args: input_scale (int): The scale of the input image. num_classes (int, optional): The number of conditional classes. Defaults to 0. in_channels (int, optional): The channel number of the input image. Defaults to 3. out_channels (int, optional): The channel number of the final output. Defaults to 1. base_channels (int, optional): The basic channel number of the discriminator. The other layers contains channels based on this number. Defaults to 96. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. blocks_cfg (dict, optional): Config for the convolution block. Defaults to dict(type='BigGANDiscResBlock'). arch_cfg (dict, optional): Config for the architecture of this discriminator. Defaults to None. init_cfg (dict, optional): Initialization config dict. If type is `Pretrained`, the pretrain model will be loaded. Otherwise, type will be parsed as the name of initialization method. Support values are 'ortho', 'N02', 'xavier'. Defaults to dict(type='ortho'). """ def __init__(self, input_scale, num_classes=0, in_channels=3, out_channels=1, base_channels=96, sn_eps=1e-6, sn_style='ajbrock', act_cfg=dict(type='ReLU'), with_spectral_norm=True, blocks_cfg=dict(type='BigGANDiscResBlock'), arch_cfg=None, init_cfg=dict(type='ortho')): super().__init__(init_cfg=init_cfg) self.num_classes = num_classes self.out_channels = out_channels self.input_scale = input_scale self.in_channels = in_channels self.base_channels = base_channels self.arch = arch_cfg if arch_cfg else self._get_default_arch_cfg( self.input_scale, self.in_channels, self.base_channels) self.blocks_cfg = deepcopy(blocks_cfg) self.blocks_cfg.update( dict( act_cfg=act_cfg, sn_eps=sn_eps, sn_style=sn_style, with_spectral_norm=with_spectral_norm)) self.sn_style = sn_style self.conv_blocks = nn.ModuleList() for index, out_ch in enumerate(self.arch['out_channels']): # change args to adapt to current block self.blocks_cfg.update( dict( in_channels=self.arch['in_channels'][index], out_channels=out_ch, with_downsample=self.arch['downsample'][index], is_head_block=(index == 0))) self.conv_blocks.append(MODELS.build(self.blocks_cfg)) if self.arch['attention'][index]: self.conv_blocks.append( SelfAttentionBlock( out_ch, with_spectral_norm=with_spectral_norm, sn_eps=sn_eps, sn_style=sn_style)) self.activate = MODELS.build(act_cfg) self.decision = nn.Linear(self.arch['out_channels'][-1], out_channels) if with_spectral_norm: if sn_style == 'torch': self.decision = spectral_norm(self.decision, eps=sn_eps) elif sn_style == 'ajbrock': self.decision = SNLinear( self.arch['out_channels'][-1], out_channels, eps=sn_eps) else: raise NotImplementedError('sn style') if self.num_classes > 0: self.proj_y = nn.Embedding(self.num_classes, self.arch['out_channels'][-1]) if with_spectral_norm: if sn_style == 'torch': self.proj_y = spectral_norm(self.proj_y, eps=sn_eps) elif sn_style == 'ajbrock': self.proj_y = SNEmbedding( self.num_classes, self.arch['out_channels'][-1], eps=sn_eps) else: raise NotImplementedError('sn style') def _get_default_arch_cfg(self, input_scale, in_channels, base_channels): assert input_scale in [32, 64, 128, 256, 512] _default_arch_cfgs = { '32': { 'in_channels': [in_channels] + [base_channels * item for item in [4, 4, 4]], 'out_channels': [base_channels * item for item in [4, 4, 4, 4]], 'downsample': [True, True, False, False], 'resolution': [16, 8, 8, 8], 'attention': [False, False, False, False] }, '64': { 'in_channels': [in_channels] + [base_channels * item for item in [1, 2, 4, 8]], 'out_channels': [base_channels * item for item in [1, 2, 4, 8, 16]], 'downsample': [True] * 4 + [False], 'resolution': [32, 16, 8, 4, 4], 'attention': [False, False, False, False, False] }, '128': { 'in_channels': [in_channels] + [base_channels * item for item in [1, 2, 4, 8, 16]], 'out_channels': [base_channels * item for item in [1, 2, 4, 8, 16, 16]], 'downsample': [True] * 5 + [False], 'resolution': [64, 32, 16, 8, 4, 4], 'attention': [True, False, False, False, False, False] }, '256': { 'in_channels': [in_channels] + [base_channels * item for item in [1, 2, 4, 8, 8, 16]], 'out_channels': [base_channels * item for item in [1, 2, 4, 8, 8, 16, 16]], 'downsample': [True] * 6 + [False], 'resolution': [128, 64, 32, 16, 8, 4, 4], 'attention': [False, True, False, False, False, False] }, '512': { 'in_channels': [in_channels] + [base_channels * item for item in [1, 1, 2, 4, 8, 8, 16]], 'out_channels': [base_channels * item for item in [1, 1, 2, 4, 8, 8, 16, 16]], 'downsample': [True] * 7 + [False], 'resolution': [256, 128, 64, 32, 16, 8, 4, 4], 'attention': [False, False, False, True, False, False, False] } } return _default_arch_cfgs[str(input_scale)] def forward(self, x, label=None): """Forward function. Args: x (torch.Tensor): Fake or real image tensor. label (torch.Tensor | None): Label Tensor. Defaults to None. Returns: torch.Tensor: Prediction for the reality of the input image with given label. """ x0 = x for conv_block in self.conv_blocks: x0 = conv_block(x0) x0 = self.activate(x0) x0 = torch.sum(x0, dim=[2, 3]) out = self.decision(x0) if self.num_classes > 0: w_y = self.proj_y(label) out = out + torch.sum(w_y * x0, dim=1, keepdim=True) return out def init_weights(self): """Init weights for models.""" if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return for m in self.modules(): init_type = self.init_cfg['type'] module_name = m.__class__.__name__ if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): if init_type == 'ortho': nn.init.orthogonal_(m.weight) elif init_type == 'N02': normal_init(m, 0.0, 0.02) elif init_type == 'xavier': xavier_init(m) else: raise NotImplementedError( f'{init_type} initialization not supported now.') # save init info init_info = (f'{module_name} belongs to (nn.Conv2d, ' 'nn.Linear, nn.Embedding), initialize by ' f'\'init_type\' {init_type}') if hasattr(m, '_params_init_info'): update_init_info(m, init_info) self._is_init = True ================================================ FILE: mmagic/models/editors/biggan/biggan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch import torch.nn as nn from mmengine.model import (BaseModule, normal_init, update_init_info, xavier_init) from torch.nn.utils import spectral_norm from mmagic.registry import MODELS from ...utils import get_module_device from .biggan_modules import SelfAttentionBlock, SNConvModule from .biggan_snmodule import SNLinear @MODELS.register_module() class BigGANGenerator(BaseModule): """BigGAN Generator. The implementation refers to https://github.com/ajbrock/BigGAN-PyTorch/blob/master/BigGAN.py # noqa. In BigGAN, we use a SAGAN-based architecture composing of an self-attention block and number of convolutional residual blocks with spectral normalization. More details can be found in: Large Scale GAN Training for High Fidelity Natural Image Synthesis (ICLR2019). The design of the model structure is highly corresponding to the output resolution. For the original BigGAN's generator, you can set ``output_scale`` as you need and use the default value of ``arch_cfg`` and ``blocks_cfg``. If you want to customize the model, you can set the arguments in this way: ``arch_cfg``: Config for the architecture of this generator. You can refer the ``_default_arch_cfgs`` in the ``_get_default_arch_cfg`` function to see the format of the ``arch_cfg``. Basically, you need to provide information of each block such as the numbers of input and output channels, whether to perform upsampling, etc. ``blocks_cfg``: Config for the convolution block. You can replace the block type to your registered customized block and adjust block params here. However, you should notice that some params are shared among these blocks like ``act_cfg``, ``with_spectral_norm``, ``sn_eps``, etc. Args: output_scale (int): Output scale for the generated image. noise_size (int, optional): Size of the input noise vector. Defaults to 120. num_classes (int, optional): The number of conditional classes. If set to 0, this model will be degraded to an unconditional model. Defaults to 0. out_channels (int, optional): Number of channels in output images. Defaults to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 96. input_scale (int, optional): The scale of the input 2D feature map. Defaults to 4. with_shared_embedding (bool, optional): Whether to use shared embedding. Defaults to True. shared_dim (int, optional): The output channels of shared embedding. Defaults to 128. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. split_noise (bool, optional): Whether to split input noise vector. Defaults to True. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to dict(type='nearest', scale_factor=2). with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. auto_sync_bn (bool, optional): Whether to use synchronized batch normalization. Defaults to True. blocks_cfg (dict, optional): Config for the convolution block. Defaults to dict(type='BigGANGenResBlock'). arch_cfg (dict, optional): Config for the architecture of this generator. Defaults to None. out_norm_cfg (dict, optional): Config for the norm of output layer. Defaults to dict(type='BN'). rgb2bgr (bool, optional): Whether to reformat the output channels with order `bgr`. We provide several pre-trained BigGAN weights whose output channels order is `rgb`. You can set this argument to True to use the weights. init_cfg (dict, optional): Initialization config dict. If type is `Pretrained`, the pretrain model will be loaded. Otherwise, type will be parsed as the name of initialization method. Support values are 'ortho', 'N02', 'xavier'. Defaults to dict(type='ortho'). """ def __init__(self, output_scale, noise_size=120, num_classes=0, out_channels=3, base_channels=96, input_scale=4, with_shared_embedding=True, shared_dim=128, sn_eps=1e-6, sn_style='ajbrock', split_noise=True, act_cfg=dict(type='ReLU'), upsample_cfg=dict(type='nearest', scale_factor=2), with_spectral_norm=True, auto_sync_bn=True, blocks_cfg=dict(type='BigGANGenResBlock'), arch_cfg=None, out_norm_cfg=dict(type='BN'), rgb2bgr=False, init_cfg=dict(type='ortho')): super().__init__(init_cfg=init_cfg) self.noise_size = noise_size self.num_classes = num_classes self.shared_dim = shared_dim self.with_shared_embedding = with_shared_embedding self.output_scale = output_scale self.arch = arch_cfg if arch_cfg else self._get_default_arch_cfg( self.output_scale, base_channels) self.input_scale = input_scale self.split_noise = split_noise self.blocks_cfg = deepcopy(blocks_cfg) self.upsample_cfg = deepcopy(upsample_cfg) self.rgb2bgr = rgb2bgr self.sn_style = sn_style # Validity Check # If 'num_classes' equals to zero, we shall set 'with_shared_embedding' # to False. if num_classes == 0: assert not self.with_shared_embedding else: if not self.with_shared_embedding: # If not `with_shared_embedding`, we will use `nn.Embedding` to # replace the original `Linear` layer in conditional BN. # Meanwhile, we do not adopt split noises. assert not self.split_noise # If using split latents, we may need to adjust noise_size if self.split_noise: # Number of places z slots into self.num_slots = len(self.arch['in_channels']) + 1 self.noise_chunk_size = self.noise_size // self.num_slots # Recalculate latent dimensionality for even splitting into chunks self.noise_size = self.noise_chunk_size * self.num_slots else: self.num_slots = 1 self.noise_chunk_size = 0 # First linear layer self.noise2feat = nn.Linear( self.noise_size // self.num_slots, self.arch['in_channels'][0] * (self.input_scale**2)) if with_spectral_norm: if sn_style == 'torch': self.noise2feat = spectral_norm(self.noise2feat, eps=sn_eps) elif sn_style == 'ajbrock': self.noise2feat = SNLinear( self.noise_size // self.num_slots, self.arch['in_channels'][0] * (self.input_scale**2), eps=sn_eps) else: raise NotImplementedError(f'Your {sn_style} is not supported') # If using 'shared_embedding', we will get an unified embedding of # label for all blocks. If not, we just pass the label to each # block. if with_shared_embedding: self.shared_embedding = nn.Embedding(num_classes, shared_dim) else: self.shared_embedding = nn.Identity() if num_classes > 0: self.dim_after_concat = ( self.shared_dim + self.noise_chunk_size if self.with_shared_embedding else self.num_classes) else: self.dim_after_concat = self.noise_chunk_size self.blocks_cfg.update( dict( dim_after_concat=self.dim_after_concat, act_cfg=act_cfg, sn_eps=sn_eps, sn_style=sn_style, input_is_label=(num_classes > 0) and (not with_shared_embedding), with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn)) self.conv_blocks = nn.ModuleList() for index, out_ch in enumerate(self.arch['out_channels']): # change args to adapt to current block self.blocks_cfg.update( dict( in_channels=self.arch['in_channels'][index], out_channels=out_ch, upsample_cfg=self.upsample_cfg if self.arch['upsample'][index] else None)) self.conv_blocks.append(MODELS.build(self.blocks_cfg)) if self.arch['attention'][index]: self.conv_blocks.append( SelfAttentionBlock( out_ch, with_spectral_norm=with_spectral_norm, sn_eps=sn_eps, sn_style=sn_style)) self.output_layer = SNConvModule( self.arch['out_channels'][-1], out_channels, kernel_size=3, padding=1, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), act_cfg=act_cfg, norm_cfg=out_norm_cfg, bias=True, order=('norm', 'act', 'conv')) def _get_default_arch_cfg(self, output_scale, base_channels): assert output_scale in [32, 64, 128, 256, 512] _default_arch_cfgs = { '32': { 'in_channels': [base_channels * item for item in [4, 4, 4]], 'out_channels': [base_channels * item for item in [4, 4, 4]], 'upsample': [True] * 3, 'resolution': [8, 16, 32], 'attention': [False, False, False] }, '64': { 'in_channels': [base_channels * item for item in [16, 16, 8, 4]], 'out_channels': [base_channels * item for item in [16, 8, 4, 2]], 'upsample': [True] * 4, 'resolution': [8, 16, 32, 64], 'attention': [False, False, False, True] }, '128': { 'in_channels': [base_channels * item for item in [16, 16, 8, 4, 2]], 'out_channels': [base_channels * item for item in [16, 8, 4, 2, 1]], 'upsample': [True] * 5, 'resolution': [8, 16, 32, 64, 128], 'attention': [False, False, False, True, False] }, '256': { 'in_channels': [base_channels * item for item in [16, 16, 8, 8, 4, 2]], 'out_channels': [base_channels * item for item in [16, 8, 8, 4, 2, 1]], 'upsample': [True] * 6, 'resolution': [8, 16, 32, 64, 128, 256], 'attention': [False, False, False, True, False, False] }, '512': { 'in_channels': [base_channels * item for item in [16, 16, 8, 8, 4, 2, 1]], 'out_channels': [base_channels * item for item in [16, 8, 8, 4, 2, 1, 1]], 'upsample': [True] * 7, 'resolution': [8, 16, 32, 64, 128, 256, 512], 'attention': [False, False, False, True, False, False, False] } } return _default_arch_cfgs[str(output_scale)] def forward(self, noise, label=None, num_batches=0, return_noise=False, truncation=-1.0, use_outside_embedding=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. label (torch.Tensor | callable | None): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` and ``label`` will be returned in a dict with ``fake_img``. Defaults to False. truncation (float, optional): Truncation factor. Give value not less than 0., the truncation trick will be adopted. Otherwise, the truncation trick will not be adopted. Defaults to -1.. use_outside_embedding (bool, optional): Whether to use outside embedding or use `shared_embedding`. Set to `True` if embedding has already be performed outside this function. Default to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img``, ``noise_batch`` and ``label`` will be returned. """ if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size)) # perform truncation if truncation >= 0.0: noise_batch = torch.clamp(noise_batch, -1. * truncation, 1. * truncation) if self.num_classes == 0: label_batch = None elif isinstance(label, torch.Tensor): if not use_outside_embedding: if label.ndim != 1: assert all([s == 1 for s in label.shape[1:]]) label = label.view(-1) assert label.ndim == 1, ( 'The label should be in shape of (n, )' f'but got {label.shape}.') label_batch = label elif callable(label): label_generator = label assert num_batches > 0 label_batch = label_generator((num_batches, )) else: assert num_batches > 0 label_batch = torch.randint(0, self.num_classes, (num_batches, )) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) if label_batch is not None: label_batch = label_batch.to(get_module_device(self)) if not use_outside_embedding: class_vector = self.shared_embedding(label_batch) else: class_vector = label_batch else: class_vector = None # If 'split noise', concat class vector and noise chunk if self.split_noise: zs = torch.split(noise_batch, self.noise_chunk_size, dim=1) z = zs[0] if class_vector is not None: ys = [torch.cat([class_vector, item], 1) for item in zs[1:]] else: ys = zs[1:] else: ys = [class_vector] * len(self.conv_blocks) z = noise_batch # First linear layer x = self.noise2feat(z) # Reshape x = x.view(x.size(0), -1, self.input_scale, self.input_scale) # Loop over blocks counter = 0 for conv_block in self.conv_blocks: if isinstance(conv_block, SelfAttentionBlock): x = conv_block(x) else: x = conv_block(x, ys[counter]) counter += 1 # Apply batchnorm-relu-conv-tanh at output out_img = torch.tanh(self.output_layer(x)) if self.rgb2bgr: out_img = out_img[:, [2, 1, 0], ...] if return_noise: output = dict( fake_img=out_img, noise_batch=noise_batch, label=label_batch) return output return out_img def init_weights(self): """Init weights for models.""" if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return for m in self.modules(): init_type = self.init_cfg['type'] module_name = m.__class__.__name__ if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): if init_type == 'ortho': nn.init.orthogonal_(m.weight) elif init_type == 'N02': normal_init(m, 0.0, 0.02) elif init_type == 'xavier': xavier_init(m) else: raise NotImplementedError( f'{init_type} initialization not supported now.') # save init info init_info = (f'{module_name} belongs to (nn.Conv2d, ' 'nn.Linear, nn.Embedding), initialize by ' f'\'init_type\' {init_type}') if hasattr(m, '_params_init_info'): update_init_info(m, init_info) self._is_init = True ================================================ FILE: mmagic/models/editors/biggan/biggan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from torch.nn import Parameter from torch.nn.modules.batchnorm import SyncBatchNorm from torch.nn.utils import spectral_norm from mmagic.registry import MODELS from .biggan_snmodule import SNConv2d, SNLinear class SNConvModule(ConvModule): """Spectral Normalization ConvModule. In this module, we inherit default ``mmcv.cnn.ConvModule`` and adopt spectral normalization. The spectral normalization is proposed in: Spectral Normalization for Generative Adversarial Networks. Args: with_spectral_norm (bool, optional): Whether to use Spectral Normalization. Defaults to False. spectral_norm_cfg (dict, optional): Config for Spectral Normalization. Defaults to None. """ def __init__(self, *args, with_spectral_norm=False, spectral_norm_cfg=None, **kwargs): super().__init__(*args, with_spectral_norm=False, **kwargs) self.with_spectral_norm = with_spectral_norm self.spectral_norm_cfg = deepcopy( spectral_norm_cfg) if spectral_norm_cfg else dict() self.sn_eps = self.spectral_norm_cfg.get('eps', 1e-6) self.sn_style = self.spectral_norm_cfg.get('sn_style', 'torch') if self.with_spectral_norm: if self.sn_style == 'torch': self.conv = spectral_norm(self.conv, eps=self.sn_eps) elif self.sn_style == 'ajbrock': self.snconv_kwargs = deepcopy(kwargs) if kwargs else dict() if 'act_cfg' in self.snconv_kwargs.keys(): self.snconv_kwargs.pop('act_cfg') if 'norm_cfg' in self.snconv_kwargs.keys(): self.snconv_kwargs.pop('norm_cfg') if 'order' in self.snconv_kwargs.keys(): self.snconv_kwargs.pop('order') self.conv = SNConv2d( *args, **self.snconv_kwargs, eps=self.sn_eps) else: raise NotImplementedError( f'{self.sn_style} style spectral Norm is not supported yet' ) @MODELS.register_module() class BigGANGenResBlock(nn.Module): """Residual block used in BigGAN's generator. Args: in_channels (int): The channel number of the input feature map. out_channels (int): The channel number of the output feature map. dim_after_concat (int): The channel number of the noise concatenated with the class vector. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to dict(type='nearest', scale_factor=2). sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. with_spectral_norm (bool, optional): Whether to use spectral normalization in this block. Defaults to True. input_is_label (bool, optional): Whether the input of BNs' linear layer is raw label instead of class vector. Defaults to False. auto_sync_bn (bool, optional): Whether to use synchronized batch normalization. Defaults to True. """ def __init__(self, in_channels, out_channels, dim_after_concat, act_cfg=dict(type='ReLU'), upsample_cfg=dict(type='nearest', scale_factor=2), sn_eps=1e-6, sn_style='ajbrock', with_spectral_norm=True, input_is_label=False, auto_sync_bn=True): super().__init__() self.activation = MODELS.build(act_cfg) self.upsample_cfg = deepcopy(upsample_cfg) self.with_upsample = upsample_cfg is not None if self.with_upsample: self.upsample_layer = MODELS.build(self.upsample_cfg) self.learnable_sc = in_channels != out_channels or self.with_upsample if self.learnable_sc: self.shortcut = SNConvModule( in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) # Here in_channels of BigGANGenResBlock equal to num_features of # BigGANConditionBN self.bn1 = BigGANConditionBN( in_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) # Here out_channels of BigGANGenResBlock equal to num_features of # BigGANConditionBN self.bn2 = BigGANConditionBN( out_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) self.conv1 = SNConvModule( in_channels=in_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv2 = SNConvModule( in_channels=out_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) def forward(self, x, y): """Forward function. Args: x (torch.Tensor): Input feature map tensor. y (torch.Tensor): Label tensor or class embedding concatenated with noise tensor. Returns: torch.Tensor: Output feature map tensor. """ x0 = self.bn1(x, y) x0 = self.activation(x0) if self.with_upsample: x0 = self.upsample_layer(x0) x = self.upsample_layer(x) x0 = self.conv1(x0) x0 = self.bn2(x0, y) x0 = self.activation(x0) x0 = self.conv2(x0) if self.learnable_sc: x = self.shortcut(x) return x0 + x @MODELS.register_module() class BigGANConditionBN(nn.Module): """Conditional Batch Normalization used in BigGAN. Args: num_features (int): The channel number of the input feature map tensor. linear_input_channels (int): The channel number of the linear layers' input tensor. bn_eps (float, optional): Epsilon value for batch normalization. Defaults to 1e-5. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. momentum (float, optional): The value used for the running_mean and running_var computation. Defaults to 0.1. input_is_label (bool, optional): Whether the input of BNs' linear layer is raw label instead of class vector. Defaults to False. with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. auto_sync_bn (bool, optional): Whether to use synchronized batch normalization. Defaults to True. """ def __init__(self, num_features, linear_input_channels, bn_eps=1e-5, sn_eps=1e-6, sn_style='ajbrock', momentum=0.1, input_is_label=False, with_spectral_norm=True, auto_sync_bn=True): super().__init__() assert num_features > 0 if linear_input_channels > 0: self.use_cbn = True else: self.use_cbn = False # Prepare gain and bias layers if self.use_cbn: if not input_is_label: self.gain = nn.Linear( linear_input_channels, num_features, bias=False) self.bias = nn.Linear( linear_input_channels, num_features, bias=False) # please pay attention if shared_embedding is False if with_spectral_norm: if sn_style == 'torch': self.gain = spectral_norm(self.gain, eps=sn_eps) self.bias = spectral_norm(self.bias, eps=sn_eps) elif sn_style == 'ajbrock': self.gain = SNLinear( linear_input_channels, num_features, bias=False, eps=sn_eps) self.bias = SNLinear( linear_input_channels, num_features, bias=False, eps=sn_eps) else: raise NotImplementedError('sn style') else: self.gain = nn.Embedding(linear_input_channels, num_features) self.bias = nn.Embedding(linear_input_channels, num_features) self.bn = nn.BatchNorm2d( num_features, eps=bn_eps, momentum=momentum, affine=not self.use_cbn) if auto_sync_bn and dist.is_initialized(): self.bn = SyncBatchNorm.convert_sync_batchnorm(self.bn) def forward(self, x, y): """Forward function. Args: x (torch.Tensor): Input feature map tensor. y (torch.Tensor): Label tensor or class embedding concatenated with noise tensor. Returns: torch.Tensor: Output feature map tensor. """ if self.use_cbn: # Calculate class-conditional gains and biases gain = (1. + self.gain(y)).view(y.size(0), -1, 1, 1) bias = self.bias(y).view(y.size(0), -1, 1, 1) out = self.bn(x) out = out * gain + bias else: out = self.bn(x) return out @MODELS.register_module() class SelfAttentionBlock(nn.Module): """Self-Attention block used in BigGAN. Args: in_channels (int): The channel number of the input feature map. with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. """ def __init__(self, in_channels, with_spectral_norm=True, sn_eps=1e-6, sn_style='ajbrock'): super(SelfAttentionBlock, self).__init__() self.in_channels = in_channels self.theta = SNConvModule( self.in_channels, self.in_channels // 8, kernel_size=1, padding=0, bias=False, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.phi = SNConvModule( self.in_channels, self.in_channels // 8, kernel_size=1, padding=0, bias=False, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.g = SNConvModule( self.in_channels, self.in_channels // 2, kernel_size=1, padding=0, bias=False, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.o = SNConvModule( self.in_channels // 2, self.in_channels, kernel_size=1, padding=0, bias=False, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) # Learnable gain parameter self.gamma = Parameter(torch.tensor(0.), requires_grad=True) def forward(self, x): """Forward function. Args: x (torch.Tensor): Input feature map tensor. Returns: torch.Tensor: Output feature map tensor. """ # Apply convs theta = self.theta(x) phi = F.max_pool2d(self.phi(x), [2, 2]) g = F.max_pool2d(self.g(x), [2, 2]) # Perform reshapes theta = theta.view(-1, self.in_channels // 8, x.shape[2] * x.shape[3]) phi = phi.view(-1, self.in_channels // 8, x.shape[2] * x.shape[3] // 4) g = g.view(-1, self.in_channels // 2, x.shape[2] * x.shape[3] // 4) # Matmul and softmax to get attention maps beta = F.softmax(torch.bmm(theta.transpose(1, 2), phi), -1) # Attention map times g path o = self.o( torch.bmm(g, beta.transpose(1, 2)).view(-1, self.in_channels // 2, x.shape[2], x.shape[3])) return self.gamma * o + x @MODELS.register_module() class BigGANDiscResBlock(nn.Module): """Residual block used in BigGAN's discriminator. Args: in_channels (int): The channel number of the input tensor. out_channels (int): The channel number of the output tensor. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU', inplace=False). sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. with_downsample (bool, optional): Whether to use downsampling in this block. Defaults to True. with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. is_head_block (bool, optional): Whether this block is the first block of BigGAN. Defaults to False. """ def __init__(self, in_channels, out_channels, act_cfg=dict(type='ReLU', inplace=False), sn_eps=1e-6, sn_style='ajbrock', with_downsample=True, with_spectral_norm=True, is_head_block=False): super().__init__() self.activation = MODELS.build(act_cfg) self.with_downsample = with_downsample self.is_head_block = is_head_block if self.with_downsample: self.downsample = nn.AvgPool2d(kernel_size=2, stride=2) self.learnable_sc = in_channels != out_channels or self.with_downsample if self.learnable_sc: self.shortcut = SNConvModule( in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv1 = SNConvModule( in_channels=in_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv2 = SNConvModule( in_channels=out_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) def forward_sc(self, x): """Forward function of shortcut. Args: x (torch.Tensor): Input feature map tensor. Returns: torch.Tensor: Output tensor of shortcut. """ if self.is_head_block: if self.with_downsample: x = self.downsample(x) if self.learnable_sc: x = self.shortcut(x) else: if self.learnable_sc: x = self.shortcut(x) if self.with_downsample: x = self.downsample(x) return x def forward(self, x): """Forward function. Args: x (torch.Tensor): Input feature map tensor. Returns: torch.Tensor: Output feature map tensor. """ if self.is_head_block: x0 = x else: x0 = self.activation(x) x0 = self.conv1(x0) x0 = self.activation(x0) x0 = self.conv2(x0) if self.with_downsample: x0 = self.downsample(x0) x1 = self.forward_sc(x) return x0 + x1 @MODELS.register_module() class BigGANDeepGenResBlock(nn.Module): """Residual block used in BigGAN-Deep's generator. Args: in_channels (int): The channel number of the input feature map. out_channels (int): The channel number of the output feature map. dim_after_concat (int): The channel number of the noise concatenated with the class vector. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to dict(type='nearest', scale_factor=2). sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. bn_eps (float, optional): Epsilon value for batch normalization. Defaults to 1e-5. with_spectral_norm (bool, optional): Whether to use spectral normalization in this block. Defaults to True. input_is_label (bool, optional): Whether the input of BNs' linear layer is raw label instead of class vector. Defaults to False. auto_sync_bn (bool, optional): Whether to use synchronized batch normalization. Defaults to True. channel_ratio (int, optional): The ratio of the input channels' number to the hidden channels' number. Defaults to 4. """ def __init__(self, in_channels, out_channels, dim_after_concat, act_cfg=dict(type='ReLU'), upsample_cfg=dict(type='nearest', scale_factor=2), sn_eps=1e-6, sn_style='ajbrock', bn_eps=1e-5, with_spectral_norm=True, input_is_label=False, auto_sync_bn=True, channel_ratio=4): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.hidden_channels = self.in_channels // channel_ratio self.activation = MODELS.build(act_cfg) self.upsample_cfg = deepcopy(upsample_cfg) self.with_upsample = upsample_cfg is not None if self.with_upsample: self.upsample_layer = MODELS.build(self.upsample_cfg) # Here in_channels of BigGANGenResBlock equal to num_features of # BigGANConditionBN self.bn1 = BigGANConditionBN( in_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, bn_eps=bn_eps, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) # Here out_channels of BigGANGenResBlock equal to num_features of # BigGANConditionBN self.bn2 = BigGANConditionBN( self.hidden_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, bn_eps=bn_eps, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) self.bn3 = BigGANConditionBN( self.hidden_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, bn_eps=bn_eps, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) self.bn4 = BigGANConditionBN( self.hidden_channels, dim_after_concat, sn_eps=sn_eps, sn_style=sn_style, bn_eps=bn_eps, input_is_label=input_is_label, with_spectral_norm=with_spectral_norm, auto_sync_bn=auto_sync_bn) self.conv1 = SNConvModule( in_channels=in_channels, out_channels=self.hidden_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv2 = SNConvModule( in_channels=self.hidden_channels, out_channels=self.hidden_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv3 = SNConvModule( in_channels=self.hidden_channels, out_channels=self.hidden_channels, kernel_size=3, stride=1, padding=1, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv4 = SNConvModule( in_channels=self.hidden_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) def forward(self, x, y): """Forward function. Args: x (torch.Tensor): Input feature map tensor. y (torch.Tensor): Label tensor or class embedding concatenated with noise tensor. Returns: torch.Tensor: Output feature map tensor. """ x0 = self.bn1(x, y) x0 = self.activation(x0) x0 = self.conv1(x0) x0 = self.bn2(x0, y) x0 = self.activation(x0) # Drop channels in x if necessary if self.in_channels != self.out_channels: x = x[:, :self.out_channels] # upsample both h and x at this point if self.with_upsample: x0 = self.upsample_layer(x0) x = self.upsample_layer(x) x0 = self.conv2(x0) x0 = self.bn3(x0, y) x0 = self.activation(x0) x0 = self.conv3(x0) x0 = self.bn4(x0, y) x0 = self.activation(x0) x0 = self.conv4(x0) return x0 + x @MODELS.register_module() class BigGANDeepDiscResBlock(nn.Module): """Residual block used in BigGAN-Deep's discriminator. Args: in_channels (int): The channel number of the input tensor. out_channels (int): The channel number of the output tensor. channel_ratio (int, optional): The ratio of the input channels' number to the hidden channels' number. Defaults to 4. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU', inplace=False). sn_eps (float, optional): Epsilon value for spectral normalization. Defaults to 1e-6. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `ajbrock`. with_downsample (bool, optional): Whether to use downsampling in this block. Defaults to True. with_spectral_norm (bool, optional): Whether to use spectral normalization. Defaults to True. """ def __init__(self, in_channels, out_channels, channel_ratio=4, act_cfg=dict(type='ReLU', inplace=False), sn_eps=1e-6, sn_style='ajbrock', with_downsample=True, with_spectral_norm=True): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.hidden_channels = self.out_channels // channel_ratio self.activation = MODELS.build(act_cfg) self.with_downsample = with_downsample if self.with_downsample: self.downsample = nn.AvgPool2d(kernel_size=2, stride=2) self.learnable_sc = (in_channels != out_channels) if self.learnable_sc: self.shortcut = SNConvModule( in_channels=in_channels, out_channels=out_channels - in_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) self.conv1 = SNConvModule( in_channels=in_channels, out_channels=self.hidden_channels, kernel_size=1, stride=1, padding=0, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), order=('act', 'conv', 'norm')) self.conv2 = SNConvModule( in_channels=self.hidden_channels, out_channels=self.hidden_channels, kernel_size=3, stride=1, padding=1, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), order=('act', 'conv', 'norm')) self.conv3 = SNConvModule( in_channels=self.hidden_channels, out_channels=self.hidden_channels, kernel_size=3, stride=1, padding=1, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style), order=('act', 'conv', 'norm')) self.conv4 = SNConvModule( in_channels=self.hidden_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=dict(eps=sn_eps, sn_style=sn_style)) def forward_sc(self, x): """Forward function of shortcut. Args: x (torch.Tensor): Input feature map tensor. Returns: torch.Tensor: Output tensor of shortcut. """ if self.with_downsample: x = self.downsample(x) if self.learnable_sc: x0 = self.shortcut(x) x = torch.cat([x, x0], dim=1) return x def forward(self, x): """Forward function. Args: x (torch.Tensor): Input feature map tensor. Returns: torch.Tensor: Output feature map tensor. """ x0 = self.conv1(x) x0 = self.conv2(x0) x0 = self.conv3(x0) x0 = self.activation(x0) # downsample if self.with_downsample: x0 = self.downsample(x0) x0 = self.conv4(x0) x1 = self.forward_sc(x) return x0 + x1 ================================================ FILE: mmagic/models/editors/biggan/biggan_snmodule.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F # yapf:disable ''' Ref: Functions in this file are borrowed from https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py # noqa ''' # yapf:enable def proj(x, y): """Calculate Projection of x onto y. Args: x (torch.Tensor): Projection vector x. y (torch.Tensor): Direction vector y. Returns: torch.Tensor: Projection of x onto y. """ return torch.mm(y, x.t()) * y / torch.mm(y, y.t()) def gram_schmidt(x, ys): """Orthogonalize x w.r.t list of vectors ys. Args: x (torch.Tensor): Vector to be added into the orthogonal vectors. ys (list[torch.Tensor]): A set of orthogonal vectors. Returns: torch.Tensor: Result of Gram–Schmidt orthogonalization. """ for y in ys: x = x - proj(x, y) return x @torch.no_grad() def power_iteration(weight, u_list, update=True, eps=1e-12): """Power iteration method for calculating spectral norm. Args: weight (torch.Tensor): Module weight. u_list (list[torch.Tensor]): list of left singular vector. The length of list equals to the simulation times. update (bool, optional): Whether update left singular vector. Defaults to True. eps (float, optional): Vector Normalization epsilon. Defaults to 1e-12. Returns: tuple[list[tensor.Tensor]]: Tuple consist of three lists which contain singular values, left singular vector and right singular vector respectively. """ us, vs, svs = [], [], [] for i, u in enumerate(u_list): v = torch.matmul(u, weight) v = F.normalize(gram_schmidt(v, vs), eps=eps) vs += [v] u = torch.matmul(v, weight.t()) u = F.normalize(gram_schmidt(u, us), eps=eps) us += [u] if update: u_list[i][:] = u svs += [ torch.squeeze(torch.matmul(torch.matmul(v, weight.t()), u.t())) ] return svs, us, vs class SpectralNorm(object): """Spectral normalization base class. Args: num_svs (int): Number of singular values. num_iters (int): Number of power iterations per step. num_outputs (int): Number of output channels. transpose (bool, optional): If set to `True`, weight matrix will be transposed before power iteration. Defaults to False. eps (float, optional): Vector Normalization epsilon for avoiding divide by zero. Defaults to 1e-12. """ def __init__(self, num_svs, num_iters, num_outputs, transpose=False, eps=1e-12): self.num_iters = num_iters self.num_svs = num_svs self.transpose = transpose self.eps = eps # Register a singular vector for each sv for i in range(self.num_svs): self.register_buffer('u%d' % i, torch.randn(1, num_outputs)) self.register_buffer('sv%d' % i, torch.ones(1)) @property def u(self): """Get left singular vectors.""" return [getattr(self, 'u%d' % i) for i in range(self.num_svs)] @property def sv(self): """Get singular values.""" return [getattr(self, 'sv%d' % i) for i in range(self.num_svs)] def sn_weight(self): """Compute the spectrally-normalized weight.""" W_mat = self.weight.view(self.weight.size(0), -1) if self.transpose: W_mat = W_mat.t() # Apply num_iters power iterations for _ in range(self.num_iters): svs, us, vs = power_iteration( W_mat, self.u, update=self.training, eps=self.eps) # Update the svs if self.training: with torch.no_grad(): for i, sv in enumerate(svs): self.sv[i][:] = sv return self.weight / svs[-1] class SNConv2d(nn.Conv2d, SpectralNorm): """2D Conv layer with spectral norm. Args: in_channels (int): Number of channels in the input feature map. out_channels (int): Number of channels produced by the convolution. kernel_size (int): Size of the convolving kernel. stride (int, optional): Stride of the convolution.. Defaults to 1. padding (int, optional): Zero-padding added to both sides of the input. Defaults to 0. dilation (int, optional): Spacing between kernel elements. Defaults to 1. groups (int, optional): Number of blocked connections from input channels to output channels. Defaults to 1. bias (bool, optional): Whether to use bias parameter. Defaults to True. num_svs (int): Number of singular values. num_iters (int): Number of power iterations per step. eps (float, optional): Vector Normalization epsilon for avoiding divide by zero. Defaults to 1e-12. """ def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, num_svs=1, num_iters=1, eps=1e-12): nn.Conv2d.__init__(self, in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) SpectralNorm.__init__(self, num_svs, num_iters, out_channels, eps=eps) def forward(self, x): """Forward function.""" return F.conv2d(x, self.sn_weight(), self.bias, self.stride, self.padding, self.dilation, self.groups) class SNLinear(nn.Linear, SpectralNorm): """Linear layer with spectral norm. Args: in_features (int): Number of channels in the input feature. out_features (int): Number of channels in the out feature. bias (bool, optional): Whether to use bias parameter. Defaults to True. num_svs (int): Number of singular values. num_iters (int): Number of power iterations per step. eps (float, optional): Vector Normalization epsilon for avoiding divide by zero. Defaults to 1e-12. """ def __init__(self, in_features, out_features, bias=True, num_svs=1, num_iters=1, eps=1e-12): nn.Linear.__init__(self, in_features, out_features, bias) SpectralNorm.__init__(self, num_svs, num_iters, out_features, eps=eps) def forward(self, x): """Forward function.""" return F.linear(x, self.sn_weight(), self.bias) # We use num_embeddings as the dim instead of embedding_dim here # for convenience sake class SNEmbedding(nn.Embedding, SpectralNorm): """Embedding layer with spectral norm. Args: num_embeddings (int): Size of the dictionary of embeddings. embedding_dim (int): The size of each embedding vector. padding_idx (int, optional): If specified, the entries at padding_idx do not contribute to the gradient; therefore, the embedding vector at padding_idx is not updated during training, i.e. it remains as a fixed “pad”. For a newly constructed Embedding, the embedding vector at padding_idx will default to all zeros, but can be updated to another value to be used as the padding vector. Defaults to None. max_norm (float, optional): If given, each embedding vector with norm larger than max_norm is renormalized to have norm max_norm. Defaults to None. norm_type (int, optional): The p of the p-norm to compute for the max_norm option. Default 2. scale_grad_by_freq (bool, optional): If given, this will scale gradients by the inverse of frequency of the words in the mini-batch. Default False. sparse (bool, optional): If True, gradient w.r.t. weight matrix will be a sparse tensor. See Notes for more details regarding sparse gradients. Defaults to False. _weight (torch.Tensor, optional): Initial Weight. Defaults to None. num_svs (int): Number of singular values. num_iters (int): Number of power iterations per step. eps (float, optional): Vector Normalization epsilon for avoiding divide by zero. Defaults to 1e-12. """ def __init__(self, num_embeddings, embedding_dim, padding_idx=None, max_norm=None, norm_type=2, scale_grad_by_freq=False, sparse=False, _weight=None, num_svs=1, num_iters=1, eps=1e-12): nn.Embedding.__init__(self, num_embeddings, embedding_dim, padding_idx, max_norm, norm_type, scale_grad_by_freq, sparse, _weight) SpectralNorm.__init__( self, num_svs, num_iters, num_embeddings, eps=eps) def forward(self, x): """Forward function.""" return F.embedding(x, self.sn_weight()) ================================================ FILE: mmagic/models/editors/cain/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .cain import CAIN from .cain_net import CAINNet __all__ = [ 'CAIN', 'CAINNet', ] ================================================ FILE: mmagic/models/editors/cain/cain.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models.base_models import BasicInterpolator from mmagic.registry import MODELS @MODELS.register_module() class CAIN(BasicInterpolator): """CAIN model for Video Interpolation. Paper: Channel Attention Is All You Need for Video Frame Interpolation Ref repo: https://github.com/myungsub/CAIN Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. required_frames (int): Required frames in each process. Default: 2 step_frames (int): Step size of video frame interpolation. Default: 1 init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. """ def forward_inference(self, inputs, data_samples=None): """Forward inference. Returns predictions of validation, testing, and simple inference. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: List[DataSample]: predictions. """ predictions = super().forward_inference( inputs, data_samples, padding_flag=True) return predictions ================================================ FILE: mmagic/models/editors/cain/cain_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.models.archs import pixel_unshuffle from mmagic.models.utils import make_layer from mmagic.registry import MODELS @MODELS.register_module() class CAINNet(BaseModule): """CAIN network structure. Paper: Channel Attention Is All You Need for Video Frame Interpolation. Ref repo: https://github.com/myungsub/CAIN Args: in_channels (int): Channel number of inputs. Default: 3. kernel_size (int): Kernel size of CAINNet. Default: 3. num_block_groups (int): Number of block groups. Default: 5. num_block_layers (int): Number of blocks in a group. Default: 12. depth (int): Down scale depth, scale = 2**depth. Default: 3. reduction (int): Channel reduction of CA. Default: 16. norm (str | None): Normalization layer. If it is None, no normalization is performed. Default: None. padding (int): Padding of CAINNet. Default: 7. act (function): activate function. Default: nn.LeakyReLU(0.2, True). init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels=3, kernel_size=3, num_block_groups=5, num_block_layers=12, depth=3, reduction=16, norm=None, padding=7, act=nn.LeakyReLU(0.2, True), init_cfg=None): super().__init__(init_cfg=init_cfg) mid_channels = in_channels * (4**depth) self.scale = 2**depth self.padding = padding self.conv_first = nn.Conv2d(mid_channels * 2, mid_channels, kernel_size, 1, 1) self.body = make_layer( ResidualGroup, num_block_groups, block_layer=ResidualChannelAttention, num_block_layers=num_block_layers, mid_channels=mid_channels, kernel_size=kernel_size, reduction=reduction, norm=norm, act=act) self.conv_last = nn.Conv2d(mid_channels, mid_channels, kernel_size, 1, 1) def forward(self, imgs, padding_flag=False): """Forward function. Args: imgs (Tensor): Input tensor with shape (n, 2, c, h, w). padding_flag (bool): Padding or not. Default: False. Returns: Tensor: Forward results. """ assert imgs.shape[1] == 2 x1, x2 = imgs[:, 0], imgs[:, 1] mean1 = x1.mean((2, 3), keepdim=True) mean2 = x2.mean((2, 3), keepdim=True) x1 -= mean1 x2 -= mean2 if padding_flag: padding_function, depadding_function = get_padding_functions( x1, self.padding) x1 = padding_function(x1) x2 = padding_function(x2) x1 = pixel_unshuffle(x1, self.scale) x2 = pixel_unshuffle(x2, self.scale) x = torch.cat([x1, x2], dim=1) x = self.conv_first(x) res = self.body(x) res += x x = self.conv_last(res) x = F.pixel_shuffle(x, self.scale) if padding_flag: x = depadding_function(x) x += (mean1 + mean2) / 2 return x def get_padding_functions(x, padding=7): """Generate padding function for CAIN. This function produces two functions to pad and depad a tensor, given the number of pixels to be padded. When applying padding and depadding sequentially, the original tensor is obtained. The generated padding function will pad the given tensor to the 'padding' power of 2, i.e., pow(2, 'padding'). tensor --padding_function--> padded tensor padded tensor --depadding_function--> original tensor Args: x (Tensor): Input tensor. padding (int): Padding size. Default: 7. Returns: padding_function (Function): Padding function. depadding_function (Function): Depadding function. """ h, w = x.shape[-2:] padding_width, padding_height = 0, 0 if w != ((w >> padding) << padding): padding_width = (((w >> padding) + 1) << padding) - w if h != ((h >> padding) << padding): padding_height = (((h >> padding) + 1) << padding) - h left, right = padding_width // 2, padding_width - padding_width // 2 up, down = padding_height // 2, padding_height - padding_height // 2 if down >= h or right >= w: function = nn.ReplicationPad2d else: function = nn.ReflectionPad2d padding_function = function(padding=[left, right, up, down]) depadding_function = function( padding=[0 - left, 0 - right, 0 - up, 0 - down]) return padding_function, depadding_function class ConvNormWithReflectionPad(BaseModule): """Apply reflection padding, followed by a convolution, which can be followed by an optional normalization. Args: in_channels (int): Channel number of input features. out_channels (int): Channel number of output features. kernel_size (int): Kernel size of convolution layer. norm (str | None): Normalization layer. If it is None, no normalization is performed. Default: None. """ def __init__(self, in_channels, out_channels, kernel_size, norm=None): super().__init__() self.reflection_pad = nn.ReflectionPad2d(kernel_size // 2) self.conv = nn.Conv2d( in_channels, out_channels, kernel_size=kernel_size, bias=True) if norm is None: self.norm = None elif norm.lower() == 'in': self.norm = nn.InstanceNorm2d( out_channels, track_running_stats=True) elif norm.lower() == 'bn': self.norm = nn.BatchNorm2d(out_channels) else: raise ValueError(f"Invalid value for 'norm': {norm}") def forward(self, x): """Forward function for ConvNormWithReflectionPad. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Output tensor with shape (n, c, h, w). """ out = self.reflection_pad(x) out = self.conv(out) if self.norm: out = self.norm(out) return out class ChannelAttentionLayer(BaseModule): """Channel Attention (CA) Layer. Args: mid_channels (int): Channel number of the intermediate features. reduction (int): Channel reduction of CA. Default: 16. """ def __init__(self, mid_channels, reduction=16): super().__init__() # global average pooling: (n, c, h, w) --> (n, c, 1, 1) self.avg_pool = nn.AdaptiveAvgPool2d(1) # channel reduction. self.channel_attention = nn.Sequential( nn.Conv2d( mid_channels, mid_channels // reduction, 1, padding=0, bias=True), nn.ReLU(inplace=True), nn.Conv2d( mid_channels // reduction, mid_channels, 1, padding=0, bias=True), nn.Sigmoid()) def forward(self, x): """Forward function for ChannelAttentionLayer. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Output tensor with shape (n, c, h, w). """ y = self.avg_pool(x) y = self.channel_attention(y) return x * y class ResidualChannelAttention(BaseModule): """Residual Channel Attention Module. Args: mid_channels (int): Channel number of the intermediate features. kernel_size (int): Kernel size of convolution layers. Default: 3. reduction (int): Channel reduction. Default: 16. norm (None | function): Norm layer. If None, no norm layer. Default: None. act (function): activation function. Default: nn.LeakyReLU(0.2, True). """ def __init__(self, mid_channels, kernel_size=3, reduction=16, norm=None, act=nn.LeakyReLU(0.2, True)): super().__init__() self.body = nn.Sequential( ConvNormWithReflectionPad( mid_channels, mid_channels, kernel_size, norm=norm), act, ConvNormWithReflectionPad( mid_channels, mid_channels, kernel_size, norm=norm), ChannelAttentionLayer(mid_channels, reduction)) def forward(self, x): """Forward function for ResidualChannelAttention. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Output tensor with shape (n, c, h, w). """ out = self.body(x) return out + x class ResidualGroup(BaseModule): """Residual Group, consisting of a stack of residual channel attention, followed by a convolution. Args: block_layer (nn.Module): nn.Module class for basic block. num_block_layers (int): number of blocks. mid_channels (int): Channel number of the intermediate features. kernel_size (int): Kernel size of ResidualGroup. reduction (int): Channel reduction of CA. Default: 16. act (function): activation function. Default: nn.LeakyReLU(0.2, True). norm (str | None): Normalization layer. If it is None, no normalization is performed. Default: None. """ def __init__(self, block_layer, num_block_layers, mid_channels, kernel_size, reduction, act=nn.LeakyReLU(0.2, True), norm=None): super().__init__() self.body = make_layer( block_layer, num_block_layers, mid_channels=mid_channels, kernel_size=kernel_size, reduction=reduction, norm=norm, act=act) self.conv_after_body = ConvNormWithReflectionPad( mid_channels, mid_channels, kernel_size, norm=norm) def forward(self, x): """Forward function for ResidualGroup. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Output tensor with shape (n, c, h, w). """ y = self.body(x) y = self.conv_after_body(y) return x + y ================================================ FILE: mmagic/models/editors/controlnet/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .controlnet import ControlStableDiffusion from .controlnet_utils import change_base_model __all__ = ['ControlStableDiffusion', 'change_base_model'] ================================================ FILE: mmagic/models/editors/controlnet/controlnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import WARNING from typing import Dict, List, Optional, Tuple, Union import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from mmengine.model import is_model_wrapper from mmengine.optim import OptimWrapperDict from PIL import Image from torch import Tensor from tqdm import tqdm from mmagic.models.archs import AttentionInjection from mmagic.models.utils import build_module from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ..stable_diffusion import StableDiffusion from .controlnet_utils import change_base_model ModelType = Union[Dict, nn.Module] @MODELS.register_module() class ControlStableDiffusion(StableDiffusion): """Implementation of `ControlNet with Stable Diffusion. `_ (ControlNet). Args: vae (Union[dict, nn.Module]): The config or module for VAE model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. tokenizer (str): The **name** for CLIP tokenizer. unet (Union[dict, nn.Module]): The config or module for Unet model. controlnet (Union[dict, nn.Module]): The config or module for ControlNet. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. dtype (str, optional): The dtype for the model. Defaults to 'fp16'. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise # noqa Defaults to 0. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Defaults to dict(type='DataPreprocessor'). init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Defaults to None/ """ def __init__(self, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, controlnet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: str = 'fp32', enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor=dict(type='DataPreprocessor'), init_cfg: Optional[dict] = None, attention_injection=False): super().__init__(vae, text_encoder, tokenizer, unet, scheduler, test_scheduler, dtype, enable_xformers, noise_offset_weight, tomesd_cfg, data_preprocessor, init_cfg) default_args = dict() if dtype is not None: default_args['dtype'] = dtype # NOTE: initialize controlnet as fp32 self.controlnet = build_module(controlnet, MODELS) self._controlnet_ori_dtype = next(self.controlnet.parameters()).dtype print_log( 'Set ControlNetModel dtype to ' f'\'{self._controlnet_ori_dtype}\'.', 'current') self.set_xformers(self.controlnet) self.vae.requires_grad_(False) self.text_encoder.requires_grad_(False) self.unet.requires_grad_(False) if attention_injection: self.unet = AttentionInjection(self.unet) def init_weights(self): """Initialize the weights. Noted that this function will only be called at train. If you want to inference with a different unet model, you can call this function manually or use `mmagic.models.editors.controlnet.controlnet_utils.change_base_model` to convert the weight of ControlNet manually. Example: >>> 1. init controlnet from unet >>> init_cfg = dict(type='init_from_unet') >>> 2. switch controlnet weight from unet >>> # base model is not defined, use `runwayml/stable-diffusion-v1-5` >>> # as default >>> init_cfg = dict(type='convert_from_unet') >>> # base model is defined >>> init_cfg = dict( >>> type='convert_from_unet', >>> base_model=dict( >>> type='UNet2DConditionModel', >>> from_pretrained='REPO_ID', >>> subfolder='unet')) """ if self.init_cfg is not None: init_type = self.init_cfg.get('type', None) else: init_type = None if init_type == 'init_from_unet': # fetch module if is_model_wrapper(self.controlnet): controlnet = self.controlnet.module else: controlnet = self.controlnet if is_model_wrapper(self.unet): unet = self.unet.module else: unet = self.unet if controlnet._from_pretrained is not None: print_log( 'ControlNet has initialized from pretrained ' f'weight \'{controlnet._from_pretrained}\'.' ' Re-initialize ControlNet from Unet.', 'current', WARNING) # copy weight log_template = 'Initialize weight ControlNet from Unet: {}' for n, p in unet.named_parameters(): if n in controlnet.state_dict(): print_log(log_template.format(n), 'current') controlnet.state_dict()[n].copy_(p.data) # check zero_conv zero_conv_blocks = controlnet.controlnet_down_blocks for n, p in zero_conv_blocks.named_parameters(): if not (p == 0).all(): print_log(f'{n} in ControlNet is not initialized with ' 'zero. Set to zero manually.') p.data.zero_() elif init_type == 'convert_from_unet': # fetch module if is_model_wrapper(self.controlnet): controlnet = self.controlnet.module else: controlnet = self.controlnet if is_model_wrapper(self.unet): unet = self.unet.module else: unet = self.unet # use sd-v15 as base model by default base_model_default_cfg = dict( type='UNet2DConditionModel', from_pretrained='runwayml/stable-diffusion-v1-5', subfolder='unet') base_model_cfg = self.init_cfg.get('base_model', base_model_default_cfg) base_model = MODELS.build(base_model_cfg) change_base_model(controlnet, unet, base_model) else: assert init_type is None, ( 'Only support \'init_from_unet\', \'convert_from_unet\' or ' f'None. But receive {init_type}.') def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: """Train step for ControlNet model. Args: data (dict): Data sampled from dataloader. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] optimizer = optim_wrapper['controlnet'] with optimizer.optim_context(self.controlnet): target = inputs['target'] control = (inputs['source'] + 1) / 2 # [-1, 1] -> [0, 1] prompt = data_samples.prompt num_batches = target.shape[0] target = target.to(self.dtype) latents = self.vae.encode(target).latent_dist.sample() latents = latents * self.vae.config.scaling_factor noise = torch.randn_like(latents) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) input_ids = self.tokenizer( prompt, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) encoder_hidden_states = self.text_encoder(input_ids)[0] if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') # forward control # NOTE: we train controlnet in fp32, convert to float manually down_block_res_samples, mid_block_res_sample = self.controlnet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float(), controlnet_cond=control.float(), return_dict=False, ) # Predict the noise residual and compute loss # NOTE: we train unet in fp32, convert to float manually model_output = self.unet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float(), down_block_additional_residuals=down_block_res_samples, mid_block_additional_residual=mid_block_res_sample) model_pred = model_output['sample'] loss = F.mse_loss(model_pred.float(), gt.float(), reduction='mean') optimizer.update_params(loss) return dict(loss=loss) def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) prompt = data['data_samples'].prompt control = data['inputs']['source'] output = self.infer( prompt, control=((control + 1) / 2), return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct( samples, data['data_samples'], key='target') control = self.data_preprocessor.destruct( control, data['data_samples'], key='source') data_sample = DataSample( fake_img=samples, control=control, prompt=data['data_samples'].prompt) data_sample_list = data_sample.split() return data_sample_list def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) prompt = data['data_samples'].prompt control = data['inputs']['source'] output = self.infer( prompt, control=((control + 1) / 2), return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct( samples, data['data_samples'], key='target') control = self.data_preprocessor.destruct( control, data['data_samples'], key='source') data_sample = DataSample( fake_img=samples, control=control, prompt=data['data_samples'].prompt) data_sample_list = data_sample.split() return data_sample_list # NOTE: maybe we should do this in a controlnet preprocessor @staticmethod def prepare_control(image: Tuple[Image.Image, List[Image.Image], Tensor, List[Tensor]], width: int, height: int, batch_size: int, num_images_per_prompt: int, device: str, dtype: str) -> Tensor: """A helper function to prepare single control images. Args: image (Tuple[Image.Image, List[Image.Image], Tensor, List[Tensor]]): # noqa The input image for control. batch_size (int): The number of the prompt. The control will be repeated for `batch_size` times. num_images_per_prompt (int): The number images generate for one prompt. device (str): The device of the control. dtype (str): The dtype of the control. Returns: Tensor: The control in torch.tensor. """ if not isinstance(image, torch.Tensor): if isinstance(image, Image.Image): image = [image] if isinstance(image[0], Image.Image): image = [ img.resize((width, height), resample=Image.LANCZOS) for img in image ] image = [np.array(img)[None, :] for img in image] image = np.concatenate(image, axis=0) image = np.array(image).astype(np.float32) / 255.0 image = image.transpose(0, 3, 1, 2) image = torch.from_numpy(image) elif isinstance(image[0], torch.Tensor): image = torch.cat(image, dim=0) image_batch_size = image.shape[0] if image_batch_size == 1: repeat_by = batch_size * num_images_per_prompt else: assert image_batch_size == batch_size, ( 'The number of Control condition must be 1 or equal to the ' 'number of prompt.') # image batch size is the same as prompt batch size repeat_by = num_images_per_prompt image = image.repeat_interleave(repeat_by, dim=0) image = image.to(device=device, dtype=dtype) return image def train(self, mode: bool = True): """Set train/eval mode. Args: mode (bool, optional): Whether set train mode. Defaults to True. """ if mode: if next(self.controlnet.parameters() ).dtype != self._controlnet_ori_dtype: print_log( 'Set ControlNetModel dtype to ' f'\'{self._controlnet_ori_dtype}\' in the train mode.', 'current') self.controlnet.to(self._controlnet_ori_dtype) else: self.controlnet.to(self.dtype) print_log( f'Set ControlNetModel dtype to \'{self.dtype}\' ' 'in the eval mode.', 'current') return super().train(mode) @torch.no_grad() def infer(self, prompt: Union[str, List[str]], height: Optional[int] = None, width: Optional[int] = None, control: Optional[Union[str, np.ndarray, torch.Tensor]] = None, controlnet_conditioning_scale: float = 1.0, num_inference_steps: int = 20, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, return_type='image', show_progress=True): """Function invoked when calling the pipeline for generation. Args: prompt (str or List[str]): The prompt or prompts to guide the image generation. height (int, Optional): The height in pixels of the generated image. If not passed, the height will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. width (int, Optional): The width in pixels of the generated image. If not passed, the width will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. num_inference_steps (int): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. Defaults to 50. guidance_scale (float): Guidance scale as defined in Classifier- Free Diffusion Guidance (https://arxiv.org/abs/2207.12598). Defaults to 7.5 negative_prompt (str or List[str], optional): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than 1). Defaults to None. num_images_per_prompt (int): The number of images to generate per prompt. Defaults to 1. eta (float): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to DDIMScheduler, will be ignored for others. Defaults to 0.0. generator (torch.Generator, optional): A torch generator to make generation deterministic. Defaults to None. latents (torch.FloatTensor, optional): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. Defaults to None. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images and Control image. """ assert return_type in ['image', 'tensor', 'numpy'] # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 img_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype if is_model_wrapper(self.controlnet): control_dtype = self.controlnet.module.dtype else: control_dtype = self.controlnet.dtype controls = self.prepare_control( control, width, height, batch_size, num_images_per_prompt, device, dtype=control_dtype) if do_classifier_free_guidance: controls = torch.cat([controls] * 2) # 3. Encode input prompt text_embeddings = self._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) # 4. Prepare timesteps # self.scheduler.set_timesteps(num_inference_steps, device=device) self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare latent variables num_channels_latents = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, text_embeddings.dtype, device, generator, latents, ) # 6. Prepare extra step kwargs. extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) latent_model_input = latent_model_input.to(control_dtype) text_embeddings = text_embeddings.to(control_dtype) down_block_res_samples, mid_block_res_sample = self.controlnet( latent_model_input, t, encoder_hidden_states=text_embeddings, controlnet_cond=controls, return_dict=False, ) down_block_res_samples = [ down_block_res_sample * controlnet_conditioning_scale for down_block_res_sample in down_block_res_samples ] mid_block_res_sample *= controlnet_conditioning_scale # predict the noise residual noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings, down_block_additional_residuals=down_block_res_samples, mid_block_additional_residual=mid_block_res_sample, )['sample'] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if do_classifier_free_guidance: controls = torch.split(controls, controls.shape[0] // 2, dim=0)[0] if return_type == 'image': image = self.output_to_pil(image) controls = self.output_to_pil(controls * 2 - 1) elif return_type == 'numpy': image = image.cpu().numpy() controls = controls.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image, 'controls': controls} def forward(self, *args, **kwargs): """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') @MODELS.register_module() class ControlStableDiffusionImg2Img(ControlStableDiffusion): def _default_height_width(self, height, width, image): if isinstance(image, list): image = image[0] if height is None: if isinstance(image, Image.Image): height = image.height elif isinstance(image, torch.Tensor): height = image.shape[3] height = (height // 8) * 8 # round down to nearest multiple of 8 if width is None: if isinstance(image, Image.Image): width = image.width elif isinstance(image, torch.Tensor): width = image.shape[2] width = (width // 8) * 8 # round down to nearest multiple of 8 return height, width def get_timesteps(self, num_inference_steps, strength, device): # get the original timestep using init_timestep init_timestep = min( int(num_inference_steps * strength), num_inference_steps) t_start = max(num_inference_steps - init_timestep, 0) timesteps = self.test_scheduler.timesteps[t_start:] return timesteps, num_inference_steps - t_start def prepare_latents(self, image, timestep, batch_size, num_images_per_prompt, dtype, device, generator=None, noise=None): if not isinstance(image, (torch.Tensor, Image.Image, list)): raise ValueError( f'`image` has to be of type `torch.Tensor`, ' f' `PIL.Image.Image` or list but is {type(image)}') image = image.to(device=device, dtype=dtype) batch_size = batch_size * num_images_per_prompt if isinstance(generator, list) and len(generator) != batch_size: raise ValueError( f'You have passed a list of generators of ' f' length {len(generator)}, but requested an effective batch' f' size of {batch_size}. Make sure the batch size ' f' matches the length of the generators.') if isinstance(generator, list): init_latents = [ self.vae.encode(image[i:i + 1]).latent_dist.sample(generator[i]) for i in range(batch_size) ] init_latents = torch.cat(init_latents, dim=0) else: init_latents = self.vae.encode(image).latent_dist.sample(generator) init_latents = self.vae.config.scaling_factor * init_latents vae_encode_latents = init_latents if batch_size > init_latents.shape[0] and \ batch_size % init_latents.shape[0] == 0: raise ValueError( f'Cannot duplicate `image` of batch size' f' {init_latents.shape[0]} to {batch_size} text prompts.') else: init_latents = torch.cat([init_latents], dim=0) shape = init_latents.shape if noise is None: noise = torch.randn( shape, generator=generator, device=device, dtype=dtype) # get latents init_latents = self.scheduler.add_noise(init_latents, noise, timestep) return init_latents, vae_encode_latents def prepare_latent_image(self, image, dtype): if isinstance(image, torch.Tensor): # Batch single image if image.ndim == 3: image = image.unsqueeze(0) image = image.to(dtype=dtype) else: # preprocess image if isinstance(image, (Image.Image, np.ndarray)): image = [image] if isinstance(image, list) and isinstance(image[0], Image.Image): image = [np.array(i.convert('RGB'))[None, :] for i in image] image = np.concatenate(image, axis=0) elif isinstance(image, list) and isinstance(image[0], np.ndarray): image = np.concatenate([i[None, :] for i in image], axis=0) image = image.transpose(0, 3, 1, 2) image = torch.from_numpy(image).to(dtype=dtype) / 127.5 - 1.0 return image @torch.no_grad() def infer( self, prompt: Union[str, List[str]], latent_image: Union[torch.FloatTensor, Image.Image, List[torch.FloatTensor], List[Image.Image]] = None, latent_mask: torch.FloatTensor = None, strength: float = 1.0, height: Optional[int] = None, width: Optional[int] = None, control: Optional[Union[str, np.ndarray, torch.Tensor]] = None, controlnet_conditioning_scale: float = 1.0, num_inference_steps: int = 20, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, return_type='image', show_progress=True, reference_img: Union[torch.FloatTensor, Image.Image, List[torch.FloatTensor], List[Image.Image]] = None, ): """Function invoked when calling the pipeline for generation. Args: prompt (str or List[str]): The prompt or prompts to guide the image generation. height (int, Optional): The height in pixels of the generated image. If not passed, the height will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. width (int, Optional): The width in pixels of the generated image. If not passed, the width will be `self.unet_sample_size * self.vae_scale_factor` Defaults to None. num_inference_steps (int): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. Defaults to 50. guidance_scale (float): Guidance scale as defined in Classifier- Free Diffusion Guidance (https://arxiv.org/abs/2207.12598). Defaults to 7.5 negative_prompt (str or List[str], optional): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than 1). Defaults to None. num_images_per_prompt (int): The number of images to generate per prompt. Defaults to 1. eta (float): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to DDIMScheduler, will be ignored for others. Defaults to 0.0. generator (torch.Generator, optional): A torch generator to make generation deterministic. Defaults to None. latents (torch.FloatTensor, optional): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. Defaults to None. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images and Control image. """ assert return_type in ['image', 'tensor', 'numpy'] # 0. Default height and width to unet # height = height or self.unet_sample_size * self.vae_scale_factor # width = width or self.unet_sample_size * self.vae_scale_factor height, width = self._default_height_width(height, width, control) # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 img_dtype = self.vae.module.dtype if hasattr( self.vae, 'module') else self.vae.dtype if is_model_wrapper(self.controlnet): control_dtype = self.controlnet.module.dtype else: control_dtype = self.controlnet.dtype controls = self.prepare_control( control, width, height, batch_size, num_images_per_prompt, device, dtype=control_dtype) if do_classifier_free_guidance: controls = torch.cat([controls] * 2) latent_image = self.prepare_latent_image(latent_image, self.controlnet.dtype) if reference_img is not None: reference_img = self.prepare_latent_image(reference_img, self.controlnet.dtype) # 3. Encode input prompt text_embeddings = self._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) text_embeddings = text_embeddings.to(control_dtype) # 4. Prepare timesteps # self.scheduler.set_timesteps(num_inference_steps, device=device) self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps timesteps, num_inference_steps = self.get_timesteps( num_inference_steps, strength, device) latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt) # 5. Prepare latent variables latents, vae_encode_latents = self.prepare_latents( latent_image, latent_timestep, batch_size, num_images_per_prompt, text_embeddings.dtype, device, generator, noise=latents) if reference_img is not None: _, ref_img_vae_latents = self.prepare_latents( reference_img, latent_timestep, batch_size, num_images_per_prompt, text_embeddings.dtype, device, generator, noise=latents) # 6. Prepare extra step kwargs. extra_step_kwargs = self.prepare_test_scheduler_extra_step_kwargs( generator, eta) # 7. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) latent_model_input = latent_model_input.to(control_dtype) if reference_img is not None: ref_img_vae_latents_t = self.scheduler.add_noise( ref_img_vae_latents, torch.randn_like(ref_img_vae_latents), t) ref_img_vae_latents_model_input = torch.cat( [ref_img_vae_latents_t] * 2) if \ do_classifier_free_guidance else ref_img_vae_latents_t ref_img_vae_latents_model_input = \ self.test_scheduler.scale_model_input( ref_img_vae_latents_model_input, t) ref_img_vae_latents_model_input = \ ref_img_vae_latents_model_input.to(control_dtype) down_block_res_samples, mid_block_res_sample = self.controlnet( latent_model_input, t, encoder_hidden_states=text_embeddings, controlnet_cond=controls, return_dict=False, ) down_block_res_samples = [ down_block_res_sample * controlnet_conditioning_scale for down_block_res_sample in down_block_res_samples ] mid_block_res_sample *= controlnet_conditioning_scale # predict the noise residual if reference_img is not None: noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings, down_block_additional_residuals=down_block_res_samples, mid_block_additional_residual=mid_block_res_sample, ref_x=ref_img_vae_latents_model_input)['sample'] else: noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings, down_block_additional_residuals=down_block_res_samples, mid_block_additional_residual=mid_block_res_sample, )['sample'] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] if latent_mask is not None: latents = latents * latent_mask + \ vae_encode_latents * (1.0 - latent_mask) # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if do_classifier_free_guidance: controls = torch.split(controls, controls.shape[0] // 2, dim=0)[0] if return_type == 'image': image = self.output_to_pil(image) controls = self.output_to_pil(controls * 2 - 1) elif return_type == 'numpy': image = image.cpu().numpy() controls = controls.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image, 'controls': controls} ================================================ FILE: mmagic/models/editors/controlnet/controlnet_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import ERROR from typing import Optional import torch.nn as nn from mmengine import print_log from mmengine.runner import save_checkpoint def change_base_model(controlnet: nn.Module, curr_model: nn.Module, base_model: nn.Module, save_path: Optional[str] = None, *args, **kwargs) -> nn.Module: """This function is used to change the base model of ControlNet. Refers to https://github.com/lllyasviel/ControlNet/blob/main/tool_transfer_control.py . # noqa. Args: controlnet (nn.Module): The model for ControlNet to convert. curr_model (nn.Module): The model of current Stable Diffusion's Unet. base_model (nn.Module): The model of Stable Diffusion's Unet which ControlNet initialized with. save_path (str, optional): The path to save the converted model. Defaults to None. *args, **kwargs: Arguments for `save_checkpoint`. """ dtype = next(controlnet.parameters()).dtype base_state_dict = base_model.state_dict() curr_state_dict = curr_model.state_dict() print_log('Start convert ControlNet to new Unet.', 'current') for k, v in controlnet.state_dict().items(): if k in base_state_dict: base_v = base_state_dict[k].cpu() curr_v = curr_state_dict[k].cpu() try: offset = v.cpu() - base_v new_v = offset + curr_v controlnet.state_dict()[k].data.copy_(new_v.to(dtype)) print_log(f'Convert success: \'{k}\'.', 'current') except Exception as exception: print_log( f'Error occurs when convert \'{k}\'. ' 'Please check that the model structure of ' '\'ControlNet\', \'BaseModel\' and \'CurrentModel\' ' 'are consistent.', 'current', ERROR) raise exception if save_path: save_checkpoint(controlnet.state_dict(), save_path, *args, **kwargs) return controlnet ================================================ FILE: mmagic/models/editors/cyclegan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .cyclegan import CycleGAN from .cyclegan_generator import ResnetGenerator __all__ = ['CycleGAN', 'ResnetGenerator'] ================================================ FILE: mmagic/models/editors/cyclegan/cyclegan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F from mmengine import MessageHub from mmengine.optim import OptimWrapperDict from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ...base_models import BaseTranslationModel from ...utils import set_requires_grad from .cyclegan_modules import GANImageBuffer @MODELS.register_module() class CycleGAN(BaseTranslationModel): """CycleGAN model for unpaired image-to-image translation. Ref: Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks """ def __init__(self, *args, buffer_size=50, loss_config=dict(cycle_loss_weight=10., id_loss_weight=0.5), **kwargs): super().__init__(*args, **kwargs) # GAN image buffers self.image_buffers = dict() self.buffer_size = buffer_size for domain in self._reachable_domains: self.image_buffers[domain] = GANImageBuffer(self.buffer_size) self.loss_config = loss_config def forward_test(self, img, target_domain, **kwargs): """Forward function for testing. Args: img (tensor): Input image tensor. target_domain (str): Target domain of output image. kwargs (dict): Other arguments. Returns: dict: Forward results. """ # This is a trick for CycleGAN # ref: https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/e1bdf46198662b0f4d0b318e24568205ec4d7aee/test.py#L54 # noqa self.train() target = self.translation(img, target_domain=target_domain, **kwargs) results = dict(source=img, target=target) return results def _get_disc_loss(self, outputs): """Backward function for the discriminators. Args: outputs (dict): Dict of forward results. Returns: dict: Discriminators' loss and loss dict. """ discriminators = self.get_module(self.discriminators) log_vars_d = dict() loss_d = 0 # GAN loss for discriminators['a'] for domain in self._reachable_domains: losses = dict() fake_img = self.image_buffers[domain].query( outputs[f'fake_{domain}']) fake_pred = discriminators[domain](fake_img.detach()) losses[f'loss_gan_d_{domain}_fake'] = F.mse_loss( fake_pred, 0. * torch.ones_like(fake_pred)) real_pred = discriminators[domain](outputs[f'real_{domain}']) losses[f'loss_gan_d_{domain}_real'] = F.mse_loss( real_pred, 1. * torch.ones_like(real_pred)) _loss_d, _log_vars_d = self.parse_losses(losses) _loss_d *= 0.5 loss_d += _loss_d log_vars_d[f'loss_gan_d_{domain}'] = _log_vars_d['loss'] * 0.5 return loss_d, log_vars_d def _get_gen_loss(self, outputs): """Backward function for the generators. Args: outputs (dict): Dict of forward results. Returns: dict: Generators' loss and loss dict. """ generators = self.get_module(self.generators) discriminators = self.get_module(self.discriminators) losses = dict() # gan loss for domain in self._reachable_domains: # Identity reconstruction for generators outputs[f'identity_{domain}'] = generators[domain]( outputs[f'real_{domain}']) # GAN loss for generators fake_pred = discriminators[domain](outputs[f'fake_{domain}']) # LSGAN loss losses[f'loss_gan_g_{domain}'] = F.mse_loss( fake_pred, 1. * torch.ones_like(fake_pred)) # cycle loss loss_weight = self.loss_config['cycle_loss_weight'] losses['cycle_loss'] = 0. for domain in self._reachable_domains: losses['cycle_loss'] += loss_weight * F.l1_loss( outputs[f'cycle_{domain}'], outputs[f'real_{domain}'], reduction='mean') # id loss loss_weight = self.loss_config['id_loss_weight'] if loss_weight != 0.: losses['id_loss'] = 0. for domain in self._reachable_domains: losses['id_loss'] += loss_weight * F.l1_loss( outputs[f'identity_{domain}'], outputs[f'real_{domain}'], reduction='mean') loss_g, log_vars_g = self.parse_losses(losses) return loss_g, log_vars_g def _get_opposite_domain(self, domain): """Get the opposite domain respect to the input domain. Args: domain (str): The input domain. Returns: str: The opposite domain. """ for item in self._reachable_domains: if item != domain: return item return None def train_step(self, data: dict, optim_wrapper: OptimWrapperDict): """Training step function. Args: data_batch (dict): Dict of the input data batch. optimizer (dict[torch.optim.Optimizer]): Dict of optimizers for the generators and discriminators. ddp_reducer (:obj:`Reducer` | None, optional): Reducer from ddp. It is used to prepare for ``backward()`` in ddp. Defaults to None. running_status (dict | None, optional): Contains necessary basic information for training, e.g., iteration number. Defaults to None. Returns: dict: Dict of loss, information for logger, the number of samples\ and results for visualization. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper = optim_wrapper['discriminators'] inputs_dict = data['inputs'] outputs, log_vars = dict(), dict() # forward generators with disc_optimizer_wrapper.optim_context(self.discriminators): for target_domain in self._reachable_domains: # fetch data by domain source_domain = self.get_other_domains(target_domain)[0] img = inputs_dict[f'img_{source_domain}'] # translation process results = self( img, test_mode=False, target_domain=target_domain) outputs[f'real_{source_domain}'] = results['source'] outputs[f'fake_{target_domain}'] = results['target'] # cycle process results = self( results['target'], test_mode=False, target_domain=source_domain) outputs[f'cycle_{source_domain}'] = results['target'] # update discriminators disc_accu_iters = disc_optimizer_wrapper._accumulative_counts loss_d, log_vars_d = self._get_disc_loss(outputs) disc_optimizer_wrapper.update_params(loss_d) log_vars.update(log_vars_d) # generators, no updates to discriminator parameters. if ((curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0 and curr_iter >= self.disc_init_steps): set_requires_grad(self.discriminators, False) # update generator gen_optimizer_wrapper = optim_wrapper['generators'] with gen_optimizer_wrapper.optim_context(self.generators): loss_g, log_vars_g = self._get_gen_loss(outputs) gen_optimizer_wrapper.update_params(loss_g) log_vars.update(log_vars_g) set_requires_grad(self.discriminators, True) return log_vars def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] outputs = {} for src_domain in self._reachable_domains: # Identity reconstruction for generators target_domain = self.get_other_domains(src_domain)[0] target = self.forward_test( inputs_dict[f'img_{src_domain}'], target_domain=target_domain)['target'] outputs[f'img_{target_domain}'] = target batch_sample_list = [] num_batches = next(iter(outputs.values())).shape[0] data_samples = data_samples.split() for idx in range(num_batches): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) for src_domain in self._reachable_domains: target_domain = self.get_other_domains(src_domain)[0] fake_img = outputs[f'img_{target_domain}'][idx] fake_img = self.data_preprocessor.destruct( fake_img, data_samples[idx], f'img_{target_domain}') setattr(gen_sample, f'fake_{target_domain}', fake_img) batch_sample_list.append(gen_sample) return batch_sample_list def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] outputs = {} for src_domain in self._reachable_domains: # Identity reconstruction for generators target_domain = self.get_other_domains(src_domain)[0] target = self.forward_test( inputs_dict[f'img_{src_domain}'], target_domain=target_domain)['target'] outputs[f'img_{target_domain}'] = target batch_sample_list = [] num_batches = next(iter(outputs.values())).shape[0] data_samples = data_samples.split() for idx in range(num_batches): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) for src_domain in self._reachable_domains: target_domain = self.get_other_domains(src_domain)[0] fake_img = outputs[f'img_{target_domain}'][idx] fake_img = self.data_preprocessor.destruct( fake_img, data_samples[idx], f'img_{target_domain}') gen_sample.set_tensor_data({f'fake_{target_domain}': fake_img}) batch_sample_list.append(gen_sample) return batch_sample_list ================================================ FILE: mmagic/models/editors/cyclegan/cyclegan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.utils import generation_init_weights from mmagic.registry import MODELS from .cyclegan_modules import ResidualBlockWithDropout @MODELS.register_module() class ResnetGenerator(BaseModule): """Construct a Resnet-based generator that consists of residual blocks between a few downsampling/upsampling operations. Args: in_channels (int): Number of channels in input images. out_channels (int): Number of channels in output images. base_channels (int): Number of filters at the last conv layer. Default: 64. norm_cfg (dict): Config dict to build norm layer. Default: `dict(type='IN')`. use_dropout (bool): Whether to use dropout layers. Default: False. num_blocks (int): Number of residual blocks. Default: 9. padding_mode (str): The name of padding layer in conv layers: 'reflect' | 'replicate' | 'zeros'. Default: 'reflect'. init_cfg (dict): Config dict for initialization. `type`: The name of our initialization method. Default: 'normal'. `gain`: Scaling factor for normal, xavier and orthogonal. Default: 0.02. """ def __init__(self, in_channels, out_channels, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)): super().__init__(init_cfg=init_cfg) assert num_blocks >= 0, ('Number of residual blocks must be ' f'non-negative, but got {num_blocks}.') assert isinstance(norm_cfg, dict), ("'norm_cfg' should be dict, but" f'got {type(norm_cfg)}') assert 'type' in norm_cfg, "'norm_cfg' must have key 'type'" # We use norm layers in the resnet generator. # Only for IN, use bias to follow cyclegan's original implementation. use_bias = norm_cfg['type'] == 'IN' model = [] model += [ ConvModule( in_channels=in_channels, out_channels=base_channels, kernel_size=7, padding=3, bias=use_bias, norm_cfg=norm_cfg, padding_mode=padding_mode) ] num_down = 2 # add downsampling layers for i in range(num_down): multiple = 2**i model += [ ConvModule( in_channels=base_channels * multiple, out_channels=base_channels * multiple * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, norm_cfg=norm_cfg) ] # add residual blocks multiple = 2**num_down for i in range(num_blocks): model += [ ResidualBlockWithDropout( base_channels * multiple, padding_mode=padding_mode, norm_cfg=norm_cfg, use_dropout=use_dropout) ] # add upsampling layers for i in range(num_down): multiple = 2**(num_down - i) model += [ ConvModule( in_channels=base_channels * multiple, out_channels=base_channels * multiple // 2, kernel_size=3, stride=2, padding=1, bias=use_bias, conv_cfg=dict(type='deconv', output_padding=1), norm_cfg=norm_cfg) ] model += [ ConvModule( in_channels=base_channels, out_channels=out_channels, kernel_size=7, padding=3, bias=True, norm_cfg=None, act_cfg=dict(type='Tanh'), padding_mode=padding_mode) ] self.model = nn.Sequential(*model) self.init_type = 'normal' if init_cfg is None else init_cfg.get( 'type', 'normal') self.init_gain = 0.02 if init_cfg is None else init_cfg.get( 'gain', 0.02) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ return self.model(x) def init_weights(self): """Initialize weights for the model.""" if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return generation_init_weights( self, init_type=self.init_type, init_gain=self.init_gain) self._is_init = True ================================================ FILE: mmagic/models/editors/cyclegan/cyclegan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn as nn from mmcv.cnn import ConvModule class ResidualBlockWithDropout(nn.Module): """Define a Residual Block with dropout layers. Ref: Deep Residual Learning for Image Recognition A residual block is a conv block with skip connections. A dropout layer is added between two common conv modules. Args: channels (int): Number of channels in the conv layer. padding_mode (str): The name of padding layer: 'reflect' | 'replicate' | 'zeros'. norm_cfg (dict): Config dict to build norm layer. Default: `dict(type='IN')`. use_dropout (bool): Whether to use dropout layers. Default: True. """ def __init__(self, channels, padding_mode, norm_cfg=dict(type='BN'), use_dropout=True): super().__init__() assert isinstance(norm_cfg, dict), ("'norm_cfg' should be dict, but" f'got {type(norm_cfg)}') assert 'type' in norm_cfg, "'norm_cfg' must have key 'type'" # We use norm layers in the residual block with dropout layers. # Only for IN, use bias to follow cyclegan's original implementation. use_bias = norm_cfg['type'] == 'IN' block = [ ConvModule( in_channels=channels, out_channels=channels, kernel_size=3, padding=1, bias=use_bias, norm_cfg=norm_cfg, padding_mode=padding_mode) ] if use_dropout: block += [nn.Dropout(0.5)] block += [ ConvModule( in_channels=channels, out_channels=channels, kernel_size=3, padding=1, bias=use_bias, norm_cfg=norm_cfg, act_cfg=None, padding_mode=padding_mode) ] self.block = nn.Sequential(*block) def forward(self, x): """Forward function. Add skip connections without final ReLU. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = x + self.block(x) return out class GANImageBuffer: """This class implements an image buffer that stores previously generated images. This buffer allows us to update the discriminator using a history of generated images rather than the ones produced by the latest generator to reduce model oscillation. Args: buffer_size (int): The size of image buffer. If buffer_size = 0, no buffer will be created. buffer_ratio (float): The chance / possibility to use the images previously stored in the buffer. Default: 0.5. """ def __init__(self, buffer_size, buffer_ratio=0.5): self.buffer_size = buffer_size # create an empty buffer if self.buffer_size > 0: self.img_num = 0 self.image_buffer = [] self.buffer_ratio = buffer_ratio def query(self, images): """Query current image batch using a history of generated images. Args: images (Tensor): Current image batch without history information. """ if self.buffer_size == 0: # if the buffer size is 0, do nothing return images return_images = [] for image in images: image = torch.unsqueeze(image.data, 0) # if the buffer is not full, keep inserting current images if self.img_num < self.buffer_size: self.img_num = self.img_num + 1 self.image_buffer.append(image) return_images.append(image) else: use_buffer = np.random.random() < self.buffer_ratio # by self.buffer_ratio, the buffer will return a previously # stored image, and insert the current image into the buffer if use_buffer: random_id = np.random.randint(0, self.buffer_size) image_tmp = self.image_buffer[random_id].clone() self.image_buffer[random_id] = image return_images.append(image_tmp) # by (1 - self.buffer_ratio), the buffer will return the # current image else: return_images.append(image) # collect all the images and return return_images = torch.cat(return_images, 0) return return_images ================================================ FILE: mmagic/models/editors/dcgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .dcgan import DCGAN from .dcgan_discriminator import DCGANDiscriminator from .dcgan_generator import DCGANGenerator __all__ = ['DCGAN', 'DCGANDiscriminator', 'DCGANGenerator'] ================================================ FILE: mmagic/models/editors/dcgan/dcgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Tuple import torch import torch.nn.functional as F from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseGAN @MODELS.register_module() class DCGAN(BaseGAN): """Implementation of `Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks`. Paper link: `_ (DCGAN). Detailed architecture can be found in :class:`~mmagic.models.editors.dcgan.DCGANGenerator` # noqa and :class:`~mmagic.models.editors.dcgan.DCGANDiscriminator` # noqa """ def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: r"""Get disc loss. DCGAN use the vanilla gan loss to train the discriminator. Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 0. * torch.ones_like(disc_pred_fake)) losses_dict['loss_disc_real'] = F.binary_cross_entropy_with_logits( disc_pred_real, 1. * torch.ones_like(disc_pred_real)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple: """Get gen loss. DCGAN use the vanilla gan loss to train the generator. Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = F.binary_cross_entropy_with_logits( disc_pred_fake, 1. * torch.ones_like(disc_pred_fake)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/dcgan/dcgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule, normal_init, update_init_info from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.registry import MODELS @MODELS.register_module() class DCGANDiscriminator(BaseModule): """Discriminator for DCGAN. Implementation Details for DCGAN architecture: #. Adopt convolution in the discriminator; #. Use batchnorm in the discriminator except for the input and final \ output layer; #. Use LeakyReLU in the discriminator in addition to the output layer. Args: input_scale (int): The scale of the input image. output_scale (int): The final scale of the convolutional feature. out_channels (int): The channel number of the final output layer. in_channels (int, optional): The channel number of the input image. Defaults to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 128. default_norm_cfg (dict, optional): Norm config for all of layers except for the final output layer. Defaults to ``dict(type='BN')``. default_act_cfg (dict, optional): Activation config for all of layers except for the final output layer. Defaults to ``dict(type='ReLU')``. out_act_cfg (dict, optional): Activation config for the final output layer. Defaults to ``dict(type='Tanh')``. pretrained (str, optional): Path for the pretrained model. Default to ``None``. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, input_scale, output_scale, out_channels, in_channels=3, base_channels=128, default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='LeakyReLU'), out_act_cfg=None, init_cfg=None): super().__init__(init_cfg=init_cfg) self.input_scale = input_scale self.output_scale = output_scale self.out_channels = out_channels self.base_channels = base_channels # the number of times for downsampling self.num_downsamples = int(np.log2(input_scale // output_scale)) # build up downsampling backbone (excluding the output layer) downsamples = [] curr_channels = in_channels for i in range(self.num_downsamples): # remove norm for the first conv norm_cfg_ = None if i == 0 else default_norm_cfg in_ch = in_channels if i == 0 else base_channels * 2**(i - 1) downsamples.append( ConvModule( in_ch, base_channels * 2**i, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='Conv2d'), norm_cfg=norm_cfg_, act_cfg=default_act_cfg)) curr_channels = base_channels * 2**i self.downsamples = nn.Sequential(*downsamples) # define output layer self.output_layer = ConvModule( curr_channels, out_channels, kernel_size=4, stride=1, padding=0, conv_cfg=dict(type='Conv2d'), norm_cfg=None, act_cfg=out_act_cfg) def forward(self, x): """Forward function. Args: x (torch.Tensor): Fake or real image tensor. Returns: torch.Tensor: Prediction for the reality of the input image. """ n = x.shape[0] x = self.downsamples(x) x = self.output_layer(x) # reshape to a flatten feature return x.view(n, -1) def init_weights(self): """Init weights for models. We just use the initialization method proposed in the original paper. """ if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return for m in self.modules(): module_name = m.__class__.__name__ if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): normal_init(m, 0, 0.02) init_info = (f'{module_name} belongs to (nn.Conv2d and ' 'nn.ConvTranspose2d), initialize by normal ' 'distribution with 0 mean and 0.02 std.') elif isinstance(m, _BatchNorm): nn.init.normal_(m.weight.data) nn.init.constant_(m.bias.data, 0) init_info = (f'{module_name} is BatchNorm, initialize weight ' 'by normal discribution with unit mean and zero ' 'std, and initialize bias as 0.') # save init info update_init_info(m, init_info) ================================================ FILE: mmagic/models/editors/dcgan/dcgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule, normal_init, update_init_info from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.registry import MODELS from ...utils import get_module_device @MODELS.register_module() class DCGANGenerator(BaseModule): """Generator for DCGAN. Implementation Details for DCGAN architecture: #. Adopt transposed convolution in the generator; #. Use batchnorm in the generator except for the final output layer; #. Use ReLU in the generator in addition to the final output layer. More details can be found in the original paper: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks http://arxiv.org/abs/1511.06434 Args: output_scale (int | tuple[int]): Output scale for the generated image. If only a integer is provided, the output image will be a square shape. The tuple of two integers will set the height and width for the output image, respectively. out_channels (int, optional): The channel number of the output feature. Default to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Default to 1024. input_scale (int | tuple[int], optional): Output scale for the generated image. If only a integer is provided, the input feature ahead of the convolutional generator will be a square shape. The tuple of two integers will set the height and width for the input convolutional feature, respectively. Defaults to 4. noise_size (int, optional): Size of the input noise vector. Defaults to 100. default_norm_cfg (dict, optional): Norm config for all of layers except for the final output layer. Defaults to ``dict(type='BN')``. default_act_cfg (dict, optional): Activation config for all of layers except for the final output layer. Defaults to ``dict(type='ReLU')``. out_act_cfg (dict, optional): Activation config for the final output layer. Defaults to ``dict(type='Tanh')``. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, output_scale, out_channels=3, base_channels=1024, input_scale=4, noise_size=100, default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='ReLU'), out_act_cfg=dict(type='Tanh'), init_cfg=None): super().__init__(init_cfg=init_cfg) self.output_scale = output_scale self.base_channels = base_channels self.input_scale = input_scale self.noise_size = noise_size # the number of times for upsampling self.num_upsamples = int(np.log2(output_scale // input_scale)) # output 4x4 feature map self.noise2feat = ConvModule( noise_size, base_channels, kernel_size=4, stride=1, padding=0, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg) # build up upsampling backbone (excluding the output layer) upsampling = [] curr_channel = base_channels for _ in range(self.num_upsamples - 1): upsampling.append( ConvModule( curr_channel, curr_channel // 2, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) curr_channel //= 2 self.upsampling = nn.Sequential(*upsampling) # output layer self.output_layer = ConvModule( curr_channel, out_channels, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='ConvTranspose2d'), norm_cfg=None, act_cfg=out_act_cfg) # self.init_weights(pretrained=pretrained) def forward(self, noise, num_batches=0, return_noise=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img`` and ``noise_batch`` will be returned. """ # receive noise and conduct sanity check. if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size if noise.ndim == 2: noise_batch = noise[:, :, None, None] elif noise.ndim == 4: noise_batch = noise else: raise ValueError('The noise should be in shape of (n, c) or ' f'(n, c, 1, 1), but got {noise.shape}') # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size, 1, 1)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size, 1, 1)) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) x = self.noise2feat(noise_batch) x = self.upsampling(x) x = self.output_layer(x) if return_noise: return dict(fake_img=x, noise_batch=noise_batch) return x def init_weights(self): """Init weights for models. We just use the initialization method proposed in the original paper. """ if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): normal_init(m, 0, 0.02) elif isinstance(m, _BatchNorm): nn.init.normal_(m.weight.data) nn.init.constant_(m.bias.data, 0) # save init info update_init_info( m, f'Initialize {m.__class__.__name__} by ' f'\'init_type\' {self.init_cfg}.') ================================================ FILE: mmagic/models/editors/ddpm/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .denoising_unet import DenoisingUnet __all__ = ['DenoisingUnet'] ================================================ FILE: mmagic/models/editors/ddpm/attention.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn.functional as F from addict import Dict from torch import nn class Transformer2DModel(nn.Module): """Transformer model for image-like data. Takes either discrete (classes of vector embeddings) or continuous (actual embeddings) inputs. When input is continuous: First, project the input (aka embedding) and reshape to b, t, d. Then apply standard transformer action. Finally, reshape to image. When input is discrete: First, input (classes of latent pixels) is converted to embeddings and has positional embeddings applied, see `ImagePositionalEmbeddings`. Then apply standard transformer action. Finally, predict classes of unnoised image. Note that it is assumed one of the input classes is the masked latent pixel. The predicted classes of the unnoised image do not contain a prediction for the masked pixel as the unnoised image cannot be masked. Args: num_attention_heads (`int`, *optional*, defaults to 16): The number of heads to use for multi-head attention. attention_head_dim (`int`, *optional*, defaults to 88): The number of channels in each head. in_channels (`int`, *optional*): Pass if the input is continuous. The number of channels in the input and output. num_layers (`int`, *optional*, defaults to 1): The number of layers of Transformer blocks to use. dropout (`float`, *optional*, defaults to 0.1): The dropout probability to use. norm_num_groups (int): Norm group num, defaults to 32. cross_attention_dim (`int`, *optional*): The number of context dimensions to use. attention_bias (`bool`, *optional*): Configure if the TransformerBlocks' attention should contain a bias parameter. sample_size (`int`, *optional*): Pass if the input is discrete. The width of the latent images. Note that this is fixed at training time as it is used for learning a number of position embeddings. See `ImagePositionalEmbeddings`. num_vector_embeds (`int`, *optional*): Pass if the input is discrete. The number of classes of the vector embeddings of the latent pixels. Includes the class for the masked latent pixel. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. use_linear_projection (bool): Whether to use linear projection, defaults to False. only_cross_attention (bool): whether only use cross attention, defaults to False. """ def __init__( self, num_attention_heads: int = 16, attention_head_dim: int = 88, in_channels: Optional[int] = None, num_layers: int = 1, dropout: float = 0.0, norm_num_groups: int = 32, cross_attention_dim: Optional[int] = None, attention_bias: bool = False, sample_size: Optional[int] = None, num_vector_embeds: Optional[int] = None, activation_fn: str = 'geglu', use_linear_projection: bool = False, only_cross_attention: bool = False, ): super().__init__() self.use_linear_projection = use_linear_projection self.num_attention_heads = num_attention_heads self.attention_head_dim = attention_head_dim inner_dim = num_attention_heads * attention_head_dim # 1. Transformer2DModel can process both standard continuous # images of shape `(batch_size, num_channels, width, height)` # as well as quantized image embeddings of shape # `(batch_size, num_image_vectors)` # Define whether input is continuous or discrete # depending on configuration self.is_input_continuous = in_channels is not None self.is_input_vectorized = num_vector_embeds is not None if self.is_input_continuous and self.is_input_vectorized: raise ValueError( f'Cannot define both `in_channels`: {in_channels} ' f'and `num_vector_embeds`: {num_vector_embeds}. Make' f' sure that either `in_channels` or `num_vector_embeds` ' 'is None.') elif not self.is_input_continuous and not self.is_input_vectorized: raise ValueError( f'Has to define either `in_channels`: {in_channels} or' f' `num_vector_embeds`: {num_vector_embeds}. Make' f' sure that either `in_channels` or ' '`num_vector_embeds` is not None.') # 2. Define input layers if self.is_input_continuous: self.in_channels = in_channels self.norm = torch.nn.GroupNorm( num_groups=norm_num_groups, num_channels=in_channels, eps=1e-6, affine=True) if use_linear_projection: self.proj_in = nn.Linear(in_channels, inner_dim) else: self.proj_in = nn.Conv2d( in_channels, inner_dim, kernel_size=1, stride=1, padding=0) else: raise ValueError('input_vectorized not supported now.') # 3. Define transformers blocks self.transformer_blocks = nn.ModuleList([ BasicTransformerBlock( inner_dim, num_attention_heads, attention_head_dim, dropout=dropout, cross_attention_dim=cross_attention_dim, activation_fn=activation_fn, attention_bias=attention_bias, only_cross_attention=only_cross_attention, ) for d in range(num_layers) ]) # 4. Define output layers if use_linear_projection: self.proj_out = nn.Linear(in_channels, inner_dim) else: self.proj_out = nn.Conv2d( inner_dim, in_channels, kernel_size=1, stride=1, padding=0) def _set_attention_slice(self, slice_size): """set attention slice.""" for block in self.transformer_blocks: block._set_attention_slice(slice_size) def forward(self, hidden_states, encoder_hidden_states=None, timestep=None, return_dict: bool = True): """forward function. Args: hidden_states ( When discrete, `torch.LongTensor` of shape `(batch size, num latent pixels)`. When continuous, `torch.FloatTensor` of shape ` (batch size, channel, height, width)`): Input hidden_states encoder_hidden_states ( `torch.LongTensor` of shape `(batch size, context dim)`, *optional*): Conditional embeddings for cross attention layer. If not given, cross-attention defaults to self-attention. timestep ( `torch.long`, *optional*): Optional timestep to be applied as an embedding in AdaLayerNorm's. Used to indicate denoising step. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`models.unet_2d_condition.UNet2DConditionOutput`] instead of a plain tuple. Returns: Dict if `return_dict` is True, otherwise a `tuple`. When returning a tuple, the first element is the sample tensor. """ # 1. Input if self.is_input_continuous: batch, channel, height, weight = hidden_states.shape residual = hidden_states hidden_states = self.norm(hidden_states) if not self.use_linear_projection: hidden_states = self.proj_in(hidden_states) inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * weight, inner_dim) else: inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * weight, inner_dim) hidden_states = self.proj_in(hidden_states) else: raise ValueError('input_vectorized not supported now.') # 2. Blocks for block in self.transformer_blocks: hidden_states = block( hidden_states, context=encoder_hidden_states, timestep=timestep) # 3. Output if not self.use_linear_projection: hidden_states = ( hidden_states.reshape(batch, height, weight, inner_dim).permute(0, 3, 1, 2).contiguous()) hidden_states = self.proj_out(hidden_states) else: hidden_states = self.proj_out(hidden_states) hidden_states = ( hidden_states.reshape(batch, height, weight, inner_dim).permute(0, 3, 1, 2).contiguous()) output = hidden_states + residual if not return_dict: return (output, ) return Dict(sample=output) class BasicTransformerBlock(nn.Module): """A basic Transformer block. Args: dim (int): The number of channels in the input and output. num_attention_heads (int): The number of heads to use for multi-head attention. attention_head_dim (int): The number of channels in each head. dropout (float, *optional*, defaults to 0.0): The dropout probability to use. cross_attention_dim (int, *optional*): The size of the context vector for cross attention. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. attention_bias (bool, *optional*, defaults to `False`): Configure if the attentions should contain a bias parameter. only_cross_attention (bool, defaults to False): whether to use cross attention only. """ def __init__( self, dim: int, num_attention_heads: int, attention_head_dim: int, dropout=0.0, cross_attention_dim: Optional[int] = None, activation_fn: str = 'geglu', attention_bias: bool = False, only_cross_attention: bool = False, ): super().__init__() self.only_cross_attention = only_cross_attention self.attn1 = CrossAttention( query_dim=dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, cross_attention_dim=cross_attention_dim if only_cross_attention else None, ) # is a self-attention self.ff = FeedForward( dim, dropout=dropout, activation_fn=activation_fn) self.attn2 = CrossAttention( query_dim=dim, cross_attention_dim=cross_attention_dim, heads=num_attention_heads, dim_head=attention_head_dim, dropout=dropout, bias=attention_bias, ) # is self-attn if context is none # layer norms self.norm1 = nn.LayerNorm(dim) self.norm2 = nn.LayerNorm(dim) self.norm3 = nn.LayerNorm(dim) def _set_attention_slice(self, slice_size): """set attention slice.""" self.attn1._slice_size = slice_size self.attn2._slice_size = slice_size def forward(self, hidden_states, context=None, timestep=None): """forward with hidden states, context and timestep.""" # 1. Self-Attention norm_hidden_states = (self.norm1(hidden_states)) if self.only_cross_attention: hidden_states = self.attn1(norm_hidden_states, context) + hidden_states else: hidden_states = self.attn1(norm_hidden_states) + hidden_states # 2. Cross-Attention norm_hidden_states = (self.norm2(hidden_states)) hidden_states = self.attn2( norm_hidden_states, context=context) + hidden_states # 3. Feed-forward hidden_states = self.ff(self.norm3(hidden_states)) + hidden_states return hidden_states class CrossAttention(nn.Module): r""" A cross attention layer. Args: query_dim (`int`): The number of channels in the query. cross_attention_dim (`int`, *optional*): The number of channels in the context. If not given, defaults to `query_dim`. heads (`int`, *optional*, defaults to 8): The number of heads to use for multi-head attention. dim_head (`int`, *optional*, defaults to 64): The number of channels in each head. dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. bias (`bool`, *optional*, defaults to False): Set to `True` for the query, key, and value linear layers to contain a bias parameter. """ def __init__( self, query_dim: int, cross_attention_dim: Optional[int] = None, heads: int = 8, dim_head: int = 64, dropout: float = 0.0, bias=False, ): super().__init__() inner_dim = dim_head * heads cross_attention_dim = cross_attention_dim if cross_attention_dim is not None else query_dim # noqa self.scale = dim_head**-0.5 self.heads = heads # for slice_size > 0 the attention score computation # is split across the batch axis to save memory # You can set slice_size with `set_attention_slice` self._slice_size = None self.to_q = nn.Linear(query_dim, inner_dim, bias=bias) self.to_k = nn.Linear(cross_attention_dim, inner_dim, bias=bias) self.to_v = nn.Linear(cross_attention_dim, inner_dim, bias=bias) self.to_out = nn.ModuleList([]) self.to_out.append(nn.Linear(inner_dim, query_dim)) self.to_out.append(nn.Dropout(dropout)) def reshape_heads_to_batch_dim(self, tensor): """reshape heads num to batch dim.""" batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size, seq_len, head_size, dim // head_size) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size * head_size, seq_len, dim // head_size) return tensor def reshape_batch_dim_to_heads(self, tensor): """reshape batch dim to heads num.""" batch_size, seq_len, dim = tensor.shape head_size = self.heads tensor = tensor.reshape(batch_size // head_size, head_size, seq_len, dim) tensor = tensor.permute(0, 2, 1, 3).reshape(batch_size // head_size, seq_len, dim * head_size) return tensor def forward(self, hidden_states, context=None, mask=None): """forward with hidden states, context and mask.""" batch_size, sequence_length, _ = hidden_states.shape query = self.to_q(hidden_states) context = context if context is not None else hidden_states key = self.to_k(context) value = self.to_v(context) dim = query.shape[-1] query = self.reshape_heads_to_batch_dim(query) key = self.reshape_heads_to_batch_dim(key) value = self.reshape_heads_to_batch_dim(value) # TODO(PVP) - mask is currently never used. Remember # to re-implement when used # attention, what we cannot get enough of if self._slice_size is None or query.shape[0] // self._slice_size == 1: hidden_states = self._attention(query, key, value) else: hidden_states = self._sliced_attention(query, key, value, sequence_length, dim) # linear proj hidden_states = self.to_out[0](hidden_states) # dropout hidden_states = self.to_out[1](hidden_states) return hidden_states def _attention(self, query, key, value): """attention calculation.""" attention_scores = torch.baddbmm( torch.empty( query.shape[0], query.shape[1], key.shape[1], dtype=query.dtype, device=query.device), query, key.transpose(-1, -2), beta=0, alpha=self.scale, ) attention_probs = attention_scores.softmax(dim=-1) # compute attention output hidden_states = torch.bmm(attention_probs, value) # reshape hidden_states hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states def _sliced_attention(self, query, key, value, sequence_length, dim): """sliced attention calculation.""" batch_size_attention = query.shape[0] hidden_states = torch.zeros( (batch_size_attention, sequence_length, dim // self.heads), device=query.device, dtype=query.dtype) slice_size = self._slice_size if self._slice_size is not None \ else hidden_states.shape[0] for i in range(hidden_states.shape[0] // slice_size): start_idx = i * slice_size end_idx = (i + 1) * slice_size attn_slice = torch.baddbmm( torch.empty( slice_size, query.shape[1], key.shape[1], dtype=query.dtype, device=query.device), query[start_idx:end_idx], key[start_idx:end_idx].transpose(-1, -2), beta=0, alpha=self.scale, ) attn_slice = attn_slice.softmax(dim=-1) attn_slice = torch.bmm(attn_slice, value[start_idx:end_idx]) hidden_states[start_idx:end_idx] = attn_slice # reshape hidden_states hidden_states = self.reshape_batch_dim_to_heads(hidden_states) return hidden_states class FeedForward(nn.Module): r""" A feed-forward layer. Args: dim (int): The number of channels in the input. dim_out (int, *optional*): The number of channels in the output. If not given, defaults to `dim`. mult (int, *optional*, defaults to 4): The multiplier to use for the hidden dimension. dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. """ def __init__( self, dim: int, dim_out: Optional[int] = None, mult: int = 4, dropout: float = 0.0, activation_fn: str = 'geglu', ): super().__init__() inner_dim = int(dim * mult) dim_out = dim_out if dim_out is not None else dim if activation_fn == 'geglu': geglu = GEGLU(dim, inner_dim) elif activation_fn == 'geglu-approximate': geglu = ApproximateGELU(dim, inner_dim) self.net = nn.ModuleList([]) # project in self.net.append(geglu) # project dropout self.net.append(nn.Dropout(dropout)) # project out self.net.append(nn.Linear(inner_dim, dim_out)) def forward(self, hidden_states): """forward with hidden states.""" for module in self.net: hidden_states = module(hidden_states) return hidden_states # feedforward class GEGLU(nn.Module): r""" A variant of the gated linear unit activation function from https://arxiv.org/abs/2002.05202. Args: dim_in (`int`): The number of channels in the input. dim_out (`int`): The number of channels in the output. """ def __init__(self, dim_in: int, dim_out: int): super().__init__() self.proj = nn.Linear(dim_in, dim_out * 2) def gelu(self, gate): """gelu activation.""" return F.gelu(gate) def forward(self, hidden_states): """forward with hidden states.""" hidden_states, gate = self.proj(hidden_states).chunk(2, dim=-1) return hidden_states * self.gelu(gate) class ApproximateGELU(nn.Module): """The approximate form of Gaussian Error Linear Unit (GELU) For more details, see section 2: https://arxiv.org/abs/1606.08415 """ def __init__(self, dim_in: int, dim_out: int): super().__init__() self.proj = nn.Linear(dim_in, dim_out) def forward(self, x): """forward function.""" x = self.proj(x) return x * torch.sigmoid(1.702 * x) ================================================ FILE: mmagic/models/editors/ddpm/denoising_unet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from copy import deepcopy from functools import partial from typing import Tuple import mmengine import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn.bricks import build_norm_layer from mmcv.cnn.bricks.conv_module import ConvModule from mmengine.logging import MMLogger from mmengine.model import BaseModule, constant_init from mmengine.runner import load_checkpoint from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from mmagic.registry import MODELS from .embeddings import TimestepEmbedding, Timesteps from .unet_blocks import UNetMidBlock2DCrossAttn, get_down_block, get_up_block logger = MMLogger.get_current_instance() class EmbedSequential(nn.Sequential): """A sequential module that passes timestep embeddings to the children that support it as an extra input. Modified from https://github.com/openai/improved-diffusion/blob/main/improved_diffusion/unet.py#L35 """ def forward(self, x, y, encoder_out=None): for layer in self: if isinstance(layer, DenoisingResBlock): x = layer(x, y) elif isinstance( layer, MultiHeadAttentionBlock) and encoder_out is not None: x = layer(x, encoder_out) else: x = layer(x) return x @MODELS.register_module('GN32') class GroupNorm32(nn.GroupNorm): def __init__(self, num_channels, num_groups=32, **kwargs): super().__init__(num_groups, num_channels, **kwargs) def forward(self, x): return super().forward(x.float()).type(x.dtype) def convert_module_to_f16(layer): """Convert primitive modules to float16.""" if isinstance(layer, (nn.Conv1d, nn.Conv2d, nn.Conv3d)): layer.weight.data = layer.weight.data.half() if layer.bias is not None: layer.bias.data = layer.bias.data.half() def convert_module_to_f32(layer): """Convert primitive modules to float32, undoing convert_module_to_f16().""" if isinstance(layer, (nn.Conv1d, nn.Conv2d, nn.Conv3d)): layer.weight.data = layer.weight.data.float() if layer.bias is not None: layer.bias.data = layer.bias.data.float() @MODELS.register_module() class SiLU(BaseModule): r"""Applies the Sigmoid Linear Unit (SiLU) function, element-wise. The SiLU function is also known as the swish function. Args: input (bool, optional): Use inplace operation or not. Defaults to `False`. """ def __init__(self, inplace=False): super().__init__() if digit_version(TORCH_VERSION) <= digit_version('1.6.0') and inplace: mmengine.print_log( 'Inplace version of \'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.') self.inplace = inplace def forward(self, x): """Forward function for SiLU. Args: x (torch.Tensor): Input tensor. Returns: torch.Tensor: Tensor after activation. """ if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): return x * torch.sigmoid(x) return F.silu(x, inplace=self.inplace) @MODELS.register_module() class MultiHeadAttention(BaseModule): """An attention block allows spatial position to attend to each other. Originally ported from here, but adapted to the N-d case. https://github.com/hojonathanho/diffusion/blob/1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66. # noqa Args: in_channels (int): Channels of the input feature map. num_heads (int, optional): Number of heads in the attention. norm_cfg (dict, optional): Config for normalization layer. Default to ``dict(type='GN', num_groups=32)`` """ def __init__(self, in_channels, num_heads=1, norm_cfg=dict(type='GN', num_groups=32)): super().__init__() self.num_heads = num_heads _, self.norm = build_norm_layer(norm_cfg, in_channels) self.qkv = nn.Conv1d(in_channels, in_channels * 3, 1) self.proj = nn.Conv1d(in_channels, in_channels, 1) self.init_weights() @staticmethod def QKVAttention(qkv): channel = qkv.shape[1] // 3 q, k, v = torch.chunk(qkv, 3, dim=1) scale = 1 / np.sqrt(np.sqrt(channel)) weight = torch.einsum('bct,bcs->bts', q * scale, k * scale) weight = torch.softmax(weight.float(), dim=-1).type(weight.dtype) weight = torch.einsum('bts,bcs->bct', weight, v) return weight def forward(self, x): """Forward function for multi head attention. Args: x (torch.Tensor): Input feature map. Returns: torch.Tensor: Feature map after attention. """ b, c, *spatial = x.shape x = x.reshape(b, c, -1) qkv = self.qkv(self.norm(x)) qkv = qkv.reshape(b * self.num_heads, -1, qkv.shape[2]) h = self.QKVAttention(qkv) h = h.reshape(b, -1, h.shape[-1]) h = self.proj(h) return (h + x).reshape(b, c, *spatial) def init_weights(self): constant_init(self.proj, 0) @MODELS.register_module() class MultiHeadAttentionBlock(BaseModule): """An attention block that allows spatial positions to attend to each other. Originally ported from here, but adapted to the N-d case. https://github.com/hojonathanho/diffusion/blob/1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66. """ def __init__(self, in_channels, num_heads=1, num_head_channels=-1, use_new_attention_order=False, norm_cfg=dict(type='GN32', num_groups=32), encoder_channels=None): super().__init__() self.in_channels = in_channels if num_head_channels == -1: self.num_heads = num_heads else: assert (in_channels % num_head_channels == 0), ( f'q,k,v channels {in_channels} is not divisible by ' 'num_head_channels {num_head_channels}') self.num_heads = in_channels // num_head_channels _, self.norm = build_norm_layer(norm_cfg, in_channels) self.qkv = nn.Conv1d(in_channels, in_channels * 3, 1) if use_new_attention_order: # split qkv before split heads self.attention = QKVAttention(self.num_heads) else: # split heads before split qkv self.attention = QKVAttentionLegacy(self.num_heads) self.proj_out = nn.Conv1d(in_channels, in_channels, 1) if encoder_channels is not None: self.encoder_kv = nn.Conv1d(encoder_channels, in_channels * 2, 1) def forward(self, x, encoder_out=None): b, c, *spatial = x.shape x = x.reshape(b, c, -1) qkv = self.qkv(self.norm(x)) if encoder_out is not None: encoder_out = self.encoder_kv(encoder_out) h = self.attention(qkv, encoder_out) else: h = self.attention(qkv) h = self.proj_out(h) return (x + h).reshape(b, c, *spatial) @MODELS.register_module() class QKVAttentionLegacy(BaseModule): """A module which performs QKV attention. Matches legacy QKVAttention + input/output heads shaping """ def __init__(self, n_heads): super().__init__() self.n_heads = n_heads def forward(self, qkv, encoder_kv=None): """Apply QKV attention. :param qkv: an [N x (H * 3 * C) x T] tensor of Qs, Ks, and Vs. :return: an [N x (H * C) x T] tensor after attention. """ bs, width, length = qkv.shape assert width % (3 * self.n_heads) == 0 ch = width // (3 * self.n_heads) q, k, v = qkv.reshape(bs * self.n_heads, ch * 3, length).split( ch, dim=1) if encoder_kv is not None: assert encoder_kv.shape[1] == self.n_heads * ch * 2 ek, ev = encoder_kv.reshape(bs * self.n_heads, ch * 2, -1).split( ch, dim=1) k = torch.cat([ek, k], dim=-1) v = torch.cat([ev, v], dim=-1) scale = 1 / math.sqrt(math.sqrt(ch)) weight = torch.einsum( 'bct,bcs->bts', q * scale, k * scale) # More stable with f16 than dividing afterwards weight = torch.softmax(weight.float(), dim=-1).type(weight.dtype) a = torch.einsum('bts,bcs->bct', weight, v) return a.reshape(bs, -1, length) @MODELS.register_module() class QKVAttention(BaseModule): """A module which performs QKV attention and splits in a different order.""" def __init__(self, n_heads): super().__init__() self.n_heads = n_heads def forward(self, qkv): """Apply QKV attention. :param qkv: an [N x (3 * H * C) x T] tensor of Qs, Ks, and Vs. :return: an [N x (H * C) x T] tensor after attention. """ bs, width, length = qkv.shape assert width % (3 * self.n_heads) == 0 ch = width // (3 * self.n_heads) q, k, v = qkv.chunk(3, dim=1) scale = 1 / math.sqrt(math.sqrt(ch)) weight = torch.einsum( 'bct,bcs->bts', (q * scale).view(bs * self.n_heads, ch, length), (k * scale).view(bs * self.n_heads, ch, length), ) # More stable with f16 than dividing afterwards weight = torch.softmax(weight.float(), dim=-1).type(weight.dtype) a = torch.einsum('bts,bcs->bct', weight, v.reshape(bs * self.n_heads, ch, length)) return a.reshape(bs, -1, length) @MODELS.register_module() class TimeEmbedding(BaseModule): """Time embedding layer, reference to Two level embedding. First embedding time by an embedding function, then feed to neural networks. Args: in_channels (int): The channel number of the input feature map. embedding_channels (int): The channel number of the output embedding. embedding_mode (str, optional): Embedding mode for the time embedding. Defaults to 'sin'. embedding_cfg (dict, optional): Config for time embedding. Defaults to None. act_cfg (dict, optional): Config for activation layer. Defaults to ``dict(type='SiLU', inplace=False)``. """ def __init__(self, in_channels, embedding_channels, embedding_mode='sin', embedding_cfg=None, act_cfg=dict(type='SiLU', inplace=False)): super().__init__() self.blocks = nn.Sequential( nn.Linear(in_channels, embedding_channels), MODELS.build(act_cfg), nn.Linear(embedding_channels, embedding_channels)) # add `dim` to embedding config embedding_cfg_ = dict(dim=in_channels) if embedding_cfg is not None: embedding_cfg_.update(embedding_cfg) if embedding_mode.upper() == 'SIN': self.embedding_fn = partial(self.sinusodial_embedding, **embedding_cfg_) else: raise ValueError('Only support `SIN` for time embedding, ' f'but receive {embedding_mode}.') @staticmethod def sinusodial_embedding(timesteps, dim, max_period=10000): """Create sinusoidal timestep embeddings. Args: timesteps (torch.Tensor): Timestep to embedding. 1-D tensor shape as ``[bz, ]``, one per batch element. dim (int): The dimension of the embedding. max_period (int, optional): Controls the minimum frequency of the embeddings. Defaults to ``10000``. Returns: torch.Tensor: Embedding results shape as `[bz, dim]`. """ half = dim // 2 freqs = torch.exp( -np.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half).to(device=timesteps.device) args = timesteps[:, None].float() * freqs[None] embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) if dim % 2: embedding = torch.cat( [embedding, torch.zeros_like(embedding[:, :1])], dim=-1) return embedding def forward(self, t): """Forward function for time embedding layer. Args: t (torch.Tensor): Input timesteps. Returns: torch.Tensor: Timesteps embedding. """ return self.blocks(self.embedding_fn(t)) @MODELS.register_module() class DenoisingResBlock(BaseModule): """Resblock for the denoising network. If `in_channels` not equals to `out_channels`, a learnable shortcut with conv layers will be added. Args: in_channels (int): Number of channels of the input feature map. embedding_channels (int): Number of channels of the input embedding. use_scale_shift_norm (bool): Whether use scale-shift-norm in `NormWithEmbedding` layer. dropout (float): Probability of the dropout layers. out_channels (int, optional): Number of output channels of the ResBlock. If not defined, the output channels will equal to the `in_channels`. Defaults to `None`. norm_cfg (dict, optional): The config for the normalization layers. Defaults too ``dict(type='GN', num_groups=32)``. act_cfg (dict, optional): The config for the activation layers. Defaults to ``dict(type='SiLU', inplace=False)``. shortcut_kernel_size (int, optional): The kernel size for the shortcut conv. Defaults to ``1``. """ def __init__(self, in_channels, embedding_channels, use_scale_shift_norm, dropout, out_channels=None, norm_cfg=dict(type='GN', num_groups=32), act_cfg=dict(type='SiLU', inplace=False), shortcut_kernel_size=1, up=False, down=False): super().__init__() out_channels = in_channels if out_channels is None else out_channels _norm_cfg = deepcopy(norm_cfg) _, norm_1 = build_norm_layer(_norm_cfg, in_channels) conv_1 = [ norm_1, MODELS.build(act_cfg), nn.Conv2d(in_channels, out_channels, 3, padding=1) ] self.conv_1 = nn.Sequential(*conv_1) norm_with_embedding_cfg = dict( in_channels=out_channels, embedding_channels=embedding_channels, use_scale_shift=use_scale_shift_norm, norm_cfg=_norm_cfg) self.norm_with_embedding = MODELS.build( dict(type='NormWithEmbedding'), default_args=norm_with_embedding_cfg) conv_2 = [ MODELS.build(act_cfg), nn.Dropout(dropout), nn.Conv2d(out_channels, out_channels, 3, padding=1) ] self.conv_2 = nn.Sequential(*conv_2) assert shortcut_kernel_size in [ 1, 3 ], ('Only support `1` and `3` for `shortcut_kernel_size`, but ' f'receive {shortcut_kernel_size}.') self.learnable_shortcut = out_channels != in_channels if self.learnable_shortcut: shortcut_padding = 1 if shortcut_kernel_size == 3 else 0 self.shortcut = nn.Conv2d( in_channels, out_channels, shortcut_kernel_size, padding=shortcut_padding) self.updown = up or down if up: self.h_upd = DenoisingUpsample(in_channels, False) self.x_upd = DenoisingUpsample(in_channels, False) elif down: self.h_upd = DenoisingDownsample(in_channels, False) self.x_upd = DenoisingDownsample(in_channels, False) else: self.h_upd = self.x_upd = nn.Identity() self.init_weights() def forward_shortcut(self, x): if self.learnable_shortcut: return self.shortcut(x) return x def forward(self, x, y): """Forward function. Args: x (torch.Tensor): Input feature map tensor. y (torch.Tensor): Shared time embedding or shared label embedding. Returns: torch.Tensor : Output feature map tensor. """ if self.updown: in_rest, in_conv = self.conv_1[:-1], self.conv_1[-1] h = in_rest(x) h = self.h_upd(h) x = self.x_upd(x) h = in_conv(h) else: h = self.conv_1(x) shortcut = self.forward_shortcut(x) h = self.norm_with_embedding(h, y) h = self.conv_2(h) return h + shortcut def init_weights(self): # apply zero init to last conv layer constant_init(self.conv_2[-1], 0) @MODELS.register_module() class NormWithEmbedding(BaseModule): """Nornalization with embedding layer. If `use_scale_shift == True`, embedding results will be chunked and used to re-shift and re-scale normalization results. Otherwise, embedding results will directly add to input of normalization layer. Args: in_channels (int): Number of channels of the input feature map. embedding_channels (int) Number of channels of the input embedding. norm_cfg (dict, optional): Config for the normalization operation. Defaults to `dict(type='GN', num_groups=32)`. act_cfg (dict, optional): Config for the activation layer. Defaults to `dict(type='SiLU', inplace=False)`. use_scale_shift (bool): If True, the output of Embedding layer will be split to 'scale' and 'shift' and map the output of normalization layer to ``out * (1 + scale) + shift``. Otherwise, the output of Embedding layer will be added with the input before normalization operation. Defaults to True. """ def __init__(self, in_channels, embedding_channels, norm_cfg=dict(type='GN', num_groups=32), act_cfg=dict(type='SiLU', inplace=False), use_scale_shift=True): super().__init__() self.use_scale_shift = use_scale_shift _, self.norm = build_norm_layer(norm_cfg, in_channels) embedding_output = in_channels * 2 if use_scale_shift else in_channels self.embedding_layer = nn.Sequential( MODELS.build(act_cfg), nn.Linear(embedding_channels, embedding_output)) def forward(self, x, y): """Forward function. Args: x (torch.Tensor): Input feature map tensor. y (torch.Tensor): Shared time embedding or shared label embedding. Returns: torch.Tensor : Output feature map tensor. """ embedding = self.embedding_layer(y).type(x.dtype) embedding = embedding[:, :, None, None] if self.use_scale_shift: scale, shift = torch.chunk(embedding, 2, dim=1) x = self.norm(x) x = x * (1 + scale) + shift else: x = self.norm(x + embedding) return x @MODELS.register_module() class DenoisingDownsample(BaseModule): """Downsampling operation used in the denoising network. Support average pooling and convolution for downsample operation. Args: in_channels (int): Number of channels of the input feature map to be downsampled. with_conv (bool, optional): Whether use convolution operation for downsampling. Defaults to `True`. """ def __init__(self, in_channels, with_conv=True): super().__init__() if with_conv: self.downsample = nn.Conv2d(in_channels, in_channels, 3, 2, 1) else: self.downsample = nn.AvgPool2d(kernel_size=2, stride=2) def forward(self, x): """Forward function for downsampling operation. Args: x (torch.Tensor): Feature map to downsample. Returns: torch.Tensor: Feature map after downsampling. """ return self.downsample(x) @MODELS.register_module() class DenoisingUpsample(BaseModule): """Upsampling operation used in the denoising network. Allows users to apply an additional convolution layer after the nearest interpolation operation. Args: in_channels (int): Number of channels of the input feature map to be downsampled. with_conv (bool, optional): Whether apply an additional convolution layer after upsampling. Defaults to `True`. """ def __init__(self, in_channels, with_conv=True): super().__init__() self.with_conv = with_conv if with_conv: self.conv = nn.Conv2d(in_channels, in_channels, 3, 1, 1) def forward(self, x): """Forward function for upsampling operation. Args: x (torch.Tensor): Feature map to upsample. Returns: torch.Tensor: Feature map after upsampling. """ x = F.interpolate(x, scale_factor=2, mode='nearest') if self.with_conv: x = self.conv(x) return x def build_down_block_resattn(resblocks_per_downsample, resblock_cfg, in_channels_, out_channels_, attention_scale, attention_cfg, in_channels_list, level, channel_factor_list, embedding_channels, use_scale_shift_norm, dropout, norm_cfg, resblock_updown, downsample_cfg, scale): """build unet down path blocks with resnet and attention.""" in_blocks = nn.ModuleList() for _ in range(resblocks_per_downsample): layers = [ MODELS.build( resblock_cfg, default_args={ 'in_channels': in_channels_, 'out_channels': out_channels_ }) ] in_channels_ = out_channels_ if scale in attention_scale: layers.append( MODELS.build( attention_cfg, default_args={'in_channels': in_channels_})) in_channels_list.append(in_channels_) in_blocks.append(EmbedSequential(*layers)) if level != len(channel_factor_list) - 1: in_blocks.append( EmbedSequential( DenoisingResBlock( out_channels_, embedding_channels, use_scale_shift_norm, dropout, norm_cfg=norm_cfg, out_channels=out_channels_, down=True) if resblock_updown else MODELS.build( downsample_cfg, default_args={'in_channels': in_channels_}))) in_channels_list.append(in_channels_) scale *= 2 return in_blocks, scale def build_mid_blocks_resattn(resblock_cfg, attention_cfg, in_channels_): """build unet mid blocks with resnet and attention.""" return EmbedSequential( MODELS.build(resblock_cfg, default_args={'in_channels': in_channels_}), MODELS.build( attention_cfg, default_args={'in_channels': in_channels_}), MODELS.build(resblock_cfg, default_args={'in_channels': in_channels_}), ) def build_up_blocks_resattn( resblocks_per_downsample, resblock_cfg, in_channels_, in_channels_list, base_channels, factor, scale, attention_scale, attention_cfg, channel_factor_list, level, embedding_channels, use_scale_shift_norm, dropout, norm_cfg, resblock_updown, upsample_cfg, ): """build up path blocks with resnet and attention.""" out_blocks = nn.ModuleList() for idx in range(resblocks_per_downsample + 1): layers = [ MODELS.build( resblock_cfg, default_args={ 'in_channels': in_channels_ + in_channels_list.pop(), 'out_channels': int(base_channels * factor) }) ] in_channels_ = int(base_channels * factor) if scale in attention_scale: layers.append( MODELS.build( attention_cfg, default_args={'in_channels': in_channels_})) if (level != len(channel_factor_list) - 1 and idx == resblocks_per_downsample): out_channels_ = in_channels_ layers.append( DenoisingResBlock( in_channels_, embedding_channels, use_scale_shift_norm, dropout, norm_cfg=norm_cfg, out_channels=out_channels_, up=True) if resblock_updown else MODELS. build( upsample_cfg, default_args={'in_channels': in_channels_})) scale //= 2 out_blocks.append(EmbedSequential(*layers)) return out_blocks, in_channels_, scale @MODELS.register_module() class DenoisingUnet(BaseModule): """Denoising Unet. This network receives a diffused image ``x_t`` and current timestep ``t``, and returns a ``output_dict`` corresponding to the passed ``output_cfg``. ``output_cfg`` defines the number of channels and the meaning of the output. ``output_cfg`` mainly contains keys of ``mean`` and ``var``, denoting how the network outputs mean and variance required for the denoising process. For ``mean``: 1. ``dict(mean='EPS')``: Model will predict noise added in the diffusion process, and the ``output_dict`` will contain a key named ``eps_t_pred``. 2. ``dict(mean='START_X')``: Model will direct predict the mean of the original image `x_0`, and the ``output_dict`` will contain a key named ``x_0_pred``. 3. ``dict(mean='X_TM1_PRED')``: Model will predict the mean of diffused image at `t-1` timestep, and the ``output_dict`` will contain a key named ``x_tm1_pred``. For ``var``: 1. ``dict(var='FIXED_SMALL')`` or ``dict(var='FIXED_LARGE')``: Variance in the denoising process is regarded as a fixed value. Therefore only 'mean' will be predicted, and the output channels will equal to the input image (e.g., three channels for RGB image.) 2. ``dict(var='LEARNED')``: Model will predict `log_variance` in the denoising process, and the ``output_dict`` will contain a key named ``log_var``. 3. ``dict(var='LEARNED_RANGE')``: Model will predict an interpolation factor and the `log_variance` will be calculated as `factor * upper_bound + (1-factor) * lower_bound`. The ``output_dict`` will contain a key named ``factor``. If ``var`` is not ``FIXED_SMALL`` or ``FIXED_LARGE``, the number of output channels will be the double of input channels, where the first half part contains predicted mean values and the other part is the predicted variance values. Otherwise, the number of output channels equals to the input channels, only containing the predicted mean values. Args: image_size (int | list[int]): The size of image to denoise. in_channels (int, optional): The input channels of the input image. Defaults as ``3``. out_channels (int, optional): The output channels of the output prediction. Defaults as ``None`` for automaticaaly assigned by ``var_mode``. base_channels (int, optional): The basic channel number of the generator. The other layers contain channels based on this number. Defaults to ``128``. resblocks_per_downsample (int, optional): Number of ResBlock used between two downsample operations. The number of ResBlock between upsample operations will be the same value to keep symmetry. Defaults to 3. num_timesteps (int, optional): The total timestep of the denoising process and the diffusion process. Defaults to ``1000``. use_rescale_timesteps (bool, optional): Whether rescale the input timesteps in range of [0, 1000]. Defaults to ``True``. dropout (float, optional): The probability of dropout operation of each ResBlock. Pass ``0`` to do not use dropout. Defaults as 0. embedding_channels (int, optional): The output channels of time embedding layer and label embedding layer. If not passed (or passed ``-1``), output channels of the embedding layers will set as four times of ``base_channels``. Defaults to ``-1``. num_classes (int, optional): The number of conditional classes. If set to 0, this model will be degraded to an unconditional model. Defaults to 0. channels_cfg (list | dict[list], optional): Config for input channels of the intermediate blocks. If list is passed, each element of the list indicates the scale factor for the input channels of the current block with regard to the ``base_channels``. For block ``i``, the input and output channels should be ``channels_cfg[i] * base_channels`` and ``channels_cfg[i+1] * base_channels`` If dict is provided, the key of the dict should be the output scale and corresponding value should be a list to define channels. Default: Please refer to ``_default_channels_cfg``. output_cfg (dict, optional): Config for output variables. Defaults to ``dict(mean='eps', var='learned_range')``. norm_cfg (dict, optional): The config for normalization layers. Defaults to ``dict(type='GN', num_groups=32)``. act_cfg (dict, optional): The config for activation layers. Defaults to ``dict(type='SiLU', inplace=False)``. shortcut_kernel_size (int, optional): The kernel size for shortcut conv in ResBlocks. The value of this argument will overwrite the default value of `resblock_cfg`. Defaults to `3`. use_scale_shift_norm (bool, optional): Whether perform scale and shift after normalization operation. Defaults to True. num_heads (int, optional): The number of attention heads. Defaults to 4. time_embedding_mode (str, optional): Embedding method of ``time_embedding``. Defaults to 'sin'. time_embedding_cfg (dict, optional): Config for ``time_embedding``. Defaults to None. resblock_cfg (dict, optional): Config for ResBlock. Defaults to ``dict(type='DenoisingResBlock')``. attention_cfg (dict, optional): Config for attention operation. Defaults to ``dict(type='MultiHeadAttention')``. upsample_conv (bool, optional): Whether use conv in upsample block. Defaults to ``True``. downsample_conv (bool, optional): Whether use conv operation in downsample block. Defaults to ``True``. upsample_cfg (dict, optional): Config for upsample blocks. Defaults to ``dict(type='DenoisingDownsample')``. downsample_cfg (dict, optional): Config for downsample blocks. Defaults to ``dict(type='DenoisingUpsample')``. attention_res (int | list[int], optional): Resolution of feature maps to apply attention operation. Defaults to ``[16, 8]``. pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ _default_channels_cfg = { 512: [0.5, 1, 1, 2, 2, 4, 4], 256: [1, 1, 2, 2, 4, 4], 128: [1, 1, 2, 3, 4], 64: [1, 2, 3, 4], 32: [1, 2, 2, 2] } def __init__(self, image_size, in_channels=3, out_channels=None, base_channels=128, resblocks_per_downsample=3, num_timesteps=1000, use_rescale_timesteps=False, dropout=0, embedding_channels=-1, num_classes=0, use_fp16=False, channels_cfg=None, output_cfg=dict(mean='eps', var='learned_range'), norm_cfg=dict(type='GN', num_groups=32), act_cfg=dict(type='SiLU', inplace=False), shortcut_kernel_size=1, use_scale_shift_norm=False, resblock_updown=False, num_heads=4, time_embedding_mode='sin', time_embedding_cfg=None, resblock_cfg=dict(type='DenoisingResBlock'), attention_cfg=dict(type='MultiHeadAttention'), encoder_channels=None, downsample_conv=True, upsample_conv=True, downsample_cfg=dict(type='DenoisingDownsample'), upsample_cfg=dict(type='DenoisingUpsample'), attention_res=[16, 8], pretrained=None, unet_type='', down_block_types: Tuple[str] = (), up_block_types: Tuple[str] = (), cross_attention_dim=768, layers_per_block: int = 2): super().__init__() self.unet_type = unet_type self.num_classes = num_classes self.num_timesteps = num_timesteps self.base_channels = base_channels self.encoder_channels = encoder_channels self.use_rescale_timesteps = use_rescale_timesteps self.dtype = torch.float16 if use_fp16 else torch.float32 self.output_cfg = deepcopy(output_cfg) self.mean_mode = self.output_cfg.get('mean', 'eps') self.var_mode = self.output_cfg.get('var', 'learned_range') self.in_channels = in_channels # double output_channels to output mean and var at same time if out_channels is None: out_channels = in_channels if 'FIXED' in self.var_mode.upper() \ else 2 * in_channels self.out_channels = out_channels # check type of image_size if not isinstance(image_size, int) and not isinstance( image_size, list): raise TypeError( 'Only support `int` and `list[int]` for `image_size`.') if isinstance(image_size, list): assert len( image_size) == 2, 'The length of `image_size` should be 2.' assert image_size[0] == image_size[ 1], 'Width and height of the image should be same.' image_size = image_size[0] self.image_size = image_size channels_cfg = deepcopy(self._default_channels_cfg) \ if channels_cfg is None else deepcopy(channels_cfg) if isinstance(channels_cfg, dict): if image_size not in channels_cfg: raise KeyError(f'`image_size={image_size} is not found in ' '`channels_cfg`, only support configs for ' f'{[chn for chn in channels_cfg.keys()]}') self.channel_factor_list = channels_cfg[image_size] elif isinstance(channels_cfg, list): self.channel_factor_list = channels_cfg else: raise ValueError('Only support list or dict for `channels_cfg`, ' f'receive {type(channels_cfg)}') embedding_channels = base_channels * 4 \ if embedding_channels == -1 else embedding_channels # init the channel scale factor scale = 1 ch = int(base_channels * self.channel_factor_list[0]) self.in_channels_list = [ch] if self.unet_type == 'stable': # time self.time_proj = Timesteps(ch) self.time_embedding = TimestepEmbedding(base_channels, embedding_channels) self.conv_in = nn.Conv2d( in_channels, ch, kernel_size=3, padding=(1, 1)) else: self.time_embedding = TimeEmbedding( base_channels, embedding_channels=embedding_channels, embedding_mode=time_embedding_mode, embedding_cfg=time_embedding_cfg, act_cfg=act_cfg) self.in_blocks = nn.ModuleList( [EmbedSequential(nn.Conv2d(in_channels, ch, 3, 1, padding=1))]) if self.num_classes != 0: self.label_embedding = nn.Embedding(self.num_classes, embedding_channels) self.resblock_cfg = deepcopy(resblock_cfg) self.resblock_cfg.setdefault('dropout', dropout) self.resblock_cfg.setdefault('norm_cfg', norm_cfg) self.resblock_cfg.setdefault('act_cfg', act_cfg) self.resblock_cfg.setdefault('embedding_channels', embedding_channels) self.resblock_cfg.setdefault('use_scale_shift_norm', use_scale_shift_norm) self.resblock_cfg.setdefault('shortcut_kernel_size', shortcut_kernel_size) # get scales of ResBlock to apply attention attention_scale = [image_size // int(res) for res in attention_res] self.attention_cfg = deepcopy(attention_cfg) self.attention_cfg.setdefault('num_heads', num_heads) self.attention_cfg.setdefault('norm_cfg', norm_cfg) self.downsample_cfg = deepcopy(downsample_cfg) self.downsample_cfg.setdefault('with_conv', downsample_conv) self.upsample_cfg = deepcopy(upsample_cfg) self.upsample_cfg.setdefault('with_conv', upsample_conv) self.down_blocks = nn.ModuleList([]) self.mid_block = None self.up_blocks = nn.ModuleList([]) attention_head_dim = (num_heads, ) * len(down_block_types) # construct the encoder part of Unet for level, factor in enumerate(self.channel_factor_list): in_channels_ = ch if level == 0 \ else int(base_channels * self.channel_factor_list[level - 1]) out_channels_ = int(base_channels * factor) if self.unet_type == 'stable': is_final_block = level == len(self.channel_factor_list) - 1 down_block_type = down_block_types[level] down_block = get_down_block( down_block_type, num_layers=layers_per_block, in_channels=in_channels_, out_channels=out_channels_, temb_channels=embedding_channels, cross_attention_dim=cross_attention_dim, add_downsample=not is_final_block, resnet_act_fn=act_cfg['type'], resnet_groups=norm_cfg['num_groups'], attn_num_head_channels=attention_head_dim[level], ) self.down_blocks.append(down_block) else: in_blocks, scale = build_down_block_resattn( resblocks_per_downsample=resblocks_per_downsample, resblock_cfg=self.resblock_cfg, in_channels_=in_channels_, out_channels_=out_channels_, attention_scale=attention_scale, attention_cfg=self.attention_cfg, in_channels_list=self.in_channels_list, level=level, channel_factor_list=self.channel_factor_list, embedding_channels=embedding_channels, use_scale_shift_norm=use_scale_shift_norm, dropout=dropout, norm_cfg=norm_cfg, resblock_updown=resblock_updown, downsample_cfg=self.downsample_cfg, scale=scale) self.in_blocks.extend(in_blocks) # construct the bottom part of Unet block_out_channels = [ times * base_channels for times in self.channel_factor_list ] in_channels_ = self.in_channels_list[-1] if self.unet_type == 'stable': self.mid_block = UNetMidBlock2DCrossAttn( in_channels=block_out_channels[-1], temb_channels=embedding_channels, cross_attention_dim=cross_attention_dim, resnet_act_fn=act_cfg['type'], resnet_time_scale_shift='default', attn_num_head_channels=attention_head_dim[-1], resnet_groups=norm_cfg['num_groups'], ) else: self.mid_blocks = build_mid_blocks_resattn(self.resblock_cfg, self.attention_cfg, in_channels_) # stable up parameters self.num_upsamplers = 0 reversed_block_out_channels = list(reversed(block_out_channels)) reversed_attention_head_dim = list(reversed(attention_head_dim)) output_channel = reversed_block_out_channels[0] # construct the decoder part of Unet in_channels_list = deepcopy(self.in_channels_list) if self.unet_type != 'stable': self.out_blocks = nn.ModuleList() for level, factor in enumerate(self.channel_factor_list[::-1]): if self.unet_type == 'stable': is_final_block = level == len(block_out_channels) - 1 prev_output_channel = output_channel output_channel = reversed_block_out_channels[level] input_channel = reversed_block_out_channels[min( level + 1, len(block_out_channels) - 1)] # add upsample block for all BUT final layer if not is_final_block: add_upsample = True self.num_upsamplers += 1 else: add_upsample = False up_block_type = up_block_types[level] up_block = get_up_block( up_block_type, num_layers=layers_per_block + 1, in_channels=input_channel, out_channels=output_channel, prev_output_channel=prev_output_channel, temb_channels=embedding_channels, cross_attention_dim=cross_attention_dim, add_upsample=add_upsample, resnet_act_fn=act_cfg['type'], resnet_groups=norm_cfg['num_groups'], attn_num_head_channels=reversed_attention_head_dim[level], ) self.up_blocks.append(up_block) prev_output_channel = output_channel else: out_blocks, in_channels_, scale = build_up_blocks_resattn( resblocks_per_downsample, self.resblock_cfg, in_channels_, in_channels_list, base_channels, factor, scale, attention_scale, self.attention_cfg, self.channel_factor_list, level, embedding_channels, use_scale_shift_norm, dropout, norm_cfg, resblock_updown, self.upsample_cfg, ) self.out_blocks.extend(out_blocks) if self.unet_type == 'stable': # out self.conv_norm_out = nn.GroupNorm( num_channels=block_out_channels[0], num_groups=norm_cfg['num_groups']) if digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.conv_act = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.conv_act = nn.ReLU() self.conv_out = nn.Conv2d( block_out_channels[0], self.out_channels, kernel_size=3, padding=1) else: self.out = ConvModule( in_channels=in_channels_, out_channels=out_channels, kernel_size=3, padding=1, act_cfg=act_cfg, norm_cfg=norm_cfg, bias=True, order=('norm', 'act', 'conv')) if self.unet_type == 'stable': self.sample_size = image_size // 8 # NOTE: hard code here self.init_weights(pretrained) def forward(self, x_t, t, encoder_hidden_states=None, label=None, return_noise=False): """Forward function. Args: x_t (torch.Tensor): Diffused image at timestep `t` to denoise. t (torch.Tensor): Current timestep. label (torch.Tensor | callable | None): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. return_noise (bool, optional): If True, inputted ``x_t`` and ``t`` will be returned in a dict with output desired by ``output_cfg``. Defaults to False. Returns: torch.Tensor | dict: If not ``return_noise`` """ # By default samples have to be AT least a multiple of t # he overall upsampling factor. # The overall upsampling factor is equal # to 2 ** (# num of upsampling layers). # However, the upsampling interpolation output size # can be forced to fit any upsampling size # on the fly if necessary. default_overall_up_factor = 2**self.num_upsamplers # upsample size should be forwarded when sample is not # a multiple of `default_overall_up_factor` forward_upsample_size = False upsample_size = None if any(s % default_overall_up_factor != 0 for s in x_t.shape[-2:]): logger.info( 'Forward upsample size to force interpolation output size.') forward_upsample_size = True if not torch.is_tensor(t): t = torch.tensor([t], dtype=torch.long, device=x_t.device) elif torch.is_tensor(t) and len(t.shape) == 0: t = t[None].to(x_t.device) if self.unet_type == 'stable': # broadcast to batch dimension in a way that's # compatible with ONNX/Core ML t = t.expand(x_t.shape[0]) t_emb = self.time_proj(t) # t does not contain any weights and will always return f32 tensors # but time_embedding might actually be running in fp16. # so we need to cast here. # there might be better ways to encapsulate this. t_emb = t_emb.to(dtype=self.dtype) embedding = self.time_embedding(t_emb) else: embedding = self.time_embedding(t) if label is not None: assert hasattr(self, 'label_embedding') embedding = self.label_embedding(label) + embedding if self.unet_type == 'stable': # 2. pre-process x_t = self.conv_in(x_t) # 3. down down_block_res_samples = (x_t, ) for downsample_block in self.down_blocks: if hasattr(downsample_block, 'attentions' ) and downsample_block.attentions is not None: x_t, res_samples = downsample_block( hidden_states=x_t, temb=embedding, encoder_hidden_states=encoder_hidden_states, ) else: x_t, res_samples = downsample_block( hidden_states=x_t, temb=embedding) down_block_res_samples += res_samples # 4. mid x_t = self.mid_block( x_t, embedding, encoder_hidden_states=encoder_hidden_states) # 5. up for i, upsample_block in enumerate(self.up_blocks): is_final_block = i == len(self.up_blocks) - 1 res_samples = down_block_res_samples[-len(upsample_block. resnets):] down_block_res_samples = down_block_res_samples[:-len( upsample_block.resnets)] # if we have not reached the final block # and need to forward the upsample size, we do it here if not is_final_block and forward_upsample_size: upsample_size = down_block_res_samples[-1].shape[2:] if hasattr(upsample_block, 'attentions' ) and upsample_block.attentions is not None: x_t = upsample_block( hidden_states=x_t, temb=embedding, res_hidden_states_tuple=res_samples, encoder_hidden_states=encoder_hidden_states, upsample_size=upsample_size, ) else: x_t = upsample_block( hidden_states=x_t, temb=embedding, res_hidden_states_tuple=res_samples, upsample_size=upsample_size) # 6. post-process x_t = self.conv_norm_out(x_t) x_t = self.conv_act(x_t) x_t = self.conv_out(x_t) outputs = x_t else: h, hs = x_t, [] h = h.type(self.dtype) # forward downsample blocks for block in self.in_blocks: h = block(h, embedding) hs.append(h) # forward middle blocks h = self.mid_blocks(h, embedding) # forward upsample blocks for block in self.out_blocks: h = block(torch.cat([h, hs.pop()], dim=1), embedding) h = h.type(x_t.dtype) outputs = self.out(h) return {'sample': outputs} def init_weights(self, pretrained=None): """Init weights for models. We just use the initialization method proposed in the original paper. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: # As Improved-DDPM, we apply zero-initialization to # second conv block in ResBlock (keywords: conv_2) # the output layer of the Unet (keywords: 'out' but # not 'out_blocks') # projection layer in Attention layer (keywords: proj) for n, m in self.named_modules(): if isinstance(m, nn.Conv2d) and ('conv_2' in n or ('out' in n and 'out_blocks' not in n)): constant_init(m, 0) if isinstance(m, nn.Conv1d) and 'proj' in n: constant_init(m, 0) else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') def convert_to_fp16(self): """Convert the precision of the model to float16.""" self.in_blocks.apply(convert_module_to_f16) self.mid_blocks.apply(convert_module_to_f16) self.out_blocks.apply(convert_module_to_f16) def convert_to_fp32(self): """Convert the precision of the model to float32.""" self.in_blocks.apply(convert_module_to_f32) self.mid_blocks.apply(convert_module_to_f32) self.out_blocks.apply(convert_module_to_f32) ================================================ FILE: mmagic/models/editors/ddpm/embeddings.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import mmengine import torch from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from torch import nn class TimestepEmbedding(nn.Module): """Module which uses linear to embed timestep.""" def __init__(self, in_channels: int, time_embed_dim: int, act_fn: str = 'silu', out_dim: int = None): super().__init__() self.linear_1 = nn.Linear(in_channels, time_embed_dim) self.act = None if act_fn == 'silu' and \ digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.act = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.act = nn.ReLU() if out_dim is not None: time_embed_dim_out = out_dim else: time_embed_dim_out = time_embed_dim self.linear_2 = nn.Linear(time_embed_dim, time_embed_dim_out) def forward(self, sample): """forward with sample.""" sample = self.linear_1(sample) if self.act is not None: sample = self.act(sample) sample = self.linear_2(sample) return sample class Timesteps(nn.Module): """A module which transforms timesteps to embedding.""" def __init__(self, num_channels: int, flip_sin_to_cos: bool = True, downscale_freq_shift: float = 0): super().__init__() self.num_channels = num_channels self.flip_sin_to_cos = flip_sin_to_cos self.downscale_freq_shift = downscale_freq_shift self.max_period = 10000 self.scale = 1 def forward(self, timesteps): """forward with timesteps.""" assert len(timesteps.shape) == 1, 'Timesteps should be a 1d-array' embedding_dim = self.num_channels half_dim = embedding_dim // 2 exponent = -math.log(self.max_period) * \ torch.arange( start=0, end=half_dim, dtype=torch.float32, device=timesteps.device) exponent = exponent / (half_dim - self.downscale_freq_shift) emb = torch.exp(exponent) emb = timesteps[:, None].float() * emb[None, :] # scale embeddings emb = self.scale * emb # concat sine and cosine embeddings emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1) # flip sine and cosine embeddings if self.flip_sin_to_cos: emb = torch.cat([emb[:, half_dim:], emb[:, :half_dim]], dim=-1) # zero pad if embedding_dim % 2 == 1: emb = torch.nn.functional.pad(emb, (0, 1, 0, 0)) return emb ================================================ FILE: mmagic/models/editors/ddpm/res_blocks.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmengine import torch import torch.nn as nn import torch.nn.functional as F from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version class ResnetBlock2D(nn.Module): """resnet block support down sample and up sample. Args: in_channels (int): input channels. out_channels (int): output channels. conv_shortcut (bool): whether to use conv shortcut. dropout (float): dropout rate. temb_channels (int): time embedding channels. groups (int): conv groups. groups_out (int): conv out groups. pre_norm (bool): whether to norm before conv. Todo: remove. eps (float): eps for groupnorm. non_linearity (str): non linearity type. time_embedding_norm (str): time embedding norm type. output_scale_factor (float): factor to scale input and output. use_in_shortcut (bool): whether to use conv in shortcut. up (bool): whether to upsample. down (bool): whether to downsample. """ def __init__( self, in_channels, out_channels=None, conv_shortcut=False, dropout=0.0, temb_channels=512, groups=32, groups_out=None, pre_norm=True, eps=1e-6, non_linearity='silu', time_embedding_norm='default', output_scale_factor=1.0, use_in_shortcut=None, up=False, down=False, ): super().__init__() self.pre_norm = pre_norm self.pre_norm = True self.in_channels = in_channels out_channels = in_channels if out_channels is None else out_channels self.out_channels = out_channels self.use_conv_shortcut = conv_shortcut self.time_embedding_norm = time_embedding_norm self.up = up self.down = down self.output_scale_factor = output_scale_factor if groups_out is None: groups_out = groups self.norm1 = torch.nn.GroupNorm( num_groups=groups, num_channels=in_channels, eps=eps, affine=True) self.conv1 = torch.nn.Conv2d( in_channels, out_channels, kernel_size=3, stride=1, padding=1) if temb_channels is not None: self.time_emb_proj = torch.nn.Linear(temb_channels, out_channels) else: self.time_emb_proj = None self.norm2 = torch.nn.GroupNorm( num_groups=groups_out, num_channels=out_channels, eps=eps, affine=True) self.dropout = torch.nn.Dropout(dropout) self.conv2 = torch.nn.Conv2d( out_channels, out_channels, kernel_size=3, stride=1, padding=1) if non_linearity == 'silu' and \ digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.nonlinearity = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.nonlinearity = nn.ReLU() self.upsample = self.downsample = None if self.up: self.upsample = Upsample2D(in_channels, use_conv=False) elif self.down: self.downsample = Downsample2D( in_channels, use_conv=False, padding=1, name='op') self.use_in_shortcut = self.in_channels != self.out_channels if use_in_shortcut is None else use_in_shortcut # noqa self.conv_shortcut = None if self.use_in_shortcut: self.conv_shortcut = torch.nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0) def forward(self, input_tensor, temb): """forward with hidden states and time embeddings.""" hidden_states = input_tensor hidden_states = self.norm1(hidden_states) hidden_states = self.nonlinearity(hidden_states) if self.upsample is not None: # upsample_nearest_nhwc fails with large batch sizes. # see https://github.com/huggingface/diffusers/issues/984 if hidden_states.shape[0] >= 64: input_tensor = input_tensor.contiguous() hidden_states = hidden_states.contiguous() input_tensor = self.upsample(input_tensor) hidden_states = self.upsample(hidden_states) elif self.downsample is not None: input_tensor = self.downsample(input_tensor) hidden_states = self.downsample(hidden_states) hidden_states = self.conv1(hidden_states) if temb is not None: temb = self.time_emb_proj(self.nonlinearity(temb))[:, :, None, None] hidden_states = hidden_states + temb hidden_states = self.norm2(hidden_states) hidden_states = self.nonlinearity(hidden_states) hidden_states = self.dropout(hidden_states) hidden_states = self.conv2(hidden_states) if self.conv_shortcut is not None: input_tensor = self.conv_shortcut(input_tensor) output_tensor = (input_tensor + hidden_states) / self.output_scale_factor return output_tensor class Upsample2D(nn.Module): """An upsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. use_conv_transpose (bool): whether to use conv transpose. out_channels (int): output channels. """ def __init__(self, channels, use_conv=False, use_conv_transpose=False, out_channels=None, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.use_conv_transpose = use_conv_transpose self.name = name conv = None if use_conv: conv = nn.Conv2d(self.channels, self.out_channels, 3, padding=1) else: conv = nn.ConvTranspose2d(channels, self.out_channels, 4, 2, 1) self.conv = conv def forward(self, hidden_states, output_size=None): """forward with hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv_transpose: return self.conv(hidden_states) # if `output_size` is passed we force the interpolation output # size and do not make use of `scale_factor=2` if output_size is None: hidden_states = F.interpolate( hidden_states, scale_factor=2.0, mode='nearest') else: hidden_states = F.interpolate( hidden_states, size=output_size, mode='nearest') hidden_states = self.conv(hidden_states) return hidden_states class Downsample2D(nn.Module): """A downsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. out_channels (int): output channels padding (int): padding num """ def __init__(self, channels, use_conv=False, out_channels=None, padding=1, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.padding = padding stride = 2 self.name = name if use_conv: conv = nn.Conv2d( self.channels, self.out_channels, 3, stride=stride, padding=padding) else: assert self.channels == self.out_channels conv = nn.AvgPool2d(kernel_size=stride, stride=stride) self.conv = conv def forward(self, hidden_states): """forward with hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv and self.padding == 0: pad = (0, 1, 0, 1) hidden_states = F.pad(hidden_states, pad, mode='constant', value=0) assert hidden_states.shape[1] == self.channels hidden_states = self.conv(hidden_states) return hidden_states ================================================ FILE: mmagic/models/editors/ddpm/unet_blocks.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from torch import nn from .attention import Transformer2DModel from .res_blocks import Downsample2D, ResnetBlock2D, Upsample2D def get_down_block( down_block_type, num_layers, in_channels, out_channels, temb_channels, add_downsample, resnet_act_fn, attn_num_head_channels, resnet_eps=1e-5, resnet_groups=32, cross_attention_dim=1280, downsample_padding=1, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, ): """get unet down path block.""" down_block_type = down_block_type[7:] if down_block_type.startswith( 'UNetRes') else down_block_type if down_block_type == 'DownBlock2D': return DownBlock2D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, add_downsample=add_downsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, downsample_padding=downsample_padding, ) elif down_block_type == 'CrossAttnDownBlock2D': return CrossAttnDownBlock2D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, add_downsample=add_downsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, downsample_padding=downsample_padding, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attn_num_head_channels, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, ) raise ValueError(f'{down_block_type} does not exist.') def get_up_block( up_block_type, num_layers, in_channels, out_channels, prev_output_channel, temb_channels, add_upsample, resnet_act_fn, attn_num_head_channels, resnet_eps=1e-5, resnet_groups=32, cross_attention_dim=1280, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, ): """get unet up path block.""" up_block_type = up_block_type[7:] if up_block_type.startswith( 'UNetRes') else up_block_type if up_block_type == 'UpBlock2D': return UpBlock2D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, prev_output_channel=prev_output_channel, temb_channels=temb_channels, add_upsample=add_upsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, ) elif up_block_type == 'CrossAttnUpBlock2D': return CrossAttnUpBlock2D( num_layers=num_layers, in_channels=in_channels, out_channels=out_channels, prev_output_channel=prev_output_channel, temb_channels=temb_channels, add_upsample=add_upsample, resnet_eps=resnet_eps, resnet_act_fn=resnet_act_fn, resnet_groups=resnet_groups, cross_attention_dim=cross_attention_dim, attn_num_head_channels=attn_num_head_channels, dual_cross_attention=dual_cross_attention, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, ) raise ValueError(f'{up_block_type} does not exist.') class UNetMidBlock2DCrossAttn(nn.Module): """unet mid block built by cross attention.""" def __init__( self, in_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-5, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, attention_type='default', output_scale_factor=1.0, cross_attention_dim=1280, dual_cross_attention=False, use_linear_projection=False, ): super().__init__() self.attention_type = attention_type self.attn_num_head_channels = attn_num_head_channels resnet_groups = resnet_groups if resnet_groups is not None else min( in_channels // 4, 32) # there is always at least one resnet resnets = [ ResnetBlock2D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, ) ] attentions = [] for _ in range(num_layers): attentions.append( Transformer2DModel( attn_num_head_channels, in_channels // attn_num_head_channels, in_channels=in_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, )) resnets.append( ResnetBlock2D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) def set_attention_slice(self, slice_size): """set attention slice.""" head_dims = self.attn_num_head_channels head_dims = [head_dims] if isinstance(head_dims, int) else head_dims if slice_size is not None and any(dim % slice_size != 0 for dim in head_dims): raise ValueError( f'Make sure slice_size {slice_size} is a common divisor of ' f'the number of heads used in cross_attention: {head_dims}') for attn in self.attentions: attn._set_attention_slice(slice_size) def forward(self, hidden_states, temb=None, encoder_hidden_states=None): """forward with hidden states.""" hidden_states = self.resnets[0](hidden_states, temb) for attn, resnet in zip(self.attentions, self.resnets[1:]): hidden_states = attn(hidden_states, encoder_hidden_states).sample hidden_states = resnet(hidden_states, temb) return hidden_states class CrossAttnDownBlock2D(nn.Module): """Down block built by cross attention.""" def __init__( self, in_channels: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-5, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, cross_attention_dim=1280, attention_type='default', output_scale_factor=1.0, downsample_padding=1, add_downsample=True, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, ): super().__init__() resnets = [] attentions = [] self.attention_type = attention_type self.attn_num_head_channels = attn_num_head_channels for i in range(num_layers): in_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) attentions.append( Transformer2DModel( attn_num_head_channels, out_channels // attn_num_head_channels, in_channels=out_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, )) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) if add_downsample: self.downsamplers = nn.ModuleList([ Downsample2D( out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name='op') ]) else: self.downsamplers = None self.gradient_checkpointing = False def set_attention_slice(self, slice_size): """set attention slice.""" head_dims = self.attn_num_head_channels head_dims = [head_dims] if isinstance(head_dims, int) else head_dims if slice_size is not None and any(dim % slice_size != 0 for dim in head_dims): raise ValueError( f'Make sure slice_size {slice_size} is a common divisor of ' f'the number of heads used in cross_attention: {head_dims}') for attn in self.attentions: attn._set_attention_slice(slice_size) def forward(self, hidden_states, temb=None, encoder_hidden_states=None): """forward with hidden states.""" output_states = () for resnet, attn in zip(self.resnets, self.attentions): hidden_states = resnet(hidden_states, temb) hidden_states = attn( hidden_states, encoder_hidden_states=encoder_hidden_states).sample output_states += (hidden_states, ) if self.downsamplers is not None: for downsampler in self.downsamplers: hidden_states = downsampler(hidden_states) output_states += (hidden_states, ) return hidden_states, output_states class DownBlock2D(nn.Module): """Down block built by resnet.""" def __init__( self, in_channels: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-5, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_downsample=True, downsample_padding=1, ): super().__init__() resnets = [] for i in range(num_layers): in_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=in_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.resnets = nn.ModuleList(resnets) if add_downsample: self.downsamplers = nn.ModuleList([ Downsample2D( out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name='op') ]) else: self.downsamplers = None self.gradient_checkpointing = False def forward(self, hidden_states, temb=None): """forward with hidden states.""" output_states = () for resnet in self.resnets: hidden_states = resnet(hidden_states, temb) output_states += (hidden_states, ) if self.downsamplers is not None: for downsampler in self.downsamplers: hidden_states = downsampler(hidden_states) output_states += (hidden_states, ) return hidden_states, output_states class CrossAttnUpBlock2D(nn.Module): """Up block built by cross attention.""" def __init__( self, in_channels: int, out_channels: int, prev_output_channel: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-5, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, cross_attention_dim=1280, attention_type='default', output_scale_factor=1.0, add_upsample=True, dual_cross_attention=False, use_linear_projection=False, only_cross_attention=False, ): super().__init__() resnets = [] attentions = [] self.attention_type = attention_type self.attn_num_head_channels = attn_num_head_channels for i in range(num_layers): res_skip_channels = in_channels if (i == num_layers - 1) else out_channels resnet_in_channels = \ prev_output_channel if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=resnet_in_channels + res_skip_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) attentions.append( Transformer2DModel( attn_num_head_channels, out_channels // attn_num_head_channels, in_channels=out_channels, num_layers=1, cross_attention_dim=cross_attention_dim, norm_num_groups=resnet_groups, use_linear_projection=use_linear_projection, only_cross_attention=only_cross_attention, )) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) if add_upsample: self.upsamplers = nn.ModuleList([ Upsample2D( out_channels, use_conv=True, out_channels=out_channels) ]) else: self.upsamplers = None self.gradient_checkpointing = False def set_attention_slice(self, slice_size): """set attention slice.""" head_dims = self.attn_num_head_channels head_dims = [head_dims] if isinstance(head_dims, int) else head_dims if slice_size is not None and any(dim % slice_size != 0 for dim in head_dims): raise ValueError( f'Make sure slice_size {slice_size} is a common divisor of ' f'the number of heads used in cross_attention: {head_dims}') for attn in self.attentions: attn._set_attention_slice(slice_size) self.gradient_checkpointing = False def forward( self, hidden_states, res_hidden_states_tuple, temb=None, encoder_hidden_states=None, upsample_size=None, ): """forward with hidden states and res hidden states.""" for resnet, attn in zip(self.resnets, self.attentions): # pop res hidden states res_hidden_states = res_hidden_states_tuple[-1] res_hidden_states_tuple = res_hidden_states_tuple[:-1] hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) hidden_states = resnet(hidden_states, temb) hidden_states = attn( hidden_states, encoder_hidden_states=encoder_hidden_states).sample if self.upsamplers is not None: for upsampler in self.upsamplers: hidden_states = upsampler(hidden_states, upsample_size) return hidden_states class UpBlock2D(nn.Module): """Up block built by resnet.""" def __init__( self, in_channels: int, prev_output_channel: int, out_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-5, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_upsample=True, ): super().__init__() resnets = [] for i in range(num_layers): res_skip_channels = in_channels if (i == num_layers - 1) else out_channels resnet_in_channels = \ prev_output_channel if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=resnet_in_channels + res_skip_channels, out_channels=out_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.resnets = nn.ModuleList(resnets) if add_upsample: self.upsamplers = nn.ModuleList([ Upsample2D( out_channels, use_conv=True, out_channels=out_channels) ]) else: self.upsamplers = None self.gradient_checkpointing = False def forward(self, hidden_states, res_hidden_states_tuple, temb=None, upsample_size=None): """forward with hidden states and res hidden states.""" for resnet in self.resnets: # pop res hidden states res_hidden_states = res_hidden_states_tuple[-1] res_hidden_states_tuple = res_hidden_states_tuple[:-1] hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) hidden_states = resnet(hidden_states, temb) if self.upsamplers is not None: for upsampler in self.upsamplers: hidden_states = upsampler(hidden_states, upsample_size) return hidden_states ================================================ FILE: mmagic/models/editors/deblurganv2/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .deblurganv2 import DeblurGanV2 from .deblurganv2_discriminator import DeblurGanV2Discriminator from .deblurganv2_generator import DeblurGanV2Generator __all__ = ['DeblurGanV2', 'DeblurGanV2Generator', 'DeblurGanV2Discriminator'] ================================================ FILE: mmagic/models/editors/deblurganv2/deblurganv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from typing import Dict, List, Optional, Union import torch from mmengine.model import BaseModel from mmengine.optim import OptimWrapperDict from torch import nn from mmagic.models.losses import AdvLoss from mmagic.registry import MODELS from mmagic.structures import DataSample ModelType = Union[Dict, nn.Module] @MODELS.register_module() class DeblurGanV2(BaseModel): def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, pixel_loss: Optional[Union[dict, str]] = None, disc_loss: Optional[Union[dict, str]] = None, adv_lambda: float = 0.001, warmup_num: int = 3, train_cfg: Optional[dict] = None, test_cfg: Optional[dict] = None, init_cfg: Optional[dict] = None, data_preprocessor: Optional[dict] = None): super().__init__( init_cfg=init_cfg, data_preprocessor=data_preprocessor) if isinstance(generator, dict): self.generator = MODELS.build(generator) else: self.generator = generator if discriminator: if isinstance(generator, dict): self.discriminator = MODELS.build(discriminator) else: self.discriminator = discriminator else: self.discriminator = None self.train_cfg = train_cfg self.test_cfg = test_cfg self.epoch_num = 0 self.warmup_num = warmup_num self.adv_lambda = adv_lambda self.register_buffer('step_counter', torch.tensor(0), False) if pixel_loss: self.pixel_loss = MODELS.build(pixel_loss) if disc_loss: if isinstance(disc_loss, dict): self.disc_loss = MODELS.build(disc_loss) else: self.disc_loss = AdvLoss(disc_loss) else: self.disc_loss = None if self.disc_loss and getattr(self.discriminator, 'full_gan', None): self.disc_loss2 = copy.deepcopy(self.disc_loss) def forward(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs) -> Union[torch.Tensor, List[DataSample], dict]: """Returns losses or predictions of training, validation, testing, and simple inference process. ``forward`` method of BaseModel is an abstract method, its subclasses must implement this method. Accepts ``inputs`` and ``data_samples`` processed by :attr:`data_preprocessor`, and returns results according to mode arguments. During non-distributed training, validation, and testing process, ``forward`` will be called by ``BaseModel.train_step``, ``BaseModel.val_step`` and ``BaseModel.val_step`` directly. During distributed data parallel training process, ``MMSeparateDistributedDataParallel.train_step`` will first call ``DistributedDataParallel.forward`` to enable automatic gradient synchronization, and then call ``forward`` to get training loss. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor``. Default: 'tensor'. - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == val``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict`` or tensor for custom use. """ if isinstance(inputs, dict): inputs = inputs['img'] if mode == 'tensor': return self.forward_tensor(inputs, data_samples, **kwargs) elif mode == 'val': predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'predict': h, w = data_samples.ori_img_shape[0][0:2] block_size = 32 min_height = (h // block_size + 1) * block_size min_width = (w // block_size + 1) * block_size pad = torch.nn.ZeroPad2d( padding=(0, min_width - w, 0, min_height - h)) inputs = pad(inputs) predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions.pred_img = predictions.pred_img[:, :, :h, :w] predictions = self.convert_to_datasample(predictions, data_samples, inputs) return predictions elif mode == 'loss': return self.forward_train(inputs, data_samples, **kwargs) def convert_to_datasample(self, predictions: DataSample, data_samples: DataSample, inputs: Optional[torch.Tensor] ) -> List[DataSample]: """Add predictions and destructed inputs (if passed) to data samples. Args: predictions (DataSample): The predictions of the model. data_samples (DataSample): The data samples loaded from dataloader. inputs (Optional[torch.Tensor]): The input of model. Defaults to None. Returns: List[DataSample]: Modified data samples. """ if inputs is not None: destructed_input = self.data_preprocessor.destruct( inputs, data_samples, 'img') data_samples.set_tensor_data({'input': destructed_input}) data_samples = data_samples.split() predictions = predictions.split() for data_sample, pred in zip(data_samples, predictions): data_sample.output = pred return data_samples def forward_tensor(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, **kwargs) -> torch.Tensor: """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: result of simple forward. """ if torch.cuda.is_available(): inputs = inputs.cuda() feats = self.generator(inputs) return feats def forward_inference(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, **kwargs) -> List[DataSample]: """Forward inference. Returns predictions of validation, testing, and simple inference. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: List[EditDataSample]: predictions. """ feats = self.forward_tensor(inputs, data_samples, **kwargs) feats = self.data_preprocessor.destruct(feats, data_samples) predictions = DataSample(pred_img=feats.cpu()) return predictions def forward_train(self, inputs, data_samples=None, **kwargs): """Forward training. Losses of training is calculated in train_step. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: Result of ``forward_tensor`` with ``training=True``. """ return self.forward_tensor( inputs, data_samples, training=True, **kwargs) def val_step(self, data: Union[tuple, dict, list]) -> list: """Gets the predictions of given data. Calls ``self.data_preprocessor(data, False)`` and ``self(inputs, data_sample, mode='predict')`` in order. Return the predictions which will be passed to evaluator. Args: data (dict or tuple or list): Data sampled from dataset. Returns: list: The predictions of given data. """ data = self.data_preprocessor(data, False) return self._run_forward(data, mode='val') self.epoch_num += 1 def test_step(self, data: Union[dict, tuple, list]) -> list: """``BaseModel`` implements ``test_step`` the same as ``val_step``. Args: data (dict or tuple or list): Data sampled from dataset. Returns: list: The predictions of given data. """ data = self.data_preprocessor(data, False) return self._run_forward(data, mode='predict') def _run_forward(self, data: Union[dict, tuple, list], mode: str) -> Union[Dict[str, torch.Tensor], list]: """Unpacks data for :meth:`forward` Args: data (dict or tuple or list): Data sampled from dataset. mode (str): Mode of forward. Returns: dict or list: Results of training or testing mode. """ if isinstance(data, dict): results = self(**data, mode=mode) elif isinstance(data, (list, tuple)): results = self(*data, mode=mode) else: raise TypeError('Output of `data_preprocessor` should be ' f'list, tuple or dict, but got {type(data)}') return results def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step of GAN-based method. Args: data (List[dict]): Data sampled from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ data = self.data_preprocessor(data, True) batch_inputs = data['inputs'] data_samples = data['data_samples'] batch_gt_data = self.extract_gt_data(data_samples) log_vars = dict() if self.warmup_num == self.epoch_num: self.generator.module.unfreeze() g_optim_wrapper = optim_wrapper['generator'] with g_optim_wrapper.optim_context(self): batch_outputs = self.forward_train(batch_inputs, data_samples) log_vars_d = self.d_step_with_optim( batch_outputs=batch_outputs.detach(), batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) log_vars_d = self.g_step_with_optim( batch_outputs=batch_outputs, batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if 'loss' in log_vars: log_vars.pop('loss') self.step_counter += 1 return log_vars def g_step(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor): """G step of DobuleGAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ losses = dict() loss_gx = self.pixel_loss(batch_outputs, batch_gt_data) batch_outputs2 = ((batch_outputs + 1) / 2.0 - self.pixel_loss.vgg.mean) / self.pixel_loss.vgg.std batch_gt_data2 = ((batch_gt_data + 1) / 2.0 - self.pixel_loss.vgg.mean) / self.pixel_loss.vgg.std loss_gp = torch.nn.MSELoss()(batch_outputs2, batch_gt_data2) losses['loss_g_content'] = 0.006 * loss_gx[0] + 0.5 * loss_gp if getattr(self.discriminator, 'full_gan', None): losses['loss_g_adv'] = self.adv_lambda * (self.disc_loss( self.discriminator.patch_gan, batch_outputs, batch_gt_data, model='generator') + self.disc_loss2( self.discriminator.full_gan, batch_outputs, batch_gt_data, model='generator')) / 2 else: losses['loss_g_adv'] = self.adv_lambda * ( self.disc_loss( self.discriminator.patch_gan, batch_outputs, batch_gt_data, model='generator')) losses['loss_g'] = losses['loss_g_content'] + losses['loss_g_adv'] return losses def d_step(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor): """D step of DobuleGAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ if getattr(self.discriminator, 'full_gan', None): loss_d = (self.disc_loss(self.discriminator.patch_gan, batch_outputs, batch_gt_data) + self.disc_loss2(self.discriminator.full_gan, batch_outputs, batch_gt_data)) / 2 else: loss_d = self.disc_loss(self.discriminator.patch_gan, batch_outputs, batch_gt_data) return loss_d def g_step_with_optim(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor, optim_wrapper: OptimWrapperDict): """G step with optim of GAN: Calculate losses of generator and run optim. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. optim_wrapper (OptimWrapperDict): Optim wrapper dict. Returns: dict: Dict of parsed losses. """ g_optim_wrapper = optim_wrapper['generator'] g_optim_wrapper.zero_grad() with g_optim_wrapper.optim_context(self): losses_g_double = self.g_step(batch_outputs, batch_gt_data) parsed_losses_g, log_vars_g = self.parse_losses(losses_g_double) loss_pix = g_optim_wrapper.scale_loss(parsed_losses_g) g_optim_wrapper.backward(loss_pix) g_optim_wrapper.step() return log_vars_g def d_step_with_optim(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor, optim_wrapper: OptimWrapperDict): """D step with optim of GAN: Calculate losses of discriminator and run optim. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. optim_wrapper (OptimWrapperDict): Optim wrapper dict. Returns: dict: Dict of parsed losses. """ log_vars = dict() d_optim_wrapper = optim_wrapper['discriminator'] d_optim_wrapper.zero_grad() with d_optim_wrapper.optim_context(self): loss_d_double = self.adv_lambda * self.d_step( batch_outputs, batch_gt_data) parsed_losses_df, log_vars_df = self.parse_losses( dict(loss_d=loss_d_double)) log_vars.update(log_vars_df) loss_df = d_optim_wrapper.scale_loss(parsed_losses_df) d_optim_wrapper.backward(loss_df, retain_graph=True) d_optim_wrapper.step() return log_vars def extract_gt_data(self, data_samples): """extract gt data from data samples. Args: data_samples (list): List of DataSample. Returns: Tensor: Extract gt data. """ batch_gt_data = data_samples.gt_img return batch_gt_data ================================================ FILE: mmagic/models/editors/deblurganv2/deblurganv2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import functools import numpy as np import torch.nn as nn from mmagic.registry import MODELS from .deblurganv2_util import get_norm_layer backbone_list = ['DoubleGan', 'MultiScale', 'NoGan', 'PatchGan'] class NLayerDiscriminator(nn.Module): """Defines the PatchGAN discriminator with the specified arguments.""" def __init__(self, input_nc=3, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, use_sigmoid=False, use_parallel=True): super(NLayerDiscriminator, self).__init__() self.use_parallel = use_parallel if type(norm_layer) == functools.partial: use_bias = norm_layer.func == nn.InstanceNorm2d else: use_bias = norm_layer == nn.InstanceNorm2d kw = 4 padw = int(np.ceil((kw - 1) / 2)) sequence = [ nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True) ] nf_mult = 1 for n in range(1, n_layers): nf_mult_prev = nf_mult nf_mult = min(2**n, 8) sequence += [ nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True) ] nf_mult_prev = nf_mult nf_mult = min(2**n_layers, 8) sequence += [ nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True) ] sequence += [ nn.Conv2d( ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw) ] if use_sigmoid: sequence += [nn.Sigmoid()] self.model = nn.Sequential(*sequence) def forward(self, input): """Forward function. Args: input (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ return self.model(input) class DicsriminatorTail(nn.Module): def __init__(self, nf_mult, n_layers, ndf=64, norm_layer=nn.BatchNorm2d, use_parallel=True): super(DicsriminatorTail, self).__init__() self.use_parallel = use_parallel if type(norm_layer) == functools.partial: use_bias = norm_layer.func == nn.InstanceNorm2d else: use_bias = norm_layer == nn.InstanceNorm2d kw = 4 padw = int(np.ceil((kw - 1) / 2)) nf_mult_prev = nf_mult nf_mult = min(2**n_layers, 8) sequence = [ nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True) ] sequence += [ nn.Conv2d( ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw) ] self.model = nn.Sequential(*sequence) def forward(self, input): """Forward function. Args: input (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ return self.model(input) class MultiScaleDiscriminator(nn.Module): """Defines the MultiScale PatchGAN discriminator with the specified arguments.""" def __init__(self, input_nc=3, ndf=64, norm_layer=nn.BatchNorm2d, use_parallel=True): super(MultiScaleDiscriminator, self).__init__() self.use_parallel = use_parallel if type(norm_layer) == functools.partial: use_bias = norm_layer.func == nn.InstanceNorm2d else: use_bias = norm_layer == nn.InstanceNorm2d kw = 4 padw = int(np.ceil((kw - 1) / 2)) sequence = [ nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True) ] nf_mult = 1 for n in range(1, 3): nf_mult_prev = nf_mult nf_mult = min(2**n, 8) sequence += [ nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True) ] self.scale_one = nn.Sequential(*sequence) self.first_tail = DicsriminatorTail(nf_mult=nf_mult, n_layers=3) nf_mult_prev = 4 nf_mult = 8 self.scale_two = nn.Sequential( nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True)) nf_mult_prev = nf_mult self.second_tail = DicsriminatorTail(nf_mult=nf_mult, n_layers=4) self.scale_three = nn.Sequential( nn.Conv2d( ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias), norm_layer(ndf * nf_mult), nn.LeakyReLU(0.2, True)) self.third_tail = DicsriminatorTail(nf_mult=nf_mult, n_layers=5) def forward(self, input): """Forward function. Args: input (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x = self.scale_one(input) x_1 = self.first_tail(x) x = self.scale_two(x) x_2 = self.second_tail(x) x = self.scale_three(x) x = self.third_tail(x) return [x_1, x_2, x] def get_fullD(norm_layer): """Get a full gan discriminator. Args: norm_layer (Str): norm type """ model_d = NLayerDiscriminator( n_layers=5, norm_layer=get_norm_layer(norm_type=norm_layer), use_sigmoid=False) return model_d class DoubleGan(nn.Module): """Get a discriminator with a patch gan and a full gan.""" def __init__(self, norm_layer='instance', d_layers=3): super().__init__() self.patch_gan = NLayerDiscriminator( n_layers=d_layers, norm_layer=get_norm_layer(norm_type=norm_layer), use_sigmoid=False) self.full_gan = get_fullD(norm_layer) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: List(torch.Tensor) : ``List(torch.tensor)`` will be returned. """ # d_full_gan = self.model_d['full'](x) d_full_gan_output = self.full_gan(x) # d_patch_gan = self.model_d['patch'](x) d_patch_gan_output = self.patch_gan(x) return [d_full_gan_output, d_patch_gan_output] class PatchGan(nn.Module): """A patch gan discriminator with the specified arguments.""" def __init__(self, norm_layer='instance', d_layers=3): super().__init__() self.patch_gan = NLayerDiscriminator( n_layers=d_layers, norm_layer=get_norm_layer(norm_type=norm_layer), use_sigmoid=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ d_patch_gan_output = self.patch_gan(x) return d_patch_gan_output class MultiScale(nn.Module): """A multiscale patch gan discriminator with the specified arguments.""" def __init__(self, norm_layer='instance', d_layers=3): super().__init__() self.model_d = MultiScaleDiscriminator( norm_layer=get_norm_layer(norm_type=norm_layer)) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ result_d = self.model_d(x) return result_d @MODELS.register_module() class DeblurGanV2Discriminator: """Defines the discriminator for DeblurGanv2 with the specified arguments.. Args: model (Str): Type of the discriminator model """ def __new__(cls, backbone, *args, **kwargs): if backbone == 'DoubleGan': return DoubleGan(*args, **kwargs) elif backbone == 'NoGan' or backbone == '': return super().__new__(cls) elif backbone == 'PatchGan': return PatchGan(*args, **kwargs) elif backbone == 'MultiScale': return MultiScale(*args, **kwargs) else: raise Exception('Discriminator model {} not found, ' 'Please use the following models: ' '{}'.format(backbone, backbone_list)) ================================================ FILE: mmagic/models/editors/deblurganv2/deblurganv2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS from .deblurganv2_util import MobileNetV2, get_norm_layer, inceptionresnetv2 backbone_list = ['FPNInception', 'FPNMobileNet', 'FPNInceptionSimple'] class FPNHead(nn.Module): """Head for FPNInception,FPNInceptionSimple and FPNMobilenet.""" def __init__(self, num_in, num_mid, num_out): super().__init__() self.block0 = nn.Conv2d( num_in, num_mid, kernel_size=3, padding=1, bias=False) self.block1 = nn.Conv2d( num_mid, num_out, kernel_size=3, padding=1, bias=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x = nn.functional.relu(self.block0(x), inplace=True) x = nn.functional.relu(self.block1(x), inplace=True) return x class FPN_inception(nn.Module): def __init__(self, norm_layer, num_filter=256, pretrained='imagenet'): """Creates an `FPN` instance for feature extraction. Args: num_filter: the number of filters in each output pyramid level pretrained: use ImageNet pre-trained backbone feature extractor """ super().__init__() self.inception = inceptionresnetv2( num_classes=1000, pretrained=pretrained) self.enc0 = self.inception.conv2d_1a self.enc1 = nn.Sequential( self.inception.conv2d_2a, self.inception.conv2d_2b, self.inception.maxpool_3a, ) # 64 self.enc2 = nn.Sequential( self.inception.conv2d_3b, self.inception.conv2d_4a, self.inception.maxpool_5a, ) # 192 self.enc3 = nn.Sequential( self.inception.mixed_5b, self.inception.repeat, self.inception.mixed_6a, ) # 1088 self.enc4 = nn.Sequential( self.inception.repeat_1, self.inception.mixed_7a, ) # 2080 self.td1 = nn.Sequential( nn.Conv2d(num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(inplace=True)) self.td2 = nn.Sequential( nn.Conv2d(num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(inplace=True)) self.td3 = nn.Sequential( nn.Conv2d(num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(inplace=True)) self.pad = nn.ReflectionPad2d(1) self.lateral4 = nn.Conv2d(2080, num_filter, kernel_size=1, bias=False) self.lateral3 = nn.Conv2d(1088, num_filter, kernel_size=1, bias=False) self.lateral2 = nn.Conv2d(192, num_filter, kernel_size=1, bias=False) self.lateral1 = nn.Conv2d(64, num_filter, kernel_size=1, bias=False) self.lateral0 = nn.Conv2d( 32, num_filter // 2, kernel_size=1, bias=False) for param in self.inception.parameters(): param.requires_grad = False def unfreeze(self): """Unfreeze params.""" for param in self.inception.parameters(): param.requires_grad = True def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ # Bottom-up pathway, from ResNet enc0 = self.enc0(x) enc1 = self.enc1(enc0) # 256 enc2 = self.enc2(enc1) # 512 enc3 = self.enc3(enc2) # 1024 enc4 = self.enc4(enc3) # 2048 # Lateral connections lateral4 = self.pad(self.lateral4(enc4)) lateral3 = self.pad(self.lateral3(enc3)) lateral2 = self.lateral2(enc2) lateral1 = self.pad(self.lateral1(enc1)) lateral0 = self.lateral0(enc0) # Top-down pathway pad = (1, 2, 1, 2) # pad last dim by 1 on each side pad1 = (0, 1, 0, 1) map4 = lateral4 map3 = self.td1( lateral3 + nn.functional.upsample(map4, scale_factor=2, mode='nearest')) map2 = self.td2( F.pad(lateral2, pad, 'reflect') + nn.functional.upsample(map3, scale_factor=2, mode='nearest')) map1 = self.td3( lateral1 + nn.functional.upsample(map2, scale_factor=2, mode='nearest')) return F.pad(lateral0, pad1, 'reflect'), map1, map2, map3, map4 class FPNInception(nn.Module): """Feature Pyramid Network (FPN) with four feature maps of resolutions 1/4, 1/8, 1/16, 1/32 and `num_filter` filters for all feature maps.""" def __init__(self, norm_layer, output_ch=3, num_filter=128, num_filter_fpn=256): super().__init__() norm_layer = get_norm_layer(norm_type=norm_layer) self.fpn = FPN_inception( num_filter=num_filter_fpn, norm_layer=norm_layer) # The segmentation heads on top of the FPN self.head1 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head2 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head3 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head4 = FPNHead(num_filter_fpn, num_filter, num_filter) self.smooth = nn.Sequential( nn.Conv2d(4 * num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(), ) self.smooth2 = nn.Sequential( nn.Conv2d(num_filter, num_filter // 2, kernel_size=3, padding=1), norm_layer(num_filter // 2), nn.ReLU(), ) self.final = nn.Conv2d( num_filter // 2, output_ch, kernel_size=3, padding=1) def unfreeze(self): """Unfreeze params.""" self.fpn.unfreeze() def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ map0, map1, map2, map3, map4 = self.fpn(x) map4 = nn.functional.upsample( self.head4(map4), scale_factor=8, mode='nearest') map3 = nn.functional.upsample( self.head3(map3), scale_factor=4, mode='nearest') map2 = nn.functional.upsample( self.head2(map2), scale_factor=2, mode='nearest') map1 = nn.functional.upsample( self.head1(map1), scale_factor=1, mode='nearest') smoothed = self.smooth(torch.cat([map4, map3, map2, map1], dim=1)) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') smoothed = self.smooth2(smoothed + map0) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') final = self.final(smoothed) res = torch.tanh(final) + x return torch.clamp(res, min=-1, max=1) class FPN_inceptionsimple(nn.Module): def __init__(self, norm_layer, num_filters=256): """Creates an `FPN` instance for feature extraction. Args: num_filters: the number of filters in each output pyramid level pretrained: use ImageNet pre-trained backbone feature extractor """ super().__init__() self.inception = inceptionresnetv2( num_classes=1000, pretrained='imagenet') self.enc0 = self.inception.conv2d_1a self.enc1 = nn.Sequential( self.inception.conv2d_2a, self.inception.conv2d_2b, self.inception.maxpool_3a, ) # 64 self.enc2 = nn.Sequential( self.inception.conv2d_3b, self.inception.conv2d_4a, self.inception.maxpool_5a, ) # 192 self.enc3 = nn.Sequential( self.inception.mixed_5b, self.inception.repeat, self.inception.mixed_6a, ) # 1088 self.enc4 = nn.Sequential( self.inception.repeat_1, self.inception.mixed_7a, ) # 2080 self.pad = nn.ReflectionPad2d(1) self.lateral4 = nn.Conv2d(2080, num_filters, kernel_size=1, bias=False) self.lateral3 = nn.Conv2d(1088, num_filters, kernel_size=1, bias=False) self.lateral2 = nn.Conv2d(192, num_filters, kernel_size=1, bias=False) self.lateral1 = nn.Conv2d(64, num_filters, kernel_size=1, bias=False) self.lateral0 = nn.Conv2d( 32, num_filters // 2, kernel_size=1, bias=False) for param in self.inception.parameters(): param.requires_grad = False def unfreeze(self): """Unfreeze params.""" for param in self.inception.parameters(): param.requires_grad = True def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ # Bottom-up pathway, from ResNet enc0 = self.enc0(x) enc1 = self.enc1(enc0) # 256 enc2 = self.enc2(enc1) # 512 enc3 = self.enc3(enc2) # 1024 enc4 = self.enc4(enc3) # 2048 # Lateral connections lateral4 = self.pad(self.lateral4(enc4)) lateral3 = self.pad(self.lateral3(enc3)) lateral2 = self.lateral2(enc2) lateral1 = self.pad(self.lateral1(enc1)) lateral0 = self.lateral0(enc0) # Top-down pathway pad = (1, 2, 1, 2) # pad last dim by 1 on each side pad1 = (0, 1, 0, 1) map4 = lateral4 map3 = lateral3 + nn.functional.upsample( map4, scale_factor=2, mode='nearest') map2 = F.pad(lateral2, pad, 'reflect') + nn.functional.upsample( map3, scale_factor=2, mode='nearest') map1 = lateral1 + nn.functional.upsample( map2, scale_factor=2, mode='nearest') return F.pad(lateral0, pad1, 'reflect'), map1, map2, map3, map4 class FPNInceptionSimple(nn.Module): """Feature Pyramid Network (FPN) with four feature maps of resolutions 1/4, 1/8, 1/16, 1/32 and `num_filter` filters for all feature maps.""" def __init__(self, norm_layer, output_ch=3, num_filter=128, num_filter_fpn=256): super().__init__() norm_layer = get_norm_layer(norm_type=norm_layer) self.fpn = FPN_inceptionsimple( num_filter=num_filter_fpn, norm_layer=norm_layer) # The segmentation heads on top of the FPN self.head1 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head2 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head3 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head4 = FPNHead(num_filter_fpn, num_filter, num_filter) self.smooth = nn.Sequential( nn.Conv2d(4 * num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(), ) self.smooth2 = nn.Sequential( nn.Conv2d(num_filter, num_filter // 2, kernel_size=3, padding=1), norm_layer(num_filter // 2), nn.ReLU(), ) self.final = nn.Conv2d( num_filter // 2, output_ch, kernel_size=3, padding=1) def unfreeze(self): """unfreeze the fpn network.""" self.fpn.unfreeze() def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ map0, map1, map2, map3, map4 = self.fpn(x) map4 = nn.functional.upsample( self.head4(map4), scale_factor=8, mode='nearest') map3 = nn.functional.upsample( self.head3(map3), scale_factor=4, mode='nearest') map2 = nn.functional.upsample( self.head2(map2), scale_factor=2, mode='nearest') map1 = nn.functional.upsample( self.head1(map1), scale_factor=1, mode='nearest') smoothed = self.smooth(torch.cat([map4, map3, map2, map1], dim=1)) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') smoothed = self.smooth2(smoothed + map0) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') final = self.final(smoothed) res = torch.tanh(final) + x return torch.clamp(res, min=-1, max=1) class FPN_mobilenet(nn.Module): def __init__(self, norm_layer, num_filters=128, pretrained=None): """Creates an `FPN` instance for feature extraction. Args: num_filters: the number of filters in each output pyramid level pretrained: use ImageNet pre-trained backbone feature extractor """ super().__init__() net = MobileNetV2(n_class=1000) if pretrained: # Load weights into the project directory if torch.cuda.is_available(): state_dict = torch.load( pretrained) # add map_location='cpu' if no gpu else: state_dict = torch.load(pretrained, map_location='cpu') net.load_state_dict(state_dict) self.features = net.features self.enc0 = nn.Sequential(*self.features[0:2]) self.enc1 = nn.Sequential(*self.features[2:4]) self.enc2 = nn.Sequential(*self.features[4:7]) self.enc3 = nn.Sequential(*self.features[7:11]) self.enc4 = nn.Sequential(*self.features[11:16]) self.td1 = nn.Sequential( nn.Conv2d(num_filters, num_filters, kernel_size=3, padding=1), norm_layer(num_filters), nn.ReLU(inplace=True)) self.td2 = nn.Sequential( nn.Conv2d(num_filters, num_filters, kernel_size=3, padding=1), norm_layer(num_filters), nn.ReLU(inplace=True)) self.td3 = nn.Sequential( nn.Conv2d(num_filters, num_filters, kernel_size=3, padding=1), norm_layer(num_filters), nn.ReLU(inplace=True)) self.lateral4 = nn.Conv2d(160, num_filters, kernel_size=1, bias=False) self.lateral3 = nn.Conv2d(64, num_filters, kernel_size=1, bias=False) self.lateral2 = nn.Conv2d(32, num_filters, kernel_size=1, bias=False) self.lateral1 = nn.Conv2d(24, num_filters, kernel_size=1, bias=False) self.lateral0 = nn.Conv2d( 16, num_filters // 2, kernel_size=1, bias=False) for param in self.features.parameters(): param.requires_grad = False def unfreeze(self): """Unfreeze params.""" for param in self.features.parameters(): param.requires_grad = True def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ # Bottom-up pathway, from ResNet enc0 = self.enc0(x) enc1 = self.enc1(enc0) # 256 enc2 = self.enc2(enc1) # 512 enc3 = self.enc3(enc2) # 1024 enc4 = self.enc4(enc3) # 2048 # Lateral connections lateral4 = self.lateral4(enc4) lateral3 = self.lateral3(enc3) lateral2 = self.lateral2(enc2) lateral1 = self.lateral1(enc1) lateral0 = self.lateral0(enc0) # Top-down pathway map4 = lateral4 map3 = self.td1( lateral3 + nn.functional.upsample(map4, scale_factor=2, mode='nearest')) map2 = self.td2( lateral2 + nn.functional.upsample(map3, scale_factor=2, mode='nearest')) map1 = self.td3( lateral1 + nn.functional.upsample(map2, scale_factor=2, mode='nearest')) return lateral0, map1, map2, map3, map4 class FPNMobileNet(nn.Module): def __init__(self, norm_layer, output_ch=3, num_filter=64, num_filter_fpn=128, pretrained=None): super().__init__() # Feature Pyramid Network (FPN) with four feature maps of resolutions # 1/4, 1/8, 1/16, 1/32 and `num_filters` filters for all feature maps. norm_layer = get_norm_layer(norm_type=norm_layer) self.fpn = FPN_mobilenet( num_filters=num_filter_fpn, norm_layer=norm_layer, pretrained=pretrained) # The segmentation heads on top of the FPN self.head1 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head2 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head3 = FPNHead(num_filter_fpn, num_filter, num_filter) self.head4 = FPNHead(num_filter_fpn, num_filter, num_filter) self.smooth = nn.Sequential( nn.Conv2d(4 * num_filter, num_filter, kernel_size=3, padding=1), norm_layer(num_filter), nn.ReLU(), ) self.smooth2 = nn.Sequential( nn.Conv2d(num_filter, num_filter // 2, kernel_size=3, padding=1), norm_layer(num_filter // 2), nn.ReLU(), ) self.final = nn.Conv2d( num_filter // 2, output_ch, kernel_size=3, padding=1) def unfreeze(self): """unfreeze the fpn network.""" self.fpn.unfreeze() def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ map0, map1, map2, map3, map4 = self.fpn(x) map4 = nn.functional.upsample( self.head4(map4), scale_factor=8, mode='nearest') map3 = nn.functional.upsample( self.head3(map3), scale_factor=4, mode='nearest') map2 = nn.functional.upsample( self.head2(map2), scale_factor=2, mode='nearest') map1 = nn.functional.upsample( self.head1(map1), scale_factor=1, mode='nearest') smoothed = self.smooth(torch.cat([map4, map3, map2, map1], dim=1)) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') smoothed = self.smooth2(smoothed + map0) smoothed = nn.functional.upsample( smoothed, scale_factor=2, mode='nearest') final = self.final(smoothed) res = torch.tanh(final) + x return torch.clamp(res, min=-1, max=1) @MODELS.register_module() class DeblurGanV2Generator: """Defines the generator for DeblurGanv2 with the specified arguments.. Args: model (Str): Type of the generator model """ def __new__(cls, backbone, *args, **kwargs): if backbone == 'FPNInception': return FPNInception(*args, **kwargs) elif backbone == 'FPNMobileNet': return FPNMobileNet(*args, **kwargs) elif backbone == 'FPNInceptionSimple': return FPNInceptionSimple(*args, **kwargs) else: raise Exception('Generator model {} not found, ' 'Please use the following models: ' '{}'.format(backbone, backbone_list)) ================================================ FILE: mmagic/models/editors/deblurganv2/deblurganv2_util.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from __future__ import absolute_import, division, print_function import functools import math import torch import torch.nn as nn import torch.nn.functional as F from torch.utils import model_zoo pretrained_settings = { 'inceptionresnetv2': { 'imagenet': { 'url': 'https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/' 'weight/inceptionresnetv2-520b38e4.pth', 'input_space': 'RGB', 'input_size': [3, 299, 299], 'input_range': [0, 1], 'mean': [0.5, 0.5, 0.5], 'std': [0.5, 0.5, 0.5], 'num_classes': 1000 }, 'imagenet+background': { 'url': 'https://download.openxlab.org.cn/models/xiaomile/DeblurGANv2/' 'weight/inceptionresnetv2-520b38e4.pth', 'input_space': 'RGB', 'input_size': [3, 299, 299], 'input_range': [0, 1], 'mean': [0.5, 0.5, 0.5], 'std': [0.5, 0.5, 0.5], 'num_classes': 1001 } } } class BasicConv2d(nn.Module): def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): super(BasicConv2d, self).__init__() self.conv = nn.Conv2d( in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, bias=False) # verify bias false self.bn = nn.BatchNorm2d( out_planes, eps=0.001, # value found in tensorflow momentum=0.1, # default pytorch value affine=True) self.relu = nn.ReLU(inplace=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x = self.conv(x) x = self.bn(x) x = self.relu(x) return x class Mixed_5b(nn.Module): def __init__(self): super(Mixed_5b, self).__init__() self.branch0 = BasicConv2d(192, 96, kernel_size=1, stride=1) self.branch1 = nn.Sequential( BasicConv2d(192, 48, kernel_size=1, stride=1), BasicConv2d(48, 64, kernel_size=5, stride=1, padding=2)) self.branch2 = nn.Sequential( BasicConv2d(192, 64, kernel_size=1, stride=1), BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1)) self.branch3 = nn.Sequential( nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), BasicConv2d(192, 64, kernel_size=1, stride=1)) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) x2 = self.branch2(x) x3 = self.branch3(x) out = torch.cat((x0, x1, x2, x3), 1) return out class Block35(nn.Module): def __init__(self, scale=1.0): super(Block35, self).__init__() self.scale = scale self.branch0 = BasicConv2d(320, 32, kernel_size=1, stride=1) self.branch1 = nn.Sequential( BasicConv2d(320, 32, kernel_size=1, stride=1), BasicConv2d(32, 32, kernel_size=3, stride=1, padding=1)) self.branch2 = nn.Sequential( BasicConv2d(320, 32, kernel_size=1, stride=1), BasicConv2d(32, 48, kernel_size=3, stride=1, padding=1), BasicConv2d(48, 64, kernel_size=3, stride=1, padding=1)) self.conv2d = nn.Conv2d(128, 320, kernel_size=1, stride=1) self.relu = nn.ReLU(inplace=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) x2 = self.branch2(x) out = torch.cat((x0, x1, x2), 1) out = self.conv2d(out) out = out * self.scale + x out = self.relu(out) return out class Mixed_6a(nn.Module): def __init__(self): super(Mixed_6a, self).__init__() self.branch0 = BasicConv2d(320, 384, kernel_size=3, stride=2) self.branch1 = nn.Sequential( BasicConv2d(320, 256, kernel_size=1, stride=1), BasicConv2d(256, 256, kernel_size=3, stride=1, padding=1), BasicConv2d(256, 384, kernel_size=3, stride=2)) self.branch2 = nn.MaxPool2d(3, stride=2) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) x2 = self.branch2(x) out = torch.cat((x0, x1, x2), 1) return out class Block17(nn.Module): def __init__(self, scale=1.0): super(Block17, self).__init__() self.scale = scale self.branch0 = BasicConv2d(1088, 192, kernel_size=1, stride=1) self.branch1 = nn.Sequential( BasicConv2d(1088, 128, kernel_size=1, stride=1), BasicConv2d( 128, 160, kernel_size=(1, 7), stride=1, padding=(0, 3)), BasicConv2d( 160, 192, kernel_size=(7, 1), stride=1, padding=(3, 0))) self.conv2d = nn.Conv2d(384, 1088, kernel_size=1, stride=1) self.relu = nn.ReLU(inplace=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) out = torch.cat((x0, x1), 1) out = self.conv2d(out) out = out * self.scale + x out = self.relu(out) return out class Mixed_7a(nn.Module): def __init__(self): super(Mixed_7a, self).__init__() self.branch0 = nn.Sequential( BasicConv2d(1088, 256, kernel_size=1, stride=1), BasicConv2d(256, 384, kernel_size=3, stride=2)) self.branch1 = nn.Sequential( BasicConv2d(1088, 256, kernel_size=1, stride=1), BasicConv2d(256, 288, kernel_size=3, stride=2)) self.branch2 = nn.Sequential( BasicConv2d(1088, 256, kernel_size=1, stride=1), BasicConv2d(256, 288, kernel_size=3, stride=1, padding=1), BasicConv2d(288, 320, kernel_size=3, stride=2)) self.branch3 = nn.MaxPool2d(3, stride=2) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) x2 = self.branch2(x) x3 = self.branch3(x) out = torch.cat((x0, x1, x2, x3), 1) return out class Block8(nn.Module): def __init__(self, scale=1.0, noReLU=False): super(Block8, self).__init__() self.scale = scale self.noReLU = noReLU self.branch0 = BasicConv2d(2080, 192, kernel_size=1, stride=1) self.branch1 = nn.Sequential( BasicConv2d(2080, 192, kernel_size=1, stride=1), BasicConv2d( 192, 224, kernel_size=(1, 3), stride=1, padding=(0, 1)), BasicConv2d( 224, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))) self.conv2d = nn.Conv2d(448, 2080, kernel_size=1, stride=1) if not self.noReLU: self.relu = nn.ReLU(inplace=False) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x0 = self.branch0(x) x1 = self.branch1(x) out = torch.cat((x0, x1), 1) out = self.conv2d(out) out = out * self.scale + x if not self.noReLU: out = self.relu(out) return out class InceptionResNetV2(nn.Module): """Define a inceptionresnetv2 model.""" def __init__(self, num_classes=1001): super(InceptionResNetV2, self).__init__() # Special attributes self.input_space = None self.input_size = (299, 299, 3) self.mean = None self.std = None # Modules self.conv2d_1a = BasicConv2d(3, 32, kernel_size=3, stride=2) self.conv2d_2a = BasicConv2d(32, 32, kernel_size=3, stride=1) self.conv2d_2b = BasicConv2d( 32, 64, kernel_size=3, stride=1, padding=1) self.maxpool_3a = nn.MaxPool2d(3, stride=2) self.conv2d_3b = BasicConv2d(64, 80, kernel_size=1, stride=1) self.conv2d_4a = BasicConv2d(80, 192, kernel_size=3, stride=1) self.maxpool_5a = nn.MaxPool2d(3, stride=2) self.mixed_5b = Mixed_5b() self.repeat = nn.Sequential( Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17), Block35(scale=0.17)) self.mixed_6a = Mixed_6a() self.repeat_1 = nn.Sequential( Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10), Block17(scale=0.10)) self.mixed_7a = Mixed_7a() self.repeat_2 = nn.Sequential( Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20), Block8(scale=0.20)) self.block8 = Block8(noReLU=True) self.conv2d_7b = BasicConv2d(2080, 1536, kernel_size=1, stride=1) self.avgpool_1a = nn.AvgPool2d(8, count_include_pad=False) self.last_linear = nn.Linear(1536, num_classes) def features(self, input): """Get network features. Args: input (torch.tensor): You can directly input a ``torch.Tensor``. """ x = self.conv2d_1a(input) x = self.conv2d_2a(x) x = self.conv2d_2b(x) x = self.maxpool_3a(x) x = self.conv2d_3b(x) x = self.conv2d_4a(x) x = self.maxpool_5a(x) x = self.mixed_5b(x) x = self.repeat(x) x = self.mixed_6a(x) x = self.repeat_1(x) x = self.mixed_7a(x) x = self.repeat_2(x) x = self.block8(x) x = self.conv2d_7b(x) return x def logits(self, features): """Get features logits. Args: features (torch.tensor): You can directly input a ``torch.Tensor``. """ x = self.avgpool_1a(features) x = x.view(x.size(0), -1) x = F.dropout(x, training=self.training) x = self.last_linear(x) return x def forward(self, input): """Forward function. Args: input (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x = self.features(input) x = self.logits(x) return x def inceptionresnetv2(num_classes=1000, pretrained='imagenet'): """return a inceptionresnetv2 network.""" if pretrained: settings = pretrained_settings['inceptionresnetv2'][pretrained] model = InceptionResNetV2(num_classes=1001) model.load_state_dict(model_zoo.load_url(settings['url'])) if pretrained == 'imagenet': new_last_linear = nn.Linear(1536, 1000) new_last_linear.weight.data = model.last_linear.weight.data[1:] new_last_linear.bias.data = model.last_linear.bias.data[1:] model.last_linear = new_last_linear model.input_space = settings['input_space'] model.input_size = settings['input_size'] model.input_range = settings['input_range'] model.mean = settings['mean'] model.std = settings['std'] else: model = InceptionResNetV2(num_classes=num_classes) return model def conv_bn(inp, oup, stride): return nn.Sequential( nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup), nn.ReLU6(inplace=True)) def conv_1x1_bn(inp, oup): return nn.Sequential( nn.Conv2d(inp, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), nn.ReLU6(inplace=True)) class InvertedResidual(nn.Module): def __init__(self, inp, oup, stride, expand_ratio): super(InvertedResidual, self).__init__() self.stride = stride assert stride in [1, 2] hidden_dim = round(inp * expand_ratio) self.use_res_connect = self.stride == 1 and inp == oup if expand_ratio == 1: self.conv = nn.Sequential( # dw nn.Conv2d( hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False), nn.BatchNorm2d(hidden_dim), nn.ReLU6(inplace=True), # pw-linear nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), ) else: self.conv = nn.Sequential( # pw nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False), nn.BatchNorm2d(hidden_dim), nn.ReLU6(inplace=True), # dw nn.Conv2d( hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False), nn.BatchNorm2d(hidden_dim), nn.ReLU6(inplace=True), # pw-linear nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), ) def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ if self.use_res_connect: return x + self.conv(x) else: return self.conv(x) class MobileNetV2(nn.Module): def __init__(self, n_class=1000, input_size=224, width_mult=1.): super(MobileNetV2, self).__init__() block = InvertedResidual input_channel = 32 last_channel = 1280 interverted_residual_setting = [ # t, c, n, s [1, 16, 1, 1], [6, 24, 2, 2], [6, 32, 3, 2], [6, 64, 4, 2], [6, 96, 3, 1], [6, 160, 3, 2], [6, 320, 1, 1], ] # building first layer assert input_size % 32 == 0 input_channel = int(input_channel * width_mult) self.last_channel = int( last_channel * width_mult) if width_mult > 1.0 else last_channel self.features = [conv_bn(3, input_channel, 2)] # building inverted residual blocks for t, c, n, s in interverted_residual_setting: output_channel = int(c * width_mult) for i in range(n): if i == 0: self.features.append( block( input_channel, output_channel, s, expand_ratio=t)) else: self.features.append( block( input_channel, output_channel, 1, expand_ratio=t)) input_channel = output_channel # building last several layers self.features.append(conv_1x1_bn(input_channel, self.last_channel)) # make it nn.Sequential self.features = nn.Sequential(*self.features) # building classifier self.classifier = nn.Sequential( nn.Dropout(0.2), nn.Linear(self.last_channel, n_class), ) self._initialize_weights() def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ x = self.features(x) x = x.mean(3).mean(2) x = self.classifier(x) return x def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) if m.bias is not None: m.bias.data.zero_() elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): n = m.weight.size(1) m.weight.data.normal_(0, 0.01) m.bias.data.zero_() def get_norm_layer(norm_type='instance'): """Returns a norm layer of the specified type. Args: norm_type (Str): norm layer type """ if norm_type == 'batch': norm_layer = functools.partial(nn.BatchNorm2d, affine=True) elif norm_type == 'instance': norm_layer = functools.partial( nn.InstanceNorm2d, affine=False, track_running_stats=True) else: raise NotImplementedError('normalization layer [%s] is not found' % norm_type) return norm_layer ================================================ FILE: mmagic/models/editors/deepfillv1/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .contextual_attention import ContextualAttentionModule from .contextual_attention_neck import ContextualAttentionNeck from .deepfill_decoder import DeepFillDecoder from .deepfill_disc import DeepFillv1Discriminators from .deepfill_encoder import DeepFillEncoder from .deepfill_refiner import DeepFillRefiner from .deepfillv1 import DeepFillv1Inpaintor __all__ = [ 'DeepFillEncoder', 'DeepFillDecoder', 'ContextualAttentionNeck', 'DeepFillv1Inpaintor', 'ContextualAttentionModule', 'DeepFillv1Discriminators', 'DeepFillRefiner' ] ================================================ FILE: mmagic/models/editors/deepfillv1/contextual_attention.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule class ContextualAttentionModule(BaseModule): """Contexture attention module. The details of this module can be found in: Generative Image Inpainting with Contextual Attention Args: unfold_raw_kernel_size (int): Kernel size used in unfolding raw feature. Default: 4. unfold_raw_stride (int): Stride used in unfolding raw feature. Default: 2. unfold_raw_padding (int): Padding used in unfolding raw feature. Default: 1. unfold_corr_kernel_size (int): Kernel size used in unfolding context for computing correlation maps. Default: 3. unfold_corr_stride (int): Stride used in unfolding context for computing correlation maps. Default: 1. unfold_corr_dilation (int): Dilation used in unfolding context for computing correlation maps. Default: 1. unfold_corr_padding (int): Padding used in unfolding context for computing correlation maps. Default: 1. scale (float): The resale factor used in resize input features. Default: 0.5. fuse_kernel_size (int): The kernel size used in fusion module. Default: 3. softmax_scale (float): The scale factor for softmax function. Default: 10. return_attention_score (bool): If True, the attention score will be returned. Default: True. """ def __init__(self, unfold_raw_kernel_size=4, unfold_raw_stride=2, unfold_raw_padding=1, unfold_corr_kernel_size=3, unfold_corr_stride=1, unfold_corr_dilation=1, unfold_corr_padding=1, scale=0.5, fuse_kernel_size=3, softmax_scale=10, return_attention_score=True): super().__init__() self.unfold_raw_kernel_size = unfold_raw_kernel_size self.unfold_raw_stride = unfold_raw_stride self.unfold_raw_padding = unfold_raw_padding self.unfold_corr_kernel_size = unfold_corr_kernel_size self.unfold_corr_stride = unfold_corr_stride self.unfold_corr_dilation = unfold_corr_dilation self.unfold_corr_padding = unfold_corr_padding self.scale = scale self.fuse_kernel_size = fuse_kernel_size self.with_fuse_correlation = fuse_kernel_size > 1 self.softmax_scale = softmax_scale self.return_attention_score = return_attention_score if self.with_fuse_correlation: assert fuse_kernel_size % 2 == 1 fuse_kernel = torch.eye(fuse_kernel_size).view( 1, 1, fuse_kernel_size, fuse_kernel_size) self.register_buffer('fuse_kernel', fuse_kernel) padding = int((fuse_kernel_size - 1) // 2) self.fuse_conv = partial(F.conv2d, padding=padding, stride=1) self.softmax = nn.Softmax(dim=1) def forward(self, x, context, mask=None): """Forward Function. Args: x (torch.Tensor): Tensor with shape (n, c, h, w). context (torch.Tensor): Tensor with shape (n, c, h, w). mask (torch.Tensor): Tensor with shape (n, 1, h, w). Default: None. Returns: tuple(torch.Tensor): Features after contextural attention. """ # raw features to be used in copy (deconv) raw_context = context raw_context_cols = self.im2col( raw_context, kernel_size=self.unfold_raw_kernel_size, stride=self.unfold_raw_stride, padding=self.unfold_raw_padding, normalize=False, return_cols=True) # resize the feature to reduce computational cost x = F.interpolate(x, scale_factor=self.scale) context = F.interpolate(context, scale_factor=self.scale) context_cols = self.im2col( context, kernel_size=self.unfold_corr_kernel_size, stride=self.unfold_corr_stride, padding=self.unfold_corr_padding, dilation=self.unfold_corr_dilation, normalize=True, return_cols=True) h_unfold, w_unfold = self.calculate_unfold_hw( context.size()[-2:], kernel_size=self.unfold_corr_kernel_size, stride=self.unfold_corr_stride, padding=self.unfold_corr_padding, dilation=self.unfold_corr_dilation, ) # reshape context_cols to # (n*h_unfold*w_unfold, c, unfold_mks, unfold_mks) # 'mks' is short for 'mask_kernel_size' context_cols = context_cols.reshape(-1, *context_cols.shape[2:]) # the shape of correlation map should be: # (n, h_unfold*w_unfold, h', w') correlation_map = self.patch_correlation(x, context_cols) # fuse correlation map to enlarge consistent attention region. if self.with_fuse_correlation: correlation_map = self.fuse_correlation_map( correlation_map, h_unfold, w_unfold) correlation_map = self.mask_correlation_map(correlation_map, mask=mask) attention_score = self.softmax(correlation_map * self.softmax_scale) raw_context_filter = raw_context_cols.reshape( -1, *raw_context_cols.shape[2:]) output = self.patch_copy_deconv(attention_score, raw_context_filter) # deconv will cause overlap and we need to remove the effects of that overlap_factor = self.calculate_overlap_factor(attention_score) output /= overlap_factor if self.return_attention_score: n, _, h_s, w_s = attention_score.size() attention_score = attention_score.view(n, h_unfold, w_unfold, h_s, w_s) return output, attention_score return output def patch_correlation(self, x, kernel): """Calculate patch correlation. Args: x (torch.Tensor): Input tensor. kernel (torch.Tensor): Kernel tensor. Returns: torch.Tensor: Tensor with shape of (n, l, h, w). """ n, _, h_in, w_in = x.size() patch_corr = F.conv2d( x.view(1, -1, h_in, w_in), kernel, stride=self.unfold_corr_stride, padding=self.unfold_corr_padding, dilation=self.unfold_corr_dilation, groups=n) h_out, w_out = patch_corr.size()[-2:] return patch_corr.view(n, -1, h_out, w_out) def patch_copy_deconv(self, attention_score, context_filter): """Copy patches using deconv. Args: attention_score (torch.Tensor): Tensor with shape of (n, l , h, w). context_filter (torch.Tensor): Filter kernel. Returns: torch.Tensor: Tensor with shape of (n, c, h, w). """ n, _, h, w = attention_score.size() attention_score = attention_score.view(1, -1, h, w) output = F.conv_transpose2d( attention_score, context_filter, stride=self.unfold_raw_stride, padding=self.unfold_raw_padding, groups=n) h_out, w_out = output.size()[-2:] return output.view(n, -1, h_out, w_out) def fuse_correlation_map(self, correlation_map, h_unfold, w_unfold): """Fuse correlation map. This operation is to fuse correlation map for increasing large consistent correlation regions. The mechanism behind this op is simple and easy to understand. A standard 'Eye' matrix will be applied as a filter on the correlation map in horizontal and vertical direction. The shape of input correlation map is (n, h_unfold*w_unfold, h, w). When adopting fusing, we will apply convolutional filter in the reshaped feature map with shape of (n, 1, h_unfold*w_fold, h*w). A simple specification for horizontal direction is shown below: .. code-block:: python (h, (h, (h, (h, 0) 1) 2) 3) ... (h, 0) (h, 1) 1 (h, 2) 1 (h, 3) 1 ... """ # horizontal direction n, _, h_map, w_map = correlation_map.size() map_ = correlation_map.permute(0, 2, 3, 1) map_ = map_.reshape(n, h_map * w_map, h_unfold * w_unfold, 1) map_ = map_.permute(0, 3, 1, 2).contiguous() map_ = self.fuse_conv(map_, self.fuse_kernel) correlation_map = map_.view(n, h_unfold, w_unfold, h_map, w_map) # vertical direction map_ = correlation_map.permute(0, 2, 1, 4, 3).reshape(n, 1, h_unfold * w_unfold, h_map * w_map) map_ = self.fuse_conv(map_, self.fuse_kernel) # Note that the dimension should be transposed since the convolution of # eye matrix will put the normed scores into the last several dimension correlation_map = map_.view(n, w_unfold, h_unfold, w_map, h_map).permute(0, 4, 3, 2, 1) correlation_map = correlation_map.reshape(n, -1, h_unfold, w_unfold) return correlation_map def calculate_unfold_hw(self, input_size, kernel_size=3, stride=1, dilation=1, padding=0): """Calculate (h, w) after unfolding. The official implementation of `unfold` in pytorch will put the dimension (h, w) into `L`. Thus, this function is just to calculate the (h, w) according to the equation in: https://pytorch.org/docs/stable/nn.html#torch.nn.Unfold """ h_in, w_in = input_size h_unfold = int((h_in + 2 * padding - dilation * (kernel_size - 1) - 1) / stride + 1) w_unfold = int((w_in + 2 * padding - dilation * (kernel_size - 1) - 1) / stride + 1) return h_unfold, w_unfold def calculate_overlap_factor(self, attention_score): """Calculate the overlap factor after applying deconv. Args: attention_score (torch.Tensor): The attention score with shape of (n, c, h, w). Returns: torch.Tensor: The overlap factor will be returned. """ h, w = attention_score.shape[-2:] kernel_size = self.unfold_raw_kernel_size ones_input = torch.ones(1, 1, h, w).to(attention_score) ones_filter = torch.ones(1, 1, kernel_size, kernel_size).to(attention_score) overlap = F.conv_transpose2d( ones_input, ones_filter, stride=self.unfold_raw_stride, padding=self.unfold_raw_padding) # avoid division by zero overlap[overlap == 0] = 1. return overlap def mask_correlation_map(self, correlation_map, mask): """Add mask weight for correlation map. Add a negative infinity number to the masked regions so that softmax function will result in 'zero' in those regions. Args: correlation_map (torch.Tensor): Correlation map with shape of (n, h_unfold*w_unfold, h_map, w_map). mask (torch.Tensor): Mask tensor with shape of (n, c, h, w). '1' in the mask indicates masked region while '0' indicates valid region. Returns: torch.Tensor: Updated correlation map with mask. """ if mask is not None: mask = F.interpolate(mask, scale_factor=self.scale) # if any pixel is masked in patch, the patch is considered to be # masked mask_cols = self.im2col( mask, kernel_size=self.unfold_corr_kernel_size, stride=self.unfold_corr_stride, padding=self.unfold_corr_padding, dilation=self.unfold_corr_dilation) mask_cols = (mask_cols.sum(dim=1, keepdim=True) > 0).float() mask_cols = mask_cols.permute(0, 2, 1).reshape(mask.size(0), -1, 1, 1) # add negative inf will bring zero in softmax mask_cols[mask_cols == 1] = -float('inf') correlation_map += mask_cols return correlation_map def im2col(self, img, kernel_size, stride=1, padding=0, dilation=1, normalize=False, return_cols=False): """Reshape image-style feature to columns. This function is used for unfold feature maps to columns. The details of this function can be found in: https://pytorch.org/docs/1.1.0/nn.html?highlight=unfold#torch.nn.Unfold Args: img (torch.Tensor): Features to be unfolded. The shape of this feature should be (n, c, h, w). kernel_size (int): In this function, we only support square kernel with same height and width. stride (int): Stride number in unfolding. Default: 1. padding (int): Padding number in unfolding. Default: 0. dilation (int): Dilation number in unfolding. Default: 1. normalize (bool): If True, the unfolded feature will be normalized. Default: False. return_cols (bool): The official implementation in PyTorch of unfolding will return features with shape of (n, c*$prod{kernel_size}$, L). If True, the features will be reshaped to (n, L, c, kernel_size, kernel_size). Otherwise, the results will maintain the shape as the official implementation. Returns: torch.Tensor: Unfolded columns. If `return_cols` is True, the \ shape of output tensor is \ `(n, L, c, kernel_size, kernel_size)`. Otherwise, the shape \ will be `(n, c*$prod{kernel_size}$, L)`. """ # unfold img to columns with shape (n, c*kernel_size**2, num_cols) img_unfold = F.unfold( img, kernel_size, stride=stride, padding=padding, dilation=dilation) # normalize the feature map if normalize: norm = torch.sqrt((img_unfold**2).sum(dim=1, keepdim=True)) eps = torch.tensor([1e-4]).to(img) img_unfold = img_unfold / torch.max(norm, eps) if return_cols: img_unfold_ = img_unfold.permute(0, 2, 1) n, num_cols = img_unfold_.size()[:2] img_cols = img_unfold_.view(n, num_cols, img.size(1), kernel_size, kernel_size) return img_cols return img_unfold ================================================ FILE: mmagic/models/editors/deepfillv1/contextual_attention_neck.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.archs import SimpleGatedConvModule from mmagic.models.editors.deepfillv1.contextual_attention import \ ContextualAttentionModule from mmagic.registry import MODELS @MODELS.register_module() class ContextualAttentionNeck(BaseModule): """Neck with contextual attention module. Args: in_channels (int): The number of input channels. conv_type (str): The type of conv module. In DeepFillv1 model, the `conv_type` should be 'conv'. In DeepFillv2 model, the `conv_type` should be 'gated_conv'. conv_cfg (dict | None): Config of conv module. Default: None. norm_cfg (dict | None): Config of norm module. Default: None. act_cfg (dict | None): Config of activation layer. Default: dict(type='ELU'). contextual_attention_args (dict): Config of contextual attention module. Default: dict(softmax_scale=10.). kwargs (keyword arguments). """ _conv_type = dict(conv=ConvModule, gated_conv=SimpleGatedConvModule) def __init__(self, in_channels, conv_type='conv', conv_cfg=None, norm_cfg=None, act_cfg=dict(type='ELU'), contextual_attention_args=dict(softmax_scale=10.), **kwargs): super().__init__() self.contextual_attention = ContextualAttentionModule( **contextual_attention_args) conv_module = self._conv_type[conv_type] self.conv1 = conv_module( in_channels, in_channels, 3, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs) self.conv2 = conv_module( in_channels, in_channels, 3, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs) def forward(self, x, mask): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). mask (torch.Tensor): Input tensor with shape of (n, 1, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ x, offset = self.contextual_attention(x, x, mask) x = self.conv1(x) x = self.conv2(x) return x, offset ================================================ FILE: mmagic/models/editors/deepfillv1/deepfill_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from functools import partial import torch import torch.nn.functional as F from mmcv.cnn import ConvModule, build_activation_layer from mmengine.model import BaseModule # from ...modules import SimpleGatedConvModule from mmagic.models.archs import SimpleGatedConvModule from mmagic.registry import MODELS @MODELS.register_module() class DeepFillDecoder(BaseModule): """Decoder used in DeepFill model. This implementation follows: Generative Image Inpainting with Contextual Attention Args: in_channels (int): The number of input channels. conv_type (str): The type of conv module. In DeepFillv1 model, the `conv_type` should be 'conv'. In DeepFillv2 model, the `conv_type` should be 'gated_conv'. norm_cfg (dict): Config dict to build norm layer. Default: None. act_cfg (dict): Config dict for activation layer, "elu" by default. out_act_cfg (dict): Config dict for output activation layer. Here, we provide commonly used `clamp` or `clip` operation. channel_factor (float): The scale factor for channel size. Default: 1. kwargs (keyword arguments). """ _conv_type = dict(conv=ConvModule, gated_conv=SimpleGatedConvModule) def __init__(self, in_channels, conv_type='conv', norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='clip', min=-1., max=1.), channel_factor=1., **kwargs): super().__init__() self.with_out_activation = out_act_cfg is not None conv_module = self._conv_type[conv_type] channel_list = [128, 128, 64, 64, 32, 16, 3] channel_list = [int(x * channel_factor) for x in channel_list] # dirty code for assign output channel with 3 channel_list[-1] = 3 for i in range(7): kwargs_ = copy.deepcopy(kwargs) if i == 6: act_cfg = None if conv_type == 'gated_conv': kwargs_['feat_act_cfg'] = None self.add_module( f'dec{i + 1}', conv_module( in_channels, channel_list[i], kernel_size=3, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs_)) in_channels = channel_list[i] if self.with_out_activation: act_type = out_act_cfg['type'] if act_type == 'clip': act_cfg_ = copy.deepcopy(out_act_cfg) act_cfg_.pop('type') self.out_act = partial(torch.clamp, **act_cfg_) else: self.out_act = build_activation_layer(out_act_cfg) def forward(self, input_dict): """Forward Function. Args: input_dict (dict | torch.Tensor): Input dict with middle features or torch.Tensor. Returns: torch.Tensor: Output tensor with shape of (n, c, h, w). """ if isinstance(input_dict, dict): x = input_dict['out'] else: x = input_dict for i in range(7): x = getattr(self, f'dec{i + 1}')(x) if i in (1, 3): x = F.interpolate(x, scale_factor=2) if self.with_out_activation: x = self.out_act(x) return x ================================================ FILE: mmagic/models/editors/deepfillv1/deepfill_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmengine.model.weight_init import normal_init from mmagic.registry import MODELS @MODELS.register_module() class DeepFillv1Discriminators(BaseModule): """Discriminators used in DeepFillv1 model. In DeepFillv1 model, the discriminators are independent without any concatenation like Global&Local model. Thus, we call this model `DeepFillv1Discriminators`. There exist a global discriminator and a local discriminator with global and local input respectively. The details can be found in: Generative Image Inpainting with Contextual Attention. Args: global_disc_cfg (dict): Config dict for global discriminator. local_disc_cfg (dict): Config dict for local discriminator. """ def __init__(self, global_disc_cfg, local_disc_cfg): super().__init__() self.global_disc = MODELS.build(global_disc_cfg) self.local_disc = MODELS.build(local_disc_cfg) def forward(self, x): """Forward function. Args: x (tuple[torch.Tensor]): Contains global image and the local image patch. Returns: tuple[torch.Tensor]: Contains the prediction from discriminators \ in global image and local image patch. """ global_img, local_img = x global_pred = self.global_disc(global_img) local_pred = self.local_disc(local_img) return global_pred, local_pred def init_weights(self): """Init weights for models.""" for m in self.modules(): if isinstance(m, nn.Linear): normal_init(m, 0, std=0.02) elif isinstance(m, nn.Conv2d): normal_init(m, 0.0, std=0.02) self._is_init = True ================================================ FILE: mmagic/models/editors/deepfillv1/deepfill_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.archs import SimpleGatedConvModule from mmagic.registry import MODELS @MODELS.register_module() class DeepFillEncoder(BaseModule): """Encoder used in DeepFill model. This implementation follows: Generative Image Inpainting with Contextual Attention Args: in_channels (int): The number of input channels. Default: 5. conv_type (str): The type of conv module. In DeepFillv1 model, the `conv_type` should be 'conv'. In DeepFillv2 model, the `conv_type` should be 'gated_conv'. norm_cfg (dict): Config dict to build norm layer. Default: None. act_cfg (dict): Config dict for activation layer, "elu" by default. encoder_type (str): Type of the encoder. Should be one of ['stage1', 'stage2_conv', 'stage2_attention']. Default: 'stage1'. channel_factor (float): The scale factor for channel size. Default: 1. kwargs (keyword arguments). """ _conv_type = dict(conv=ConvModule, gated_conv=SimpleGatedConvModule) def __init__(self, in_channels=5, conv_type='conv', norm_cfg=None, act_cfg=dict(type='ELU'), encoder_type='stage1', channel_factor=1., **kwargs): super().__init__() conv_module = self._conv_type[conv_type] channel_list_dict = dict( stage1=[32, 64, 64, 128, 128, 128], stage2_conv=[32, 32, 64, 64, 128, 128], stage2_attention=[32, 32, 64, 128, 128, 128]) channel_list = channel_list_dict[encoder_type] channel_list = [int(x * channel_factor) for x in channel_list] kernel_size_list = [5, 3, 3, 3, 3, 3] stride_list = [1, 2, 1, 2, 1, 1] for i in range(6): ks = kernel_size_list[i] padding = (ks - 1) // 2 self.add_module( f'enc{i + 1}', conv_module( in_channels, channel_list[i], kernel_size=ks, stride=stride_list[i], padding=padding, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs)) in_channels = channel_list[i] def forward(self, x): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ for i in range(6): x = getattr(self, f'enc{i + 1}')(x) outputs = dict(out=x) return outputs ================================================ FILE: mmagic/models/editors/deepfillv1/deepfill_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class DeepFillRefiner(BaseModule): """Refiner used in DeepFill model. This implementation follows: Generative Image Inpainting with Contextual Attention. Args: encoder_attention (dict): Config dict for encoder used in branch with contextual attention module. encoder_conv (dict): Config dict for encoder used in branch with just convolutional operation. dilation_neck (dict): Config dict for dilation neck in branch with just convolutional operation. contextual_attention (dict): Config dict for contextual attention neck. decoder (dict): Config dict for decoder used to fuse and decode features. """ def __init__(self, encoder_attention=dict( type='DeepFillEncoder', encoder_type='stage2_attention'), encoder_conv=dict( type='DeepFillEncoder', encoder_type='stage2_conv'), dilation_neck=dict( type='GLDilationNeck', in_channels=128, act_cfg=dict(type='ELU')), contextual_attention=dict( type='ContextualAttentionNeck', in_channels=128), decoder=dict(type='DeepFillDecoder', in_channels=256)): super().__init__() self.encoder_attention = MODELS.build(encoder_attention) self.encoder_conv = MODELS.build(encoder_conv) self.contextual_attention_neck = MODELS.build(contextual_attention) self.dilation_neck = MODELS.build(dilation_neck) self.decoder = MODELS.build(decoder) def forward(self, x, mask): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). mask (torch.Tensor): Input tensor with shape of (n, 1, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ # conv branch encoder_dict = self.encoder_conv(x) conv_x = self.dilation_neck(encoder_dict['out']) # contextual attention branch attention_x = self.encoder_attention(x)['out'] h_x, w_x = attention_x.shape[-2:] # resale mask to a smaller size resized_mask = F.interpolate(mask, size=(h_x, w_x)) attention_x, offset = self.contextual_attention_neck( attention_x, resized_mask) # concat two branches x = torch.cat([conv_x, attention_x], dim=1) x = self.decoder(dict(out=x)) return x, offset ================================================ FILE: mmagic/models/editors/deepfillv1/deepfillv1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional import torch from mmagic.models.base_models import TwoStageInpaintor from mmagic.models.utils import extract_around_bbox, extract_bbox_patch from mmagic.registry import MODELS from ...utils import set_requires_grad @MODELS.register_module() class DeepFillv1Inpaintor(TwoStageInpaintor): """Inpaintor for deepfillv1 method. This inpaintor is implemented according to the paper: Generative image inpainting with contextual attention Importantly, this inpaintor is an example for using custom training schedule based on `TwoStageInpaintor`. The training pipeline of deepfillv1 is as following: .. code-block:: python if cur_iter < iter_tc: update generator with only l1 loss else: update discriminator if cur_iter > iter_td: update generator with l1 loss and adversarial loss The new attribute `cur_iter` is added for recording current number of iteration. The `train_cfg` contains the setting of the training schedule: .. code-block:: python train_cfg = dict( start_iter=0, disc_step=1, iter_tc=90000, iter_td=100000 ) `iter_tc` and `iter_td` correspond to the notation :math:`T_C` and :math:`T_D` of the original paper. Args: generator (dict): Config for encoder-decoder style generator. disc (dict): Config for discriminator. loss_gan (dict): Config for adversarial loss. loss_gp (dict): Config for gradient penalty loss. loss_disc_shift (dict): Config for discriminator shift loss. loss_composed_percep (dict): Config for perceptual and style loss with composed image as input. loss_out_percep (dict): Config for perceptual and style loss with direct output as input. loss_l1_hole (dict): Config for l1 loss in the hole. loss_l1_valid (dict): Config for l1 loss in the valid region. loss_tv (dict): Config for total variation loss. train_cfg (dict): Configs for training scheduler. `disc_step` must be contained for indicates the discriminator updating steps in each training step. test_cfg (dict): Configs for testing scheduler. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, data_preprocessor: dict, encdec: dict, disc=None, loss_gan=None, loss_gp=None, loss_disc_shift=None, loss_composed_percep=None, loss_out_percep=False, loss_l1_hole=None, loss_l1_valid=None, loss_tv=None, stage1_loss_type=None, stage2_loss_type=None, train_cfg=None, test_cfg=None, init_cfg: Optional[dict] = None): super().__init__( data_preprocessor=data_preprocessor, encdec=encdec, disc=disc, loss_gan=loss_gan, loss_gp=loss_gp, loss_disc_shift=loss_disc_shift, loss_composed_percep=loss_composed_percep, loss_out_percep=loss_out_percep, loss_l1_hole=loss_l1_hole, loss_l1_valid=loss_l1_valid, loss_tv=loss_tv, stage1_loss_type=stage1_loss_type, stage2_loss_type=stage2_loss_type, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg) if self.train_cfg is not None: self.cur_iter = self.train_cfg.start_iter def forward_train_d(self, data_batch, is_real, is_disc): """Forward function in discriminator training step. In this function, we modify the default implementation with only one discriminator. In DeepFillv1 model, they use two separated discriminators for global and local consistency. Args: data_batch (torch.Tensor): Batch of real data or fake data. is_real (bool): If True, the gan loss will regard this batch as real data. Otherwise, the gan loss will regard this batch as fake data. is_disc (bool): If True, this function is called in discriminator training step. Otherwise, this function is called in generator training step. This will help us to compute different types of adversarial loss, like LSGAN. Returns: dict: Contains the loss items computed in this function. """ global_pred, local_pred = self.disc(data_batch) loss_global = self.loss_gan(global_pred, is_real, is_disc) loss_local = self.loss_gan(local_pred, is_real, is_disc) if is_real: loss = dict( real_loss_global=loss_global, real_loss_local=loss_local) else: loss = dict( fake_loss_global=loss_global, fake_loss_local=loss_local) if self.with_disc_shift_loss: loss_d_shift_global = self.loss_disc_shift(loss_global) loss_d_shift_local = self.loss_disc_shift(loss_local) # 0.5 for average the fake and real data loss.update(loss_disc_shift_global=loss_d_shift_global * 0.5) loss.update(loss_disc_shift_local=loss_d_shift_local * 0.5) return loss def two_stage_loss(self, stage1_data, stage2_data, gt, mask, masked_img): """Calculate two-stage loss. Args: stage1_data (dict): Contain stage1 results. stage2_data (dict): Contain stage2 results. gt (torch.Tensor): Ground-truth image. mask (torch.Tensor): Mask image. masked_img (torch.Tensor): Composition of mask image and ground-truth image. Returns: tuple(dict): Dict contains the results computed within this \ function for visualization and dict contains the loss items \ computed in this function. """ loss = dict() results = dict( gt_img=gt.cpu(), mask=mask.cpu(), masked_img=masked_img.cpu()) # calculate losses for stage1 if self.stage1_loss_type is not None: fake_res = stage1_data['fake_res'] fake_img = stage1_data['fake_img'] for type_key in self.stage1_loss_type: tmp_loss = self.calculate_loss_with_type( type_key, fake_res, fake_img, gt, mask, prefix='stage1_') loss.update(tmp_loss) results.update( dict( stage1_fake_res=stage1_data['fake_res'].cpu(), stage1_fake_img=stage1_data['fake_img'].cpu())) if self.stage2_loss_type is not None: fake_res = stage2_data['fake_res'] fake_img = stage2_data['fake_img'] fake_local = stage2_data['fake_local'] for type_key in self.stage2_loss_type: tmp_loss = self.calculate_loss_with_type( type_key, fake_res, fake_img, gt, mask, prefix='stage2_', fake_local=fake_local) loss.update(tmp_loss) results.update( dict( stage2_fake_res=stage2_data['fake_res'].cpu(), stage2_fake_img=stage2_data['fake_img'].cpu())) return results, loss def calculate_loss_with_type(self, loss_type, fake_res, fake_img, gt, mask, prefix='stage1_', fake_local=None): """Calculate multiple types of losses. Args: loss_type (str): Type of the loss. fake_res (torch.Tensor): Direct results from model. fake_img (torch.Tensor): Composited results from model. gt (torch.Tensor): Ground-truth tensor. mask (torch.Tensor): Mask tensor. prefix (str, optional): Prefix for loss name. Defaults to 'stage1\_'. # noqa fake_local (torch.Tensor, optional): Local results from model. Defaults to None. Returns: dict: Contain loss value with its name. """ loss_dict = dict() if loss_type == 'loss_gan': g_fake_global_pred, g_fake_local_pred = self.disc( (fake_img, fake_local)) loss_g_fake_global = self.loss_gan( g_fake_global_pred, True, is_disc=False) loss_g_fake_local = self.loss_gan( g_fake_local_pred, True, is_disc=False) loss_dict[prefix + 'loss_g_fake'] = loss_g_fake_global + loss_g_fake_local elif 'percep' in loss_type: loss_pecep, loss_style = self.loss_percep(fake_img, gt) if loss_pecep is not None: loss_dict[prefix + loss_type] = loss_pecep if loss_style is not None: loss_dict[prefix + loss_type[:-6] + 'style'] = loss_style elif 'tv' in loss_type: loss_tv = self.loss_tv(fake_img, mask=mask) loss_dict[prefix + loss_type] = loss_tv elif 'l1' in loss_type: weight = 1. - mask if 'valid' in loss_type else mask loss_l1 = getattr(self, loss_type)(fake_res, gt, weight=weight) loss_dict[prefix + loss_type] = loss_l1 else: raise NotImplementedError( f'Please check your loss type {loss_type}' ' and the config dict in init function. ' 'We cannot find the related loss function.') return loss_dict def train_step(self, data: List[dict], optim_wrapper): """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. optimize discriminator (if have) 3. optimize generator If `self.train_cfg.disc_step > 1`, the train step will contain multiple iterations for optimizing discriminator with different input data and only one iteration for optimizing generator after `disc_step` iterations for discriminator. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of \ samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} masked_img = batch_inputs # float gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() # PyTorch 2.0 could not compile 'data_samples.mask_bbox' # bbox_tensor = torch.LongTensor(data_samples.mask_bbox) bbox_tensor = torch.LongTensor(data_samples.metainfo['mask_bbox']) # get common output from encdec # input with ones tmp_ones = torch.ones_like(mask) input_x = torch.cat([masked_img, tmp_ones, mask], dim=1) stage1_fake_res, stage2_fake_res = self.generator(input_x) stage1_fake_img = masked_img * (1. - mask) + stage1_fake_res * mask stage2_fake_img = masked_img * (1. - mask) + stage2_fake_res * mask stage2_fake_local, bbox_new = extract_around_bbox( stage2_fake_img, bbox_tensor, self.train_cfg.local_size) gt_local = extract_bbox_patch(bbox_new, gt_img) fake_gt_local = torch.cat([stage2_fake_local, gt_local], dim=2) # discriminator training step # In this version, we only use the results from the second stage to # train discriminators, which is a commonly used setting. This can be # easily modified to your custom training schedule. if self.train_cfg.disc_step > 0 and self.with_gan: set_requires_grad(self.disc, True) fake_data = (stage2_fake_img.detach(), stage2_fake_local.detach()) real_data = (gt_img, gt_local) disc_losses = self.forward_train_d(fake_data, False, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].zero_grad() optim_wrapper['disc'].backward(loss_disc) disc_losses = self.forward_train_d(real_data, True, is_disc=True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].backward(loss_disc) if self.with_gp_loss: if hasattr(self.disc, 'module'): global_disc = self.disc.module.global_disc local_disc = self.disc.module.local_disc else: global_disc = self.disc.global_disc local_disc = self.disc.local_disc loss_gp_global = self.loss_gp( global_disc, gt_img, stage2_fake_img, mask=mask) loss_gp_local = self.loss_gp(local_disc, gt_local, stage2_fake_local) loss_disc, log_vars_d = self.parse_losses( dict( loss_gp_global=loss_gp_global, loss_gp_local=loss_gp_local)) log_vars.update(log_vars_d) optim_wrapper['disc'].backward(loss_disc) optim_wrapper['disc'].step() self.disc_step_count = (self.disc_step_count + 1) % self.train_cfg.disc_step if self.disc_step_count != 0: # results contain the data for visualization results = dict( gt_img=gt_img.cpu(), masked_img=masked_img.cpu(), stage1_fake_res=stage1_fake_res.cpu(), stage1_fake_img=stage1_fake_img.cpu(), stage2_fake_res=stage2_fake_res.cpu(), stage2_fake_img=stage2_fake_img.cpu(), fake_gt_local=fake_gt_local.cpu(), fake_res=stage2_fake_res.cpu(), fake_img=stage2_fake_img.cpu()) return log_vars # prepare stage1 results and stage2 results dict for calculating losses stage1_results = dict( fake_res=stage1_fake_res, fake_img=stage1_fake_img) stage2_results = dict( fake_res=stage2_fake_res, fake_img=stage2_fake_img, fake_local=stage2_fake_local) # generator (encdec) and refiner training step, results contain the # data for visualization if self.with_gan: set_requires_grad(self.disc, False) results, two_stage_losses = self.two_stage_loss( stage1_results, stage2_results, gt_img, mask, masked_img) loss_two_stage, log_vars_two_stage = self.parse_losses( two_stage_losses) log_vars.update(log_vars_two_stage) optim_wrapper['generator'].zero_grad() optim_wrapper['generator'].backward(loss_two_stage) optim_wrapper['generator'].step() results['fake_gt_local'] = fake_gt_local.cpu() return log_vars ================================================ FILE: mmagic/models/editors/deepfillv2/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .two_stage_encoder_decoder import DeepFillEncoderDecoder __all__ = ['DeepFillEncoderDecoder'] ================================================ FILE: mmagic/models/editors/deepfillv2/two_stage_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init, normal_init from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.registry import MODELS @MODELS.register_module() class DeepFillEncoderDecoder(BaseModule): """Two-stage encoder-decoder structure used in DeepFill model. The details are in: Generative Image Inpainting with Contextual Attention Args: stage1 (dict): Config dict for building stage1 model. As DeepFill model uses Global&Local model as baseline in first stage, the stage1 model can be easily built with `GLEncoderDecoder`. stage2 (dict): Config dict for building stage2 model. return_offset (bool): Whether to return offset feature in contextual attention module. Default: False. """ def __init__(self, stage1=dict( type='GLEncoderDecoder', encoder=dict(type='DeepFillEncoder'), decoder=dict(type='DeepFillDecoder', in_channels=128), dilation_neck=dict( type='GLDilationNeck', in_channels=128, act_cfg=dict(type='ELU'))), stage2=dict(type='DeepFillRefiner'), return_offset=False): super().__init__() self.stage1 = MODELS.build(stage1) self.stage2 = MODELS.build(stage2) self.return_offset = return_offset # support fp16 self.fp16_enabled = False def forward(self, x): """Forward function. Args: x (torch.Tensor): This input tensor has the shape of (n, 5, h, w). In channel dimension, we concatenate [masked_img, ones, mask] as DeepFillv1 models do. Returns: tuple[torch.Tensor]: The first two item is the results from first \ and second stage. If set `return_offset` as True, the offset \ will be returned as the third item. """ input_x = x.clone() masked_img = input_x[:, :3, ...] mask = input_x[:, -1:, ...] x = self.stage1(x) stage1_res = x.clone() stage1_img = stage1_res * mask + masked_img * (1. - mask) stage2_input = torch.cat([stage1_img, input_x[:, 3:, ...]], dim=1) stage2_res, offset = self.stage2(stage2_input, mask) if self.return_offset: return stage1_res, stage2_res, offset return stage1_res, stage2_res # TODO: study the effects of init functions def init_weights(self): """Init weights for models.""" for m in self.modules(): if isinstance(m, nn.Conv2d): normal_init(m, 0, 0.02) elif isinstance(m, (_BatchNorm, nn.InstanceNorm2d)): constant_init(m, 1) self._is_init = True ================================================ FILE: mmagic/models/editors/dic/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .dic import DIC from .dic_net import (DICNet, FeedbackBlock, FeedbackBlockCustom, FeedbackBlockHeatmapAttention) from .feedback_hour_glass import FeedbackHourglass from .light_cnn import LightCNN, MaxFeature __all__ = [ 'DICNet', 'DIC', 'FeedbackHourglass', 'LightCNN', 'MaxFeature', 'FeedbackBlock', 'FeedbackBlockCustom', 'FeedbackBlockHeatmapAttention', ] ================================================ FILE: mmagic/models/editors/dic/dic.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List import torch from mmengine.optim import OptimWrapperDict from mmagic.models.utils import set_requires_grad from mmagic.registry import MODELS from ..srgan import SRGAN @MODELS.register_module() class DIC(SRGAN): """DIC model for Face Super-Resolution. Paper: Deep Face Super-Resolution with Iterative Collaboration between Attentive Recovery and Landmark Estimation. Args: generator (dict): Config for the generator. pixel_loss (dict): Config for the pixel loss. align_loss (dict): Config for the align loss. discriminator (dict): Config for the discriminator. Default: None. gan_loss (dict): Config for the gan loss. Default: None. feature_loss (dict): Config for the feature loss. Default: None. train_cfg (dict): Config for train. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Default: None. """ def __init__(self, generator, pixel_loss, align_loss, discriminator=None, gan_loss=None, feature_loss=None, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, discriminator=discriminator, gan_loss=gan_loss, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.align_loss = MODELS.build(align_loss) self.feature_loss = MODELS.build( feature_loss) if feature_loss else None self.pixel_init = train_cfg.get('pixel_init', 0) if train_cfg else 0 def forward_tensor(self, inputs, data_samples=None, training=False): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. training (bool): Whether is training. Default: False. Returns: (Tensor | Tuple[List[Tensor]]): results of forward inference and forward train. """ sr_list, heatmap_list = self.generator(inputs) if training: return sr_list, heatmap_list else: return sr_list[-1] def if_run_g(self): """Calculates whether need to run the generator step.""" return True def if_run_d(self): """Calculates whether need to run the discriminator step.""" return self.step_counter >= self.pixel_init and super().if_run_d() def g_step(self, batch_outputs, batch_gt_data): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ sr_list, heatmap_list = batch_outputs gt, gt_heatmap = batch_gt_data losses = dict() # pix loss for step, (sr, heatmap) in enumerate(zip(sr_list, heatmap_list)): losses[f'loss_pixel_v{step}'] = self.pixel_loss(sr, gt) losses[f'loss_align_v{step}'] = self.align_loss( heatmap, gt_heatmap) if self.step_counter >= self.pixel_init: pred = sr_list[-1] # perceptual loss if self.feature_loss: loss_feature = self.feature_loss(pred, gt) losses['loss_feature'] = loss_feature # gan loss for generator if self.gan_loss and self.discriminator: fake_g_pred = self.discriminator(pred) losses['loss_gan'] = self.gan_loss( fake_g_pred, target_is_real=True, is_disc=False) return losses def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step of GAN-based method. Args: data (List[dict]): Data sampled from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ g_optim_wrapper = optim_wrapper['generator'] data = self.data_preprocessor(data, True) batch_inputs = data['inputs'] data_samples = data['data_samples'] batch_gt_data = self.extract_gt_data(data_samples) log_vars = dict() with g_optim_wrapper.optim_context(self): batch_outputs = self.forward_train(batch_inputs, data_samples) if self.if_run_g(): set_requires_grad(self.discriminator, False) log_vars_d = self.g_step_with_optim( batch_outputs=batch_outputs, batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if self.if_run_d(): set_requires_grad(self.discriminator, True) sr_list, _ = batch_outputs gt, _ = batch_gt_data for _ in range(self.disc_repeat): # detach before function call to resolve PyTorch2.0 compile bug log_vars_d = self.d_step_with_optim( batch_outputs=sr_list[-1].detach(), batch_gt_data=gt, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if 'loss' in log_vars: log_vars.pop('loss') self.step_counter += 1 return log_vars @staticmethod def extract_gt_data(data_samples): """extract gt data from data samples. Args: data_samples (list): List of DataSample. Returns: Tensor: Extract gt data. """ batch_gt_img = data_samples.gt_img batch_gt_heatmap = data_samples.gt_heatmap return [batch_gt_img, batch_gt_heatmap] ================================================ FILE: mmagic/models/editors/dic/dic_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.models.utils import make_layer from mmagic.registry import MODELS from .feedback_hour_glass import FeedbackHourglass, reduce_to_five_heatmaps @MODELS.register_module() class DICNet(BaseModule): """DIC network structure for face super-resolution. Paper: Deep Face Super-Resolution with Iterative Collaboration between Attentive Recovery and Landmark Estimation Args: in_channels (int): Number of channels in the input image out_channels (int): Number of channels in the output image mid_channels (int): Channel number of intermediate features. Default: 64 num_blocks (tuple[int]): Block numbers in the trunk network. Default: 6 hg_mid_channels (int): Channel number of intermediate features of HourGlass. Default: 256 hg_num_keypoints (int): Keypoint number of HourGlass. Default: 68 num_steps (int): Number of iterative steps. Default: 4 upscale_factor (int): Upsampling factor. Default: 8 detach_attention (bool): Detached from the current tensor for heatmap or not. prelu_init (float): `init` of PReLU. Default: 0.2 num_heatmaps (int): Number of heatmaps. Default: 5 num_fusion_blocks (int): Number of fusion blocks. Default: 7 init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels, out_channels, mid_channels, num_blocks=6, hg_mid_channels=256, hg_num_keypoints=68, num_steps=4, upscale_factor=8, detach_attention=False, prelu_init=0.2, num_heatmaps=5, num_fusion_blocks=7, init_cfg=None): super().__init__(init_cfg=init_cfg) self.num_steps = num_steps self.detach_attention = detach_attention self.conv_first = nn.Sequential( nn.Conv2d(in_channels, mid_channels * 4, 3, 1, 1), nn.PReLU(init=prelu_init), nn.PixelShuffle(2)) self.first_block = FeedbackBlockCustom( in_channels=mid_channels, mid_channels=mid_channels, num_blocks=num_blocks, upscale_factor=upscale_factor) self.block = FeedbackBlockHeatmapAttention( mid_channels=mid_channels, num_blocks=num_blocks, upscale_factor=upscale_factor, num_heatmaps=num_heatmaps, num_fusion_blocks=num_fusion_blocks) self.block.need_reset = False self.hour_glass = FeedbackHourglass( mid_channels=hg_mid_channels, num_keypoints=hg_num_keypoints) self.conv_last = nn.Sequential( nn.ConvTranspose2d(mid_channels, mid_channels, 8, 4, 2), nn.PReLU(init=prelu_init), nn.Conv2d(mid_channels, out_channels, 3, 1, 1)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor. Returns: Tensor: Forward results. sr_outputs (list[Tensor]): forward sr results. heatmap_outputs (list[Tensor]): forward heatmap results. """ inter_res = nn.functional.interpolate( x, size=(128, 128), mode='bilinear', align_corners=False) x = self.conv_first(x) sr_outputs = [] heatmap_outputs = [] last_hidden = None heatmap = None for step in range(self.num_steps): if step == 0: sr_feature = self.first_block(x) self.block.last_hidden = sr_feature else: heatmap = reduce_to_five_heatmaps(heatmap, self.detach_attention) sr_feature = self.block(x, heatmap) sr = self.conv_last(sr_feature) sr = torch.add(inter_res, sr) heatmap, last_hidden = self.hour_glass(sr, last_hidden) sr_outputs.append(sr) heatmap_outputs.append(heatmap) return sr_outputs, heatmap_outputs class FeedbackBlock(nn.Module): """Feedback Block of DIC. It has a style of: .. code-block:: text ----- Module -----> ^ | |____________| Args: mid_channels (int): Number of channels in the intermediate features. num_blocks (int): Number of blocks. upscale_factor (int): upscale factor. padding (int): Padding size. Default: 2. prelu_init (float): `init` of PReLU. Default: 0.2 """ def __init__(self, mid_channels, num_blocks, upscale_factor, padding=2, prelu_init=0.2): super().__init__() stride = upscale_factor kernel_size = upscale_factor + 4 self.num_blocks = num_blocks self.need_reset = True self.last_hidden = None self.conv_first = nn.Sequential( nn.Conv2d(2 * mid_channels, mid_channels, kernel_size=1), nn.PReLU(init=prelu_init)) self.up_blocks = nn.ModuleList() self.down_blocks = nn.ModuleList() self.lr_blocks = nn.ModuleList() self.hr_blocks = nn.ModuleList() for idx in range(self.num_blocks): self.up_blocks.append( nn.Sequential( nn.ConvTranspose2d(mid_channels, mid_channels, kernel_size, stride, padding), nn.PReLU(init=prelu_init))) self.down_blocks.append( nn.Sequential( nn.Conv2d(mid_channels, mid_channels, kernel_size, stride, padding), nn.PReLU(init=prelu_init))) if idx > 0: self.lr_blocks.append( nn.Sequential( nn.Conv2d( mid_channels * (idx + 1), mid_channels, kernel_size=1), nn.PReLU(init=prelu_init))) self.hr_blocks.append( nn.Sequential( nn.Conv2d( mid_channels * (idx + 1), mid_channels, kernel_size=1), nn.PReLU(init=prelu_init))) self.conv_last = nn.Sequential( nn.Conv2d(num_blocks * mid_channels, mid_channels, kernel_size=1), nn.PReLU(init=prelu_init)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.need_reset: self.last_hidden = x self.need_reset = False x = torch.cat((x, self.last_hidden), dim=1) x = self.conv_first(x) lr_features = [x] hr_features = [] for idx in range(self.num_blocks): # when idx == 0, lr_features == [x] lr = torch.cat(lr_features, 1) if idx > 0: lr = self.lr_blocks[idx - 1](lr) hr = self.up_blocks[idx](lr) hr_features.append(hr) hr = torch.cat(hr_features, 1) if idx > 0: hr = self.hr_blocks[idx - 1](hr) lr = self.down_blocks[idx](hr) lr_features.append(lr) output = torch.cat(lr_features[1:], 1) output = self.conv_last(output) self.last_hidden = output return output class FeedbackBlockCustom(FeedbackBlock): """Custom feedback block, will be used as the first feedback block. Args: in_channels (int): Number of channels in the input features. mid_channels (int): Number of channels in the intermediate features. num_blocks (int): Number of blocks. upscale_factor (int): upscale factor. """ def __init__(self, in_channels, mid_channels, num_blocks, upscale_factor): super().__init__(mid_channels, num_blocks, upscale_factor) prelu_init = 0.2 self.conv_first = nn.Sequential( nn.Conv2d(in_channels, mid_channels, kernel_size=1), nn.PReLU(init=prelu_init)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.conv_first(x) lr_features = [x] hr_features = [] for idx in range(self.num_blocks): # when idx == 0, lr_features == [x] lr = torch.cat(lr_features, 1) if idx > 0: lr = self.lr_blocks[idx - 1](lr) hr = self.up_blocks[idx](lr) hr_features.append(hr) hr = torch.cat(hr_features, 1) if idx > 0: hr = self.hr_blocks[idx - 1](hr) lr = self.down_blocks[idx](hr) lr_features.append(lr) output = torch.cat(lr_features[1:], 1) output = self.conv_last(output) return output class GroupResBlock(nn.Module): """ResBlock with Group Conv. Args: in_channels (int): Channel number of input features. out_channels (int): Channel number of output features. mid_channels (int): Channel number of intermediate features. groups (int): Number of blocked connections from input to output. res_scale (float): Used to scale the residual before addition. Default: 1.0. """ def __init__(self, in_channels, out_channels, mid_channels, groups, res_scale=1.0): super().__init__() self.res = nn.Sequential( nn.Conv2d(in_channels, mid_channels, 3, 1, 1, groups=groups), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(mid_channels, out_channels, 3, 1, 1, groups=groups)) self.res_scale = res_scale def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ res = self.res(x).mul(self.res_scale) return x + res class FeatureHeatmapFusingBlock(nn.Module): """Fusing Feature and Heatmap. Args: in_channels (int): Number of channels in the input features. num_heatmaps (int): Number of heatmap. num_blocks (int): Number of blocks. mid_channels (int | None): Number of channels in the intermediate features. Default: None """ def __init__(self, in_channels, num_heatmaps, num_blocks, mid_channels=None): super().__init__() self.num_heatmaps = num_heatmaps res_block_channel = in_channels * num_heatmaps if mid_channels is None: self.mid_channels = num_heatmaps * in_channels else: self.mid_channels = mid_channels self.conv_first = nn.Sequential( nn.Conv2d(in_channels, res_block_channel, kernel_size=1), nn.LeakyReLU(negative_slope=0.2, inplace=True)) self.body = make_layer( GroupResBlock, num_blocks, in_channels=res_block_channel, out_channels=res_block_channel, mid_channels=self.mid_channels, groups=num_heatmaps) def forward(self, feature, heatmap): """Forward function. Args: feature (Tensor): Input feature tensor. heatmap (Tensor): Input heatmap tensor. Returns: Tensor: Forward results. """ assert self.num_heatmaps == heatmap.size(1) batch_size = heatmap.size(0) w, h = feature.shape[-2:] feature = self.conv_first(feature) # B * (num_heatmaps*in_channels) * h * w feature = self.body(feature) attention = nn.functional.softmax( heatmap, dim=1) # B * num_heatmaps * h * w feature = feature.view(batch_size, self.num_heatmaps, -1, w, h) * attention.unsqueeze(2) feature = feature.sum(1) return feature class FeedbackBlockHeatmapAttention(FeedbackBlock): """Feedback block with HeatmapAttention. Args: in_channels (int): Number of channels in the input features. mid_channels (int): Number of channels in the intermediate features. num_blocks (int): Number of blocks. upscale_factor (int): upscale factor. padding (int): Padding size. Default: 2. prelu_init (float): `init` of PReLU. Default: 0.2 """ def __init__(self, mid_channels, num_blocks, upscale_factor, num_heatmaps, num_fusion_blocks, padding=2, prelu_init=0.2): super().__init__( mid_channels, num_blocks, upscale_factor, padding=padding, prelu_init=prelu_init) self.fusion_block = FeatureHeatmapFusingBlock(mid_channels, num_heatmaps, num_fusion_blocks) def forward(self, x, heatmap): """Forward function. Args: x (Tensor): Input feature tensor. heatmap (Tensor): Input heatmap tensor. Returns: Tensor: Forward results. """ if self.need_reset: self.last_hidden = x self.need_reset = False x = torch.cat((x, self.last_hidden), dim=1) x = self.conv_first(x) # fusion x = self.fusion_block(x, heatmap) lr_features = [] hr_features = [] lr_features.append(x) for idx in range(self.num_blocks): # when idx == 0, lr_features == [x] lr = torch.cat(lr_features, 1) if idx > 0: lr = self.lr_blocks[idx - 1](lr) hr = self.up_blocks[idx](lr) hr_features.append(hr) hr = torch.cat(hr_features, 1) if idx > 0: hr = self.hr_blocks[idx - 1](hr) lr = self.down_blocks[idx](hr) lr_features.append(lr) output = torch.cat(lr_features[1:], 1) output = self.conv_last(output) self.last_hidden = output return output ================================================ FILE: mmagic/models/editors/dic/feedback_hour_glass.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class FeedbackHourglass(BaseModule): """Feedback Hourglass model for face landmark. It has a style of: :: -- preprocessing ----- Hourglass -----> ^ | |_______________| Args: mid_channels (int): Number of channels in the intermediate features. num_keypoints (int): Number of keypoints. """ def __init__(self, mid_channels, num_keypoints): super().__init__() self.mid_channels = mid_channels self.num_keypoints = num_keypoints self.pre_conv_block = nn.Sequential( nn.Conv2d(3, self.mid_channels // 4, 7, 2, 3), nn.ReLU(inplace=True), ResBlock(self.mid_channels // 4, self.mid_channels // 2), nn.MaxPool2d(2, 2), ResBlock(self.mid_channels // 2, self.mid_channels // 2), ResBlock(self.mid_channels // 2, self.mid_channels), ) self.first_conv = nn.Conv2d(2 * self.mid_channels, 2 * self.mid_channels, 1) self.hg = Hourglass(4, 2 * self.mid_channels) self.last = nn.Sequential( ResBlock(self.mid_channels, self.mid_channels), nn.Conv2d(self.mid_channels, self.mid_channels, 1), nn.ReLU(inplace=True), nn.Conv2d(self.mid_channels, self.num_keypoints, 1)) def forward(self, x, last_hidden=None): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). last_hidden (Tensor | None): The feedback of FeedbackHourglass. In first step, last_hidden=None. Otherwise, last_hidden is the past output of FeedbackHourglass. Default: None. Returns: heatmap (Tensor): Heatmap of facial landmark. feedback (Tensor): Feedback Tensor. """ feature = self.pre_conv_block(x) if last_hidden is None: feature = self.first_conv(torch.cat((feature, feature), dim=1)) else: feature = self.first_conv(torch.cat((feature, last_hidden), dim=1)) feature = self.hg(feature) heatmap = self.last(feature[:, :self.mid_channels]) # first half feedback = feature[:, self.mid_channels:] # second half return heatmap, feedback class ResBlock(nn.Module): """ResBlock for Hourglass. It has a style of: :: ---Conv-ReLU-Conv-Conv-+- |_________Conv________| or ---Conv-ReLU-Conv-Conv-+- |_____________________| Args: in_channels (int): Number of channels in the input features. out_channels (int): Number of channels in the output features. """ def __init__(self, in_channels, out_channels): super().__init__() self.conv_block = nn.Sequential( nn.Conv2d(in_channels, out_channels // 2, 1), nn.ReLU(inplace=True), nn.Conv2d( out_channels // 2, out_channels // 2, 3, stride=1, padding=1), nn.Conv2d(out_channels // 2, out_channels, 1)) if in_channels == out_channels: self.skip_layer = None else: self.skip_layer = nn.Conv2d(in_channels, out_channels, 1) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ residual = self.conv_block(x) if self.skip_layer: x = self.skip_layer(x) return x + residual class Hourglass(nn.Module): """Hourglass model for face landmark. It is a recursive model. Args: depth (int): Depth of Hourglass, the number of recursions. mid_channels (int): Number of channels in the intermediate features. """ def __init__(self, depth, mid_channels): super().__init__() self.up1 = ResBlock(mid_channels, mid_channels) self.pool = nn.MaxPool2d(2, 2) self.low1 = ResBlock(mid_channels, mid_channels) if depth == 1: self.low2 = ResBlock(mid_channels, mid_channels) else: self.low2 = Hourglass(depth - 1, mid_channels) self.low3 = ResBlock(mid_channels, mid_channels) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ up1 = self.up1(x) low1 = self.low1(self.pool(x)) low2 = self.low2(low1) low3 = self.low3(low2) up2 = nn.functional.interpolate( low3, scale_factor=2, mode='bilinear', align_corners=True) return up1 + up2 def reduce_to_five_heatmaps(ori_heatmap, detach): """Reduce facial landmark heatmaps to 5 heatmaps. DIC realizes facial SR with the help of key points of the face. The number of key points in datasets are different from each other. This function reduces the input heatmaps into 5 heatmaps: left eye right eye nose mouse face silhouette Args: ori_heatmap (Tensor): Input heatmap tensor. (B, N, 32, 32). detach (bool): Detached from the current tensor or not. returns: Tensor: New heatmap tensor. (B, 5, 32, 32). """ heatmap = ori_heatmap.clone() max_heat = heatmap.max(dim=2, keepdim=True)[0].max(dim=3, keepdim=True)[0] max_heat = max_heat.clamp_min_(0.05) heatmap /= max_heat if heatmap.size(1) == 5: return heatmap.detach() if detach else heatmap elif heatmap.size(1) == 68: new_heatmap = torch.zeros_like(heatmap[:, :5]) new_heatmap[:, 0] = heatmap[:, 36:42].sum(1) # left eye new_heatmap[:, 1] = heatmap[:, 42:48].sum(1) # right eye new_heatmap[:, 2] = heatmap[:, 27:36].sum(1) # nose new_heatmap[:, 3] = heatmap[:, 48:68].sum(1) # mouse new_heatmap[:, 4] = heatmap[:, :27].sum(1) # face silhouette return new_heatmap.detach() if detach else new_heatmap elif heatmap.size(1) == 194: # Helen new_heatmap = torch.zeros_like(heatmap[:, :5]) tmp_id = torch.cat((torch.arange(134, 153), torch.arange(174, 193))) new_heatmap[:, 0] = heatmap[:, tmp_id].sum(1) # left eye tmp_id = torch.cat((torch.arange(114, 133), torch.arange(154, 173))) new_heatmap[:, 1] = heatmap[:, tmp_id].sum(1) # right eye tmp_id = torch.arange(41, 57) new_heatmap[:, 2] = heatmap[:, tmp_id].sum(1) # nose tmp_id = torch.arange(58, 113) new_heatmap[:, 3] = heatmap[:, tmp_id].sum(1) # mouse tmp_id = torch.arange(0, 40) new_heatmap[:, 4] = heatmap[:, tmp_id].sum(1) # face silhouette return new_heatmap.detach() if detach else new_heatmap else: raise NotImplementedError( f'Face landmark number {heatmap.size(1)} not implemented!') ================================================ FILE: mmagic/models/editors/dic/light_cnn.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine import MMLogger from mmengine.model import BaseModule from mmengine.runner import load_checkpoint from mmagic.registry import MODELS @MODELS.register_module() class LightCNN(BaseModule): """LightCNN discriminator with input size 128 x 128. It is used to train DICGAN. Args: in_channels (int): Channel number of inputs. """ def __init__(self, in_channels): super().__init__() self.features = nn.Sequential( MaxFeature(in_channels, 48, 5, 1, 2), nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), MaxFeature(48, 48, 1, 1, 0), MaxFeature(48, 96, 3, 1, 1), nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), MaxFeature(96, 96, 1, 1, 0), MaxFeature(96, 192, 3, 1, 1), nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), MaxFeature(192, 192, 1, 1, 0), MaxFeature(192, 128, 3, 1, 1), MaxFeature(128, 128, 1, 1, 0), MaxFeature(128, 128, 3, 1, 1), nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True), ) self.classifier = nn.Sequential( MaxFeature(8 * 8 * 128, 256, filter_type='linear'), nn.LeakyReLU(0.2, True), nn.Linear(256, 1)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor. Returns: Tensor: Forward results. """ x = self.features(x) x = x.view(x.size(0), -1) out = self.classifier(x) return out def init_weights(self, pretrained=None, strict=True): """Init weights for models. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. strict (boo, optional): Whether strictly load the pretrained model. Defaults to True. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=strict, logger=logger) elif pretrained is not None: raise TypeError(f'"pretrained" must be a str or None. ' f'But received {type(pretrained)}.') class MaxFeature(nn.Module): """Conv2d or Linear layer with max feature selector. Generate feature maps with double channels, split them and select the max feature. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. kernel_size (int or tuple): Size of the convolving kernel. stride (int or tuple, optional): Stride of the convolution. Default: 1 padding (int or tuple, optional): Zero-padding added to both sides of the input. Default: 1 filter_type (str): Type of filter. Options are 'conv2d' and 'linear'. Default: 'conv2d'. """ def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, filter_type='conv2d'): super().__init__() self.out_channels = out_channels filter_type = filter_type.lower() if filter_type == 'conv2d': self.filter = nn.Conv2d( in_channels, 2 * out_channels, kernel_size=kernel_size, stride=stride, padding=padding) elif filter_type == 'linear': self.filter = nn.Linear(in_channels, 2 * out_channels) else: raise ValueError("'filter_type' should be 'conv2d' or 'linear', " f'but got {filter_type}') def forward(self, x): """Forward function. Args: x (Tensor): Input tensor. Returns: Tensor: Forward results. """ x = self.filter(x) out = torch.chunk(x, chunks=2, dim=1) return torch.max(out[0], out[1]) ================================================ FILE: mmagic/models/editors/dim/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .dim import DIM __all__ = ['DIM'] ================================================ FILE: mmagic/models/editors/dim/dim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Tuple import torch from mmengine.logging import MMLogger from mmagic.models.base_models import BaseMattor from mmagic.models.utils import get_unknown_tensor from mmagic.registry import MODELS @MODELS.register_module() class DIM(BaseMattor): """Deep Image Matting model. https://arxiv.org/abs/1703.03872 .. note:: For ``(self.train_cfg.train_backbone, self.train_cfg.train_refiner)``: * ``(True, False)`` corresponds to the encoder-decoder stage in \ the paper. * ``(False, True)`` corresponds to the refinement stage in the \ paper. * ``(True, True)`` corresponds to the fine-tune stage in the paper. Args: data_preprocessor (dict, optional): Config of data pre-processor. backbone (dict): Config of backbone. refiner (dict): Config of refiner. loss_alpha (dict): Config of the alpha prediction loss. Default: None. loss_comp (dict): Config of the composition loss. Default: None. loss_refine (dict): Config of the loss of the refiner. Default: None. train_cfg (dict): Config of training. In ``train_cfg``, ``train_backbone`` should be specified. If the model has a refiner, ``train_refiner`` should be specified. test_cfg (dict): Config of testing. In ``test_cfg``, If the model has a refiner, ``train_refiner`` should be specified. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. """ def __init__(self, data_preprocessor, backbone, refiner=None, train_cfg=None, test_cfg=None, loss_alpha=None, loss_comp=None, loss_refine=None, init_cfg: Optional[dict] = None): # Build data _preprocessor and backbone # No init here, init at last super().__init__( backbone=backbone, data_preprocessor=data_preprocessor, init_cfg=init_cfg, train_cfg=train_cfg, test_cfg=test_cfg) # build refiner if it's not None. if refiner is None: self.train_cfg['train_refiner'] = False self.test_cfg['refine'] = False else: self.refiner = MODELS.build(refiner) # if argument train_cfg is not None, validate if the config is proper. assert hasattr(self.train_cfg, 'train_refiner') assert hasattr(self.test_cfg, 'refine') if self.test_cfg.refine and not self.train_cfg.train_refiner: logger = MMLogger.get_current_instance() logger.warning( 'You are not training the refiner, but it is used for ' 'model forwarding.') if not self.train_cfg.train_backbone: self.freeze_backbone() # Build losses if all(v is None for v in (loss_alpha, loss_comp, loss_refine)): raise ValueError('Please specify at least one loss for DIM.') if loss_alpha is not None: self.loss_alpha = MODELS.build(loss_alpha) if loss_comp is not None: self.loss_comp = MODELS.build(loss_comp) if loss_refine is not None: self.loss_refine = MODELS.build(loss_refine) def init_weights(self): """Initialize the model network weights.""" super().init_weights() if self.with_refiner: self.refiner.init_weights() @property def with_refiner(self): """Whether the matting model has a refiner.""" return hasattr(self, 'refiner') and self.refiner is not None def train(self, mode=True): """Mode switcher. Args: mode (bool): whether to set training mode (``True``) or evaluation mode (``False``). Default: ``True``. """ super().train(mode) if mode and (not self.train_cfg.train_backbone): self.backbone.eval() def freeze_backbone(self): """Freeze the backbone and only train the refiner.""" self.backbone.eval() for param in self.backbone.parameters(): param.requires_grad = False def _forward(self, x: torch.Tensor, *, refine: bool = True) -> Tuple[torch.Tensor, torch.Tensor]: """Raw forward function. Args: x (torch.Tensor): Concatenation of merged image and trimap with shape (N, 4, H, W) refine (bool): if forward through refiner Returns: torch.Tensor: pred_alpha, with shape (N, 1, H, W) torch.Tensor: pred_refine, with shape (N, 4, H, W) """ raw_alpha = self.backbone(x) pred_alpha = raw_alpha.sigmoid() if refine and hasattr(self, 'refiner'): refine_input = torch.cat((x[:, :3, :, :], pred_alpha), 1) pred_refine = self.refiner(refine_input, raw_alpha) else: # As ONNX does not support NoneType for output, # we choose to use zero tensor to represent None pred_refine = torch.zeros([]) return pred_alpha, pred_refine def _forward_test(self, inputs): """Forward to get alpha prediction.""" pred_alpha, pred_refine = self._forward(inputs) if self.test_cfg.refine: return pred_refine else: return pred_alpha def _forward_train(self, inputs, data_samples): """Defines the computation performed at every training call. Args: inputs (torch.Tensor): Concatenation of normalized image and trimap shape (N, 4, H, W) data_samples (list[DataSample]): Data samples containing: - gt_alpha (Tensor): Ground-truth of alpha shape (N, 1, H, W), normalized to 0 to 1. - gt_fg (Tensor): Ground-truth of foreground shape (N, C, H, W), normalized to 0 to 1. - gt_bg (Tensor): Ground-truth of background shape (N, C, H, W), normalized to 0 to 1. Returns: dict: Contains the loss items and batch information. """ # merged, trimap, meta, alpha, ori_merged, fg, bg gt_alpha = data_samples.gt_alpha gt_fg = data_samples.gt_fg gt_bg = data_samples.gt_bg gt_merged = data_samples.gt_merged pred_alpha, pred_refine = self._forward( inputs, refine=self.train_cfg.train_refiner) trimap = inputs[:, 3:, :, :] # Dim should use proc_trimap='rescale_to_zero_one' weight = get_unknown_tensor(trimap, unknown_value=128 / 255) losses = dict() if self.train_cfg.train_backbone: if self.loss_alpha is not None: losses['loss_alpha'] = self.loss_alpha(pred_alpha, gt_alpha, weight) if self.loss_comp is not None: losses['loss_comp'] = self.loss_comp(pred_alpha, gt_fg, gt_bg, gt_merged, weight) if self.train_cfg.train_refiner: losses['loss_refine'] = self.loss_refine(pred_refine, gt_alpha, weight) return losses ================================================ FILE: mmagic/models/editors/disco_diffusion/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .clip_wrapper import ClipWrapper from .disco import DiscoDiffusion from .guider import ImageTextGuider from .secondary_model import SecondaryDiffusionImageNet2, alpha_sigma_to_t __all__ = [ 'DiscoDiffusion', 'ImageTextGuider', 'ClipWrapper', 'SecondaryDiffusionImageNet2', 'alpha_sigma_to_t' ] ================================================ FILE: mmagic/models/editors/disco_diffusion/clip_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Union import torch import torch.nn as nn from mmengine import print_log from mmagic.registry import MODELS @MODELS.register_module() class ClipWrapper(nn.Module): r"""Clip Models wrapper. We provide wrappers for the clip models of ``openai`` and ``mlfoundations``, where the user can specify ``clip_type`` as ``clip`` or ``open_clip``, and then initialize a clip model using the same arguments as in the original codebase. The following clip models settings are provided in the official repo of disco diffusion: | Setting | Source | Arguments | # noqa |:-----------------------------:|-----------|--------------------------------------------------------------| # noqa | ViTB32 | clip | name='ViT-B/32', jit=False | # noqa | ViTB16 | clip | name='ViT-B/16', jit=False | # noqa | ViTL14 | clip | name='ViT-L/14', jit=False | # noqa | ViTL14_336px | clip | name='ViT-L/14@336px', jit=False | # noqa | RN50 | clip | name='RN50', jit=False | # noqa | RN50x4 | clip | name='RN50x4', jit=False | # noqa | RN50x16 | clip | name='RN50x16', jit=False | # noqa | RN50x64 | clip | name='RN50x64', jit=False | # noqa | RN101 | clip | name='RN101', jit=False | # noqa | ViTB32_laion2b_e16 | open_clip | name='ViT-B-32', pretrained='laion2b_e16' | # noqa | ViTB32_laion400m_e31 | open_clip | model_name='ViT-B-32', pretrained='laion400m_e31' | # noqa | ViTB32_laion400m_32 | open_clip | model_name='ViT-B-32', pretrained='laion400m_e32' | # noqa | ViTB32quickgelu_laion400m_e31 | open_clip | model_name='ViT-B-32-quickgelu', pretrained='laion400m_e31' | # noqa | ViTB32quickgelu_laion400m_e32 | open_clip | model_name='ViT-B-32-quickgelu', pretrained='laion400m_e32' | # noqa | ViTB16_laion400m_e31 | open_clip | model_name='ViT-B-16', pretrained='laion400m_e31' | # noqa | ViTB16_laion400m_e32 | open_clip | model_name='ViT-B-16', pretrained='laion400m_e32' | # noqa | RN50_yffcc15m | open_clip | model_name='RN50', pretrained='yfcc15m' | # noqa | RN50_cc12m | open_clip | model_name='RN50', pretrained='cc12m' | # noqa | RN50_quickgelu_yfcc15m | open_clip | model_name='RN50-quickgelu', pretrained='yfcc15m' | # noqa | RN50_quickgelu_cc12m | open_clip | model_name='RN50-quickgelu', pretrained='cc12m' | # noqa | RN101_yfcc15m | open_clip | model_name='RN101', pretrained='yfcc15m' | # noqa | RN101_quickgelu_yfcc15m | open_clip | model_name='RN101-quickgelu', pretrained='yfcc15m' | # noqa An example of a ``clip_modes_cfg`` is as follows: Examples: >>> # Use OpenAI's CLIP >>> config = dict( >>> type='ClipWrapper', >>> clip_type='clip', >>> name='ViT-B/32', >>> jit=False) >>> # Use OpenCLIP >>> config = dict( >>> type='ClipWrapper', >>> clip_type='open_clip', >>> model_name='RN50', >>> pretrained='yfcc15m') >>> # Use CLIP from Hugging Face Transformers >>> config = dict( >>> type='ClipWrapper', >>> clip_type='huggingface', >>> pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', >>> subfolder='text_encoder') Args: clip_type (List[Dict]): The original source of the clip model. Whether be ``clip``, ``open_clip`` or ``hugging_face``. *args, **kwargs: Arguments to initialize corresponding clip model. """ def __init__(self, clip_type, *args, **kwargs): super().__init__() self.clip_type = clip_type assert clip_type in ['clip', 'open_clip', 'huggingface'] error_msg = ('{} need to be installed! Run `pip install -r ' 'requirements/optional.txt` and try again') if clip_type == 'clip': try: import clip except ImportError: raise ImportError(error_msg.format('\'clip\'')) print_log(f'Creating {kwargs["name"]} by OpenAI', 'current') self.model, _ = clip.load(*args, **kwargs) elif clip_type == 'open_clip': try: import open_clip except ImportError: raise ImportError(error_msg.format('\'open_clip_torch\'')) print_log(f'Creating {kwargs["model_name"]} by ' 'mlfoundations', 'current') self.model = open_clip.create_model(*args, **kwargs) elif clip_type == 'huggingface': try: import transformers except ImportError: raise ImportError(error_msg.format('\'transforms\'')) # NOTE: use CLIPTextModel to adopt stable diffusion pipeline model_cls = transformers.CLIPTextModel self.model = model_cls.from_pretrained(*args, **kwargs) self.config = self.model.config print_log( f'Creating {self.model.name_or_path} ' 'by \'HuggingFace\'', 'current') self.model.eval().requires_grad_(False) def get_embedding_layer(self): """Function to get embedding layer of the clip model. Only support for CLIPTextModel currently. """ if self.clip_type != 'huggingface': print_log( 'Do not support \'get_embedding_layer\' for clip_type: ' f'\'{self.clip_type}\' currently.', 'current') return None if self.model.__class__.__name__ != 'CLIPTextModel': print_log( 'Only support \'get_embedding_layer\' for ' 'CLIPTextModel.', 'current') return None return self.model.text_model.embeddings.token_embedding def add_embedding(self, embeddings: Union[dict, List[dict]]): assert self.clip_type == 'huggingface', ( 'Only support add embedding for HuggingFace transformers.') assert self.model.__class__.__name__ == 'CLIPTextModel', ( 'Only support add embedding for \'CLIPTextModel\' (CLIP).') embedding_layer = self.get_embedding_layer() if not isinstance(embedding_layer, EmbeddingLayerWithFixes): self.model.embeddings = EmbeddingLayerWithFixes(embedding_layer) self.model.embeddings.add_embedding(embeddings) def set_only_embedding_trainable(self): func_name = '\'set_only_embedding_trainable\'' assert self.clip_type == 'huggingface', ( f'Only support {func_name} for HuggingFace transformers.') assert self.model.__class__.__name__ == 'CLIPTextModel', ( f'Only support {func_name} for \'CLIPTextModel\' (CLIP).') self.model.requires_grad_(False) embedding_layer = self.get_embedding_layer() if isinstance(embedding_layer, EmbeddingLayerWithFixes): embedding_layer.trainable_embeddings.requires_grad_(True) print_log('Set only embedding trainable.', 'current') else: print_log( 'Do not found EmbeddingLayerWithFixes. ' f'{func_name} do nothing.', 'current') def set_embedding_layer(self): assert self.clip_type == 'huggingface', ( 'Only support add embedding for HuggingFace transformers.') assert self.model.__class__.__name__ == 'CLIPTextModel', ( 'Only support add embedding for \'CLIPTextModel\' (CLIP).') embedding_layer = self.get_embedding_layer() if not isinstance(embedding_layer, EmbeddingLayerWithFixes): self.model.text_model.embeddings.token_embedding = \ EmbeddingLayerWithFixes(embedding_layer) print_log('Set embedding layer to EmbeddingLayerWithFixes', 'current') def unset_embedding_layer(self): wrapped_embedding_layer = self.model.embeddings if isinstance(wrapped_embedding_layer, EmbeddingLayerWithFixes): self.model.text_model.embeddings.token_embedding = \ wrapped_embedding_layer.wrapped print_log('Unset embedding layer.', 'current') def forward(self, *args, **kwargs): """Forward function.""" return self.model(*args, **kwargs) class EmbeddingLayerWithFixes(nn.Module): """The revised embedding layer to support external embeddings. This design of this class is inspired by https://github.com/AUTOMATIC1111/stable- diffusion-webui/blob/22bcc7be428c94e9408f589966c2040187245d81/modules/sd_hi jack.py#L224 # noqa. Args: wrapped (nn.Emebdding): The embedding layer to be wrapped. external_embeddings (Union[dict, List[dict]], optional): The external embeddings added to this layer. Defaults to None. """ def __init__(self, wrapped: nn.Embedding, external_embeddings: Optional[Union[dict, List[dict]]] = None): super().__init__() self.wrapped = wrapped self.num_embeddings = wrapped.weight.shape[0] self.external_embeddings = [] if external_embeddings: self.add_embeddings(external_embeddings) self.trainable_embeddings = nn.ParameterDict() @property def weight(self): """Get the weight of wrapped embedding layer.""" return self.wrapped.weight def check_duplicate_names(self, embeddings: List[dict]): """Check whether duplicate names exist in list of 'external embeddings'. Args: embeddings (List[dict]): A list of embedding to be check. """ names = [emb['name'] for emb in embeddings] assert len(names) == len(set(names)), ( 'Found duplicated names in \'external_embeddings\'. Name list: ' f'\'{names}\'') def check_ids_overlap(self, embeddings): """Check whether overlap exist in token ids of 'external_embeddings'. Args: embeddings (List[dict]): A list of embedding to be check. """ ids_range = [[emb['start'], emb['end'], emb['name']] for emb in embeddings] ids_range.sort() # sort by 'start' # check if 'end' has overlapping for idx in range(len(ids_range) - 1): name1, name2 = ids_range[idx][-1], ids_range[idx + 1][-1] assert ids_range[idx][1] <= ids_range[idx + 1][0], ( f'Found ids overlapping between embeddings \'{name1}\' ' f'and \'{name2}\'.') def add_embeddings(self, embeddings: Optional[Union[dict, List[dict]]]): """Add external embeddings to this layer. Use case: >>> 1. Add token to tokenizer and get the token id. >>> tokenizer = TokenizerWrapper('openai/clip-vit-base-patch32') >>> # 'how much' in kiswahili >>> tokenizer.add_placeholder_tokens('ngapi', num_vec_per_token=4) >>> >>> 2. Add external embeddings to the model. >>> new_embedding = { >>> 'name': 'ngapi', # 'how much' in kiswahili >>> 'embedding': torch.ones(1, 15) * 4, >>> 'start': tokenizer.get_token_info('kwaheri')['start'], >>> 'end': tokenizer.get_token_info('kwaheri')['end'], >>> 'trainable': False # if True, will registry as a parameter >>> } >>> embedding_layer = nn.Embedding(10, 15) >>> embedding_layer_wrapper = EmbeddingLayerWithFixes(embedding_layer) >>> embedding_layer_wrapper.add_embeddings(new_embedding) >>> >>> 3. Forward tokenizer and embedding layer! >>> input_text = ['hello, ngapi!', 'hello my friend, ngapi?'] >>> input_ids = tokenizer( >>> input_text, padding='max_length', truncation=True, >>> return_tensors='pt')['input_ids'] >>> out_feat = embedding_layer_wrapper(input_ids) >>> >>> 4. Let's validate the result! >>> assert (out_feat[0, 3: 7] == 2.3).all() >>> assert (out_feat[2, 5: 9] == 2.3).all() Args: embeddings (Union[dict, list[dict]]): The external embeddings to be added. Each dict must contain the following 4 fields: 'name' (the name of this embedding), 'embedding' (the embedding tensor), 'start' (the start token id of this embedding), 'end' (the end token id of this embedding). For example: `{name: NAME, start: START, end: END, embedding: torch.Tensor}` """ if isinstance(embeddings, dict): embeddings = [embeddings] self.external_embeddings += embeddings self.check_duplicate_names(self.external_embeddings) self.check_ids_overlap(self.external_embeddings) # set for trainable added_trainable_emb_info = [] for embedding in embeddings: trainable = embedding.get('trainable', False) if trainable: name = embedding['name'] embedding['embedding'] = torch.nn.Parameter( embedding['embedding']) self.trainable_embeddings[name] = embedding['embedding'] added_trainable_emb_info.append(name) added_emb_info = [emb['name'] for emb in embeddings] added_emb_info = ', '.join(added_emb_info) print_log(f'Successfully add external embeddings: {added_emb_info}.', 'current') if added_trainable_emb_info: added_trainable_emb_info = ', '.join(added_trainable_emb_info) print_log( 'Successfully add trainable external embeddings: ' f'{added_trainable_emb_info}', 'current') def replace_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor: """Replace external input ids to 0. Args: input_ids (torch.Tensor): The input ids to be replaced. Returns: torch.Tensor: The replaced input ids. """ input_ids_fwd = input_ids.clone() input_ids_fwd[input_ids_fwd >= self.num_embeddings] = 0 return input_ids_fwd def replace_embeddings(self, input_ids: torch.Tensor, embedding: torch.Tensor, external_embedding: dict) -> torch.Tensor: """Replace external embedding to the embedding layer. Noted that, in this function we use `torch.cat` to avoid inplace modification. Args: input_ids (torch.Tensor): The original token ids. Shape like [LENGTH, ]. embedding (torch.Tensor): The embedding of token ids after `replace_input_ids` function. external_embedding (dict): The external embedding to be replaced. Returns: torch.Tensor: The replaced embedding. """ new_embedding = [] name = external_embedding['name'] start = external_embedding['start'] end = external_embedding['end'] target_ids_to_replace = [i for i in range(start, end)] ext_emb = external_embedding['embedding'] # do not need to replace if not (input_ids == start).any(): return embedding # start replace s_idx, e_idx = 0, 0 while e_idx < len(input_ids): if input_ids[e_idx] == start: if e_idx != 0: # add embedding do not need to replace new_embedding.append(embedding[s_idx:e_idx]) # check if the next embedding need to replace is valid actually_ids_to_replace = [ int(i) for i in input_ids[e_idx:e_idx + end - start] ] assert actually_ids_to_replace == target_ids_to_replace, ( f'Invalid \'input_ids\' in position: {s_idx} to {e_idx}. ' f'Expect \'{target_ids_to_replace}\' for embedding ' f'\'{name}\' but found \'{actually_ids_to_replace}\'.') new_embedding.append(ext_emb) s_idx = e_idx + end - start e_idx = s_idx + 1 else: e_idx += 1 if e_idx == len(input_ids): new_embedding.append(embedding[s_idx:e_idx]) return torch.cat(new_embedding, dim=0) def forward(self, input_ids: torch.Tensor, external_embeddings: Optional[List[dict]] = None): """The forward function. Args: input_ids (torch.Tensor): The token ids shape like [bz, LENGTH] or [LENGTH, ]. external_embeddings (Optional[List[dict]]): The external embeddings. If not passed, only `self.external_embeddings` will be used. Defaults to None. input_ids: shape like [bz, LENGTH] or [LENGTH]. """ assert input_ids.ndim in [1, 2] if input_ids.ndim == 1: input_ids = input_ids.unsqueeze(0) if external_embeddings is None and not self.external_embeddings: return self.wrapped(input_ids) input_ids_fwd = self.replace_input_ids(input_ids) inputs_embeds = self.wrapped(input_ids_fwd) vecs = [] if external_embeddings is None: external_embeddings = [] elif isinstance(external_embeddings, dict): external_embeddings = [external_embeddings] embeddings = self.external_embeddings + external_embeddings for input_id, embedding in zip(input_ids, inputs_embeds): new_embedding = embedding for external_embedding in embeddings: new_embedding = self.replace_embeddings( input_id, new_embedding, external_embedding) vecs.append(new_embedding) return torch.stack(vecs) ================================================ FILE: mmagic/models/editors/disco_diffusion/disco.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Union import mmcv import mmengine import torch import torch.nn as nn from mmengine.runner import set_random_seed from mmengine.runner.checkpoint import (_load_checkpoint, _load_checkpoint_with_prefix) from tqdm import tqdm from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from .guider import ImageTextGuider ModelType = Union[Dict, nn.Module] @MODELS.register_module('disco') @MODELS.register_module('dd') @MODELS.register_module() class DiscoDiffusion(nn.Module): """Disco Diffusion (DD) is a Google Colab Notebook which leverages an AI Image generating technique called CLIP-Guided Diffusion to allow you to create compelling and beautiful images from just text inputs. Created by Somnai, augmented by Gandamu, and building on the work of RiversHaveWings, nshepperd, and many others. Ref: Github Repo: https://github.com/alembics/disco-diffusion Colab: https://colab.research.google.com/github/alembics/disco-diffusion/blob/main/Disco_Diffusion.ipynb # noqa Args: unet (ModelType): Config of denoising Unet. diffusion_scheduler (ModelType): Config of diffusion_scheduler scheduler. secondary_model (ModelType): A smaller secondary diffusion model trained by Katherine Crowson to remove noise from intermediate timesteps to prepare them for CLIP. Ref: https://twitter.com/rivershavewings/status/1462859669454536711 # noqa Defaults to None. clip_models (list): Config of clip models. Defaults to []. use_fp16 (bool): Whether to use fp16 for unet model. Defaults to False. pretrained_cfgs (dict): Path Config for pretrained weights. Usually this is a dict contains module name and the corresponding ckpt path. Defaults to None. """ def __init__(self, unet, diffusion_scheduler, secondary_model=None, clip_models=[], use_fp16=False, pretrained_cfgs=None): super().__init__() self.unet = unet if isinstance(unet, nn.Module) else MODELS.build(unet) self.diffusion_scheduler = DIFFUSION_SCHEDULERS.build( diffusion_scheduler) if isinstance(diffusion_scheduler, dict) else diffusion_scheduler assert len(clip_models) > 0 if isinstance(clip_models[0], nn.Module): _clip_models = clip_models else: _clip_models = [] for clip_cfg in clip_models: _clip_models.append(MODELS.build(clip_cfg)) self.guider = ImageTextGuider(_clip_models) if secondary_model is not None: self.secondary_model = secondary_model if isinstance( secondary_model, nn.Module) else MODELS.build(secondary_model) self.with_secondary_model = True else: self.with_secondary_model = False if pretrained_cfgs: self.load_pretrained_models(pretrained_cfgs) if use_fp16: mmengine.print_log('Convert unet modules to floatpoint16') self.unet.convert_to_fp16() def load_pretrained_models(self, pretrained_cfgs): """Loading pretrained weights to model. ``pretrained_cfgs`` is a dict consist of module name as key and checkpoint path as value. Args: pretrained_cfgs (dict): Path Config for pretrained weights. Usually this is a dict contains module name and the corresponding ckpt path. Defaults to None. """ for key, ckpt_cfg in pretrained_cfgs.items(): prefix = ckpt_cfg.get('prefix', '') map_location = ckpt_cfg.get('map_location', 'cpu') strict = ckpt_cfg.get('strict', True) ckpt_path = ckpt_cfg.get('ckpt_path') if prefix: state_dict = _load_checkpoint_with_prefix( prefix, ckpt_path, map_location) else: state_dict = _load_checkpoint(ckpt_path, map_location) getattr(self, key).load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained {key} from {ckpt_path}') @property def device(self): """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device @torch.no_grad() def infer(self, scheduler_kwargs=None, height=None, width=None, init_image=None, batch_size=1, num_inference_steps=100, skip_steps=0, show_progress=True, text_prompts=[], image_prompts=[], eta=0.8, clip_guidance_scale=5000, init_scale=1000, tv_scale=0., sat_scale=0., range_scale=150, cut_overview=[12] * 400 + [4] * 600, cut_innercut=[4] * 400 + [12] * 600, cut_ic_pow=[1] * 1000, cut_icgray_p=[0.2] * 400 + [0] * 600, cutn_batches=4, seed=None): """Inference API for disco diffusion. Args: scheduler_kwargs (dict): Args for infer time diffusion scheduler. Defaults to None. height (int): Height of output image. Defaults to None. width (int): Width of output image. Defaults to None. init_image (str): Initial image at the start point of denoising. Defaults to None. batch_size (int): Batch size. Defaults to 1. num_inference_steps (int): Number of inference steps. Defaults to 1000. skip_steps (int): Denoising steps to skip, usually set with ``init_image``. Defaults to 0. show_progress (bool): Whether to show progress. Defaults to False. text_prompts (list): Text prompts. Defaults to []. image_prompts (list): Image prompts, this is not the same as ``init_image``, they works the same way with ``text_prompts``. Defaults to []. eta (float): Eta for ddim sampling. Defaults to 0.8. clip_guidance_scale (int): The Scale of influence of prompts on output image. Defaults to 1000. seed (int): Sampling seed. Defaults to None. """ # set diffusion_scheduler if scheduler_kwargs is not None: mmengine.print_log('Switch to infer diffusion scheduler!', 'current') infer_scheduler = DIFFUSION_SCHEDULERS.build(scheduler_kwargs) else: infer_scheduler = self.diffusion_scheduler # set random seed if isinstance(seed, int): set_random_seed(seed=seed) # set step values if num_inference_steps > 0: infer_scheduler.set_timesteps(num_inference_steps) _ = image_prompts height = (height // 64) * 64 if height else self.unet.image_size width = (width // 64) * 64 if width else self.unet.image_size if init_image is None: image = torch.randn( (batch_size, self.unet.in_channels, height, width)) image = image.to(self.device) else: init = mmcv.imread(init_image, channel_order='rgb') init = mmcv.imresize( init, (width, height), interpolation='lanczos') / 255. init_image = torch.as_tensor( init, dtype=torch.float32).to(self.device).unsqueeze(0).permute( 0, 3, 1, 2).mul(2).sub(1) image = init_image.clone() image = infer_scheduler.add_noise( image, torch.randn_like(image), infer_scheduler.timesteps[skip_steps]) # get stats from text prompts and image prompts model_stats = self.guider.compute_prompt_stats( text_prompts=text_prompts) timesteps = infer_scheduler.timesteps[skip_steps:] if show_progress: timesteps = tqdm(timesteps) for t in timesteps: # 1. predicted model_output model_output = self.unet(image, t)['sample'] # 2. compute previous image: x_t -> x_t-1 cond_kwargs = dict( model_stats=model_stats, init_image=init_image, unet=self.unet, clip_guidance_scale=clip_guidance_scale, init_scale=init_scale, tv_scale=tv_scale, sat_scale=sat_scale, range_scale=range_scale, cut_overview=cut_overview, cut_innercut=cut_innercut, cut_ic_pow=cut_ic_pow, cut_icgray_p=cut_icgray_p, cutn_batches=cutn_batches, ) if self.with_secondary_model: cond_kwargs.update(secondary_model=self.secondary_model) diffusion_scheduler_output = infer_scheduler.step( model_output, t, image, cond_fn=self.guider.cond_fn, cond_kwargs=cond_kwargs, eta=eta) image = diffusion_scheduler_output['prev_sample'] return {'samples': image} ================================================ FILE: mmagic/models/editors/disco_diffusion/guider.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import lpips import numpy as np import pandas as pd import torch import torch.nn as nn import torch.nn.functional as F import torchvision.transforms as T import torchvision.transforms.functional as TF from mmengine.utils import digit_version from resize_right import resize from torchvision import __version__ as TORCHVISION_VERSION from mmagic.models.losses import tv_loss from mmagic.utils import try_import from .secondary_model import alpha_sigma_to_t clip = try_import('clip') normalize = T.Normalize( mean=[0.48145466, 0.4578275, 0.40821073], std=[0.26862954, 0.26130258, 0.27577711]) def sinc(x): """ Sinc function. If x equal to 0, sinc(x) = 1 else: sinc(x) = sin(x)/ x Args: x (torch.Tensor): Input Tensor Returns: torch.Tensor: Function output. """ return torch.where(x != 0, torch.sin(math.pi * x) / (math.pi * x), x.new_ones([])) def lanczos(x, a): """Lanczos filter's reconstruction kernel L(x).""" cond = torch.logical_and(-a < x, x < a) out = torch.where(cond, sinc(x) * sinc(x / a), x.new_zeros([])) return out / out.sum() def ramp(ratio, width): """_summary_ Args: ratio (_type_): _description_ width (_type_): _description_ Returns: _type_: _description_ """ n = math.ceil(width / ratio + 1) out = torch.empty([n]) cur = 0 for i in range(out.shape[0]): out[i] = cur cur += ratio return torch.cat([-out[1:].flip([0]), out])[1:-1] def resample(input, size, align_corners=True): """Lanczos resampling image. Args: input (torch.Tensor): Input image tensor. size (Tuple[int, int]): Output image size. align_corners (bool): align_corners argument of F.interpolate. Defaults to True. Returns: torch.Tensor: Resampling results. """ n, c, h, w = input.shape dh, dw = size input = input.reshape([n * c, 1, h, w]) if dh < h: kernel_h = lanczos(ramp(dh / h, 2), 2).to(input.device, input.dtype) pad_h = (kernel_h.shape[0] - 1) // 2 input = F.pad(input, (0, 0, pad_h, pad_h), 'reflect') input = F.conv2d(input, kernel_h[None, None, :, None]) if dw < w: kernel_w = lanczos(ramp(dw / w, 2), 2).to(input.device, input.dtype) pad_w = (kernel_w.shape[0] - 1) // 2 input = F.pad(input, (pad_w, pad_w, 0, 0), 'reflect') input = F.conv2d(input, kernel_w[None, None, None, :]) input = input.reshape([n, c, h, w]) return F.interpolate( input, size, mode='bicubic', align_corners=align_corners) def range_loss(input): """range loss.""" return (input - input.clamp(-1, 1)).pow(2).mean([1, 2, 3]) def spherical_dist_loss(x, y): """spherical distance loss.""" x = F.normalize(x, dim=-1) y = F.normalize(y, dim=-1) return (x - y).norm(dim=-1).div(2).arcsin().pow(2).mul(2) class MakeCutouts(nn.Module): """Each iteration, the AI cuts the image into smaller pieces known as cuts. , and compares each cut to the prompt to decide how to guide the next diffusion step. This classes will randomly cut patches and perform image augmentation to these patches. Args: cut_size (int): Size of the patches. cutn (int): Number of patches to cut. """ def __init__(self, cut_size, cutn): super().__init__() self.cut_size = cut_size self.cutn = cutn self.augs = T.Compose([ T.RandomHorizontalFlip(p=0.5), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.RandomAffine(degrees=15, translate=(0.1, 0.1)), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.RandomPerspective(distortion_scale=0.4, p=0.7), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.RandomGrayscale(p=0.15), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), ]) def forward(self, input, skip_augs=False): input = T.Pad(input.shape[2] // 4, fill=0)(input) sideY, sideX = input.shape[2:4] max_size = min(sideX, sideY) cutouts = [] for ch in range(self.cutn): if ch > self.cutn - self.cutn // 4: cutout = input.clone() else: size = int(max_size * torch.zeros(1, ).normal_( mean=.8, std=.3).clip(float(self.cut_size / max_size), 1.)) offsetx = torch.randint(0, abs(sideX - size + 1), ()) offsety = torch.randint(0, abs(sideY - size + 1), ()) cutout = input[:, :, offsety:offsety + size, offsetx:offsetx + size] if not skip_augs: cutout = self.augs(cutout) cutouts.append(resample(cutout, (self.cut_size, self.cut_size))) del cutout cutouts = torch.cat(cutouts, dim=0) return cutouts class MakeCutoutsDango(nn.Module): """Dango233(https://github.com/Dango233)'s version of MakeCutouts. The improvement compared to ``MakeCutouts`` is that it use partial greyscale augmentation to capture structure, and partial rotation augmentation to capture whole frames. Args: cut_size (int): Size of the patches. Overview (int): The total number of overview cuts. In details, Overview=1, Add whole frame; Overview=2, Add grayscaled frame; Overview=3, Add horizontal flip frame; Overview=4, Add grayscaled horizontal flip frame; Overview>4, Repeat add frame Overview times. Defaults to 4. InnerCrop (int): The total number of inner cuts. Defaults to 0. IC_Size_Pow (float): This sets the size of the border used for inner cuts. High values have larger borders, and therefore the cuts themselves will be smaller and provide finer details. Defaults to 0.5. IC_Grey_P (float): The portion of the inner cuts can be set to be grayscale instead of color. This may help with improved definition of shapes and edges, especially in the early diffusion steps where the image structure is being defined. Defaults to 0.2. """ def __init__(self, cut_size, Overview=4, InnerCrop=0, IC_Size_Pow=0.5, IC_Grey_P=0.2): super().__init__() self.cut_size = cut_size self.Overview = Overview self.InnerCrop = InnerCrop self.IC_Size_Pow = IC_Size_Pow self.IC_Grey_P = IC_Grey_P random_affine_args = dict(degrees=10, translate=(0.05, 0.05)) if digit_version(TORCHVISION_VERSION) >= digit_version('0.9.0'): random_affine_args['interpolation'] = T.InterpolationMode.BILINEAR else: from PIL import Image random_affine_args['resample'] = Image.NEAREST self.augs = T.Compose([ T.RandomHorizontalFlip(p=0.5), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.RandomAffine(**random_affine_args), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.RandomGrayscale(p=0.1), T.Lambda(lambda x: x + torch.randn_like(x) * 0.01), T.ColorJitter( brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1), ]) def forward(self, input, skip_augs=False): """Forward function.""" cutouts = [] gray = T.Grayscale(3) sideY, sideX = input.shape[2:4] max_size = min(sideX, sideY) min_size = min(sideX, sideY, self.cut_size) output_shape = [1, 3, self.cut_size, self.cut_size] pad_input = F.pad(input, ((sideY - max_size) // 2, (sideY - max_size) // 2, (sideX - max_size) // 2, (sideX - max_size) // 2)) cutout = resize(pad_input, out_shape=output_shape) if self.Overview > 0: if self.Overview <= 4: if self.Overview >= 1: cutouts.append(cutout) if self.Overview >= 2: cutouts.append(gray(cutout)) if self.Overview >= 3: cutouts.append(TF.hflip(cutout)) if self.Overview == 4: cutouts.append(gray(TF.hflip(cutout))) else: cutout = resize(pad_input, out_shape=output_shape) for _ in range(self.Overview): cutouts.append(cutout) if self.InnerCrop > 0: for i in range(self.InnerCrop): size = int( torch.rand([])**self.IC_Size_Pow * (max_size - min_size) + min_size) offsetx = torch.randint(0, sideX - size + 1, ()) offsety = torch.randint(0, sideY - size + 1, ()) cutout = input[:, :, offsety:offsety + size, offsetx:offsetx + size] if i <= int(self.IC_Grey_P * self.InnerCrop): cutout = gray(cutout) cutout = resize(cutout, out_shape=output_shape) cutouts.append(cutout) cutouts = torch.cat(cutouts) if not skip_augs: cutouts = self.augs(cutouts) return cutouts def parse_prompt(prompt): """Parse prompt, return text and text weight.""" if prompt.startswith('http://') or prompt.startswith('https://'): vals = prompt.rsplit(':', 2) vals = [vals[0] + ':' + vals[1], *vals[2:]] else: vals = prompt.rsplit(':', 1) vals = vals + ['', '1'][len(vals):] return vals[0], float(vals[1]) def split_prompts(prompts, max_frames=1): """Split prompts to a list of prompts.""" prompt_series = pd.Series([np.nan for a in range(max_frames)]) for i, prompt in prompts.items(): prompt_series[i] = prompt # prompt_series = prompt_series.astype(str) prompt_series = prompt_series.ffill().bfill() return prompt_series class ImageTextGuider(nn.Module): """Disco-Diffusion uses text and images to guide image generation. We will use the clip models to extract text and image features as prompts, and then during the iteration, the features of the image patches are computed, and the similarity loss between the prompts features and the generated features is computed. Other losses also include RGB Range loss, total variation loss. Using these losses we can guide the image generation towards the desired target. Args: clip_models (List[Dict]): List of clip model settings. """ def __init__(self, clip_models): super().__init__() assert clip is not None, ( "Cannot import 'clip'. Please install 'clip' via " "\"pip install git+https://github.com/openai/CLIP.git\".") self.clip_models = clip_models self.lpips_model = lpips.LPIPS(net='vgg') def frame_prompt_from_text(self, text_prompts, frame_num=0): """Get current frame prompt.""" prompts_series = split_prompts(text_prompts) if prompts_series is not None and frame_num >= len(prompts_series): frame_prompt = prompts_series[-1] elif prompts_series is not None: frame_prompt = prompts_series[frame_num] else: frame_prompt = [] return frame_prompt def compute_prompt_stats(self, text_prompts=[], image_prompt=None, fuzzy_prompt=False, rand_mag=0.05): """Compute prompts statistics. Args: text_prompts (list): Text prompts. Defaults to []. image_prompt (list): Image prompts. Defaults to None. fuzzy_prompt (bool, optional): Controls whether to add multiple noisy prompts to the prompt losses. If True, can increase variability of image output. Defaults to False. rand_mag (float, optional): Controls the magnitude of the random noise added by fuzzy_prompt. Defaults to 0.05. """ model_stats = [] frame_prompt = self.frame_prompt_from_text(text_prompts) for clip_model in self.clip_models: model_stat = { 'clip_model': None, 'target_embeds': [], 'make_cutouts': None, 'weights': [] } model_stat['clip_model'] = clip_model for prompt in frame_prompt: txt, weight = parse_prompt(prompt) txt = clip_model.model.encode_text( clip.tokenize(prompt).to(self.device)).float() if fuzzy_prompt: for i in range(25): model_stat['target_embeds'].append( (txt + torch.randn(txt.shape).cuda() * rand_mag).clamp( 0, 1)) model_stat['weights'].append(weight) else: model_stat['target_embeds'].append(txt) model_stat['weights'].append(weight) model_stat['target_embeds'] = torch.cat( model_stat['target_embeds']) model_stat['weights'] = torch.tensor( model_stat['weights'], device=self.device) if model_stat['weights'].sum().abs() < 1e-3: raise RuntimeError('The weights must not sum to 0.') model_stat['weights'] /= model_stat['weights'].sum().abs() model_stats.append(model_stat) return model_stats def cond_fn(self, model, diffusion_scheduler, x, t, beta_prod_t, model_stats, secondary_model=None, init_image=None, clamp_grad=True, clamp_max=0.05, clip_guidance_scale=5000, init_scale=1000, tv_scale=0., sat_scale=0., range_scale=150, cut_overview=[12] * 400 + [4] * 600, cut_innercut=[4] * 400 + [12] * 600, cut_ic_pow=[1] * 1000, cut_icgray_p=[0.2] * 400 + [0] * 600, cutn_batches=4): """Clip guidance function. Args: model (nn.Module): _description_ diffusion_scheduler (object): _description_ x (torch.Tensor): _description_ t (int): _description_ beta_prod_t (torch.Tensor): _description_ model_stats (List[torch.Tensor]): _description_ secondary_model (nn.Module): A smaller secondary diffusion model trained by Katherine Crowson to remove noise from intermediate timesteps to prepare them for CLIP. Ref: https://twitter.com/rivershavewings/status/1462859669454536711 # noqa Defaults to None. init_image (torch.Tensor): Initial image for denoising. Defaults to None. clamp_grad (bool, optional): Whether clamp gradient. Defaults to True. clamp_max (float, optional): Clamp max values. Defaults to 0.05. clip_guidance_scale (int, optional): The scale of influence of clip guidance on image generation. Defaults to 5000. """ with torch.enable_grad(): x_is_NaN = False x = x.detach().requires_grad_() n = x.shape[0] if secondary_model is not None: alpha = torch.tensor( diffusion_scheduler.alphas_cumprod[t]**0.5, dtype=torch.float32) sigma = torch.tensor( (1 - diffusion_scheduler.alphas_cumprod[t])**0.5, dtype=torch.float32) cosine_t = alpha_sigma_to_t(alpha, sigma).to(x.device) model_output = secondary_model( x, cosine_t[None].repeat([x.shape[0]])) pred_original_sample = model_output['pred'] else: model_output = model(x, t)['sample'] model_output, predicted_variance = torch.split( model_output, x.shape[1], dim=1) alpha_prod_t = 1 - beta_prod_t pred_original_sample = (x - beta_prod_t**(0.5) * model_output) / alpha_prod_t**(0.5) # fac = diffusion_scheduler_output['beta_prod_t']** (0.5) # x_in = diffusion_scheduler_output['original_sample'] * fac + x * (1 - fac) # noqa fac = beta_prod_t**(0.5) x_in = pred_original_sample * fac + x * (1 - fac) x_in_grad = torch.zeros_like(x_in) for model_stat in model_stats: for i in range(cutn_batches): t_int = int(t.item()) + 1 try: input_resolution = model_stat[ 'clip_model'].model.visual.input_resolution except AttributeError: input_resolution = 224 cuts = MakeCutoutsDango( input_resolution, Overview=cut_overview[1000 - t_int], InnerCrop=cut_innercut[1000 - t_int], IC_Size_Pow=cut_ic_pow[1000 - t_int], IC_Grey_P=cut_icgray_p[1000 - t_int]) clip_in = normalize(cuts(x_in.add(1).div(2))) image_embeds = model_stat['clip_model'].model.encode_image( clip_in).float() dists = spherical_dist_loss( image_embeds.unsqueeze(1), model_stat['target_embeds'].unsqueeze(0)) dists = dists.view([ cut_overview[1000 - t_int] + cut_innercut[1000 - t_int], n, -1 ]) losses = dists.mul(model_stat['weights']).sum(2).mean(0) x_in_grad += torch.autograd.grad( losses.sum() * clip_guidance_scale, x_in)[0] / cutn_batches tv_losses = tv_loss(x_in) range_losses = range_loss(pred_original_sample) sat_losses = torch.abs(x_in - x_in.clamp(min=-1, max=1)).mean() loss = tv_losses.sum() * tv_scale + range_losses.sum( ) * range_scale + sat_losses.sum() * sat_scale if init_image is not None and init_scale: init_losses = self.lpips_model(x_in, init_image) loss = loss + init_losses.sum() * init_scale x_in_grad += torch.autograd.grad(loss, x_in)[0] if not torch.isnan(x_in_grad).any(): grad = -torch.autograd.grad(x_in, x, x_in_grad)[0] else: x_is_NaN = True grad = torch.zeros_like(x) if clamp_grad and not x_is_NaN: magnitude = grad.square().mean().sqrt() return grad * magnitude.clamp(max=clamp_max) / magnitude return grad @property def device(self): """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device def forward(self, x): """forward function.""" raise NotImplementedError('No forward function for disco guider') ================================================ FILE: mmagic/models/editors/disco_diffusion/secondary_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from functools import partial import torch import torch.nn as nn from mmagic.registry import MODELS # Note: This model is copied from Disco-Diffusion colab. # SourceCode: https://colab.research.google.com/drive/1uGKaBOEACeinAA7jX1_zSFtj_ZW-huHS#scrollTo=XIqUfrmvLIhg # noqa def append_dims(x, n): """Append dims.""" return x[(Ellipsis, *(None, ) * (n - x.ndim))] def expand_to_planes(x, shape): """Expand tensor to planes.""" return append_dims(x, len(shape)).repeat([1, 1, *shape[2:]]) def alpha_sigma_to_t(alpha, sigma): """convert alpha&sigma to timestep.""" return torch.atan2(sigma, alpha) * 2 / math.pi def t_to_alpha_sigma(t): """convert timestep to alpha and sigma.""" return torch.cos(t * math.pi / 2), torch.sin(t * math.pi / 2) class ConvBlock(nn.Sequential): """Convolution Block. Args: c_in (int): Input channels. c_out (int): Output channels. """ def __init__(self, c_in, c_out): super().__init__( nn.Conv2d(c_in, c_out, 3, padding=1), nn.ReLU(inplace=True), ) class SkipBlock(nn.Module): """Skip block wrapper. Wrapping main block and skip block and concat their outputs together. Args: main (list): A list of main modules. skip (nn.Module): Skip Module. If not given, set to ``nn.Identity()``. Defaults to None. """ def __init__(self, main, skip=None): super().__init__() self.main = nn.Sequential(*main) self.skip = skip if skip else nn.Identity() def forward(self, input): """Forward function.""" return torch.cat([self.main(input), self.skip(input)], dim=1) class FourierFeatures(nn.Module): """Fourier features mapping MLP. Args: in_features (int): Input channels. out_features (int): Output channels. std (float): Standard deviation. Defaults to 1.. """ def __init__(self, in_features, out_features, std=1.): super().__init__() assert out_features % 2 == 0 self.weight = nn.Parameter( torch.randn([out_features // 2, in_features]) * std) def forward(self, input): """Forward function.""" f = 2 * math.pi * input @ self.weight.T return torch.cat([f.cos(), f.sin()], dim=-1) @MODELS.register_module() class SecondaryDiffusionImageNet2(nn.Module): """A smaller secondary diffusion model trained by Katherine Crowson to remove noise from intermediate timesteps to prepare them for CLIP. Ref: https://twitter.com/rivershavewings/status/1462859669454536711 # noqa """ def __init__(self): super().__init__() self.in_channels = 3 c = 64 # The base channel count cs = [c, c * 2, c * 2, c * 4, c * 4, c * 8] self.timestep_embed = FourierFeatures(1, 16) self.down = nn.AvgPool2d(2) self.up = nn.Upsample( scale_factor=2, mode='bilinear', align_corners=False) self.net = nn.Sequential( ConvBlock(3 + 16, cs[0]), ConvBlock(cs[0], cs[0]), SkipBlock([ self.down, ConvBlock(cs[0], cs[1]), ConvBlock(cs[1], cs[1]), SkipBlock([ self.down, ConvBlock(cs[1], cs[2]), ConvBlock(cs[2], cs[2]), SkipBlock([ self.down, ConvBlock(cs[2], cs[3]), ConvBlock(cs[3], cs[3]), SkipBlock([ self.down, ConvBlock(cs[3], cs[4]), ConvBlock(cs[4], cs[4]), SkipBlock([ self.down, ConvBlock(cs[4], cs[5]), ConvBlock(cs[5], cs[5]), ConvBlock(cs[5], cs[5]), ConvBlock(cs[5], cs[4]), self.up, ]), ConvBlock(cs[4] * 2, cs[4]), ConvBlock(cs[4], cs[3]), self.up, ]), ConvBlock(cs[3] * 2, cs[3]), ConvBlock(cs[3], cs[2]), self.up, ]), ConvBlock(cs[2] * 2, cs[2]), ConvBlock(cs[2], cs[1]), self.up, ]), ConvBlock(cs[1] * 2, cs[1]), ConvBlock(cs[1], cs[0]), self.up, ]), ConvBlock(cs[0] * 2, cs[0]), nn.Conv2d(cs[0], 3, 3, padding=1), ) def forward(self, input, t): """Forward function.""" timestep_embed = expand_to_planes( self.timestep_embed(t[:, None]), input.shape) v = self.net(torch.cat([input, timestep_embed], dim=1)) alphas, sigmas = map( partial(append_dims, n=v.ndim), t_to_alpha_sigma(t)) pred = input * alphas - v * sigmas eps = input * sigmas + v * alphas return dict(v=v, pred=pred, eps=eps) ================================================ FILE: mmagic/models/editors/dreambooth/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .dreambooth import DreamBooth __all__ = ['DreamBooth'] ================================================ FILE: mmagic/models/editors/dreambooth/dreambooth.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from mmagic.models.archs import set_lora from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ..stable_diffusion.stable_diffusion import StableDiffusion ModelType = Union[Dict, nn.Module] @MODELS.register_module() class DreamBooth(StableDiffusion): """Implementation of `DreamBooth with Stable Diffusion. `_ (DreamBooth). Args: vae (Union[dict, nn.Module]): The config or module for VAE model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. tokenizer (str): The **name** for CLIP tokenizer. unet (Union[dict, nn.Module]): The config or module for Unet model. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. lora_config (dict, optional): The config for LoRA finetuning. Defaults to None. val_prompts (Union[str, List[str]], optional): The prompts for validation. Defaults to None. class_prior_prompt (str, optional): The prompt for class prior loss. num_class_images (int, optional): The number of images for class prior. Defaults to 3. prior_loss_weight (float, optional): The weight for class prior loss. Defaults to 0. finetune_text_encoder (bool, optional): Whether to fine-tune text encoder. Defaults to False. dtype (str, optional): The dtype for the model. Defaults to 'fp16'. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise # noqa Defaults to 0. tomesd_cfg (dict, optional): The config for TOMESD. Please refers to https://github.com/dbolya/tomesd and https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/utils/tome_utils.py for detail. # noqa Defaults to None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Defaults to dict(type='DataPreprocessor'). init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Defaults to None/ """ def __init__(self, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, lora_config: Optional[dict] = None, val_prompts: Union[str, List[str]] = None, class_prior_prompt: Optional[str] = None, num_class_images: Optional[int] = 3, prior_loss_weight: float = 0, finetune_text_encoder: bool = False, dtype: str = 'fp16', enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), init_cfg: Optional[dict] = None): super().__init__(vae, text_encoder, tokenizer, unet, scheduler, test_scheduler, dtype, enable_xformers, noise_offset_weight, tomesd_cfg, data_preprocessor, init_cfg) self.num_class_images = num_class_images self.class_prior_prompt = class_prior_prompt self.prior_loss_weight = prior_loss_weight self.class_images = [] self.dtype = torch.float32 if dtype == 'fp16': self.dtype = torch.float16 elif dtype == 'bf16': self.dtype = torch.bfloat16 else: assert dtype in [ 'fp32', None ], ('dtype must be one of \'fp32\', \'fp16\', \'bf16\' or None.') self.finetune_text_encoder = finetune_text_encoder self.val_prompts = val_prompts self.lora_config = deepcopy(lora_config) self.prepare_model() self.set_lora() @torch.no_grad() def generate_class_prior_images(self, num_batches=None): """Generate images for class prior loss. Args: num_batches (int): Number of batches to generate images. If not passed, all images will be generated in one forward. Defaults to None. """ if self.prior_loss_weight == 0: return if self.class_images: return assert self.class_prior_prompt is not None, ( '\'class_prior_prompt\' must be set when \'prior_loss_weight\' is ' 'larger than 0.') assert self.num_class_images is not None, ( '\'num_class_images\' must be set when \'prior_loss_weight\' is ' 'larger than 0.') print_log( 'Generating class prior images with prompt: ' f'{self.class_prior_prompt}', 'current') num_batches = num_batches or self.num_class_images unet_dtype = next(self.unet.parameters()).dtype self.unet.to(self.dtype) for idx in range(0, self.num_class_images, num_batches): prompt = self.class_prior_prompt if self.num_class_images > 1: prompt += f' {idx + 1} of {self.num_class_images}' output = self.infer(prompt, return_type='tensor') samples = output['samples'] self.class_images.append(samples.clamp(-1, 1)) self.unet.to(unet_dtype) def prepare_model(self): """Prepare model for training. Move model to target dtype and disable gradient for some models. """ self.vae.requires_grad_(False) print_log('Set VAE untrainable.', 'current') self.vae.to(self.dtype) print_log(f'Move VAE to {self.dtype}.', 'current') if not self.finetune_text_encoder or self.lora_config: self.text_encoder.requires_grad_(False) print_log('Set Text Encoder untrainable.', 'current') self.text_encoder.to(self.dtype) print_log(f'Move Text Encoder to {self.dtype}.', 'current') if self.lora_config: self.unet.requires_grad_(False) print_log('Set Unet untrainable.', 'current') def set_lora(self): """Set LORA for model.""" if self.lora_config: set_lora(self.unet, self.lora_config) @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) data_samples = data['data_samples'] if self.val_prompts is None: prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples.split() * len(prompt) data_samples = DataSample.stack(data_samples.split() * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ if self.val_prompts is None: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples = DataSample.stack(data['data_samples'] * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list def train_step(self, data, optim_wrapper): data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] with optim_wrapper.optim_context(self.unet): image = inputs # image for new concept prompt = data_samples.prompt num_batches = image.shape[0] if self.prior_loss_weight != 0: # image and prompt for prior preservation self.generate_class_prior_images(num_batches=num_batches) class_images_used = [] for _ in range(num_batches): idx = random.randint(0, len(self.class_images) - 1) class_images_used.append(self.class_images[idx]) image = torch.cat([image, *class_images_used], dim=0) prompt = prompt + [self.class_prior_prompt] image = image.to(self.dtype) latents = self.vae.encode(image).latent_dist.sample() latents = latents * self.vae.config.scaling_factor noise = torch.randn_like(latents) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) input_ids = self.tokenizer( prompt, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) encoder_hidden_states = self.text_encoder(input_ids)[0] if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') # NOTE: we train unet in fp32, convert to float manually model_output = self.unet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float()) model_pred = model_output['sample'] loss_dict = dict() if self.prior_loss_weight != 0: model_pred, prior_pred = model_pred.split(2, dim=1) gt, prior_gt = gt.split(2, dim=1) # calculate loss in FP32 dreambooth_loss = F.mse_loss(model_pred.float(), gt.float()) prior_loss = F.mse_loss(prior_pred.float(), prior_gt.float()) loss_dict['dreambooth_loss'] = dreambooth_loss loss_dict['prior_loss'] = prior_loss * self.prior_loss_weight else: # calculate loss in FP32 dreambooth_loss = F.mse_loss(model_pred.float(), gt.float()) loss_dict['dreambooth_loss'] = dreambooth_loss parsed_loss, log_vars = self.parse_losses(loss_dict) optim_wrapper.update_params(parsed_loss) return log_vars def forward(self, inputs: torch.Tensor, data_samples: Optional[list] = None, mode: str = 'tensor') -> Union[Dict[str, torch.Tensor], list]: """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') ================================================ FILE: mmagic/models/editors/duf/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .duf import DynamicUpsamplingFilter __all__ = ['DynamicUpsamplingFilter'] ================================================ FILE: mmagic/models/editors/duf/duf.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn.functional as F from mmengine.model import BaseModule class DynamicUpsamplingFilter(BaseModule): """Dynamic upsampling filter used in DUF. Ref: https://github.com/yhjo09/VSR-DUF. It only supports input with 3 channels. And it applies the same filters to 3 channels. Args: filter_size (tuple): Filter size of generated filters. The shape is (kh, kw). Default: (5, 5). """ def __init__(self, filter_size=(5, 5)): super().__init__() if not isinstance(filter_size, tuple): raise TypeError('The type of filter_size must be tuple, ' f'but got type{filter_size}') if len(filter_size) != 2: raise ValueError('The length of filter size must be 2, ' f'but got {len(filter_size)}.') # generate a local expansion filter, similar to im2col self.filter_size = filter_size filter_prod = np.prod(filter_size) expansion_filter = torch.eye(int(filter_prod)).view( filter_prod, 1, *filter_size) # (kh*kw, 1, kh, kw) self.expansion_filter = expansion_filter.repeat( 3, 1, 1, 1) # repeat for all the 3 channels def forward(self, x, filters): """Forward function for DynamicUpsamplingFilter. Args: x (Tensor): Input image with 3 channels. The shape is (n, 3, h, w). filters (Tensor): Generated dynamic filters. The shape is (n, filter_prod, upsampling_square, h, w). filter_prod: prod of filter kernel size, e.g., 1*5*5=25. upsampling_square: similar to pixel shuffle, upsampling_square = upsampling * upsampling e.g., for x 4 upsampling, upsampling_square= 4*4 = 16 Returns: Tensor: Filtered image with shape (n, 3*upsampling, h, w) """ n, filter_prod, upsampling_square, h, w = filters.size() kh, kw = self.filter_size expanded_input = F.conv2d( x, self.expansion_filter.to(x), padding=(kh // 2, kw // 2), groups=3) # (n, 3*filter_prod, h, w) expanded_input = expanded_input.view(n, 3, filter_prod, h, w).permute( 0, 3, 4, 1, 2) # (n, h, w, 3, filter_prod) filters = filters.permute( 0, 3, 4, 1, 2) # (n, h, w, filter_prod, upsampling_square] out = torch.matmul(expanded_input, filters) # (n, h, w, 3, upsampling_square) return out.permute(0, 3, 4, 1, 2).view(n, 3 * upsampling_square, h, w) ================================================ FILE: mmagic/models/editors/edsr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .edsr_net import EDSRNet __all__ = ['EDSRNet'] ================================================ FILE: mmagic/models/editors/edsr/edsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import make_layer from mmagic.registry import MODELS @MODELS.register_module() class EDSRNet(BaseModule): """EDSR network structure. Paper: Enhanced Deep Residual Networks for Single Image Super-Resolution. Ref repo: https://github.com/thstkdgus35/EDSR-PyTorch Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_blocks (int): Block number in the trunk network. Default: 16. upscale_factor (int): Upsampling factor. Support 2^n and 3. Default: 4. res_scale (float): Used to scale the residual in residual block. Default: 1. rgb_mean (list[float]): Image mean in RGB orders. Default: [0.4488, 0.4371, 0.4040], calculated from DIV2K dataset. rgb_std (list[float]): Image std in RGB orders. In EDSR, it uses [1.0, 1.0, 1.0]. Default: [1.0, 1.0, 1.0]. """ def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=16, upscale_factor=4, res_scale=1, rgb_mean=[0.4488, 0.4371, 0.4040], rgb_std=[1.0, 1.0, 1.0]): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.mid_channels = mid_channels self.num_blocks = num_blocks self.upscale_factor = upscale_factor self.mean = torch.Tensor(rgb_mean).view(1, -1, 1, 1) self.std = torch.Tensor(rgb_std).view(1, -1, 1, 1) self.conv_first = nn.Conv2d(in_channels, mid_channels, 3, padding=1) self.body = make_layer( ResidualBlockNoBN, num_blocks, mid_channels=mid_channels, res_scale=res_scale) self.conv_after_body = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) self.upsample = UpsampleModule(upscale_factor, mid_channels) self.conv_last = nn.Conv2d( mid_channels, out_channels, 3, 1, 1, bias=True) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ self.mean = self.mean.to(x) self.std = self.std.to(x) x = (x - self.mean) / self.std x = self.conv_first(x) res = self.conv_after_body(self.body(x)) res += x x = self.conv_last(self.upsample(res)) x = x * self.std + self.mean return x class UpsampleModule(nn.Sequential): """Upsample module used in EDSR. Args: scale (int): Scale factor. Supported scales: 2^n and 3. mid_channels (int): Channel number of intermediate features. """ def __init__(self, scale, mid_channels): modules = [] if (scale & (scale - 1)) == 0: # scale = 2^n for _ in range(int(math.log(scale, 2))): modules.append( PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3)) elif scale == 3: modules.append( PixelShufflePack( mid_channels, mid_channels, scale, upsample_kernel=3)) else: raise ValueError(f'scale {scale} is not supported. ' 'Supported scales: 2^n and 3.') super().__init__(*modules) ================================================ FILE: mmagic/models/editors/edvr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .edvr import EDVR from .edvr_net import EDVRNet __all__ = ['EDVR', 'EDVRNet'] ================================================ FILE: mmagic/models/editors/edvr/edvr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models import BaseEditModel from mmagic.registry import MODELS @MODELS.register_module() class EDVR(BaseEditModel): """EDVR model for video super-resolution. EDVR: Video Restoration with Enhanced Deformable Convolutional Networks. Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. """ def __init__(self, generator, pixel_loss, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.with_tsa = generator.get('with_tsa', False) self.tsa_iter = self.train_cfg.get('tsa_iter', None) if self.train_cfg else None self.register_buffer('step_counter', torch.tensor(0), False) def forward_train(self, inputs, data_samples=None): """Forward training. Returns dict of losses of training. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ if self.step_counter == 0 and self.with_tsa: if self.tsa_iter is None: raise KeyError( 'In TSA mode, train_cfg must contain "tsa_iter".') # only train TSA module at the beginning if with TSA module for k, v in self.generator.named_parameters(): if 'fusion' not in k: v.requires_grad = False if self.with_tsa and (self.step_counter == self.tsa_iter): # train all the parameters for v in self.generator.parameters(): v.requires_grad = True self.step_counter += 1 return super().forward_train(inputs, data_samples) ================================================ FILE: mmagic/models/editors/edvr/edvr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmcv.ops import ModulatedDeformConv2d, modulated_deform_conv2d from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init, kaiming_init from torch.nn.modules.utils import _pair from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import make_layer from mmagic.registry import MODELS @MODELS.register_module() class EDVRNet(BaseModule): """EDVR network structure for video super-resolution. Now only support X4 upsampling factor. Paper: EDVR: Video Restoration with Enhanced Deformable Convolutional Networks. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_frames (int): Number of input frames. Default: 5. deform_groups (int): Deformable groups. Defaults: 8. num_blocks_extraction (int): Number of blocks for feature extraction. Default: 5. num_blocks_reconstruction (int): Number of blocks for reconstruction. Default: 10. center_frame_idx (int): The index of center frame. Frame counting from 0. Default: 2. with_tsa (bool): Whether to use TSA module. Default: True. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels, out_channels, mid_channels=64, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=10, center_frame_idx=2, with_tsa=True, init_cfg=None): super().__init__(init_cfg=init_cfg) self.center_frame_idx = center_frame_idx self.with_tsa = with_tsa act_cfg = dict(type='LeakyReLU', negative_slope=0.1) self.conv_first = nn.Conv2d(in_channels, mid_channels, 3, 1, 1) self.feature_extraction = make_layer( ResidualBlockNoBN, num_blocks_extraction, mid_channels=mid_channels) # generate pyramid features self.feat_l2_conv1 = ConvModule( mid_channels, mid_channels, 3, 2, 1, act_cfg=act_cfg) self.feat_l2_conv2 = ConvModule( mid_channels, mid_channels, 3, 1, 1, act_cfg=act_cfg) self.feat_l3_conv1 = ConvModule( mid_channels, mid_channels, 3, 2, 1, act_cfg=act_cfg) self.feat_l3_conv2 = ConvModule( mid_channels, mid_channels, 3, 1, 1, act_cfg=act_cfg) # pcd alignment self.pcd_alignment = PCDAlignment( mid_channels=mid_channels, deform_groups=deform_groups) # fusion if self.with_tsa: self.fusion = TSAFusion( mid_channels=mid_channels, num_frames=num_frames, center_frame_idx=self.center_frame_idx) else: self.fusion = nn.Conv2d(num_frames * mid_channels, mid_channels, 1, 1) # reconstruction self.reconstruction = make_layer( ResidualBlockNoBN, num_blocks_reconstruction, mid_channels=mid_channels) # upsample self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, 64, 2, upsample_kernel=3) # we fix the output channels in the last few layers to 64. self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1) self.conv_last = nn.Conv2d(64, out_channels, 3, 1, 1) self.img_upsample = nn.Upsample( scale_factor=4, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) def forward(self, x): """Forward function for EDVRNet. Args: x (Tensor): Input tensor with shape (n, t, c, h, w). Returns: Tensor: SR center frame with shape (n, c, h, w). """ n, t, c, h, w = x.size() assert h % 4 == 0 and w % 4 == 0, ( 'The height and width of inputs should be a multiple of 4, ' f'but got {h} and {w}.') x_center = x[:, self.center_frame_idx, :, :, :].contiguous() # extract LR features # L1 l1_feat = self.lrelu(self.conv_first(x.view(-1, c, h, w))) l1_feat = self.feature_extraction(l1_feat) # L2 l2_feat = self.feat_l2_conv2(self.feat_l2_conv1(l1_feat)) # L3 l3_feat = self.feat_l3_conv2(self.feat_l3_conv1(l2_feat)) l1_feat = l1_feat.view(n, t, -1, h, w) l2_feat = l2_feat.view(n, t, -1, h // 2, w // 2) l3_feat = l3_feat.view(n, t, -1, h // 4, w // 4) # pcd alignment ref_feats = [ # reference feature list l1_feat[:, self.center_frame_idx, :, :, :].clone(), l2_feat[:, self.center_frame_idx, :, :, :].clone(), l3_feat[:, self.center_frame_idx, :, :, :].clone() ] aligned_feat = [] for i in range(t): neighbor_feats = [ l1_feat[:, i, :, :, :].clone(), l2_feat[:, i, :, :, :].clone(), l3_feat[:, i, :, :, :].clone() ] aligned_feat.append(self.pcd_alignment(neighbor_feats, ref_feats)) aligned_feat = torch.stack(aligned_feat, dim=1) # (n, t, c, h, w) if self.with_tsa: feat = self.fusion(aligned_feat) else: aligned_feat = aligned_feat.view(n, -1, h, w) feat = self.fusion(aligned_feat) # reconstruction out = self.reconstruction(feat) out = self.lrelu(self.upsample1(out)) out = self.lrelu(self.upsample2(out)) out = self.lrelu(self.conv_hr(out)) out = self.conv_last(out) base = self.img_upsample(x_center) out += base return out def init_weights(self): """Init weights for models.""" super().init_weights() init_type = None if self.init_cfg is None else self.init_cfg.get( 'type', None) if init_type != 'Pretrained' and self.with_tsa: for module in [ self.fusion.feat_fusion, self.fusion.spatial_attn1, self.fusion.spatial_attn2, self.fusion.spatial_attn3, self.fusion.spatial_attn4, self.fusion.spatial_attn_l1, self.fusion.spatial_attn_l2, self.fusion.spatial_attn_l3, self.fusion.spatial_attn_add1 ]: kaiming_init( module.conv, a=0.1, mode='fan_out', nonlinearity='leaky_relu', bias=0, distribution='uniform') class ModulatedDCNPack(ModulatedDeformConv2d): """Modulated Deformable Convolutional Pack. Different from the official DCN, which generates offsets and masks from the preceding features, this ModulatedDCNPack takes another different feature to generate masks and offsets. Args: in_channels (int): Same as nn.Conv2d. out_channels (int): Same as nn.Conv2d. kernel_size (int or tuple[int]): Same as nn.Conv2d. stride (int or tuple[int]): Same as nn.Conv2d. padding (int or tuple[int]): Same as nn.Conv2d. dilation (int or tuple[int]): Same as nn.Conv2d. groups (int): Same as nn.Conv2d. bias (bool or str): If specified as `auto`, it will be decided by the norm_cfg. Bias will be set as True if norm_cfg is None, otherwise False. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.conv_offset = nn.Conv2d( self.in_channels, self.deform_groups * 3 * self.kernel_size[0] * self.kernel_size[1], kernel_size=self.kernel_size, stride=_pair(self.stride), padding=_pair(self.padding), bias=True) self.init_offset() def init_offset(self): """Init constant offset.""" constant_init(self.conv_offset, val=0, bias=0) def forward(self, x, extra_feat): """Forward function.""" out = self.conv_offset(extra_feat) o1, o2, mask = torch.chunk(out, 3, dim=1) offset = torch.cat((o1, o2), dim=1) mask = torch.sigmoid(mask) return modulated_deform_conv2d(x, offset, mask, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups, self.deform_groups) class PCDAlignment(BaseModule): """Alignment module using Pyramid, Cascading and Deformable convolution (PCD). It is used in EDVRNet. Args: mid_channels (int): Number of the channels of middle features. Default: 64. deform_groups (int): Deformable groups. Defaults: 8. act_cfg (dict): Activation function config for ConvModule. Default: LeakyReLU with negative_slope=0.1. """ def __init__(self, mid_channels=64, deform_groups=8, act_cfg=dict(type='LeakyReLU', negative_slope=0.1)): super().__init__() # Pyramid has three levels: # L3: level 3, 1/4 spatial size # L2: level 2, 1/2 spatial size # L1: level 1, original spatial size self.offset_conv1 = nn.ModuleDict() self.offset_conv2 = nn.ModuleDict() self.offset_conv3 = nn.ModuleDict() self.dcn_pack = nn.ModuleDict() self.feat_conv = nn.ModuleDict() for i in range(3, 0, -1): level = f'l{i}' self.offset_conv1[level] = ConvModule( mid_channels * 2, mid_channels, 3, padding=1, act_cfg=act_cfg) if i == 3: self.offset_conv2[level] = ConvModule( mid_channels, mid_channels, 3, padding=1, act_cfg=act_cfg) else: self.offset_conv2[level] = ConvModule( mid_channels * 2, mid_channels, 3, padding=1, act_cfg=act_cfg) self.offset_conv3[level] = ConvModule( mid_channels, mid_channels, 3, padding=1, act_cfg=act_cfg) self.dcn_pack[level] = ModulatedDCNPack( mid_channels, mid_channels, 3, padding=1, deform_groups=deform_groups) if i < 3: act_cfg_ = act_cfg if i == 2 else None self.feat_conv[level] = ConvModule( mid_channels * 2, mid_channels, 3, padding=1, act_cfg=act_cfg_) # Cascading DCN self.cas_offset_conv1 = ConvModule( mid_channels * 2, mid_channels, 3, padding=1, act_cfg=act_cfg) self.cas_offset_conv2 = ConvModule( mid_channels, mid_channels, 3, padding=1, act_cfg=act_cfg) self.cas_dcnpack = ModulatedDCNPack( mid_channels, mid_channels, 3, padding=1, deform_groups=deform_groups) self.upsample = nn.Upsample( scale_factor=2, mode='bilinear', align_corners=False) self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) def forward(self, neighbor_feats, ref_feats): """Forward function for PCDAlignment. Align neighboring frames to the reference frame in the feature level. Args: neighbor_feats (list[Tensor]): List of neighboring features. It contains three pyramid levels (L1, L2, L3), each with shape (n, c, h, w). ref_feats (list[Tensor]): List of reference features. It contains three pyramid levels (L1, L2, L3), each with shape (n, c, h, w). Returns: Tensor: Aligned features. """ # The number of pyramid levels is 3. assert len(neighbor_feats) == 3 and len(ref_feats) == 3, ( 'The length of neighbor_feats and ref_feats must be both 3, ' f'but got {len(neighbor_feats)} and {len(ref_feats)}') # Pyramids upsampled_offset, upsampled_feat = None, None for i in range(3, 0, -1): level = f'l{i}' offset = torch.cat([neighbor_feats[i - 1], ref_feats[i - 1]], dim=1) offset = self.offset_conv1[level](offset) if i == 3: offset = self.offset_conv2[level](offset) else: offset = self.offset_conv2[level]( torch.cat([offset, upsampled_offset], dim=1)) offset = self.offset_conv3[level](offset) feat = self.dcn_pack[level](neighbor_feats[i - 1], offset) if i == 3: feat = self.lrelu(feat) else: feat = self.feat_conv[level]( torch.cat([feat, upsampled_feat], dim=1)) if i > 1: # upsample offset and features upsampled_offset = self.upsample(offset) * 2 upsampled_feat = self.upsample(feat) # Cascading offset = torch.cat([feat, ref_feats[0]], dim=1) offset = self.cas_offset_conv2(self.cas_offset_conv1(offset)) feat = self.lrelu(self.cas_dcnpack(feat, offset)) return feat class TSAFusion(BaseModule): """Temporal Spatial Attention (TSA) fusion module. It is used in EDVRNet. Args: mid_channels (int): Number of the channels of middle features. Default: 64. num_frames (int): Number of frames. Default: 5. center_frame_idx (int): The index of center frame. Default: 2. act_cfg (dict): Activation function config for ConvModule. Default: LeakyReLU with negative_slope=0.1. """ def __init__(self, mid_channels=64, num_frames=5, center_frame_idx=2, act_cfg=dict(type='LeakyReLU', negative_slope=0.1)): super().__init__() self.center_frame_idx = center_frame_idx # temporal attention (before fusion conv) self.temporal_attn1 = nn.Conv2d( mid_channels, mid_channels, 3, padding=1) self.temporal_attn2 = nn.Conv2d( mid_channels, mid_channels, 3, padding=1) self.feat_fusion = ConvModule( num_frames * mid_channels, mid_channels, 1, act_cfg=act_cfg) # spatial attention (after fusion conv) self.max_pool = nn.MaxPool2d(3, stride=2, padding=1) self.avg_pool = nn.AvgPool2d(3, stride=2, padding=1) self.spatial_attn1 = ConvModule( num_frames * mid_channels, mid_channels, 1, act_cfg=act_cfg) self.spatial_attn2 = ConvModule( mid_channels * 2, mid_channels, 1, act_cfg=act_cfg) self.spatial_attn3 = ConvModule( mid_channels, mid_channels, 3, padding=1, act_cfg=act_cfg) self.spatial_attn4 = ConvModule( mid_channels, mid_channels, 1, act_cfg=act_cfg) self.spatial_attn5 = nn.Conv2d( mid_channels, mid_channels, 3, padding=1) self.spatial_attn_l1 = ConvModule( mid_channels, mid_channels, 1, act_cfg=act_cfg) self.spatial_attn_l2 = ConvModule( mid_channels * 2, mid_channels, 3, padding=1, act_cfg=act_cfg) self.spatial_attn_l3 = ConvModule( mid_channels, mid_channels, 3, padding=1, act_cfg=act_cfg) self.spatial_attn_add1 = ConvModule( mid_channels, mid_channels, 1, act_cfg=act_cfg) self.spatial_attn_add2 = nn.Conv2d(mid_channels, mid_channels, 1) self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self.upsample = nn.Upsample( scale_factor=2, mode='bilinear', align_corners=False) def forward(self, aligned_feat): """Forward function for TSAFusion. Args: aligned_feat (Tensor): Aligned features with shape (n, t, c, h, w). Returns: Tensor: Features after TSA with the shape (n, c, h, w). """ n, t, c, h, w = aligned_feat.size() # temporal attention embedding_ref = self.temporal_attn1( aligned_feat[:, self.center_frame_idx, :, :, :].clone()) emb = self.temporal_attn2(aligned_feat.view(-1, c, h, w)) emb = emb.view(n, t, -1, h, w) # (n, t, c, h, w) corr_l = [] # correlation list for i in range(t): emb_neighbor = emb[:, i, :, :, :] corr = torch.sum(emb_neighbor * embedding_ref, 1) # (n, h, w) corr_l.append(corr.unsqueeze(1)) # (n, 1, h, w) corr_prob = torch.sigmoid(torch.cat(corr_l, dim=1)) # (n, t, h, w) corr_prob = corr_prob.unsqueeze(2).expand(n, t, c, h, w) corr_prob = corr_prob.contiguous().view(n, -1, h, w) # (n, t*c, h, w) aligned_feat = aligned_feat.view(n, -1, h, w) * corr_prob # fusion feat = self.feat_fusion(aligned_feat) # spatial attention attn = self.spatial_attn1(aligned_feat) attn_max = self.max_pool(attn) attn_avg = self.avg_pool(attn) attn = self.spatial_attn2(torch.cat([attn_max, attn_avg], dim=1)) # pyramid levels attn_level = self.spatial_attn_l1(attn) attn_max = self.max_pool(attn_level) attn_avg = self.avg_pool(attn_level) attn_level = self.spatial_attn_l2( torch.cat([attn_max, attn_avg], dim=1)) attn_level = self.spatial_attn_l3(attn_level) attn_level = self.upsample(attn_level) attn = self.spatial_attn3(attn) + attn_level attn = self.spatial_attn4(attn) attn = self.upsample(attn) attn = self.spatial_attn5(attn) attn_add = self.spatial_attn_add2(self.spatial_attn_add1(attn)) attn = torch.sigmoid(attn) # after initialization, * 2 makes (attn * 2) to be close to 1. feat = feat * attn * 2 + attn_add return feat ================================================ FILE: mmagic/models/editors/eg3d/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .camera import GaussianCamera, UniformCamera from .dual_discriminator import DualDiscriminator from .eg3d import EG3D from .eg3d_generator import TriplaneGenerator __all__ = [ 'DualDiscriminator', 'TriplaneGenerator', 'EG3D', 'UniformCamera', 'GaussianCamera' ] ================================================ FILE: mmagic/models/editors/eg3d/camera.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import List, Optional, Union import torch from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.utils import normalize_vecs from mmagic.registry import MODELS DeviceType = Optional[Union[str, int]] VectorType = Optional[Union[list, torch.Tensor]] class BaseCamera(object): """Base camera class. Sample camera position on sphere with specific distribution (e.g., Gaussian, Uniform) and return camera-to-world matrix and intrinsics matrix. Args: horizontal_mean (Optional[float]): Mean of the horizontal range in radian. Defaults to None. vertical_mean (Optional[float]): Mean of the vertical range in radian. Defaults to None. horizontal_std (Optional[float]): Standard deviation of the horizontal range in radian. Defaults to None. vertical_std (Optional[float]): Standard deviation of the vertical range in radian. Defaults to None. look_at (Optional[List, torch.Tensor]): The look at position of the camera. Defaults to None. fov (Optional[float]): The FOV (field-of-view) in degree. Defaults to None. up (Optional[List, torch.Tensor]): The up direction of the world coordinate. Defaults to None. radius (Optional[float]): Radius of the sphere. Defaults to None. sampling_strategy (Optional[str]): The sampling strategy (distribution) of the camera. Support 'Uniform' and 'Gaussian'. Defaults to 'Uniform'. """ def __init__(self, horizontal_mean: Optional[float] = None, vertical_mean: Optional[float] = None, horizontal_std: Optional[float] = 0, vertical_std: Optional[float] = 0, look_at: VectorType = [0, 0, 0], fov: Optional[float] = None, focal: Optional[float] = None, up: VectorType = [0, 1, 0], radius: Optional[float] = 1, sampling_strategy: str = 'uniform'): super().__init__() self.horizontal_mean = horizontal_mean self.vertical_mean = vertical_mean self.horizontal_std = horizontal_std self.vertical_std = vertical_std self.look_at = look_at self.up = up self.radius = radius self.sampling_statregy = sampling_strategy assert ((fov is None) or (focal is None)), ( '\'fov\' and \'focal\' should not be passed at the same time.') self.fov = fov self.focal = focal def _sample_in_range(self, mean: float, std: float, batch_size: int) -> torch.Tensor: """Sample value with specific mean and std. Args: mean (float): Mean of the sampled value. std (float): Standard deviation of the sampled value. batch_size (int): The batch size of the sampled result. Returns: torch.Tensor: Sampled results. """ if self.sampling_statregy.upper() == 'UNIFORM': return (torch.rand((batch_size, 1)) - 0.5) * 2 * std + mean elif self.sampling_statregy.upper() == 'GAUSSIAN': return torch.randn((batch_size, 1)) * std + mean else: raise ValueError( 'Only support \'Uniform\' sampling and \'Gaussian\' sampling ' 'currently. If you want to implement your own sampling ' 'method, you can overwrite \'_sample_in_range\' function by ' 'yourself.') def sample_intrinsic(self, fov: Optional[float] = None, focal: Optional[float] = None, device: Optional[DeviceType] = None, batch_size: int = 1) -> torch.Tensor: """Sample intrinsic matrix. Args: fov (Optional[float], optional): FOV (field of view) in degree. If not passed, :attr:`self.fov` will be used. Defaults to None. focal (Optional[float], optional): Focal in pixel. If not passed, :attr:`self.focal` will be used. Defaults to None. batch_size (int): The batch size of the output. Defaults to 1. device (DeviceType, optional): Device to put the intrinsic matrix. If not passed, :attr:`self.device` will be used. Defaults to None. Returns: torch.Tensor: Intrinsic matrix. """ # 1. check if foc and focal is both passed assert (fov is None) or (focal is None), ( '\'fov\' and focal should not be passed at the same time.') # 2. if fov and focal is neither not passed, use initialized ones. if fov is None and focal is None: fov = self.fov if fov is None else fov focal = self.focal if focal is None else focal if fov is None and focal is None: raise ValueError( '\'fov\', \'focal\', \'self.fov\' and \'self.focal\' should ' 'not be None neither.') if fov is not None: intrinstic = self.fov_to_intrinsic(fov, device) else: intrinstic = self.focal_to_instrinsic(focal, device) return intrinstic[None, ...].repeat(batch_size, 1, 1) def fov_to_intrinsic(self, fov: Optional[float] = None, device: DeviceType = None) -> torch.Tensor: """Calculate intrinsic matrix from FOV (field of view). Args: fov (Optional[float], optional): FOV (field of view) in degree. If not passed, :attr:`self.fov` will be used. Defaults to None. device (DeviceType, optional): Device to put the intrinsic matrix. If not passed, :attr:`self.device` will be used. Defaults to None. Returns: torch.Tensor: Intrinsic matrix. """ fov = self.fov if fov is None else fov assert fov is not None, ( '\'fov\' and \'self.fov\' should not be None at the same time.') # device = self.device if device is None else device # NOTE: EG3D multiplies '1 / 1.414' as `image_width` to `focal`, we # retain this operation focal = float(1 / (math.tan(fov * math.pi / 360) * 1.414)) intrinsics = [[focal, 0, 0.5], [0, focal, 0.5], [0, 0, 1]] intrinsics = torch.tensor(intrinsics, device=device) return intrinsics def focal_to_instrinsic(self, focal: Optional[float] = None, device: DeviceType = None) -> torch.Tensor: """Calculate intrinsic matrix from focal. Args: focal (Optional[float], optional): Focal in degree. If not passed, :attr:`self.focal` will be used. Defaults to None. device (DeviceType, optional): Device to put the intrinsic matrix. If not passed, :attr:`self.device` will be used. Defaults to None. Returns: torch.Tensor: Intrinsic matrix. """ focal = self.focal if focal is None else focal assert focal is not None, ( '\'focal\' and \'self.focal\' should not be None at the ' 'same time.') # device = self.device if device is None else device intrinsics = [[focal, 0, 0.5], [0, focal, 0.5], [0, 0, 1]] intrinsics = torch.tensor(intrinsics, device=device) return intrinsics def sample_theta(self, mean: float, std: float, batch_size: int) -> torch.Tensor: """Sampling the theta (yaw). Args: mean (float): Mean of theta. std (float): Standard deviation of theta. batch_size (int): Target batch size of theta. Returns: torch.Tensor: Sampled theta. """ h = self._sample_in_range(mean, std, batch_size) return h def sample_phi(self, mean: float, std: float, batch_size: int) -> torch.Tensor: """Sampling the phi (pitch). Unlike sampling theta, we uniformly sample phi on cosine space to release a spherical uniform sampling. Args: mean (float): Mean of phi. std (float): Standard deviation of phi. batch_size (int): Target batch size of phi. Returns: torch.Tensor: Sampled phi. """ v = self._sample_in_range(mean, std, batch_size) v = torch.clamp(v, 1e-5, math.pi - 1e-5) v = v / math.pi if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): import numpy as np phi = torch.from_numpy(np.arccos((1 - 2 * v).numpy())) else: phi = torch.arccos(1 - 2 * v) return phi def sample_camera2world(self, h_mean: Optional[float] = None, v_mean: Optional[float] = None, h_std: Optional[float] = None, v_std: Optional[float] = None, look_at: VectorType = None, up: VectorType = None, radius: Optional[float] = None, batch_size: int = 1, device: Optional[str] = None) -> torch.Tensor: """Sample camera-to-world matrix with the passed condition. Args: h_mean (Optional[float], optional): Mean of horizontal range in radian. Defaults to None. v_mean (Optional[float], optional): Mean of vertical range in radian. Defaults to None. h_std (Optional[float], optional): Standard deviation of horizontal in radian. Defaults to None. v_std (Optional[float], optional): Standard deviation of horizontal in radian. Defaults to None. look_at (Optional[Tuple[list, torch.Tensor]], optional): Look-at position. Defaults to None. up (Optional[Tuple[list, torch.Tensor]], optional): Up direction of the world coordinate. Defaults to None. radius (Optional[float]): Radius of the sphere. Defaults to None. batch_size (int, optional): Batch size of the results. Defaults to 1. device (Optional[str], optional): The target device of the results. Defaults to None. Returns: torch.Tensor: Sampled camera-to-world matrix. """ # parse input h_mean = self.horizontal_mean if h_mean is None else h_mean v_mean = self.vertical_mean if v_mean is None else v_mean h_std = self.horizontal_std if h_std is None else h_std v_std = self.vertical_std if v_std is None else v_std radius = self.radius if radius is None else radius # device = self.device if device is None else device look_at = self.look_at if look_at is None else look_at if not isinstance(look_at, torch.FloatTensor): look_at = torch.FloatTensor(look_at) look_at = look_at.to(device) up = self.up if up is None else up if not isinstance(up, torch.FloatTensor): up = torch.FloatTensor(up) up = up.to(device) # sample yaw and pitch theta = self.sample_theta(h_mean, h_std, batch_size).to(device) phi = self.sample_phi(v_mean, v_std, batch_size).to(device) # construct camera origin camera_origins = torch.zeros((batch_size, 3), device=device) camera_origins[:, 0:1] = radius * torch.sin(phi) * torch.cos(math.pi - theta) camera_origins[:, 2:3] = radius * torch.sin(phi) * torch.sin(math.pi - theta) camera_origins[:, 1:2] = radius * torch.cos(phi) # calculate forward vector and camer2world forward_vectors = normalize_vecs(look_at - camera_origins) camera2world = create_cam2world_matrix(forward_vectors, camera_origins, up) return camera2world def interpolation_cam2world(self, num_images: int, h_mean: Optional[float] = None, v_mean: Optional[float] = None, h_std: Optional[float] = None, v_std: Optional[float] = None, look_at: VectorType = None, up: VectorType = None, radius: Optional[float] = None, batch_size: int = 1, device: Optional[str] = None ) -> List[torch.Tensor]: """Interpolation camera original in spherical trajectory and return a list of camera-to-world matrix. Args: num_images (int): The number of images in interpolation. h_mean (Optional[float], optional): Mean of horizontal range in radian. Defaults to None. v_mean (Optional[float], optional): Mean of vertical range in radian. Defaults to None. h_std (Optional[float], optional): Standard deviation of horizontal in radian. Defaults to None. v_std (Optional[float], optional): Standard deviation of horizontal in radian. Defaults to None. look_at (Optional[Tuple[list, torch.Tensor]], optional): Look-at position. Defaults to None. up (Optional[Tuple[list, torch.Tensor]], optional): Up direction of the world coordinate. Defaults to None. radius (Optional[float]): Radius of the sphere. Defaults to None. batch_size (int, optional): Batch size of the results. Defaults to 1. device (Optional[str], optional): The target device of the results. Defaults to None. Returns: List[torch.Tensor]: List of sampled camera-to-world matrix. """ h_mean = self.horizontal_mean if h_mean is None else h_mean v_mean = self.vertical_mean if v_mean is None else v_mean h_std = self.horizontal_std if h_std is None else h_std v_std = self.vertical_std if v_std is None else v_std radius = self.radius if radius is None else radius look_at = self.look_at if look_at is None else look_at if not isinstance(look_at, torch.FloatTensor): look_at = torch.FloatTensor(look_at) look_at = look_at.to(device) up = self.up if up is None else up if not isinstance(up, torch.FloatTensor): up = torch.FloatTensor(up) up = up.to(device) cam2world_list = [] for idx in range(num_images): h = h_mean + h_std * math.sin(2 * math.pi / num_images * idx) v = v_mean + v_std * math.cos(2 * math.pi / num_images * idx) cam2world = self.sample_camera2world( h_mean=h, v_mean=v, h_std=0, v_std=0, batch_size=batch_size, device=device) cam2world_list.append(cam2world) return cam2world_list def __repr__(self): repr_string = f'{self.__class__.__name__}' attribute_list = [ 'horizontal_mean', 'vertical_mean', 'horizontal_std', 'vertical_std', 'FOV', 'focal', 'look_at', 'up', 'radius', 'sampling_statregy' ] for attribute in attribute_list: if getattr(self, attribute, None) is not None: repr_string += f'\n {attribute}: {getattr(self, attribute)}' return repr_string @MODELS.register_module() class GaussianCamera(BaseCamera): """Pre-defined camera class. Sample camera position in gaussian distribution. Args: horizontal_mean (Optional[float]): Mean of the horizontal range in radian. Defaults to None. vertical_mean (Optional[float]): Mean of the vertical range in radian. Defaults to None. horizontal_std (Optional[float]): Standard deviation of the horizontal range in radian. Defaults to None. vertical_std (Optional[float]): Standard deviation of the vertical range in radian. Defaults to None. look_at (Optional[List, torch.Tensor]): The look at position of the camera. Defaults to None. up (Optional[List, torch.Tensor]): The up direction of the world coordinate. Defaults to None. radius (Optional[float]): Radius of the sphere. Defaults to None. """ def __init__(self, horizontal_mean: Optional[float] = None, vertical_mean: Optional[float] = None, horizontal_std: Optional[float] = 0, vertical_std: Optional[float] = 0, look_at: List = [0, 0, 0], fov: Optional[float] = None, focal: Optional[float] = None, up: VectorType = [0, 1, 0], radius: Optional[float] = 1): super().__init__(horizontal_mean, vertical_mean, horizontal_std, vertical_std, look_at, fov, focal, up, radius, 'gaussian') @MODELS.register_module() class UniformCamera(BaseCamera): """Pre-defined camera class. Sample camera position in uniform distribution. Args: horizontal_mean (Optional[float]): Mean of the horizontal range in radian. Defaults to None. vertical_mean (Optional[float]): Mean of the vertical range in radian. Defaults to None. horizontal_std (Optional[float]): Standard deviation of the horizontal range in radian. Defaults to None. vertical_std (Optional[float]): Standard deviation of the vertical range in radian. Defaults to None. look_at (Optional[List, torch.Tensor]): The look at position of the camera. Defaults to None. up (Optional[List, torch.Tensor]): The up direction of the world coordinate. Defaults to None. radius (Optional[float]): Radius of the sphere. Defaults to None. """ def __init__(self, horizontal_mean: Optional[float] = None, vertical_mean: Optional[float] = None, horizontal_std: Optional[float] = 0, vertical_std: Optional[float] = 0, look_at: List = [0, 0, 0], fov: Optional[float] = None, focal: Optional[float] = None, up: VectorType = [0, 1, 0], radius: Optional[float] = 1): super().__init__(horizontal_mean, vertical_mean, horizontal_std, vertical_std, look_at, fov, focal, up, radius, 'uniform') def create_cam2world_matrix(forward_vector: torch.Tensor, origin: torch.Tensor, up: torch.Tensor) -> torch.Tensor: """Calculate camera-to-world matrix from camera's forward vector, world origin and world up direction. The calculation is performed in right-hand coordinate system and the returned matrix is in homogeneous coordinates (shape like (bz, 4, 4)). Args: forward_vector (torch.Tensor): The forward vector of the camera. origin (torch.Tensor): The origin of the world coordinate. up (torch.Tensor): The up direction of the world coordinate. Returns: torch.Tensor: Camera-to-world matrix. """ forward_vector = normalize_vecs(forward_vector) up_vector = up.type(torch.float).expand_as(forward_vector) right_vector = -normalize_vecs( torch.cross(up_vector, forward_vector, dim=-1)) up_vector = normalize_vecs( torch.cross(forward_vector, right_vector, dim=-1)) rotation_matrix = torch.eye( 4, device=origin.device).unsqueeze(0).repeat(forward_vector.shape[0], 1, 1) rotation_matrix[:, :3, :3] = torch.stack( (right_vector, up_vector, forward_vector), axis=-1) translation_matrix = torch.eye( 4, device=origin.device).unsqueeze(0).repeat(forward_vector.shape[0], 1, 1) translation_matrix[:, :3, 3] = origin cam2world = (translation_matrix @ rotation_matrix)[:, :, :] assert (cam2world.shape[1:] == (4, 4)) return cam2world ================================================ FILE: mmagic/models/editors/eg3d/dual_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import numpy as np import torch import torch.nn.functional as F from mmengine.runner.amp import autocast from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from torch import Tensor from mmagic.registry import MODELS from ..stylegan2 import StyleGAN2Discriminator @MODELS.register_module('EG3DDiscriminator') @MODELS.register_module() class DualDiscriminator(StyleGAN2Discriminator): """Dual Discriminator for EG3D. DualDiscriminator shares the same network structure with StyleGAN2's Discriminator. However, DualDiscriminator take volume rendered low-resolution image and super-resolved image at the same time. The LR image will be upsampled and concatenate with SR ones, and then feed to the discriminator together. Args: img_channels (int): The number of the image channels. Defaults to 3. use_dual_disc (bool): Whether use dual discriminator as EG3D. If True, the input channel of the first conv block will be set as `2 * img_channels`. Defaults to True. disc_c_noise (float): The factor of noise's standard deviation add to conditional input before passed to mapping network. Defaults to 0. *args, **kwargs: Arguments for StyleGAN2Discriminator. """ def __init__(self, img_channels: int = 3, use_dual_disc: bool = True, disc_c_noise: float = 0, *args, **kwargs): if use_dual_disc: img_channels *= 2 self.use_dual_disc = use_dual_disc super().__init__(img_channels=img_channels, *args, **kwargs) self.disc_c_noise = disc_c_noise def forward(self, img: Tensor, img_raw: Optional[Tensor] = None, cond: Optional[Tensor] = None): """Forward function. Args: img (torch.Tensor): Input high resoluation image tensor. img_raw (torch.Tensor): Input raw (low resolution) image tensor. Defaults to None. cond (torch.Tensor): The conditional input (camera-to-world matrix and intrinsics matrix). Defaults to None. Returns: torch.Tensor: Predict score for the input image. """ if self.use_dual_disc: assert img_raw is not None, ( '\'img_raw\' must be passed when \'use_dual_disc\' is True.') # This setting was used to finetune on converted weights if self.input_bgr2rgb: img = img[:, [2, 1, 0], ...] if img_raw is not None: img_raw = img_raw[:, [2, 1, 0], ...] if img_raw is not None: # the official implementation only use 'antialiased' upsampline, # therefore we only support 'antialiased' for torch >= 1.11.0 interpolation_kwargs = dict( size=(img.shape[-1], img.shape[-1]), mode='bilinear', align_corners=False) if digit_version(TORCH_VERSION) >= digit_version('1.11.0'): interpolation_kwargs['antialias'] = True img_raw_sr = F.interpolate(img_raw, **interpolation_kwargs) img = torch.cat([img, img_raw_sr], dim=1) # convs has own fp-16 controller, do not wrap here x = self.convs(img) x = self.mbstd_layer(x) fp16_enabled = ( self.final_conv.fp16_enabled or not self.convert_input_fp32) with autocast(enabled=fp16_enabled): if not fp16_enabled: x = x.to(torch.float32) x = self.final_conv(x) x = x.view(x.shape[0], -1) x = self.final_linear(x) # conditioning if cond is not None: assert self.mapping is not None, ( '\'mapping\' network must not be None when conditional ' 'input is passed.') # if self.disc_c_noise is not None and self.disc_c_noise > 0: if self.disc_c_noise is not None: cond = cond + torch.randn_like( cond) * cond.std() * self.disc_c_noise cmap = self.mapping(None, cond) x = (x * cmap).sum( dim=1, keepdim=True) * (1 / np.sqrt(cmap.shape[1])) return x ================================================ FILE: mmagic/models/editors/eg3d/eg3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn from mmengine import Config from mmengine.utils import ProgressBar from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, SampleList from ...base_models import BaseConditionalGAN from ...utils import get_valid_num_batches ModelType = Union[Dict, nn.Module] @MODELS.register_module() class EG3D(BaseConditionalGAN): """Implementation of `Efficient Geometry-aware 3D Generative Adversarial Networks` _ (EG3D). # noqa Detailed architecture can be found in :class:`~mmagic.models.editors.eg3d.eg3d_generator.TriplaneGenerator` and :class:`~mmagic.models.editors.eg3d.dual_discriminator.DualDiscriminator` Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. camera (Optional[ModelType]): The pre-defined camera to sample random camera position. If you want to generate images or videos via high-level API, you must set this argument. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): Number of times the generator was completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): Number of times the discriminator was completely updated before the generator is updated. Defaults to 1. noise_size (Optional[int]): Size of the input noise vector. Default to 128. num_classes (Optional[int]): The number classes you would like to generate. Defaults to None. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. loss_config (Optional[Dict]): The config for training losses. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, camera: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, noise_size: Optional[int] = None, ema_config: Optional[Dict] = None, loss_config: Optional[Dict] = None): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, noise_size, None, ema_config, loss_config) if isinstance(camera, dict): self.camera = MODELS.build(camera) elif isinstance(camera, nn.Module): self.camera = camera else: self.camera = None def label_fn(self, label: Optional[Tensor] = None, num_batches: int = 1) -> Tensor: """Label sampling function for EG3D model. Args: label (Optional[Tensor]): Conditional for EG3D model. If not passed, :attr:`self.camera` will be used to sample random camera-to-world and intrinsics matrix. Defaults to None. Returns: torch.Tensor: Conditional input for EG3D model. """ if label is not None: return label # sample random conditional from camera assert self.camera is not None, ( '\'camera\' is not defined for \'EG3D\'.') camera2world = self.camera.sample_camera2world(batch_size=num_batches) intrinsics = self.camera.sample_intrinsic(batch_size=num_batches) cond = torch.cat( [camera2world.reshape(-1, 16), intrinsics.reshape(-1, 9)], dim=1).to(self.device) return cond def data_sample_to_label(self, data_sample: SampleList ) -> Optional[torch.Tensor]: """Get labels from input `data_sample` and pack to `torch.Tensor`. If no label is found in the passed `data_sample`, `None` would be returned. Args: data_sample (List[DataSample]): Input data samples. Returns: Optional[torch.Tensor]: Packed label tensor. """ if not data_sample or 'gt_label' not in data_sample.keys(): return None return data_sample.gt_label.label def pack_to_data_sample( self, output: Dict[str, Tensor], # index: int, data_sample: Optional[DataSample] = None) -> DataSample: """Pack output to data sample. If :attr:`data_sample` is not passed, a new DataSample will be instantiated. Otherwise, outputs will be added to the passed datasample. Args: output (Dict[Tensor]): Output of the model. index (int): The index to save. data_sample (DataSample, optional): Data sample to save outputs. Defaults to None. Returns: DataSample: Data sample with packed outputs. """ assert isinstance(output, dict), ('Output of EG3D generator should be a dict.') data_sample = DataSample() if data_sample is None else data_sample for k, v in output.items(): assert isinstance(v, torch.Tensor), ( f'Output must be tensor. But \'{k}\' is type of ' f'\'{type(v)}\'.') # NOTE: hard code here, we assume all tensor are [bz, ...] data_sample.set_tensor_data({k: v}) return data_sample def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: """Sample images with the given inputs. If forward mode is 'ema' or 'orig', the image generated by corresponding generator will be returned. If forward mode is 'ema/orig', images generated by original generator and EMA generator will both be returned in a dict. Args: inputs (ForwardInputs): Dict containing the necessary information (e.g. noise, num_batches, mode) to generate image. data_samples (Optional[list]): Data samples collated by :attr:`data_preprocessor`. Defaults to None. mode (Optional[str]): `mode` is not used in :class:`BaseConditionalGAN`. Defaults to None. Returns: List[DataSample]: Generated images or image dict. """ if isinstance(inputs, Tensor): noise = inputs sample_kwargs = {} else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) sample_kwargs = inputs.get('sample_kwargs', dict()) num_batches = noise.shape[0] labels = self.data_sample_to_label(data_samples) if labels is None: num_batches = get_valid_num_batches(inputs, data_samples) labels = self.label_fn(num_batches=num_batches) sample_model = self._get_valid_model(inputs) batch_sample_list = [] if sample_model in ['ema', 'orig']: if sample_model == 'ema': generator = self.generator_ema else: generator = self.generator outputs = generator(noise, label=labels) outputs['fake_img'] = self.data_preprocessor.destruct( outputs['fake_img'], data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample = self.pack_to_data_sample(outputs, gen_sample) gen_sample.noise = noise gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = sample_model batch_sample_list = gen_sample.split(allow_nonseq_value=True) else: outputs_orig = self.generator(noise, label=labels) outputs_ema = self.generator_ema(noise, label=labels) outputs_orig['fake_img'] = self.data_preprocessor.destruct( outputs_orig['fake_img'], data_samples) outputs_ema['fake_img'] = self.data_preprocessor.destruct( outputs_ema['fake_img'], data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.ema = self.pack_to_data_sample(outputs_ema) gen_sample.orig = self.pack_to_data_sample(outputs_orig) gen_sample.noise = noise gen_sample.sample_kwargs = deepcopy(sample_kwargs) gen_sample.sample_model = sample_model batch_sample_list = gen_sample.split(allow_nonseq_value=True) return batch_sample_list @torch.no_grad() def interpolation(self, num_images: int, num_batches: int = 4, mode: str = 'both', sample_model: str = 'orig', show_pbar: bool = True) -> List[dict]: """Interpolation input and return a list of output results. We support three kinds of interpolation mode: * 'camera': First generate style code with random noise and forward camera. Then synthesis images with interpolated camera position and fixed style code. * 'conditioning': First generate style code with fixed noise and interpolated camera. Then synthesis images with style codes and forward camera. * 'both': Generate images with interpolated camera position. Args: num_images (int): The number of images want to generate. num_batches (int, optional): The number of batches to generate at one time. Defaults to 4. mode (str, optional): The interpolation mode. Supported choices are 'both', 'camera', and 'conditioning'. Defaults to 'both'. sample_model (str, optional): The model used to generate images, support 'orig' and 'ema'. Defaults to 'orig'. show_pbar (bool, optional): Whether display a progress bar during interpolation. Defaults to True. Returns: List[dict]: The list of output dict of each frame. """ assert hasattr(self, 'camera'), ('Camera must be defined.') assert mode.upper() in ['BOTH', 'CONDITIONING', 'CAMERA'] assert sample_model in ['ema', 'orig'] if sample_model == 'orig': gen = self.generator else: assert self.with_ema_gen, ( '\'sample_model\' is EMA, but ema model not found.') # generator_ema is wrapped by AverageModel gen = self.generator_ema.module cam2world_forward = self.camera.sample_camera2world( h_std=0, v_std=0, batch_size=num_batches, device=self.device) intrinsics = self.camera.sample_intrinsic( batch_size=num_batches, device=self.device) cond_forward = torch.cat([ cam2world_forward.view(num_batches, -1), intrinsics.view(num_batches, -1) ], dim=1) # 1. generate cond list if mode.upper() in ['CAMERA', 'BOTH']: cam2world_list = self.camera.interpolation_cam2world( num_images, batch_size=num_batches, device=self.device) cond_list = [] for cam2world in cam2world_list: cond = torch.cat([ cam2world.view(num_batches, -1), intrinsics.view(num_batches, -1) ], dim=1) cond_list.append(cond) else: cond_list = [cond_forward for _ in range(num_images)] # 2. generate pre-defined style list if mode.upper() == 'CAMERA': # same noise + forward cond style = gen.backbone.mapping( self.noise_fn(num_batches=num_batches), cond_forward) style_list = [style for _ in range(num_images)] else: # same noise + different cond noise = self.noise_fn(num_batches=num_batches) style_list = [ gen.backbone.mapping(noise, cond) for cond in cond_list ] # 3. interpolation if show_pbar: pbar = ProgressBar(num_images) output_list = [] for style, cond in zip(style_list, cond_list): # generate image with const noise output = gen( style, cond, input_is_latent=True, add_noise=True, randomize_noise=False) # use fixed noise output_list.append({k: v.cpu() for k, v in output.items()}) if show_pbar: pbar.update(1) if show_pbar: print('\n') return output_list ================================================ FILE: mmagic/models/editors/eg3d/eg3d_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Optional, Tuple import torch from mmengine.model import BaseModule from torch import Tensor from mmagic.registry import MODELS from .eg3d_modules import SuperResolutionModule, TriPlaneBackbone from .ray_sampler import sample_rays from .renderer import EG3DRenderer @MODELS.register_module('EG3DGenerator') @MODELS.register_module() class TriplaneGenerator(BaseModule): """The generator for EG3D. EG3D generator contains three components: * A StyleGAN2 based backbone to generate a triplane feature * A neural renderer to sample and render low-resolution 2D feature and image from generated triplane feature * A super resolution module to upsample low-resolution image to high-resolution one Args: out_size (int): The resolution of the generated 2D image. noise_size (int): The size of the noise vector of the StyleGAN2 backbone. Defaults to 512. style_channels (int): The number of channels for style code. Defaults to 512. cond_size (int): The size of the conditional input. Defaults to 25 (first 16 elements are flattened camera-to-world matrix and the last 9 elements are flattened intrinsic matrix). cond_mapping_channels (Optional[int]): The channels of the conditional mapping layers. If not passed, will use the same value as :attr:`style_channels`. Defaults to None. cond_scale (float): The scale factor is multiple by the conditional input. Defaults to 1. zero_cond_input (bool): Whether use 'zero tensor' as the conditional input. Defaults to False. num_mlps (int): The number of MLP layers (mapping network) used in backbone. Defaults to 8. triplane_size (int): The size of generated triplane feature. Defaults to 256. triplane_channels (int): The number of channels for each plane of the triplane feature. Defaults to 32. sr_in_size (int): The input resolution of super resolution module. If the input feature not match with the passed `sr_in_size`, bilinear interpolation will be used to resize feature to target size. Defaults to 64. sr_in_channels (int): The number of the input channels of super resolution module. Defaults to 32. sr_hidden_channels (int): The number of the hidden channels of super resolution module. Defaults to 128. sr_out_channels (int): The number of the output channels of super resolution module. Defaults to 64. sr_add_noise (bool): Whether use noise injection to super resolution module. Defaults to False. neural_rendering_resolution (int): The resolution of the neural rendering output. Defaults to 64. Noted that in the training process, neural rendering resolution will be changed. Defaults to 64. renderer_cfg (int): The config to build :class:`EG3DRenderer`. Defaults to '{}'. rgb2bgr (bool): Whether convert the RGB output to BGR. This is useful when pretrained model is trained on RGB dataset. Defaults to False. init_cfg (Optional[dict]): Initialization config. Defaults to None. """ def __init__(self, out_size: int, noise_size: int = 512, style_channels: int = 512, cond_size: int = 25, cond_mapping_channels: Optional[int] = None, cond_scale: float = 1, zero_cond_input: bool = False, num_mlps: int = 8, triplane_size: int = 256, triplane_channels: int = 32, sr_in_size: int = 64, sr_in_channels: int = 32, sr_hidden_channels: int = 128, sr_out_channels: int = 64, sr_antialias: bool = True, sr_add_noise: bool = True, neural_rendering_resolution: int = 64, renderer_cfg: dict = dict(), rgb2bgr: bool = False, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) self.out_size = out_size self.noise_size = noise_size self.cond_size = cond_size self.style_size = style_channels self.cond_scale = cond_scale self.zero_cond_input = zero_cond_input self.sr_add_noise = sr_add_noise # build StyleGAN2 backbone self.triplane_channels = triplane_channels self.backbone = TriPlaneBackbone( out_size=triplane_size, noise_size=noise_size, out_channels=triplane_channels * 3, style_channels=style_channels, num_mlps=num_mlps, cond_size=cond_size, cond_scale=self.cond_scale, cond_mapping_channels=cond_mapping_channels, zero_cond_input=self.zero_cond_input) # build renderer + nerf-decoder and ray sampler self.neural_rendering_resolution = neural_rendering_resolution renderer_cfg_ = deepcopy(renderer_cfg) decoder_cfg_ = renderer_cfg.get('decoder_cfg', dict()) decoder_cfg_['in_channels'] = triplane_channels decoder_cfg_['out_channels'] = sr_in_channels renderer_cfg_['decoder_cfg'] = decoder_cfg_ self.renderer = EG3DRenderer(**deepcopy(renderer_cfg_)) # build super-resolution module sr_factor = out_size // sr_in_size assert sr_factor in [ 2, 4, 8 ], ('Only support super resolution with factor 2, 4 or 8. ' f'But \'out_size\' and \'sr_in_size\'are {out_size} and ' f'{sr_in_size}.') self.sr_model = SuperResolutionModule( in_channels=sr_in_channels, in_size=sr_in_size, hidden_size=sr_in_size * 2 if sr_factor in [4, 8] else sr_in_size, out_size=out_size, style_channels=style_channels, hidden_channels=sr_hidden_channels, out_channels=sr_out_channels, sr_antialias=sr_antialias) # flag for pretrained models self.rgb2bgr = rgb2bgr def sample_ray(self, cond: torch.Tensor) -> Tuple[Tensor]: """Sample render points corresponding to the given conditional. Args: cond (torch.Tensor): Conditional inputs. Returns: Tuple[Tensor]: The original and direction vector of sampled rays. """ cam2world_matrix = cond[:, :16].view(-1, 4, 4) intrinsics = cond[:, 16:25].view(-1, 3, 3) ray_origin, ray_directions = sample_rays( cam2world_matrix, intrinsics, self.neural_rendering_resolution) return ray_origin, ray_directions def forward(self, noise: Tensor, label: Optional[Tensor] = None, truncation: Optional[float] = 1, num_truncation_layer: Optional[int] = None, input_is_latent: bool = False, plane: Optional[Tensor] = None, add_noise: bool = True, randomize_noise: bool = True, render_kwargs: Optional[dict] = None) -> dict: """The forward function for EG3D generator. Args: noise (Tensor): The input noise vector. label (Optional[Tensor]): The conditional input. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. num_truncation_layer (int, optional): Number of layers use truncated latent. Defaults to None. input_is_latent (bool): Whether the input latent. Defaults to False. plane (Optional[Tensor]): The pre-generated triplane feature. If passed, will use the passed plane to generate 2D image. Defaults to None. add_noise (bool): Whether apply noise injection to the triplane backbone. Defaults to True. randomize_noise (bool, optional): If `False`, images are sampled with the buffered noise tensor injected to the style conv block. Defaults to True. render_kwargs (Optional[dict], optional): The specific kwargs for rendering. Defaults to None. Returns: dict: A dict contains 'fake_img', 'lr_img', 'depth', 'ray_directions' and 'ray_origins'. """ batch_size = noise.shape[0] if not input_is_latent: styles = self.backbone.mapping( noise, label, truncation=truncation, num_truncation_layer=num_truncation_layer) else: styles = noise ray_origins, ray_directions = self.sample_ray(label) if plane is None: plane = self.backbone.synthesis( styles, add_noise=add_noise, randomize_noise=randomize_noise) # Reshape output into three `triplane_channels`-channel planes plane = plane.view( len(plane), 3, self.triplane_channels, plane.shape[-2], plane.shape[-1]) # Perform volume rendering feature_samples, depth_samples, _ = self.renderer( plane, ray_origins, ray_directions, render_kwargs=render_kwargs) # Reshape into 'raw' neural-rendered image H = W = self.neural_rendering_resolution feature_image = feature_samples.permute(0, 2, 1).reshape( batch_size, feature_samples.shape[-1], H, W).contiguous() depth_image = depth_samples.permute(0, 2, 1).reshape(batch_size, 1, H, W) # Run super resolution to get final image rgb_image = feature_image[:, :3] sr_image = self.sr_model( rgb_image, feature_image, styles, add_noise=self.sr_add_noise) if self.rgb2bgr: sr_image = sr_image.flip(1) rgb_image = rgb_image.flip(1) output_dict = dict( fake_img=sr_image, lr_img=rgb_image, # low-resolution images depth=depth_image, ray_directions=ray_directions, ray_origins=ray_origins) return output_dict ================================================ FILE: mmagic/models/editors/eg3d/eg3d_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Tuple, Union import torch import torch.nn.functional as F from mmengine import print_log from mmengine.model import BaseModule from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from ..stylegan2 import StyleGAN2Generator from ..stylegan2.stylegan2_modules import ModulatedStyleConv, ModulatedToRGB class TriPlaneBackbone(StyleGAN2Generator): """Tr-plane backbone for EG3D generator. This class is a wrapper of StyleGAN2Generator. Args: noise_size (int, optional): The size of (number of channels) the input noise. If not passed, will be set the same value as :attr:`style_channels`. Defaults to None. out_size (int): The output size of the StyleGAN2 generator. out_channels (int): The number of channels for output. num_mlps (int, optional): The number of MLP layers. Defaults to 8. style_channels (int): The number of channels for style code. Defaults to 512. cond_size (int, optional): The size of the conditional input. If not passed or less than 1, no conditional embedding will be used. Defaults to None. cond_mapping_channels (int, optional): The channels of the conditional mapping layers. If not passed, will use the same value as :attr:`style_channels`. Defaults to None. cond_scale (float): The scale factor is multiple by the conditional input. Defaults to 1. zero_cond_input (bool): Whether use 'zero tensor' as the conditional input. Defaults to False. *args, **kwargs: Arguments for StyleGAN2Generator. """ def __init__(self, noise_size: int, out_size: int, out_channels: int, num_mlps: int = 8, style_channels: int = 512, cond_size: Optional[int] = 25, cond_mapping_channels: Optional[int] = None, cond_scale: float = 0, zero_cond_input: bool = False, *args, **kwargs): super().__init__( out_size, style_channels, num_mlps=num_mlps, noise_size=noise_size, out_channels=out_channels, cond_size=cond_size, cond_mapping_channels=cond_mapping_channels, *args, **kwargs) self.cond_scale = cond_scale self.zero_cond_input = zero_cond_input def mapping(self, noise: torch.Tensor, label: Optional[torch.Tensor] = None, truncation: float = 1, num_truncation_layer: Optional[int] = None, update_ws: bool = True) -> torch.Tensor: """Mapping input noise (z) to style space (w). Args: noise (torch.Tensor): Noise input. label (Optional[torch.Tensor]): Conditional inputs. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. num_truncation_layer (int, optional): Number of layers use truncated latent. Defaults to None. update_ws (bool): Whether update latent code with EMA. Only work when `w_avg` is registered. Defaults to False. Returns: torch.Tensor: Style codes after mapping. """ assert noise.shape[1] == self.noise_size noise = self.pixel_norm(noise) if label is not None: assert label.shape[1] == self.cond_size if self.zero_cond_input: label = torch.zeros_like(label) label = label * self.cond_scale embedding = self.embed(label) embedding = self.pixel_norm(embedding) else: # generate a zero input even if cond is not passed. if self.zero_cond_input: assert self.cond_size is not None, ( '\'cond_size\' must be passed when ' '\'zero_cond_input\' is True.') label = torch.zeros( noise.shape[0], self.cond_size, device=noise.device) embedding = self.embed(label) embedding = self.pixel_norm(embedding) else: embedding = None mapping_input = noise if embedding is None \ else torch.cat([noise, embedding], dim=1) styles = self.style_mapping(mapping_input) if hasattr(self, 'w_avg') and update_ws: self.w_avg.copy_(styles.detach().mean( dim=0).lerp(self.w_avg, self.w_avg_beta)) if truncation < 1: truncation_latent = self.get_mean_latent() styles = truncation_latent + truncation * ( styles - truncation_latent) return styles def synthesis(self, styles: torch.Tensor, *args, **kwargs) -> torch.Tensor: """Generate the Triplane feature. Args: styles (torch.Tensor): The input style code. *args, **kwargs: Arguments for StyleGAN2Generator's forward. Returns: torch.Tensor: The generated Triplane feature. """ outputs = super().forward( styles, input_is_latent=True, update_ws=False, *args, **kwargs) return outputs class SuperResolutionModule(BaseModule): """Super resolution module for EG3D generator. Args: in_channels (int): The channels of the input feature. in_size (int): The size of the input feature. hidden_size (int): The size of the hidden feature. Only support hidden size equals to in_size or in_size times two. Defaults to None. out_size (int): The size of the output image. Defaults to None. hidden_channels (int): The channels of the hidden feature. Defaults to 64. style_channels (int): The channels of the style code. Defaults to 512. sr_antialias (bool): Whether use antialias interpolation method in upsampling. Defaults to True. fp16_enable (bool): Whether enable fp16 in this module. Defaults to False. """ def __init__(self, in_channels: int, in_size: Optional[int] = None, hidden_size: Optional[int] = None, out_size: Optional[int] = None, hidden_channels: int = 128, out_channels: int = 64, style_channels: Optional[int] = 512, sr_antialias: bool = True, fp16_enable: bool = False): super().__init__() self.in_size = in_size self.sr_antialias = sr_antialias self.fp16_enable = fp16_enable self.style_channels = style_channels block0_upsample = hidden_size > in_size if block0_upsample: assert hidden_size == in_size * 2, ( 'Only support upsampling with factor 2. But \'in_resolution\' ' f'and \'hidden_resolution\' are \'{in_size}\' and ' f'\'{hidden_size}\'.') self.block0 = SynthesisBlock( in_channels, hidden_channels, style_channels, img_channels=3, upsample=block0_upsample, fp16_enabled=fp16_enable) block1_upsample = out_size > hidden_size if block1_upsample: assert out_size == hidden_size * 2, ( 'Only support upsampling with factor 2. But ' '\'hidden_resolution\' and \'out_resolution\' are ' f'\'{in_size}\' and \'{hidden_size}\'.') self.block1 = SynthesisBlock( hidden_channels, out_channels, style_channels, img_channels=3, upsample=block1_upsample, fp16_enabled=fp16_enable) if digit_version(TORCH_VERSION) < digit_version('1.11.0'): print_log(f'Current Pytorch version is {TORCH_VERSION}, lower ' 'than 1.11.0. \'sr_antialias\' is ignored.') def forward(self, img: torch.Tensor, feature: torch.Tensor, styles: Union[torch.Tensor, List[torch.Tensor]], add_noise: bool = False) -> torch.Tensor: """Forward function. Args: img (torch.Tensor): Image to super resolution. x (torch.Tensor): Feature map of the input image. styles (torch.Tensor): Style codes in w space. add_noise (bool, optional): Whether add noise to image. Defaults to False. Returns: torch.Tensor: Image after super resolution. """ if isinstance(styles, list): styles = styles[-1] if styles.ndim == 3: styles = styles[-1] assert styles.ndim == 2 and styles.shape[-1] == self.style_channels styles = styles[:, None, :].repeat(1, 3, 1) if feature.shape[-1] != self.in_size: interpolation_kwargs = dict( size=(self.in_size, self.in_size), mode='bilinear', align_corners=False) if digit_version(TORCH_VERSION) >= digit_version('1.11.0'): interpolation_kwargs['antialias'] = self.sr_antialias feature = F.interpolate(feature, **interpolation_kwargs) img = F.interpolate(img, **interpolation_kwargs) feature, img = self.block0(feature, img, styles, add_noise) feature, img = self.block1(feature, img, styles, add_noise) return img class SynthesisBlock(BaseModule): """Synthesis block for EG3D's SuperResolutionModule. Args: in_channels (int): The number of channels for the input feature. out_channels (int): The number of channels for the output feature. style_channels (int): The number of channels for style code. img_channels (int): The number of channels of output image. upsample (bool): Whether do upsampling. Defaults to True. conv_clamp (float, optional): Whether clamp the convolutional layer results to avoid gradient overflow. Defaults to `256.0`. fp16_enabled (bool): Whether enable fp16. Defaults to False. """ def __init__(self, in_channels: int, out_channels: int, style_channels: int, img_channels: int, upsample: bool = True, conv_clamp: int = 256, fp16_enabled: bool = False): super().__init__() # architecture is default as 'skip' in EG3D self.in_channels = in_channels self.out_channels = out_channels self.fp16_enabled = fp16_enabled self.upsample = upsample self.conv0 = ModulatedStyleConv( in_channels, out_channels, kernel_size=3, upsample=upsample, style_channels=style_channels, fp16_enabled=fp16_enabled, conv_clamp=conv_clamp) self.conv1 = ModulatedStyleConv( out_channels, out_channels, kernel_size=3, style_channels=style_channels, conv_clamp=conv_clamp) self.to_rgb = ModulatedToRGB( out_channels, style_channels, img_channels, upsample=upsample) def forward(self, x: torch.Tensor, img: torch.Tensor, styles: torch.Tensor, add_noise: bool = False) -> Tuple[torch.Tensor]: """Forward Synthesis block. Args: x (torch.Tensor): Input feature. img (torch.Tensor): Input image. styles (torch.Tensor): Input style code. add_noise (bool, optional): Whether apply noise injection. Defaults to False. Returns: Tuple[torch.Tensor]: Output feature and image. """ w_iter = iter(styles.unbind(dim=1)) x = self.conv0(x, next(w_iter), add_noise=add_noise) x = self.conv1(x, next(w_iter), add_noise=add_noise) img = self.to_rgb(x, next(w_iter), img) assert img.dtype == torch.float32 return x, img ================================================ FILE: mmagic/models/editors/eg3d/eg3d_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Tuple import torch def get_ray_limits_box(rays_o: torch.Tensor, rays_d: torch.Tensor, box_side_length: float ) -> Tuple[torch.Tensor, torch.Tensor]: """ Author: Petr Kellnhofer Intersects rays with the [-1, 1] NDC volume. Returns min and max distance of entry. Returns -1 for no intersection. https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection # noqa Args: rays_o (torch.Tensor): The origin of each ray. rays_d (torch.Tensor): The direction vector of each ray. box_side_length (float): The side length of axis aligned bounding box (AABB). Returns: Tuple[torch.Tensor, torch.Tensor]: Start and end point for each ray. Both shape like (bz, res, res, 1). """ o_shape = rays_o.shape rays_o = rays_o.detach().reshape(-1, 3) rays_d = rays_d.detach().reshape(-1, 3) bb_min = [ -1 * (box_side_length / 2), -1 * (box_side_length / 2), -1 * (box_side_length / 2) ] bb_max = [ 1 * (box_side_length / 2), 1 * (box_side_length / 2), 1 * (box_side_length / 2) ] bounds = torch.tensor([bb_min, bb_max], dtype=rays_o.dtype, device=rays_o.device) is_valid = torch.ones(rays_o.shape[:-1], dtype=bool, device=rays_o.device) # Precompute inverse for stability. invdir = 1 / rays_d sign = (invdir < 0).long() # Intersect with YZ plane. tmin = (bounds.index_select(0, sign[..., 0])[..., 0] - rays_o[..., 0]) * invdir[..., 0] tmax = (bounds.index_select(0, 1 - sign[..., 0])[..., 0] - rays_o[..., 0]) * invdir[..., 0] # Intersect with XZ plane. tymin = (bounds.index_select(0, sign[..., 1])[..., 1] - rays_o[..., 1]) * invdir[..., 1] tymax = (bounds.index_select(0, 1 - sign[..., 1])[..., 1] - rays_o[..., 1]) * invdir[..., 1] # Resolve parallel rays. is_valid[torch.logical_or(tmin > tymax, tymin > tmax)] = False # Use the shortest intersection. tmin = torch.max(tmin, tymin) tmax = torch.min(tmax, tymax) # Intersect with XY plane. tzmin = (bounds.index_select(0, sign[..., 2])[..., 2] - rays_o[..., 2]) * invdir[..., 2] tzmax = (bounds.index_select(0, 1 - sign[..., 2])[..., 2] - rays_o[..., 2]) * invdir[..., 2] # Resolve parallel rays. is_valid[torch.logical_or(tmin > tzmax, tzmin > tmax)] = False # Use the shortest intersection. tmin = torch.max(tmin, tzmin) tmax = torch.min(tmax, tzmax) # Mark invalid. tmin[torch.logical_not(is_valid)] = -1 tmax[torch.logical_not(is_valid)] = -2 return tmin.reshape(*o_shape[:-1], 1), tmax.reshape(*o_shape[:-1], 1) def inverse_transform_sampling(bins: torch.Tensor, weights: torch.Tensor, n_importance: int, deterministic: bool = False, eps: float = 1e-5) -> torch.Tensor: """Sample `N_importance` samples from `bins` with distribution defined by `weights`. Args: bins (int): (N_points, N_samples+1) where N_samples is the number of coarse samples per ray - 2. weights (torch.Tensor): Weights shape like (N_points, N_samples-1). n_importance (int): The number of samples to draw from the distribution. deterministic (bool): Whether use deterministic sampling method. Defaults to False. eps (float): a small number to prevent division by zero. Defaults to 1e-5. Outputs: torch.Tensor: the sampled samples. """ N_rays, N_samples_ = weights.shape # prevent division by zero (don't do inplace op!) weights = weights + eps # (N_rays, N_samples_) pdf = weights / torch.sum(weights, -1, keepdim=True) # (N_rays, N_samples), cumulative distribution function cdf = torch.cumsum(pdf, -1) # (N_rays, N_samples_+1) cdf = torch.cat([torch.zeros_like(cdf[:, :1]), cdf], -1) # padded to 0~1 inclusive if deterministic: u = torch.linspace(0, 1, n_importance, device=bins.device) u = u.expand(N_rays, n_importance) else: u = torch.rand(N_rays, n_importance, device=bins.device) u = u.contiguous() inds = torch.searchsorted(cdf, u, right=True) below = torch.clamp_min(inds - 1, 0) above = torch.clamp_max(inds, N_samples_) inds_sampled = torch.stack([below, above], -1).view(N_rays, 2 * n_importance) cdf_g = torch.gather(cdf, 1, inds_sampled).view(N_rays, n_importance, 2) bins_g = torch.gather(bins, 1, inds_sampled).view(N_rays, n_importance, 2) denom = cdf_g[..., 1] - cdf_g[..., 0] # denom equals 0 means a bin has weight 0, in which case it will not # be sampled anyway, therefore any value for it is fine (set to 1 here) denom[denom < eps] = 1 t = (u - cdf_g[..., 0]) / denom samples = bins_g[..., 0] + t * (bins_g[..., 1] - bins_g[..., 0]) return samples def linspace_batch(start: torch.Tensor, stop: torch.Tensor, num: int) -> torch.Tensor: """Creates a tensor of shape [num, *start.shape] whose values are evenly spaced from start to end, inclusive. Replicates but the multi-dimensional behaviour of numpy.linspace in PyTorch. Args: start (torch.Tensor): The start point of each ray. Shape like (bz, res, res, 1). stop (torch.Tensor): The end point of each ray. Shape like (bz, res, res, 1). num (int): The number of points to sample. Returns: torch.Tensor: The sampled points. Shape like (num, bz, res, res, 1) """ # create a tensor of 'num' steps from 0 to 1 steps = torch.arange( num, dtype=torch.float32, device=start.device) / ( num - 1) # reshape the 'steps' tensor to [-1, *([1]*start.ndim)] to allow for # broadcastings # - using 'steps.reshape([-1, *([1]*start.ndim)])' would be nice here but # torchscript cannot statically infer the expected size of a list in this # context, hence the code below for i in range(start.ndim): steps = steps.unsqueeze(-1) # the output starts at 'start' and increments until 'stop' in # each dimension out = start[None] + steps * (stop - start)[None] return out ================================================ FILE: mmagic/models/editors/eg3d/ray_sampler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Tuple import torch def sample_rays(cam2world: torch.Tensor, intrinsics: torch.Tensor, resolution: int) -> Tuple[torch.Tensor]: """Sample origin and direction vectors of rays with passed camera-to-world matrix and intrinsics matrix. Noted that skew coefficient is not considered in this function. Args: cam2world (torch.Tensor): The camera-to-world matrix in homogeneous coordinates. Shape like (bz, 4, 4). intrinsics (torch.Tensor): The intrinsic matrix. Shape like (bz, 3, 3). resolution (int): The expect resolution of the render output. Returns: Tuple[torch.Tensor]: Origins and view directions for rays. Both shape like (bz, resolution^2, 3) """ batch_size, n_points = cam2world.shape[0], resolution**2 cam_in_world = cam2world[:, :3, 3] fx = intrinsics[:, 0, 0] fy = intrinsics[:, 1, 1] cx = intrinsics[:, 0, 2] cy = intrinsics[:, 1, 2] device = cam2world.device # torch.meshgrid has been modified in 1.10.0 (compatibility with previous # versions), and will be further modified in 1.12 (Breaking Change) if 'indexing' in torch.meshgrid.__code__.co_varnames: u, v = torch.meshgrid( torch.arange(resolution, dtype=torch.float32, device=device), torch.arange(resolution, dtype=torch.float32, device=device), indexing='ij') else: u, v = torch.meshgrid( torch.arange(resolution, dtype=torch.float32, device=device), torch.arange(resolution, dtype=torch.float32, device=device)) uv = torch.stack([u, v]) uv = uv * (1. / resolution) + (0.5 / resolution) uv = uv.flip(0).reshape(2, -1).transpose(1, 0) uv = uv.unsqueeze(0).repeat(cam2world.shape[0], 1, 1) x_cam = uv[:, :, 0].view(batch_size, -1) y_cam = uv[:, :, 1].view(batch_size, -1) z_cam = torch.ones((batch_size, n_points), device=cam2world.device) x_lift = (x_cam - cx.unsqueeze(-1)) / fx.unsqueeze(-1) * z_cam y_lift = (y_cam - cy.unsqueeze(-1)) / fy.unsqueeze(-1) * z_cam points_in_cam = torch.stack( (x_lift, y_lift, z_cam, torch.ones_like(z_cam)), dim=-1) # camera coordinate to world coordinate points_in_world = torch.bmm(cam2world, points_in_cam.permute(0, 2, 1)) points_in_world = points_in_world.permute(0, 2, 1)[:, :, :3] ray_dirs = points_in_world - cam_in_world[:, None, :] ray_dirs = torch.nn.functional.normalize(ray_dirs, dim=2) ray_origins = cam_in_world.unsqueeze(1).repeat(1, ray_dirs.shape[1], 1) return ray_origins, ray_dirs ================================================ FILE: mmagic/models/editors/eg3d/renderer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """The renderer is a module that takes in rays, decides where to sample along each ray, and computes pixel colors using the volume rendering equation.""" from typing import Any, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from ..stylegan3.stylegan3_modules import FullyConnectedLayer from .eg3d_utils import (get_ray_limits_box, inverse_transform_sampling, linspace_batch) class EG3DRenderer(BaseModule): """Renderer for EG3D. This class samples render points on each input ray and interpolate the triplane feature corresponding to the points' coordinates. Then, predict each point's RGB feature and density (sigma) by a neural network and calculate the RGB feature of each ray by integration. Different from typical NeRF models, the decoder of EG3DRenderer takes triplane feature of each points as input instead of positional encoding of the coordinates. Args: decoder_cfg (dict): The config to build neural renderer. ray_start (float): The start position of all rays. ray_end (float): The end position of all rays. box_warp (float): The side length of the cube spanned by the triplanes. The box is axis-aligned, centered at the origin. The range of each axis is `[-box_warp/2, box_warp/2]`. If `box_warp=1.8`, it has vertices at the range of axis is `[-0.9, 0.9]`. Defaults to 1. depth_resolution (int): Resolution of depth, as well as the number of points per ray. Defaults to 64. depth_resolution_importance (int): Resolution of depth in hierarchical sampling. Defaults to 64. clamp_mode (str): The clamp mode for density predicted by neural renderer. Defaults to 'softplus'. white_back (bool): Whether render a white background. Defaults to True. projection_mode (str): The projection method to mapping coordinates of render points to plane feature. The usage of this argument please refer to :meth:`self.project_onto_planes` and https://github.com/NVlabs/eg3d/issues/67. Defaults to 'Official'. """ def __init__(self, decoder_cfg: dict, ray_start: float, ray_end: float, box_warp: float = 1, depth_resolution: int = 64, depth_resolution_importance: int = 64, density_noise: float = 0, clamp_mode: str = 'softplus', white_back: bool = True, projection_mode: str = 'Official'): super().__init__() self.decoder = EG3DDecoder(**decoder_cfg) self.ray_start = ray_start self.ray_end = ray_end self.box_warp = box_warp self.depth_resolution = depth_resolution self.depth_resolution_importance = depth_resolution_importance self.density_noise = density_noise self.clamp_mode = clamp_mode self.white_back = white_back self.projection_mode = projection_mode def get_value(self, target: str, render_kwargs: Optional[dict] = None) -> Any: """Get value of target field. Args: target (str): The key of the target field. render_kwargs (Optional[dict], optional): The input key word arguments dict. Defaults to None. Returns: Any: The default value of target field. """ if render_kwargs is None: return getattr(self, target) return render_kwargs.get(target, getattr(self, target)) def forward(self, planes: torch.Tensor, ray_origins: torch.Tensor, ray_directions: torch.Tensor, render_kwargs: Optional[dict] = None) -> Tuple[torch.Tensor]: """Render 2D RGB feature, weighed depth and weights with the passed triplane features and rays. 'weights' denotes `w` in Equation 5 of the NeRF's paper. Args: planes (torch.Tensor): The triplane features shape like (bz, 3, TriPlane_feat, TriPlane_res, TriPlane_res). ray_origins (torch.Tensor): The original of each ray to render, shape like (bz, NeRF_res * NeRF_res, 3). ray_directions (torch.Tensor): The direction vector of each ray to render, shape like (bz, NeRF_res * NeRF_res, 3). render_kwargs (Optional[dict], optional): The specific kwargs for rendering. Defaults to None. Returns: Tuple[torch.Tensor]: Renderer RGB feature, weighted depths and weights. """ ray_start = self.get_value('ray_start', render_kwargs) ray_end = self.get_value('ray_end', render_kwargs) box_warp = self.get_value('box_warp', render_kwargs) depth_resolution = self.get_value('depth_resolution', render_kwargs) depth_resolution_importance = self.get_value( 'depth_resolution_importance', render_kwargs) density_noise = self.get_value('density_noise', render_kwargs) if ray_start == ray_end == 'auto': ray_start, ray_end = get_ray_limits_box( ray_origins, ray_directions, box_side_length=box_warp) is_ray_valid = ray_end > ray_start if torch.any(is_ray_valid).item(): ray_start[~is_ray_valid] = ray_start[is_ray_valid].min() ray_end[~is_ray_valid] = ray_start[is_ray_valid].max() depths_coarse = self.sample_stratified(ray_origins, ray_start, ray_end, depth_resolution) else: assert (isinstance(ray_start, float) and isinstance( ray_end, float)), ( '\'ray_start\' and \'ray_end\' must be both float type or ' f'both \'auto\'. But receive {ray_start} and {ray_end}.') assert ray_start < ray_end, ( '\'ray_start\' must less than \'ray_end\'.') # Create stratified depth samples depths_coarse = self.sample_stratified(ray_origins, ray_start, ray_end, depth_resolution) batch_size, num_rays, samples_per_ray, _ = depths_coarse.shape # Coarse Pass sample_coordinates = ( ray_origins.unsqueeze(-2) + depths_coarse * ray_directions.unsqueeze(-2)).reshape( batch_size, -1, 3) out = self.neural_rendering(planes, sample_coordinates, density_noise, box_warp) colors_coarse = out['rgb'] densities_coarse = out['sigma'] colors_coarse = colors_coarse.reshape(batch_size, num_rays, samples_per_ray, colors_coarse.shape[-1]) densities_coarse = densities_coarse.reshape(batch_size, num_rays, samples_per_ray, 1) # Fine Pass N_importance = depth_resolution_importance if N_importance is not None and N_importance > 0: _, _, weights = self.volume_rendering(colors_coarse, densities_coarse, depths_coarse) depths_fine = self.sample_importance(depths_coarse, weights, N_importance) sample_coordinates = ( ray_origins.unsqueeze(-2) + depths_fine * ray_directions.unsqueeze(-2)).reshape( batch_size, -1, 3) out = self.neural_rendering(planes, sample_coordinates, density_noise, box_warp) colors_fine = out['rgb'] densities_fine = out['sigma'] colors_fine = colors_fine.reshape(batch_size, num_rays, N_importance, colors_fine.shape[-1]) densities_fine = densities_fine.reshape(batch_size, num_rays, N_importance, 1) all_depths, all_colors, all_densities = self.unify_samples( depths_coarse, colors_coarse, densities_coarse, depths_fine, colors_fine, densities_fine) # Aggregate rgb_final, depth_final, weights = self.volume_rendering( all_colors, all_densities, all_depths) else: rgb_final, depth_final, weights = self.volume_rendering( colors_coarse, densities_coarse, depths_coarse) return rgb_final, depth_final, weights.sum(2) def sample_stratified(self, ray_origins: torch.Tensor, ray_start: Union[float, torch.Tensor], ray_end: Union[float, torch.Tensor], depth_resolution: int) -> torch.Tensor: """Return depths of approximately uniformly spaced samples along rays. Args: ray_origins (torch.Tensor): The original of each ray, shape like (bz, NeRF_res * NeRF_res, 3). Only used to provide device and shape info. ray_start (Union[float, torch.Tensor]): The start position of rays. If a float is passed, all rays will have the same start distance. ray_end (Union[float, torch.Tensor]): The end position of rays. If a float is passed, all rays will have the same end distance. depth_resolution (int): Resolution of depth, as well as the number of points per ray. Returns: torch.Tensor: The sampled coarse depth shape like (bz, NeRF_res * NeRF_res, 1). """ N, M, _ = ray_origins.shape if isinstance(ray_start, torch.Tensor): # perform linspace for batch of tensor depths_coarse = linspace_batch(ray_start, ray_end, depth_resolution) depths_coarse = depths_coarse.permute(1, 2, 0, 3) depth_delta = (ray_end - ray_start) / (depth_resolution - 1) depths_coarse += torch.rand_like(depths_coarse) * depth_delta[..., None] else: depths_coarse = torch.linspace( ray_start, ray_end, depth_resolution, device=ray_origins.device) depths_coarse = depths_coarse.reshape(1, 1, depth_resolution, 1) depths_coarse = depths_coarse.repeat(N, M, 1, 1) depth_delta = (ray_end - ray_start) / (depth_resolution - 1) depths_coarse += torch.rand_like(depths_coarse) * depth_delta return depths_coarse def neural_rendering(self, planes: torch.Tensor, sample_coordinates: float, density_noise: float, box_warp: float) -> dict: """Predict RGB features and densities of the coordinates by neural renderer model and the triplane input. Args: planes (torch.Tensor): Triplane feature shape like (bz, 3, TriPlane_feat, TriPlane_res, TriPlane_res). sample_coordinates (torch.Tensor): Coordinates of the sampling points, shape like (bz, N_depth * NeRF_res * NeRF_res, 1). density_noise (float): Strength of noise add to the predicted density. box_warp (float): The side length of the cube spanned by the triplanes. Returns: dict: A dict contains RGB features ('rgb') and densities ('sigma'). """ sampled_features = self.sample_from_planes( planes, sample_coordinates, box_warp=box_warp) out = self.decoder(sampled_features) if density_noise > 0: out['sigma'] += torch.randn_like(out['sigma']) * density_noise return out def sample_from_planes(self, plane_features: torch.Tensor, coordinates: torch.Tensor, interp_mode: str = 'bilinear', box_warp: float = None) -> torch.Tensor: """Sample from feature from triplane feature with the passed coordinates of render points. Args: plane_features (torch.Tensor): The triplane feature. coordinates (torch.Tensor): The coordinates of points to render. interp_mode (str): The interpolation mode to sample feature from triplane. box_warp (float): The side length of the cube spanned by the triplanes. Returns: torch.Tensor: The sampled triplane feature of the render points. """ N, n_planes, C, H, W = plane_features.shape _, M, _ = coordinates.shape plane_features = plane_features.view(N * n_planes, C, H, W) coordinates = (2 / box_warp) * coordinates # NOTE: do not support change projection_mode for specific renderer, # use self.projection_mode projected_coordinates = self.project_onto_planes(coordinates) projected_coordinates = projected_coordinates[:, None, ...] output_features = torch.nn.functional.grid_sample( plane_features, projected_coordinates.float(), mode=interp_mode, padding_mode='zeros', align_corners=False) output_features = output_features.permute(0, 3, 2, 1).reshape( N, n_planes, M, C) return output_features def project_onto_planes(self, coordinates: torch.Tensor) -> torch.Tensor: """Project 3D points to plane formed by coordinate axes. In this function, we use indexing operation to replace matrix multiplication to achieve higher calculation performance. In the original implementation, the mapping matrix is incorrect. Therefore we support users to define `projection_mode` to control projection behavior in the initialization function of :class:`~EG3DRenderer`. If you want to run inference with the official pretrained model, please remember to set `projection_mode = 'official'`. More information please refer to https://github.com/NVlabs/eg3d/issues/67. If the project mode `official`, the equivalent projection matrix is inverse matrix of: [[[1, 0, 0], [0, 1, 0], [0, 0, 1]], [[1, 0, 0], [0, 0, 1], [0, 1, 0]], [[0, 0, 1], [1, 0, 0], [0, 1, 0]]] Otherwise, the equivalent projection matrix is inverse matrix of: [[[1, 0, 0], [0, 1, 0], [0, 0, 1]], [[1, 0, 0], [0, 0, 1], [0, 1, 0]], [[0, 0, 1], [0, 1, 0], [1, 0, 0]]] Args: coordinates (torch.Tensor): The coordinates of the render points. shape like (bz, NeRF_res * NeRF_res * N_depth, 3). Returns: torch.Tensor: The projected coordinates. """ N, _, _ = coordinates.shape xy_coord = coordinates[:, :, (0, 1)] # (bz, N_points, 3) xz_coord = coordinates[:, :, (0, 2)] # (bz, N_points, 3) if self.projection_mode.upper() == 'OFFICIAL': yz_coord = coordinates[:, :, (2, 0)] # actually zx_coord else: yz_coord = coordinates[:, :, (2, 1)] coord_proejcted = torch.cat([xy_coord, xz_coord, yz_coord], dim=0) # create a index list to release the following remapping: # [xy, xy, ..., xz, xz, ..., yz, yz, ...] -> [xy, xz, yz, ...] index = [] for n in range(N): index += [n, N + n, N * 2 + n] return coord_proejcted[index, ...] def unify_samples(self, depths_c: torch.Tensor, colors_c: torch.Tensor, densities_c: torch.Tensor, depths_f: torch.Tensor, colors_f: torch.Tensor, densities_f: torch.Tensor) -> Tuple[torch.Tensor]: """Sort and merge coarse samples and fine samples. Args: depths_c (torch.Tensor): Coarse depths shape like (bz, NeRF_res * NeRF_res, N_depth, 1). colors_c (torch.Tensor): Coarse color features shape like (bz, NeRF_res * NeRF_res, N_depth, N_feat). densities_c (torch.Tensor): Coarse densities shape like (bz, NeRF_res * NeRF_res, N_depth, 1). depths_f (torch.Tensor): Fine depths shape like (bz, NeRF_res * NeRF_res, N_depth_fine, 1). colors_f (torch.Tensor): Fine colors features shape like (bz, NeRF_res * NeRF_res, N_depth_fine, N_feat). densities_f (torch.Tensor): Fine densities shape like (bz, NeRF_res * NeRF_res, N_depth_fine, 1). Returns: Tuple[torch.Tensor]: Unified depths, color features and densities. The third dimension of returns are `N_depth + N_depth_fine`. """ all_depths = torch.cat([depths_c, depths_f], dim=-2) all_colors = torch.cat([colors_c, colors_f], dim=-2) all_densities = torch.cat([densities_c, densities_f], dim=-2) _, indices = torch.sort(all_depths, dim=-2) all_depths = torch.gather(all_depths, -2, indices) all_colors = torch.gather( all_colors, -2, indices.expand(-1, -1, -1, all_colors.shape[-1])) all_densities = torch.gather(all_densities, -2, indices.expand(-1, -1, -1, 1)) return all_depths, all_colors, all_densities def volume_rendering(self, colors: torch.Tensor, densities: torch.Tensor, depths: torch.Tensor) -> Tuple[torch.Tensor]: """Volume rendering. Args: colors (torch.Tensor): Color feature for each points. Shape like (bz, N_points, N_depth, N_feature). densities (torch.Tensor): Density for each points. Shape like (bz, N_points, N_depth, 1). depths (torch.Tensor): Depths for each points. Shape like (bz, N_points, N_depth, 1). Returns: Tuple[torch.Tensor]: A tuple of color feature `(bz, N_points, N_feature)`, weighted depth `(bz, N_points, 1)` and weight `(bz, N_points, N_depth-1, 1)`. """ deltas = depths[:, :, 1:] - depths[:, :, :-1] colors_mid = (colors[:, :, :-1] + colors[:, :, 1:]) / 2 densities_mid = (densities[:, :, :-1] + densities[:, :, 1:]) / 2 depths_mid = (depths[:, :, :-1] + depths[:, :, 1:]) / 2 if self.clamp_mode == 'softplus': # activation bias of -1 makes things initialize better densities_mid = F.softplus(densities_mid - 1) else: assert False, ( 'EG3DRenderer only supports \'softplus\' for \'clamp_mode\', ' f'but receive \'{self.clamp_mode}\'.') density_delta = densities_mid * deltas alpha = 1 - torch.exp(-density_delta) alpha_shifted = torch.cat( [torch.ones_like(alpha[:, :, :1]), 1 - alpha + 1e-10], -2) weights = alpha * torch.cumprod(alpha_shifted, -2)[:, :, :-1] composite_rgb = torch.sum(weights * colors_mid, -2) weight_total = weights.sum(2) composite_depth = torch.sum(weights * depths_mid, -2) / weight_total # clip the composite to min/max range of depths if digit_version(TORCH_VERSION) < digit_version('1.8.0'): composite_depth[torch.isnan(composite_depth)] = float('inf') else: composite_depth = torch.nan_to_num(composite_depth, float('inf')) composite_depth = torch.clamp(composite_depth, torch.min(depths), torch.max(depths)) if self.white_back: composite_rgb = composite_rgb + 1 - weight_total composite_rgb = composite_rgb * 2 - 1 # Scale to (-1, 1) return composite_rgb, composite_depth, weights @torch.no_grad() def sample_importance(self, z_vals: torch.Tensor, weights: torch.Tensor, N_importance: int) -> torch.Tensor: """Return depths of importance sampled points along rays. Args: z_vals (torch.Tensor): Coarse Z value (depth). Shape like (bz, N_points, N_depth, N_feature). weights (torch.Tensor): Weights of the coarse samples. Shape like (bz, N_points, N_depths-1, 1). N_importance (int): Number of samples to resample. """ batch_size, num_rays, samples_per_ray, _ = z_vals.shape z_vals = z_vals.reshape(batch_size * num_rays, samples_per_ray) # -1 to account for loss of 1 sample in MipRayMarcher weights = weights.reshape(batch_size * num_rays, -1) # smooth weights as MipNeRF # max(weights[:-1], weights[1:]) weights = F.max_pool1d(weights.unsqueeze(1).float(), 2, 1, padding=1) # 0.5 * (weights[:-1] + weights[1:]) weights = F.avg_pool1d(weights, 2, 1).squeeze() weights = weights + 0.01 # add resampling padding z_vals_mid = 0.5 * (z_vals[:, :-1] + z_vals[:, 1:]) importance_z_vals = inverse_transform_sampling(z_vals_mid, weights[:, 1:-1], N_importance).detach() importance_z_vals = importance_z_vals.reshape(batch_size, num_rays, N_importance, 1) return importance_z_vals class EG3DDecoder(BaseModule): """Decoder for EG3D model. Args: in_channels (int): The number of input channels. out_channels (int): The number of output channels. Defaults to 32. hidden_channels (int): The number of channels of hidden layer. Defaults to 64. lr_multiplier (float, optional): Equalized learning rate multiplier. Defaults to 1. rgb_padding (float): Padding for RGB output. Defaults to 0.001. """ def __init__(self, in_channels: int, out_channels: int = 32, hidden_channels: int = 64, lr_multiplier: float = 1, rgb_padding: float = 0.001): super().__init__() self.net = nn.Sequential( FullyConnectedLayer( in_channels, hidden_channels, lr_multiplier=lr_multiplier), nn.Softplus(), FullyConnectedLayer( hidden_channels, 1 + out_channels, lr_multiplier=lr_multiplier)) self.rgb_padding = rgb_padding def forward(self, sampled_features: torch.Tensor) -> dict: """Forward function. Args: sampled_features (torch.Tensor): The sampled triplane feature for each points. Shape like (batch_size, xxx, xxx, n_ch). Returns: dict: A dict contains rgb feature and sigma value for each point. """ sampled_features = sampled_features.mean(1) N, M, C = sampled_features.shape feat = sampled_features.view(-1, C) feat = self.net(feat) feat = feat.view(N, M, -1) rgb = torch.sigmoid( feat[..., 1:]) * (1 + 2 * self.rgb_padding) - self.rgb_padding sigma = feat[..., 0:1] return {'rgb': rgb, 'sigma': sigma} ================================================ FILE: mmagic/models/editors/esrgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .esrgan import ESRGAN from .rrdb_net import RRDBNet __all__ = [ 'ESRGAN', 'RRDBNet', ] ================================================ FILE: mmagic/models/editors/esrgan/esrgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from ..srgan import SRGAN @MODELS.register_module() class ESRGAN(SRGAN): """Enhanced SRGAN model for single image super-resolution. Ref: ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks. It uses RaGAN for GAN updates: The relativistic discriminator: a key element missing from standard GAN. Args: generator (dict): Config for the generator. discriminator (dict): Config for the discriminator. Default: None. gan_loss (dict): Config for the gan loss. Note that the loss weight in gan loss is only for the generator. pixel_loss (dict): Config for the pixel loss. Default: None. perceptual_loss (dict): Config for the perceptual loss. Default: None. train_cfg (dict): Config for training. Default: None. You may change the training of gan by setting: `disc_steps`: how many discriminator updates after one generate update; `disc_init_steps`: how many discriminator updates at the start of the training. These two keys are useful when training with WGAN. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. """ def g_step(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ losses = dict() # pix loss if self.pixel_loss: losses['loss_pix'] = self.pixel_loss(batch_outputs, batch_gt_data) # perceptual loss if self.perceptual_loss: loss_percep, loss_style = self.perceptual_loss( batch_outputs, batch_gt_data) if loss_percep is not None: losses['loss_perceptual'] = loss_percep if loss_style is not None: losses['loss_style'] = loss_style # gan loss for generator if self.gan_loss and self.discriminator: real_d_pred = self.discriminator(batch_gt_data).detach() fake_g_pred = self.discriminator(batch_outputs) loss_gan_fake = self.gan_loss( fake_g_pred - torch.mean(real_d_pred), target_is_real=True, is_disc=False) loss_gan_real = self.gan_loss( real_d_pred - torch.mean(fake_g_pred), target_is_real=False, is_disc=False) losses['loss_gan'] = (loss_gan_fake + loss_gan_real) / 2 return losses def d_step_real(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor): """D step of real data. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ # real fake_d_pred = self.discriminator(batch_outputs) real_d_pred = self.discriminator(batch_gt_data) loss_d_real = self.gan_loss( real_d_pred - torch.mean(fake_d_pred.detach()), target_is_real=True, is_disc=True ) * 0.5 # 0.5 for averaging loss_d_real and loss_d_fake self.real_d_pred = torch.mean(real_d_pred.detach()) # for d_step_fake return loss_d_real def d_step_fake(self, batch_outputs: torch.Tensor, batch_gt_data): """D step of fake data. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ # fake fake_d_pred = self.discriminator(batch_outputs.detach()) loss_d_fake = self.gan_loss( fake_d_pred - self.real_d_pred, target_is_real=False, is_disc=True ) * 0.5 # 0.5 for averaging loss_d_real and loss_d_fake return loss_d_fake ================================================ FILE: mmagic/models/editors/esrgan/rrdb_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.models.archs import pixel_unshuffle from mmagic.models.utils import default_init_weights, make_layer from mmagic.registry import MODELS @MODELS.register_module() class RRDBNet(BaseModule): """Networks consisting of Residual in Residual Dense Block, which is used in ESRGAN and Real-ESRGAN. ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks. Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data. # noqa: E501 Currently, it supports [x1/x2/x4] upsampling scale factor. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64 num_blocks (int): Block number in the trunk network. Defaults: 23 growth_channels (int): Channels for each growth. Default: 32. upscale_factor (int): Upsampling factor. Support x1, x2 and x4. Default: 4. init_cfg (dict, optional): Initialization config dict. Default: None. """ _supported_upscale_factors = [1, 2, 4] def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=23, growth_channels=32, upscale_factor=4, init_cfg=None): super().__init__(init_cfg=init_cfg) if upscale_factor in self._supported_upscale_factors: in_channels = in_channels * ((4 // upscale_factor)**2) else: raise ValueError(f'Unsupported scale factor {upscale_factor}. ' f'Currently supported ones are ' f'{self._supported_upscale_factors}.') self.upscale_factor = upscale_factor self.conv_first = nn.Conv2d(in_channels, mid_channels, 3, 1, 1) self.body = make_layer( RRDB, num_blocks, mid_channels=mid_channels, growth_channels=growth_channels) self.conv_body = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) # upsample self.conv_up1 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) self.conv_up2 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) self.conv_hr = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) self.conv_last = nn.Conv2d(mid_channels, out_channels, 3, 1, 1) self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.upscale_factor in [1, 2]: feat = pixel_unshuffle(x, scale=4 // self.upscale_factor) else: feat = x feat = self.conv_first(feat) body_feat = self.conv_body(self.body(feat)) feat = feat + body_feat # upsample feat = self.lrelu( self.conv_up1(F.interpolate(feat, scale_factor=2, mode='nearest'))) feat = self.lrelu( self.conv_up2(F.interpolate(feat, scale_factor=2, mode='nearest'))) out = self.conv_last(self.lrelu(self.conv_hr(feat))) return out def init_weights(self): """Init weights for models.""" if self.init_cfg: super().init_weights() else: # Use smaller std for better stability and performance. We # use 0.1. See more details in "ESRGAN: Enhanced Super-Resolution # Generative Adversarial Networks" for m in [ self.conv_first, self.conv_body, self.conv_up1, self.conv_up2, self.conv_hr, self.conv_last ]: default_init_weights(m, 0.1) class ResidualDenseBlock(nn.Module): """Residual Dense Block. Used in RRDB block in ESRGAN. Args: mid_channels (int): Channel number of intermediate features. Default: 64. growth_channels (int): Channels for each growth. Default: 32. """ def __init__(self, mid_channels=64, growth_channels=32): super().__init__() for i in range(5): out_channels = mid_channels if i == 4 else growth_channels self.add_module( f'conv{i+1}', nn.Conv2d(mid_channels + i * growth_channels, out_channels, 3, 1, 1)) self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) self.init_weights() def init_weights(self): """Init weights for ResidualDenseBlock. Use smaller std for better stability and performance. We empirically use 0.1. See more details in "ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks" """ for i in range(5): default_init_weights(getattr(self, f'conv{i+1}'), 0.1) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x1 = self.lrelu(self.conv1(x)) x2 = self.lrelu(self.conv2(torch.cat((x, x1), 1))) x3 = self.lrelu(self.conv3(torch.cat((x, x1, x2), 1))) x4 = self.lrelu(self.conv4(torch.cat((x, x1, x2, x3), 1))) x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1)) # Empirically, we use 0.2 to scale the residual for better performance return x5 * 0.2 + x class RRDB(nn.Module): """Residual in Residual Dense Block. Used in RRDB-Net in ESRGAN. Args: mid_channels (int): Channel number of intermediate features. growth_channels (int): Channels for each growth. Default: 32. """ def __init__(self, mid_channels, growth_channels=32): super().__init__() self.rdb1 = ResidualDenseBlock(mid_channels, growth_channels) self.rdb2 = ResidualDenseBlock(mid_channels, growth_channels) self.rdb3 = ResidualDenseBlock(mid_channels, growth_channels) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = self.rdb1(x) out = self.rdb2(out) out = self.rdb3(out) # Empirically, we use 0.2 to scale the residual for better performance return out * 0.2 + x ================================================ FILE: mmagic/models/editors/fastcomposer/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .fastcomposer import FastComposer __all__ = ['FastComposer'] ================================================ FILE: mmagic/models/editors/fastcomposer/fastcomposer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from collections import OrderedDict from typing import Any, Callable, Dict, List, Optional, Union import numpy as np import torch from PIL import Image from torch import nn from torch.hub import load_state_dict_from_url from tqdm import tqdm from transformers import CLIPTokenizer from mmagic.registry import MODELS from ..stable_diffusion import StableDiffusion from .fastcomposer_util import FastComposerModel, get_object_transforms ModelType = Union[Dict, nn.Module] @MODELS.register_module() class FastComposer(StableDiffusion): def __init__(self, pretrained_cfg: dict, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: str = 'fp32', enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor=dict(type='DataPreprocessor'), init_cfg: Optional[dict] = None): super().__init__(vae, text_encoder, tokenizer, unet, scheduler, test_scheduler, dtype, enable_xformers, noise_offset_weight, tomesd_cfg, data_preprocessor, init_cfg) self.vae = self.vae.model self.unet = self.unet.model model = FastComposerModel.from_pretrained(pretrained_cfg, self.vae, self.unet) if pretrained_cfg['finetuned_model_path'][:7] == 'http://' or \ pretrained_cfg['finetuned_model_path'][:8] == 'https://': model.load_state_dict( load_state_dict_from_url( pretrained_cfg['finetuned_model_path'], map_location='cpu'), strict=False) elif pretrained_cfg['finetuned_model_path']: model.load_state_dict( torch.load( pretrained_cfg['finetuned_model_path'], map_location='cpu'), strict=False) weight_dtype = torch.float32 if dtype == 'fp16': weight_dtype = torch.float16 elif dtype == 'bf16': weight_dtype = torch.bfloat16 model = model.to(weight_dtype) self.unet = model.unet if pretrained_cfg['enable_xformers_memory_efficient_attention']: self.unet.enable_xformers_memory_efficient_attention() self.text_encoder = model.text_encoder self.image_encoder = model.image_encoder self.postfuse_module = model.postfuse_module del model self.special_tokenizer = CLIPTokenizer.from_pretrained( pretrained_cfg['pretrained_model_name_or_path'], subfolder='tokenizer', revision=pretrained_cfg['revision'], ) self.special_tokenizer.add_tokens(['img'], special_tokens=True) self.image_token_id = self.special_tokenizer.convert_tokens_to_ids( 'img') self.object_transforms = get_object_transforms(pretrained_cfg) @torch.no_grad() def _tokenize_and_mask_noun_phrases_ends(self, caption): """Augment the text embedding.""" input_ids = self.special_tokenizer.encode(caption) noun_phrase_end_mask = [False for _ in input_ids] clean_input_ids = [] clean_index = 0 for i, id in enumerate(input_ids): if id == self.image_token_id: noun_phrase_end_mask[clean_index - 1] = True else: clean_input_ids.append(id) clean_index += 1 max_len = self.special_tokenizer.model_max_length if len(clean_input_ids) > max_len: clean_input_ids = clean_input_ids[:max_len] else: clean_input_ids = clean_input_ids + [ self.tokenizer.pad_token_id ] * ( max_len - len(clean_input_ids)) if len(noun_phrase_end_mask) > max_len: noun_phrase_end_mask = noun_phrase_end_mask[:max_len] else: noun_phrase_end_mask = noun_phrase_end_mask + [False] * ( max_len - len(noun_phrase_end_mask)) clean_input_ids = torch.tensor(clean_input_ids, dtype=torch.long) noun_phrase_end_mask = torch.tensor( noun_phrase_end_mask, dtype=torch.bool) return clean_input_ids.unsqueeze(0), noun_phrase_end_mask.unsqueeze(0) @torch.no_grad() def _encode_augmented_prompt(self, prompt: str, reference_images: List[Image.Image], device: torch.device, weight_dtype: torch.dtype): """Encode reference images. Args: prompt (str or list(int)): prompt to be encoded. reference_images: (List[Image.Image]): List of reference images. device (torch.device):torch device. weight_dtype (torch.dtype): torch.dtype. Returns: text_embeddings (torch.Tensor): text embeddings generated by clip text encoder. """ # TODO: check this object_pixel_values = [] for image in reference_images: image_tensor = torch.from_numpy(np.array( image.convert('RGB'))).permute(2, 0, 1) image = self.object_transforms(image_tensor) object_pixel_values.append(image) object_pixel_values = torch.stack( object_pixel_values, dim=0).to(memory_format=torch.contiguous_format).float() object_pixel_values = object_pixel_values.unsqueeze(0).to( dtype=weight_dtype, device=device) object_embeds = self.image_encoder(object_pixel_values) id_and_mask = self._tokenize_and_mask_noun_phrases_ends(prompt) input_ids, image_token_mask = id_and_mask input_ids, image_token_mask = input_ids.to( device), image_token_mask.to(device) num_objects = image_token_mask.sum(dim=1) augmented_prompt_embeds = self.postfuse_module( self.text_encoder(input_ids)[0], object_embeds, image_token_mask, num_objects) return augmented_prompt_embeds @torch.no_grad() def infer(self, prompt: Union[str, List[str]] = None, height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, latents: Optional[torch.FloatTensor] = None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, output_type: Optional[str] = 'pil', return_dict: bool = True, callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None, callback_steps: int = 1, cross_attention_kwargs: Optional[Dict[str, Any]] = None, alpha_: float = 0.7, reference_subject_images: List[Image.Image] = None, augmented_prompt_embeds: Optional[torch.FloatTensor] = None, show_progress: bool = True): r""" Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`. instead. height (`int`, *optional*): defaults to self.unet.config.sample_size * self.vae_scale_factor The height in pixels of the generated image. width (`int`, *optional*): defaults to self.unet.config.sample_size * self.vae_scale_factor The width in pixels of the generated image. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance] (https://arxiv.org/abs/2207.12598). `guidance_scale` is defined as `w` of equation 2. of [Imagen Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale > 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`, usually at the expense of lower image quality. negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. If not defined, one has to pass `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator` or `List[torch.Generator]`, *optional*): One or a list of [torch generator(s)](https://pytorch.org/ docs/stable/generated/torch.Generator.html) to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will ge generated by sampling using the supplied random `generator`. prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, text embeddings will be generated from `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input argument. output_type (`str`, *optional*, defaults to `"pil"`): The output format of the generate image. Choose between [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a plain tuple. callback (`Callable`, *optional*): A function that will be called every `callback_steps` steps during inference. The function will be called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`. callback_steps (`int`, *optional*, defaults to 1): The frequency at which the `callback` function will be called. If not specified, the callback will be called at every step. cross_attention_kwargs (`dict`, *optional*): A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under `self.processor` in [diffusers.cross_attention](https://github.com/huggingface/ diffusers/blob/main/src/diffusers/models/cross_attention.py). alpha_ (`float`, defaults to 0.7): The ratio of subject conditioning. If `alpha_` is 0.7, the beginning 30% of denoising steps use text prompts, while the last 70% utilize image-augmented prompts. Increase alpha for identity preservation, decrease it for prompt consistency. reference_subject_images (`List[PIL.Image.Image]`): a list of PIL images that are used as reference subjects. The number of images should be equal to the number of augmented tokens in the prompts. augmented_prompt_embeds: (`torch.FloatTensor`, *optional*): Pre-generated image augmented text embeddings. If not provided, embeddings will be generated from `prompt` and `reference_subject_images`. show_progress: ('bool'): show progress or not. Examples: Returns: `OrderedDict` or `tuple`: `OrderedDict` if `return_dict` is True, otherwise a `tuple. When returning a tuple, the first element is a list with the generated images, and the second element is a list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work" (nsfw) content, according to the `safety_checker`. """ # 0. Default height and width to unet height = height or self.unet.config.sample_size * self.vae_scale_factor width = width or self.unet.config.sample_size * self.vae_scale_factor # 1. Check inputs. Raise error if not correct self.check_inputs( prompt, height, width, ) assert_text = 'Prompt and reference subject images or prompt_embeds ' \ 'and augmented_prompt_embeds must be provided.' assert (prompt and reference_subject_images) or \ (prompt_embeds and augmented_prompt_embeds), assert_text # 2. Define call parameters if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] device = self.device # here `guidance_scale` is defined analog to # the guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 assert do_classifier_free_guidance # 3. Encode input prompt prompt_text_only = prompt.replace('img', '') prompt_embeds = self._encode_prompt(prompt_text_only, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) if augmented_prompt_embeds is None: augmented_prompt_embeds = self._encode_augmented_prompt( prompt, reference_subject_images, device, prompt_embeds.dtype) augmented_prompt_embeds = augmented_prompt_embeds.repeat( num_images_per_prompt, 1, 1) prompt_embeds = torch.cat([prompt_embeds, augmented_prompt_embeds], dim=0) # 4. Prepare timesteps self.scheduler.set_timesteps(num_inference_steps, device=device) timesteps = self.scheduler.timesteps # 5. Prepare latent variables num_channels_latents = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, prompt_embeds.dtype, device, generator, latents, ) start_subject_conditioning_step = (1 - alpha_) * num_inference_steps extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) (null_prompt_embeds, text_prompt_embeds, augmented_prompt_embeds) = prompt_embeds.chunk(3) # 7. Denoising loop num_warmup_steps = len( timesteps) - num_inference_steps * self.scheduler.order if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): latent_model_input = ( torch.cat([latents] * 2) if do_classifier_free_guidance else latents) latent_model_input = self.scheduler.scale_model_input( latent_model_input, t) if i <= start_subject_conditioning_step: current_prompt_embeds = torch.cat( [null_prompt_embeds, text_prompt_embeds], dim=0) else: current_prompt_embeds = torch.cat( [null_prompt_embeds, augmented_prompt_embeds], dim=0) # predict the noise residual noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=current_prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, ).sample # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) else: assert 0, 'Not Implemented' # compute the previous noisy sample x_t -> x_t-1 latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample # call the callback, if provided if i == len(timesteps) - 1 or (i + 1 > num_warmup_steps and (i + 1) % self.scheduler.order == 0): if callback is not None and i % callback_steps == 0: callback(i, t, latents) has_nsfw_concept = None if output_type == 'latent': image = latents has_nsfw_concept = None elif output_type == 'pil': # 8. Post-processing image = self.decode_latents(latents) # 10. Convert to PIL image = self.output_to_pil(image) else: # 8. Post-processing image = self.decode_latents(latents) # Offload last model to CPU if hasattr( self, 'final_offload_hook') and self.final_offload_hook is not None: self.final_offload_hook.offload() if not return_dict: return (image, has_nsfw_concept) return OrderedDict( samples=image, nsfw_content_detected=has_nsfw_concept) ================================================ FILE: mmagic/models/editors/fastcomposer/fastcomposer_util.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import gc import types from collections import OrderedDict from typing import Optional, Tuple, Union import torch import torch.nn.functional as F import torchvision.transforms as T from torch import nn from torch.nn import Linear from transformers import (CLIPModel, CLIPPreTrainedModel, CLIPTextModel, CLIPVisionConfig, CLIPVisionModel) from transformers.modeling_outputs import BaseModelOutputWithPooling from mmagic.utils import try_import _expand_mask = try_import('transformers.models.clip.modeling_clip') if _expand_mask is None: _expand_mask = try_import( 'ransformers.models.clip.modeling_clip._prepare_4d_attention_mask') class FastComposerModel(nn.Module): """FastComposerModel is based on the StableDiffusion Model and the Clip Model.""" def __init__(self, text_encoder, image_encoder, vae, unet, cfg): super().__init__() self.text_encoder = text_encoder self.image_encoder = image_encoder self.vae = vae self.unet = unet self.use_ema = False self.ema_param = None self.pretrained_model_name_or_path = cfg[ 'pretrained_model_name_or_path'] self.revision = cfg['revision'] self.non_ema_revision = cfg['non_ema_revision'] self.object_localization = cfg['object_localization'] self.object_localization_weight = cfg['object_localization_weight'] self.localization_layers = cfg['localization_layers'] self.mask_loss = cfg['mask_loss'] self.mask_loss_prob = cfg['mask_loss_prob'] embed_dim = text_encoder.config.hidden_size self.postfuse_module = FastComposerPostfuseModule(embed_dim) if self.object_localization: self.cross_attention_scores = {} self.unet = unet_store_cross_attention_scores( self.unet, self.cross_attention_scores, self.localization_layers) self.object_localization_loss_fn = BalancedL1Loss( cfg['object_localization_threshold'], cfg['object_localization_normalize'], ) def _clear_cross_attention_scores(self): """Delete cross attention scores.""" if hasattr(self, 'cross_attention_scores'): keys = list(self.cross_attention_scores.keys()) for k in keys: del self.cross_attention_scores[k] gc.collect() @staticmethod def from_pretrained(cfg, vae, unet): """Init FastComposerTextEncoder and FastComposerCLIPImageEncoder.""" text_encoder = FastComposerTextEncoder.from_pretrained( cfg['pretrained_model_name_or_path'], subfolder='text_encoder', revision=cfg['revision'], ) if not isinstance(cfg['image_encoder'], dict): image_encoder = FastComposerCLIPImageEncoder.from_pretrained( cfg['image_encoder']) else: vision_model = CLIPVisionModel( CLIPVisionConfig.from_dict(cfg['image_encoder'])) visual_projection = Linear( in_features=1024, out_features=768, bias=False) vision_processor = T.Normalize( (0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711), ) image_encoder = FastComposerCLIPImageEncoder( vision_model, visual_projection, vision_processor, ) return FastComposerModel(text_encoder, image_encoder, vae, unet, cfg) def forward(self, batch, noise_scheduler): """Forward function. Args: batch (torch.Tensor ): You can directly input a ``torch.Tensor``. noise_scheduler (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: Dict """ pixel_values = batch['pixel_values'] input_ids = batch['input_ids'] image_token_mask = batch['image_token_mask'] object_pixel_values = batch['object_pixel_values'] num_objects = batch['num_objects'] vae_dtype = self.vae.parameters().__next__().dtype vae_input = pixel_values.to(vae_dtype) latents = self.vae.encode(vae_input).latent_dist.sample() latents = latents * self.vae.config.scaling_factor # Sample noise that we'll add to the latents noise = torch.randn_like(latents) bsz = latents.shape[0] # Sample a random timestep for each image timesteps = torch.randint( 0, noise_scheduler.num_train_timesteps, (bsz, ), device=latents.device) timesteps = timesteps.long() # Add noise to the latents according to # the noise magnitude at each timestep # (this is the forward diffusion process) noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps) # (bsz, max_num_objects, num_image_tokens, dim) object_embeds = self.image_encoder(object_pixel_values) encoder_hidden_states = self.text_encoder( input_ids, image_token_mask, object_embeds, num_objects)[0] # (bsz, seq_len, dim) encoder_hidden_states = self.postfuse_module( encoder_hidden_states, object_embeds, image_token_mask, num_objects, ) # Get the target for loss depending on the prediction type if noise_scheduler.config.prediction_type == 'epsilon': target = noise elif noise_scheduler.config.prediction_type == 'v_prediction': target = noise_scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{noise_scheduler.config.prediction_type}') pred = self.unet(noisy_latents, timesteps, encoder_hidden_states).sample if self.mask_loss and torch.rand(1) < self.mask_loss_prob: object_segmaps = batch['object_segmaps'] mask = (object_segmaps.sum(dim=1) > 0).float() mask = F.interpolate( mask.unsqueeze(1), size=(pred.shape[-2], pred.shape[-1]), mode='bilinear', align_corners=False, ) pred = pred * mask target = target * mask denoise_loss = F.mse_loss( pred.float(), target.float(), reduction='mean') return_dict = {'denoise_loss': denoise_loss} if self.object_localization: object_segmaps = batch['object_segmaps'] image_token_idx = batch['image_token_idx'] image_token_idx_mask = batch['image_token_idx_mask'] localization_loss = get_object_localization_loss( self.cross_attention_scores, object_segmaps, image_token_idx, image_token_idx_mask, self.object_localization_loss_fn, ) return_dict['localization_loss'] = localization_loss loss = self.object_localization_weight * localization_loss loss += denoise_loss self._clear_cross_attention_scores() else: loss = denoise_loss return_dict['loss'] = loss return return_dict class FastComposerTextEncoder(CLIPPreTrainedModel): """TextEncoder for FastComposerModel.""" @staticmethod def from_pretrained(model_name_or_path, **kwargs): """Init textEncoder with Stable Diffusion Model name or path.""" model = CLIPTextModel.from_pretrained(model_name_or_path, **kwargs) text_model = model.text_model return FastComposerTextEncoder(text_model) def __init__(self, text_model): super().__init__(text_model.config) self.config = text_model.config self.final_layer_norm = text_model.final_layer_norm self.embeddings = text_model.embeddings self.encoder = text_model.encoder self._build_causal_attention_mask = build_causal_attention_mask def forward( self, input_ids, image_token_mask=None, object_embeds=None, num_objects=None, attention_mask: Optional[torch.Tensor] = None, output_attentions: Optional[bool] = None, output_hidden_states: Optional[bool] = None, return_dict: Optional[bool] = None, ) -> Union[Tuple, BaseModelOutputWithPooling]: """Forward function. Args: input_ids (torch.Tensor ): You can directly input a ``torch.Tensor``. image_token_mask (torch.Tensor ): You can directly input a ``torch.Tensor``. object_embeds (torch.Tensor ): You can directly input a ``torch.Tensor``. num_objects (torch.Tensor ): You can directly input a ``torch.Tensor``. attention_mask (torch.Tensor ): You can directly input a ``torch.Tensor``. output_attentions (bool ): Default to None. output_hidden_states (bool ): Default to None. return_dict (bool ): Default to None. Returns: Union[Tuple, BaseModelOutputWithPooling] """ output_attentions = ( output_attentions if output_attentions is not None else self.config.output_attentions) output_hidden_states = ( output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states) return_dict = ( return_dict if return_dict is not None else self.config.use_return_dict) input_shape = input_ids.size() input_ids = input_ids.view(-1, input_shape[-1]) hidden_states = self.embeddings(input_ids) bsz, seq_len = input_shape causal_attention_mask = self._build_causal_attention_mask( bsz, seq_len, hidden_states.dtype).to(hidden_states.device) # expand attention_mask if attention_mask is not None: # [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len] attention_mask = _expand_mask(attention_mask, hidden_states.dtype) encoder_outputs = self.encoder( inputs_embeds=hidden_states, attention_mask=attention_mask, causal_attention_mask=causal_attention_mask, output_attentions=output_attentions, output_hidden_states=output_hidden_states, return_dict=return_dict, ) last_hidden_state = encoder_outputs[0] last_hidden_state = self.final_layer_norm(last_hidden_state) # text_embeds.shape = [batch_size, sequence_length, transformer.width] # take features from the eot embedding # (eot_token is the highest number in each sequence) # casting to torch.int for onnx compatibility: # argmax doesn't support int64 inputs with opset 14 pooled_output = last_hidden_state[ torch.arange( last_hidden_state.shape[0], device=last_hidden_state.device), input_ids.to(dtype=torch.int, device=last_hidden_state.device ).argmax(dim=-1), ] if not return_dict: return (last_hidden_state, pooled_output) + encoder_outputs[1:] return BaseModelOutputWithPooling( last_hidden_state=last_hidden_state, pooler_output=pooled_output, hidden_states=encoder_outputs.hidden_states, attentions=encoder_outputs.attentions, ) class FastComposerCLIPImageEncoder(CLIPPreTrainedModel): """CLIPImageEncoder for FastComposerModel.""" @staticmethod def from_pretrained(global_model_name_or_path): """Init CLIPModel with Clip model name or path.""" model = CLIPModel.from_pretrained(global_model_name_or_path) vision_model = model.vision_model visual_projection = model.visual_projection vision_processor = T.Normalize( (0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711), ) return FastComposerCLIPImageEncoder( vision_model, visual_projection, vision_processor, ) def __init__( self, vision_model, visual_projection, vision_processor, ): super().__init__(vision_model.config) self.vision_model = vision_model self.visual_projection = visual_projection self.vision_processor = vision_processor self.image_size = vision_model.config.image_size def forward(self, object_pixel_values): """Forward function. Args: object_pixel_values (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ b, num_objects, c, h, w = object_pixel_values.shape object_pixel_values = object_pixel_values.view(b * num_objects, c, h, w) if h != self.image_size or w != self.image_size: h, w = self.image_size, self.image_size object_pixel_values = F.interpolate( object_pixel_values, (h, w), mode='bilinear') object_pixel_values = self.vision_processor(object_pixel_values) object_embeds = self.vision_model(object_pixel_values)[1] object_embeds = self.visual_projection(object_embeds) object_embeds = object_embeds.view(b, num_objects, 1, -1) return object_embeds def get_object_transforms(cfg): """Get Object transforms.""" if cfg['no_object_augmentation']: pre_augmentations = [] augmentations = [] else: pre_augmentations = [ ( 'zoomin', T.RandomApply([RandomZoomIn(min_zoom=1.0, max_zoom=2.0)], p=0.5), ), ] augmentations = [ ( 'rotate', T.RandomApply( [ T.RandomAffine( degrees=30, interpolation=T.InterpolationMode.BILINEAR) ], p=0.75, ), ), ('jitter', T.RandomApply([T.ColorJitter(0.5, 0.5, 0.5, 0.5)], p=0.5)), ('blur', T.RandomApply([T.GaussianBlur(5, sigma=(0.1, 2.0))], p=0.5)), ('gray', T.RandomGrayscale(p=0.1)), ('flip', T.RandomHorizontalFlip()), ('elastic', T.RandomApply([T.ElasticTransform()], p=0.5)), ] object_transforms = torch.nn.Sequential( OrderedDict([ *pre_augmentations, ('pad_to_square', PadToSquare(fill=0, padding_mode='constant')), ( 'resize', T.Resize( (cfg['object_resolution'], cfg['object_resolution']), interpolation=T.InterpolationMode.BILINEAR, ), ), *augmentations, ('convert_to_float', T.ConvertImageDtype(torch.float32)), ])) return object_transforms class FastComposerPostfuseModule(nn.Module): """Postfuse Module for FastComposerModel.""" def __init__(self, embed_dim): super().__init__() self.mlp1 = MLP( embed_dim * 2, embed_dim, embed_dim, use_residual=False) self.mlp2 = MLP(embed_dim, embed_dim, embed_dim, use_residual=True) self.layer_norm = nn.LayerNorm(embed_dim) def fuse_fn(self, text_embeds, object_embeds): """Fuse function. Args: text_embeds (torch.Tensor ): You can directly input a ``torch.Tensor``. object_embeds (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ text_object_embeds = torch.cat([text_embeds, object_embeds], dim=-1) text_object_embeds = self.mlp1(text_object_embeds) + text_embeds text_object_embeds = self.mlp2(text_object_embeds) text_object_embeds = self.layer_norm(text_object_embeds) return text_object_embeds def forward( self, text_embeds, object_embeds, image_token_mask, num_objects, ) -> torch.Tensor: """Forward function. Args: text_embeds (torch.Tensor ): You can directly input a ``torch.Tensor``. object_embeds (torch.Tensor ): You can directly input a ``torch.Tensor``. image_token_mask (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ text_object_embeds = fuse_object_embeddings(text_embeds, image_token_mask, object_embeds, num_objects, self.fuse_fn) return text_object_embeds def unet_store_cross_attention_scores(unet, attention_scores, layers=5): """Unet store cross attention scores.""" from diffusers.models.attention_processor import (Attention, AttnProcessor, AttnProcessor2_0) UNET_LAYER_NAMES = [ 'down_blocks.0', 'down_blocks.1', 'down_blocks.2', 'mid_block', 'up_blocks.1', 'up_blocks.2', 'up_blocks.3', ] start_layer = (len(UNET_LAYER_NAMES) - layers) // 2 end_layer = start_layer + layers applicable_layers = UNET_LAYER_NAMES[start_layer:end_layer] def make_new_get_attention_scores_fn(name): """Wrapper Function of create attention scores for unet.""" def new_get_attention_scores(module, query, key, attention_mask=None): """Create attention scores for unet.""" attention_probs = module.old_get_attention_scores( query, key, attention_mask) attention_scores[name] = attention_probs return attention_probs return new_get_attention_scores for name, module in unet.named_modules(): if isinstance(module, Attention) and 'attn2' in name: if not any(layer in name for layer in applicable_layers): continue if isinstance(module.processor, AttnProcessor2_0): module.set_processor(AttnProcessor()) module.old_get_attention_scores = module.get_attention_scores module.get_attention_scores = types.MethodType( make_new_get_attention_scores_fn(name), module) return unet class BalancedL1Loss(nn.Module): """BalancedL1Loss for object localization.""" def __init__(self, threshold=1.0, normalize=False): super().__init__() self.threshold = threshold self.normalize = normalize def forward(self, object_token_attn_prob, object_segmaps): """Forward function. Args: object_token_attn_prob (torch.Tensor ): You can directly input a ``torch.Tensor``. object_segmaps (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: float : ``float`` will be returned. """ if self.normalize: object_token_attn_prob = object_token_attn_prob / ( object_token_attn_prob.max(dim=2, keepdim=True)[0] + 1e-5) background_segmaps = 1 - object_segmaps background_segmaps_sum = background_segmaps.sum(dim=2) + 1e-5 object_segmaps_sum = object_segmaps.sum(dim=2) + 1e-5 background_loss = (object_token_attn_prob * background_segmaps).sum( dim=2) / background_segmaps_sum object_loss = (object_token_attn_prob * object_segmaps).sum(dim=2) / object_segmaps_sum return background_loss - object_loss def get_object_localization_loss( cross_attention_scores, object_segmaps, image_token_idx, image_token_idx_mask, loss_fn, ): """To obtain the average of the loss for each layer of object localization.""" num_layers = len(cross_attention_scores) loss = 0 for k, v in cross_attention_scores.items(): layer_loss = get_object_localization_loss_for_one_layer( v, object_segmaps, image_token_idx, image_token_idx_mask, loss_fn) loss += layer_loss return loss / num_layers def get_object_localization_loss_for_one_layer( cross_attention_scores, object_segmaps, object_token_idx, object_token_idx_mask, loss_fn, ): """Get object localization loss for one layer.""" bxh, num_noise_latents, num_text_tokens = cross_attention_scores.shape b, max_num_objects, _, _ = object_segmaps.shape size = int(num_noise_latents**0.5) # Resize the object segmentation maps to # the size of the cross attention scores object_segmaps = F.interpolate( object_segmaps, size=(size, size), mode='bilinear') # (b, max_num_objects, size, size) object_segmaps = object_segmaps.view( b, max_num_objects, -1) # (b, max_num_objects, num_noise_latents) num_heads = bxh // b cross_attention_scores = cross_attention_scores.view( b, num_heads, num_noise_latents, num_text_tokens) # Gather object_token_attn_prob object_token_attn_prob = torch.gather( cross_attention_scores, dim=3, index=object_token_idx.view(b, 1, 1, max_num_objects).expand( b, num_heads, num_noise_latents, max_num_objects), ) # (b, num_heads, num_noise_latents, max_num_objects) object_segmaps = ( object_segmaps.permute(0, 2, 1).unsqueeze(1).expand(b, num_heads, num_noise_latents, max_num_objects)) loss = loss_fn(object_token_attn_prob, object_segmaps) loss = loss * object_token_idx_mask.view(b, 1, max_num_objects) object_token_cnt = object_token_idx_mask.sum(dim=1).view(b, 1) + 1e-5 loss = (loss.sum(dim=2) / object_token_cnt).mean() return loss class RandomZoomIn(nn.Module): """RandomZoomIn for object transform.""" def __init__(self, min_zoom=1.0, max_zoom=1.5): super().__init__() self.min_zoom = min_zoom self.max_zoom = max_zoom def forward(self, image: torch.Tensor): """Forward function. Args: image (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ zoom = torch.rand(1) * (self.max_zoom - self.min_zoom) + self.min_zoom image = T.functional.resize( image, (int(zoom * image.shape[1]), int(zoom * image.shape[2])), interpolation=T.InterpolationMode.BILINEAR, ) # crop top square image = CropTopSquare()(image) return image class PadToSquare(nn.Module): """If the height of the image is greater than the width, padding will be added on both sides of the image to make it a square.""" def __init__(self, fill=0, padding_mode='constant'): super().__init__() self.fill = fill self.padding_mode = padding_mode def forward(self, image: torch.Tensor): """Forward function. Args: image (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ _, h, w = image.shape if h == w: return image elif h > w: padding = (h - w) // 2 image = torch.nn.functional.pad( image, (padding, padding, 0, 0), self.padding_mode, self.fill, ) else: padding = (w - h) // 2 image = torch.nn.functional.pad( image, (0, 0, padding, padding), self.padding_mode, self.fill, ) return image class CropTopSquare(nn.Module): """If the height of the image is greater than the width, the image will be cropped into a square starting from the top of the image.""" def __init__(self): super().__init__() def forward(self, image: torch.Tensor): """Forward function. Args: image (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ _, h, w = image.shape if h <= w: return image return image[:, :w, :] class MLP(nn.Module): """Multilayer Perceptron.""" def __init__(self, in_dim, out_dim, hidden_dim, use_residual=True): super().__init__() if use_residual: assert in_dim == out_dim self.layernorm = nn.LayerNorm(in_dim) self.fc1 = nn.Linear(in_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, out_dim) self.use_residual = use_residual self.act_fn = nn.GELU() def forward(self, x): """Forward function. Args: x (torch.Tensor ): You can directly input a ``torch.Tensor``. Returns: torch.Tensor : ``torch.tensor`` will be returned. """ residual = x x = self.layernorm(x) x = self.fc1(x) x = self.act_fn(x) x = self.fc2(x) if self.use_residual: x = x + residual return x def fuse_object_embeddings( inputs_embeds, image_token_mask, object_embeds, num_objects, fuse_fn=torch.add, ): """Fuse object embeddings.""" object_embeds = object_embeds.to(inputs_embeds.dtype) batch_size, max_num_objects = object_embeds.shape[:2] seq_length = inputs_embeds.shape[1] flat_object_embeds = object_embeds.view(-1, object_embeds.shape[-2], object_embeds.shape[-1]) valid_object_mask = ( torch.arange(max_num_objects, device=flat_object_embeds.device)[None, :] < num_objects[:, None]) valid_object_embeds = flat_object_embeds[valid_object_mask.flatten()] inputs_embeds = inputs_embeds.view(-1, inputs_embeds.shape[-1]) image_token_mask = image_token_mask.view(-1) valid_object_embeds = valid_object_embeds.view( -1, valid_object_embeds.shape[-1]) # slice out the image token embeddings image_token_embeds = inputs_embeds[image_token_mask] valid_object_embeds = fuse_fn(image_token_embeds, valid_object_embeds) inputs_embeds.masked_scatter_(image_token_mask[:, None], valid_object_embeds) inputs_embeds = inputs_embeds.view(batch_size, seq_length, -1) return inputs_embeds def build_causal_attention_mask(bsz, seq_len, dtype, device=None): """The function originally belonged to CLIPTextTransformer, but it has been removed in versions of transformers after 4.25.1.""" # lazily create causal attention mask, # with full attention between the vision tokens # pytorch uses additive attention mask; fill with -inf mask = torch.empty(bsz, seq_len, seq_len, dtype=dtype, device=device) mask.fill_(torch.tensor(torch.finfo(dtype).min)) mask.triu_(1) # zero out the lower diagonal mask = mask.unsqueeze(1) # expand mask return mask ================================================ FILE: mmagic/models/editors/fba/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .fba_decoder import FBADecoder from .fba_encoder import FBAResnetDilated __all__ = [ 'FBADecoder', 'FBAResnetDilated', ] ================================================ FILE: mmagic/models/editors/fba/fba_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine import MMLogger from mmengine.model.weight_init import constant_init, kaiming_init from mmengine.runner import load_checkpoint from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.registry import MODELS @MODELS.register_module() class FBADecoder(nn.Module): """Decoder for FBA matting. Args: pool_scales (tuple[int]): Pooling scales used in Pooling Pyramid Module. in_channels (int): Input channels. channels (int): Channels after modules, before conv_seg. conv_cfg (dict|None): Config of conv layers. norm_cfg (dict|None): Config of norm layers. act_cfg (dict): Config of activation layers. align_corners (bool): align_corners argument of F.interpolate. """ def __init__(self, pool_scales, in_channels, channels, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU'), align_corners=False): super().__init__() assert isinstance(pool_scales, (list, tuple)) # Pyramid Pooling Module self.pool_scales = pool_scales self.in_channels = in_channels self.channels = channels self.conv_cfg = conv_cfg self.norm_cfg = norm_cfg self.act_cfg = act_cfg self.align_corners = align_corners self.batch_norm = False self.ppm = [] for scale in self.pool_scales: self.ppm.append( nn.Sequential( nn.AdaptiveAvgPool2d(scale), *(ConvModule( self.in_channels, self.channels, kernel_size=1, bias=True, conv_cfg=self.conv_cfg, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg).children()))) self.ppm = nn.ModuleList(self.ppm) # Followed the author's implementation that # concatenate conv layers described in the supplementary # material between up operations self.conv_up1 = nn.Sequential(*(list( ConvModule( self.in_channels + len(pool_scales) * 256, self.channels, padding=1, kernel_size=3, bias=True, conv_cfg=self.conv_cfg, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg).children()) + list( ConvModule( self.channels, self.channels, padding=1, bias=True, kernel_size=3, conv_cfg=self.conv_cfg, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg).children()))) self.conv_up2 = nn.Sequential(*(list( ConvModule( self.channels * 2, self.channels, padding=1, kernel_size=3, bias=True, conv_cfg=self.conv_cfg, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg).children()))) if (self.norm_cfg['type'] == 'BN'): d_up3 = 128 else: d_up3 = 64 self.conv_up3 = nn.Sequential(*(list( ConvModule( self.channels + d_up3, 64, padding=1, kernel_size=3, bias=True, conv_cfg=self.conv_cfg, norm_cfg=self.norm_cfg, act_cfg=self.act_cfg).children()))) self.unpool = nn.MaxUnpool2d(2, stride=2) conv_up4_1 = list( ConvModule( 64 + 3 + 3 + 2, 32, padding=1, kernel_size=3, bias=True, act_cfg=self.act_cfg).children()) conv_up4_2 = list( ConvModule( 32, 16, padding=1, kernel_size=3, bias=True, act_cfg=self.act_cfg).children()) conv_up4_3 = list( ConvModule( 16, 7, padding=0, kernel_size=1, bias=True, act_cfg=None).children()) self.conv_up4 = nn.Sequential(*(conv_up4_1 + conv_up4_2 + conv_up4_3)) def init_weights(self, pretrained=None): """Init weights for the model. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, nn.Conv2d): kaiming_init(m) elif isinstance(m, (_BatchNorm, nn.GroupNorm)): constant_init(m, 1) else: raise TypeError('pretrained must be a str or None') def forward(self, inputs): """Forward function. Args: inputs (dict): Output dict of FbaEncoder. Returns: tuple(Tensor): Predicted alpha, fg and bg of the current batch. """ conv_out = inputs['conv_out'] img = inputs['merged'] two_channel_trimap = inputs['two_channel_trimap'] conv5 = conv_out[-1] input_size = conv5.size() ppm_out = [conv5] for pool_scale in self.ppm: ppm_out.append( nn.functional.interpolate( pool_scale(conv5), (input_size[2], input_size[3]), mode='bilinear', align_corners=self.align_corners)) ppm_out = torch.cat(ppm_out, 1) x = self.conv_up1(ppm_out) x = torch.nn.functional.interpolate( x, scale_factor=2, mode='bilinear', align_corners=self.align_corners) x = torch.cat((x, conv_out[-4]), 1) x = self.conv_up2(x) x = torch.nn.functional.interpolate( x, scale_factor=2, mode='bilinear', align_corners=self.align_corners) x = torch.cat((x, conv_out[-5]), 1) x = self.conv_up3(x) x = torch.nn.functional.interpolate( x, scale_factor=2, mode='bilinear', align_corners=self.align_corners) x = torch.cat((x, conv_out[-6][:, :3], img, two_channel_trimap), 1) output = self.conv_up4(x) alpha = torch.clamp(output[:, 0:1], 0, 1) F = torch.sigmoid(output[:, 1:4]) B = torch.sigmoid(output[:, 4:7]) return alpha, F, B ================================================ FILE: mmagic/models/editors/fba/fba_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models.archs import ResNet from mmagic.registry import MODELS @MODELS.register_module() class FBAResnetDilated(ResNet): """ResNet-based encoder for FBA image matting.""" def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ # x: (merged_t, trimap_t, two_channel_trimap,merged) # t refers to transformed. two_channel_trimap = x[:, 9:11] merged = x[:, 11:14] x = x[:, 0:11, ...] conv_out = [x] if self.deep_stem: x = self.stem(x) else: x = self.conv1(x) x = self.norm1(x) x = self.activate(x) conv_out.append(x) x = self.maxpool(x) x = self.layer1(x) conv_out.append(x) x = self.layer2(x) conv_out.append(x) x = self.layer3(x) conv_out.append(x) x = self.layer4(x) conv_out.append(x) return { 'conv_out': conv_out, 'merged': merged, 'two_channel_trimap': two_channel_trimap } ================================================ FILE: mmagic/models/editors/flavr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .flavr import FLAVR from .flavr_net import FLAVRNet __all__ = [ 'FLAVR', 'FLAVRNet', ] ================================================ FILE: mmagic/models/editors/flavr/flavr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models.base_models import BasicInterpolator from mmagic.registry import MODELS from mmagic.utils import tensor2img # TODO tensor2img will be move @MODELS.register_module() class FLAVR(BasicInterpolator): """FLAVR model for video interpolation. Paper: FLAVR: Flow-Agnostic Video Representations for Fast Frame Interpolation Ref repo: https://github.com/tarun005/FLAVR Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. required_frames (int): Required frames in each process. Default: 2 step_frames (int): Step size of video frame interpolation. Default: 1 init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Attributes: init_cfg (dict, optional): Initialization config dict. data_preprocessor (:obj:`BaseDataPreprocessor`): Used for pre-processing data sampled by dataloader to the format accepted by :meth:`forward`. """ @staticmethod def merge_frames(input_tensors, output_tensors): """merge input frames and output frames. Interpolate a frame between the given two frames. Merged from [[in1, in2, in3, in4], [in2, in3, in4, in5], ...] [[out1], [out2], [out3], ...] to [in1, in2, out1, in3, out2, ..., in(-3), out(-1), in(-2), in(-1)] Args: input_tensors (Tensor): The input frames with shape [n, 4, c, h, w] output_tensors (Tensor): The output frames with shape [n, 1, c, h, w]. Returns: list[np.array]: The final frames. """ num_frames = input_tensors.shape[0] result = [tensor2img(input_tensors[0, 0])] for i in range(num_frames): result.append(tensor2img(input_tensors[i, 1])) result.append(tensor2img(output_tensors[i, 0])) result.append(tensor2img(input_tensors[-1, 2])) result.append(tensor2img(input_tensors[-1, 3])) return result ================================================ FILE: mmagic/models/editors/flavr/flavr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class FLAVRNet(BaseModule): """PyTorch implementation of FLAVR for video frame interpolation. Paper: FLAVR: Flow-Agnostic Video Representations for Fast Frame Interpolation Ref repo: https://github.com/tarun005/FLAVR Args: num_input_frames (int): Number of input frames. num_output_frames (int): Number of output frames. mid_channels_list (list[int]): List of number of mid channels. Default: [512, 256, 128, 64] encoder_layers_list (list[int]): List of number of layers in encoder. Default: [2, 2, 2, 2] bias (bool): If ``True``, adds a learnable bias to the conv layers. Default: ``True`` norm_cfg (dict | None): Config dict for normalization layer. Default: None join_type (str): Join type of tensors from decoder and encoder. Candidates are ``concat`` and ``add``. Default: ``concat`` up_mode (str): Up-mode UpConv3d, candidates are ``transpose`` and ``trilinear``. Default: ``transpose`` init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, num_input_frames, num_output_frames, mid_channels_list=[512, 256, 128, 64], encoder_layers_list=[2, 2, 2, 2], bias=False, norm_cfg=None, join_type='concat', up_mode='transpose', init_cfg=None): super().__init__(init_cfg=init_cfg) self.encoder = Encoder( block=BasicBlock, layers=encoder_layers_list, stem_layer=BasicStem, mid_channels_list=mid_channels_list[::-1], bias=bias, norm_cfg=norm_cfg) self.decoder = Decoder( join_type=join_type, up_mode=up_mode, mid_channels_list=mid_channels_list, batchnorm=norm_cfg) self.feature_fuse = ConvModule( mid_channels_list[3] * num_input_frames, mid_channels_list[3], kernel_size=1, stride=1, bias=False, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2, inplace=True)) out_channels = 3 * num_output_frames self.conv_last = nn.Sequential( nn.ReflectionPad2d(3), nn.Conv2d( mid_channels_list[3], out_channels=out_channels, kernel_size=7, stride=1, padding=0)) def forward(self, images: torch.Tensor): """Forward function. Args: images (Tensor): Input frames tensor with shape (N, T, C, H, W). Returns: out (Tensor): Output tensor. """ # from [b, t, c, h, w] to [b, c, d, h, w], where t==d images = images.permute((0, 2, 1, 3, 4)) # Batch mean normalization works slightly better than global mean # normalization, Refer to https://github.com/myungsub/CAIN mean_ = images.mean((2, 3, 4), keepdim=True) images = images - mean_ xs = self.encoder(images) dx_out = self.decoder(xs) out = self.feature_fuse(dx_out) out = self.conv_last(out) # b, t*c, h, w b, c_all, h, w = out.shape t = c_all // 3 mean_ = mean_.view(b, 1, 3, 1, 1) out = out.view(b, t, 3, h, w) out = out + mean_ # if t==1, which means the output only contains one frame. out = out.squeeze(1) return out class Encoder(nn.Module): """Encoder of FLAVR. Args: block (nn.Module): Basic block of encoder. layers (str): List of layers in encoder. stem_layer (nn.Module): stem layer (conv first). mid_channels_list (list[int]): List of mid channels. norm_cfg (dict | None): Config dict for normalization layer. Default: None bias (bool): If ``True``, adds a learnable bias to the conv layers. Default: ``True`` """ def __init__(self, block, layers, stem_layer, mid_channels_list, norm_cfg, bias): super().__init__() self.in_channels = mid_channels_list[0] self.bias = bias self.stem_layer = stem_layer(mid_channels_list[0], bias, norm_cfg) self.layer1 = self._make_layer( block, mid_channels_list[0], layers[0], norm_cfg=norm_cfg, stride=1) self.layer2 = self._make_layer( block, mid_channels_list[1], layers[1], norm_cfg=norm_cfg, stride=2, temporal_stride=1) self.layer3 = self._make_layer( block, mid_channels_list[2], layers[2], norm_cfg=norm_cfg, stride=2, temporal_stride=1) self.layer4 = self._make_layer( block, mid_channels_list[3], layers[3], norm_cfg=norm_cfg, stride=1, temporal_stride=1) # init weights self._initialize_weights() def forward(self, x): """Forward function. Args: x (Tensor): Input tensor). Returns: tuple(Tensor): Output tensors. """ x_0 = self.stem_layer(x) x_1 = self.layer1(x_0) x_2 = self.layer2(x_1) x_3 = self.layer3(x_2) x_4 = self.layer4(x_3) return x_0, x_1, x_2, x_3, x_4 def _make_layer(self, block, mid_channels, num_blocks, norm_cfg, stride=1, temporal_stride=None): """Make layers by stacking the blocks.""" downsample = None if stride != 1 or self.in_channels != mid_channels * block.expansion: if temporal_stride: ds_stride = (temporal_stride, stride, stride) else: ds_stride = (stride, stride, stride) downsample = ConvModule( self.in_channels, mid_channels * block.expansion, kernel_size=1, stride=ds_stride, bias=False, conv_cfg=dict(type='Conv3d'), norm_cfg=norm_cfg, act_cfg=None) stride = ds_stride layers = [] layers.append( block( self.in_channels, mid_channels, norm_cfg=norm_cfg, stride=stride, bias=self.bias, downsample=downsample)) self.in_channels = mid_channels * block.expansion for _ in range(1, num_blocks): layers.append( block( self.in_channels, mid_channels, norm_cfg=norm_cfg, bias=self.bias)) return nn.Sequential(*layers) def _initialize_weights(self): """Init weights for models.""" for m in self.modules(): if isinstance(m, nn.Conv3d): nn.init.kaiming_normal_( m.weight, mode='fan_out', nonlinearity='relu') if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.BatchNorm3d): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) nn.init.constant_(m.bias, 0) class Decoder(nn.Module): """Decoder of FLAVR. Args: join_type (str): Join type of tensors from decoder and encoder. Candidates are ``concat`` and ``add``. Default: ``concat`` up_mode (str): Up-mode UpConv3d, candidates are ``transpose`` and ``trilinear``. Default: ``transpose`` mid_channels_list (list[int]): List of mid channels. Default: [512, 256, 128, 64] batchnorm (bool): Whether contains BatchNorm3d. Default: False. """ def __init__(self, join_type, up_mode, mid_channels_list=[512, 256, 128, 64], batchnorm=False): super().__init__() growth = 2 if join_type == 'concat' else 1 self.join_type = join_type self.lrelu = nn.LeakyReLU(0.2, True) self.layer0 = Conv3d( mid_channels_list[0], mid_channels_list[1], kernel_size=3, padding=1, bias=True, batchnorm=batchnorm) self.layer1 = UpConv3d( mid_channels_list[1] * growth, mid_channels_list[2], kernel_size=(3, 4, 4), stride=(1, 2, 2), padding=(1, 1, 1), up_mode=up_mode, batchnorm=batchnorm) self.layer2 = UpConv3d( mid_channels_list[2] * growth, mid_channels_list[3], kernel_size=(3, 4, 4), stride=(1, 2, 2), padding=(1, 1, 1), up_mode=up_mode, batchnorm=batchnorm) self.layer3 = Conv3d( mid_channels_list[3] * growth, mid_channels_list[3], kernel_size=3, padding=1, bias=True, batchnorm=batchnorm) self.layer4 = UpConv3d( mid_channels_list[3] * growth, mid_channels_list[3], kernel_size=(3, 4, 4), stride=(1, 2, 2), padding=(1, 1, 1), up_mode=up_mode, batchnorm=batchnorm) def forward(self, xs): """Forward function. Args: xs (Tensor): Input tensor). Returns: dx_out (Tensor): Output tensor. """ dx_3 = self.lrelu(self.layer0(xs[4])) dx_3 = self._join_tensors(dx_3, xs[3]) dx_2 = self.lrelu(self.layer1(dx_3)) dx_2 = self._join_tensors(dx_2, xs[2]) dx_1 = self.lrelu(self.layer2(dx_2)) dx_1 = self._join_tensors(dx_1, xs[1]) dx_0 = self.lrelu(self.layer3(dx_1)) dx_0 = self._join_tensors(dx_0, xs[0]) dx_out = self.lrelu(self.layer4(dx_0)) dx_out = torch.cat(torch.unbind(dx_out, 2), 1) return dx_out def _join_tensors(self, x1, x2): """Concat or Add two tensors. Args: x1 (Tensor): The first input tensor. x2 (Tensor): The second input tensor. """ if self.join_type == 'concat': return torch.cat([x1, x2], dim=1) else: return x1 + x2 class UpConv3d(nn.Module): """A conv block that bundles conv/SEGating/norm layers. Args: in_channels (int): Number of channels in the input feature map. Same as that in ``nn._ConvNd``. out_channels (int): Number of channels produced by the convolution. Same as that in ``nn._ConvNd``. kernel_size (int | tuple[int]): Size of the convolving kernel. Same as that in ``nn._ConvNd``. stride (int | tuple[int]): Stride of the convolution. Same as that in ``nn._ConvNd``. padding (int | tuple[int]): Zero-padding added to both sides of the input. Same as that in ``nn._ConvNd``. up_mode (str): Up-mode UpConv3d, candidates are ``transpose`` and ``trilinear``. Default: ``transpose``. batchnorm (bool): Whether contains BatchNorm3d. Default: False. """ def __init__(self, in_channels, out_channels, kernel_size, stride, padding, up_mode='transpose', batchnorm=False): super().__init__() self.up_mode = up_mode if self.up_mode == 'transpose': self.upconv = nn.ModuleList([ nn.ConvTranspose3d( in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding), SEGating(out_channels) ]) else: self.upconv = nn.ModuleList([ nn.Upsample( mode='trilinear', scale_factor=(1, 2, 2), align_corners=False), nn.Conv3d(in_channels, out_channels, kernel_size=1, stride=1), SEGating(out_channels) ]) if batchnorm: self.upconv += [nn.BatchNorm3d(out_channels)] self.upconv = nn.Sequential(*self.upconv) def forward(self, x): """Forward function.""" return self.upconv(x) class Conv3d(nn.Module): """A conv block that bundles conv/SEGating/norm layers. Args: in_channels (int): Number of channels in the input feature map. Same as that in ``nn._ConvNd``. out_channels (int): Number of channels produced by the convolution. Same as that in ``nn._ConvNd``. kernel_size (int | tuple[int]): Size of the convolving kernel. Same as that in ``nn._ConvNd``. stride (int | tuple[int]): Stride of the convolution. Same as that in ``nn._ConvNd``. Default: 1. padding (int | tuple[int]): Zero-padding added to both sides of the input. Same as that in ``nn._ConvNd``. bias (bool): If ``True``, adds a learnable bias to the conv layer. Default: ``True`` batchnorm (bool): Whether contains BatchNorm3d. Default: False. """ def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True, batchnorm=False): super().__init__() self.conv = [ nn.Conv3d( in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=bias), SEGating(out_channels) ] if batchnorm: self.conv += [nn.BatchNorm3d(out_channels)] self.conv = nn.Sequential(*self.conv) def forward(self, x): """Forward function.""" return self.conv(x) class BasicStem(ConvModule): """The default conv-batchnorm-relu stem of FLAVR. Args: out_channels (int): Number of output channels. Default: 64 bias (bool): If ``True``, adds a learnable bias to the conv layer. Default: ``False`` norm_cfg (dict | None): Config dict for normalization layer. Default: None. """ def __init__(self, out_channels=64, bias=False, norm_cfg=None): super().__init__( 3, out_channels, kernel_size=(3, 7, 7), stride=(1, 2, 2), padding=(1, 3, 3), bias=bias, conv_cfg=dict(type='Conv3d'), norm_cfg=norm_cfg, inplace=False) class BasicBlock(nn.Module): """Basic block of encoder in FLAVR. Args: in_channels (int): Number of channels in the input feature map. mid_channels (int): Number of middle channels. stride (int | tuple[int]): Stride of the first convolution. Default: 1. norm_cfg (dict | None): Config dict for normalization layer. Default: None. bias (bool): If ``True``, adds a learnable bias to the conv layers. Default: ``True`` downsample (None | torch.nn.Module): Down-sample layer. Default: None. """ expansion = 1 def __init__( self, in_channels, mid_channels, stride=1, norm_cfg=None, bias=False, downsample=None, ): super().__init__() self.conv1 = ConvModule( in_channels, mid_channels, kernel_size=(3, 3, 3), stride=stride, padding=(1, 1, 1), bias=bias, conv_cfg=dict(type='Conv3d'), norm_cfg=norm_cfg) self.conv2 = ConvModule( mid_channels, mid_channels, kernel_size=(3, 3, 3), stride=(1, 1, 1), padding=(1, 1, 1), bias=bias, conv_cfg=dict(type='Conv3d'), norm_cfg=norm_cfg, act_cfg=None) self.fg = SEGating(mid_channels) # Feature Gating self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride def forward(self, x): """Forward function. Args: xs (Tensor): Input tensor). Returns: out (Tensor): Output tensor. """ residual = x out = self.conv1(x) out = self.conv2(out) out = self.fg(out) if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out class SEGating(nn.Module): """Gating of SE attention. Args: in_channels (int): Number of channels in the input feature map. """ def __init__(self, in_channels): super().__init__() self.pool = nn.AdaptiveAvgPool3d(1) self.attn_layer = nn.Sequential( nn.Conv3d( in_channels, in_channels, kernel_size=1, stride=1, bias=True), nn.Sigmoid()) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor). Returns: Tensor: Output tensors. """ out = self.pool(x) y = self.attn_layer(out) return x * y ================================================ FILE: mmagic/models/editors/gca/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .gca import GCA from .gca_module import GCAModule from .resgca_dec import ResGCADecoder, ResNetDec, ResShortcutDec from .resgca_enc import ResGCAEncoder, ResNetEnc, ResShortcutEnc __all__ = [ 'GCA', 'GCAModule', 'ResNetEnc', 'ResShortcutEnc', 'ResGCAEncoder', 'ResNetDec', 'ResShortcutDec', 'ResGCADecoder' ] ================================================ FILE: mmagic/models/editors/gca/gca.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional from mmagic.models.base_models import BaseMattor from mmagic.models.utils import get_unknown_tensor from mmagic.registry import MODELS @MODELS.register_module() class GCA(BaseMattor): """Guided Contextual Attention image matting model. https://arxiv.org/abs/2001.04069 Args: data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. backbone (dict): Config of backbone. loss_alpha (dict): Config of the alpha prediction loss. Default: None. init_cfg (dict, optional): Initialization config dict. Default: None. train_cfg (dict): Config of training. In ``train_cfg``, ``train_backbone`` should be specified. If the model has a refiner, ``train_refiner`` should be specified. test_cfg (dict): Config of testing. In ``test_cfg``, If the model has a refiner, ``train_refiner`` should be specified. """ def __init__(self, data_preprocessor, backbone, loss_alpha=None, init_cfg: Optional[dict] = None, train_cfg=None, test_cfg=None): super().__init__( backbone=backbone, data_preprocessor=data_preprocessor, init_cfg=init_cfg, train_cfg=train_cfg, test_cfg=test_cfg) self.loss_alpha = MODELS.build(loss_alpha) def _forward(self, inputs): """Forward function. Args: inputs (torch.Tensor): Input tensor. Returns: Tensor: Output tensor. """ raw_alpha = self.backbone(inputs) pred_alpha = (raw_alpha.tanh() + 1.0) / 2.0 return pred_alpha def _forward_test(self, inputs): """Forward function for testing GCA model. Args: inputs (torch.Tensor): batch input tensor. Returns: Tensor: Output tensor of model. """ return self._forward(inputs) def _forward_train(self, inputs, data_samples): """Forward function for training GCA model. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement]): data samples collated by :attr:`data_preprocessor`. Returns: dict: Contains the loss items and batch information. """ trimap = inputs[:, 3:, :, :] gt_alpha = data_samples.gt_alpha pred_alpha = self._forward(inputs) # FormatTrimap(to_onehot=False) will change unknown_value to 1 # FormatTrimap(to_onehot=True) will shift to 3 dim, # get_unknown_tensor can handle that directly without knowing # unknown_value. weight = get_unknown_tensor(trimap, unknown_value=1) losses = {'loss': self.loss_alpha(pred_alpha, gt_alpha, weight)} return losses ================================================ FILE: mmagic/models/editors/gca/gca_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model.weight_init import constant_init, xavier_init from torch.nn import functional as F class GCAModule(nn.Module): """Guided Contextual Attention Module. From https://arxiv.org/pdf/2001.04069.pdf. Based on https://github.com/nbei/Deep-Flow-Guided-Video-Inpainting. This module use image feature map to augment the alpha feature map with guided contextual attention score. Image feature and alpha feature are unfolded to small patches and later used as conv kernel. Thus, we refer the unfolding size as kernel size. Image feature patches have a default kernel size 3 while the kernel size of alpha feature patches could be specified by `rate` (see `rate` below). The image feature patches are used to convolve with the image feature itself to calculate the contextual attention. Then the attention feature map is convolved by alpha feature patches to obtain the attention alpha feature. At last, the attention alpha feature is added to the input alpha feature. Args: in_channels (int): Input channels of the guided contextual attention module. out_channels (int): Output channels of the guided contextual attention module. kernel_size (int): Kernel size of image feature patches. Default 3. stride (int): Stride when unfolding the image feature. Default 1. rate (int): The downsample rate of image feature map. The corresponding kernel size and stride of alpha feature patches will be `rate x 2` and `rate`. It could be regarded as the granularity of the gca module. Default: 2. pad_args (dict): Parameters of padding when convolve image feature with image feature patches or alpha feature patches. Allowed keys are `mode` and `value`. See torch.nn.functional.pad() for more information. Default: dict(mode='reflect'). interpolation (str): Interpolation method in upsampling and downsampling. penalty (float): Punishment hyperparameter to avoid a large correlation between each unknown patch and itself. Default: -1e4. eps (float): A small number to avoid dividing by 0 when calculating the normed image feature patch. Default: 1e-4. """ def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, rate=2, pad_args=dict(mode='reflect'), interpolation='nearest', penalty=-1e4, eps=1e-4): super().__init__() self.kernel_size = kernel_size self.stride = stride self.rate = rate self.pad_args = pad_args self.interpolation = interpolation self.penalty = penalty self.eps = eps # reduced the channels of input image feature. self.guidance_conv = nn.Conv2d(in_channels, in_channels // 2, 1) # convolution after the attention alpha feature self.out_conv = ConvModule( out_channels, out_channels, 1, norm_cfg=dict(type='BN'), act_cfg=None) self.init_weights() def init_weights(self): """Init weights for the model.""" xavier_init(self.guidance_conv, distribution='uniform') xavier_init(self.out_conv.conv, distribution='uniform') constant_init(self.out_conv.norm, 1e-3) def forward(self, img_feat, alpha_feat, unknown=None, softmax_scale=1.): """Forward function of GCAModule. Args: img_feat (Tensor): Image feature map of shape (N, ori_c, ori_h, ori_w). alpha_feat (Tensor): Alpha feature map of shape (N, alpha_c, ori_h, ori_w). unknown (Tensor, optional): Unknown area map generated by trimap. If specified, this tensor should have shape (N, 1, ori_h, ori_w). softmax_scale (float, optional): The softmax scale of the attention if unknown area is not provided in forward. Default: 1. Returns: Tensor: The augmented alpha feature. """ if alpha_feat.shape[2:4] != img_feat.shape[2:4]: raise ValueError( 'image feature size does not align with alpha feature size: ' f'image feature size {img_feat.shape[2:4]}, ' f'alpha feature size {alpha_feat.shape[2:4]}') if unknown is not None and unknown.shape[2:4] != img_feat.shape[2:4]: raise ValueError( 'image feature size does not align with unknown mask size: ' f'image feature size {img_feat.shape[2:4]}, ' f'unknown mask size {unknown.shape[2:4]}') # preprocess image feature img_feat = self.guidance_conv(img_feat) img_feat = F.interpolate( img_feat, scale_factor=1 / self.rate, mode=self.interpolation) # preprocess unknown mask unknown, softmax_scale = self.process_unknown_mask( unknown, img_feat, softmax_scale) img_ps, alpha_ps, unknown_ps = self.extract_feature_maps_patches( img_feat, alpha_feat, unknown) # create self correlation mask with shape: # (N, img_h*img_w, img_h, img_w) self_mask = self.get_self_correlation_mask(img_feat) # split tensors by batch dimension; tuple is returned img_groups = torch.split(img_feat, 1, dim=0) img_ps_groups = torch.split(img_ps, 1, dim=0) alpha_ps_groups = torch.split(alpha_ps, 1, dim=0) unknown_ps_groups = torch.split(unknown_ps, 1, dim=0) scale_groups = torch.split(softmax_scale, 1, dim=0) groups = (img_groups, img_ps_groups, alpha_ps_groups, unknown_ps_groups, scale_groups) out = [] # i is the virtual index of the sample in the current batch for img_i, img_ps_i, alpha_ps_i, unknown_ps_i, scale_i in zip(*groups): similarity_map = self.compute_similarity_map(img_i, img_ps_i) gca_score = self.compute_guided_attention_score( similarity_map, unknown_ps_i, scale_i, self_mask) out_i = self.propagate_alpha_feature(gca_score, alpha_ps_i) out.append(out_i) out = torch.cat(out, dim=0) out.reshape_as(alpha_feat) out = self.out_conv(out) + alpha_feat return out def extract_feature_maps_patches(self, img_feat, alpha_feat, unknown): """Extract image feature, alpha feature unknown patches. Args: img_feat (Tensor): Image feature map of shape (N, img_c, img_h, img_w). alpha_feat (Tensor): Alpha feature map of shape (N, alpha_c, ori_h, ori_w). unknown (Tensor, optional): Unknown area map generated by trimap of shape (N, 1, img_h, img_w). Returns: tuple: 3-tuple of ``Tensor``: Image feature patches of shape \ (N, img_h*img_w, img_c, img_ks, img_ks). ``Tensor``: Guided contextual attention alpha feature map. \ (N, img_h*img_w, alpha_c, alpha_ks, alpha_ks). ``Tensor``: Unknown mask of shape (N, img_h*img_w, 1, 1). """ # extract image feature patches with shape: # (N, img_h*img_w, img_c, img_ks, img_ks) img_ks = self.kernel_size img_ps = self.extract_patches(img_feat, img_ks, self.stride) # extract alpha feature patches with shape: # (N, img_h*img_w, alpha_c, alpha_ks, alpha_ks) alpha_ps = self.extract_patches(alpha_feat, self.rate * 2, self.rate) # extract unknown mask patches with shape: (N, img_h*img_w, 1, 1) unknown_ps = self.extract_patches(unknown, img_ks, self.stride) unknown_ps = unknown_ps.squeeze(dim=2) # squeeze channel dimension unknown_ps = unknown_ps.mean(dim=[2, 3], keepdim=True) return img_ps, alpha_ps, unknown_ps def compute_similarity_map(self, img_feat, img_ps): """Compute similarity between image feature patches. Args: img_feat (Tensor): Image feature map of shape (1, img_c, img_h, img_w). img_ps (Tensor): Image feature patches tensor of shape (1, img_h*img_w, img_c, img_ks, img_ks). Returns: Tensor: Similarity map between image feature patches with shape \ (1, img_h*img_w, img_h, img_w). """ img_ps = img_ps[0] # squeeze dim 0 # convolve the feature to get correlation (similarity) map escape_NaN = torch.FloatTensor([self.eps]).to(img_feat) img_ps_normed = img_ps / torch.max(self.l2_norm(img_ps), escape_NaN) img_feat = self.pad(img_feat, self.kernel_size, self.stride) similarity_map = F.conv2d(img_feat, img_ps_normed) return similarity_map def compute_guided_attention_score(self, similarity_map, unknown_ps, scale, self_mask): """Compute guided attention score. Args: similarity_map (Tensor): Similarity map of image feature with shape (1, img_h*img_w, img_h, img_w). unknown_ps (Tensor): Unknown area patches tensor of shape (1, img_h*img_w, 1, 1). scale (Tensor): Softmax scale of known and unknown area: [unknown_scale, known_scale]. self_mask (Tensor): Self correlation mask of shape (1, img_h*img_w, img_h, img_w). At (1, i*i, i, i) mask value equals -1e4 for i in [1, img_h*img_w] and other area is all zero. Returns: Tensor: Similarity map between image feature patches with shape \ (1, img_h*img_w, img_h, img_w). """ # scale the correlation with predicted scale factor for known and # unknown area unknown_scale, known_scale = scale[0] out = similarity_map * ( unknown_scale * unknown_ps.gt(0.).float() + known_scale * unknown_ps.le(0.).float()) # mask itself, self-mask only applied to unknown area out = out + self_mask * unknown_ps gca_score = F.softmax(out, dim=1) return gca_score def propagate_alpha_feature(self, gca_score, alpha_ps): """Propagate alpha feature based on guided attention score. Args: gca_score (Tensor): Guided attention score map of shape (1, img_h*img_w, img_h, img_w). alpha_ps (Tensor): Alpha feature patches tensor of shape (1, img_h*img_w, alpha_c, alpha_ks, alpha_ks). Returns: Tensor: Propagated alpha feature map of shape \ (1, alpha_c, alpha_h, alpha_w). """ alpha_ps = alpha_ps[0] # squeeze dim 0 if self.rate == 1: gca_score = self.pad(gca_score, kernel_size=2, stride=1) alpha_ps = alpha_ps.permute(1, 0, 2, 3) out = F.conv2d(gca_score, alpha_ps) / 4. else: out = F.conv_transpose2d( gca_score, alpha_ps, stride=self.rate, padding=1) / 4. return out def process_unknown_mask(self, unknown, img_feat, softmax_scale): """Process unknown mask. Args: unknown (Tensor, optional): Unknown area map generated by trimap of shape (N, 1, ori_h, ori_w) img_feat (Tensor): The interpolated image feature map of shape (N, img_c, img_h, img_w). softmax_scale (float, optional): The softmax scale of the attention if unknown area is not provided in forward. Default: 1. Returns: tuple: 2-tuple of ``Tensor``: Interpolated unknown area map of shape \ (N, img_h*img_w, img_h, img_w). ``Tensor``: Softmax scale tensor of known and unknown area of \ shape (N, 2). """ n, _, h, w = img_feat.shape if unknown is not None: unknown = unknown.clone() unknown = F.interpolate( unknown, scale_factor=1 / self.rate, mode=self.interpolation) unknown_mean = unknown.mean(dim=[2, 3]) known_mean = 1 - unknown_mean unknown_scale = torch.clamp( torch.sqrt(unknown_mean / known_mean), 0.1, 10).to(img_feat) known_scale = torch.clamp( torch.sqrt(known_mean / unknown_mean), 0.1, 10).to(img_feat) softmax_scale = torch.cat([unknown_scale, known_scale], dim=1) else: unknown = torch.ones((n, 1, h, w)).to(img_feat) softmax_scale = torch.FloatTensor( [softmax_scale, softmax_scale]).view(1, 2).repeat(n, 1).to(img_feat) return unknown, softmax_scale def extract_patches(self, x, kernel_size, stride): """Extract feature patches. The feature map will be padded automatically to make sure the number of patches is equal to `(H / stride) * (W / stride)`. Args: x (Tensor): Feature map of shape (N, C, H, W). kernel_size (int): Size of each patches. stride (int): Stride between patches. Returns: Tensor: Extracted patches of shape \ (N, (H / stride) * (W / stride) , C, kernel_size, kernel_size). """ n, c, _, _ = x.shape x = self.pad(x, kernel_size, stride) x = F.unfold(x, (kernel_size, kernel_size), stride=(stride, stride)) x = x.permute(0, 2, 1) x = x.reshape(n, -1, c, kernel_size, kernel_size) return x def pad(self, x, kernel_size, stride): """Pad input tensor. Args: x (Tensor): Input tensor. kernel_size (int): Kernel size of conv layer. stride (int): Stride of conv layer. Returns: Tensor: Padded tensor """ left = (kernel_size - stride + 1) // 2 right = (kernel_size - stride) // 2 pad = (left, right, left, right) return F.pad(x, pad, **self.pad_args) def get_self_correlation_mask(self, img_feat): """Create self correlation mask. Args: img_feat (Tensor): Input tensor. Returns: Tensor: Mask tensor. """ _, _, h, w = img_feat.shape # As ONNX does not support dynamic num_classes, we have to convert it # into an integer self_mask = F.one_hot( torch.arange(h * w).view(h, w), num_classes=int(h * w)) self_mask = self_mask.permute(2, 0, 1).view(1, h * w, h, w) # use large negative value to mask out self-correlation before softmax self_mask = self_mask * self.penalty return self_mask.to(img_feat) @staticmethod def l2_norm(x): """L2 normalization function. Args: x (Tensor): Input tensor. Returns: Tensor: L2 normalized output tensor. """ x = x**2 x = x.sum(dim=[1, 2, 3], keepdim=True) return torch.sqrt(x) ================================================ FILE: mmagic/models/editors/gca/resgca_dec.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init from mmagic.registry import MODELS from .gca_module import GCAModule from .resgca_enc import BasicBlock class BasicBlockDec(BasicBlock): """Basic residual block for decoder. For decoder, we use ConvTranspose2d with kernel_size 4 and padding 1 for conv1. And the output channel of conv1 is modified from `out_channels` to `in_channels`. """ def build_conv1(self, in_channels, out_channels, kernel_size, stride, conv_cfg, norm_cfg, act_cfg, with_spectral_norm): """Build conv1 of the block. Args: in_channels (int): The input channels of the ConvModule. out_channels (int): The output channels of the ConvModule. kernel_size (int): The kernel size of the ConvModule. stride (int): The stride of the ConvModule. If stride is set to 2, then ``conv_cfg`` will be overwritten as ``dict(type='Deconv')`` and ``kernel_size`` will be overwritten as 4. conv_cfg (dict): The conv config of the ConvModule. norm_cfg (dict): The norm config of the ConvModule. act_cfg (dict): The activation config of the ConvModule. with_spectral_norm (bool): Whether use spectral norm. Returns: nn.Module: The built ConvModule. """ if stride == 2: conv_cfg = dict(type='Deconv') kernel_size = 4 padding = 1 else: padding = kernel_size // 2 return ConvModule( in_channels, in_channels, kernel_size, stride=stride, padding=padding, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) def build_conv2(self, in_channels, out_channels, kernel_size, conv_cfg, norm_cfg, with_spectral_norm): """Build conv2 of the block. Args: in_channels (int): The input channels of the ConvModule. out_channels (int): The output channels of the ConvModule. kernel_size (int): The kernel size of the ConvModule. conv_cfg (dict): The conv config of the ConvModule. norm_cfg (dict): The norm config of the ConvModule. with_spectral_norm (bool): Whether use spectral norm. Returns: nn.Module: The built ConvModule. """ return ConvModule( in_channels, out_channels, kernel_size, stride=1, padding=kernel_size // 2, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None, with_spectral_norm=with_spectral_norm) @MODELS.register_module() class ResNetDec(BaseModule): """ResNet decoder for image matting. This class is adopted from https://github.com/Yaoyi-Li/GCA-Matting. Args: block (str): Type of residual block. Currently only `BasicBlockDec` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Channel num of input features. kernel_size (int): Kernel size of the conv layers in the decoder. conv_cfg (dict): dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. with_spectral_norm (bool): Whether use spectral norm after conv. Default: False. late_downsample (bool): Whether to adopt late downsample strategy, Default: False. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, block, layers, in_channels, kernel_size=3, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict( type='LeakyReLU', negative_slope=0.2, inplace=True), with_spectral_norm=False, late_downsample=False, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) if block == 'BasicBlockDec': block = BasicBlockDec else: raise NotImplementedError(f'{block} is not implemented.') self.kernel_size = kernel_size self.inplanes = in_channels self.midplanes = 64 if late_downsample else 32 self.layer1 = self._make_layer(block, 256, layers[0], conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer2 = self._make_layer(block, 128, layers[1], conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer3 = self._make_layer(block, 64, layers[2], conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer4 = self._make_layer(block, self.midplanes, layers[3], conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.conv1 = ConvModule( self.midplanes, 32, 4, stride=2, padding=1, conv_cfg=dict(type='Deconv'), norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) self.conv2 = ConvModule( 32, 1, self.kernel_size, padding=self.kernel_size // 2, act_cfg=None) def init_weights(self): """Init weights for the module.""" if self.init_cfg is not None: super().init_weights() else: for m in self.modules(): if isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): constant_init(m.weight, 1) constant_init(m.bias, 0) # Zero-initialize the last BN in each residual branch, so that the # residual branch starts with zeros, and each residual block behaves # like an identity. This improves the model by 0.2~0.3% according to # https://arxiv.org/abs/1706.02677 for m in self.modules(): if isinstance(m, BasicBlockDec): constant_init(m.conv2.bn.weight, 0) def _make_layer(self, block, planes, num_blocks, conv_cfg, norm_cfg, act_cfg, with_spectral_norm): upsample = nn.Sequential( nn.UpsamplingNearest2d(scale_factor=2), ConvModule( self.inplanes, planes * block.expansion, 1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None, with_spectral_norm=with_spectral_norm)) layers = [ block( self.inplanes, planes, kernel_size=self.kernel_size, stride=2, interpolation=upsample, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) ] self.inplanes = planes * block.expansion for _ in range(1, num_blocks): layers.append( block( self.inplanes, planes, kernel_size=self.kernel_size, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm)) return nn.Sequential(*layers) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.conv1(x) x = self.conv2(x) return x @MODELS.register_module() class ResShortcutDec(ResNetDec): """ResNet decoder for image matting with shortcut connection. :: feat1 --------------------------- conv2 --- out | feat2 ---------------------- conv1 | feat3 ----------------- layer4 | feat4 ------------ layer3 | feat5 ------- layer2 | out --- layer1 Args: block (str): Type of residual block. Currently only `BasicBlockDec` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Channel number of input features. kernel_size (int): Kernel size of the conv layers in the decoder. conv_cfg (dict): Dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. late_downsample (bool): Whether to adopt late downsample strategy, Default: False. """ def forward(self, inputs): """Forward function of resnet shortcut decoder. Args: inputs (dict): Output dictionary of the ResNetEnc containing: - out (Tensor): Output of the ResNetEnc. - feat1 (Tensor): Shortcut connection from input image. - feat2 (Tensor): Shortcut connection from conv2 of ResNetEnc. - feat3 (Tensor): Shortcut connection from layer1 of ResNetEnc. - feat4 (Tensor): Shortcut connection from layer2 of ResNetEnc. - feat5 (Tensor): Shortcut connection from layer3 of ResNetEnc. Returns: Tensor: Output tensor. """ feat1 = inputs['feat1'] feat2 = inputs['feat2'] feat3 = inputs['feat3'] feat4 = inputs['feat4'] feat5 = inputs['feat5'] x = inputs['out'] x = self.layer1(x) + feat5 x = self.layer2(x) + feat4 x = self.layer3(x) + feat3 x = self.layer4(x) + feat2 x = self.conv1(x) + feat1 x = self.conv2(x) return x @MODELS.register_module() class ResGCADecoder(ResShortcutDec): """ResNet decoder with shortcut connection and gca module. :: feat1 ---------------------------------------- conv2 --- out | feat2 ----------------------------------- conv1 | feat3 ------------------------------ layer4 | feat4, img_feat -- gca_module - layer3 | feat5 ------- layer2 | out --- layer1 * gca module also requires unknown tensor generated by trimap which is \ ignored in the above graph. Args: block (str): Type of residual block. Currently only `BasicBlockDec` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Channel number of input features. kernel_size (int): Kernel size of the conv layers in the decoder. conv_cfg (dict): Dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. with_spectral_norm (bool): Whether use spectral norm. Default: False. late_downsample (bool): Whether to adopt late downsample strategy, Default: False. """ def __init__(self, block, layers, in_channels, kernel_size=3, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict( type='LeakyReLU', negative_slope=0.2, inplace=True), with_spectral_norm=False, late_downsample=False): super().__init__(block, layers, in_channels, kernel_size, conv_cfg, norm_cfg, act_cfg, with_spectral_norm, late_downsample) self.gca = GCAModule(128, 128) def forward(self, inputs): """Forward function of resnet shortcut decoder. Args: inputs (dict): Output dictionary of the ResGCAEncoder containing: - out (Tensor): Output of the ResGCAEncoder. - feat1 (Tensor): Shortcut connection from input image. - feat2 (Tensor): Shortcut connection from conv2 of \ ResGCAEncoder. - feat3 (Tensor): Shortcut connection from layer1 of \ ResGCAEncoder. - feat4 (Tensor): Shortcut connection from layer2 of \ ResGCAEncoder. - feat5 (Tensor): Shortcut connection from layer3 of \ ResGCAEncoder. - img_feat (Tensor): Image feature extracted by guidance head. - unknown (Tensor): Unknown tensor generated by trimap. Returns: Tensor: Output tensor. """ img_feat = inputs['img_feat'] unknown = inputs['unknown'] feat1 = inputs['feat1'] feat2 = inputs['feat2'] feat3 = inputs['feat3'] feat4 = inputs['feat4'] feat5 = inputs['feat5'] x = inputs['out'] x = self.layer1(x) + feat5 x = self.layer2(x) + feat4 x = self.gca(img_feat, x, unknown) x = self.layer3(x) + feat3 x = self.layer4(x) + feat2 x = self.conv1(x) + feat1 x = self.conv2(x) return x ================================================ FILE: mmagic/models/editors/gca/resgca_enc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule, build_activation_layer from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init from mmagic.registry import MODELS from .gca_module import GCAModule class BasicBlock(nn.Module): """Basic residual block. Args: in_channels (int): Input channels of the block. out_channels (int): Output channels of the block. kernel_size (int): Kernel size of the convolution layers. Default: 3. stride (int): Stride of the first conv of the block. Default: 1. interpolation (nn.Module, optional): Interpolation module for skip connection. Default: None. conv_cfg (dict): dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. with_spectral_norm (bool): Whether use spectral norm after conv. Default: False. """ expansion = 1 def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, interpolation=None, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU'), with_spectral_norm=False): super().__init__() assert stride in (1, 2), ( f'stride other than 1 and 2 is not implemented, got {stride}') assert stride != 2 or interpolation is not None, ( 'if stride is 2, interpolation should be specified') self.conv1 = self.build_conv1(in_channels, out_channels, kernel_size, stride, conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.conv2 = self.build_conv2(in_channels, out_channels, kernel_size, conv_cfg, norm_cfg, with_spectral_norm) self.interpolation = interpolation self.activation = build_activation_layer(act_cfg) self.stride = stride def build_conv1(self, in_channels, out_channels, kernel_size, stride, conv_cfg, norm_cfg, act_cfg, with_spectral_norm): """Build conv1 of the block. Args: in_channels (int): The input channels of the ConvModule. out_channels (int): The output channels of the ConvModule. kernel_size (int): The kernel size of the ConvModule. stride (int): The stride of the ConvModule. If stride is set to 2, then ``conv_cfg`` will be overwritten as ``dict(type='Deconv')`` and ``kernel_size`` will be overwritten as 4. conv_cfg (dict): The conv config of the ConvModule. norm_cfg (dict): The norm config of the ConvModule. act_cfg (dict): The activation config of the ConvModule. with_spectral_norm (bool): Whether use spectral norm. Returns: nn.Module: The built ConvModule. """ return ConvModule( in_channels, out_channels, kernel_size, stride=stride, padding=kernel_size // 2, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) def build_conv2(self, in_channels, out_channels, kernel_size, conv_cfg, norm_cfg, with_spectral_norm): """Build conv2 of the block. Args: in_channels (int): The input channels of the ConvModule. out_channels (int): The output channels of the ConvModule. kernel_size (int): The kernel size of the ConvModule. stride (int): The stride of the ConvModule. If stride is set to 2, then ``conv_cfg`` will be overwritten as ``dict(type='Deconv')`` and ``kernel_size`` will be overwritten as 4. conv_cfg (dict): The conv config of the ConvModule. norm_cfg (dict): The norm config of the ConvModule. act_cfg (dict): The activation config of the ConvModule. with_spectral_norm (bool): Whether use spectral norm. Returns: nn.Module: The built ConvModule. """ return ConvModule( out_channels, out_channels, kernel_size, stride=1, padding=kernel_size // 2, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None, with_spectral_norm=with_spectral_norm) def forward(self, x): """Forward function. Args: inputs (torch.Tensor): Input tensor. Returns: Tensor: Output tensor. """ identity = x out = self.conv1(x) out = self.conv2(out) if self.interpolation is not None: identity = self.interpolation(x) out += identity out = self.activation(out) return out @MODELS.register_module() class ResNetEnc(BaseModule): """ResNet encoder for image matting. This class is adopted from https://github.com/Yaoyi-Li/GCA-Matting. Implement and pre-train on ImageNet with the tricks from https://arxiv.org/abs/1812.01187 without the mix-up part. Args: block (str): Type of residual block. Currently only `BasicBlock` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Number of input channels. conv_cfg (dict): dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. with_spectral_norm (bool): Whether use spectral norm after conv. Default: False. late_downsample (bool): Whether to adopt late downsample strategy, Default: False. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, block, layers, in_channels, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU'), with_spectral_norm=False, late_downsample=False, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) if block == 'BasicBlock': block = BasicBlock else: raise NotImplementedError(f'{block} is not implemented.') self.inplanes = 64 self.midplanes = 64 if late_downsample else 32 start_stride = [1, 2, 1, 2] if late_downsample else [2, 1, 2, 1] self.conv1 = ConvModule( in_channels, 32, 3, stride=start_stride[0], padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) self.conv2 = ConvModule( 32, self.midplanes, 3, stride=start_stride[1], padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) self.conv3 = ConvModule( self.midplanes, self.inplanes, 3, stride=start_stride[2], padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) self.layer1 = self._make_layer(block, 64, layers[0], start_stride[3], conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer2 = self._make_layer(block, 128, layers[1], 2, conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer3 = self._make_layer(block, 256, layers[2], 2, conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.layer4 = self._make_layer(block, 512, layers[3], 2, conv_cfg, norm_cfg, act_cfg, with_spectral_norm) self.out_channels = 512 def init_weights(self): """Init weights for the module.""" if self.init_cfg is not None: super().init_weights() if self.init_cfg['type'] == 'Pretrained': # if pretrained weight is trained on 3-channel images, # initialize other channels with zeros self.conv1.conv.weight.data[:, 3:, :, :] = 0 else: for m in self.modules(): if isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): constant_init(m.weight, 1) constant_init(m.bias, 0) # Zero-initialize the last BN in each residual branch, so that the # residual branch starts with zeros, and each residual block # behaves like an identity. This improves the model by 0.2~0.3% # according to https://arxiv.org/abs/1706.02677 for m in self.modules(): if isinstance(m, BasicBlock): constant_init(m.conv2.bn.weight, 0) def _make_layer(self, block, planes, num_blocks, stride, conv_cfg, norm_cfg, act_cfg, with_spectral_norm): downsample = None if stride != 1: downsample = nn.Sequential( nn.AvgPool2d(2, stride), ConvModule( self.inplanes, planes * block.expansion, 1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None, with_spectral_norm=with_spectral_norm)) layers = [ block( self.inplanes, planes, stride=stride, interpolation=downsample, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm) ] self.inplanes = planes * block.expansion for _ in range(1, num_blocks): layers.append( block( self.inplanes, planes, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm)) return nn.Sequential(*layers) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: Tensor: Output tensor. """ x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) return x @MODELS.register_module() class ResShortcutEnc(ResNetEnc): """ResNet backbone for image matting with shortcut connection. :: image ---------------- shortcut[0] --- feat1 | conv1-conv2 ---------- shortcut[1] --- feat2 | conv3-layer1 --- shortcut[2] --- feat3 | layer2 -- shortcut[4] --- feat4 | layer3 - shortcut[5] --- feat5 | layer4 ---------------- out Baseline model of Natural Image Matting via Guided Contextual Attention https://arxiv.org/pdf/2001.04069.pdf. Args: block (str): Type of residual block. Currently only `BasicBlock` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Number of input channels. conv_cfg (dict): Dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. with_spectral_norm (bool): Whether use spectral norm after conv. Default: False. late_downsample (bool): Whether to adopt late downsample strategy. Default: False. order (tuple[str]): Order of `conv`, `norm` and `act` layer in shortcut convolution module. Default: ('conv', 'act', 'norm'). init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, block, layers, in_channels, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU'), with_spectral_norm=False, late_downsample=False, order=('conv', 'act', 'norm'), init_cfg: Optional[dict] = None): super().__init__( block, layers, in_channels, conv_cfg, norm_cfg, act_cfg, with_spectral_norm, late_downsample, init_cfg=init_cfg) # TODO: rename self.midplanes to self.mid_channels in ResNetEnc self.shortcut_in_channels = [in_channels, self.midplanes, 64, 128, 256] self.shortcut_out_channels = [32, self.midplanes, 64, 128, 256] self.shortcut = nn.ModuleList() for in_channel, out_channel in zip(self.shortcut_in_channels, self.shortcut_out_channels): self.shortcut.append( self._make_shortcut(in_channel, out_channel, conv_cfg, norm_cfg, act_cfg, order, with_spectral_norm)) def _make_shortcut(self, in_channels, out_channels, conv_cfg, norm_cfg, act_cfg, order, with_spectral_norm): return nn.Sequential( ConvModule( in_channels, out_channels, 3, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, order=order), ConvModule( out_channels, out_channels, 3, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, order=order)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: dict: Contains the output tensor and shortcut feature. """ out = self.conv1(x) x1 = self.conv2(out) out = self.conv3(x1) x2 = self.layer1(out) x3 = self.layer2(x2) x4 = self.layer3(x3) out = self.layer4(x4) feat1 = self.shortcut[0](x) feat2 = self.shortcut[1](x1) feat3 = self.shortcut[2](x2) feat4 = self.shortcut[3](x3) feat5 = self.shortcut[4](x4) return { 'out': out, 'feat1': feat1, 'feat2': feat2, 'feat3': feat3, 'feat4': feat4, 'feat5': feat5, } @MODELS.register_module() class ResGCAEncoder(ResShortcutEnc): """ResNet backbone with shortcut connection and gca module. :: image ---------------- shortcut[0] -------------- feat1 | conv1-conv2 ---------- shortcut[1] -------------- feat2 | conv3-layer1 ---- shortcut[2] -------------- feat3 | | image - guidance_conv ------------ img_feat | | layer2 --- gca_module - shortcut[4] - feat4 | layer3 -- shortcut[5] - feat5 | layer4 --------------- out * gca module also requires unknown tensor generated by trimap which is \ ignored in the above graph. Implementation of Natural Image Matting via Guided Contextual Attention https://arxiv.org/pdf/2001.04069.pdf. Args: block (str): Type of residual block. Currently only `BasicBlock` is implemented. layers (list[int]): Number of layers in each block. in_channels (int): Number of input channels. conv_cfg (dict): Dictionary to construct convolution layer. If it is None, 2d convolution will be applied. Default: None. norm_cfg (dict): Config dict for normalization layer. "BN" by default. act_cfg (dict): Config dict for activation layer, "ReLU" by default. late_downsample (bool): Whether to adopt late downsample strategy. Default: False. order (tuple[str]): Order of `conv`, `norm` and `act` layer in shortcut convolution module. Default: ('conv', 'act', 'norm'). init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, block, layers, in_channels, conv_cfg=None, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU'), with_spectral_norm=False, late_downsample=False, order=('conv', 'act', 'norm'), init_cfg: Optional[dict] = None): super().__init__( block, layers, in_channels, conv_cfg, norm_cfg, act_cfg, with_spectral_norm, late_downsample, order, init_cfg=init_cfg) assert in_channels in (4, 6), ( f'in_channels must be 4 or 6, but got {in_channels}') self.trimap_channels = in_channels - 3 guidance_in_channels = [3, 16, 32] guidance_out_channels = [16, 32, 128] guidance_head = [] for in_channel, out_channel in zip(guidance_in_channels, guidance_out_channels): guidance_head += [ ConvModule( in_channel, out_channel, 3, stride=2, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg, with_spectral_norm=with_spectral_norm, padding_mode='reflect', order=order) ] self.guidance_head = nn.Sequential(*guidance_head) self.gca = GCAModule(128, 128) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (N, C, H, W). Returns: dict: Contains the output tensor, shortcut feature and \ intermediate feature. """ out = self.conv1(x) x1 = self.conv2(out) out = self.conv3(x1) img_feat = self.guidance_head(x[:, :3, ...]) if self.trimap_channels == 3: unknown = x[:, 4:5, ...] else: unknown = x[:, 3:, ...].eq(1).float() # same as img_feat, downsample to 1/8 unknown = F.interpolate(unknown, scale_factor=1 / 8, mode='nearest') x2 = self.layer1(out) x3 = self.layer2(x2) x3 = self.gca(img_feat, x3, unknown) x4 = self.layer3(x3) out = self.layer4(x4) # shortcut block feat1 = self.shortcut[0](x) feat2 = self.shortcut[1](x1) feat3 = self.shortcut[2](x2) feat4 = self.shortcut[3](x3) feat5 = self.shortcut[4](x4) return { 'out': out, 'feat1': feat1, 'feat2': feat2, 'feat3': feat3, 'feat4': feat4, 'feat5': feat5, 'img_feat': img_feat, 'unknown': unknown } ================================================ FILE: mmagic/models/editors/ggan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .ggan import GGAN __all__ = ['GGAN'] ================================================ FILE: mmagic/models/editors/ggan/ggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Tuple import torch import torch.nn.functional as F from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseGAN @MODELS.register_module() class GGAN(BaseGAN): """Implementation of `Geometric GAN`. `_(GGAN). """ def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: r"""Get disc loss. GGAN use hinge loss to train the discriminator. .. math: L_{D} = -\mathbb{E}_{\left(x, y\right)\sim{p}_{data}} \left[\min\left(0, -1 + D\left(x, y\right)\right)\right] -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}}\left[\min \left(0, -1 - D\left(G\left(z\right), y\right)\right)\right] Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.relu(1 + disc_pred_fake).mean() losses_dict['loss_disc_real'] = F.relu(1 - disc_pred_real).mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake): r"""Get disc loss. GGAN use hinge loss to train the generator. .. math: L_{G} = -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}} D\left(G\left(z\right), y\right) Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/glean/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .glean_styleganv2 import GLEANStyleGANv2 __all__ = ['GLEANStyleGANv2'] ================================================ FILE: mmagic/models/editors/glean/glean_styleganv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.models.archs import PixelShufflePack from mmagic.models.utils import make_layer from mmagic.registry import MODELS from ..esrgan.rrdb_net import RRDB @MODELS.register_module() class GLEANStyleGANv2(BaseModule): r"""GLEAN (using StyleGANv2) architecture for super-resolution. Paper: GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution, CVPR, 2021 This method makes use of StyleGAN2 and hence the arguments mostly follow that in 'StyleGAN2v2Generator'. In StyleGAN2, we use a static architecture composing of a style mapping module and number of convolutional style blocks. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN CVPR2020. You can load pretrained model through passing information into ``pretrained`` argument. We have already offered official weights as follows: - stylegan2-ffhq-config-f: http://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-ffhq-config-f-official_20210327_171224-bce9310c.pth # noqa - stylegan2-horse-config-f: http://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-horse-config-f-official_20210327_173203-ef3e69ca.pth # noqa - stylegan2-car-config-f: http://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-car-config-f-official_20210327_172340-8cfe053c.pth # noqa - stylegan2-cat-config-f: http://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-cat-config-f-official_20210327_172444-15bc485b.pth # noqa - stylegan2-church-config-f: http://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-church-config-f-official_20210327_172657-1d42b7d1.pth # noqa If you want to load the ema model, you can just use following codes: .. code-block:: python # ckpt_http is one of the valid path from http source generator = StyleGANv2Generator(1024, 512, pretrained=dict( ckpt_path=ckpt_http, prefix='generator_ema')) Of course, you can also download the checkpoint in advance and set ``ckpt_path`` with local path. If you just want to load the original generator (not the ema model), please set the prefix with 'generator'. Note that our implementation allows to generate BGR image, while the original StyleGAN2 outputs RGB images by default. Thus, we provide ``bgr2rgb`` argument to convert the image space. Args: in_size (int): The size of the input image. out_size (int): The output size of the StyleGAN2 generator. img_channels (int): Number of channels of the input images. 3 for RGB image and 1 for grayscale image. Default: 3. rrdb_channels (int): Number of channels of the RRDB features. Default: 64. num_rrdbs (int): Number of RRDB blocks in the encoder. Default: 23. style_channels (int): The number of channels for style code. Default: 512. num_mlps (int, optional): The number of MLP layers. Defaults to 8. channel_multiplier (int, optional): The multiplier factor for the channel number. Defaults to 2. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 3, 3, 1]. lr_mlp (float, optional): The learning rate for the style mapping layer. Defaults to 0.01. default_style_mode (str, optional): The default mode of style mixing. In training, we adopt mixing style mode in default. However, in the evaluation, we use 'single' style mode. `['mix', 'single']` are currently supported. Defaults to 'mix'. eval_style_mode (str, optional): The evaluation mode of style mixing. Defaults to 'single'. mix_prob (float, optional): Mixing probability. The value should be in range of [0, 1]. Defaults to 0.9. init_cfg (dict, optional): Initialization config dict. Default: None. fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. bgr2rgb (bool, optional): Whether to flip the image channel dimension. Defaults to False. """ def __init__(self, in_size, out_size, img_channels=3, rrdb_channels=64, num_rrdbs=23, style_channels=512, num_mlps=8, channel_multiplier=2, blur_kernel=[1, 3, 3, 1], lr_mlp=0.01, default_style_mode='mix', eval_style_mode='single', mix_prob=0.9, init_cfg=None, fp16_enabled=False, bgr2rgb=False): super().__init__(init_cfg=init_cfg) # input size must be strictly smaller than output size if in_size >= out_size: raise ValueError('in_size must be smaller than out_size, but got ' f'{in_size} and {out_size}.') # latent bank (StyleGANv2), with weights being fixed self.generator = MODELS.build( dict( type='StyleGANv2Generator', out_size=out_size, style_channels=style_channels, num_mlps=num_mlps, channel_multiplier=channel_multiplier, blur_kernel=blur_kernel, lr_mlp=lr_mlp, default_style_mode=default_style_mode, eval_style_mode=eval_style_mode, mix_prob=mix_prob, fp16_enabled=fp16_enabled, bgr2rgb=bgr2rgb)) self.generator.requires_grad_(False) self.in_size = in_size self.style_channels = style_channels channels = self.generator.channels # encoder num_styles = int(np.log2(out_size)) * 2 - 2 encoder_res = [2**i for i in range(int(np.log2(in_size)), 1, -1)] self.encoder = nn.ModuleList() self.encoder.append( nn.Sequential( RRDBFeatureExtractor( img_channels, rrdb_channels, num_blocks=num_rrdbs), nn.Conv2d( rrdb_channels, channels[in_size], 3, 1, 1, bias=True), nn.LeakyReLU(negative_slope=0.2, inplace=True))) for res in encoder_res: in_channels = channels[res] if res > 4: out_channels = channels[res // 2] block = nn.Sequential( nn.Conv2d(in_channels, out_channels, 3, 2, 1, bias=True), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=True), nn.LeakyReLU(negative_slope=0.2, inplace=True)) else: block = nn.Sequential( nn.Conv2d(in_channels, in_channels, 3, 1, 1, bias=True), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Flatten(), nn.Linear(16 * in_channels, num_styles * style_channels)) self.encoder.append(block) # additional modules for StyleGANv2 self.fusion_out = nn.ModuleList() self.fusion_skip = nn.ModuleList() for res in encoder_res[::-1]: num_channels = channels[res] self.fusion_out.append( nn.Conv2d(num_channels * 2, num_channels, 3, 1, 1, bias=True)) self.fusion_skip.append( nn.Conv2d(num_channels + 3, 3, 3, 1, 1, bias=True)) # decoder decoder_res = [ 2**i for i in range(int(np.log2(in_size)), int(np.log2(out_size) + 1)) ] self.decoder = nn.ModuleList() for res in decoder_res: if res == in_size: in_channels = channels[res] else: in_channels = 2 * channels[res] if res < out_size: out_channels = channels[res * 2] self.decoder.append( PixelShufflePack( in_channels, out_channels, 2, upsample_kernel=3)) else: self.decoder.append( nn.Sequential( nn.Conv2d(in_channels, 64, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(64, img_channels, 3, 1, 1))) def forward(self, lq): """Forward function. Args: lq (Tensor): Input LR image with shape (n, c, h, w). Returns: Tensor: Output HR image. """ h, w = lq.shape[2:] if h != self.in_size or w != self.in_size: raise AssertionError( f'Spatial resolution must equal in_size ({self.in_size}).' f' Got ({h}, {w}).') # encoder feat = lq encoder_features = [] for block in self.encoder: feat = block(feat) encoder_features.append(feat) encoder_features = encoder_features[::-1] latent = encoder_features[0].view(lq.size(0), -1, self.style_channels) encoder_features = encoder_features[1:] # generator injected_noise = [ getattr(self.generator, f'injected_noise_{i}') for i in range(self.generator.num_injected_noises) ] # 4x4 stage out = self.generator.constant_input(latent) out = self.generator.conv1(out, latent[:, 0], noise=injected_noise[0]) skip = self.generator.to_rgb1(out, latent[:, 1]) _index = 1 # 8x8 ---> higher res generator_features = [] for up_conv, conv, noise1, noise2, to_rgb in zip( self.generator.convs[::2], self.generator.convs[1::2], injected_noise[1::2], injected_noise[2::2], self.generator.to_rgbs): # feature fusion by channel-wise concatenation if out.size(2) <= self.in_size: fusion_index = (_index - 1) // 2 feat = encoder_features[fusion_index] out = torch.cat([out, feat], dim=1) out = self.fusion_out[fusion_index](out) skip = torch.cat([skip, feat], dim=1) skip = self.fusion_skip[fusion_index](skip) # original StyleGAN operations out = up_conv(out, latent[:, _index], noise=noise1) out = conv(out, latent[:, _index + 1], noise=noise2) skip = to_rgb(out, latent[:, _index + 2], skip) # store features for decoder if out.size(2) > self.in_size: generator_features.append(out) _index += 2 # decoder hr = encoder_features[-1] for i, block in enumerate(self.decoder): if i > 0: hr = torch.cat([hr, generator_features[i - 1]], dim=1) hr = block(hr) return hr class RRDBFeatureExtractor(nn.Module): """Feature extractor composed of Residual-in-Residual Dense Blocks (RRDBs). It is equivalent to ESRGAN with the upsampling module removed. Args: in_channels (int): Channel number of inputs. Default: 3. mid_channels (int): Channel number of intermediate features. Default: 64 num_blocks (int): Block number in the trunk network. Default: 23. growth_channels (int): Channels for each growth. Default: 32. """ def __init__(self, in_channels=3, mid_channels=64, num_blocks=23, growth_channels=32): super().__init__() self.conv_first = nn.Conv2d(in_channels, mid_channels, 3, 1, 1) self.body = make_layer( RRDB, num_blocks, mid_channels=mid_channels, growth_channels=growth_channels) self.conv_body = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ feat = self.conv_first(x) return feat + self.conv_body(self.body(feat)) ================================================ FILE: mmagic/models/editors/global_local/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .gl_decoder import GLDecoder from .gl_dilation import GLDilationNeck from .gl_disc import GLDiscs from .gl_encoder import GLEncoder from .gl_encoder_decoder import GLEncoderDecoder from .gl_inpaintor import GLInpaintor __all__ = [ 'GLEncoder', 'GLDecoder', 'GLEncoderDecoder', 'GLDilationNeck', 'GLInpaintor', 'GLDiscs' ] ================================================ FILE: mmagic/models/editors/global_local/gl_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class GLDecoder(BaseModule): """Decoder used in Global&Local model. This implementation follows: Globally and locally Consistent Image Completion Args: in_channels (int): Channel number of input feature. norm_cfg (dict): Config dict to build norm layer. act_cfg (dict): Config dict for activation layer, "relu" by default. out_act (str): Output activation type, "clip" by default. Noted that in our implementation, we clip the output with range [-1, 1]. """ def __init__(self, in_channels=256, norm_cfg=None, act_cfg=dict(type='ReLU'), out_act='clip'): super().__init__() self.dec1 = ConvModule( in_channels, 256, kernel_size=3, stride=1, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec2 = ConvModule( 256, 256, kernel_size=3, stride=1, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec3 = ConvModule( 256, 128, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='Deconv'), norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec4 = ConvModule( 128, 128, kernel_size=3, stride=1, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec5 = ConvModule( 128, 64, kernel_size=4, stride=2, padding=1, conv_cfg=dict(type='Deconv'), norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec6 = ConvModule( 64, 32, kernel_size=3, stride=1, padding=1, norm_cfg=norm_cfg, act_cfg=act_cfg) self.dec7 = ConvModule( 32, 3, kernel_size=3, stride=1, padding=1, norm_cfg=None, act_cfg=None) if out_act == 'sigmoid': self.output_act = nn.Sigmoid() elif out_act == 'clip': self.output_act = partial(torch.clamp, min=-1, max=1.) else: raise ValueError( f'{out_act} activation for output has not be supported.') def forward(self, x): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ for i in range(7): x = getattr(self, f'dec{i + 1}')(x) x = self.output_act(x) return x ================================================ FILE: mmagic/models/editors/global_local/gl_dilation.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.archs import SimpleGatedConvModule from mmagic.registry import MODELS @MODELS.register_module() class GLDilationNeck(BaseModule): """Dilation Backbone used in Global&Local model. This implementation follows: Globally and locally Consistent Image Completion Args: in_channels (int): Channel number of input feature. conv_type (str): The type of conv module. In DeepFillv1 model, the `conv_type` should be 'conv'. In DeepFillv2 model, the `conv_type` should be 'gated_conv'. norm_cfg (dict): Config dict to build norm layer. act_cfg (dict): Config dict for activation layer, "relu" by default. kwargs (keyword arguments). """ _conv_type = dict(conv=ConvModule, gated_conv=SimpleGatedConvModule) def __init__(self, in_channels=256, conv_type='conv', norm_cfg=None, act_cfg=dict(type='ReLU'), **kwargs): super().__init__() conv_module = self._conv_type[conv_type] dilation_convs_ = [] for i in range(4): dilation_ = int(2**(i + 1)) dilation_convs_.append( conv_module( in_channels, in_channels, kernel_size=3, padding=dilation_, dilation=dilation_, stride=1, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs)) self.dilation_convs = nn.Sequential(*dilation_convs_) def forward(self, x): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ x = self.dilation_convs(x) return x ================================================ FILE: mmagic/models/editors/global_local/gl_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.models.archs import MultiLayerDiscriminator from mmagic.registry import MODELS @MODELS.register_module() class GLDiscs(BaseModule): """Discriminators in Global&Local. This discriminator contains a local discriminator and a global discriminator as described in the original paper: Globally and locally Consistent Image Completion Args: global_disc_cfg (dict): Config dict to build global discriminator. local_disc_cfg (dict): Config dict to build local discriminator. """ def __init__(self, global_disc_cfg, local_disc_cfg): super().__init__() self.global_disc = MultiLayerDiscriminator(**global_disc_cfg) self.local_disc = MultiLayerDiscriminator(**local_disc_cfg) self.fc = nn.Linear(2048, 1, bias=True) def forward(self, x): """Forward function. Args: x (tuple[torch.Tensor]): Contains global image and the local image patch. Returns: tuple[torch.Tensor]: Contains the prediction from discriminators \ in global image and local image patch. """ g_img, l_img = x g_pred = self.global_disc(g_img) l_pred = self.local_disc(l_img) pred = self.fc(torch.cat([g_pred, l_pred], dim=1)) return pred def init_weights(self): """Init weights for models.""" for m in self.modules(): # Here, we only initialize the module with fc layer since the # conv and norm layers has been initialized in `ConvModule`. if isinstance(m, nn.Linear): nn.init.normal_(m.weight.data, 0.0, 0.02) nn.init.constant_(m.bias.data, 0.0) self._is_init = True ================================================ FILE: mmagic/models/editors/global_local/gl_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class GLEncoder(BaseModule): """Encoder used in Global&Local model. This implementation follows: Globally and locally Consistent Image Completion Args: norm_cfg (dict): Config dict to build norm layer. act_cfg (dict): Config dict for activation layer, "relu" by default. """ def __init__(self, norm_cfg=None, act_cfg=dict(type='ReLU')): super().__init__() channel_list = [64, 128, 128, 256, 256, 256] kernel_size_list = [5, 3, 3, 3, 3, 3] stride_list = [1, 2, 1, 2, 1, 1] in_channels = 4 for i in range(6): ks = kernel_size_list[i] padding = (ks - 1) // 2 self.add_module( f'enc{i + 1}', ConvModule( in_channels, channel_list[i], kernel_size=ks, stride=stride_list[i], padding=padding, norm_cfg=norm_cfg, act_cfg=act_cfg)) in_channels = channel_list[i] def forward(self, x): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ for i in range(6): x = getattr(self, f'enc{i + 1}')(x) return x ================================================ FILE: mmagic/models/editors/global_local/gl_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class GLEncoderDecoder(BaseModule): """Encoder-Decoder used in Global&Local model. This implementation follows: Globally and locally Consistent Image Completion The architecture of the encoder-decoder is:\ (conv2d x 6) --> (dilated conv2d x 4) --> (conv2d or deconv2d x 7) Args: encoder (dict): Config dict to encoder. decoder (dict): Config dict to build decoder. dilation_neck (dict): Config dict to build dilation neck. """ def __init__(self, encoder=dict(type='GLEncoder'), decoder=dict(type='GLDecoder'), dilation_neck=dict(type='GLDilationNeck')): super().__init__() self.encoder = MODELS.build(encoder) self.decoder = MODELS.build(decoder) self.dilation_neck = MODELS.build(dilation_neck) # support fp16 self.fp16_enabled = False def forward(self, x): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ x = self.encoder(x) if isinstance(x, dict): x = x['out'] x = self.dilation_neck(x) x = self.decoder(x) return x ================================================ FILE: mmagic/models/editors/global_local/gl_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional import torch from mmagic.models.base_models import OneStageInpaintor from mmagic.models.utils import extract_around_bbox, extract_bbox_patch from mmagic.registry import MODELS from ...utils import set_requires_grad @MODELS.register_module() class GLInpaintor(OneStageInpaintor): """Inpaintor for global&local method. This inpaintor is implemented according to the paper: Globally and Locally Consistent Image Completion Importantly, this inpaintor is an example for using custom training schedule based on `OneStageInpaintor`. The training pipeline of global&local is as following: .. code-block:: python if cur_iter < iter_tc: update generator with only l1 loss else: update discriminator if cur_iter > iter_td: update generator with l1 loss and adversarial loss The new attribute `cur_iter` is added for recording current number of iteration. The `train_cfg` contains the setting of the training schedule: .. code-block:: python train_cfg = dict( start_iter=0, disc_step=1, iter_tc=90000, iter_td=100000 ) `iter_tc` and `iter_td` correspond to the notation :math:`T_C` and :math:`T_D` of the original paper. Args: generator (dict): Config for encoder-decoder style generator. disc (dict): Config for discriminator. loss_gan (dict): Config for adversarial loss. loss_gp (dict): Config for gradient penalty loss. loss_disc_shift (dict): Config for discriminator shift loss. loss_composed_percep (dict): Config for perceptural and style loss with composed image as input. loss_out_percep (dict): Config for perceptual and style loss with direct output as input. loss_l1_hole (dict): Config for l1 loss in the hole. loss_l1_valid (dict): Config for l1 loss in the valid region. loss_tv (dict): Config for total variation loss. train_cfg (dict): Configs for training scheduler. `disc_step` must be contained for indicates the discriminator updating steps in each training step. test_cfg (dict): Configs for testing scheduler. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, data_preprocessor: dict, encdec: dict, disc=None, loss_gan=None, loss_gp=None, loss_disc_shift=None, loss_composed_percep=None, loss_out_percep=False, loss_l1_hole=None, loss_l1_valid=None, loss_tv=None, train_cfg=None, test_cfg=None, init_cfg: Optional[dict] = None): super().__init__( data_preprocessor=data_preprocessor, encdec=encdec, disc=disc, loss_gan=loss_gan, loss_gp=loss_gp, loss_disc_shift=loss_disc_shift, loss_composed_percep=loss_composed_percep, loss_out_percep=loss_out_percep, loss_l1_hole=loss_l1_hole, loss_l1_valid=loss_l1_valid, loss_tv=loss_tv, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg) if self.train_cfg is not None: self.cur_iter = self.train_cfg.start_iter def generator_loss(self, fake_res, fake_img, fake_local, gt, mask, masked_img): """Forward function in generator training step. In this function, we mainly compute the loss items for generator with the given (fake_res, fake_img). In general, the `fake_res` is the direct output of the generator and the `fake_img` is the composition of direct output and ground-truth image. Args: fake_res (torch.Tensor): Direct output of the generator. fake_img (torch.Tensor): Composition of `fake_res` and ground-truth image. fake_local (torch.Tensor): Local image. gt (torch.Tensor): Ground-truth image. mask (torch.Tensor): Mask image. masked_img (torch.Tensor): Composition of mask image and ground-truth image. Returns: tuple[dict]: A tuple containing two dictionaries. The first one \ is the result dict, which contains the results computed \ within this function for visualization. The second one is the \ loss dict, containing loss items computed in this function. """ loss = dict() # if cur_iter <= iter_td, do not calculate adversarial loss if self.with_gan and self.cur_iter > self.train_cfg.iter_td: g_fake_pred = self.disc((fake_img, fake_local)) loss_g_fake = self.loss_gan(g_fake_pred, True, False) loss['loss_g_fake'] = loss_g_fake if self.with_l1_hole_loss: loss_l1_hole = self.loss_l1_hole(fake_res, gt, weight=mask) loss['loss_l1_hole'] = loss_l1_hole if self.with_l1_valid_loss: loss_l1_valid = self.loss_l1_valid(fake_res, gt, weight=1. - mask) loss['loss_l1_valid'] = loss_l1_valid res = dict( gt_img=gt.cpu(), masked_img=masked_img.cpu(), fake_res=fake_res.cpu(), fake_img=fake_img.cpu()) return res, loss def train_step(self, data: List[dict], optim_wrapper): """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. optimize discriminator (if in current schedule) 3. optimize generator (if in current schedule) If ``self.train_cfg.disc_step > 1``, the train step will contain multiple iterations for optimizing discriminator with different input data and sonly one iteration for optimizing generator after `disc_step` iterations for discriminator. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of \ samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} masked_img = batch_inputs # float gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() # PyTorch 2.0 could not compile 'data_samples.mask_bbox' # bbox_tensor = torch.LongTensor(data_samples.mask_bbox) bbox_tensor = torch.LongTensor(data_samples.metainfo['mask_bbox']) input_x = torch.cat([masked_img, mask], dim=1) fake_res = self.generator(input_x) fake_img = gt_img * (1. - mask) + fake_res * mask fake_local, bbox_new = extract_around_bbox(fake_img, bbox_tensor, self.train_cfg.local_size) gt_local = extract_bbox_patch(bbox_new, gt_img) fake_gt_local = torch.cat([fake_local, gt_local], dim=2) # if cur_iter > iter_tc, update discriminator if (self.train_cfg.disc_step > 0 and self.cur_iter > self.train_cfg.iter_tc): # set discriminator requires_grad as True set_requires_grad(self.disc, True) fake_data = (fake_img.detach(), fake_local.detach()) real_data = (gt_img, gt_local) disc_losses = self.forward_train_d(fake_data, False, True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].zero_grad() optim_wrapper['disc'].backward(loss_disc) disc_losses = self.forward_train_d(real_data, True, True) loss_disc, log_vars_d = self.parse_losses(disc_losses) log_vars.update(log_vars_d) optim_wrapper['disc'].backward(loss_disc) optim_wrapper['disc'].step() self.disc_step_count = (self.disc_step_count + 1) % self.train_cfg.disc_step # if cur_iter <= iter_td, do not update generator if (self.disc_step_count != 0 or self.cur_iter <= self.train_cfg.iter_td): results = dict( gt_img=gt_img.cpu(), masked_img=masked_img.cpu(), fake_res=fake_res.cpu(), fake_img=fake_img.cpu(), fake_gt_local=fake_gt_local.cpu()) # outputs = dict(**log_vars,**results) self.cur_iter += 1 return log_vars # set discriminators requires_grad as False to avoid extra computation. set_requires_grad(self.disc, False) # update generator if (self.cur_iter <= self.train_cfg.iter_tc or self.cur_iter > self.train_cfg.iter_td): results, g_losses = self.generator_loss(fake_res, fake_img, fake_local, gt_img, mask, masked_img) loss_g, log_vars_g = self.parse_losses(g_losses) log_vars.update(log_vars_g) optim_wrapper['generator'].zero_grad() optim_wrapper['generator'].backward(loss_g) optim_wrapper['generator'].step() results.update(fake_gt_local=fake_gt_local.cpu()) # outputs = dict(**log_vars,**results) self.cur_iter += 1 return log_vars ================================================ FILE: mmagic/models/editors/guided_diffusion/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .adm import AblatedDiffusionModel from .classifier import EncoderUNetModel __all__ = ['AblatedDiffusionModel', 'EncoderUNetModel'] ================================================ FILE: mmagic/models/editors/guided_diffusion/adm.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import List, Optional import mmengine import torch import torch.nn as nn import torch.nn.functional as F from mmengine import MessageHub from mmengine.model import BaseModel, is_model_wrapper from mmengine.optim import OptimWrapperDict from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from tqdm import tqdm from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, SampleList def classifier_grad(classifier, x, t, y=None, classifier_scale=1.0): """compute classification gradient to x.""" assert y is not None with torch.enable_grad(): x_in = x.detach().requires_grad_(True) timesteps = torch.ones_like(y) * t logits = classifier(x_in, timesteps) log_probs = F.log_softmax(logits, dim=-1) selected = log_probs[range(len(logits)), y.view(-1)] return torch.autograd.grad(selected.sum(), x_in)[0] * classifier_scale @MODELS.register_module('ADM') @MODELS.register_module('GuidedDiffusion') @MODELS.register_module() class AblatedDiffusionModel(BaseModel): """Guided diffusion Model. Args: data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. unet (ModelType): Config of denoising Unet. diffusion_scheduler (ModelType): Config of diffusion_scheduler scheduler. use_fp16 (bool): Whether to use fp16 for unet model. Defaults to False. classifier (ModelType): Config of classifier. Defaults to None. pretrained_cfgs (dict): Path Config for pretrained weights. Usually this is a dict contains module name and the corresponding ckpt path.Defaults to None. """ def __init__(self, data_preprocessor, unet, diffusion_scheduler, use_fp16=False, classifier=None, classifier_scale=1.0, rgb2bgr=False, pretrained_cfgs=None): super().__init__(data_preprocessor=data_preprocessor) self.unet = MODELS.build(unet) self.diffusion_scheduler = DIFFUSION_SCHEDULERS.build( diffusion_scheduler) if classifier: self.classifier = MODELS.build(classifier) else: self.classifier = None self.classifier_scale = classifier_scale if pretrained_cfgs: self.load_pretrained_models(pretrained_cfgs) if use_fp16: mmengine.print_log('Convert unet modules to floatpoint16') self.unet.convert_to_fp16() self.rgb2bgr = rgb2bgr def load_pretrained_models(self, pretrained_cfgs): """_summary_ Args: pretrained_cfgs (_type_): _description_ """ for key, ckpt_cfg in pretrained_cfgs.items(): prefix = ckpt_cfg.get('prefix', '') map_location = ckpt_cfg.get('map_location', 'cpu') strict = ckpt_cfg.get('strict', True) ckpt_path = ckpt_cfg.get('ckpt_path') if prefix == '': state_dict = torch.load(ckpt_path, map_location=map_location) else: state_dict = _load_checkpoint_with_prefix( prefix, ckpt_path, map_location) getattr(self, key).load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained {key} from {ckpt_path}') @property def device(self): """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device @torch.no_grad() def infer(self, scheduler_kwargs=None, init_image=None, batch_size=1, num_inference_steps=1000, labels=None, classifier_scale=0.0, show_progress=False): """_summary_ Args: init_image (_type_, optional): _description_. Defaults to None. batch_size (int, optional): _description_. Defaults to 1. num_inference_steps (int, optional): _description_. Defaults to 1000. labels (_type_, optional): _description_. Defaults to None. show_progress (bool, optional): _description_. Defaults to False. Returns: _type_: _description_ """ if scheduler_kwargs is not None: mmengine.print_log('Switch to infer diffusion scheduler!', 'current') infer_scheduler = DIFFUSION_SCHEDULERS.build(scheduler_kwargs) else: infer_scheduler = self.diffusion_scheduler # Sample gaussian noise to begin loop if init_image is None: image = torch.randn( (batch_size, self.get_module(self.unet, 'in_channels'), self.get_module(self.unet, 'image_size'), self.get_module(self.unet, 'image_size'))) else: image = init_image image = image.to(self.device) if isinstance(labels, int): labels = torch.tensor(labels).repeat(batch_size) elif labels is None: labels = torch.randint( low=0, high=self.get_module(self.unet, 'num_classes'), size=(batch_size, ), device=self.device) labels = labels.to(self.device) # set step values if num_inference_steps > 0: infer_scheduler.set_timesteps(num_inference_steps) timesteps = infer_scheduler.timesteps if show_progress and mmengine.dist.is_main_process(): timesteps = tqdm(timesteps) for t in timesteps: # 1. predicted model_output model_output = self.unet(image, t, label=labels)['sample'] # 2. compute previous image: x_t -> x_t-1 if classifier_scale > 0 and self.classifier is not None: cond_fn = classifier_grad cond_kwargs = dict( y=labels, classifier=self.classifier, classifier_scale=classifier_scale) else: cond_fn = None cond_kwargs = {} diffusion_scheduler_output = infer_scheduler.step( model_output, t, image, cond_fn=cond_fn, cond_kwargs=cond_kwargs) image = diffusion_scheduler_output['prev_sample'] if self.rgb2bgr: image = image[:, [2, 1, 0], ...] return {'samples': image} def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: """_summary_ Args: inputs (ForwardInputs): _description_ data_samples (Optional[list], optional): _description_. Defaults to None. mode (Optional[str], optional): _description_. Defaults to None. Returns: List[DataSample]: _description_ """ init_image = inputs.get('init_image', None) batch_size = inputs.get('num_batches', 1) sample_kwargs = inputs.get('sample_kwargs', dict()) labels = sample_kwargs.get('labels', None) num_inference_steps = sample_kwargs.get( 'num_inference_steps', self.diffusion_scheduler.num_train_timesteps) show_progress = sample_kwargs.get('show_progress', False) classifier_scale = sample_kwargs.get('classifier_scale', self.classifier_scale) outputs = self.infer( init_image=init_image, batch_size=batch_size, num_inference_steps=num_inference_steps, show_progress=show_progress, classifier_scale=classifier_scale) batch_sample_list = [] for idx in range(batch_size): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) if isinstance(outputs, dict): gen_sample.fake_img = outputs['samples'][idx] gen_sample.set_gt_label(labels[idx]) # Append input condition (noise and sample_kwargs) to # batch_sample_list if init_image is not None: gen_sample.noise = init_image[idx] gen_sample.sample_kwargs = deepcopy(sample_kwargs) batch_sample_list.append(gen_sample) return batch_sample_list def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor(data)`` and ``self(inputs, data_sample, mode=None)`` in order. Return the generated results which will be passed to evaluator. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: List[DataSample]: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs def train_step(self, data: dict, optim_wrapper: OptimWrapperDict): """_summary_ Args: data (dict): _description_ optim_wrapper (OptimWrapperDict): _description_ Returns: _type_: _description_ """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') # sampling x0 and timestep data = self.data_preprocessor(data) real_imgs = data['inputs'] timestep = self.diffusion_scheduler.sample_timestep() # calculating loss loss_dict = self.diffusion_scheduler.training_loss( self.unet, real_imgs, timestep) loss, log_vars = self._parse_losses(loss_dict) optim_wrapper['denoising'].update_params(loss) # update EMA if self.with_ema_denoising and (curr_iter + 1) >= self.ema_start: self.denoising_ema.update_parameters( self.denoising_ema. module if is_model_wrapper(self.denoising) else self.denoising) # if not update buffer, copy buffer from orig model if not self.denoising_ema.update_buffers: self.denoising_ema.sync_buffers( self.denoising.module if is_model_wrapper(self.denoising) else self.denoising) elif self.with_ema_denoising: # before ema, copy weights from orig self.denoising_ema.sync_parameters( self.denoising. module if is_model_wrapper(self.denoising) else self.denoising) return log_vars def get_module(self, model: nn.Module, module_name: str) -> nn.Module: """Get an inner module from model. Since we will wrapper DDP for some model, we have to judge whether the module can be indexed directly. Args: model (nn.Module): This model may wrapped with DDP or not. module_name (str): The name of specific module. Return: nn.Module: Returned sub module. """ module = model.module if hasattr(model, 'module') else model return getattr(module, module_name) ================================================ FILE: mmagic/models/editors/guided_diffusion/classifier.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from abc import abstractmethod import torch import torch.nn as nn import torch.nn.functional as F from mmagic.models.editors.ddpm.denoising_unet import (QKVAttention, QKVAttentionLegacy, convert_module_to_f16, convert_module_to_f32) from mmagic.registry import MODELS def checkpoint(func, inputs, params, flag): """Evaluate a function without caching intermediate activations, allowing for reduced memory at the expense of extra compute in the backward pass. :param func: the function to evaluate. :param inputs: the argument sequence to pass to `func`. :param params: a sequence of parameters `func` depends on but does not explicitly take as arguments. :param flag: if False, disable gradient checkpointing. """ if flag: args = tuple(inputs) + tuple(params) return CheckpointFunction.apply(func, len(inputs), *args) else: return func(*inputs) class CheckpointFunction(torch.autograd.Function): @staticmethod def forward(ctx, run_function, length, *args): ctx.run_function = run_function ctx.input_tensors = list(args[:length]) ctx.input_params = list(args[length:]) with torch.no_grad(): output_tensors = ctx.run_function(*ctx.input_tensors) return output_tensors @staticmethod def backward(ctx, *output_grads): ctx.input_tensors = [ x.detach().requires_grad_(True) for x in ctx.input_tensors ] with torch.enable_grad(): # Fixes a bug where the first op in run_function modifies the # Tensor storage in place, which is not allowed for detach()'d # Tensors. shallow_copies = [x.view_as(x) for x in ctx.input_tensors] output_tensors = ctx.run_function(*shallow_copies) input_grads = torch.autograd.grad( output_tensors, ctx.input_tensors + ctx.input_params, output_grads, allow_unused=True, ) del ctx.input_tensors del ctx.input_params del output_tensors return (None, None) + input_grads def timestep_embedding(timesteps, dim, max_period=10000): """Create sinusoidal timestep embeddings. :param timesteps: a 1-D Tensor of N indices, one per batch element. These may be fractional. :param dim: the dimension of the output. :param max_period: controls the minimum frequency of the embeddings. :return: an [N x dim] Tensor of positional embeddings. """ half = dim // 2 freqs = torch.exp(-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half).to(device=timesteps.device) args = timesteps[:, None].float() * freqs[None] embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) if dim % 2: embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1) return embedding def zero_module(module): """Zero out the parameters of a module and return it.""" for p in module.parameters(): p.detach().zero_() return module class Upsample(nn.Module): """An upsampling layer with an optional convolution. :param channels: channels in the inputs and outputs. :param use_conv: a bool determining if a convolution is applied. :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then upsampling occurs in the inner-two dimensions. """ def __init__(self, channels, use_conv, dims=2, out_channels=None): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.dims = dims if use_conv: self.conv = nn.Conv2d( self.channels, self.out_channels, 3, padding=1) def forward(self, x): """Forward function. Args: x (torch.Tensor): The tensor to upsample. Returns: torch.Tensor: The upsample results. """ assert x.shape[1] == self.channels if self.dims == 3: x = F.interpolate( x, (x.shape[2], x.shape[3] * 2, x.shape[4] * 2), mode='nearest') else: x = F.interpolate(x, scale_factor=2, mode='nearest') if self.use_conv: x = self.conv(x) return x class TimestepBlock(nn.Module): """Any module where forward() takes timestep embeddings as a second argument.""" @abstractmethod def forward(self, x, emb): """Apply the module to `x` given `emb` timestep embeddings.""" class AttentionBlock(nn.Module): """An attention block that allows spatial positions to attend to each other. Originally ported from here, but adapted to the N-d case. https://github.com/hojonathanho/diffusion/blob/1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66. """ def __init__( self, channels, num_heads=1, num_head_channels=-1, use_checkpoint=False, use_new_attention_order=False, ): super().__init__() self.channels = channels if num_head_channels == -1: self.num_heads = num_heads else: assert ( channels % num_head_channels == 0), f'q,k,v channels {channels} is not ' 'divisible by num_head_channels {num_head_channels}' self.num_heads = channels // num_head_channels self.use_checkpoint = use_checkpoint self.norm = normalization(channels) self.qkv = nn.Conv1d(channels, channels * 3, 1) if use_new_attention_order: # split qkv before split heads self.attention = QKVAttention(self.num_heads) else: # split heads before split qkv self.attention = QKVAttentionLegacy(self.num_heads) self.proj_out = zero_module(nn.Conv1d(channels, channels, 1)) def forward(self, x): """Forward function. This function support gradient checkpoint to save memory. Args: x (torch.Tensor): The input tensor for attention. Returns: torch.Tensor: The attention results """ return checkpoint(self._forward, (x, ), self.parameters(), True) def _forward(self, x): """Forward function of attention block. Args: x (torch.Tensor): The input tensor for attention. Returns: torch.Tensor: The attention results """ b, c, *spatial = x.shape x = x.reshape(b, c, -1) qkv = self.qkv(self.norm(x)) h = self.attention(qkv) h = self.proj_out(h) return (x + h).reshape(b, c, *spatial) class TimestepEmbedSequential(nn.Sequential, TimestepBlock): """A sequential module that passes timestep embeddings to the children that support it as an extra input.""" def forward(self, x, emb): """Forward function. This function support sequential forward with embedding input. Args: x (torch.Tensor): Input tensor to forward. emb (torch.Tensor): Input timestep embedding. Returns: torch.Tensor: The forward results. """ for layer in self: if isinstance(layer, TimestepBlock): x = layer(x, emb) else: x = layer(x) return x class GroupNorm32(nn.GroupNorm): def forward(self, x): """Forward group normalization. Args: x (torch.Tensor): The input tensor. Returns: torch.Tensor: Tensor after group norm. """ return super().forward(x.float()).type(x.dtype) def normalization(channels): """Make a standard normalization layer. :param channels: number of input channels. :return: an nn.Module for normalization. """ return GroupNorm32(32, channels) class Downsample(nn.Module): """A downsampling layer with an optional convolution. :param channels: channels in the inputs and outputs. :param use_conv: a bool determining if a convolution is applied. :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then downsampling occurs in the inner-two dimensions. """ def __init__(self, channels, use_conv, dims=2, out_channels=None): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.dims = dims stride = 2 if dims != 3 else (1, 2, 2) if use_conv: self.op = nn.Conv2d( self.channels, self.out_channels, 3, stride=stride, padding=1) else: assert self.channels == self.out_channels self.op = nn.AvgPool2d(kernel_size=stride, stride=stride) def forward(self, x): """Forward function for downsample. Args: x (torch.Tensor): The input tensor. Returns: torch.Tenor: Results after downsample. """ assert x.shape[1] == self.channels return self.op(x) class ResBlock(TimestepBlock): """A residual block that can optionally change the number of channels. :param channels: the number of input channels. :param emb_channels: the number of timestep embedding channels. :param dropout: the rate of dropout. :param out_channels: if specified, the number of out channels. :param use_conv: if True and out_channels is specified, use a spatial convolution instead of a smaller 1x1 convolution to change the channels in the skip connection. :param dims: determines if the signal is 1D, 2D, or 3D. :param use_checkpoint: if True, use gradient checkpointing on this module. :param up: if True, use this block for upsampling. :param down: if True, use this block for downsampling. """ def __init__( self, channels, emb_channels, dropout, out_channels=None, use_conv=False, use_scale_shift_norm=False, dims=2, use_checkpoint=False, up=False, down=False, ): super().__init__() self.channels = channels self.emb_channels = emb_channels self.dropout = dropout self.out_channels = out_channels or channels self.use_conv = use_conv self.use_checkpoint = use_checkpoint self.use_scale_shift_norm = use_scale_shift_norm self.in_layers = nn.Sequential( normalization(channels), nn.SiLU(), nn.Conv2d(channels, self.out_channels, 3, padding=1), ) self.updown = up or down if up: self.h_upd = Upsample(channels, False, dims) self.x_upd = Upsample(channels, False, dims) elif down: self.h_upd = Downsample(channels, False, dims) self.x_upd = Downsample(channels, False, dims) else: self.h_upd = self.x_upd = nn.Identity() self.emb_layers = nn.Sequential( nn.SiLU(), nn.Linear( emb_channels, 2 * self.out_channels if use_scale_shift_norm else self.out_channels, ), ) self.out_layers = nn.Sequential( normalization(self.out_channels), nn.SiLU(), nn.Dropout(p=dropout), zero_module( nn.Conv2d(self.out_channels, self.out_channels, 3, padding=1)), ) if self.out_channels == channels: self.skip_connection = nn.Identity() elif use_conv: self.skip_connection = nn.Conv2d( channels, self.out_channels, 3, padding=1) else: self.skip_connection = nn.Conv2d(channels, self.out_channels, 1) def forward(self, x, emb): """Apply the block to a Tensor, conditioned on a timestep embedding. :param x: an [N x C x ...] Tensor of features. :param emb: an [N x emb_channels] Tensor of timestep embeddings. :return: an [N x C x ...] Tensor of outputs. """ return checkpoint(self._forward, (x, emb), self.parameters(), self.use_checkpoint) def _forward(self, x, emb): """Forward function. Args: x (torch.Tensor): Input feature tensor to forward. emb (torch.Tensor): The timesteps embedding to forward. Returns: torch.Tensor: The forward results. """ if self.updown: in_rest, in_conv = self.in_layers[:-1], self.in_layers[-1] h = in_rest(x) h = self.h_upd(h) x = self.x_upd(x) h = in_conv(h) else: h = self.in_layers(x) emb_out = self.emb_layers(emb).type(h.dtype) while len(emb_out.shape) < len(h.shape): emb_out = emb_out[..., None] if self.use_scale_shift_norm: out_norm, out_rest = self.out_layers[0], self.out_layers[1:] scale, shift = torch.chunk(emb_out, 2, dim=1) h = out_norm(h) * (1 + scale) + shift h = out_rest(h) else: h = h + emb_out h = self.out_layers(h) return self.skip_connection(x) + h class AttentionPool2d(nn.Module): """Adapted from CLIP: https://github.com/openai/CLIP/blob/main/clip/model.py. """ def __init__( self, spacial_dim: int, embed_dim: int, num_heads_channels: int, output_dim: int = None, ): super().__init__() self.positional_embedding = nn.Parameter( torch.randn(embed_dim, spacial_dim**2 + 1) / embed_dim**0.5) self.qkv_proj = nn.Conv1d(embed_dim, 3 * embed_dim, 1) self.c_proj = nn.Conv1d(embed_dim, output_dim or embed_dim, 1) self.num_heads = embed_dim // num_heads_channels self.attention = QKVAttention(self.num_heads) def forward(self, x): """Forward function. Args: x (torch.Tensor): Input feature tensor to forward. Returns: torch.Tensor: The forward results. """ b, c, *_spatial = x.shape x = x.reshape(b, c, -1) # NC(HW) x = torch.cat([x.mean(dim=-1, keepdim=True), x], dim=-1) # NC(HW+1) x = x + self.positional_embedding[None, :, :].to(x.dtype) # NC(HW+1) x = self.qkv_proj(x) x = self.attention(x) x = self.c_proj(x) return x[:, :, 0] @MODELS.register_module() class EncoderUNetModel(nn.Module): """The half UNet model with attention and timestep embedding. For usage, see UNet. """ def __init__( self, image_size, in_channels, model_channels, out_channels, num_res_blocks, attention_resolutions, dropout=0, channel_mult=(1, 2, 4, 8), conv_resample=True, dims=2, use_checkpoint=False, use_fp16=False, num_heads=1, num_head_channels=-1, num_heads_upsample=-1, use_scale_shift_norm=False, resblock_updown=False, use_new_attention_order=False, pool='adaptive', ): super().__init__() if num_heads_upsample == -1: num_heads_upsample = num_heads self.in_channels = in_channels self.model_channels = model_channels self.out_channels = out_channels self.num_res_blocks = num_res_blocks self.attention_resolutions = attention_resolutions self.dropout = dropout self.channel_mult = channel_mult self.conv_resample = conv_resample self.use_checkpoint = use_checkpoint self.dtype = torch.float16 if use_fp16 else torch.float32 self.num_heads = num_heads self.num_head_channels = num_head_channels self.num_heads_upsample = num_heads_upsample time_embed_dim = model_channels * 4 self.time_embed = nn.Sequential( nn.Linear(model_channels, time_embed_dim), nn.SiLU(), nn.Linear(time_embed_dim, time_embed_dim), ) ch = int(channel_mult[0] * model_channels) self.input_blocks = nn.ModuleList([ TimestepEmbedSequential(nn.Conv2d(in_channels, ch, 3, padding=1)) ]) self._feature_size = ch input_block_chans = [ch] ds = 1 for level, mult in enumerate(channel_mult): for _ in range(num_res_blocks): layers = [ ResBlock( ch, time_embed_dim, dropout, out_channels=int(mult * model_channels), dims=dims, use_checkpoint=use_checkpoint, use_scale_shift_norm=use_scale_shift_norm, ) ] ch = int(mult * model_channels) if ds in attention_resolutions: layers.append( AttentionBlock( ch, use_checkpoint=use_checkpoint, num_heads=num_heads, num_head_channels=num_head_channels, use_new_attention_order=use_new_attention_order, )) self.input_blocks.append(TimestepEmbedSequential(*layers)) self._feature_size += ch input_block_chans.append(ch) if level != len(channel_mult) - 1: out_ch = ch self.input_blocks.append( TimestepEmbedSequential( ResBlock( ch, time_embed_dim, dropout, out_channels=out_ch, dims=dims, use_checkpoint=use_checkpoint, use_scale_shift_norm=use_scale_shift_norm, down=True, ) if resblock_updown else Downsample( ch, conv_resample, dims=dims, out_channels=out_ch)) ) ch = out_ch input_block_chans.append(ch) ds *= 2 self._feature_size += ch self.middle_block = TimestepEmbedSequential( ResBlock( ch, time_embed_dim, dropout, dims=dims, use_checkpoint=use_checkpoint, use_scale_shift_norm=use_scale_shift_norm, ), AttentionBlock( ch, use_checkpoint=use_checkpoint, num_heads=num_heads, num_head_channels=num_head_channels, use_new_attention_order=use_new_attention_order, ), ResBlock( ch, time_embed_dim, dropout, dims=dims, use_checkpoint=use_checkpoint, use_scale_shift_norm=use_scale_shift_norm, ), ) self._feature_size += ch self.pool = pool if pool == 'adaptive': self.out = nn.Sequential( normalization(ch), nn.SiLU(), nn.AdaptiveAvgPool2d((1, 1)), zero_module(nn.Conv2d(ch, out_channels, 1)), nn.Flatten(), ) elif pool == 'attention': assert num_head_channels != -1 self.out = nn.Sequential( normalization(ch), nn.SiLU(), AttentionPool2d((image_size // ds), ch, num_head_channels, out_channels), ) elif pool == 'spatial': self.out = nn.Sequential( nn.Linear(self._feature_size, 2048), nn.ReLU(), nn.Linear(2048, self.out_channels), ) elif pool == 'spatial_v2': self.out = nn.Sequential( nn.Linear(self._feature_size, 2048), normalization(2048), nn.SiLU(), nn.Linear(2048, self.out_channels), ) else: raise NotImplementedError(f'Unexpected {pool} pooling') def convert_to_fp16(self): """Convert the torso of the model to float16.""" self.input_blocks.apply(convert_module_to_f16) self.middle_block.apply(convert_module_to_f16) def convert_to_fp32(self): """Convert the torso of the model to float32.""" self.input_blocks.apply(convert_module_to_f32) self.middle_block.apply(convert_module_to_f32) def forward(self, x, timesteps): """Apply the model to an input batch. :param x: an [N x C x ...] Tensor of inputs. :param timesteps: a 1-D batch of timesteps. :return: an [N x K] Tensor of outputs. """ emb = self.time_embed( timestep_embedding(timesteps, self.model_channels)) results = [] h = x.type(self.dtype) for module in self.input_blocks: h = module(h, emb) if self.pool.startswith('spatial'): results.append(h.type(x.dtype).mean(dim=(2, 3))) h = self.middle_block(h, emb) if self.pool.startswith('spatial'): results.append(h.type(x.dtype).mean(dim=(2, 3))) h = torch.cat(results, axis=-1) return self.out(h) else: h = h.type(x.dtype) return self.out(h) ================================================ FILE: mmagic/models/editors/iconvsr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .iconvsr_net import IconVSRNet __all__ = ['IconVSRNet'] ================================================ FILE: mmagic/models/editors/iconvsr/iconvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from logging import WARNING import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine import MMLogger, print_log from mmengine.model import BaseModule from mmengine.runner import load_checkpoint from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import flow_warp, make_layer from mmagic.registry import MODELS from ..basicvsr.basicvsr_net import ResidualBlocksWithInputConv, SPyNet from ..edvr.edvr_net import PCDAlignment, TSAFusion @MODELS.register_module() class IconVSRNet(BaseModule): """IconVSR network structure for video super-resolution. Support only x4 upsampling. Paper: BasicVSR: The Search for Essential Components in Video Super-Resolution and Beyond, CVPR, 2021 Args: mid_channels (int): Channel number of the intermediate features. Default: 64. num_blocks (int): Number of residual blocks in each propagation branch. Default: 30. keyframe_stride (int): Number determining the keyframes. If stride=5, then the (0, 5, 10, 15, ...)-th frame will be the keyframes. Default: 5. padding (int): Number of frames to be padded at two ends of the sequence. 2 for REDS and 3 for Vimeo-90K. Default: 2. spynet_pretrained (str): Pre-trained model path of SPyNet. Default: None. edvr_pretrained (str): Pre-trained model path of EDVR (for refill). Default: None. """ def __init__(self, mid_channels=64, num_blocks=30, keyframe_stride=5, padding=2, spynet_pretrained=None, edvr_pretrained=None): super().__init__() self.mid_channels = mid_channels self.padding = padding self.keyframe_stride = keyframe_stride # optical flow network for alignment self.spynet = SPyNet(pretrained=spynet_pretrained) # information-refill self.edvr = EDVRFeatureExtractor( num_frames=padding * 2 + 1, center_frame_idx=padding, pretrained=edvr_pretrained) self.backward_fusion = nn.Conv2d( 2 * mid_channels, mid_channels, 3, 1, 1, bias=True) self.forward_fusion = nn.Conv2d( 2 * mid_channels, mid_channels, 3, 1, 1, bias=True) # propagation branches self.backward_resblocks = ResidualBlocksWithInputConv( mid_channels + 3, mid_channels, num_blocks) self.forward_resblocks = ResidualBlocksWithInputConv( 2 * mid_channels + 3, mid_channels, num_blocks) # upsample self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, 64, 2, upsample_kernel=3) self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1) self.conv_last = nn.Conv2d(64, 3, 3, 1, 1) self.img_upsample = nn.Upsample( scale_factor=4, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self._raised_warning = False def spatial_padding(self, lrs): """Apply padding spatially. Since the PCD module in EDVR requires that the resolution is a multiple of 4, we apply padding to the input LR images if their resolution is not divisible by 4. Args: lrs (Tensor): Input LR sequence with shape (n, t, c, h, w). Returns: Tensor: Padded LR sequence with shape (n, t, c, h_pad, w_pad). """ n, t, c, h, w = lrs.size() pad_h = (4 - h % 4) % 4 pad_w = (4 - w % 4) % 4 # padding lrs = lrs.view(-1, c, h, w) lrs = F.pad(lrs, [0, pad_w, 0, pad_h], mode='reflect') return lrs.view(n, t, c, h + pad_h, w + pad_w) def check_if_mirror_extended(self, lrs): """Check whether the input is a mirror-extended sequence. If mirror-extended, the i-th (i=0, ..., t-1) frame is equal to the (t-1-i)-th frame. Args: lrs (tensor): Input LR images with shape (n, t, c, h, w) """ self.is_mirror_extended = False if lrs.size(1) % 2 == 0: lrs_1, lrs_2 = torch.chunk(lrs, 2, dim=1) if torch.norm(lrs_1 - lrs_2.flip(1)) == 0: self.is_mirror_extended = True def compute_refill_features(self, lrs, keyframe_idx): """Compute keyframe features for information-refill. Since EDVR-M is used, padding is performed before feature computation. Args: lrs (Tensor): Input LR images with shape (n, t, c, h, w) keyframe_idx (list(int)): The indices specifying the keyframes. Return: dict(Tensor): The keyframe features. Each key corresponds to the indices in keyframe_idx. """ if self.padding == 2: lrs = [lrs[:, [4, 3]], lrs, lrs[:, [-4, -5]]] # padding elif self.padding == 3: lrs = [lrs[:, [6, 5, 4]], lrs, lrs[:, [-5, -6, -7]]] # padding lrs = torch.cat(lrs, dim=1) num_frames = 2 * self.padding + 1 feats_refill = {} for i in keyframe_idx: feats_refill[i] = self.edvr(lrs[:, i:i + num_frames].contiguous()) return feats_refill def compute_flow(self, lrs): """Compute optical flow using SPyNet for feature warping. Note that if the input is an mirror-extended sequence, 'flows_forward' is not needed, since it is equal to 'flows_backward.flip(1)'. Args: lrs (tensor): Input LR images with shape (n, t, c, h, w) Return: tuple(Tensor): Optical flow. 'flows_forward' corresponds to the flows used for forward-time propagation (current to previous). 'flows_backward' corresponds to the flows used for backward-time propagation (current to next). """ n, t, c, h, w = lrs.size() lrs_1 = lrs[:, :-1, :, :, :].reshape(-1, c, h, w) lrs_2 = lrs[:, 1:, :, :, :].reshape(-1, c, h, w) flows_backward = self.spynet(lrs_1, lrs_2).view(n, t - 1, 2, h, w) if self.is_mirror_extended: # flows_forward = flows_backward.flip(1) flows_forward = None else: flows_forward = self.spynet(lrs_2, lrs_1).view(n, t - 1, 2, h, w) return flows_forward, flows_backward def forward(self, lrs): """Forward function for IconVSR. Args: lrs (Tensor): Input LR tensor with shape (n, t, c, h, w). Returns: Tensor: Output HR tensor with shape (n, t, c, 4h, 4w). """ n, t, c, h_input, w_input = lrs.size() if (h_input < 64 or w_input < 64) and not self._raised_warning: print_log( f'{self.__class__.__name__} is designed for input ' 'larger than 64x64, but the resolution of current image ' f'is {h_input}x{w_input}. We recommend you to check your ' 'input.', 'current', WARNING) self._raised_warning = True # check whether the input is an extended sequence self.check_if_mirror_extended(lrs) lrs = self.spatial_padding(lrs) h, w = lrs.size(3), lrs.size(4) # get the keyframe indices for information-refill keyframe_idx = list(range(0, t, self.keyframe_stride)) if keyframe_idx[-1] != t - 1: keyframe_idx.append(t - 1) # the last frame must be a keyframe # compute optical flow and compute features for information-refill flows_forward, flows_backward = self.compute_flow(lrs) feats_refill = self.compute_refill_features(lrs, keyframe_idx) # backward-time propagation outputs = [] feat_prop = lrs.new_zeros(n, self.mid_channels, h, w) for i in range(t - 1, -1, -1): lr_curr = lrs[:, i, :, :, :] if i < t - 1: # no warping for the last timestep flow = flows_backward[:, i, :, :, :] feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1)) if i in keyframe_idx: feat_prop = torch.cat([feat_prop, feats_refill[i]], dim=1) feat_prop = self.backward_fusion(feat_prop) feat_prop = torch.cat([lr_curr, feat_prop], dim=1) feat_prop = self.backward_resblocks(feat_prop) outputs.append(feat_prop) outputs = outputs[::-1] # forward-time propagation and upsampling feat_prop = torch.zeros_like(feat_prop) for i in range(0, t): lr_curr = lrs[:, i, :, :, :] if i > 0: # no warping for the first timestep if flows_forward is not None: flow = flows_forward[:, i - 1, :, :, :] else: flow = flows_backward[:, -i, :, :, :] feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1)) if i in keyframe_idx: # information-refill feat_prop = torch.cat([feat_prop, feats_refill[i]], dim=1) feat_prop = self.forward_fusion(feat_prop) feat_prop = torch.cat([lr_curr, outputs[i], feat_prop], dim=1) feat_prop = self.forward_resblocks(feat_prop) out = self.lrelu(self.upsample1(feat_prop)) out = self.lrelu(self.upsample2(out)) out = self.lrelu(self.conv_hr(out)) out = self.conv_last(out) base = self.img_upsample(lr_curr) out += base outputs[i] = out return torch.stack(outputs, dim=1)[:, :, :, :4 * h_input, :4 * w_input] class EDVRFeatureExtractor(BaseModule): """EDVR feature extractor for information-refill in IconVSR. We use EDVR-M in IconVSR. To adopt pretrained models, please specify "pretrained". Paper: EDVR: Video Restoration with Enhanced Deformable Convolutional Networks. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_frames (int): Number of input frames. Default: 5. deform_groups (int): Deformable groups. Defaults: 8. num_blocks_extraction (int): Number of blocks for feature extraction. Default: 5. num_blocks_reconstruction (int): Number of blocks for reconstruction. Default: 10. center_frame_idx (int): The index of center frame. Frame counting from 0. Default: 2. with_tsa (bool): Whether to use TSA module. Default: True. pretrained (str): The pretrained model path. Default: None. """ def __init__(self, in_channels=3, out_channel=3, mid_channels=64, num_frames=5, deform_groups=8, num_blocks_extraction=5, num_blocks_reconstruction=10, center_frame_idx=2, with_tsa=True, pretrained=None): super().__init__() self.center_frame_idx = center_frame_idx self.with_tsa = with_tsa act_cfg = dict(type='LeakyReLU', negative_slope=0.1) self.conv_first = nn.Conv2d(in_channels, mid_channels, 3, 1, 1) self.feature_extraction = make_layer( ResidualBlockNoBN, num_blocks_extraction, mid_channels=mid_channels) # generate pyramid features self.feat_l2_conv1 = ConvModule( mid_channels, mid_channels, 3, 2, 1, act_cfg=act_cfg) self.feat_l2_conv2 = ConvModule( mid_channels, mid_channels, 3, 1, 1, act_cfg=act_cfg) self.feat_l3_conv1 = ConvModule( mid_channels, mid_channels, 3, 2, 1, act_cfg=act_cfg) self.feat_l3_conv2 = ConvModule( mid_channels, mid_channels, 3, 1, 1, act_cfg=act_cfg) # pcd alignment self.pcd_alignment = PCDAlignment( mid_channels=mid_channels, deform_groups=deform_groups) # fusion if self.with_tsa: self.fusion = TSAFusion( mid_channels=mid_channels, num_frames=num_frames, center_frame_idx=self.center_frame_idx) else: self.fusion = nn.Conv2d(num_frames * mid_channels, mid_channels, 1, 1) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=True, logger=logger) elif pretrained is not None: raise TypeError(f'"pretrained" must be a str or None. ' f'But received {type(pretrained)}.') def forward(self, x): """Forward function for EDVRFeatureExtractor. Args: x (Tensor): Input tensor with shape (n, t, 3, h, w). Returns: Tensor: Intermediate feature with shape (n, mid_channels, h, w). """ n, t, c, h, w = x.size() # extract LR features # L1 l1_feat = self.lrelu(self.conv_first(x.view(-1, c, h, w))) l1_feat = self.feature_extraction(l1_feat) # L2 l2_feat = self.feat_l2_conv2(self.feat_l2_conv1(l1_feat)) # L3 l3_feat = self.feat_l3_conv2(self.feat_l3_conv1(l2_feat)) l1_feat = l1_feat.view(n, t, -1, h, w) l2_feat = l2_feat.view(n, t, -1, h // 2, w // 2) l3_feat = l3_feat.view(n, t, -1, h // 4, w // 4) # pcd alignment ref_feats = [ # reference feature list l1_feat[:, self.center_frame_idx, :, :, :].clone(), l2_feat[:, self.center_frame_idx, :, :, :].clone(), l3_feat[:, self.center_frame_idx, :, :, :].clone() ] aligned_feat = [] for i in range(t): neighbor_feats = [ l1_feat[:, i, :, :, :].clone(), l2_feat[:, i, :, :, :].clone(), l3_feat[:, i, :, :, :].clone() ] aligned_feat.append(self.pcd_alignment(neighbor_feats, ref_feats)) aligned_feat = torch.stack(aligned_feat, dim=1) # (n, t, c, h, w) if self.with_tsa: feat = self.fusion(aligned_feat) else: aligned_feat = aligned_feat.view(n, -1, h, w) feat = self.fusion(aligned_feat) return feat ================================================ FILE: mmagic/models/editors/indexnet/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .indexnet import IndexNet from .indexnet_decoder import IndexedUpsample, IndexNetDecoder from .indexnet_encoder import (DepthwiseIndexBlock, HolisticIndexBlock, IndexNetEncoder) __all__ = [ 'IndexNet', 'IndexedUpsample', 'IndexNetEncoder', 'IndexNetDecoder', 'DepthwiseIndexBlock', 'HolisticIndexBlock' ] ================================================ FILE: mmagic/models/editors/indexnet/indexnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models.base_models import BaseMattor from mmagic.models.utils import get_unknown_tensor from mmagic.registry import MODELS @MODELS.register_module() class IndexNet(BaseMattor): """IndexNet matting model. This implementation follows: Indices Matter: Learning to Index for Deep Image Matting Args: data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. backbone (dict): Config of backbone. train_cfg (dict): Config of training. In 'train_cfg', 'train_backbone' should be specified. test_cfg (dict): Config of testing. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. loss_alpha (dict): Config of the alpha prediction loss. Default: None. loss_comp (dict): Config of the composition loss. Default: None. """ def __init__(self, data_preprocessor, backbone, loss_alpha=None, loss_comp=None, init_cfg=None, train_cfg=None, test_cfg=None): super().__init__( backbone=backbone, data_preprocessor=data_preprocessor, init_cfg=init_cfg, train_cfg=train_cfg, test_cfg=test_cfg) self.loss_alpha = ( MODELS.build(loss_alpha) if loss_alpha is not None else None) self.loss_comp = ( MODELS.build(loss_comp) if loss_comp is not None else None) def _forward(self, inputs): """Forward function. Args: inputs (torch.Tensor): Input tensor. Returns: Tensor: Output tensor. """ pred_alpha = self.backbone(inputs) return pred_alpha def _forward_test(self, inputs): """Forward function for testing IndexNet model. Args: inputs (torch.Tensor): batch input tensor. Returns: Tensor: Output tensor of model. """ return self._forward(inputs) def _forward_train(self, inputs, data_samples): """Forward function for training IndexNet model. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement]): data samples collated by :attr:`data_preprocessor`. Returns: dict: Contains the loss items and batch information. """ trimap = inputs[:, 3:, :, :] gt_alpha = data_samples.gt_alpha gt_fg = data_samples.gt_fg gt_bg = data_samples.gt_bg gt_merged = data_samples.gt_merged pred_alpha = self.backbone(inputs) weight = get_unknown_tensor(trimap, unknown_value=128 / 255) losses = dict() if self.loss_alpha is not None: losses['loss_alpha'] = self.loss_alpha(pred_alpha, gt_alpha, weight) if self.loss_comp is not None: losses['loss_comp'] = self.loss_comp(pred_alpha, gt_fg, gt_bg, gt_merged, weight) return losses ================================================ FILE: mmagic/models/editors/indexnet/indexnet_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import Optional import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmengine.model.weight_init import kaiming_init, normal_init from mmagic.models.archs import DepthwiseSeparableConvModule from mmagic.registry import MODELS class IndexedUpsample(BaseModule): """Indexed upsample module. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int, optional): Kernel size of the convolution layer. Defaults to 5. norm_cfg (dict, optional): Config dict for normalization layer. Defaults to dict(type='BN'). conv_module (ConvModule | DepthwiseSeparableConvModule, optional): Conv module. Defaults to ConvModule. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels, out_channels, kernel_size=5, norm_cfg=dict(type='BN'), conv_module=ConvModule, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) self.conv = conv_module( in_channels, out_channels, kernel_size, padding=(kernel_size - 1) // 2, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')) def init_weights(self): """Init weights for the module.""" if self.init_cfg is not None: super().init_weights() else: for m in self.modules(): if isinstance(m, nn.Conv2d): kaiming_init(m, mode='fan_in', nonlinearity='leaky_relu') def forward(self, x, shortcut, dec_idx_feat=None): """Forward function. Args: x (Tensor): Input feature map with shape (N, C, H, W). shortcut (Tensor): The shortcut connection with shape (N, C, H', W'). dec_idx_feat (Tensor, optional): The decode index feature map with shape (N, C, H', W'). Defaults to None. Returns: Tensor: Output tensor with shape (N, C, H', W'). """ if dec_idx_feat is not None: assert shortcut.dim() == 4, ( 'shortcut must be tensor with 4 dimensions') x = dec_idx_feat * F.interpolate(x, size=shortcut.shape[2:]) out = torch.cat((x, shortcut), dim=1) return self.conv(out) @MODELS.register_module() class IndexNetDecoder(BaseModule): """Decoder for IndexNet. Please refer to https://arxiv.org/abs/1908.00672. Args: in_channels (int): Input channels of the decoder. kernel_size (int, optional): Kernel size of the convolution layer. Defaults to 5. norm_cfg (None | dict, optional): Config dict for normalization layer. Defaults to dict(type='BN'). separable_conv (bool): Whether to use separable conv. Default: False. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels, kernel_size=5, norm_cfg=dict(type='BN'), separable_conv=False, init_cfg: Optional[dict] = None): # TODO: remove in_channels argument super().__init__(init_cfg=init_cfg) if separable_conv: conv_module = DepthwiseSeparableConvModule else: conv_module = ConvModule blocks_in_channels = [ in_channels * 2, 96 * 2, 64 * 2, 32 * 2, 24 * 2, 16 * 2, 32 * 2 ] blocks_out_channels = [96, 64, 32, 24, 16, 32, 32] self.decoder_layers = nn.ModuleList() for in_channel, out_channel in zip(blocks_in_channels, blocks_out_channels): self.decoder_layers.append( IndexedUpsample(in_channel, out_channel, kernel_size, norm_cfg, conv_module)) self.pred = nn.Sequential( conv_module( 32, 1, kernel_size, padding=(kernel_size - 1) // 2, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')), nn.Conv2d( 1, 1, kernel_size, padding=(kernel_size - 1) // 2, bias=False)) def init_weights(self): """Init weights for the module.""" if self.init_cfg is not None: super().init_weights() else: for m in self.modules(): if isinstance(m, nn.Conv2d): std = math.sqrt(2. / (m.out_channels * m.kernel_size[0]**2)) normal_init(m, mean=0, std=std) def forward(self, inputs): """Forward function. Args: inputs (dict): Output dict of IndexNetEncoder. Returns: Tensor: Predicted alpha matte of the current batch. """ shortcuts = reversed(inputs['shortcuts']) dec_idx_feat_list = reversed(inputs['dec_idx_feat_list']) out = inputs['out'] group = (self.decoder_layers, shortcuts, dec_idx_feat_list) for decode_layer, shortcut, dec_idx_feat in zip(*group): out = decode_layer(out, shortcut, dec_idx_feat) out = self.pred(out) return out ================================================ FILE: mmagic/models/editors/indexnet/indexnet_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial from typing import Optional import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init, xavier_init from mmengine.utils.dl_utils.parrots_wrapper import SyncBatchNorm from mmagic.models.archs import ASPP, DepthwiseSeparableConvModule from mmagic.registry import MODELS def build_index_block(in_channels, out_channels, kernel_size, stride=2, padding=0, groups=1, norm_cfg=dict(type='BN'), use_nonlinear=False, expansion=1): """Build an conv block for IndexBlock. Args: in_channels (int): The input channels of the block. out_channels (int): The output channels of the block. kernel_size (int): The kernel size of the block. stride (int, optional): The stride of the block. Defaults to 2. padding (int, optional): The padding of the block. Defaults to 0. groups (int, optional): The groups of the block. Defaults to 1. norm_cfg (dict, optional): The norm config of the block. Defaults to dict(type='BN'). use_nonlinear (bool, optional): Whether use nonlinearity in the block. If true, a ConvModule with kernel size 1 will be appended and an ``ReLU6`` nonlinearity will be added to the origin ConvModule. Defaults to False. expansion (int, optional): Expansion ratio of the middle channels. Effective when ``use_nonlinear`` is true. Defaults to 1. Returns: nn.Module: The built conv block. """ if use_nonlinear: return nn.Sequential( ConvModule( in_channels, in_channels * expansion, kernel_size, stride=stride, padding=padding, groups=groups, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')), ConvModule( in_channels * expansion, out_channels, 1, stride=1, padding=0, groups=groups, bias=False, norm_cfg=None, act_cfg=None)) return ConvModule( in_channels, out_channels, kernel_size, stride=stride, padding=padding, groups=groups, bias=False, norm_cfg=None, act_cfg=None) class HolisticIndexBlock(BaseModule): """Holistic Index Block. From https://arxiv.org/abs/1908.00672. Args: in_channels (int): Input channels of the holistic index block. norm_cfg (dict): Config dict for normalization layer. Default: dict(type='BN'). use_context (bool, optional): Whether use larger kernel size in index block. Refer to the paper for more information. Defaults to False. use_nonlinear (bool): Whether add a non-linear conv layer in the index block. Default: False. """ def __init__(self, in_channels, norm_cfg=dict(type='BN'), use_context=False, use_nonlinear=False): super().__init__() if use_context: kernel_size, padding = 4, 1 else: kernel_size, padding = 2, 0 self.index_block = build_index_block( in_channels, 4, kernel_size, stride=2, padding=padding, groups=1, norm_cfg=norm_cfg, use_nonlinear=use_nonlinear, expansion=2) self.sigmoid = nn.Sigmoid() self.softmax = nn.Softmax(dim=1) self.pixel_shuffle = nn.PixelShuffle(2) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape (N, C, H, W). Returns: tuple(Tensor): Encoder index feature and decoder index feature. """ x = self.index_block(x) # normalization y = self.sigmoid(x) z = self.softmax(y) # pixel shuffling enc_idx_feat = self.pixel_shuffle(z) dec_idx_feat = self.pixel_shuffle(y) return enc_idx_feat, dec_idx_feat class DepthwiseIndexBlock(BaseModule): """Depthwise index block. From https://arxiv.org/abs/1908.00672. Args: in_channels (int): Input channels of the holistic index block. norm_cfg (dict): Config dict for normalization layer. Default: dict(type='BN'). use_context (bool, optional): Whether use larger kernel size in index block. Refer to the paper for more information. Defaults to False. use_nonlinear (bool): Whether add a non-linear conv layer in the index blocks. Default: False. mode (str): Mode of index block. Should be 'o2o' or 'm2o'. In 'o2o' mode, the group of the conv layers is 1; In 'm2o' mode, the group of the conv layer is `in_channels`. """ def __init__(self, in_channels, norm_cfg=dict(type='BN'), use_context=False, use_nonlinear=False, mode='o2o'): super().__init__() groups = in_channels if mode == 'o2o' else 1 if use_context: kernel_size, padding = 4, 1 else: kernel_size, padding = 2, 0 self.index_blocks = nn.ModuleList() for _ in range(4): self.index_blocks.append( build_index_block( in_channels, in_channels, kernel_size, stride=2, padding=padding, groups=groups, norm_cfg=norm_cfg, use_nonlinear=use_nonlinear)) self.sigmoid = nn.Sigmoid() self.softmax = nn.Softmax(dim=2) self.pixel_shuffle = nn.PixelShuffle(2) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape (N, C, H, W). Returns: tuple(Tensor): Encoder index feature and decoder index feature. """ n, c, h, w = x.shape feature_list = [ _index_block(x).unsqueeze(2) for _index_block in self.index_blocks ] x = torch.cat(feature_list, dim=2) # normalization y = self.sigmoid(x) z = self.softmax(y) # pixel shuffling y = y.view(n, c * 4, h // 2, w // 2) z = z.view(n, c * 4, h // 2, w // 2) enc_idx_feat = self.pixel_shuffle(z) dec_idx_feat = self.pixel_shuffle(y) return enc_idx_feat, dec_idx_feat class InvertedResidual(BaseModule): """Inverted residual layer for indexnet encoder. It basically is a depthwise separable conv module. If `expand_ratio` is not one, then a conv module of kernel_size 1 will be inserted to change the input channels to `in_channels * expand_ratio`. Args: in_channels (int): Input channels of the layer. out_channels (int): Output channels of the layer. stride (int): Stride of the depthwise separable conv module. dilation (int): Dilation of the depthwise separable conv module. expand_ratio (float): Expand ratio of the input channels of the depthwise separable conv module. norm_cfg (dict | None): Config dict for normalization layer. use_res_connect (bool, optional): Whether use shortcut connection. Defaults to False. """ def __init__(self, in_channels, out_channels, stride, dilation, expand_ratio, norm_cfg, use_res_connect=False): super().__init__() assert stride in [1, 2], 'stride must 1 or 2' self.use_res_connect = use_res_connect self.kernel_size = 3 self.dilation = dilation if expand_ratio == 1: self.conv = DepthwiseSeparableConvModule( in_channels, out_channels, 3, stride=stride, dilation=dilation, norm_cfg=norm_cfg, dw_act_cfg=dict(type='ReLU6'), pw_act_cfg=None) else: hidden_dim = round(in_channels * expand_ratio) self.conv = nn.Sequential( ConvModule( in_channels, hidden_dim, 1, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')), DepthwiseSeparableConvModule( hidden_dim, out_channels, 3, stride=stride, dilation=dilation, norm_cfg=norm_cfg, dw_act_cfg=dict(type='ReLU6'), pw_act_cfg=None)) def pad(self, inputs, kernel_size, dilation): """Pad input tensor. Args: inputs (Tensor): Input tensor. kernel_size (int): Kernel size of conv layer. dilation (int): Dilation of conv layer. Returns: Tensor: Padded tensor """ effective_ksize = kernel_size + (kernel_size - 1) * (dilation - 1) left = (effective_ksize - 1) // 2 right = effective_ksize // 2 return F.pad(inputs, (left, right, left, right)) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape (N, C, H, W). Returns: Tensor: Output feature map. """ out = self.conv(self.pad(x, self.kernel_size, self.dilation)) if self.use_res_connect: out = out + x return out @MODELS.register_module() class IndexNetEncoder(BaseModule): """Encoder for IndexNet. Please refer to https://arxiv.org/abs/1908.00672. Args: in_channels (int, optional): Input channels of the encoder. out_stride (int, optional): Output stride of the encoder. For example, if `out_stride` is 32, the input feature map or image will be downsample to the 1/32 of original size. Defaults to 32. width_mult (int, optional): Width multiplication factor of channel dimension in MobileNetV2. Defaults to 1. index_mode (str, optional): Index mode of the index network. It must be one of {'holistic', 'o2o', 'm2o'}. If it is set to 'holistic', then Holistic index network will be used as the index network. If it is set to 'o2o' (or 'm2o'), when O2O (or M2O) Depthwise index network will be used as the index network. Defaults to 'm2o'. aspp (bool, optional): Whether use ASPP module to augment output feature. Defaults to True. norm_cfg (None | dict, optional): Config dict for normalization layer. Defaults to dict(type='BN'). freeze_bn (bool, optional): Whether freeze batch norm layer. Defaults to False. use_nonlinear (bool, optional): Whether use nonlinearity in index network. Refer to the paper for more information. Defaults to True. use_context (bool, optional): Whether use larger kernel size in index network. Refer to the paper for more information. Defaults to True. init_cfg (dict, optional): Initialization config dict. Default: None. Raises: ValueError: out_stride must 16 or 32. NameError: Supported index_mode are {'holistic', 'o2o', 'm2o'}. """ def __init__(self, in_channels, out_stride=32, width_mult=1, index_mode='m2o', aspp=True, norm_cfg=dict(type='BN'), freeze_bn=False, use_nonlinear=True, use_context=True, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) if out_stride not in [16, 32]: raise ValueError(f'out_stride must 16 or 32, got {out_stride}') self.out_stride = out_stride self.width_mult = width_mult # we name the index network in the paper index_block if index_mode == 'holistic': index_block = HolisticIndexBlock elif index_mode in ('o2o', 'm2o'): index_block = partial(DepthwiseIndexBlock, mode=index_mode) else: raise NameError('Unknown index block mode {}'.format(index_mode)) # default setting initial_channels = 32 inverted_residual_setting = [ # expand_ratio, input_chn, output_chn, num_blocks, stride, dilation [1, initial_channels, 16, 1, 1, 1], [6, 16, 24, 2, 2, 1], [6, 24, 32, 3, 2, 1], [6, 32, 64, 4, 2, 1], [6, 64, 96, 3, 1, 1], [6, 96, 160, 3, 2, 1], [6, 160, 320, 1, 1, 1], ] # update layer setting according to width_mult initial_channels = int(initial_channels * width_mult) for layer_setting in inverted_residual_setting: # update in_channels and out_channels layer_setting[1] = int(layer_setting[1] * self.width_mult) layer_setting[2] = int(layer_setting[2] * self.width_mult) if out_stride == 32: # It should be noted that layers 0 is not an InvertedResidual layer # but a ConvModule. Thus, the index of InvertedResidual layer in # downsampled_layers starts at 1. self.downsampled_layers = [0, 2, 3, 4, 6] else: # out_stride is 16 self.downsampled_layers = [0, 2, 3, 4] # if out_stride is 16, then increase the dilation of the last two # InvertedResidual layer to increase the receptive field inverted_residual_setting[5][5] = 2 inverted_residual_setting[6][5] = 2 # build the first layer self.layers = nn.ModuleList([ ConvModule( in_channels, initial_channels, 3, padding=1, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')) ]) # build bottleneck layers for layer_setting in inverted_residual_setting: self.layers.append(self._make_layer(layer_setting, norm_cfg)) # freeze encoder batch norm layers self.freeze_bn = freeze_bn # build index blocks self.index_layers = nn.ModuleList() for layer in self.downsampled_layers: # inverted_residual_setting begins at layer1, the in_channels # of layer1 is the out_channels of layer0 self.index_layers.append( index_block(inverted_residual_setting[layer][1], norm_cfg, use_context, use_nonlinear)) self.avg_pool = nn.AvgPool2d(2, stride=2) if aspp: dilation = (2, 4, 8) if out_stride == 32 else (6, 12, 18) self.dconv = ASPP( 320 * self.width_mult, 160, mid_channels=int(256 * self.width_mult), dilations=dilation, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6'), separable_conv=True) else: self.dconv = ConvModule( 320 * self.width_mult, 160, 1, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU6')) self.out_channels = 160 def _make_layer(self, layer_setting, norm_cfg): # expand_ratio, in_channels, out_channels, num_blocks, stride, dilation (expand_ratio, in_channels, out_channels, num_blocks, stride, dilation) = layer_setting # downsample is now implemented by index block. In those layers that # have downsampling originally, use stride of 1 in the first block and # decrease the dilation accordingly. dilation0 = max(dilation // 2, 1) if stride == 2 else dilation layers = [ InvertedResidual(in_channels, out_channels, 1, dilation0, expand_ratio, norm_cfg) ] in_channels = out_channels for _ in range(1, num_blocks): layers.append( InvertedResidual( in_channels, out_channels, 1, dilation, expand_ratio, norm_cfg, use_res_connect=True)) return nn.Sequential(*layers) def train(self, mode=True): """Set BatchNorm modules in the model to evaluation mode.""" super().train(mode) if mode and self.freeze_bn: for m in self.modules(): if isinstance(m, (nn.BatchNorm2d, SyncBatchNorm)): m.eval() def init_weights(self): """Init weights for the model. Initialization is based on self._init_cfg Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. """ if self.init_cfg is not None: super().init_weights() else: # Default initialization for m in self.modules(): if isinstance(m, nn.Conv2d): xavier_init(m) elif isinstance(m, nn.BatchNorm2d): constant_init(m, 1) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape (N, C, H, W). Returns: dict: Output tensor, shortcut feature and decoder index feature. """ dec_idx_feat_list = list() shortcuts = list() for i, layer in enumerate(self.layers): x = layer(x) if i in self.downsampled_layers: enc_idx_feat, dec_idx_feat = self.index_layers[ self.downsampled_layers.index(i)]( x) x = enc_idx_feat * x shortcuts.append(x) dec_idx_feat_list.append(dec_idx_feat) x = 4 * self.avg_pool(x) elif i != 7: shortcuts.append(x) dec_idx_feat_list.append(None) x = self.dconv(x) return { 'out': x, 'shortcuts': shortcuts, 'dec_idx_feat_list': dec_idx_feat_list } ================================================ FILE: mmagic/models/editors/inst_colorization/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .colorization_net import ColorizationNet from .fusion_net import FusionNet from .inst_colorization import InstColorization __all__ = [ 'InstColorization', 'ColorizationNet', 'FusionNet', ] ================================================ FILE: mmagic/models/editors/inst_colorization/color_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch def xyz2rgb(xyz): """Conversion images from xyz to rgb. Args: xyz (tensor): The images to be conversion Returns: out (tensor): The converted image """ r = 3.24048134 * xyz[:, 0, :, :] - 1.53715152 * xyz[:, 1, :, :] \ - 0.49853633 * xyz[:, 2, :, :] g = -0.96925495 * xyz[:, 0, :, :] + 1.87599 * xyz[:, 1, :, :] \ + .04155593 * xyz[:, 2, :, :] b = .05564664 * xyz[:, 0, :, :] - .20404134 * xyz[:, 1, :, :] \ + 1.05731107 * xyz[:, 2, :, :] # sometimes reaches a small negative number, which causes NaNs rgb = torch.cat((r[:, None, :, :], g[:, None, :, :], b[:, None, :, :]), dim=1) rgb = torch.max(rgb, torch.zeros_like(rgb)) mask = (rgb > .0031308).type(torch.FloatTensor) if rgb.is_cuda: mask = mask.cuda() rgb = (1.055 * (rgb**(1. / 2.4)) - 0.055) * mask + 12.92 * rgb * (1 - mask) return rgb def lab2xyz(lab): """Conversion images from lab to xyz. Args: lab (tensor): The images to be conversion Returns: out (tensor): The converted image """ y_int = (lab[:, 0, :, :] + 16.) / 116. x_int = (lab[:, 1, :, :] / 500.) + y_int z_int = y_int - (lab[:, 2, :, :] / 200.) if (z_int.is_cuda): z_int = torch.max(torch.Tensor((0, )).cuda(), z_int) else: z_int = torch.max(torch.Tensor((0, )), z_int) out = torch.cat( (x_int[:, None, :, :], y_int[:, None, :, :], z_int[:, None, :, :]), dim=1) mask = (out > .2068966).type(torch.FloatTensor) if (out.is_cuda): mask = mask.cuda() out = (out**3.) * mask + (out - 16. / 116.) / 7.787 * (1 - mask) sc = torch.Tensor((0.95047, 1., 1.08883))[None, :, None, None] sc = sc.to(out.device) out = out * sc return out def lab2rgb(lab_rs, color_data_opt): """Conversion images from lab to rgb. Args: lab_rs (tensor): The images to be conversion color_data_opt (dict): Config for image colorspace transformation. Include: l_norm, ab_norm, l_cent Returns: out (tensor): The converted image """ L = lab_rs[:, [0], :, :] * color_data_opt['l_norm'] + color_data_opt['l_cent'] AB = lab_rs[:, 1:, :, :] * color_data_opt['ab_norm'] lab = torch.cat((L, AB), dim=1) out = xyz2rgb(lab2xyz(lab)) return out def encode_ab_ind(data_ab, color_data_opt): """Encode ab value into an index. Args: data_ab: Nx2xHxW from [-1,1] color_data_opt: Config for image colorspace transformation. ab_max, ab_quant, ab_norm, ab_quant Returns: Nx1xHxW from [0,Q) """ A = 2 * color_data_opt['ab_max'] / color_data_opt['ab_quant'] + 1 data_ab_rs = torch.round( (data_ab * color_data_opt['ab_norm'] + color_data_opt['ab_max']) / color_data_opt['ab_quant']) # normalized bin number data_q = data_ab_rs[:, [0], :, :] * A + data_ab_rs[:, [1], :, :] return data_q def rgb2xyz(rgb): """Conversion images from rgb to xyz rgb from [0,1] xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423], [0.212671, 0.715160, 0.072169], [0.019334, 0.119193, 0.950227]]) Args: rgb (Tensor): image in rgb colorspace Returns: xyz (Tensor): image in xyz colorspace """ mask = (rgb > .04045).type(torch.FloatTensor) if (rgb.is_cuda): mask = mask.cuda() rgb = (((rgb + .055) / 1.055)**2.4) * mask + rgb / 12.92 * (1 - mask) x = .412453 * rgb[:, 0, :, :] + .357580 * rgb[:, 1, :, :] \ + .180423 * rgb[:, 2, :, :] y = .212671 * rgb[:, 0, :, :] + .715160 * rgb[:, 1, :, :] \ + .072169 * rgb[:, 2, :, :] z = .019334 * rgb[:, 0, :, :] + .119193 * rgb[:, 1, :, :] \ + .950227 * rgb[:, 2, :, :] out = torch.cat((x[:, None, :, :], y[:, None, :, :], z[:, None, :, :]), dim=1) return out def xyz2lab(xyz): """Conversion images from xyz to lab xyz from [0,1] factors: 0.95047, 1., 1.08883 Args: xyz (Tensor): image in xyz colorspace Returns: out (Tensor): Image in lab colorspace """ sc = torch.Tensor((0.95047, 1., 1.08883))[None, :, None, None] if (xyz.is_cuda): sc = sc.cuda() xyz_scale = xyz / sc mask = (xyz_scale > .008856).type(torch.FloatTensor) if (xyz_scale.is_cuda): mask = mask.cuda() xyz_int = xyz_scale**(1 / 3.) * mask + (7.787 * xyz_scale + 16. / 116.) * (1 - mask) L = 116. * xyz_int[:, 1, :, :] - 16. a = 500. * (xyz_int[:, 0, :, :] - xyz_int[:, 1, :, :]) b = 200. * (xyz_int[:, 1, :, :] - xyz_int[:, 2, :, :]) out = torch.cat((L[:, None, :, :], a[:, None, :, :], b[:, None, :, :]), dim=1) return out def rgb2lab(rgb, color_opt): """Conversion images from rgb to lab. Args: data_raw (tensor): The images to be conversion color_opt (dict): Config for image colorspace transformation. Include: ab_thresh, ab_norm, sample_PS, mask_cent Returns: out (tensor): The converted image """ lab = xyz2lab(rgb2xyz(rgb)) l_rs = (lab[:, [0], :, :] - color_opt['l_cent']) / color_opt['l_norm'] ab_rs = lab[:, 1:, :, :] / color_opt['ab_norm'] out = torch.cat((l_rs, ab_rs), dim=1) return out def get_colorization_data(data_raw, color_opt, num_points=None): """Conversion images from rgb to lab. Args: data_raw (tensor): The images to be conversion color_opt (dict): Config for image colorspace transformation. Include: ab_thresh, ab_norm, sample_PS, mask_cent Returns: results (dict): Output in add_color_patches_rand_gt """ if len(data_raw.shape) == 3: data_raw = data_raw.unsqueeze(0) data = {} data_lab = rgb2lab(data_raw, color_opt) data['A'] = data_lab[:, [ 0, ], :, :] data['B'] = data_lab[:, 1:, :, :] # mask out grayscale images if color_opt['ab_thresh'] > 0: thresh = 1. * color_opt['ab_thresh'] / color_opt['ab_norm'] mask = torch.sum( torch.abs( torch.max(torch.max(data['B'], dim=3)[0], dim=2)[0] - torch.min(torch.min(data['B'], dim=3)[0], dim=2)[0]), dim=1) >= thresh data['A'] = data['A'][mask, :, :, :] data['B'] = data['B'][mask, :, :, :] if torch.sum(mask) == 0: return None return add_color_patches_rand_gt( data, color_opt, p=color_opt['p'], num_points=num_points) def add_color_patches_rand_gt(data, color_opt, p=.125, num_points=None, use_avg=True, samp='normal'): """Add random color points sampled from ground truth based on: Number of points. - if num_points is 0, then sample from geometric distribution, drawn from probability p - if num_points > 0, then sample that number of points Location of points - if samp is 'normal', draw from N(0.5, 0.25) of image - otherwise, draw from U[0, 1] of image Args: data (tensor): The images to be conversion color_opt (dict): Config for image colorspace transformation Include: ab_thresh, ab_norm, sample_PS, mask_cent p (float): Sampling geometric distribution, 1.0 means no hints num_points (int): Certain number of points use_avg (bool): Whether to use the mean when add color point Default: True. samp (str): Geometric distribution or uniform distribution when sample location. Default: normal. Returns: results (dict): Result dict from :obj:``mmcv.BaseDataset``. """ N, C, H, W = data['B'].shape data['hint_B'] = torch.zeros_like(data['B']) data['mask_B'] = torch.zeros_like(data['A']) for nn in range(N): pp = 0 cont_cond = True while cont_cond: # draw from geometric if num_points is None: cont_cond = np.random.rand() < (1 - p) else: # add certain number of points cont_cond = pp < num_points # skip out of loop if condition not met if not cont_cond: continue # patch size P = np.random.choice(color_opt['sample_PS']) # sample location: geometric distribution if samp == 'normal': h = int( np.clip( np.random.normal((H - P + 1) / 2., (H - P + 1) / 4.), 0, H - P)) w = int( np.clip( np.random.normal((W - P + 1) / 2., (W - P + 1) / 4.), 0, W - P)) else: # uniform distribution h = np.random.randint(H - P + 1) w = np.random.randint(W - P + 1) # add color point if use_avg: data['hint_B'][nn, :, h:h + P, w:w + P] = torch.mean( torch.mean( data['B'][nn, :, h:h + P, w:w + P], dim=2, keepdim=True), dim=1, keepdim=True).view(1, C, 1, 1) else: data['hint_B'][nn, :, h:h + P, w:w + P] = \ data['B'][nn, :, h:h + P, w:w + P] data['mask_B'][nn, :, h:h + P, w:w + P] = 1 # increment counter pp += 1 data['mask_B'] -= color_opt['mask_cent'] return data ================================================ FILE: mmagic/models/editors/inst_colorization/colorization_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from .weight_layer import get_norm_layer @MODELS.register_module() class ColorizationNet(BaseModule): """Real-Time User-Guided Image Colorization with Learned Deep Priors. The backbone used for. https://arxiv.org/abs/1705.02999 Codes adapted from 'https://github.com/ericsujw/InstColorization.git' 'InstColorization/blob/master/models/networks.py#L108' Args: input_nc (int): input image channels output_nc (int): output image channels norm_type (str): instance normalization or batch normalization use_tanh (bool): Whether to use nn.Tanh() Default: True. classification (bool): backprop trunk using classification, otherwise use regression. Default: True """ def __init__(self, input_nc, output_nc, norm_type, use_tanh=True, classification=True): super().__init__() self.input_nc = input_nc self.output_nc = output_nc self.classification = classification norm_layer = get_norm_layer(norm_type) use_bias = True # Conv1 self.model1 = nn.Sequential( nn.Conv2d( input_nc, 64, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 64, 64, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(64), ) # Conv2 self.model2 = nn.Sequential( nn.Conv2d( 64, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(128), ) # Conv3 self.model3 = nn.Sequential( nn.Conv2d( 128, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(256), ) # Conv4 self.model4 = nn.Sequential( nn.Conv2d( 256, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(512), ) # Conv5 self.model5 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), norm_layer(512), ) # Conv6 self.model6 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), norm_layer(512), ) # Conv7 self.model7 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(512), ) # Conv8 self.model8up = nn.ConvTranspose2d( 512, 256, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model3short8 = nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias) self.model8 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(256), ) # Conv9 self.model9up = nn.ConvTranspose2d( 256, 128, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model2short9 = nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias) self.model9 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(128), ) # Conv10 self.model10up = nn.ConvTranspose2d( 128, 128, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model1short10 = nn.Conv2d( 64, 128, kernel_size=3, stride=1, padding=1, bias=use_bias) self.model10 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, dilation=1, stride=1, padding=1, bias=use_bias), nn.LeakyReLU(negative_slope=.2), ) # classification output self.model_class = nn.Conv2d( 256, 529, kernel_size=1, padding=0, dilation=1, stride=1, bias=use_bias) # regression output model_out = [ nn.Conv2d( 128, 2, kernel_size=1, padding=0, dilation=1, stride=1, bias=use_bias), ] if (use_tanh): model_out += [nn.Tanh()] self.model_out = nn.Sequential(*model_out) self.upsample4 = nn.Upsample(scale_factor=4, mode='nearest') self.softmax = nn.Softmax(dim=1) def forward(self, input_A, input_B, mask_B): """Forward function. Args: input_A (tensor): Channel of the image in lab color space input_B (tensor): Color patch mask_B (tensor): Color patch mask Returns: out_class (tensor): Classification output out_reg (tensor): Regression output feature_map (dict): The full-image feature """ conv1_2 = self.model1(torch.cat((input_A, input_B, mask_B), dim=1)) conv2_2 = self.model2(conv1_2[:, :, ::2, ::2]) conv3_3 = self.model3(conv2_2[:, :, ::2, ::2]) conv4_3 = self.model4(conv3_3[:, :, ::2, ::2]) conv5_3 = self.model5(conv4_3) conv6_3 = self.model6(conv5_3) conv7_3 = self.model7(conv6_3) conv8_up = self.model8up(conv7_3) + self.model3short8(conv3_3) conv8_3 = self.model8(conv8_up) if (self.classification): out_class = self.model_class(conv8_3) conv9_up = self.model9up(conv8_3.detach()) + self.model2short9( conv2_2.detach()) conv9_3 = self.model9(conv9_up) conv10_up = self.model10up(conv9_3) + self.model1short10( conv1_2.detach()) else: out_class = self.model_class(conv8_3.detach()) conv9_up = self.model9up(conv8_3) + self.model2short9(conv2_2) conv9_3 = self.model9(conv9_up) conv10_up = self.model10up(conv9_3) + self.model1short10(conv1_2) conv10_2 = self.model10(conv10_up) out_reg = self.model_out(conv10_2) feature_map = {} feature_map['conv1_2'] = conv1_2 feature_map['conv2_2'] = conv2_2 feature_map['conv3_3'] = conv3_3 feature_map['conv4_3'] = conv4_3 feature_map['conv5_3'] = conv5_3 feature_map['conv6_3'] = conv6_3 feature_map['conv7_3'] = conv7_3 feature_map['conv8_up'] = conv8_up feature_map['conv8_3'] = conv8_3 feature_map['conv9_up'] = conv9_up feature_map['conv9_3'] = conv9_3 feature_map['conv10_up'] = conv10_up feature_map['conv10_2'] = conv10_2 feature_map['out_reg'] = out_reg return (out_class, out_reg, feature_map) ================================================ FILE: mmagic/models/editors/inst_colorization/fusion_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from .weight_layer import WeightLayer, get_norm_layer @MODELS.register_module() class FusionNet(BaseModule): """Instance-aware Image Colorization. https://arxiv.org/abs/2005.10825 Codes adapted from 'https://github.com/ericsujw/InstColorization.git' 'InstColorization/blob/master/models/networks.py#L314' FusionNet: the full image model with weight layer for fusion. Args: input_nc (int): input image channels output_nc (int): output image channels norm_type (str): instance normalization or batch normalization use_tanh (bool): Whether to use nn.Tanh() Default: True. classification (bool): backprop trunk using classification, otherwise use regression. Default: True """ def __init__(self, input_nc, output_nc, norm_type, use_tanh=True, classification=True): super().__init__() self.input_nc = input_nc self.output_nc = output_nc self.classification = classification norm_layer = get_norm_layer(norm_type) use_bias = True # Conv1 self.model1 = nn.Sequential( nn.Conv2d( input_nc, 64, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 64, 64, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(64), ) self.weight_layer = WeightLayer(64) # Conv2 self.model2 = nn.Sequential( nn.Conv2d( 64, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(128), ) self.weight_layer2 = WeightLayer(128) # Conv3 self.model3 = nn.Sequential( nn.Conv2d( 128, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(256), ) self.weight_layer3 = WeightLayer(256) # Conv4 self.model4 = nn.Sequential( nn.Conv2d( 256, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(512), ) self.weight_layer4 = WeightLayer(512) # Conv5 self.model5 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), norm_layer(512), ) self.weight_layer5 = WeightLayer(512) # Conv6 self.model6 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, dilation=2, stride=1, padding=2, bias=use_bias), nn.ReLU(True), norm_layer(512), ) self.weight_layer6 = WeightLayer(512) # Conv7 self.model7 = nn.Sequential( nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 512, 512, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(512), ) self.weight_layer7 = WeightLayer(512) # Conv8 self.model8up = nn.ConvTranspose2d( 512, 256, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model3short8 = nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias) self.weight_layer8_1 = WeightLayer(256) self.model8 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), nn.Conv2d( 256, 256, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(256), ) self.weight_layer8_2 = WeightLayer(256) # Conv9 self.model9up = nn.ConvTranspose2d( 256, 128, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model2short9 = nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias) self.weight_layer9_1 = WeightLayer(128) self.model9 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, stride=1, padding=1, bias=use_bias), nn.ReLU(True), norm_layer(128), ) self.weight_layer9_2 = WeightLayer(128) # Conv10 self.model10up = nn.ConvTranspose2d( 128, 128, kernel_size=4, stride=2, padding=1, bias=use_bias) self.model1short10 = nn.Conv2d( 64, 128, kernel_size=3, stride=1, padding=1, bias=use_bias) self.weight_layer10_1 = WeightLayer(128) self.model10 = nn.Sequential( nn.ReLU(True), nn.Conv2d( 128, 128, kernel_size=3, dilation=1, stride=1, padding=1, bias=use_bias), nn.LeakyReLU(negative_slope=.2), ) self.weight_layer10_2 = WeightLayer(128) # classification output self.model_class = nn.Conv2d( 256, 529, kernel_size=1, padding=0, dilation=1, stride=1, bias=use_bias) # regression output model_out = [ nn.Conv2d( 128, 2, kernel_size=1, padding=0, dilation=1, stride=1, bias=use_bias), ] if (use_tanh): model_out += [nn.Tanh()] self.model_out = nn.Sequential(*model_out) self.weight_layerout = WeightLayer(2) self.upsample4 = nn.Upsample(scale_factor=4, mode='nearest') self.softmax = nn.Softmax(dim=1) def forward(self, input_A, input_B, mask_B, instance_feature, box_info_list): """Forward function. Args: input_A (tensor): Channel of the image in lab color space input_B (tensor): Color patch mask_B (tensor): Color patch mask instance_feature (dict): A bunch of instance features box_info_list (list): Bounding box information corresponding to the instance Returns: out_reg (tensor): Regression output """ conv1_2 = self.model1(torch.cat((input_A, input_B, mask_B), dim=1)) conv1_2 = self.weight_layer(instance_feature['conv1_2'], conv1_2, box_info_list[0]) conv2_2 = self.model2(conv1_2[:, :, ::2, ::2]) conv2_2 = self.weight_layer2(instance_feature['conv2_2'], conv2_2, box_info_list[1]) conv3_3 = self.model3(conv2_2[:, :, ::2, ::2]) conv3_3 = self.weight_layer3(instance_feature['conv3_3'], conv3_3, box_info_list[2]) conv4_3 = self.model4(conv3_3[:, :, ::2, ::2]) conv4_3 = self.weight_layer4(instance_feature['conv4_3'], conv4_3, box_info_list[3]) conv5_3 = self.model5(conv4_3) conv5_3 = self.weight_layer5(instance_feature['conv5_3'], conv5_3, box_info_list[3]) conv6_3 = self.model6(conv5_3) conv6_3 = self.weight_layer6(instance_feature['conv6_3'], conv6_3, box_info_list[3]) conv7_3 = self.model7(conv6_3) conv7_3 = self.weight_layer7(instance_feature['conv7_3'], conv7_3, box_info_list[3]) conv8_up = self.model8up(conv7_3) + self.model3short8(conv3_3) conv8_up = self.weight_layer8_1(instance_feature['conv8_up'], conv8_up, box_info_list[2]) conv8_3 = self.model8(conv8_up) conv8_3 = self.weight_layer8_2(instance_feature['conv8_3'], conv8_3, box_info_list[2]) conv9_up = self.model9up(conv8_3) + self.model2short9(conv2_2) conv9_up = self.weight_layer9_1(instance_feature['conv9_up'], conv9_up, box_info_list[1]) conv9_3 = self.model9(conv9_up) conv9_3 = self.weight_layer9_2(instance_feature['conv9_3'], conv9_3, box_info_list[1]) conv10_up = self.model10up(conv9_3) + self.model1short10(conv1_2) conv10_up = self.weight_layer10_1(instance_feature['conv10_up'], conv10_up, box_info_list[0]) conv10_2 = self.model10(conv10_up) conv10_2 = self.weight_layer10_2(instance_feature['conv10_2'], conv10_2, box_info_list[0]) out_reg = self.model_out(conv10_2) return out_reg ================================================ FILE: mmagic/models/editors/inst_colorization/inst_colorization.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Optional, Union import torch from mmengine.config import Config from mmengine.model import BaseModel from mmengine.optim import OptimWrapperDict from mmagic.registry import MODELS from mmagic.structures import DataSample from .color_utils import get_colorization_data, lab2rgb @MODELS.register_module() class InstColorization(BaseModel): """Colorization InstColorization method. This Colorization is implemented according to the paper: Instance-aware Image Colorization, CVPR 2020 Adapted from 'https://github.com/ericsujw/InstColorization.git' 'InstColorization/models/train_model' Copyright (c) 2020, Su, under MIT License. Args: data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. image_model (dict): Config for single image model instance_model (dict): Config for instance model fusion_model (dict): Config for fusion model color_data_opt (dict): Option for colorspace conversion which_direction (str): AtoB or BtoA loss (dict): Config for loss. init_cfg (str): Initialization config dict. Default: None. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. """ def __init__(self, data_preprocessor: Union[dict, Config], image_model, instance_model, fusion_model, color_data_opt, which_direction='AtoB', loss=None, init_cfg=None, train_cfg=None, test_cfg=None): super().__init__( init_cfg=init_cfg, data_preprocessor=data_preprocessor) # colorization networks # image_model: used to colorize a single image self.image_model = MODELS.build(image_model) # instance model: used to colorize cropped instance self.instance_model = MODELS.build(instance_model) # fusion model: input a single image with related instance features self.fusion_model = MODELS.build(fusion_model) self.color_data_opt = color_data_opt self.which_direction = which_direction self.train_cfg = train_cfg self.test_cfg = test_cfg def forward(self, inputs: torch.Tensor, data_samples: Optional[List[DataSample]] = None, mode: str = 'tensor', **kwargs): """Returns losses or predictions of training, validation, testing, and simple inference process. ``forward`` method of BaseModel is an abstract method, its subclasses must implement this method. Accepts ``inputs`` and ``data_samples`` processed by :attr:`data_preprocessor`, and returns results according to mode arguments. During non-distributed training, validation, and testing process, ``forward`` will be called by ``BaseModel.train_step``, ``BaseModel.val_step`` and ``BaseModel.val_step`` directly. During distributed data parallel training process, ``MMSeparateDistributedDataParallel.train_step`` will first call ``DistributedDataParallel.forward`` to enable automatic gradient synchronization, and then call ``forward`` to get training loss. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. mode (str): mode should be one of ``loss``, ``predict`` and ``tensor``. Default: 'tensor'. - ``loss``: Called by ``train_step`` and return loss ``dict`` used for logging - ``predict``: Called by ``val_step`` and ``test_step`` and return list of ``BaseDataElement`` results used for computing metric. - ``tensor``: Called by custom use to get ``Tensor`` type results. Returns: ForwardResults: - If ``mode == loss``, return a ``dict`` of loss tensor used for backward and logging. - If ``mode == predict``, return a ``list`` of :obj:`BaseDataElement` for computing metric and getting inference result. - If ``mode == tensor``, return a tensor or ``tuple`` of tensor or ``dict`` or tensor for custom use. """ if mode == 'tensor': return self.forward_tensor(inputs, data_samples, **kwargs) elif mode == 'predict': predictions = self.forward_inference(inputs, data_samples, **kwargs) predictions = self.convert_to_datasample(data_samples, predictions) return predictions elif mode == 'loss': return self.forward_train(inputs, data_samples, **kwargs) def convert_to_datasample(self, inputs, data_samples): """Add predictions and destructed inputs (if passed) to data samples. Args: inputs (Optional[torch.Tensor]): The input of model. Defaults to None. data_samples (List[DataSample]): The data samples loaded from dataloader. Returns: List[DataSample]: Modified data samples. """ for data_sample, output in zip(inputs, data_samples): data_sample.output = output return inputs def forward_train(self, inputs, data_samples=None, **kwargs): """Forward function for training.""" raise NotImplementedError( 'Instance Colorization has not supported training.') def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step function. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of samples and results for visualization. """ raise NotImplementedError( 'Instance Colorization has not supported training.') def forward_inference(self, inputs, data_samples=None, **kwargs): """Forward inference. Returns predictions of validation, testing. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: List[DataSample]: predictions. """ feats = self.forward_tensor(inputs, data_samples, **kwargs) feats = self.data_preprocessor.destruct(feats, data_samples) predictions = [] for idx in range(feats.shape[0]): pred_img = feats[idx].to('cpu') predictions.append( DataSample( pred_img=pred_img, metainfo=data_samples[idx].metainfo)) return predictions def forward_tensor(self, inputs, data_samples): """Forward function in tensor mode. Args: inputs (torch.Tensor): Input tensor. data_sample (dict): Dict contains data sample. Returns: dict: Dict contains output results. """ # prepare data assert len(data_samples) == 1, \ 'fusion model supports only one image due to different numbers '\ 'of instances of different images' full_img_data = get_colorization_data(inputs, self.color_data_opt) AtoB = self.which_direction == 'AtoB' # preprocess input for a single image full_real_A = full_img_data['A' if AtoB else 'B'] full_hint_B = full_img_data['hint_B'] full_mask_B = full_img_data['mask_B'] if not data_samples.empty_box[0]: # preprocess instance input cropped_img = data_samples.cropped_img[0] box_info_list = [ data_samples.box_info[0], data_samples.box_info_2x[0], data_samples.box_info_4x[0], data_samples.box_info_8x[0] ] cropped_data = get_colorization_data(cropped_img, self.color_data_opt) real_A = cropped_data['A' if AtoB else 'B'] hint_B = cropped_data['hint_B'] mask_B = cropped_data['mask_B'] # network forward _, output, feature_map = self.instance_model( real_A, hint_B, mask_B) output = self.fusion_model(full_real_A, full_hint_B, full_mask_B, feature_map, box_info_list) else: _, output, _ = self.image_model(full_real_A, full_hint_B, full_mask_B) output = [ full_real_A.type(torch.cuda.FloatTensor), output.type(torch.cuda.FloatTensor) ] output = torch.cat(output, dim=1) output = torch.clamp(lab2rgb(output, self.color_data_opt), 0.0, 1.0) return output ================================================ FILE: mmagic/models/editors/inst_colorization/weight_layer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import functools import torch from mmengine.model import BaseModule from torch import nn from mmagic.registry import MODELS def get_norm_layer(norm_type='instance'): """Gets the normalization layer. Args: norm_type (str): Type of the normalization layer. Returns: norm_layer (BatchNorm2d or InstanceNorm2d or None): normalization layer. Default: instance """ if norm_type == 'batch': norm_layer = functools.partial(nn.BatchNorm2d, affine=True) elif norm_type == 'instance': norm_layer = functools.partial(nn.InstanceNorm2d, affine=False) elif norm_type == 'none': norm_layer = None else: raise NotImplementedError('normalization layer [%s] is not found' % norm_type) return norm_layer @MODELS.register_module() class WeightLayer(BaseModule): """Weight layer of the fusion_net. A small neural network with three convolutional layers to predict full-image weight map and perinstance weight map. Args: input_ch (int): Number of channels in the input image. inner_ch (int): Number of channels produced by the convolution. Default: True """ def __init__(self, input_ch, inner_ch=16): super().__init__() self.simple_instance_conv = nn.Sequential( nn.Conv2d(input_ch, inner_ch, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.Conv2d(inner_ch, inner_ch, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.Conv2d(inner_ch, 1, kernel_size=3, stride=1, padding=1), nn.ReLU(True), ) self.simple_bg_conv = nn.Sequential( nn.Conv2d(input_ch, inner_ch, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.Conv2d(inner_ch, inner_ch, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.Conv2d(inner_ch, 1, kernel_size=3, stride=1, padding=1), nn.ReLU(True), ) self.normalize = nn.Softmax(1) def resize_and_pad(self, feauture_maps, info_array): """Resize the instance feature as well as the weight map to match the size of full-image and do zero padding on both of them. Args: feauture_maps (tensor): Feature map info_array (tensor): The bounding box Returns: feauture_maps (tensor): Feature maps after resize and padding """ feauture_maps = torch.nn.functional.interpolate( feauture_maps, size=(info_array[5], info_array[4]), mode='bilinear') feauture_maps = torch.nn.functional.pad(feauture_maps, (info_array[0], info_array[1], info_array[2], info_array[3]), 'constant', 0) return feauture_maps def forward(self, instance_feature, bg_feature, box_info): """Forward function. Args: instance_feature (tensor): Instance feature obtained from the colorization_net bg_feature (tensor): full-image feature box_info (tensor): The bounding box corresponding to the instance Returns: out (tensor): Fused feature """ mask_list = [] featur_map_list = [] mask_sum_for_pred = torch.zeros_like(bg_feature)[:1, :1] for i in range(instance_feature.shape[0]): tmp_crop = torch.unsqueeze(instance_feature[i], 0) conv_tmp_crop = self.simple_instance_conv(tmp_crop) pred_mask = self.resize_and_pad(conv_tmp_crop, box_info[i]) tmp_crop = self.resize_and_pad(tmp_crop, box_info[i]) mask = torch.zeros_like(bg_feature)[:1, :1] mask[0, 0, box_info[i][2]:box_info[i][2] + box_info[i][5], box_info[i][0]:box_info[i][0] + box_info[i][4]] = 1.0 device = mask.device mask = mask.type(torch.FloatTensor).to(device) mask_sum_for_pred = torch.clamp(mask_sum_for_pred + mask, 0.0, 1.0) mask_list.append(pred_mask) featur_map_list.append(tmp_crop) pred_bg_mask = self.simple_bg_conv(bg_feature) mask_list.append(pred_bg_mask + (1 - mask_sum_for_pred) * 100000.0) mask_list = self.normalize(torch.cat(mask_list, 1)) mask_list_maskout = mask_list.clone() featur_map_list.append(bg_feature) featur_map_list = torch.cat(featur_map_list, 0) mask_list_maskout = mask_list_maskout.permute(1, 0, 2, 3).contiguous() out = featur_map_list * mask_list_maskout out = torch.sum(out, 0, keepdim=True) return out ================================================ FILE: mmagic/models/editors/liif/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .liif import LIIF from .liif_net import LIIFEDSRNet, LIIFRDNNet from .mlp_refiner import MLPRefiner __all__ = [ 'LIIF', 'LIIFEDSRNet', 'LIIFRDNNet', 'MLPRefiner', ] ================================================ FILE: mmagic/models/editors/liif/liif.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import torch from mmagic.models.base_models import BaseEditModel from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class LIIF(BaseEditModel): """LIIF model for single image super-resolution. Paper: Learning Continuous Image Representation with Local Implicit Image Function Args: generator (dict): Config for the generator. pixel_loss (dict): Config for the pixel loss. pretrained (str): Path for pretrained model. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. """ def forward_tensor(self, inputs, data_samples=None, **kwargs): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: result of simple forward. """ coord = torch.stack(data_samples.metainfo['coord']).to(inputs) cell = torch.stack(data_samples.metainfo['cell']).to(inputs) feats = self.generator(inputs, coord, cell, **kwargs) return feats def forward_inference(self, inputs, data_samples=None, **kwargs): """Forward inference. Returns predictions of validation, testing, and simple inference. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (BaseDataElement, optional): data samples collated by :attr:`data_preprocessor`. Returns: List[DataSample]: predictions. """ # NOTE: feats: shape [bz, N, 3] feats = self.forward_tensor(inputs, data_samples, test_mode=True) # reshape for eval, [bz, N, 3] -> [bz, 3, H, W] ih, iw = inputs.shape[-2:] # metainfo in stacked data sample is a list, fetch by indexing coord_count = data_samples.metainfo['coord'][0].shape[0] s = math.sqrt(coord_count / (ih * iw)) shape = [len(data_samples), round(ih * s), round(iw * s), 3] feats = feats.view(shape).permute(0, 3, 1, 2).contiguous() feats = self.data_preprocessor.destruct(feats, data_samples) predictions = DataSample(pred_img=feats.cpu()) return predictions ================================================ FILE: mmagic/models/editors/liif/liif_net.py ================================================ from abc import abstractmethod import torch import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from mmagic.utils import make_coord class LIIFNet(BaseModule): """LIIF net for single image super-resolution, CVPR, 2021. Paper: Learning Continuous Image Representation with Local Implicit Image Function The subclasses should define `generator` with `encoder` and `imnet`, and overwrite the function `gen_feature`. If `encoder` does not contain `mid_channels`, `__init__` should be overwrite. Args: encoder (dict): Config for the generator. imnet (dict): Config for the imnet. local_ensemble (bool): Whether to use local ensemble. Default: True. feat_unfold (bool): Whether to use feature unfold. Default: True. cell_decode (bool): Whether to use cell decode. Default: True. eval_bsize (int): Size of batched predict. Default: None. """ def __init__(self, encoder, imnet, local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=None): super().__init__() self.local_ensemble = local_ensemble self.feat_unfold = feat_unfold self.cell_decode = cell_decode self.eval_bsize = eval_bsize # model self.encoder = MODELS.build(encoder) imnet_in_dim = self.encoder.mid_channels if self.feat_unfold: imnet_in_dim *= 9 imnet_in_dim += 2 # attach coordinates if self.cell_decode: imnet_in_dim += 2 imnet['in_dim'] = imnet_in_dim self.imnet = MODELS.build(imnet) def forward(self, x, coord, cell, test_mode=False): """Forward function. Args: x: input tensor. coord (Tensor): coordinates tensor. cell (Tensor): cell tensor. test_mode (bool): Whether in test mode or not. Default: False. Returns: pred (Tensor): output of model. """ feature = self.gen_feature(x) if self.eval_bsize is None or not test_mode: pred = self.query_rgb(feature, coord, cell) else: pred = self.batched_predict(feature, coord, cell) return pred def query_rgb(self, feature, coord, cell=None): """Query RGB value of GT. Adapted from 'https://github.com/yinboc/liif.git' 'liif/models/liif.py' Copyright (c) 2020, Yinbo Chen, under BSD 3-Clause License. Args: feature (Tensor): encoded feature. coord (Tensor): coord tensor, shape (BHW, 2). cell (Tensor | None): cell tensor. Default: None. Returns: result (Tensor): (part of) output. """ if self.imnet is None: coord = coord.type(feature.type()) result = F.grid_sample( feature, coord.flip(-1).unsqueeze(1), mode='nearest', align_corners=False) result = result[:, :, 0, :].permute(0, 2, 1) return result if self.feat_unfold: feature = F.unfold( feature, 3, padding=1).view(feature.shape[0], feature.shape[1] * 9, feature.shape[2], feature.shape[3]) if self.local_ensemble: vx_lst = [-1, 1] vy_lst = [-1, 1] eps_shift = 1e-6 else: vx_lst, vy_lst, eps_shift = [0], [0], 0 # field radius (global: [-1, 1]) radius_x = 2 / feature.shape[-2] / 2 radius_y = 2 / feature.shape[-1] / 2 feat_coord = make_coord(feature.shape[-2:], flatten=False) \ .permute(2, 0, 1) \ .unsqueeze(0).expand(feature.shape[0], 2, *feature.shape[-2:]) feat_coord = feat_coord.to(coord) preds = [] areas = [] for vx in vx_lst: for vy in vy_lst: coord_ = coord.clone() coord_[:, :, 0] += vx * radius_x + eps_shift coord_[:, :, 1] += vy * radius_y + eps_shift coord_.clamp_(-1 + 1e-6, 1 - 1e-6) coord_ = coord_.type(feature.type()) query_feat = F.grid_sample( feature, coord_.flip(-1).unsqueeze(1), mode='nearest', align_corners=False)[:, :, 0, :] \ .permute(0, 2, 1) feat_coord = feat_coord.type(coord_.type()) query_coord = F.grid_sample( feat_coord, coord_.flip(-1).unsqueeze(1), mode='nearest', align_corners=False)[:, :, 0, :] \ .permute(0, 2, 1) rel_coord = coord - query_coord rel_coord[:, :, 0] *= feature.shape[-2] rel_coord[:, :, 1] *= feature.shape[-1] mid_tensor = torch.cat([query_feat, rel_coord], dim=-1) if self.cell_decode: rel_cell = cell.clone() rel_cell[:, :, 0] *= feature.shape[-2] rel_cell[:, :, 1] *= feature.shape[-1] mid_tensor = torch.cat([mid_tensor, rel_cell], dim=-1) bs, q = coord.shape[:2] pred = self.imnet(mid_tensor.view(bs * q, -1)).view(bs, q, -1) preds.append(pred) area = torch.abs(rel_coord[:, :, 0] * rel_coord[:, :, 1]) areas.append(area + 1e-9) total_area = torch.stack(areas).sum(dim=0) if self.local_ensemble: areas = areas[::-1] result = 0 for pred, area in zip(preds, areas): result = result + pred * (area / total_area).unsqueeze(-1) return result def batched_predict(self, x, coord, cell): """Batched predict. Args: x (Tensor): Input tensor. coord (Tensor): coord tensor. cell (Tensor): cell tensor. Returns: pred (Tensor): output of model. """ with torch.no_grad(): n = coord.shape[1] left = 0 preds = [] while left < n: right = min(left + self.eval_bsize, n) pred = self.query_rgb(x, coord[:, left:right, :], cell[:, left:right, :]) preds.append(pred) left = right pred = torch.cat(preds, dim=1) return pred @abstractmethod def gen_feature(self, x): """Generate feature. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ @MODELS.register_module() class LIIFEDSRNet(LIIFNet): """LIIF net based on EDSR. Paper: Learning Continuous Image Representation with Local Implicit Image Function Args: encoder (dict): Config for the generator. imnet (dict): Config for the imnet. local_ensemble (bool): Whether to use local ensemble. Default: True. feat_unfold (bool): Whether to use feature unfold. Default: True. cell_decode (bool): Whether to use cell decode. Default: True. eval_bsize (int): Size of batched predict. Default: None. """ def __init__(self, encoder, imnet, local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=None): super().__init__( encoder=encoder, imnet=imnet, local_ensemble=local_ensemble, feat_unfold=feat_unfold, cell_decode=cell_decode, eval_bsize=eval_bsize) self.conv_first = self.encoder.conv_first self.body = self.encoder.body self.conv_after_body = self.encoder.conv_after_body del self.encoder def gen_feature(self, x): """Generate feature. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.conv_first(x) res = self.body(x) res = self.conv_after_body(res) res += x return res @MODELS.register_module() class LIIFRDNNet(LIIFNet): """LIIF net based on RDN. Paper: Learning Continuous Image Representation with Local Implicit Image Function Args: encoder (dict): Config for the generator. imnet (dict): Config for the imnet. local_ensemble (bool): Whether to use local ensemble. Default: True. feat_unfold (bool): Whether to use feat unfold. Default: True. cell_decode (bool): Whether to use cell decode. Default: True. eval_bsize (int): Size of batched predict. Default: None. """ def __init__(self, encoder, imnet, local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=None): super().__init__( encoder=encoder, imnet=imnet, local_ensemble=local_ensemble, feat_unfold=feat_unfold, cell_decode=cell_decode, eval_bsize=eval_bsize) self.sfe1 = self.encoder.sfe1 self.sfe2 = self.encoder.sfe2 self.rdbs = self.encoder.rdbs self.gff = self.encoder.gff self.num_blocks = self.encoder.num_blocks del self.encoder def gen_feature(self, x): """Generate feature. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ sfe1 = self.sfe1(x) sfe2 = self.sfe2(sfe1) x = sfe2 local_features = [] for i in range(self.num_blocks): x = self.rdbs[i](x) local_features.append(x) x = self.gff(torch.cat(local_features, 1)) + sfe1 return x ================================================ FILE: mmagic/models/editors/liif/mlp_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class MLPRefiner(BaseModule): """Multilayer perceptrons (MLPs), refiner used in LIIF. Args: in_dim (int): Input dimension. out_dim (int): Output dimension. hidden_list (list[int]): List of hidden dimensions. """ def __init__(self, in_dim, out_dim, hidden_list): super().__init__() layers = [] last_channels = in_dim for hidden in hidden_list: layers.append(nn.Linear(last_channels, hidden)) layers.append(nn.ReLU()) last_channels = hidden layers.append(nn.Linear(last_channels, out_dim)) self.layers = nn.Sequential(*layers) def forward(self, x): """Forward function. Args: x (Tensor): The input of MLP. Returns: Tensor: The output of MLP. """ shape = x.shape[:-1] x = self.layers(x.view(-1, x.shape[-1])) return x.view(*shape, -1) ================================================ FILE: mmagic/models/editors/lsgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .lsgan import LSGAN from .lsgan_discriminator import LSGANDiscriminator from .lsgan_generator import LSGANGenerator __all__ = ['LSGAN', 'LSGANDiscriminator', 'LSGANGenerator'] ================================================ FILE: mmagic/models/editors/lsgan/lsgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Tuple import torch import torch.nn.functional as F from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseGAN @MODELS.register_module() class LSGAN(BaseGAN): """Implementation of `Least Squares Generative Adversarial Networks`. Paper link: https://arxiv.org/pdf/1611.04076.pdf Detailed architecture can be found in :class:`~mmagic.models.editors.lsgan.LSGANGenerator` and :class:`~mmagic.models.editors.lsgan.LSGANDiscriminator` """ def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: r"""Get disc loss. LSGAN use the least squares loss to train the discriminator. .. math:: L_{D}=\left(D\left(X_{\text {data }}\right)-1\right)^{2} +(D(G(z)))^{2} Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.mse_loss( disc_pred_fake, 0. * torch.ones_like(disc_pred_fake)) losses_dict['loss_disc_real'] = F.mse_loss( disc_pred_real, 1. * torch.ones_like(disc_pred_real)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple: """Get gen loss. LSGAN use the least squares loss to train the generator. .. math:: L_{G}=(D(G(z))-1)^{2} Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = F.mse_loss( disc_pred_fake, 1. * torch.ones_like(disc_pred_fake)) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/lsgan/lsgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class LSGANDiscriminator(BaseModule): """Discriminator for LSGAN. Implementation Details for LSGAN architecture: #. Adopt convolution in the discriminator; #. Use batchnorm in the discriminator except for the input and final \ output layer; #. Use LeakyReLU in the discriminator in addition to the output layer; #. Use fully connected layer in the output layer; #. Use 5x5 conv rather than 4x4 conv in DCGAN. Args: input_scale (int, optional): The scale of the input image. Defaults to 128. output_scale (int, optional): The final scale of the convolutional feature. Defaults to 8. out_channels (int, optional): The channel number of the final output layer. Defaults to 1. in_channels (int, optional): The channel number of the input image. Defaults to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 128. conv_cfg (dict, optional): Config for the convolution module used in this discriminator. Defaults to dict(type='Conv2d'). default_norm_cfg (dict, optional): Norm config for all of layers except for the final output layer. Defaults to ``dict(type='BN')``. default_act_cfg (dict, optional): Activation config for all of layers except for the final output layer. Defaults to ``dict(type='LeakyReLU', negative_slope=0.2)``. out_act_cfg (dict, optional): Activation config for the final output layer. Defaults to ``dict(type='Tanh')``. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, input_scale=128, output_scale=8, out_channels=1, in_channels=3, base_channels=64, conv_cfg=dict(type='Conv2d'), default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act_cfg=None, init_cfg=None): super().__init__(init_cfg=init_cfg) assert input_scale % output_scale == 0 assert input_scale // output_scale >= 2 self.input_scale = input_scale self.output_scale = output_scale self.out_channels = out_channels self.base_channels = base_channels self.with_out_activation = out_act_cfg is not None self.conv_blocks = nn.ModuleList() self.conv_blocks.append( ConvModule( in_channels, base_channels, kernel_size=5, stride=2, padding=2, conv_cfg=conv_cfg, norm_cfg=None, act_cfg=default_act_cfg)) # the number of times for downsampling self.num_downsamples = int(np.log2(input_scale // output_scale)) - 1 # build up downsampling backbone (excluding the output layer) curr_channels = base_channels for _ in range(self.num_downsamples): self.conv_blocks.append( ConvModule( curr_channels, curr_channels * 2, kernel_size=5, stride=2, padding=2, conv_cfg=conv_cfg, norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) curr_channels = curr_channels * 2 # output layer self.decision = nn.Sequential( nn.Linear(output_scale * output_scale * curr_channels, out_channels)) if self.with_out_activation: self.out_activation = MODELS.build(out_act_cfg) def forward(self, x): """Forward function. Args: x (torch.Tensor): Fake or real image tensor. Returns: torch.Tensor: Prediction for the reality of the input image. """ n = x.shape[0] for conv in self.conv_blocks: x = conv(x) x = x.reshape(n, -1) x = self.decision(x) if self.with_out_activation: x = self.out_activation(x) return x ================================================ FILE: mmagic/models/editors/lsgan/lsgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS from ...utils import get_module_device @MODELS.register_module() class LSGANGenerator(BaseModule): """Generator for LSGAN. Implementation Details for LSGAN architecture: #. Adopt transposed convolution in the generator; #. Use batchnorm in the generator except for the final output layer; #. Use ReLU in the generator in addition to the final output layer; #. Keep channels of feature maps unchanged in the convolution backbone; #. Use one more 3x3 conv every upsampling in the convolution backbone. We follow the implementation details of the origin paper: Least Squares Generative Adversarial Networks https://arxiv.org/pdf/1611.04076.pdf Args: output_scale (int, optional): Output scale for the generated image. Defaults to 128. out_channels (int, optional): The channel number of the output feature. Defaults to 3. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 256. input_scale (int, optional): The scale of the input 2D feature map. Defaults to 8. noise_size (int, optional): Size of the input noise vector. Defaults to 1024. conv_cfg (dict, optional): Config for the convolution module used in this generator. Defaults to dict(type='ConvTranspose2d'). default_norm_cfg (dict, optional): Norm config for all of layers except for the final output layer. Defaults to dict(type='BN'). default_act_cfg (dict, optional): Activation config for all of layers except for the final output layer. Defaults to dict(type='ReLU'). out_act_cfg (dict, optional): Activation config for the final output layer. Defaults to dict(type='Tanh'). init_cfg (dict, optional): Initialization config dict. """ def __init__(self, output_scale=128, out_channels=3, base_channels=256, input_scale=8, noise_size=1024, conv_cfg=dict(type='ConvTranspose2d'), default_norm_cfg=dict(type='BN'), default_act_cfg=dict(type='ReLU'), out_act_cfg=dict(type='Tanh'), init_cfg=None): super().__init__(init_cfg=init_cfg) assert output_scale % input_scale == 0 assert output_scale // input_scale >= 4 self.output_scale = output_scale self.base_channels = base_channels self.input_scale = input_scale self.noise_size = noise_size self.noise2feat_head = nn.Sequential( nn.Linear(noise_size, input_scale * input_scale * base_channels)) self.noise2feat_tail = nn.Sequential(nn.BatchNorm2d(base_channels)) if default_act_cfg is not None: self.noise2feat_tail.add_module('act', MODELS.build(default_act_cfg)) # the number of times for upsampling self.num_upsamples = int(np.log2(output_scale // input_scale)) - 2 # build up convolution backbone (excluding the output layer) self.conv_blocks = nn.ModuleList() for _ in range(self.num_upsamples): self.conv_blocks.append( ConvModule( base_channels, base_channels, kernel_size=3, stride=2, padding=1, conv_cfg=dict(conv_cfg, output_padding=1), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) self.conv_blocks.append( ConvModule( base_channels, base_channels, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) # output blocks self.conv_blocks.append( ConvModule( base_channels, int(base_channels // 2), kernel_size=3, stride=2, padding=1, conv_cfg=dict(conv_cfg, output_padding=1), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) self.conv_blocks.append( ConvModule( int(base_channels // 2), int(base_channels // 4), kernel_size=3, stride=2, padding=1, conv_cfg=dict(conv_cfg, output_padding=1), norm_cfg=default_norm_cfg, act_cfg=default_act_cfg)) self.conv_blocks.append( ConvModule( int(base_channels // 4), out_channels, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=None, act_cfg=out_act_cfg)) def forward(self, noise, num_batches=0, return_noise=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img`` and ``noise_batch`` will be returned. """ # receive noise and conduct sanity check. if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size if noise.ndim == 2: noise_batch = noise else: raise ValueError('The noise should be in shape of (n, c)' f'but got {noise.shape}') # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size)) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) # noise2feat x = self.noise2feat_head(noise_batch) x = x.reshape( (-1, self.base_channels, self.input_scale, self.input_scale)) x = self.noise2feat_tail(x) # conv module for conv in self.conv_blocks: x = conv(x) if return_noise: return dict(fake_img=x, noise_batch=noise_batch) return x ================================================ FILE: mmagic/models/editors/mspie/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .mspie_stylegan2 import MSPIEStyleGAN2 from .mspie_stylegan2_discriminator import MSStyleGAN2Discriminator from .mspie_stylegan2_generator import MSStyleGANv2Generator from .pe_singan import PESinGAN from .pe_singan_generator import SinGANMSGeneratorPE from .positional_encoding import CatersianGrid, SinusoidalPositionalEmbedding __all__ = [ 'MSPIEStyleGAN2', 'MSStyleGAN2Discriminator', 'MSStyleGANv2Generator', 'PESinGAN', 'SinGANMSGeneratorPE', 'CatersianGrid', 'SinusoidalPositionalEmbedding' ] ================================================ FILE: mmagic/models/editors/mspie/mspie_stylegan2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict, Union import numpy as np import torch import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F from mmengine import MessageHub from mmengine.logging import MMLogger from mmengine.model import is_model_wrapper from mmengine.optim import OptimWrapper, OptimWrapperDict from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...utils import set_requires_grad from ..stylegan2 import StyleGAN2 ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module() class MSPIEStyleGAN2(StyleGAN2): """MS-PIE StyleGAN2. In this GAN, we adopt the MS-PIE training schedule so that multi-scale images can be generated with a single generator. Details can be found in: Positional Encoding as Spatial Inductive Bias in GANs, CVPR2021. Args: train_settings (dict): Config for training settings. Defaults to `dict()`. """ def __init__(self, *args, train_settings=dict(), **kwargs): super().__init__(*args, **kwargs) self.train_settings = deepcopy(train_settings) # set the number of upsampling blocks. This value will be used to # calculate the current result size according to the size of the input # feature map, e.g., positional encoding map self.num_upblocks = self.train_settings.get('num_upblocks', 6) # multiple input scales (a list of int) that will be added to the # original starting scale. self.multi_input_scales = self.train_settings.get('multi_input_scales') self.multi_scale_probability = self.train_settings.get( 'multi_scale_probability') def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: """Train GAN model. In the training of GAN models, generator and discriminator are updated alternatively. In MMagic's design, `self.train_step` is called with data input. Therefore we always update discriminator, whose updating is relay on real data, and then determine if the generator needs to be updated based on the current number of iterations. More details about whether to update generator can be found in :meth:`should_gen_update`. Args: data (dict): Data sampled from dataloader. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts with disc_optimizer_wrapper.optim_context(self.discriminator): log_vars = self.train_discriminator( **data, optimizer_wrapper=disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): log_vars_gen = self.train_generator( **data, optimizer_wrapper=gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = self.gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) # if not update buffer, copy buffer from orig model if not self.generator_ema.update_buffers: self.generator_ema.sync_buffers( self.generator.module if is_model_wrapper( self.generator) else self.generator) elif self.with_ema_gen: # before ema, copy weights from orig self.generator_ema.sync_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (TrainInput): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator( noise, return_noise=False, chosen_scale=self.chosen_scale) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake, num_batches) optimizer_wrapper.update_params(parsed_loss) return log_vars def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (TrainInput): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img if dist.is_initialized(): # randomly sample a scale for current training iteration chosen_scale = np.random.choice(self.multi_input_scales, 1, self.multi_scale_probability)[0] chosen_scale = torch.tensor(chosen_scale, dtype=torch.int).cuda() dist.broadcast(chosen_scale, 0) chosen_scale = int(chosen_scale.item()) else: logger = MMLogger.get_current_instance() logger.info( 'Distributed training has not been initialized. Degrade to ' 'the standard stylegan2') chosen_scale = 0 curr_size = (4 + chosen_scale) * (2**self.num_upblocks) # adjust the shape of images if real_imgs.shape[-2:] != (curr_size, curr_size): real_imgs = F.interpolate( real_imgs, size=(curr_size, curr_size), mode='bilinear', align_corners=True) num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise_batch, return_noise=False, chosen_scale=chosen_scale) # store chosen scale for training generator setattr(self, 'chosen_scale', chosen_scale) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real, real_imgs) optimizer_wrapper.update_params(parsed_losses) return log_vars ================================================ FILE: mmagic/models/editors/mspie/mspie_stylegan2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from ..stylegan1 import EqualLinearActModule from ..stylegan2 import ConvDownLayer, ModMBStddevLayer, ResBlock @MODELS.register_module() class MSStyleGAN2Discriminator(BaseModule): """StyleGAN2 Discriminator. The architecture of this discriminator is proposed in StyleGAN2. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN CVPR2020. Args: in_size (int): The input size of images. channel_multiplier (int, optional): The multiplier factor for the channel number. Defaults to 2. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 3, 3, 1]. mbstd_cfg (dict, optional): Configs for minibatch-stddev layer. Defaults to dict(group_size=4, channel_groups=1). """ def __init__(self, in_size, channel_multiplier=2, blur_kernel=[1, 3, 3, 1], mbstd_cfg=dict(group_size=4, channel_groups=1), with_adaptive_pool=False, pool_size=(2, 2)): super().__init__() self.with_adaptive_pool = with_adaptive_pool self.pool_size = pool_size channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256 * channel_multiplier, 128: 128 * channel_multiplier, 256: 64 * channel_multiplier, 512: 32 * channel_multiplier, 1024: 16 * channel_multiplier, } log_size = int(np.log2(in_size)) in_channels = channels[in_size] convs = [ConvDownLayer(3, channels[in_size], 1)] for i in range(log_size, 2, -1): out_channel = channels[2**(i - 1)] convs.append(ResBlock(in_channels, out_channel, blur_kernel)) in_channels = out_channel self.convs = nn.Sequential(*convs) self.mbstd_layer = ModMBStddevLayer(**mbstd_cfg) self.final_conv = ConvDownLayer(in_channels + 1, channels[4], 3) if self.with_adaptive_pool: self.adaptive_pool = nn.AdaptiveAvgPool2d(pool_size) linear_in_channels = channels[4] * pool_size[0] * pool_size[1] else: linear_in_channels = channels[4] * 4 * 4 self.final_linear = nn.Sequential( EqualLinearActModule( linear_in_channels, channels[4], act_cfg=dict(type='fused_bias')), EqualLinearActModule(channels[4], 1), ) def forward(self, x): """Forward function. Args: x (torch.Tensor): Input image tensor. Returns: torch.Tensor: Predict score for the input image. """ x = self.convs(x) x = self.mbstd_layer(x) x = self.final_conv(x) if self.with_adaptive_pool: x = self.adaptive_pool(x) x = x.view(x.shape[0], -1) x = self.final_linear(x) return x ================================================ FILE: mmagic/models/editors/mspie/mspie_stylegan2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random from copy import deepcopy import mmengine import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from ...utils import get_module_device from ..pggan import PixelNorm from ..stylegan1 import (ConstantInput, EqualLinearActModule, get_mean_latent, style_mixing) from ..stylegan2 import ModulatedToRGB from .mspie_stylegan2_modules import ModulatedPEStyleConv @MODELS.register_module() class MSStyleGANv2Generator(BaseModule): """StyleGAN2 Generator. In StyleGAN2, we use a static architecture composing of a style mapping module and number of convolutional style blocks. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN CVPR2020. Args: out_size (int): The output size of the StyleGAN2 generator. style_channels (int): The number of channels for style code. num_mlps (int, optional): The number of MLP layers. Defaults to 8. channel_multiplier (int, optional): The multiplier factor for the channel number. Defaults to 2. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 3, 3, 1]. lr_mlp (float, optional): The learning rate for the style mapping layer. Defaults to 0.01. default_style_mode (str, optional): The default mode of style mixing. In training, we adopt mixing style mode in default. However, in the evaluation, we use 'single' style mode. `['mix', 'single']` are currently supported. Defaults to 'mix'. eval_style_mode (str, optional): The evaluation mode of style mixing. Defaults to 'single'. mix_prob (float, optional): Mixing probability. The value should be in range of [0, 1]. Defaults to 0.9. """ def __init__(self, out_size, style_channels, num_mlps=8, channel_multiplier=2, blur_kernel=[1, 3, 3, 1], lr_mlp=0.01, default_style_mode='mix', eval_style_mode='single', mix_prob=0.9, no_pad=False, deconv2conv=False, interp_pad=None, up_config=dict(scale_factor=2, mode='nearest'), up_after_conv=False, head_pos_encoding=None, head_pos_size=(4, 4), interp_head=False): super().__init__() self.out_size = out_size self.style_channels = style_channels self.num_mlps = num_mlps self.channel_multiplier = channel_multiplier self.lr_mlp = lr_mlp self._default_style_mode = default_style_mode self.default_style_mode = default_style_mode self.eval_style_mode = eval_style_mode self.mix_prob = mix_prob self.no_pad = no_pad self.deconv2conv = deconv2conv self.interp_pad = interp_pad self.with_interp_pad = interp_pad is not None self.up_config = deepcopy(up_config) self.up_after_conv = up_after_conv self.head_pos_encoding = head_pos_encoding self.head_pos_size = head_pos_size self.interp_head = interp_head # define style mapping layers mapping_layers = [PixelNorm()] for _ in range(num_mlps): mapping_layers.append( EqualLinearActModule( style_channels, style_channels, equalized_lr_cfg=dict(lr_mul=lr_mlp, gain=1.), act_cfg=dict(type='fused_bias'))) self.style_mapping = nn.Sequential(*mapping_layers) self.channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256 * channel_multiplier, 128: 128 * channel_multiplier, 256: 64 * channel_multiplier, 512: 32 * channel_multiplier, 1024: 16 * channel_multiplier, } in_ch = self.channels[4] # constant input layer if self.head_pos_encoding: if self.head_pos_encoding['type'] in [ 'CatersianGrid', 'CSG', 'CSG2d' ]: in_ch = 2 self.head_pos_enc = MODELS.build(self.head_pos_encoding) else: size_ = 4 if self.no_pad: size_ += 2 self.constant_input = ConstantInput(self.channels[4], size=size_) # 4x4 stage self.conv1 = ModulatedPEStyleConv( in_ch, self.channels[4], kernel_size=3, style_channels=style_channels, blur_kernel=blur_kernel, deconv2conv=self.deconv2conv, no_pad=self.no_pad, up_config=self.up_config, interp_pad=self.interp_pad) self.to_rgb1 = ModulatedToRGB( self.channels[4], style_channels, upsample=False) # generator backbone (8x8 --> higher resolutions) self.log_size = int(np.log2(self.out_size)) self.convs = nn.ModuleList() self.upsamples = nn.ModuleList() self.to_rgbs = nn.ModuleList() in_channels_ = self.channels[4] for i in range(3, self.log_size + 1): out_channels_ = self.channels[2**i] self.convs.append( ModulatedPEStyleConv( in_channels_, out_channels_, 3, style_channels, upsample=True, blur_kernel=blur_kernel, deconv2conv=self.deconv2conv, no_pad=self.no_pad, up_config=self.up_config, interp_pad=self.interp_pad, up_after_conv=self.up_after_conv)) self.convs.append( ModulatedPEStyleConv( out_channels_, out_channels_, 3, style_channels, upsample=False, blur_kernel=blur_kernel, deconv2conv=self.deconv2conv, no_pad=self.no_pad, up_config=self.up_config, interp_pad=self.interp_pad, up_after_conv=self.up_after_conv)) self.to_rgbs.append( ModulatedToRGB(out_channels_, style_channels, upsample=True)) in_channels_ = out_channels_ self.num_latents = self.log_size * 2 - 2 self.num_injected_noises = self.num_latents - 1 # register buffer for injected noises noises = self.make_injected_noise() for layer_idx in range(self.num_injected_noises): self.register_buffer(f'injected_noise_{layer_idx}', noises[layer_idx]) def train(self, mode=True): """Set train/eval mode. Args: mode (bool, optional): Whether set train mode. Defaults to True. """ if mode: if self.default_style_mode != self._default_style_mode: mmengine.print_log( f'Switch to train style mode: {self._default_style_mode}') self.default_style_mode = self._default_style_mode else: if self.default_style_mode != self.eval_style_mode: mmengine.print_log( f'Switch to evaluation style mode: {self.eval_style_mode}') self.default_style_mode = self.eval_style_mode return super(MSStyleGANv2Generator, self).train(mode) def make_injected_noise(self, chosen_scale=0): """make noises that will be injected into feature maps. Args: chosen_scale (int, optional): Chosen scale. Defaults to 0. Returns: list[Tensor]: List of layer-wise noise tensor. """ device = get_module_device(self) base_scale = 2**2 + chosen_scale noises = [torch.randn(1, 1, base_scale, base_scale, device=device)] for i in range(3, self.log_size + 1): for n in range(2): _pad = 0 if self.no_pad and not self.up_after_conv and n == 0: _pad = 2 noises.append( torch.randn( 1, 1, base_scale * 2**(i - 2) + _pad, base_scale * 2**(i - 2) + _pad, device=device)) return noises def get_mean_latent(self, num_samples=4096, **kwargs): """Get mean latent of W space in this generator. Args: num_samples (int, optional): Number of sample times. Defaults to 4096. Returns: Tensor: Mean latent of this generator. """ return get_mean_latent(self, num_samples, **kwargs) def style_mixing(self, n_source, n_target, inject_index=1, truncation_latent=None, truncation=0.7, chosen_scale=0): """Generating style mixing images. Args: n_source (int): Number of source images. n_target (int): Number of target images. inject_index (int, optional): Index from which replace with source latent. Defaults to 1. truncation_latent (torch.Tensor, optional): Mean truncation latent. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. curr_scale (int): Current image scale. Defaults to -1. transition_weight (float, optional): The weight used in resolution transition. Defaults to 1.0. chosen_scale (int, optional): Chosen scale. Defaults to 0. Returns: torch.Tensor: Table of style-mixing images. """ return style_mixing( self, n_source=n_source, n_target=n_target, inject_index=inject_index, truncation_latent=truncation_latent, truncation=truncation, style_channels=self.style_channels, chosen_scale=chosen_scale) def forward(self, styles, num_batches=-1, return_noise=False, return_latents=False, inject_index=None, truncation=1, truncation_latent=None, input_is_latent=False, injected_noise=None, randomize_noise=True, chosen_scale=0): """Forward function. This function has been integrated with the truncation trick. Please refer to the usage of `truncation` and `truncation_latent`. Args: styles (torch.Tensor | list[torch.Tensor] | callable | None): In StyleGAN2, you can provide noise tensor or latent tensor. Given a list containing more than one noise or latent tensors, style mixing trick will be used in training. Of course, You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. return_latents (bool, optional): If True, ``latent`` will be returned in a dict with ``fake_img``. Defaults to False. inject_index (int | None, optional): The index number for mixing style codes. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. truncation_latent (torch.Tensor, optional): Mean truncation latent. Defaults to None. input_is_latent (bool, optional): If `True`, the input tensor is the latent tensor. Defaults to False. injected_noise (torch.Tensor | None, optional): Given a tensor, the random noise will be fixed as this input injected noise. Defaults to None. randomize_noise (bool, optional): If `False`, images are sampled with the buffered noise tensor injected to the style conv block. Defaults to True. Returns: torch.Tensor | dict: Generated image tensor or dictionary \ containing more data. """ # receive noise and conduct sanity check. if isinstance(styles, torch.Tensor): assert styles.shape[1] == self.style_channels styles = [styles] elif mmengine.is_seq_of(styles, torch.Tensor): for t in styles: assert t.shape[-1] == self.style_channels # receive a noise generator and sample noise. elif callable(styles): device = get_module_device(self) noise_generator = styles assert num_batches > 0 if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ noise_generator((num_batches, self.style_channels)) for _ in range(2) ] else: styles = [noise_generator((num_batches, self.style_channels))] styles = [s.to(device) for s in styles] # otherwise, we will adopt default noise sampler. else: device = get_module_device(self) assert num_batches > 0 and not input_is_latent if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ torch.randn((num_batches, self.style_channels)) for _ in range(2) ] else: styles = [torch.randn((num_batches, self.style_channels))] styles = [s.to(device) for s in styles] if not input_is_latent: noise_batch = styles styles = [self.style_mapping(s) for s in styles] else: noise_batch = None if injected_noise is None: if randomize_noise: injected_noise = [None] * self.num_injected_noises elif chosen_scale > 0: if not hasattr(self, f'injected_noise_{chosen_scale}_0'): noises_ = self.make_injected_noise(chosen_scale) for i in range(self.num_injected_noises): setattr(self, f'injected_noise_{chosen_scale}_{i}', noises_[i]) injected_noise = [ getattr(self, f'injected_noise_{chosen_scale}_{i}') for i in range(self.num_injected_noises) ] else: injected_noise = [ getattr(self, f'injected_noise_{i}') for i in range(self.num_injected_noises) ] # use truncation trick if truncation < 1: style_t = [] # calculate truncation latent on the fly if truncation_latent is None and not hasattr( self, 'truncation_latent'): self.truncation_latent = self.get_mean_latent() truncation_latent = self.truncation_latent elif truncation_latent is None and hasattr(self, 'truncation_latent'): truncation_latent = self.truncation_latent for style in styles: style_t.append(truncation_latent + truncation * (style - truncation_latent)) styles = style_t # no style mixing if len(styles) < 2: inject_index = self.num_latents if styles[0].ndim < 3: latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) else: latent = styles[0] # style mixing else: if inject_index is None: inject_index = random.randint(1, self.num_latents - 1) latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) latent2 = styles[1].unsqueeze(1).repeat( 1, self.num_latents - inject_index, 1) latent = torch.cat([latent, latent2], 1) if isinstance(chosen_scale, int): chosen_scale = (chosen_scale, chosen_scale) # 4x4 stage if self.head_pos_encoding: if self.interp_head: out = self.head_pos_enc.make_grid2d(self.head_pos_size[0], self.head_pos_size[1], latent.size(0)) h_in = self.head_pos_size[0] + chosen_scale[0] w_in = self.head_pos_size[1] + chosen_scale[1] out = F.interpolate( out, size=(h_in, w_in), mode='bilinear', align_corners=True) else: out = self.head_pos_enc.make_grid2d( self.head_pos_size[0] + chosen_scale[0], self.head_pos_size[1] + chosen_scale[1], latent.size(0)) out = out.to(latent) else: out = self.constant_input(latent) if chosen_scale[0] != 0 or chosen_scale[1] != 0: out = F.interpolate( out, size=(out.shape[2] + chosen_scale[0], out.shape[3] + chosen_scale[1]), mode='bilinear', align_corners=True) out = self.conv1(out, latent[:, 0], noise=injected_noise[0]) skip = self.to_rgb1(out, latent[:, 1]) _index = 1 # 8x8 ---> higher resolutions for up_conv, conv, noise1, noise2, to_rgb in zip( self.convs[::2], self.convs[1::2], injected_noise[1::2], injected_noise[2::2], self.to_rgbs): out = up_conv(out, latent[:, _index], noise=noise1) out = conv(out, latent[:, _index + 1], noise=noise2) skip = to_rgb(out, latent[:, _index + 2], skip) _index += 2 img = skip if return_latents or return_noise: output_dict = dict( fake_img=img, latent=latent, inject_index=inject_index, noise_batch=noise_batch, injected_noise=injected_noise) return output_dict return img ================================================ FILE: mmagic/models/editors/mspie/mspie_stylegan2_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule try: from mmcv.ops import conv2d, conv_transpose2d except ImportError: conv2d = None conv_transpose2d = None print('Warning: mmcv.ops.conv2d, mmcv.ops.conv_transpose2d' 'are not available.') from ..pggan import equalized_lr from ..stylegan1 import Blur, EqualLinearActModule, NoiseInjection from ..stylegan2.stylegan2_modules import _FusedBiasLeakyReLU class ModulatedPEConv2d(BaseModule): r"""Modulated Conv2d in StyleGANv2 with Positional Encoding (PE). This module is modified from the ``ModulatedConv2d`` in StyleGAN2 to support the experiments in: Positional Encoding as Spatial Inductive Bias in GANs, CVPR'2021. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. style_channels (int): Channels for the style codes. demodulate (bool, optional): Whether to adopt demodulation. Defaults to True. upsample (bool, optional): Whether to adopt upsampling in features. Defaults to False. downsample (bool, optional): Whether to adopt downsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. equalized_lr_cfg (dict | None, optional): Configs for equalized lr. Defaults to dict(mode='fan_in', lr_mul=1., gain=1.). style_mod_cfg (dict, optional): Configs for style modulation module. Defaults to dict(bias_init=1.). style_bias (float, optional): Bias value for style code. Defaults to 0.. eps (float, optional): Epsilon value to avoid computation error. Defaults to 1e-8. no_pad (bool, optional): Whether to removing the padding in convolution. Defaults to False. deconv2conv (bool, optional): Whether to substitute the transposed conv with (conv2d, upsampling). Defaults to False. interp_pad (int | None, optional): The padding number of interpolation pad. Defaults to None. up_config (dict, optional): Upsampling config. Defaults to dict(scale_factor=2, mode='nearest'). up_after_conv (bool, optional): Whether to adopt upsampling after convolution. Defaults to False. """ def __init__(self, in_channels, out_channels, kernel_size, style_channels, demodulate=True, upsample=False, downsample=False, blur_kernel=[1, 3, 3, 1], equalized_lr_cfg=dict(mode='fan_in', lr_mul=1., gain=1.), style_mod_cfg=dict(bias_init=1.), style_bias=0., eps=1e-8, no_pad=False, deconv2conv=False, interp_pad=None, up_config=dict(scale_factor=2, mode='nearest'), up_after_conv=False): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.kernel_size = kernel_size self.style_channels = style_channels self.demodulate = demodulate # sanity check for kernel size assert isinstance(self.kernel_size, int) and (self.kernel_size >= 1 and self.kernel_size % 2 == 1) self.upsample = upsample self.downsample = downsample self.style_bias = style_bias self.eps = eps self.no_pad = no_pad self.deconv2conv = deconv2conv self.interp_pad = interp_pad self.with_interp_pad = interp_pad is not None self.up_config = deepcopy(up_config) self.up_after_conv = up_after_conv # build style modulation module style_mod_cfg = dict() if style_mod_cfg is None else style_mod_cfg self.style_modulation = EqualLinearActModule(style_channels, in_channels, **style_mod_cfg) # set lr_mul for conv weight lr_mul_ = 1. if equalized_lr_cfg is not None: lr_mul_ = equalized_lr_cfg.get('lr_mul', 1.) self.weight = nn.Parameter( torch.randn(1, out_channels, in_channels, kernel_size, kernel_size).div_(lr_mul_)) # build blurry layer for upsampling if upsample and not self.deconv2conv: factor = 2 p = (len(blur_kernel) - factor) - (kernel_size - 1) pad0 = (p + 1) // 2 + factor - 1 pad1 = p // 2 + 1 self.blur = Blur(blur_kernel, (pad0, pad1), upsample_factor=factor) # build blurry layer for downsampling if downsample: factor = 2 p = (len(blur_kernel) - factor) + (kernel_size - 1) pad0 = (p + 1) // 2 pad1 = p // 2 self.blur = Blur(blur_kernel, pad=(pad0, pad1)) # add equalized_lr hook for conv weight if equalized_lr_cfg is not None: equalized_lr(self, **equalized_lr_cfg) # if `no_pad`, remove all of the padding in conv self.padding = kernel_size // 2 if not no_pad else 0 def forward(self, x, style): """Forward function. Args: x ([Tensor): Input features with shape of (N, C, H, W). style (Tensor): Style latent with shape of (N, C). Returns: Tensor: Output feature with shape of (N, C, H, W). """ n, c, h, w = x.shape # process style code style = self.style_modulation(style).view(n, 1, c, 1, 1) + self.style_bias # combine weight and style weight = self.weight * style if self.demodulate: demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps) weight = weight * demod.view(n, self.out_channels, 1, 1, 1) weight = weight.view(n * self.out_channels, c, self.kernel_size, self.kernel_size) if self.upsample and not self.deconv2conv: x = x.reshape(1, n * c, h, w) weight = weight.view(n, self.out_channels, c, self.kernel_size, self.kernel_size) weight = weight.transpose(1, 2).reshape(n * c, self.out_channels, self.kernel_size, self.kernel_size) x = conv_transpose2d(x, weight, padding=0, stride=2, groups=n) x = x.reshape(n, self.out_channels, *x.shape[-2:]) x = self.blur(x) elif self.upsample and self.deconv2conv: if self.up_after_conv: x = x.reshape(1, n * c, h, w) x = conv2d(x, weight, padding=self.padding, groups=n) x = x.view(n, self.out_channels, *x.shape[2:4]) if self.with_interp_pad: h_, w_ = x.shape[-2:] up_cfg_ = deepcopy(self.up_config) up_scale = up_cfg_.pop('scale_factor') size_ = (h_ * up_scale + self.interp_pad, w_ * up_scale + self.interp_pad) x = F.interpolate(x, size=size_, **up_cfg_) else: x = F.interpolate(x, **self.up_config) if not self.up_after_conv: h_, w_ = x.shape[-2:] x = x.view(1, n * c, h_, w_) x = conv2d(x, weight, padding=self.padding, groups=n) x = x.view(n, self.out_channels, *x.shape[2:4]) elif self.downsample: x = self.blur(x) x = x.view(1, n * self.in_channels, *x.shape[-2:]) x = conv2d(x, weight, stride=2, padding=0, groups=n) x = x.view(n, self.out_channels, *x.shape[-2:]) else: x = x.view(1, n * c, h, w) x = conv2d(x, weight, stride=1, padding=self.padding, groups=n) x = x.view(n, self.out_channels, *x.shape[-2:]) return x class ModulatedPEStyleConv(BaseModule): """Modulated Style Convolution with Positional Encoding. This module is modified from the ``ModulatedStyleConv`` in StyleGAN2 to support the experiments in: Positional Encoding as Spatial Inductive Bias in GANs, CVPR'2021. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. style_channels (int): Channels for the style codes. demodulate (bool, optional): Whether to adopt demodulation. Defaults to True. upsample (bool, optional): Whether to adopt upsampling in features. Defaults to False. downsample (bool, optional): Whether to adopt downsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. equalized_lr_cfg (dict | None, optional): Configs for equalized lr. Defaults to dict(mode='fan_in', lr_mul=1., gain=1.). style_mod_cfg (dict, optional): Configs for style modulation module. Defaults to dict(bias_init=1.). style_bias (float, optional): Bias value for style code. Defaults to 0.. """ def __init__(self, in_channels, out_channels, kernel_size, style_channels, upsample=False, blur_kernel=[1, 3, 3, 1], demodulate=True, style_mod_cfg=dict(bias_init=1.), style_bias=0., **kwargs): super().__init__() self.conv = ModulatedPEConv2d( in_channels, out_channels, kernel_size, style_channels, demodulate=demodulate, upsample=upsample, blur_kernel=blur_kernel, style_mod_cfg=style_mod_cfg, style_bias=style_bias, **kwargs) self.noise_injector = NoiseInjection() self.activate = _FusedBiasLeakyReLU(out_channels) def forward(self, x, style, noise=None, return_noise=False): """Forward Function. Args: x ([Tensor): Input features with shape of (N, C, H, W). style (Tensor): Style latent with shape of (N, C). noise (Tensor, optional): Noise for injection. Defaults to None. return_noise (bool, optional): Whether to return noise tensors. Defaults to False. Returns: Tensor: Output features with shape of (N, C, H, W) """ out = self.conv(x, style) if return_noise: out, noise = self.noise_injector( out, noise=noise, return_noise=return_noise) else: out = self.noise_injector( out, noise=noise, return_noise=return_noise) out = self.activate(out) if return_noise: return out, noise return out ================================================ FILE: mmagic/models/editors/mspie/pe_singan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Union import torch import torch.nn as nn from mmengine import Config from torch import Tensor from mmagic.registry import MODELS from ..singan import SinGAN ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module() class PESinGAN(SinGAN): """Positional Encoding in SinGAN. This modified SinGAN is used to reimplement the experiments in: Positional Encoding as Spatial Inductive Bias in GANs, CVPR2021. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType], data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, num_scales: Optional[int] = None, fixed_noise_with_pad: bool = False, first_fixed_noises_ch: int = 1, iters_per_scale: int = 200, noise_weight_init: int = 0.1, lr_scheduler_args: Optional[dict] = None, test_pkl_data: Optional[str] = None, ema_confg: Optional[dict] = None): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, num_scales, iters_per_scale, noise_weight_init, lr_scheduler_args, test_pkl_data, ema_confg) self.fixed_noise_with_pad = fixed_noise_with_pad self.first_fixed_noises_ch = first_fixed_noises_ch def construct_fixed_noises(self): """Construct the fixed noises list used in SinGAN.""" for i, real in enumerate(self.reals): h, w = real.shape[-2:] if self.fixed_noise_with_pad: pad_ = self.get_module(self.generator, 'pad_head') h += 2 * pad_ w += 2 * pad_ if i == 0: noise = torch.randn(1, self.first_fixed_noises_ch, h, w).to(real) self.fixed_noises.append(noise) else: noise = torch.zeros((1, 1, h, w)).to(real) self.fixed_noises.append(noise) ================================================ FILE: mmagic/models/editors/mspie/pe_singan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial import mmengine import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS from ..singan.singan_generator import SinGANMultiScaleGenerator from ..singan.singan_modules import GeneratorBlock @MODELS.register_module() class SinGANMSGeneratorPE(SinGANMultiScaleGenerator): """Multi-Scale Generator used in SinGAN with positional encoding. More details can be found in: Positional Encoding as Spatial Inductive Bias in GANs, CVPR'2021. Notes: - In this version, we adopt the interpolation function from the official PyTorch APIs, which is different from the original implementation by the authors. However, in our experiments, this influence can be ignored. Args: in_channels (int): Input channels. out_channels (int): Output channels. num_scales (int): The number of scales/stages in generator. Note that this number is counted from zero, which is the same as the original paper. kernel_size (int, optional): Kernel size, same as :obj:`nn.Conv2d`. Defaults to 3. padding (int, optional): Padding for the convolutional layer, same as :obj:`nn.Conv2d`. Defaults to 0. num_layers (int, optional): The number of convolutional layers in each generator block. Defaults to 5. base_channels (int, optional): The basic channels for convolutional layers in the generator block. Defaults to 32. min_feat_channels (int, optional): Minimum channels for the feature maps in the generator block. Defaults to 32. out_act_cfg (dict | None, optional): Configs for output activation layer. Defaults to dict(type='Tanh'). padding_mode (str, optional): The mode of convolutional padding, same as :obj:`nn.Conv2d`. Defaults to 'zero'. pad_at_head (bool, optional): Whether to add padding at head. Defaults to True. interp_pad (bool, optional): The padding value of interpolating feature maps. Defaults to False. noise_with_pad (bool, optional): Whether the input fixed noises are with explicit padding. Defaults to False. positional_encoding (dict | None, optional): Configs for the positional encoding. Defaults to None. first_stage_in_channels (int | None, optional): The input channel of the first generator block. If None, the first stage will adopt the same input channels as other stages. Defaults to None. """ def __init__(self, in_channels, out_channels, num_scales, kernel_size=3, padding=0, num_layers=5, base_channels=32, min_feat_channels=32, out_act_cfg=dict(type='Tanh'), padding_mode='zero', pad_at_head=True, interp_pad=False, noise_with_pad=False, positional_encoding=None, first_stage_in_channels=None, **kwargs): super(SinGANMultiScaleGenerator, self).__init__() self.pad_at_head = pad_at_head self.interp_pad = interp_pad self.noise_with_pad = noise_with_pad self.with_positional_encode = positional_encoding is not None if self.with_positional_encode: self.head_position_encode = MODELS.build(positional_encoding) self.pad_head = int((kernel_size - 1) / 2 * num_layers) self.blocks = nn.ModuleList() self.upsample = partial( F.interpolate, mode='bicubic', align_corners=True) for scale in range(num_scales + 1): base_ch = min(base_channels * pow(2, int(np.floor(scale / 4))), 128) min_feat_ch = min( min_feat_channels * pow(2, int(np.floor(scale / 4))), 128) if scale == 0: in_ch = ( first_stage_in_channels if first_stage_in_channels else in_channels) else: in_ch = in_channels self.blocks.append( GeneratorBlock( in_channels=in_ch, out_channels=out_channels, kernel_size=kernel_size, padding=padding, num_layers=num_layers, base_channels=base_ch, min_feat_channels=min_feat_ch, out_act_cfg=out_act_cfg, padding_mode=padding_mode, **kwargs)) if padding_mode == 'zero': self.noise_padding_layer = nn.ZeroPad2d(self.pad_head) self.img_padding_layer = nn.ZeroPad2d(self.pad_head) self.mask_padding_layer = nn.ReflectionPad2d(self.pad_head) elif padding_mode == 'reflect': self.noise_padding_layer = nn.ReflectionPad2d(self.pad_head) self.img_padding_layer = nn.ReflectionPad2d(self.pad_head) self.mask_padding_layer = nn.ReflectionPad2d(self.pad_head) mmengine.print_log('Using Reflection padding', 'current') else: raise NotImplementedError( f'Padding mode {padding_mode} is not supported') def forward(self, input_sample, fixed_noises, noise_weights, rand_mode, curr_scale, num_batches=1, get_prev_res=False, return_noise=False): """Forward function. Args: input_sample (Tensor | None): The input for generator. In the original implementation, a tensor filled with zeros is adopted. If None is given, we will construct it from the first fixed noises. fixed_noises (list[Tensor]): List of the fixed noises in SinGAN. noise_weights (list[float]): List of the weights for random noises. rand_mode (str): Choices from ['rand', 'recon']. In ``rand`` mode, it will sample from random noises. Otherwise, the reconstruction for the single image will be returned. curr_scale (int): The scale for the current inference or training. num_batches (int, optional): The number of batches. Defaults to 1. get_prev_res (bool, optional): Whether to return results from previous stages. Defaults to False. return_noise (bool, optional): Whether to return noises tensor. Defaults to False. Returns: Tensor | dict: Generated image tensor or dictionary containing \ more data. """ if get_prev_res or return_noise: prev_res_list = [] noise_list = [] if input_sample is None: h, w = fixed_noises[0].shape[-2:] if self.noise_with_pad: h -= 2 * self.pad_head w -= 2 * self.pad_head input_sample = torch.zeros( (num_batches, 3, h, w)).to(fixed_noises[0]) g_res = input_sample for stage in range(curr_scale + 1): if rand_mode == 'recon': noise_ = fixed_noises[stage] else: noise_ = torch.randn(num_batches, *fixed_noises[stage].shape[1:]).to(g_res) if return_noise: noise_list.append(noise_) if self.with_positional_encode and stage == 0: head_grid = self.head_position_encode(fixed_noises[0]) noise_ = noise_ + head_grid # add padding at head if self.pad_at_head: if self.interp_pad: if self.noise_with_pad: size = noise_.shape[-2:] else: size = (noise_.size(2) + 2 * self.pad_head, noise_.size(3) + 2 * self.pad_head) noise_ = self.upsample(noise_, size) g_res_pad = self.upsample(g_res, size) else: if not self.noise_with_pad: noise_ = self.noise_padding_layer(noise_) g_res_pad = self.img_padding_layer(g_res) else: g_res_pad = g_res if stage == 0 and self.with_positional_encode: noise = noise_ * noise_weights[stage] else: noise = noise_ * noise_weights[stage] + g_res_pad g_res = self.blocks[stage](noise.detach(), g_res) if get_prev_res and stage != curr_scale: prev_res_list.append(g_res) # upsample, here we use interpolation from PyTorch if stage != curr_scale: h_next, w_next = fixed_noises[stage + 1].shape[-2:] if self.noise_with_pad: # remove the additional padding if noise with pad h_next -= 2 * self.pad_head w_next -= 2 * self.pad_head g_res = self.upsample(g_res, (h_next, w_next)) if get_prev_res or return_noise: output_dict = dict( fake_img=g_res, prev_res_list=prev_res_list, noise_batch=noise_list) return output_dict return g_res ================================================ FILE: mmagic/models/editors/mspie/positional_encoding.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module('SPE') @MODELS.register_module('SPE2d') class SinusoidalPositionalEmbedding(BaseModule): """Sinusoidal Positional Embedding 1D or 2D (SPE/SPE2d). This module is a modified from: https://github.com/pytorch/fairseq/blob/master/fairseq/modules/sinusoidal_positional_embedding.py # noqa Based on the original SPE in single dimension, we implement a 2D sinusoidal positional encoding (SPE2d), as introduced in Positional Encoding as Spatial Inductive Bias in GANs, CVPR'2021. Args: embedding_dim (int): The number of dimensions for the positional encoding. padding_idx (int | list[int]): The index for the padding contents. The padding positions will obtain an encoding vector filling in zeros. init_size (int, optional): The initial size of the positional buffer. Defaults to 1024. div_half_dim (bool, optional): If true, the embedding will be divided by :math:`d/2`. Otherwise, it will be divided by :math:`(d/2 -1)`. Defaults to False. center_shift (int | None, optional): Shift the center point to some index. Defaults to None. """ def __init__(self, embedding_dim, padding_idx, init_size=1024, div_half_dim=False, center_shift=None): super().__init__() self.embedding_dim = embedding_dim self.padding_idx = padding_idx self.div_half_dim = div_half_dim self.center_shift = center_shift self.weights = SinusoidalPositionalEmbedding.get_embedding( init_size, embedding_dim, padding_idx, self.div_half_dim) self.register_buffer('_float_tensor', torch.FloatTensor(1)) self.max_positions = int(1e5) @staticmethod def get_embedding(num_embeddings, embedding_dim, padding_idx=None, div_half_dim=False): """Build sinusoidal embeddings. This matches the implementation in tensor2tensor, but differs slightly from the description in Section 3.5 of "Attention Is All You Need". """ assert embedding_dim % 2 == 0, ( 'In this version, we request ' f'embedding_dim divisible by 2 but got {embedding_dim}') # there is a little difference from the original paper. half_dim = embedding_dim // 2 if not div_half_dim: emb = np.log(10000) / (half_dim - 1) else: emb = np.log(1e4) / half_dim # compute exp(-log10000 / d * i) emb = torch.exp(torch.arange(half_dim, dtype=torch.float) * -emb) emb = torch.arange( num_embeddings, dtype=torch.float).unsqueeze(1) * emb.unsqueeze(0) emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1).view(num_embeddings, -1) if padding_idx is not None: emb[padding_idx, :] = 0 return emb def forward(self, input, **kwargs): """Input is expected to be of size [bsz x seqlen]. Returned tensor is expected to be of size [bsz x seq_len x emb_dim] """ assert input.dim() == 2 or input.dim( ) == 4, 'Input dimension should be 2 (1D) or 4(2D)' if input.dim() == 4: return self.make_grid2d_like(input, **kwargs) b, seq_len = input.shape max_pos = self.padding_idx + 1 + seq_len if self.weights is None or max_pos > self.weights.size(0): # recompute/expand embedding if needed self.weights = SinusoidalPositionalEmbedding.get_embedding( max_pos, self.embedding_dim, self.padding_idx) self.weights = self.weights.to(self._float_tensor) positions = self.make_positions(input, self.padding_idx).to( self._float_tensor.device) return self.weights.index_select(0, positions.view(-1)).view( b, seq_len, self.embedding_dim).detach() def make_positions(self, input, padding_idx): """Make position tensors. Args: input (tensor): Input tensor. padding_idx (int | list[int]): The index for the padding contents. The padding positions will obtain an encoding vector filling in zeros. Returns: tensor: Position tensors. """ mask = input.ne(padding_idx).int() return (torch.cumsum(mask, dim=1).type_as(mask) * mask).long() + padding_idx def make_grid2d(self, height, width, num_batches=1, center_shift=None): """Make 2-d grid mask. Args: height (int): Height of the grid. width (int): Width of the grid. num_batches (int, optional): The number of batch size. Defaults to 1. center_shift (int | None, optional): Shift the center point to some index. Defaults to None. Returns: Tensor: 2-d Grid mask. """ h, w = height, width # if `center_shift` is not given from the outside, use # `self.center_shift` if center_shift is None: center_shift = self.center_shift h_shift = 0 w_shift = 0 # center shift to the input grid if center_shift is not None: # if h/w is even, the left center should be aligned with # center shift if h % 2 == 0: h_left_center = h // 2 h_shift = center_shift - h_left_center else: h_center = h // 2 + 1 h_shift = center_shift - h_center if w % 2 == 0: w_left_center = w // 2 w_shift = center_shift - w_left_center else: w_center = w // 2 + 1 w_shift = center_shift - w_center # Note that the index is started from 1 since zero will be padding idx. # axis -- (b, h or w) x_axis = torch.arange(1, w + 1).unsqueeze(0).repeat(num_batches, 1) + w_shift y_axis = torch.arange(1, h + 1).unsqueeze(0).repeat(num_batches, 1) + h_shift # emb -- (b, emb_dim, h or w) x_emb = self(x_axis).transpose(1, 2) y_emb = self(y_axis).transpose(1, 2) # make grid for x/y axis # Note that repeat will copy data. If use learned emb, expand may be # better. x_grid = x_emb.unsqueeze(2).repeat(1, 1, h, 1) y_grid = y_emb.unsqueeze(3).repeat(1, 1, 1, w) # cat grid -- (b, 2 x emb_dim, h, w) grid = torch.cat([x_grid, y_grid], dim=1) return grid.detach() def make_grid2d_like(self, x, center_shift=None): """Input tensor with shape of (b, ..., h, w) Return tensor with shape of (b, 2 x emb_dim, h, w) Note that the positional embedding highly depends on the the function, ``make_positions``. """ h, w = x.shape[-2:] grid = self.make_grid2d(h, w, x.size(0), center_shift) return grid.to(x) @MODELS.register_module('CSG2d') @MODELS.register_module('CSG') @MODELS.register_module() class CatersianGrid(BaseModule): """Catersian Grid for 2d tensor. The Catersian Grid is a common-used positional encoding in deep learning. In this implementation, we follow the convention of ``grid_sample`` in PyTorch. In other words, ``[-1, -1]`` denotes the left-top corner while ``[1, 1]`` denotes the right-bottom corner. """ def forward(self, x, **kwargs): assert x.dim() == 4 return self.make_grid2d_like(x, **kwargs) def make_grid2d(self, height, width, num_batches=1, requires_grad=False): h, w = height, width grid_y, grid_x = torch.meshgrid(torch.arange(0, h), torch.arange(0, w)) grid_x = 2 * grid_x / max(float(w) - 1., 1.) - 1. grid_y = 2 * grid_y / max(float(h) - 1., 1.) - 1. grid = torch.stack((grid_x, grid_y), 0) grid.requires_grad = requires_grad grid = torch.unsqueeze(grid, 0) grid = grid.repeat(num_batches, 1, 1, 1) return grid def make_grid2d_like(self, x, requires_grad=False): """Input tensor with shape of (b, ..., h, w) Return tensor with shape of (b, 2 x emb_dim, h, w) Note that the positional embedding highly depends on the the function, ``make_grid2d``. """ h, w = x.shape[-2:] grid = self.make_grid2d(h, w, x.size(0), requires_grad=requires_grad) return grid.to(x) ================================================ FILE: mmagic/models/editors/nafnet/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .nafbaseline_net import NAFBaseline, NAFBaselineLocal from .nafnet_net import NAFNet, NAFNetLocal __all__ = [ 'NAFNet', 'NAFNetLocal', 'NAFBaseline', 'NAFBaselineLocal', ] ================================================ FILE: mmagic/models/editors/nafnet/naf_avgpool2d.py ================================================ # Copyright (c) 2022 megvii-model. All Rights Reserved. # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule class NAFAvgPool2d(BaseModule): """Average Pooling 2D used in NAFNet. Note: this is different from the normal AvgPool2d in pytorch. According to: Improving Image Restoration by Revisiting Global Information Aggregation statistics are aggregated in a local region for each pixel rather than the global average pooling. """ def __init__(self, kernel_size=None, base_size=None, auto_pad=True, fast_imp=False, train_size=None): super().__init__() self.kernel_size = kernel_size self.base_size = base_size self.auto_pad = auto_pad # only used for fast implementation self.fast_imp = fast_imp self.rs = [5, 4, 3, 2, 1] self.max_r1 = self.rs[0] self.max_r2 = self.rs[0] self.train_size = train_size def extra_repr(self) -> str: return 'kernel_size={}, base_size={}, stride={}, fast_imp={}'.format( self.kernel_size, self.base_size, self.kernel_size, self.fast_imp) def forward(self, x): if self.kernel_size is None and self.base_size: train_size = self.train_size if isinstance(self.base_size, int): self.base_size = (self.base_size, self.base_size) self.kernel_size = list(self.base_size) self.kernel_size[ 0] = x.shape[2] * self.base_size[0] // train_size[-2] self.kernel_size[ 1] = x.shape[3] * self.base_size[1] // train_size[-1] # only used for fast implementation self.max_r1 = max(1, self.rs[0] * x.shape[2] // train_size[-2]) self.max_r2 = max(1, self.rs[0] * x.shape[3] // train_size[-1]) if self.kernel_size[0] >= x.size(-2) and self.kernel_size[1] >= x.size( -1): return F.adaptive_avg_pool2d(x, 1) if self.fast_imp: # Non-equivalent implementation but faster h, w = x.shape[2:] if self.kernel_size[0] >= h and self.kernel_size[1] >= w: out = F.adaptive_avg_pool2d(x, 1) else: r1 = [r for r in self.rs if h % r == 0][0] r2 = [r for r in self.rs if w % r == 0][0] # reduction_constraint r1 = min(self.max_r1, r1) r2 = min(self.max_r2, r2) s = x[:, :, ::r1, ::r2].cumsum(dim=-1).cumsum(dim=-2) n, c, h, w = s.shape k1, k2 = min(h - 1, self.kernel_size[0] // r1), min(w - 1, self.kernel_size[1] // r2) out = (s[:, :, :-k1, :-k2] - s[:, :, :-k1, k2:] - s[:, :, k1:, :-k2] + s[:, :, k1:, k2:]) / ( k1 * k2) out = torch.nn.functional.interpolate( out, scale_factor=(r1, r2)) else: n, c, h, w = x.shape s = x.cumsum(dim=-1).cumsum_(dim=-2) s = torch.nn.functional.pad(s, (1, 0, 1, 0)) # pad 0 for convenience k1, k2 = min(h, self.kernel_size[0]), min(w, self.kernel_size[1]) s1, s2, s3, s4 = s[:, :, :-k1, :-k2], s[:, :, :-k1, k2:], s[:, :, k1:, :-k2], s[:, :, k1:, k2:] out = s4 + s1 - s2 - s3 out = out / (k1 * k2) if self.auto_pad: n, c, h, w = x.shape _h, _w = out.shape[2:] pad2d = ((w - _w) // 2, (w - _w + 1) // 2, (h - _h) // 2, (h - _h + 1) // 2) out = torch.nn.functional.pad(out, pad2d, mode='replicate') return out def replace_layers(model, base_size, train_size, fast_imp, **kwargs): """Replace all layers with AvgPool2d.""" for n, m in model.named_children(): if len(list(m.children())) > 0: # compound module, go inside it replace_layers(m, base_size, train_size, fast_imp, **kwargs) if isinstance(m, nn.AdaptiveAvgPool2d): pool = NAFAvgPool2d( base_size=base_size, fast_imp=fast_imp, train_size=train_size) assert m.output_size == 1 setattr(model, n, pool) class Local_Base(): """Local Base class to use global average pooling. args: train_size: training image size """ def convert(self, *args, train_size, **kwargs): replace_layers(self, *args, train_size=train_size, **kwargs) imgs = torch.rand(train_size) with torch.no_grad(): self.forward(imgs) ================================================ FILE: mmagic/models/editors/nafnet/naf_layerNorm2d.py ================================================ # Copyright (c) 2022 megvii-model. All Rights Reserved. # Copyright (c) OpenMMLab. All rights reserved. import torch from torch import nn as nn class LayerNormFunction(torch.autograd.Function): """Layer normalization.""" @staticmethod def forward(ctx, x, weight, bias, eps): ctx.eps = eps N, C, H, W = x.size() mu = x.mean(1, keepdim=True) var = (x - mu).pow(2).mean(1, keepdim=True) y = (x - mu) / (var + eps).sqrt() ctx.save_for_backward(y, var, weight) y = weight.view(1, C, 1, 1) * y + bias.view(1, C, 1, 1) return y @staticmethod def backward(ctx, grad_output): eps = ctx.eps N, C, H, W = grad_output.size() y, var, weight = ctx.saved_variables g = grad_output * weight.view(1, C, 1, 1) mean_g = g.mean(dim=1, keepdim=True) mean_gy = (g * y).mean(dim=1, keepdim=True) gx = 1. / torch.sqrt(var + eps) * (g - y * mean_gy - mean_g) return gx, (grad_output * y).sum(dim=3).sum(dim=2).sum( dim=0), grad_output.sum(dim=3).sum(dim=2).sum(dim=0), None class LayerNorm2d(nn.Module): """Layer normalization module. Note: This is different from the layernorm2d in pytorch. The layer norm here will handle different channels respectively. For more information, please refer to the issue: https://github.com/megvii-research/NAFNet/issues/35 """ def __init__(self, channels, eps=1e-6): super(LayerNorm2d, self).__init__() self.register_parameter('weight', nn.Parameter(torch.ones(channels))) self.register_parameter('bias', nn.Parameter(torch.zeros(channels))) self.eps = eps def forward(self, x): return LayerNormFunction.apply(x, self.weight, self.bias, self.eps) ================================================ FILE: mmagic/models/editors/nafnet/nafbaseline_net.py ================================================ # Copyright (c) 2022 megvii-model. All Rights Reserved. # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from .naf_avgpool2d import Local_Base from .naf_layerNorm2d import LayerNorm2d @MODELS.register_module() class NAFBaseline(BaseModule): """The original version of Baseline model in "Simple Baseline for Image Restoration". Args: img_channels (int): Channel number of inputs. mid_channels (int): Channel number of intermediate features. middle_blk_num (int): Number of middle blocks. enc_blk_nums (List of int): Number of blocks for each encoder. dec_blk_nums (List of int): Number of blocks for each decoder. """ def __init__(self, img_channel=3, mid_channels=16, middle_blk_num=1, enc_blk_nums=[1, 1, 1, 28], dec_blk_nums=[1, 1, 1, 1], dw_expand=1, ffn_expand=2): super().__init__() self.intro = nn.Conv2d( in_channels=img_channel, out_channels=mid_channels, kernel_size=3, padding=1, stride=1, groups=1, bias=True) self.ending = nn.Conv2d( in_channels=mid_channels, out_channels=img_channel, kernel_size=3, padding=1, stride=1, groups=1, bias=True) self.encoders = nn.ModuleList() self.decoders = nn.ModuleList() self.middle_blks = nn.ModuleList() self.ups = nn.ModuleList() self.downs = nn.ModuleList() chan = mid_channels for num in enc_blk_nums: self.encoders.append( nn.Sequential(*[ BaselineBlock(chan, dw_expand, ffn_expand) for _ in range(num) ])) self.downs.append(nn.Conv2d(chan, 2 * chan, 2, 2)) chan = chan * 2 self.middle_blks = \ nn.Sequential( *[BaselineBlock(chan, dw_expand, ffn_expand) for _ in range(middle_blk_num)] ) for num in dec_blk_nums: self.ups.append( nn.Sequential( nn.Conv2d(chan, chan * 2, 1, bias=False), nn.PixelShuffle(2))) chan = chan // 2 self.decoders.append( nn.Sequential(*[ BaselineBlock(chan, dw_expand, ffn_expand) for _ in range(num) ])) self.padder_size = 2**len(self.encoders) def forward(self, inp): """Forward function. args: inp: input tensor image with (B, C, H, W) shape """ B, C, H, W = inp.shape inp = self.check_image_size(inp) x = self.intro(inp) encs = [] for encoder, down in zip(self.encoders, self.downs): x = encoder(x) encs.append(x) x = down(x) x = self.middle_blks(x) for decoder, up, enc_skip in zip(self.decoders, self.ups, encs[::-1]): x = up(x) x = x + enc_skip x = decoder(x) x = self.ending(x) x = x + inp return x[:, :, :H, :W] def check_image_size(self, x): """Check image size and pad images so that it has enough dimension do downsample. args: x: input tensor image with (B, C, H, W) shape. """ _, _, h, w = x.size() mod_pad_h = (self.padder_size - h % self.padder_size) % self.padder_size mod_pad_w = (self.padder_size - w % self.padder_size) % self.padder_size x = F.pad(x, (0, mod_pad_w, 0, mod_pad_h)) return x @MODELS.register_module() class NAFBaselineLocal(Local_Base, NAFBaseline): """The original version of Baseline model in "Simple Baseline for Image Restoration". Args: img_channels (int): Channel number of inputs. mid_channels (int): Channel number of intermediate features. middle_blk_num (int): Number of middle blocks. enc_blk_nums (List of int): Number of blocks for each encoder. dec_blk_nums (L`ist of int): Number of blocks for each decoder. """ def __init__(self, *args, train_size=(1, 3, 256, 256), fast_imp=False, **kwargs): Local_Base.__init__(self) NAFBaseline.__init__(self, *args, **kwargs) N, C, H, W = train_size base_size = (int(H * 1.5), int(W * 1.5)) self.eval() with torch.no_grad(): self.convert( base_size=base_size, train_size=train_size, fast_imp=fast_imp) # Components for Baseline class BaselineBlock(BaseModule): """Baseline's Block in paper. Args: in_channels (int): number of channels DW_Expand (int): channel expansion factor for part 1 FFN_Expand (int): channel expansion factor for part 2 drop_out_rate (float): drop out ratio """ def __init__(self, in_channels, DW_Expand=1, FFN_Expand=2, drop_out_rate=0.): super().__init__() dw_channel = in_channels * DW_Expand self.conv1 = nn.Conv2d( in_channels=in_channels, out_channels=dw_channel, kernel_size=1, padding=0, stride=1, groups=1, bias=True) self.conv2 = nn.Conv2d( in_channels=dw_channel, out_channels=dw_channel, kernel_size=3, padding=1, stride=1, groups=dw_channel, bias=True) self.conv3 = nn.Conv2d( in_channels=dw_channel, out_channels=in_channels, kernel_size=1, padding=0, stride=1, groups=1, bias=True) # Channel Attention self.se = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d( in_channels=dw_channel, out_channels=dw_channel // 2, kernel_size=1, padding=0, stride=1, groups=1, bias=True), nn.ReLU(inplace=True), nn.Conv2d( in_channels=dw_channel // 2, out_channels=dw_channel, kernel_size=1, padding=0, stride=1, groups=1, bias=True), nn.Sigmoid()) # GELU self.gelu = nn.GELU() ffn_channel = FFN_Expand * in_channels self.conv4 = nn.Conv2d( in_channels=in_channels, out_channels=ffn_channel, kernel_size=1, padding=0, stride=1, groups=1, bias=True) self.conv5 = nn.Conv2d( in_channels=ffn_channel, out_channels=in_channels, kernel_size=1, padding=0, stride=1, groups=1, bias=True) self.norm1 = LayerNorm2d(in_channels) self.norm2 = LayerNorm2d(in_channels) self.dropout1 = nn.Dropout( drop_out_rate) if drop_out_rate > 0. else nn.Identity() self.dropout2 = nn.Dropout( drop_out_rate) if drop_out_rate > 0. else nn.Identity() self.beta = nn.Parameter( torch.zeros((1, in_channels, 1, 1)), requires_grad=True) self.gamma = nn.Parameter( torch.zeros((1, in_channels, 1, 1)), requires_grad=True) def forward(self, inp): """Forward Function. Args: inp: input tensor image """ x = inp x = self.norm1(x) x = self.conv1(x) x = self.conv2(x) x = self.gelu(x) x = x * self.se(x) x = self.conv3(x) x = self.dropout1(x) y = inp + x * self.beta x = self.conv4(self.norm2(y)) x = self.gelu(x) x = self.conv5(x) x = self.dropout2(x) return y + x * self.gamma ================================================ FILE: mmagic/models/editors/nafnet/nafnet_net.py ================================================ # Copyright (c) 2022 megvii-model. All Rights Reserved. # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from .naf_avgpool2d import Local_Base from .naf_layerNorm2d import LayerNorm2d @MODELS.register_module() class NAFNet(BaseModule): """NAFNet. The original version of NAFNet in "Simple Baseline for Image Restoration". Args: img_channels (int): Channel number of inputs. mid_channels (int): Channel number of intermediate features. middle_blk_num (int): Number of middle blocks. enc_blk_nums (List of int): Number of blocks for each encoder. dec_blk_nums (List of int): Number of blocks for each decoder. """ def __init__(self, img_channels=3, mid_channels=16, middle_blk_num=1, enc_blk_nums=[], dec_blk_nums=[]): super().__init__() self.intro = nn.Conv2d( in_channels=img_channels, out_channels=mid_channels, kernel_size=3, padding=1, stride=1, groups=1, bias=True) self.ending = nn.Conv2d( in_channels=mid_channels, out_channels=img_channels, kernel_size=3, padding=1, stride=1, groups=1, bias=True) self.encoders = nn.ModuleList() self.decoders = nn.ModuleList() self.middle_blks = nn.ModuleList() self.ups = nn.ModuleList() self.downs = nn.ModuleList() chan = mid_channels for num in enc_blk_nums: self.encoders.append( nn.Sequential(*[NAFBlock(chan) for _ in range(num)])) self.downs.append(nn.Conv2d(chan, 2 * chan, 2, 2)) chan = chan * 2 self.middle_blks = \ nn.Sequential( *[NAFBlock(chan) for _ in range(middle_blk_num)] ) for num in dec_blk_nums: self.ups.append( nn.Sequential( nn.Conv2d(chan, chan * 2, 1, bias=False), nn.PixelShuffle(2))) chan = chan // 2 self.decoders.append( nn.Sequential(*[NAFBlock(chan) for _ in range(num)])) self.padder_size = 2**len(self.encoders) def forward(self, inp): """Forward function. args: inp: input tensor image with (B, C, H, W) shape """ B, C, H, W = inp.shape inp = self.check_image_size(inp) x = self.intro(inp) encs = [] for encoder, down in zip(self.encoders, self.downs): x = encoder(x) encs.append(x) x = down(x) x = self.middle_blks(x) for decoder, up, enc_skip in zip(self.decoders, self.ups, encs[::-1]): x = up(x) x = x + enc_skip x = decoder(x) x = self.ending(x) x = x + inp return x[:, :, :H, :W] def check_image_size(self, x): """Check image size and pad images so that it has enough dimension do downsample. args: x: input tensor image with (B, C, H, W) shape. """ _, _, h, w = x.size() mod_pad_h = (self.padder_size - h % self.padder_size) % self.padder_size mod_pad_w = (self.padder_size - w % self.padder_size) % self.padder_size x = F.pad(x, (0, mod_pad_w, 0, mod_pad_h)) return x @MODELS.register_module() class NAFNetLocal(Local_Base, NAFNet): """The original version of NAFNetLocal in "Simple Baseline for Image Restoration". NAFNetLocal uses local average pooling modules than NAFNet. Args: img_channels (int): Channel number of inputs. mid_channels (int): Channel number of intermediate features. middle_blk_num (int): Number of middle blocks. enc_blk_nums (List of int): Number of blocks for each encoder. dec_blk_nums (List of int): Number of blocks for each decoder. """ def __init__(self, *args, train_size=(1, 3, 256, 256), fast_imp=False, **kwargs): Local_Base.__init__(self) NAFNet.__init__(self, *args, **kwargs) N, C, H, W = train_size base_size = (int(H * 1.5), int(W * 1.5)) self.eval() with torch.no_grad(): self.convert( base_size=base_size, train_size=train_size, fast_imp=fast_imp) # Components for NAFNet class NAFBlock(BaseModule): """NAFNet's Block in paper. Simple gate will shrink the channel to a half. To keep the number of channels, it expands the channels first. Args: in_channels (int): number of channels DW_Expand (int): channel expansion factor for part 1 FFN_Expand (int): channel expansion factor for part 2 drop_out_rate (float): drop out ratio """ def __init__(self, in_channels, DW_Expand=2, FFN_Expand=2, drop_out_rate=0.): super().__init__() # Part 1 dw_channel = in_channels * DW_Expand self.conv1 = nn.Conv2d( in_channels=in_channels, out_channels=dw_channel, kernel_size=1, padding=0, stride=1, groups=1, bias=True) self.conv2 = nn.Conv2d( in_channels=dw_channel, out_channels=dw_channel, kernel_size=3, padding=1, stride=1, groups=dw_channel, bias=True) # Simplified Channel Attention self.sca = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d( in_channels=dw_channel // 2, out_channels=dw_channel // 2, kernel_size=1, padding=0, stride=1, groups=1, bias=True), ) self.conv3 = nn.Conv2d( in_channels=dw_channel // 2, out_channels=in_channels, kernel_size=1, padding=0, stride=1, groups=1, bias=True) # Part 2 ffn_channel = FFN_Expand * in_channels self.conv4 = nn.Conv2d( in_channels=in_channels, out_channels=ffn_channel, kernel_size=1, padding=0, stride=1, groups=1, bias=True) self.conv5 = nn.Conv2d( in_channels=ffn_channel // 2, out_channels=in_channels, kernel_size=1, padding=0, stride=1, groups=1, bias=True) # Simple Gate self.sg = SimpleGate() # Layer Normalization self.norm1 = LayerNorm2d(in_channels) self.norm2 = LayerNorm2d(in_channels) # Dropout self.dropout1 = nn.Dropout( drop_out_rate) if drop_out_rate > 0. else nn.Identity() self.dropout2 = nn.Dropout( drop_out_rate) if drop_out_rate > 0. else nn.Identity() # Feature weight ratio self.beta = nn.Parameter( torch.zeros((1, in_channels, 1, 1)), requires_grad=True) self.gamma = nn.Parameter( torch.zeros((1, in_channels, 1, 1)), requires_grad=True) def forward(self, inp): """Forward Function. Args: inp: input tensor image """ x = inp # part 1 x = self.norm1(x) x = self.conv1(x) x = self.conv2(x) x = self.sg(x) x = x * self.sca(x) x = self.conv3(x) x = self.dropout1(x) y = inp + x * self.beta # part 2 x = self.norm2(y) x = self.conv4(x) x = self.sg(x) x = self.conv5(x) x = self.dropout2(x) out = y + x * self.gamma return out class SimpleGate(BaseModule): """The Simple Gate in "Simple Baseline for Image Restoration". Args: x: input tensor feature map with (B, 2 * C, H, W) Return: x1 * x2 (where x1, x2 are two separate parts by simple split x to [B, C, H, W]) """ def forward(self, x): x1, x2 = x.chunk(2, dim=1) return x1 * x2 ================================================ FILE: mmagic/models/editors/pconv/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .mask_conv_module import MaskConvModule from .partial_conv import PartialConv2d from .pconv_decoder import PConvDecoder from .pconv_encoder import PConvEncoder from .pconv_encoder_decoder import PConvEncoderDecoder from .pconv_inpaintor import PConvInpaintor __all__ = [ 'PConvEncoder', 'PConvDecoder', 'PConvEncoderDecoder', 'PConvInpaintor', 'MaskConvModule', 'PartialConv2d', 'MaskConvModule' ] ================================================ FILE: mmagic/models/editors/pconv/mask_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmcv.cnn import ConvModule class MaskConvModule(ConvModule): """Mask convolution module. This is a simple wrapper for mask convolution like: 'partial conv'. Convolutions in this module always need a mask as extra input. Args: in_channels (int): Same as nn.Conv2d. out_channels (int): Same as nn.Conv2d. kernel_size (int or tuple[int]): Same as nn.Conv2d. stride (int or tuple[int]): Same as nn.Conv2d. padding (int or tuple[int]): Same as nn.Conv2d. dilation (int or tuple[int]): Same as nn.Conv2d. groups (int): Same as nn.Conv2d. bias (bool or str): If specified as `auto`, it will be decided by the norm_cfg. Bias will be set as True if norm_cfg is None, otherwise False. conv_cfg (dict): Config dict for convolution layer. norm_cfg (dict): Config dict for normalization layer. act_cfg (dict): Config dict for activation layer, "relu" by default. inplace (bool): Whether to use inplace mode for activation. with_spectral_norm (bool): Whether use spectral norm in conv module. padding_mode (str): If the `padding_mode` has not been supported by current `Conv2d` in Pytorch, we will use our own padding layer instead. Currently, we support ['zeros', 'circular'] with official implementation and ['reflect'] with our own implementation. Default: 'zeros'. order (tuple[str]): The order of conv/norm/activation layers. It is a sequence of "conv", "norm" and "act". Examples are ("conv", "norm", "act") and ("act", "conv", "norm"). """ supported_conv_list = ['PConv'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) assert self.conv_cfg['type'] in self.supported_conv_list self.init_weights() def forward(self, x, mask=None, activate=True, norm=True, return_mask=True): """Forward function for partial conv2d. Args: x (torch.Tensor): Tensor with shape of (n, c, h, w). mask (torch.Tensor): Tensor with shape of (n, c, h, w) or (n, 1, h, w). If mask is not given, the function will work as standard conv2d. Default: None. activate (bool): Whether use activation layer. norm (bool): Whether use norm layer. return_mask (bool): If True and mask is not None, the updated mask will be returned. Default: True. Returns: Tensor or tuple: Result Tensor or 2-tuple of ``Tensor``: Results after partial conv. ``Tensor``: Updated mask will be returned if mask is given \ and `return_mask` is True. """ for layer in self.order: if layer == 'conv': if self.with_explicit_padding: x = self.padding_layer(x) mask = self.padding_layer(mask) if return_mask: x, updated_mask = self.conv( x, mask, return_mask=return_mask) else: x = self.conv(x, mask, return_mask=False) elif layer == 'norm' and norm and self.with_norm: x = self.norm(x) elif layer == 'act' and activate and self.with_activation: x = self.activate(x) if return_mask: return x, updated_mask return x ================================================ FILE: mmagic/models/editors/pconv/partial_conv.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS @MODELS.register_module(name='PConv') class PartialConv2d(nn.Conv2d): """Implementation for partial convolution. Image Inpainting for Irregular Holes Using Partial Convolutions [https://arxiv.org/abs/1804.07723] Args: multi_channel (bool): If True, the mask is multi-channel. Otherwise, the mask is single-channel. eps (float): Need to be changed for mixed precision training. For mixed precision training, you need change 1e-8 to 1e-6. """ def __init__(self, *args, multi_channel=False, eps=1e-8, **kwargs): super().__init__(*args, **kwargs) # whether the mask is multi-channel or not self.multi_channel = multi_channel self.eps = eps if self.multi_channel: out_channels, in_channels = self.out_channels, self.in_channels else: out_channels, in_channels = 1, 1 self.register_buffer( 'weight_mask_updater', torch.ones(out_channels, in_channels, self.kernel_size[0], self.kernel_size[1])) self.mask_kernel_numel = np.prod(self.weight_mask_updater.shape[1:4]) self.mask_kernel_numel = (self.mask_kernel_numel).item() def forward(self, input, mask=None, return_mask=True): """Forward function for partial conv2d. Args: input (torch.Tensor): Tensor with shape of (n, c, h, w). mask (torch.Tensor): Tensor with shape of (n, c, h, w) or (n, 1, h, w). If mask is not given, the function will work as standard conv2d. Default: None. return_mask (bool): If True and mask is not None, the updated mask will be returned. Default: True. Returns: torch.Tensor : Results after partial conv.\ torch.Tensor : Updated mask will be returned if mask is given and \ ``return_mask`` is True. """ assert input.dim() == 4 if mask is not None: assert mask.dim() == 4 if self.multi_channel: assert mask.shape[1] == input.shape[1] else: assert mask.shape[1] == 1 # update mask and compute mask ratio if mask is not None: with torch.no_grad(): updated_mask = F.conv2d( mask, self.weight_mask_updater, bias=None, stride=self.stride, padding=self.padding, dilation=self.dilation) mask_ratio = self.mask_kernel_numel / (updated_mask + self.eps) updated_mask = torch.clamp(updated_mask, 0, 1) mask_ratio = mask_ratio * updated_mask # standard conv2d if mask is not None: input = input * mask raw_out = super().forward(input) if mask is not None: if self.bias is None: output = raw_out * mask_ratio else: # compute new bias when mask is given bias_view = self.bias.view(1, self.out_channels, 1, 1) output = (raw_out - bias_view) * mask_ratio + bias_view output = output * updated_mask else: output = raw_out if return_mask and mask is not None: return output, updated_mask return output ================================================ FILE: mmagic/models/editors/pconv/pconv_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from .mask_conv_module import MaskConvModule @MODELS.register_module() class PConvDecoder(BaseModule): """Decoder with partial conv. About the details for this architecture, pls see: Image Inpainting for Irregular Holes Using Partial Convolutions Args: num_layers (int): The number of convolutional layers. Default: 7. interpolation (str): The upsample mode. Default: 'nearest'. conv_cfg (dict): Config for convolution module. Default: {'type': 'PConv', 'multi_channel': True}. norm_cfg (dict): Config for norm layer. Default: {'type': 'BN'}. """ def __init__(self, num_layers=7, interpolation='nearest', conv_cfg=dict(type='PConv', multi_channel=True), norm_cfg=dict(type='BN')): super().__init__() self.num_layers = num_layers self.interpolation = interpolation for i in range(4, num_layers): name = f'dec{i+1}' self.add_module( name, MaskConvModule( 512 + 512, 512, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2))) self.dec4 = MaskConvModule( 512 + 256, 256, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) self.dec3 = MaskConvModule( 256 + 128, 128, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) self.dec2 = MaskConvModule( 128 + 64, 64, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) self.dec1 = MaskConvModule( 64 + 3, 3, kernel_size=3, stride=1, padding=1, conv_cfg=conv_cfg, norm_cfg=None, act_cfg=None) def forward(self, input_dict): """Forward Function. Args: input_dict (dict | torch.Tensor): Input dict with middle features or torch.Tensor. Returns: torch.Tensor: Output tensor with shape of (n, c, h, w). """ hidden_feats = input_dict['hidden_feats'] hidden_masks = input_dict['hidden_masks'] h_key = 'h{:d}'.format(self.num_layers) h, h_mask = hidden_feats[h_key], hidden_masks[h_key] for i in range(self.num_layers, 0, -1): enc_h_key = f'h{i-1}' dec_l_key = f'dec{i}' h = F.interpolate(h, scale_factor=2, mode=self.interpolation) h_mask = F.interpolate( h_mask, scale_factor=2, mode=self.interpolation) h = torch.cat([h, hidden_feats[enc_h_key]], dim=1) h_mask = torch.cat([h_mask, hidden_masks[enc_h_key]], dim=1) h, h_mask = getattr(self, dec_l_key)(h, h_mask) return h, h_mask ================================================ FILE: mmagic/models/editors/pconv/pconv_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import BaseModule from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.models.editors.pconv.mask_conv_module import MaskConvModule from mmagic.registry import MODELS @MODELS.register_module() class PConvEncoder(BaseModule): """Encoder with partial conv. About the details for this architecture, pls see: Image Inpainting for Irregular Holes Using Partial Convolutions Args: in_channels (int): The number of input channels. Default: 3. num_layers (int): The number of convolutional layers. Default: 7. conv_cfg (dict): Config for convolution module. Default: {'type': 'PConv', 'multi_channel': True}. norm_cfg (dict): Config for norm layer. Default: {'type': 'BN'}. norm_eval (bool): Whether to set norm layers to eval mode, namely, freeze running stats (mean and var). Note: Effective on Batch Norm and its variants only. Default: False. """ def __init__(self, in_channels=3, num_layers=7, conv_cfg=dict(type='PConv', multi_channel=True), norm_cfg=dict(type='BN', requires_grad=True), norm_eval=False): super().__init__() self.num_layers = num_layers self.norm_eval = norm_eval self.enc1 = MaskConvModule( in_channels, 64, kernel_size=7, stride=2, padding=3, conv_cfg=conv_cfg, norm_cfg=None, act_cfg=dict(type='ReLU')) self.enc2 = MaskConvModule( 64, 128, kernel_size=5, stride=2, padding=2, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')) self.enc3 = MaskConvModule( 128, 256, kernel_size=5, stride=2, padding=2, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')) self.enc4 = MaskConvModule( 256, 512, kernel_size=3, stride=2, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')) for i in range(4, num_layers): name = f'enc{i+1}' self.add_module( name, MaskConvModule( 512, 512, kernel_size=3, stride=2, padding=1, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU'))) def train(self, mode=True): """Set BatchNorm modules in the model to evaluation mode.""" super().train(mode) if mode and self.norm_eval: for m in self.modules(): # trick: eval have effect on BatchNorm only if isinstance(m, _BatchNorm): m.eval() def forward(self, x, mask): """Forward function for partial conv encoder. Args: x (torch.Tensor): Masked image with shape (n, c, h, w). mask (torch.Tensor): Mask tensor with shape (n, c, h, w). Returns: dict: Contains the results and middle level features in this \ module. `hidden_feats` contain the middle feature maps and \ `hidden_masks` store updated masks. """ # dict for hidden layers of main information flow hidden_feats = {} # dict for hidden layers of mask information flow hidden_masks = {} hidden_feats['h0'], hidden_masks['h0'] = x, mask h_key_prev = 'h0' for i in range(1, self.num_layers + 1): l_key = f'enc{i}' h_key = f'h{i}' hidden_feats[h_key], hidden_masks[h_key] = getattr(self, l_key)( hidden_feats[h_key_prev], hidden_masks[h_key_prev]) h_key_prev = h_key outputs = dict( out=hidden_feats[f'h{self.num_layers}'], hidden_feats=hidden_feats, hidden_masks=hidden_masks) return outputs ================================================ FILE: mmagic/models/editors/pconv/pconv_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class PConvEncoderDecoder(BaseModule): """Encoder-Decoder with partial conv module. Args: encoder (dict): Config of the encoder. decoder (dict): Config of the decoder. """ def __init__(self, encoder, decoder): super().__init__() self.encoder = MODELS.build(encoder) self.decoder = MODELS.build(decoder) # support fp16 self.fp16_enabled = False def forward(self, x, mask_in): """Forward Function. Args: x (torch.Tensor): Input tensor with shape of (n, c, h, w). mask_in (torch.Tensor): Input tensor with shape of (n, c, h, w). Returns: torch.Tensor: Output tensor with shape of (n, c, h', w'). """ enc_outputs = self.encoder(x, mask_in) x, final_mask = self.decoder(enc_outputs) return x, final_mask ================================================ FILE: mmagic/models/editors/pconv/pconv_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List from mmagic.models.base_models import OneStageInpaintor from mmagic.registry import MODELS @MODELS.register_module() class PConvInpaintor(OneStageInpaintor): """Inpaintor for Partial Convolution method. This inpaintor is implemented according to the paper: Image inpainting for irregular holes using partial convolutions """ def forward_tensor(self, inputs, data_samples): """Forward function in tensor mode. Args: inputs (torch.Tensor): Input tensor. data_sample (dict): Dict contains data sample. Returns: dict: Dict contains output results. """ masked_img = inputs # N,3,H,W masks = data_samples.mask masks = 1. - masks masks = masks.repeat(1, 3, 1, 1) fake_reses, _ = self.generator(masked_img, masks) fake_imgs = fake_reses * (1. - masks) + masked_img * masks return fake_reses, fake_imgs def train_step(self, data: List[dict], optim_wrapper): """Train step function. In this function, the inpaintor will finish the train step following the pipeline: 1. get fake res/image 2. optimize discriminator (if have) 3. optimize generator If `self.train_cfg.disc_step > 1`, the train step will contain multiple iterations for optimizing discriminator with different input data and only one iteration for optimizing generator after `disc_step` iterations for discriminator. Args: data (List[dict]): Batch of data as input. optim_wrapper (dict[torch.optim.Optimizer]): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of \ samples and results for visualization. """ data = self.data_preprocessor(data, True) batch_inputs, data_samples = data['inputs'], data['data_samples'] log_vars = {} masked_img = batch_inputs # float gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() mask_input = mask.expand_as(gt_img) mask_input = 1. - mask_input fake_res, final_mask = self.generator(masked_img, mask_input) fake_img = gt_img * (1. - mask) + fake_res * mask results, g_losses = self.generator_loss(fake_res, fake_img, gt_img, mask, masked_img) loss_g_, log_vars_g = self.parse_losses(g_losses) log_vars.update(log_vars_g) optim_wrapper.zero_grad() optim_wrapper.backward(loss_g_) optim_wrapper.step() return log_vars ================================================ FILE: mmagic/models/editors/pggan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .pggan import ProgressiveGrowingGAN from .pggan_discriminator import PGGANDiscriminator from .pggan_generator import PGGANGenerator from .pggan_modules import (EqualizedLR, EqualizedLRConvDownModule, EqualizedLRConvModule, EqualizedLRConvUpModule, EqualizedLRLinearModule, MiniBatchStddevLayer, PGGANNoiseTo2DFeat, PixelNorm, equalized_lr) __all__ = [ 'ProgressiveGrowingGAN', 'EqualizedLR', 'equalized_lr', 'EqualizedLRConvModule', 'EqualizedLRLinearModule', 'EqualizedLRConvUpModule', 'EqualizedLRConvDownModule', 'PixelNorm', 'MiniBatchStddevLayer', 'PGGANNoiseTo2DFeat', 'PGGANGenerator', 'PGGANDiscriminator' ] ================================================ FILE: mmagic/models/editors/pggan/pggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial from typing import Dict, List, Optional, Tuple, Union import mmengine import numpy as np import torch import torch.autograd as autograd import torch.nn as nn import torch.nn.functional as F from mmengine import MessageHub from mmengine.dist import get_world_size from mmengine.model import is_model_wrapper from mmengine.optim import OptimWrapper, OptimWrapperDict from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, SampleList from ...base_models import BaseGAN from ...utils import get_valid_num_batches, set_requires_grad ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module('PGGAN') @MODELS.register_module() class ProgressiveGrowingGAN(BaseGAN): """Progressive Growing Unconditional GAN. In this GAN model, we implement progressive growing training schedule, which is proposed in Progressive Growing of GANs for improved Quality, Stability and Variation, ICLR 2018. We highly recommend to use ``GrowScaleImgDataset`` for saving computational load in data pre-processing. Notes for **using PGGAN**: #. In official implementation, Tero uses gradient penalty with ``norm_mode="HWC"`` #. We do not implement ``minibatch_repeats`` where has been used in official Tensorflow implementation. Notes for resuming progressive growing GANs: Users should specify the ``prev_stage`` in ``train_cfg``. Otherwise, the model is possible to reset the optimizer status, which will bring inferior performance. For example, if your model is resumed from the `256` stage, you should set ``train_cfg=dict(prev_stage=256)``. Args: generator (dict): Config for generator. discriminator (dict): Config for discriminator. """ def __init__(self, generator, discriminator, data_preprocessor, nkimgs_per_scale, noise_size=None, interp_real=None, transition_kimgs: int = 600, prev_stage: int = 0, ema_config: Optional[Dict] = None): super().__init__(generator, discriminator, data_preprocessor, 1, 1, noise_size, ema_config) # register necessary training status self.register_buffer('shown_nkimg', torch.tensor(0.)) self.register_buffer('_curr_transition_weight', torch.tensor(1.)) if interp_real is None: interp_real = dict(mode='bilinear', align_corners=True) self.interp_real_to = partial(F.interpolate, **interp_real) self.scales, self.nkimgs = [], [] for k, v in nkimgs_per_scale.items(): # support for different data types if isinstance(k, str): k = (int(k), int(k)) elif isinstance(k, int): k = (k, k) else: assert mmengine.is_tuple_of(k, int) # sanity check for the order of scales assert len(self.scales) == 0 or k[0] > self.scales[-1][0] self.scales.append(k) self.nkimgs.append(v) self.cum_nkimgs = np.cumsum(self.nkimgs) self.curr_stage = 0 # dirty workaround for avoiding optimizer bug in resuming self.prev_stage = prev_stage # actually nkimgs shown at the end of per training stage self._actual_nkimgs = [] # In each scale, transit from previous torgb layer to newer torgb layer # with `transition_kimgs` imgs self.transition_kimgs = transition_kimgs # this buffer is used to resume model easily self.register_buffer( '_next_scale_int', torch.tensor(self.scales[0][0], dtype=torch.int32)) # TODO: init it with the same value as `_next_scale_int` # a dirty workaround for testing self.register_buffer( '_curr_scale_int', torch.tensor(self.scales[-1][0], dtype=torch.int32)) def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> SampleList: """Sample images from noises by using the generator. Args: batch_inputs (ForwardInputs): Dict containing the necessary information (e.g. noise, num_batches, mode) to generate image. data_samples (Optional[list]): Data samples collated by :attr:`data_preprocessor`. Defaults to None. mode (Optional[str]): `mode` is not used in :class:`ProgressiveGrowingGAN`. Defaults to None. Returns: SampleList: A list of ``DataSample`` contain generated results. """ if isinstance(inputs, Tensor): noise = inputs curr_scale = transition_weight = None else: noise = inputs.get('noise', None) num_batches = get_valid_num_batches(inputs, data_samples) noise = self.noise_fn(noise, num_batches=num_batches) curr_scale = inputs.get('curr_scale', None) transition_weight = inputs.get('transition_weight', None) num_batches = noise.shape[0] # use `self.curr_scale` if curr_scale is None if curr_scale is None: # in training, 'curr_scale' will be set as attribute if hasattr(self, 'curr_scale'): curr_scale = self.curr_scale[0] # in testing, adopt '_curr_scale_int' from buffer as testing scale else: curr_scale = self._curr_scale_int.item() # use `self._curr_transition_weight` if `transition_weight` is None if transition_weight is None: transition_weight = self._curr_transition_weight.item() sample_model = self._get_valid_model(inputs) batch_sample_list = [] if sample_model in ['ema', 'orig']: if sample_model == 'ema': generator = self.generator_ema else: generator = self.generator outputs = generator( noise, curr_scale=curr_scale, transition_weight=transition_weight) outputs = self.data_preprocessor.destruct(outputs, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.fake_img = outputs gen_sample.sample_model = sample_model gen_sample.noise = noise batch_sample_list = gen_sample.split(allow_nonseq_value=True) else: # sample model is 'ema/orig' outputs_orig = self.generator( noise, curr_scale=curr_scale, transition_weight=transition_weight) outputs_ema = self.generator_ema( noise, curr_scale=curr_scale, transition_weight=transition_weight) outputs_orig = self.data_preprocessor.destruct( outputs_orig, data_samples) outputs_ema = self.data_preprocessor.destruct( outputs_ema, data_samples) gen_sample = DataSample() if data_samples: gen_sample.update(data_samples) if isinstance(inputs, dict) and 'img' in inputs: gen_sample.gt_img = inputs['img'] gen_sample.ema = DataSample(fake_img=outputs_ema) gen_sample.orig = DataSample(fake_img=outputs_orig) gen_sample.noise = noise gen_sample.sample_model = 'ema/orig' batch_sample_list = gen_sample.split(allow_nonseq_value=True) return batch_sample_list def train_discriminator(self, inputs: Tensor, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (Tensor): Inputs from current resolution training. data_samples (List[DataSample]): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = inputs num_batches = len(data_samples) noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise_batch, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight, return_noise=False) disc_pred_fake = self.discriminator( fake_imgs, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) disc_pred_real = self.discriminator( real_imgs, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) parsed_loss, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real, fake_imgs, real_imgs) optimizer_wrapper.update_params(parsed_loss) return log_vars def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor, fake_data: Tensor, real_data: Tensor) -> Tuple[Tensor, dict]: r"""Get disc loss. PGGAN use WGAN-GP's loss and discriminator shift loss to train the discriminator. .. math: L_{D} = \mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) - \mathbb{E}_{x\sim{p_{data}}}D\left\(x\right\) + L_{GP} \\ L_{GP} = \lambda\mathbb{E}(\Vert\nabla_{\tilde{x}}D(\tilde{x}) \Vert_2-1)^2 \\ \tilde{x} = \epsilon x + (1-\epsilon)G(z) L_{shift} = Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. fake_data (Tensor): Generated images, used to calculate gradient penalty. real_data (Tensor): Real images, used to calculate gradient penalty. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = disc_pred_fake.mean() losses_dict['loss_disc_real'] = -disc_pred_real.mean() # gradient penalty batch_size = real_data.size(0) alpha = torch.rand(batch_size, 1, 1, 1).to(real_data) # interpolate between real_data and fake_data interpolates = alpha * real_data + (1. - alpha) * fake_data interpolates = autograd.Variable(interpolates, requires_grad=True) disc_interpolates = self.discriminator( interpolates, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) gradients = autograd.grad( outputs=disc_interpolates, inputs=interpolates, grad_outputs=torch.ones_like(disc_interpolates), create_graph=True, retain_graph=True, only_inputs=True)[0] # norm_mode is 'HWC' gradients_penalty = (( gradients.reshape(batch_size, -1).norm(2, dim=1) - 1)**2).mean() losses_dict['loss_gp'] = 10 * gradients_penalty losses_dict['loss_disc_shift'] = 0.001 * 0.5 * ( disc_pred_fake**2 + disc_pred_real**2) parsed_loss, log_vars = self.parse_losses(losses_dict) return parsed_loss, log_vars def train_generator(self, inputs: Tensor, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (Tensor): Inputs from current resolution training. data_samples (List[DataSample]): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise_batch = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator( noise_batch, num_batches=num_batches, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) disc_pred_fake_g = self.discriminator( fake_imgs, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) parsed_loss, log_vars = self.gen_loss(disc_pred_fake_g) optimizer_wrapper.update_params(parsed_loss) return log_vars def gen_loss(self, disc_pred_fake: Tensor) -> Tuple[Tensor, dict]: r"""Generator loss for PGGAN. PGGAN use WGAN's loss to train the generator. .. math: L_{G} = -\mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) + L_{MSE} Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. recon_imgs (Tensor): Reconstructive images. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_vars = self.parse_losses(losses_dict) return loss, log_vars def train_step(self, data: dict, optim_wrapper: OptimWrapperDict): """Train step function. This function implements the standard training iteration for asynchronous adversarial training. Namely, in each iteration, we first update discriminator and then compute loss for generator with the newly updated discriminator. As for distributed training, we use the ``reducer`` from ddp to synchronize the necessary params in current computational graph. Args: data_batch (dict): Input data from dataloader. optimizer (dict): Dict contains optimizer for generator and discriminator. ddp_reducer (:obj:`Reducer` | None, optional): Reducer from ddp. It is used to prepare for ``backward()`` in ddp. Defaults to None. running_status (dict | None, optional): Contains necessary basic information for training, e.g., iteration number. Defaults to None. Returns: dict: Contains 'log_vars', 'num_samples', and 'results'. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') # update current stage self.curr_stage = int( min( sum(self.cum_nkimgs <= self.shown_nkimg.item()), len(self.scales) - 1)) self.curr_scale = self.scales[self.curr_stage] self._curr_scale_int = self._next_scale_int.clone() if self.curr_stage != self.prev_stage: self.prev_stage = self.curr_stage self._actual_nkimgs.append(self.shown_nkimg.item()) data = self.data_preprocessor(data, True) data_sample = data['data_samples'] real_imgs = data_sample.gt_img curr_scale = str(self.curr_scale[0]) disc_optimizer_wrapper: OptimWrapper = optim_wrapper[ f'discriminator_{curr_scale}'] gen_optimizer_wrapper: OptimWrapper = optim_wrapper[ f'generator_{curr_scale}'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts # update training configs, like transition weight for torgb layers. # get current transition weight for interpolating two torgb layers if self.curr_stage == 0: transition_weight = 1. else: transition_weight = ( self.shown_nkimg.item() - self._actual_nkimgs[-1]) / self.transition_kimgs # clip to [0, 1] transition_weight = min(max(transition_weight, 0.), 1.) self._curr_transition_weight = torch.tensor(transition_weight).to( self._curr_transition_weight) if real_imgs.shape[2:] == self.curr_scale: pass elif real_imgs.shape[2] >= self.curr_scale[0] and real_imgs.shape[ 3] >= self.curr_scale[1]: real_imgs = self.interp_real_to(real_imgs, size=self.curr_scale) else: raise RuntimeError( f'The scale of real image {real_imgs.shape[2:]} is smaller ' f'than current scale {self.curr_scale}.') # normal gan training process with disc_optimizer_wrapper.optim_context(self.discriminator): log_vars = self.train_discriminator(real_imgs, data_sample, disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): log_vars_gen = self.train_generator( real_imgs, data_sample, gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = self.gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) # if not update buffer, copy buffer from orig model if not self.generator_ema.update_buffers: self.generator_ema.sync_buffers( self.generator.module if is_model_wrapper( self.generator) else self.generator) elif self.with_ema_gen: # before ema, copy weights from orig self.generator_ema.sync_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) # add batch size info to log_vars _batch_size = real_imgs.shape[0] * get_world_size() self.shown_nkimg += (_batch_size / 1000.) log_vars.update( dict( shown_nkimg=self.shown_nkimg.item(), curr_scale=self.curr_scale[0], transition_weight=transition_weight)) # check if a new scale will be added in the next iteration _curr_stage = int( min( sum(self.cum_nkimgs <= self.shown_nkimg.item()), len(self.scales) - 1)) # in the next iteration, we will switch to a new scale if _curr_stage != self.curr_stage: # `self._next_scale_int` is updated at the end of `train_step` self._next_scale_int = self._next_scale_int * 2 return log_vars ================================================ FILE: mmagic/models/editors/pggan/pggan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from functools import partial import numpy as np import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from .pggan_modules import (EqualizedLRConvDownModule, EqualizedLRConvModule, MiniBatchStddevLayer, PGGANDecisionHead) @MODELS.register_module() class PGGANDiscriminator(BaseModule): """Discriminator for PGGAN. Args: in_scale (int): The scale of the input image. label_size (int, optional): Size of the label vector. Defaults to 0. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 8192. max_channels (int, optional): Maximum channels for the feature maps in the discriminator block. Defaults to 512. in_channels (int, optional): Number of channels in input images. Defaults to 3. channel_decay (float, optional): Decay for channels of feature maps. Defaults to 1.0. mbstd_cfg (dict, optional): Configs for minibatch-stddev layer. Defaults to dict(group_size=4). fused_convdown (bool, optional): Whether use fused downconv. Defaults to True. conv_module_cfg (dict, optional): Config for the convolution module used in this generator. Defaults to None. fused_convdown_cfg (dict, optional): Config for the fused downconv module used in this discriminator. Defaults to None. fromrgb_layer_cfg (dict, optional): Config for the fromrgb layer. Defaults to None. downsample_cfg (dict, optional): Config for the downsampling operation. Defaults to None. """ _default_fromrgb_cfg = dict( conv_cfg=None, kernel_size=1, stride=1, padding=0, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=None, order=('conv', 'act', 'norm')) _default_conv_module_cfg = dict( kernel_size=3, padding=1, stride=1, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) _default_convdown_cfg = dict( kernel_size=3, padding=1, stride=2, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) def __init__(self, in_scale, label_size=0, base_channels=8192, max_channels=512, in_channels=3, channel_decay=1.0, mbstd_cfg=dict(group_size=4), fused_convdown=True, conv_module_cfg=None, fused_convdown_cfg=None, fromrgb_layer_cfg=None, downsample_cfg=None): super().__init__() self.in_scale = in_scale self.in_log2_scale = int(np.log2(self.in_scale)) self.label_size = label_size self.base_channels = base_channels self.max_channels = max_channels self.in_channels = in_channels self.channel_decay = channel_decay self.with_mbstd = mbstd_cfg is not None self.fused_convdown = fused_convdown self.conv_module_cfg = deepcopy(self._default_conv_module_cfg) if conv_module_cfg is not None: self.conv_module_cfg.update(conv_module_cfg) if self.fused_convdown: self.fused_convdown_cfg = deepcopy(self._default_convdown_cfg) if fused_convdown_cfg is not None: self.fused_convdown_cfg.update(fused_convdown_cfg) self.fromrgb_layer_cfg = deepcopy(self._default_fromrgb_cfg) if fromrgb_layer_cfg: self.fromrgb_layer_cfg.update(fromrgb_layer_cfg) # setup conv blocks self.conv_blocks = nn.ModuleList() self.fromrgb_layers = nn.ModuleList() for s in range(2, self.in_log2_scale + 1): self.fromrgb_layers.append( self._get_fromrgb_layer(self.in_channels, s)) self.conv_blocks.extend( self._get_convdown_block(self._num_out_channels(s - 1), s)) # setup downsample layer self.downsample_cfg = deepcopy(downsample_cfg) if self.downsample_cfg is None or self.downsample_cfg.get( 'type', None) == 'avgpool': self.downsample = nn.AvgPool2d(kernel_size=2, stride=2) elif self.downsample_cfg.get('type', None) in ['nearest', 'bilinear']: self.downsample = partial( F.interpolate, mode=self.downsample_cfg.pop('type'), **self.downsample_cfg) else: raise NotImplementedError( 'We have not supported the downsampling with type' f' {downsample_cfg}.') # setup minibatch stddev layer if self.with_mbstd: self.mbstd_layer = MiniBatchStddevLayer(**mbstd_cfg) # minibatch stddev layer will concatenate an additional feature map # in channel dimension. decision_in_channels = self._num_out_channels(1) * 16 + 16 else: decision_in_channels = self._num_out_channels(1) * 16 # setup decision layer self.decision = PGGANDecisionHead(decision_in_channels, self._num_out_channels(0), 1 + self.label_size) def _num_out_channels(self, log_scale: int) -> int: """Calculate the number of output channels of the current network from logarithm of current scale. Args: log_scale (int): The logarithm of the current scale. Returns: int: The number of output channels. """ return min( int(self.base_channels / (2.0**(log_scale * self.channel_decay))), self.max_channels) def _get_fromrgb_layer(self, in_channels: int, log2_scale: int) -> nn.Module: """Get the 'fromrgb' layer from logarithm of current scale. Args: in_channels (int): The number of input channels. log2_scale (int): The logarithm of the current scale. Returns: nn.Module: The built from-rgb layer. """ return EqualizedLRConvModule(in_channels, self._num_out_channels(log2_scale - 1), **self.fromrgb_layer_cfg) def _get_convdown_block(self, in_channels: int, log2_scale: int) -> nn.Module: """Get the downsample layer from logarithm of current scale. Args: in_channels (int): The number of input channels. log2_scale (int): The logarithm of the current scale. Returns: nn.Module: The built Conv layer. """ modules = [] if log2_scale == 2: modules.append( EqualizedLRConvModule(in_channels, self._num_out_channels(log2_scale - 1), **self.conv_module_cfg)) else: modules.append( EqualizedLRConvModule(in_channels, self._num_out_channels(log2_scale - 1), **self.conv_module_cfg)) if self.fused_convdown: cfg_ = dict(downsample=dict(type='fused_pool')) cfg_.update(self.fused_convdown_cfg) else: cfg_ = dict(downsample=self.downsample) cfg_.update(self.conv_module_cfg) modules.append( EqualizedLRConvDownModule( self._num_out_channels(log2_scale - 1), self._num_out_channels(log2_scale - 2), **cfg_)) return modules def forward(self, x, transition_weight=1., curr_scale=-1): """Forward function. Args: x (torch.Tensor): Input image tensor. transition_weight (float, optional): The weight used in resolution transition. Defaults to 1.0. curr_scale (int, optional): The scale for the current inference or training. Defaults to -1. Returns: Tensor: Predict score for the input image. """ curr_log2_scale = self.in_log2_scale if curr_scale < 4 else int( np.log2(curr_scale)) original_img = x x = self.fromrgb_layers[curr_log2_scale - 2](x) for s in range(curr_log2_scale, 2, -1): x = self.conv_blocks[2 * s - 5](x) x = self.conv_blocks[2 * s - 4](x) if s == curr_log2_scale: img_down = self.downsample(original_img) y = self.fromrgb_layers[curr_log2_scale - 3](img_down) x = y + transition_weight * (x - y) if self.with_mbstd: x = self.mbstd_layer(x) x = self.decision(x) if self.label_size > 0: return x[:, :1], x[:, 1:] return x ================================================ FILE: mmagic/models/editors/pggan/pggan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from ...utils import get_module_device from .pggan_modules import (EqualizedLRConvModule, EqualizedLRConvUpModule, PGGANNoiseTo2DFeat) @MODELS.register_module() class PGGANGenerator(BaseModule): """Generator for PGGAN. Args: noise_size (int): Size of the input noise vector. out_scale (int): Output scale for the generated image. label_size (int, optional): Size of the label vector. Defaults to 0. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Defaults to 8192. channel_decay (float, optional): Decay for channels of feature maps. Defaults to 1.0. max_channels (int, optional): Maximum channels for the feature maps in the generator block. Defaults to 512. fused_upconv (bool, optional): Whether use fused upconv. Defaults to True. conv_module_cfg (dict, optional): Config for the convolution module used in this generator. Defaults to None. fused_upconv_cfg (dict, optional): Config for the fused upconv module used in this generator. Defaults to None. upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to None. """ _default_fused_upconv_cfg = dict( conv_cfg=dict(type='deconv'), kernel_size=3, stride=2, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='PixelNorm'), order=('conv', 'act', 'norm')) _default_conv_module_cfg = dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='PixelNorm'), order=('conv', 'act', 'norm')) _default_upsample_cfg = dict(type='nearest', scale_factor=2) def __init__(self, noise_size, out_scale, label_size=0, base_channels=8192, channel_decay=1., max_channels=512, fused_upconv=True, conv_module_cfg=None, fused_upconv_cfg=None, upsample_cfg=None): super().__init__() self.noise_size = noise_size if noise_size else min( base_channels, max_channels) self.out_scale = out_scale self.out_log2_scale = int(np.log2(out_scale)) # sanity check for the output scale assert out_scale == 2**self.out_log2_scale and out_scale >= 4 self.label_size = label_size self.base_channels = base_channels self.channel_decay = channel_decay self.max_channels = max_channels self.fused_upconv = fused_upconv # set conv cfg self.conv_module_cfg = deepcopy(self._default_conv_module_cfg) # update with customized config if conv_module_cfg: self.conv_module_cfg.update(conv_module_cfg) if self.fused_upconv: self.fused_upconv_cfg = deepcopy(self._default_fused_upconv_cfg) # update with customized config if fused_upconv_cfg: self.fused_upconv_cfg.update(fused_upconv_cfg) self.upsample_cfg = deepcopy(self._default_upsample_cfg) if upsample_cfg is not None: self.upsample_cfg.update(upsample_cfg) self.noise2feat = PGGANNoiseTo2DFeat(noise_size + label_size, self._num_out_channels(1)) self.torgb_layers = nn.ModuleList() self.conv_blocks = nn.ModuleList() for s in range(2, self.out_log2_scale + 1): in_ch = self._num_out_channels( s - 1) if s == 2 else self._num_out_channels(s - 2) # setup torgb layers self.torgb_layers.append( self._get_torgb_layer(self._num_out_channels(s - 1))) # setup upconv or conv blocks self.conv_blocks.extend(self._get_upconv_block(in_ch, s)) # build upsample layer for residual path self.upsample_layer = MODELS.build(self.upsample_cfg) def _get_torgb_layer(self, in_channels: int): """Get the to-rgb layer based on `in_channels`. Args: in_channels (int): Number of input channels. Returns: nn.Module: To-rgb layer. """ return EqualizedLRConvModule( in_channels, 3, kernel_size=1, stride=1, equalized_lr_cfg=dict(gain=1), bias=True, norm_cfg=None, act_cfg=None) def _num_out_channels(self, log_scale: int): """Calculate the number of output channels based on logarithm of current scale. Args: log_scale (int): The logarithm of the current scale. Returns: int: The current number of output channels. """ return min( int(self.base_channels / (2.0**(log_scale * self.channel_decay))), self.max_channels) def _get_upconv_block(self, in_channels, log_scale): """Get the conv block for upsampling. Args: in_channels (int): The number of input channels. log_scale (int): The logarithmic of the current scale. Returns: nn.Module: The conv block for upsampling. """ modules = [] # start 4x4 scale if log_scale == 2: modules.append( EqualizedLRConvModule(in_channels, self._num_out_channels(log_scale - 1), **self.conv_module_cfg)) # 8x8 --> 1024x1024 scales else: if self.fused_upconv: cfg_ = dict(upsample=dict(type='fused_nn')) cfg_.update(self.fused_upconv_cfg) else: cfg_ = dict(upsample=self.upsample_cfg) cfg_.update(self.conv_module_cfg) # up + conv modules.append( EqualizedLRConvUpModule(in_channels, self._num_out_channels(log_scale - 1), **cfg_)) # refine conv modules.append( EqualizedLRConvModule( self._num_out_channels(log_scale - 1), self._num_out_channels(log_scale - 1), **self.conv_module_cfg)) return modules def forward(self, noise, label=None, num_batches=0, return_noise=False, transition_weight=1., curr_scale=-1): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. label (Tensor, optional): Label vector with shape [N, C]. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. transition_weight (float, optional): The weight used in resolution transition. Defaults to 1.0. curr_scale (int, optional): The scale for the current inference or training. Defaults to -1. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img`` and ``noise_batch`` will be returned. """ # receive noise and conduct sanity check. if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 # TODO: check pggan default noise type noise_batch = torch.randn((num_batches, self.noise_size)) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) if label is not None: noise_batch = torch.cat([noise_batch, label.to(noise_batch)], dim=1) # noise vector to 2D feature x = self.noise2feat(noise_batch) # build current computational graph curr_log2_scale = self.out_log2_scale if curr_scale < 0 else int( np.log2(curr_scale)) # 4x4 scale x = self.conv_blocks[0](x) if curr_log2_scale <= 3: out_img = last_img = self.torgb_layers[0](x) # 8x8 and larger scales for s in range(3, curr_log2_scale + 1): x = self.conv_blocks[2 * s - 5](x) x = self.conv_blocks[2 * s - 4](x) if s + 1 == curr_log2_scale: last_img = self.torgb_layers[s - 2](x) elif s == curr_log2_scale: out_img = self.torgb_layers[s - 2](x) residual_img = self.upsample_layer(last_img) out_img = residual_img + transition_weight * ( out_img - residual_img) if return_noise: output = dict( fake_img=out_img, noise_batch=noise_batch, label=label) return output return out_img ================================================ FILE: mmagic/models/editors/pggan/pggan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn.bricks import ConvModule, build_norm_layer from mmengine.model import BaseModule, normal_init from torch.nn.init import _calculate_correct_fan from mmagic.models.archs import AllGatherLayer from mmagic.registry import MODELS class EqualizedLR: r"""Equalized Learning Rate. This trick is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation The general idea is to dynamically rescale the weight in training instead of in initializing so that the variance of the responses in each layer is guaranteed with some statistical properties. Note that this function is always combined with a convolution module which is initialized with :math:`\mathcal{N}(0, 1)`. Args: name (str | optional): The name of weights. Defaults to 'weight'. mode (str, optional): The mode of computing ``fan`` which is the same as ``kaiming_init`` in pytorch. You can choose one from ['fan_in', 'fan_out']. Defaults to 'fan_in'. """ def __init__(self, name='weight', gain=2**0.5, mode='fan_in', lr_mul=1.0): self.name = name self.mode = mode self.gain = gain self.lr_mul = lr_mul def compute_weight(self, module): """Compute weight with equalized learning rate. Args: module (nn.Module): A module that is wrapped with equalized lr. Returns: torch.Tensor: Updated weight. """ weight = getattr(module, self.name + '_orig') if weight.ndim == 5: # weight in shape of [b, out, in, k, k] fan = _calculate_correct_fan(weight[0], self.mode) else: assert weight.ndim <= 4 fan = _calculate_correct_fan(weight, self.mode) weight = weight * torch.tensor( self.gain, device=weight.device) * torch.sqrt( torch.tensor(1. / fan, device=weight.device)) * self.lr_mul return weight def __call__(self, module, inputs): """Standard interface for forward pre hooks.""" setattr(module, self.name, self.compute_weight(module)) @staticmethod def apply(module, name, gain=2**0.5, mode='fan_in', lr_mul=1.): """Apply function. This function is to register an equalized learning rate hook in an ``nn.Module``. Args: module (nn.Module): Module to be wrapped. name (str | optional): The name of weights. Defaults to 'weight'. mode (str, optional): The mode of computing ``fan`` which is the same as ``kaiming_init`` in pytorch. You can choose one from ['fan_in', 'fan_out']. Defaults to 'fan_in'. Returns: nn.Module: Module that is registered with equalized lr hook. """ # sanity check for duplicated hooks. for _, hook in module._forward_pre_hooks.items(): if isinstance(hook, EqualizedLR): raise RuntimeError( 'Cannot register two equalized_lr hooks on the same ' f'parameter {name} in {module} module.') fn = EqualizedLR(name, gain=gain, mode=mode, lr_mul=lr_mul) weight = module._parameters[name] delattr(module, name) module.register_parameter(name + '_orig', weight) # We still need to assign weight back as fn.name because all sorts of # things may assume that it exists, e.g., when initializing weights. # However, we can't directly assign as it could be an nn.Parameter and # gets added as a parameter. Instead, we register weight.data as a # plain attribute. setattr(module, name, weight.data) module.register_forward_pre_hook(fn) # TODO: register load state dict hook return fn def equalized_lr(module, name='weight', gain=2**0.5, mode='fan_in', lr_mul=1.): r"""Equalized Learning Rate. This trick is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation The general idea is to dynamically rescale the weight in training instead of in initializing so that the variance of the responses in each layer is guaranteed with some statistical properties. Note that this function is always combined with a convolution module which is initialized with :math:`\mathcal{N}(0, 1)`. Args: module (nn.Module): Module to be wrapped. name (str | optional): The name of weights. Defaults to 'weight'. mode (str, optional): The mode of computing ``fan`` which is the same as ``kaiming_init`` in pytorch. You can choose one from ['fan_in', 'fan_out']. Defaults to 'fan_in'. Returns: nn.Module: Module that is registered with equalized lr hook. """ EqualizedLR.apply(module, name, gain=gain, mode=mode, lr_mul=lr_mul) return module def pixel_norm(x, eps=1e-6): """Pixel Normalization. This normalization is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation Args: x (torch.Tensor): Tensor to be normalized. eps (float, optional): Epsilon to avoid dividing zero. Defaults to 1e-6. Returns: torch.Tensor: Normalized tensor. """ if torch.__version__ >= '1.7.0': norm = torch.linalg.norm(x, ord=2, dim=1, keepdim=True) # support older pytorch version else: norm = torch.norm(x, p=2, dim=1, keepdim=True) norm = norm / torch.sqrt(torch.tensor(x.shape[1]).to(x)) return x / (norm + eps) @MODELS.register_module() class PixelNorm(BaseModule): """Pixel Normalization. This module is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation Args: eps (float, optional): Epsilon value. Defaults to 1e-6. """ _abbr_ = 'pn' def __init__(self, in_channels=None, eps=1e-6): super().__init__() self.eps = eps def forward(self, x): """Forward function. Args: x (torch.Tensor): Tensor to be normalized. Returns: torch.Tensor: Normalized tensor. """ return pixel_norm(x, self.eps) @MODELS.register_module() class EqualizedLRConvModule(ConvModule): r"""Equalized LR ConvModule. In this module, we inherit default ``mmcv.cnn.ConvModule`` and adopt equalized lr in convolution. The equalized learning rate is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation Note that, the initialization of ``self.conv`` will be overwritten as :math:`\mathcal{N}(0, 1)`. Args: equalized_lr_cfg (dict | None, optional): Config for ``EqualizedLR``. If ``None``, equalized learning rate is ignored. Defaults to dict(mode='fan_in'). """ def __init__(self, *args, equalized_lr_cfg=dict(mode='fan_in'), **kwargs): super().__init__(*args, **kwargs) self.with_equalized_lr = equalized_lr_cfg is not None if self.with_equalized_lr: self.conv = equalized_lr(self.conv, **equalized_lr_cfg) # initialize the conv weight with standard Gaussian noise. self._init_conv_weights() def _init_conv_weights(self): """Initialize conv weights as described in PGGAN.""" normal_init(self.conv) @MODELS.register_module() class EqualizedLRConvUpModule(EqualizedLRConvModule): r"""Equalized LR (Upsample + Conv) Module. In this module, we inherit ``EqualizedLRConvModule`` and adopt upsampling before convolution. As for upsampling, in addition to the sampling layer in MMCV, we also offer the "fused_nn" type. "fused_nn" denotes fusing upsampling and convolution. The fusion is modified from the official Tensorflow implementation in: https://github.com/tkarras/progressive_growing_of_gans/blob/master/networks.py#L86 Args: upsample (dict | None, optional): Config for upsampling operation. If ``None``, upsampling is ignored. If you need a faster fused version as the official PGGAN in Tensorflow, you should set it as ``dict(type='fused_nn')``. Defaults to ``dict(type='nearest', scale_factor=2)``. """ def __init__(self, *args, upsample=dict(type='nearest', scale_factor=2), **kwargs): super().__init__(*args, **kwargs) self.with_upsample = upsample is not None if self.with_upsample: if upsample.get('type') == 'fused_nn': assert isinstance(self.conv, nn.ConvTranspose2d) self.conv.register_forward_pre_hook( EqualizedLRConvUpModule.fused_nn_hook) else: self.upsample_layer = MODELS.build(upsample) def forward(self, x, **kwargs): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if hasattr(self, 'upsample_layer'): x = self.upsample_layer(x) return super().forward(x, **kwargs) @staticmethod def fused_nn_hook(module, inputs): """Standard interface for forward pre hooks.""" weight = module.weight # pad the last two dimensions weight = F.pad(weight, (1, 1, 1, 1)) weight = weight[..., 1:, 1:] + weight[..., 1:, :-1] + weight[ ..., :-1, 1:] + weight[..., :-1, :-1] module.weight = weight @MODELS.register_module() class EqualizedLRConvDownModule(EqualizedLRConvModule): r"""Equalized LR (Conv + Downsample) Module. In this module, we inherit ``EqualizedLRConvModule`` and adopt downsampling after convolution. As for downsampling, we provide two modes of "avgpool" and "fused_pool". "avgpool" denotes the commonly used average pooling operation, while "fused_pool" represents fusing downsampling and convolution. The fusion is modified from the official Tensorflow implementation in: https://github.com/tkarras/progressive_growing_of_gans/blob/master/networks.py#L109 Args: downsample (dict | None, optional): Config for downsampling operation. If ``None``, downsampling is ignored. Currently, we support the types of ["avgpool", "fused_pool"]. Defaults to dict(type='fused_pool'). """ def __init__(self, *args, downsample=dict(type='fused_pool'), **kwargs): super().__init__(*args, **kwargs) downsample_cfg = deepcopy(downsample) self.with_downsample = downsample is not None if self.with_downsample: type_ = downsample_cfg.pop('type') if type_ == 'avgpool': self.downsample = nn.AvgPool2d(2, 2) elif type_ == 'fused_pool': self.conv.register_forward_pre_hook( EqualizedLRConvDownModule.fused_avgpool_hook) elif callable(downsample): self.downsample = downsample else: raise NotImplementedError( 'Currently, we only support ["avgpool", "fused_pool"] as ' f'the type of downsample, but got {type_} instead.') def forward(self, x, **kwargs): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: torch.Tensor: Normalized tensor. """ x = super().forward(x, **kwargs) if hasattr(self, 'downsample'): x = self.downsample(x) return x @staticmethod def fused_avgpool_hook(module, inputs): """Standard interface for forward pre hooks.""" weight = module.weight # pad the last two dimensions weight = F.pad(weight, (1, 1, 1, 1)) weight = (weight[..., 1:, 1:] + weight[..., 1:, :-1] + weight[..., :-1, 1:] + weight[..., :-1, :-1]) * 0.25 module.weight = weight @MODELS.register_module() class EqualizedLRLinearModule(nn.Linear): r"""Equalized LR LinearModule. In this module, we adopt equalized lr in ``nn.Linear``. The equalized learning rate is proposed in: Progressive Growing of GANs for Improved Quality, Stability, and Variation Note that, the initialization of ``self.weight`` will be overwritten as :math:`\mathcal{N}(0, 1)`. Args: equalized_lr_cfg (dict | None, optional): Config for ``EqualizedLR``. If ``None``, equalized learning rate is ignored. Defaults to dict(mode='fan_in'). """ def __init__(self, *args, equalized_lr_cfg=dict(mode='fan_in'), **kwargs): super().__init__(*args, **kwargs) self.with_equalized_lr = equalized_lr_cfg is not None if self.with_equalized_lr: self.lr_mul = equalized_lr_cfg.get('lr_mul', 1.) else: # In fact, lr_mul will only be used in EqualizedLR for # initialization self.lr_mul = 1. if self.with_equalized_lr: equalized_lr(self, **equalized_lr_cfg) self._init_linear_weights() def _init_linear_weights(self): """Initialize linear weights as described in PGGAN.""" nn.init.normal_(self.weight, 0, 1. / self.lr_mul) if self.bias is not None: nn.init.constant_(self.bias, 0.) @MODELS.register_module() class PGGANNoiseTo2DFeat(BaseModule): def __init__(self, noise_size, out_channels, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='PixelNorm'), normalize_latent=True, order=('linear', 'act', 'norm')): super().__init__() self.noise_size = noise_size self.out_channels = out_channels self.normalize_latent = normalize_latent self.with_activation = act_cfg is not None self.with_norm = norm_cfg is not None self.order = order assert len(order) == 3 and set(order) == set(['linear', 'act', 'norm']) # w/o bias, because the bias is added after reshaping the tensor to # 2D feature self.linear = EqualizedLRLinearModule( noise_size, out_channels * 16, equalized_lr_cfg=dict(gain=np.sqrt(2) / 4), bias=False) if self.with_activation: self.activation = MODELS.build(act_cfg) # add bias for reshaped 2D feature. self.register_parameter( 'bias', nn.Parameter(torch.zeros(1, out_channels, 1, 1))) if self.with_norm: _, self.norm = build_norm_layer(norm_cfg, out_channels) def forward(self, x): """Forward function. Args: x (Tensor): Input noise tensor with shape (n, c). Returns: Tensor: Forward results with shape (n, c, 4, 4). """ assert x.ndim == 2 if self.normalize_latent: x = pixel_norm(x) for order in self.order: if order == 'linear': x = self.linear(x) # [n, c, 4, 4] x = torch.reshape(x, (-1, self.out_channels, 4, 4)) x = x + self.bias elif order == 'act' and self.with_activation: x = self.activation(x) elif order == 'norm' and self.with_norm: x = self.norm(x) return x class PGGANDecisionHead(BaseModule): def __init__(self, in_channels, mid_channels, out_channels, bias=True, equalized_lr_cfg=dict(gain=1), act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act=None): super().__init__() self.in_channels = in_channels self.mid_channels = mid_channels self.out_channels = out_channels self.with_activation = act_cfg is not None self.with_out_activation = out_act is not None # setup linear layers # dirty code for supporting default mode in PGGAN if equalized_lr_cfg: equalized_lr_cfg_ = dict(gain=2**0.5) else: equalized_lr_cfg_ = None self.linear0 = EqualizedLRLinearModule( self.in_channels, self.mid_channels, bias=bias, equalized_lr_cfg=equalized_lr_cfg_) self.linear1 = EqualizedLRLinearModule( self.mid_channels, self.out_channels, bias=bias, equalized_lr_cfg=equalized_lr_cfg) # setup activation layers if self.with_activation: self.activation = MODELS.build(act_cfg) if self.with_out_activation: self.out_activation = MODELS.build(out_act) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if x.ndim > 2: x = torch.reshape(x, (x.shape[0], -1)) x = self.linear0(x) if self.with_activation: x = self.activation(x) x = self.linear1(x) if self.with_out_activation: x = self.out_activation(x) return x @MODELS.register_module() class MiniBatchStddevLayer(BaseModule): """Minibatch standard deviation. Args: group_size (int, optional): The size of groups in batch dimension. Defaults to 4. eps (float, optional): Epsilon value to avoid computation error. Defaults to 1e-8. gather_all_batch (bool, optional): Whether gather batch from all GPUs. Defaults to False. """ def __init__(self, group_size=4, eps=1e-8, gather_all_batch=False): super().__init__() self.group_size = group_size self.eps = eps self.gather_all_batch = gather_all_batch if self.gather_all_batch: assert torch.distributed.is_initialized( ), 'Only in distributed training can the tensors be all gathered.' def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.gather_all_batch: x = torch.cat(AllGatherLayer.apply(x), dim=0) # batch size should be smaller than or equal to group size. Otherwise, # batch size should be divisible by the group size. assert x.shape[ 0] <= self.group_size or x.shape[0] % self.group_size == 0, ( 'Batch size be smaller than or equal ' 'to group size. Otherwise,' ' batch size should be divisible by the group size.' f'But got batch size {x.shape[0]},' f' group size {self.group_size}') n, c, h, w = x.shape group_size = min(n, self.group_size) # [G, M, C, H, W] y = torch.reshape(x, (group_size, -1, c, h, w)) # [G, M, C, H, W] y = y - y.mean(dim=0, keepdim=True) # In pt>=1.7, you can just use `.square()` function. # [M, C, H, W] y = y.pow(2).mean(dim=0, keepdim=False) y = torch.sqrt(y + self.eps) # [M, 1, 1, 1] y = y.mean(dim=(1, 2, 3), keepdim=True) y = y.repeat(group_size, 1, h, w) return torch.cat([x, y], dim=1) ================================================ FILE: mmagic/models/editors/pix2pix/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .pix2pix import Pix2Pix from .pix2pix_generator import UnetGenerator __all__ = ['Pix2Pix', 'UnetGenerator'] ================================================ FILE: mmagic/models/editors/pix2pix/pix2pix.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F from mmengine import MessageHub from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ...base_models import BaseTranslationModel from ...utils import set_requires_grad @MODELS.register_module() class Pix2Pix(BaseTranslationModel): """Pix2Pix model for paired image-to-image translation. Ref: Image-to-Image Translation with Conditional Adversarial Networks """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.pixel_loss_weight = self.loss_config.get('pixel_loss_weight', 100) def forward_test(self, img, target_domain, **kwargs): """Forward function for testing. Args: img (tensor): Input image tensor. target_domain (str): Target domain of output image. kwargs (dict): Other arguments. Returns: dict: Forward results. """ # This is a trick for Pix2Pix # ref: https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/e1bdf46198662b0f4d0b318e24568205ec4d7aee/test.py#L54 # noqa self.train() target = self.translation(img, target_domain=target_domain, **kwargs) results = dict(source=img, target=target) return results def _get_disc_loss(self, outputs): """Get the loss of discriminator. Args: outputs (dict): A dict of output. Returns: Tuple: Loss and a dict of log of loss terms. """ # GAN loss for the discriminator losses = dict() discriminators = self.get_module(self.discriminators) target_domain = self._default_domain source_domain = self.get_other_domains(target_domain)[0] fake_ab = torch.cat((outputs[f'real_{source_domain}'], outputs[f'fake_{target_domain}']), 1) fake_pred = discriminators[target_domain](fake_ab.detach()) losses['loss_gan_d_fake'] = F.binary_cross_entropy_with_logits( fake_pred, 0. * torch.ones_like(fake_pred)) real_ab = torch.cat((outputs[f'real_{source_domain}'], outputs[f'real_{target_domain}']), 1) real_pred = discriminators[target_domain](real_ab) losses['loss_gan_d_real'] = F.binary_cross_entropy_with_logits( real_pred, 1. * torch.ones_like(real_pred)) loss_d, log_vars_d = self.parse_losses(losses) loss_d *= 0.5 return loss_d, log_vars_d def _get_gen_loss(self, outputs): """Get the loss of generator. Args: outputs (dict): A dict of output. Returns: Tuple: Loss and a dict of log of loss terms. """ target_domain = self._default_domain source_domain = self.get_other_domains(target_domain)[0] losses = dict() discriminators = self.get_module(self.discriminators) # GAN loss for the generator fake_ab = torch.cat((outputs[f'real_{source_domain}'], outputs[f'fake_{target_domain}']), 1) fake_pred = discriminators[target_domain](fake_ab) losses['loss_gan_g'] = F.binary_cross_entropy_with_logits( fake_pred, 1. * torch.ones_like(fake_pred)) # L1 loss for generator losses['loss_pixel'] = self.pixel_loss_weight * F.l1_loss( outputs[f'real_{target_domain}'], outputs[f'fake_{target_domain}'], reduce='mean') loss_g, log_vars_g = self.parse_losses(losses) return loss_g, log_vars_g def train_step(self, data, optim_wrapper=None): """Training step function. Args: data_batch (dict): Dict of the input data batch. optimizer (dict[torch.optim.Optimizer]): Dict of optimizers for the generator and discriminator. ddp_reducer (:obj:`Reducer` | None, optional): Reducer from ddp. It is used to prepare for ``backward()`` in ddp. Defaults to None. running_status (dict | None, optional): Contains necessary basic information for training, e.g., iteration number. Defaults to None. Returns: dict: Dict of loss, information for logger, the number of samples\ and results for visualization. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) inputs_dict = data['inputs'] disc_optimizer_wrapper = optim_wrapper['discriminators'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts target_domain = self._default_domain source_domain = self.get_other_domains(self._default_domain)[0] source_image = inputs_dict[f'img_{source_domain}'] target_image = inputs_dict[f'img_{target_domain}'] # forward generator outputs = dict() with disc_optimizer_wrapper.optim_context(self.discriminators): results = self( source_image, target_domain=self._default_domain, test_mode=False) outputs[f'real_{source_domain}'] = results['source'] outputs[f'fake_{target_domain}'] = results['target'] outputs[f'real_{target_domain}'] = target_image log_vars = dict() # discriminator set_requires_grad(self.discriminators, True) # optimize loss_d, log_vars_d = self._get_disc_loss(outputs) disc_optimizer_wrapper.update_params(loss_d) log_vars.update(log_vars_d) # generator, no updates to discriminator parameters. gen_optimizer_wrapper = optim_wrapper['generators'] if ((curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0 and curr_iter >= self.disc_init_steps): set_requires_grad(self.discriminators, False) # optimize with gen_optimizer_wrapper.optim_context(self.generators): loss_g, log_vars_g = self._get_gen_loss(outputs) gen_optimizer_wrapper.update_params(loss_g) log_vars.update(log_vars_g) return log_vars def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: List[DataSample]: Generated image or image dict. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] target_domain = self._reachable_domains[0] source_domain = self.get_other_domains(target_domain)[0] outputs = self.forward_test( inputs_dict[f'img_{source_domain}'], target_domain=target_domain) batch_sample_list = [] num_batches = next(iter(outputs.values())).shape[0] for idx in range(num_batches): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) target = outputs['target'][idx] target = self.data_preprocessor.destruct(target, data_samples[idx], f'img_{target_domain}') setattr(gen_sample, f'fake_{target_domain}', target) batch_sample_list.append(gen_sample) return batch_sample_list def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: List[DataSample]: Generated image or image dict. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] target_domain = self._reachable_domains[0] source_domain = self.get_other_domains(target_domain)[0] outputs = self.forward_test( inputs_dict[f'img_{source_domain}'], target_domain=target_domain) batch_sample_list = [] if data_samples: data_samples = data_samples.split() num_batches = next(iter(outputs.values())).shape[0] for idx in range(num_batches): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) target = outputs['target'][idx] target = self.data_preprocessor.destruct(target, data_samples[idx], f'img_{target_domain}') gen_sample.set_tensor_data({f'fake_{target_domain}': target}) batch_sample_list.append(gen_sample) return batch_sample_list ================================================ FILE: mmagic/models/editors/pix2pix/pix2pix_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmengine.model import BaseModule from mmagic.registry import MODELS from ...utils import generation_init_weights from .pix2pix_modules import UnetSkipConnectionBlock @MODELS.register_module() class UnetGenerator(BaseModule): """Construct the Unet-based generator from the innermost layer to the outermost layer, which is a recursive process. Args: in_channels (int): Number of channels in input images. out_channels (int): Number of channels in output images. num_down (int): Number of downsamplings in Unet. If `num_down` is 8, the image with size 256x256 will become 1x1 at the bottleneck. Default: 8. base_channels (int): Number of channels at the last conv layer. Default: 64. norm_cfg (dict): Config dict to build norm layer. Default: `dict(type='BN')`. use_dropout (bool): Whether to use dropout layers. Default: False. init_cfg (dict): Config dict for initialization. `type`: The name of our initialization method. Default: 'normal'. `gain`: Scaling factor for normal, xavier and orthogonal. Default: 0.02. """ def __init__(self, in_channels, out_channels, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=False, init_cfg=dict(type='normal', gain=0.02)): super().__init__(init_cfg=init_cfg) # We use norm layers in the unet generator. assert isinstance(norm_cfg, dict), ("'norm_cfg' should be dict, but" f'got {type(norm_cfg)}') assert 'type' in norm_cfg, "'norm_cfg' must have key 'type'" # add the innermost layer unet_block = UnetSkipConnectionBlock( base_channels * 8, base_channels * 8, in_channels=None, submodule=None, norm_cfg=norm_cfg, is_innermost=True) # add intermediate layers with base_channels * 8 filters for _ in range(num_down - 5): unet_block = UnetSkipConnectionBlock( base_channels * 8, base_channels * 8, in_channels=None, submodule=unet_block, norm_cfg=norm_cfg, use_dropout=use_dropout) # gradually reduce the number of filters # from base_channels * 8 to base_channels unet_block = UnetSkipConnectionBlock( base_channels * 4, base_channels * 8, in_channels=None, submodule=unet_block, norm_cfg=norm_cfg) unet_block = UnetSkipConnectionBlock( base_channels * 2, base_channels * 4, in_channels=None, submodule=unet_block, norm_cfg=norm_cfg) unet_block = UnetSkipConnectionBlock( base_channels, base_channels * 2, in_channels=None, submodule=unet_block, norm_cfg=norm_cfg) # add the outermost layer self.model = UnetSkipConnectionBlock( out_channels, base_channels, in_channels=in_channels, submodule=unet_block, is_outermost=True, norm_cfg=norm_cfg) self.init_type = 'normal' if init_cfg is None else init_cfg.get( 'type', 'normal') self.init_gain = 0.02 if init_cfg is None else init_cfg.get( 'gain', 0.02) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ return self.model(x) def init_weights(self): """Initialize weights for the model. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Default: None. strict (bool, optional): Whether to allow different params for the model and checkpoint. Default: True. """ if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': super().init_weights() return generation_init_weights( self, init_type=self.init_type, init_gain=self.init_gain) self._is_init = True ================================================ FILE: mmagic/models/editors/pix2pix/pix2pix_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule class UnetSkipConnectionBlock(nn.Module): """Construct a Unet submodule with skip connections, with the following. structure: downsampling - `submodule` - upsampling. Args: outer_channels (int): Number of channels at the outer conv layer. inner_channels (int): Number of channels at the inner conv layer. in_channels (int): Number of channels in input images/features. If is None, equals to `outer_channels`. Default: None. submodule (UnetSkipConnectionBlock): Previously constructed submodule. Default: None. is_outermost (bool): Whether this module is the outermost module. Default: False. is_innermost (bool): Whether this module is the innermost module. Default: False. norm_cfg (dict): Config dict to build norm layer. Default: `dict(type='BN')`. use_dropout (bool): Whether to use dropout layers. Default: False. """ def __init__(self, outer_channels, inner_channels, in_channels=None, submodule=None, is_outermost=False, is_innermost=False, norm_cfg=dict(type='BN'), use_dropout=False): super().__init__() # cannot be both outermost and innermost assert not (is_outermost and is_innermost), ( "'is_outermost' and 'is_innermost' cannot be True" 'at the same time.') self.is_outermost = is_outermost assert isinstance(norm_cfg, dict), ("'norm_cfg' should be dict, but" f'got {type(norm_cfg)}') assert 'type' in norm_cfg, "'norm_cfg' must have key 'type'" # We use norm layers in the unet skip connection block. # Only for IN, use bias since it does not have affine parameters. use_bias = norm_cfg['type'] == 'IN' kernel_size = 4 stride = 2 padding = 1 if in_channels is None: in_channels = outer_channels down_conv_cfg = dict(type='Conv2d') down_norm_cfg = norm_cfg down_act_cfg = dict(type='LeakyReLU', negative_slope=0.2) up_conv_cfg = dict(type='Deconv') up_norm_cfg = norm_cfg up_act_cfg = dict(type='ReLU') up_in_channels = inner_channels * 2 up_bias = use_bias middle = [submodule] upper = [] if is_outermost: down_act_cfg = None down_norm_cfg = None up_bias = True up_norm_cfg = None upper = [nn.Tanh()] elif is_innermost: down_norm_cfg = None up_in_channels = inner_channels middle = [] else: upper = [nn.Dropout(0.5)] if use_dropout else [] down = [ ConvModule( in_channels=in_channels, out_channels=inner_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=use_bias, conv_cfg=down_conv_cfg, norm_cfg=down_norm_cfg, act_cfg=down_act_cfg, order=('act', 'conv', 'norm')) ] up = [ ConvModule( in_channels=up_in_channels, out_channels=outer_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=up_bias, conv_cfg=up_conv_cfg, norm_cfg=up_norm_cfg, act_cfg=up_act_cfg, order=('act', 'conv', 'norm')) ] model = down + middle + up + upper self.model = nn.Sequential(*model) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.is_outermost: return self.model(x) # add skip connections return torch.cat([x, self.model(x)], 1) ================================================ FILE: mmagic/models/editors/plain/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .plain_decoder import PlainDecoder from .plain_refiner import PlainRefiner __all__ = ['PlainRefiner', 'PlainDecoder'] ================================================ FILE: mmagic/models/editors/plain/plain_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmengine.model.weight_init import xavier_init from torch.autograd import Function from torch.nn.modules.pooling import _MaxUnpoolNd from torch.nn.modules.utils import _pair from mmagic.registry import MODELS class MaxUnpool2dop(Function): """We warp the `torch.nn.functional.max_unpool2d` with an extra `symbolic` method, which is needed while exporting to ONNX. Users should not call this function directly. """ @staticmethod def forward(ctx, input, indices, kernel_size, stride, padding, output_size): """Forward function of MaxUnpool2dop. Args: input (Tensor): Tensor needed to upsample. indices (Tensor): Indices output of the previous MaxPool. kernel_size (Tuple): Size of the max pooling window. stride (Tuple): Stride of the max pooling window. padding (Tuple): Padding that was added to the input. output_size (List or Tuple): The shape of output tensor. Returns: Tensor: Output tensor. """ return F.max_unpool2d(input, indices, kernel_size, stride, padding, output_size) @staticmethod def symbolic(g, input, indices, kernel_size, stride, padding, output_size): """This is the function to define the module of MaxUnpool. Args: g (_type_): _description_ input (Tensor): Tensor needed to upsample. indices (Tensor): Indices output of the previous MaxPool. kernel_size (int): Size of the max pooling window. stride (Tuple): Stride of the max pooling window. padding (Tuple): Padding that was added to the input. output_size (List or Tuple): The shape of output tensor. Returns: _type_: _description_ """ # get shape input_shape = g.op('Shape', input) const_0 = g.op('Constant', value_t=torch.tensor(0)) const_1 = g.op('Constant', value_t=torch.tensor(1)) batch_size = g.op('Gather', input_shape, const_0, axis_i=0) channel = g.op('Gather', input_shape, const_1, axis_i=0) # height = (height - 1) * stride + kernel_size height = g.op( 'Gather', input_shape, g.op('Constant', value_t=torch.tensor(2)), axis_i=0) height = g.op('Sub', height, const_1) height = g.op('Mul', height, g.op('Constant', value_t=torch.tensor(stride[1]))) height = g.op('Add', height, g.op('Constant', value_t=torch.tensor(kernel_size[1]))) # width = (width - 1) * stride + kernel_size width = g.op( 'Gather', input_shape, g.op('Constant', value_t=torch.tensor(3)), axis_i=0) width = g.op('Sub', width, const_1) width = g.op('Mul', width, g.op('Constant', value_t=torch.tensor(stride[0]))) width = g.op('Add', width, g.op('Constant', value_t=torch.tensor(kernel_size[0]))) # step of channel channel_step = g.op('Mul', height, width) # step of batch batch_step = g.op('Mul', channel_step, channel) # channel offset range_channel = g.op('Range', const_0, channel, const_1) range_channel = g.op( 'Reshape', range_channel, g.op('Constant', value_t=torch.tensor([1, -1, 1, 1]))) range_channel = g.op('Mul', range_channel, channel_step) range_channel = g.op('Cast', range_channel, to_i=7) # 7 is int64 # batch offset range_batch = g.op('Range', const_0, batch_size, const_1) range_batch = g.op( 'Reshape', range_batch, g.op('Constant', value_t=torch.tensor([-1, 1, 1, 1]))) range_batch = g.op('Mul', range_batch, batch_step) range_batch = g.op('Cast', range_batch, to_i=7) # 7 is int64 # update indices indices = g.op('Add', indices, range_channel) indices = g.op('Add', indices, range_batch) return g.op( 'MaxUnpool', input, indices, kernel_shape_i=kernel_size, strides_i=stride) class MaxUnpool2d(_MaxUnpoolNd): """This module is modified from Pytorch `MaxUnpool2d` module. Args: kernel_size (int or tuple): Size of the max pooling window. stride (int or tuple): Stride of the max pooling window. Default: None (It is set to `kernel_size` by default). padding (int or tuple): Padding that is added to the input. Default: 0. """ def __init__(self, kernel_size, stride=None, padding=0): super(MaxUnpool2d, self).__init__() self.kernel_size = _pair(kernel_size) self.stride = _pair(stride or kernel_size) self.padding = _pair(padding) def forward(self, input, indices, output_size=None): """Forward function of MaxUnpool2d. Args: input (Tensor): Tensor needed to upsample. indices (Tensor): Indices output of the previous MaxPool. output_size (List or Tuple): The shape of output tensor. Default: None. Returns: Tensor: Output tensor. """ return MaxUnpool2dop.apply(input, indices, self.kernel_size, self.stride, self.padding, output_size) @MODELS.register_module() class PlainDecoder(BaseModule): """Simple decoder from Deep Image Matting. Args: in_channels (int): Channel num of input features. init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, in_channels, init_cfg: Optional[dict] = None): super().__init__(init_cfg=init_cfg) self.deconv6_1 = nn.Conv2d(in_channels, 512, kernel_size=1) self.deconv5_1 = nn.Conv2d(512, 512, kernel_size=5, padding=2) self.deconv4_1 = nn.Conv2d(512, 256, kernel_size=5, padding=2) self.deconv3_1 = nn.Conv2d(256, 128, kernel_size=5, padding=2) self.deconv2_1 = nn.Conv2d(128, 64, kernel_size=5, padding=2) self.deconv1_1 = nn.Conv2d(64, 64, kernel_size=5, padding=2) self.deconv1 = nn.Conv2d(64, 1, kernel_size=5, padding=2) self.relu = nn.ReLU(inplace=True) self.max_unpool2d_for_onnx = MaxUnpool2d(kernel_size=2, stride=2) self.max_unpool2d = nn.MaxUnpool2d(kernel_size=2, stride=2) def init_weights(self): """Init weights for the module.""" if self.init_cfg is not None: super().init_weights() else: # Default initialization for m in self.modules(): if isinstance(m, nn.Conv2d): xavier_init(m) def forward(self, inputs): """Forward function of PlainDecoder. Args: inputs (dict): Output dictionary of the VGG encoder containing: - out (Tensor): Output of the VGG encoder. - max_idx_1 (Tensor): Index of the first maxpooling layer in the VGG encoder. - max_idx_2 (Tensor): Index of the second maxpooling layer in the VGG encoder. - max_idx_3 (Tensor): Index of the third maxpooling layer in the VGG encoder. - max_idx_4 (Tensor): Index of the fourth maxpooling layer in the VGG encoder. - max_idx_5 (Tensor): Index of the fifth maxpooling layer in the VGG encoder. Returns: Tensor: Output tensor. """ max_idx_1 = inputs['max_idx_1'] max_idx_2 = inputs['max_idx_2'] max_idx_3 = inputs['max_idx_3'] max_idx_4 = inputs['max_idx_4'] max_idx_5 = inputs['max_idx_5'] x = inputs['out'] max_unpool2d = self.max_unpool2d if torch.onnx.is_in_onnx_export(): max_unpool2d = self.max_unpool2d_for_onnx out = self.relu(self.deconv6_1(x)) out = max_unpool2d(out, max_idx_5) out = self.relu(self.deconv5_1(out)) out = max_unpool2d(out, max_idx_4) out = self.relu(self.deconv4_1(out)) out = max_unpool2d(out, max_idx_3) out = self.relu(self.deconv3_1(out)) out = max_unpool2d(out, max_idx_2) out = self.relu(self.deconv2_1(out)) out = max_unpool2d(out, max_idx_1) out = self.relu(self.deconv1_1(out)) raw_alpha = self.deconv1(out) return raw_alpha ================================================ FILE: mmagic/models/editors/plain/plain_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmengine.model.weight_init import xavier_init from mmagic.registry import MODELS @MODELS.register_module() class PlainRefiner(BaseModule): """Simple refiner from Deep Image Matting. Args: conv_channels (int): Number of channels produced by the three main convolutional layer. Default: 64. pretrained (str): Name of pretrained model. Default: None. """ def __init__(self, conv_channels=64, init_cfg=None): super().__init__(init_cfg=init_cfg) # assert pretrained is None, 'pretrained not supported yet' self.refine_conv1 = nn.Conv2d( 4, conv_channels, kernel_size=3, padding=1) self.refine_conv2 = nn.Conv2d( conv_channels, conv_channels, kernel_size=3, padding=1) self.refine_conv3 = nn.Conv2d( conv_channels, conv_channels, kernel_size=3, padding=1) self.refine_pred = nn.Conv2d( conv_channels, 1, kernel_size=3, padding=1) self.relu = nn.ReLU(inplace=True) def init_weights(self): """Init weights for the module.""" for m in self.modules(): if isinstance(m, nn.Conv2d): xavier_init(m) def forward(self, x, raw_alpha): """Forward function. Args: x (Tensor): The input feature map of refiner. raw_alpha (Tensor): The raw predicted alpha matte. Returns: Tensor: The refined alpha matte. """ out = self.relu(self.refine_conv1(x)) out = self.relu(self.refine_conv2(out)) out = self.relu(self.refine_conv3(out)) raw_refine = self.refine_pred(out) pred_refine = torch.sigmoid(raw_alpha + raw_refine) return pred_refine ================================================ FILE: mmagic/models/editors/rdn/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .rdn_net import RDB, RDNNet __all__ = ['RDB', 'RDNNet'] ================================================ FILE: mmagic/models/editors/rdn/rdn_net.py ================================================ import torch from mmengine.model import BaseModule from torch import nn from mmagic.registry import MODELS @MODELS.register_module() class RDNNet(BaseModule): """RDN model for single image super-resolution. Paper: Residual Dense Network for Image Super-Resolution Adapted from 'https://github.com/yjn870/RDN-pytorch.git' 'RDN-pytorch/blob/master/models.py' Copyright (c) 2021, JaeYun Yeo, under MIT License. Most of the implementation follows the implementation in: 'https://github.com/sanghyun-son/EDSR-PyTorch.git' 'EDSR-PyTorch/blob/master/src/model/rdn.py' Copyright (c) 2017, sanghyun-son, under MIT license. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_blocks (int): Block number in the trunk network. Default: 16. upscale_factor (int): Upsampling factor. Support 2^n and 3. Default: 4. num_layer (int): Layer number in the Residual Dense Block. Default: 8. channel_growth(int): Channels growth in each layer of RDB. Default: 64. """ def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=16, upscale_factor=4, num_layers=8, channel_growth=64): super().__init__() self.mid_channels = mid_channels self.channel_growth = channel_growth self.num_blocks = num_blocks self.num_layers = num_layers # shallow feature extraction self.sfe1 = nn.Conv2d( in_channels, mid_channels, kernel_size=3, padding=3 // 2) self.sfe2 = nn.Conv2d( mid_channels, mid_channels, kernel_size=3, padding=3 // 2) # residual dense blocks self.rdbs = nn.ModuleList() for _ in range(self.num_blocks): self.rdbs.append( RDB(self.mid_channels, self.channel_growth, self.num_layers)) # global feature fusion self.gff = nn.Sequential( nn.Conv2d( self.mid_channels * self.num_blocks, self.mid_channels, kernel_size=1), nn.Conv2d( self.mid_channels, self.mid_channels, kernel_size=3, padding=3 // 2)) # up-sampling assert 2 <= upscale_factor <= 4 if upscale_factor == 2 or upscale_factor == 4: self.upscale = [] for _ in range(upscale_factor // 2): self.upscale.extend([ nn.Conv2d( self.mid_channels, self.mid_channels * (2**2), kernel_size=3, padding=3 // 2), nn.PixelShuffle(2) ]) self.upscale = nn.Sequential(*self.upscale) else: self.upscale = nn.Sequential( nn.Conv2d( self.mid_channels, self.mid_channels * (upscale_factor**2), kernel_size=3, padding=3 // 2), nn.PixelShuffle(upscale_factor)) self.output = nn.Conv2d( self.mid_channels, out_channels, kernel_size=3, padding=3 // 2) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ sfe1 = self.sfe1(x) sfe2 = self.sfe2(sfe1) x = sfe2 local_features = [] for i in range(self.num_blocks): x = self.rdbs[i](x) local_features.append(x) x = self.gff(torch.cat(local_features, 1)) + sfe1 # global residual learning x = self.upscale(x) x = self.output(x) return x class DenseLayer(BaseModule): """Dense layer. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. """ def __init__(self, in_channels, out_channels): super().__init__() self.conv = nn.Conv2d( in_channels, out_channels, kernel_size=3, padding=3 // 2) self.relu = nn.ReLU(inplace=True) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c_in, h, w). Returns: Tensor: Forward results, tensor with shape (n, c_in+c_out, h, w). """ return torch.cat([x, self.relu(self.conv(x))], 1) class RDB(BaseModule): """Residual Dense Block of Residual Dense Network. Args: in_channels (int): Channel number of inputs. channel_growth (int): Channels growth in each layer. num_layers (int): Layer number in the Residual Dense Block. """ def __init__(self, in_channels, channel_growth, num_layers): super().__init__() self.layers = nn.Sequential(*[ DenseLayer(in_channels + channel_growth * i, channel_growth) for i in range(num_layers) ]) # local feature fusion self.lff = nn.Conv2d( in_channels + channel_growth * num_layers, in_channels, kernel_size=1) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ return x + self.lff(self.layers(x)) # local residual learning ================================================ FILE: mmagic/models/editors/real_basicvsr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .real_basicvsr import RealBasicVSR from .real_basicvsr_net import RealBasicVSRNet __all__ = ['RealBasicVSR', 'RealBasicVSRNet'] ================================================ FILE: mmagic/models/editors/real_basicvsr/real_basicvsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List import torch import torch.nn.functional as F from mmengine.optim import OptimWrapperDict from mmagic.models.utils import set_requires_grad from mmagic.registry import MODELS from ..real_esrgan import RealESRGAN @MODELS.register_module() class RealBasicVSR(RealESRGAN): """RealBasicVSR model for real-world video super-resolution. Ref: Investigating Tradeoffs in Real-World Video Super-Resolution, arXiv Args: generator (dict): Config for the generator. discriminator (dict, optional): Config for the discriminator. Default: None. gan_loss (dict, optional): Config for the gan loss. Note that the loss weight in gan loss is only for the generator. pixel_loss (dict, optional): Config for the pixel loss. Default: None. cleaning_loss (dict, optional): Config for the image cleaning loss. Default: None. perceptual_loss (dict, optional): Config for the perceptual loss. Default: None. is_use_sharpened_gt_in_pixel (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for pixel loss. Default: False. is_use_sharpened_gt_in_percep (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for perceptual loss. Default: False. is_use_sharpened_gt_in_gan (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for adversarial loss. Default: False. train_cfg (dict): Config for training. Default: None. You may change the training of gan by setting: `disc_steps`: how many discriminator updates after one generate update; `disc_init_steps`: how many discriminator updates at the start of the training. These two keys are useful when training with WGAN. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Default: None. """ def __init__(self, generator, discriminator=None, gan_loss=None, pixel_loss=None, cleaning_loss=None, perceptual_loss=None, is_use_sharpened_gt_in_pixel=False, is_use_sharpened_gt_in_percep=False, is_use_sharpened_gt_in_gan=False, is_use_ema=False, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, discriminator=discriminator, gan_loss=gan_loss, pixel_loss=pixel_loss, perceptual_loss=perceptual_loss, is_use_sharpened_gt_in_pixel=is_use_sharpened_gt_in_pixel, is_use_sharpened_gt_in_percep=is_use_sharpened_gt_in_percep, is_use_sharpened_gt_in_gan=is_use_sharpened_gt_in_gan, is_use_ema=is_use_ema, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.cleaning_loss = MODELS.build( cleaning_loss) if cleaning_loss else None def extract_gt_data(self, data_samples): """extract gt data from data samples. Args: data_samples (list): List of DataSample. Returns: Tensor: Extract gt data. """ gt_pixel, gt_percep, gt_gan = super().extract_gt_data(data_samples) n, t, c, h, w = gt_pixel.size() gt_pixel = gt_pixel.view(-1, c, h, w) gt_percep = gt_percep.view(-1, c, h, w) gt_gan = gt_gan.view(-1, c, h, w) if self.cleaning_loss: gt_clean = gt_pixel.view(-1, c, h, w) gt_clean = F.interpolate( gt_clean, scale_factor=0.25, mode='area', recompute_scale_factor=False) gt_clean = gt_clean.view(n, t, c, h // 4, w // 4) else: gt_clean = None return gt_pixel, gt_percep, gt_gan, gt_clean def g_step(self, batch_outputs, batch_gt_data): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tuple[Tensor]): Batch GT data. Returns: dict: Dict of losses. """ gt_pixel, gt_percep, gt_gan, gt_clean = batch_gt_data fake_g_output, fake_g_lq = batch_outputs fake_g_output = fake_g_output.view(gt_pixel.shape) losses = super().g_step( batch_outputs=fake_g_output, batch_gt_data=(gt_pixel, gt_percep, gt_gan)) if self.cleaning_loss: losses['loss_clean'] = self.cleaning_loss(fake_g_lq, gt_clean) return losses def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step of GAN-based method. Args: data (List[dict]): Data sampled from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ g_optim_wrapper = optim_wrapper['generator'] data = self.data_preprocessor(data, True) batch_inputs = data['inputs'] data_samples = data['data_samples'] batch_gt_data = self.extract_gt_data(data_samples) log_vars = dict() with g_optim_wrapper.optim_context(self): batch_outputs = self.forward_train(batch_inputs, data_samples) if self.if_run_g(): set_requires_grad(self.discriminator, False) log_vars_d = self.g_step_with_optim( batch_outputs=batch_outputs, batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if self.if_run_d(): set_requires_grad(self.discriminator, True) gt_pixel, gt_percep, gt_gan, gt_clean = batch_gt_data fake_g_output, fake_g_lq = batch_outputs fake_g_output = fake_g_output.view(gt_pixel.shape) for _ in range(self.disc_repeat): # detach before function call to resolve PyTorch2.0 compile bug log_vars_d = self.d_step_with_optim( batch_outputs=fake_g_output.detach(), batch_gt_data=(gt_pixel, gt_percep, gt_gan), optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if 'loss' in log_vars: log_vars.pop('loss') self.step_counter += 1 return log_vars def forward_train(self, batch_inputs, data_samples=None): """Forward Train. Run forward of generator with ``return_lqs=True`` Args: batch_inputs (Tensor): Batch inputs. data_samples (List[DataSample]): Data samples of Editing. Default:None Returns: Tuple[Tensor]: Result of generator. (outputs, lqs) """ return self.generator(batch_inputs, return_lqs=True) ================================================ FILE: mmagic/models/editors/real_basicvsr/real_basicvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS from ..basicvsr.basicvsr_net import BasicVSRNet, ResidualBlocksWithInputConv @MODELS.register_module() class RealBasicVSRNet(BaseModule): """RealBasicVSR network structure for real-world video super-resolution. Support only x4 upsampling. Paper: Investigating Tradeoffs in Real-World Video Super-Resolution, arXiv Args: mid_channels (int, optional): Channel number of the intermediate features. Default: 64. num_propagation_blocks (int, optional): Number of residual blocks in each propagation branch. Default: 20. num_cleaning_blocks (int, optional): Number of residual blocks in the image cleaning module. Default: 20. dynamic_refine_thres (int, optional): Stop cleaning the images when the residue is smaller than this value. Default: 255. spynet_pretrained (str, optional): Pre-trained model path of SPyNet. Default: None. is_fix_cleaning (bool, optional): Whether to fix the weights of the image cleaning module during training. Default: False. is_sequential_cleaning (bool, optional): Whether to clean the images sequentially. This is used to save GPU memory, but the speed is slightly slower. Default: False. """ def __init__(self, mid_channels=64, num_propagation_blocks=20, num_cleaning_blocks=20, dynamic_refine_thres=255, spynet_pretrained=None, is_fix_cleaning=False, is_sequential_cleaning=False): super().__init__() self.dynamic_refine_thres = dynamic_refine_thres / 255. self.is_sequential_cleaning = is_sequential_cleaning # image cleaning module self.image_cleaning = nn.Sequential( ResidualBlocksWithInputConv(3, mid_channels, num_cleaning_blocks), nn.Conv2d(mid_channels, 3, 3, 1, 1, bias=True), ) if is_fix_cleaning: # keep the weights of the cleaning module fixed self.image_cleaning.requires_grad_(False) # BasicVSR self.basicvsr = BasicVSRNet(mid_channels, num_propagation_blocks, spynet_pretrained) self.basicvsr.spynet.requires_grad_(False) def forward(self, lqs, return_lqs=False): """Forward function for BasicVSR++. Args: lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w). return_lqs (bool): Whether to return LQ sequence. Default: False. Returns: Tensor: Output HR sequence. """ n, t, c, h, w = lqs.size() for _ in range(0, 3): # at most 3 cleaning, determined empirically if self.is_sequential_cleaning: residues = [] for i in range(0, t): residue_i = self.image_cleaning(lqs[:, i, :, :, :]) lqs[:, i, :, :, :] += residue_i residues.append(residue_i) residues = torch.stack(residues, dim=1) else: # time -> batch, then apply cleaning at once lqs = lqs.view(-1, c, h, w) residues = self.image_cleaning(lqs) lqs = (lqs + residues).view(n, t, c, h, w) # determine whether to continue cleaning if torch.mean(torch.abs(residues)) < self.dynamic_refine_thres: break # Super-resolution (BasicVSR) outputs = self.basicvsr(lqs) if return_lqs: return outputs, lqs else: return outputs ================================================ FILE: mmagic/models/editors/real_esrgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .real_esrgan import RealESRGAN from .unet_disc import UNetDiscriminatorWithSpectralNorm __all__ = [ 'RealESRGAN', 'UNetDiscriminatorWithSpectralNorm', ] ================================================ FILE: mmagic/models/editors/real_esrgan/real_esrgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch from mmagic.registry import MODELS from ..srgan import SRGAN @MODELS.register_module() class RealESRGAN(SRGAN): """Real-ESRGAN model for single image super-resolution. Ref: Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data, 2021. Note: generator_ema is realized in EMA_HOOK Args: generator (dict): Config for the generator. discriminator (dict, optional): Config for the discriminator. Default: None. gan_loss (dict, optional): Config for the gan loss. Note that the loss weight in gan loss is only for the generator. pixel_loss (dict, optional): Config for the pixel loss. Default: None. perceptual_loss (dict, optional): Config for the perceptual loss. Default: None. is_use_sharpened_gt_in_pixel (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for pixel loss. Default: False. is_use_sharpened_gt_in_percep (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for perceptual loss. Default: False. is_use_sharpened_gt_in_gan (bool, optional): Whether to use the image sharpened by unsharp masking as the GT for adversarial loss. Default: False. is_use_ema (bool, optional): When to apply exponential moving average on the network weights. Default: True. train_cfg (dict): Config for training. Default: None. You may change the training of gan by setting: `disc_steps`: how many discriminator updates after one generate update; `disc_init_steps`: how many discriminator updates at the start of the training. These two keys are useful when training with WGAN. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Default: None. """ def __init__(self, generator, discriminator=None, gan_loss=None, pixel_loss=None, perceptual_loss=None, is_use_sharpened_gt_in_pixel=False, is_use_sharpened_gt_in_percep=False, is_use_sharpened_gt_in_gan=False, is_use_ema=True, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, discriminator=discriminator, gan_loss=gan_loss, pixel_loss=pixel_loss, perceptual_loss=perceptual_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.is_use_sharpened_gt_in_pixel = is_use_sharpened_gt_in_pixel self.is_use_sharpened_gt_in_percep = is_use_sharpened_gt_in_percep self.is_use_sharpened_gt_in_gan = is_use_sharpened_gt_in_gan self.is_use_ema = is_use_ema if is_use_ema: self.generator_ema = deepcopy(self.generator) else: self.generator_ema = None if train_cfg is not None: # used for initializing from ema model self.start_iter = train_cfg.get('start_iter', -1) else: self.start_iter = -1 def forward_tensor(self, inputs, data_samples=None, training=False): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. training (bool): Whether is training. Default: False. Returns: Tensor: result of simple forward. """ if training or not self.is_use_ema: feats = self.generator(inputs) else: feats = self.generator_ema(inputs) return feats def g_step(self, batch_outputs, batch_gt_data): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tuple[Tensor]): Batch GT data. Returns: dict: Dict of losses. """ gt_pixel, gt_percep, _ = batch_gt_data losses = dict() # pix loss if self.pixel_loss: losses['loss_pix'] = self.pixel_loss(batch_outputs, gt_pixel) # perceptual loss if self.perceptual_loss: loss_percep, loss_style = self.perceptual_loss( batch_outputs, gt_percep) if loss_percep is not None: losses['loss_perceptual'] = loss_percep if loss_style is not None: losses['loss_style'] = loss_style # gan loss for generator if self.gan_loss and self.discriminator: fake_g_pred = self.discriminator(batch_outputs) losses['loss_gan'] = self.gan_loss( fake_g_pred, target_is_real=True, is_disc=False) return losses def d_step_real(self, batch_outputs, batch_gt_data: torch.Tensor): """Real part of D step. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tuple[Tensor]): Batch GT data. Returns: Tensor: Real part of gan_loss for discriminator. """ _, _, gt_gan = batch_gt_data # real real_d_pred = self.discriminator(gt_gan) loss_d_real = self.gan_loss( real_d_pred, target_is_real=True, is_disc=True) return loss_d_real def d_step_fake(self, batch_outputs, batch_gt_data): """Fake part of D step. Args: batch_outputs (Tensor): Output of generator. batch_gt_data (Tuple[Tensor]): Batch GT data. Returns: Tensor: Fake part of gan_loss for discriminator. """ # fake fake_d_pred = self.discriminator(batch_outputs.detach()) loss_d_fake = self.gan_loss( fake_d_pred, target_is_real=False, is_disc=True) return loss_d_fake def extract_gt_data(self, data_samples): """extract gt data from data samples. Args: data_samples (list): List of DataSample. Returns: Tensor: Extract gt data. """ gt = data_samples.gt_img gt_unsharp = data_samples.gt_unsharp / 255. gt_pixel, gt_percep, gt_gan = gt.clone(), gt.clone(), gt.clone() if self.is_use_sharpened_gt_in_pixel: gt_pixel = gt_unsharp.clone() if self.is_use_sharpened_gt_in_percep: gt_percep = gt_unsharp.clone() if self.is_use_sharpened_gt_in_gan: gt_gan = gt_unsharp.clone() return gt_pixel, gt_percep, gt_gan ================================================ FILE: mmagic/models/editors/real_esrgan/unet_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from torch.nn.utils import spectral_norm from mmagic.registry import MODELS @MODELS.register_module() class UNetDiscriminatorWithSpectralNorm(BaseModule): """A U-Net discriminator with spectral normalization. Args: in_channels (int): Channel number of the input. mid_channels (int, optional): Channel number of the intermediate features. Default: 64. skip_connection (bool, optional): Whether to use skip connection. Default: True. """ def __init__(self, in_channels, mid_channels=64, skip_connection=True): super().__init__() self.skip_connection = skip_connection self.conv_0 = nn.Conv2d( in_channels, mid_channels, kernel_size=3, stride=1, padding=1) # downsample self.conv_1 = spectral_norm( nn.Conv2d(mid_channels, mid_channels * 2, 4, 2, 1, bias=False)) self.conv_2 = spectral_norm( nn.Conv2d(mid_channels * 2, mid_channels * 4, 4, 2, 1, bias=False)) self.conv_3 = spectral_norm( nn.Conv2d(mid_channels * 4, mid_channels * 8, 4, 2, 1, bias=False)) # upsample self.conv_4 = spectral_norm( nn.Conv2d(mid_channels * 8, mid_channels * 4, 3, 1, 1, bias=False)) self.conv_5 = spectral_norm( nn.Conv2d(mid_channels * 4, mid_channels * 2, 3, 1, 1, bias=False)) self.conv_6 = spectral_norm( nn.Conv2d(mid_channels * 2, mid_channels, 3, 1, 1, bias=False)) # final layers self.conv_7 = spectral_norm( nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, bias=False)) self.conv_8 = spectral_norm( nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, bias=False)) self.conv_9 = nn.Conv2d(mid_channels, 1, 3, 1, 1) self.upsample = nn.Upsample( scale_factor=2, mode='bilinear', align_corners=False) self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) def forward(self, img): """Forward function. Args: img (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ feat_0 = self.lrelu(self.conv_0(img)) # downsample feat_1 = self.lrelu(self.conv_1(feat_0)) feat_2 = self.lrelu(self.conv_2(feat_1)) feat_3 = self.lrelu(self.conv_3(feat_2)) # upsample feat_3 = self.upsample(feat_3) feat_4 = self.lrelu(self.conv_4(feat_3)) if self.skip_connection: feat_4 = feat_4 + feat_2 feat_4 = self.upsample(feat_4) feat_5 = self.lrelu(self.conv_5(feat_4)) if self.skip_connection: feat_5 = feat_5 + feat_1 feat_5 = self.upsample(feat_5) feat_6 = self.lrelu(self.conv_6(feat_5)) if self.skip_connection: feat_6 = feat_6 + feat_0 # final layers out = self.lrelu(self.conv_7(feat_6)) out = self.lrelu(self.conv_8(out)) return self.conv_9(out) ================================================ FILE: mmagic/models/editors/restormer/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .restormer_net import Restormer __all__ = ['Restormer'] ================================================ FILE: mmagic/models/editors/restormer/restormer_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numbers import torch import torch.nn as nn import torch.nn.functional as F from einops import rearrange from mmengine.model import BaseModule from mmagic.registry import MODELS def to_3d(x): """Reshape input tensor.""" return rearrange(x, 'b c h w -> b (h w) c') def to_4d(x, h, w): """Reshape input tensor.""" return rearrange(x, 'b (h w) c -> b c h w', h=h, w=w) class BiasFree_LayerNorm(BaseModule): """Layer normalization without bias. Args: normalized_shape (tuple): The shape of inputs. """ def __init__(self, normalized_shape): super(BiasFree_LayerNorm, self).__init__() if isinstance(normalized_shape, numbers.Integral): normalized_shape = (normalized_shape, ) normalized_shape = torch.Size(normalized_shape) assert len(normalized_shape) == 1 self.weight = nn.Parameter(torch.ones(normalized_shape)) self.normalized_shape = normalized_shape def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ sigma = x.var(-1, keepdim=True, unbiased=False) return x / torch.sqrt(sigma + 1e-5) * self.weight class WithBias_LayerNorm(BaseModule): """Layer normalization with bias. The bias can be learned. Args: normalized_shape (tuple): The shape of inputs. """ def __init__(self, normalized_shape): super(WithBias_LayerNorm, self).__init__() if isinstance(normalized_shape, numbers.Integral): normalized_shape = (normalized_shape, ) normalized_shape = torch.Size(normalized_shape) assert len(normalized_shape) == 1 self.weight = nn.Parameter(torch.ones(normalized_shape)) self.bias = nn.Parameter(torch.zeros(normalized_shape)) self.normalized_shape = normalized_shape def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ mu = x.mean(-1, keepdim=True) sigma = x.var(-1, keepdim=True, unbiased=False) return (x - mu) / torch.sqrt(sigma + 1e-5) * self.weight + self.bias class LayerNorm(BaseModule): """Layer normalization module. Note: This is different from the layernorm2d in pytorch. The layer norm here can select Layer Normalization type. Args: dim (int): Channel number of inputs. LayerNorm_type (str): Layer Normalization type. """ def __init__(self, dim, LayerNorm_type): super(LayerNorm, self).__init__() if LayerNorm_type == 'BiasFree': self.body = BiasFree_LayerNorm(dim) else: self.body = WithBias_LayerNorm(dim) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ h, w = x.shape[-2:] return to_4d(self.body(to_3d(x)), h, w) class FeedForward(BaseModule): """Gated-Dconv Feed-Forward Network (GDFN) The original version of GDFN in "Restormer: Efficient Transformer for High-Resolution Image Restoration". Args: dim (int): Channel number of inputs. ffn_expansion_factor (float): channel expansion factor. Default: 2.66 bias (bool): The bias of convolution. """ def __init__(self, dim, ffn_expansion_factor, bias): super(FeedForward, self).__init__() hidden_features = int(dim * ffn_expansion_factor) self.project_in = nn.Conv2d( dim, hidden_features * 2, kernel_size=1, bias=bias) self.dwconv = nn.Conv2d( hidden_features * 2, hidden_features * 2, kernel_size=3, stride=1, padding=1, groups=hidden_features * 2, bias=bias) self.project_out = nn.Conv2d( hidden_features, dim, kernel_size=1, bias=bias) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ x = self.project_in(x) x1, x2 = self.dwconv(x).chunk(2, dim=1) x = F.gelu(x1) * x2 x = self.project_out(x) return x class Attention(BaseModule): """Multi-DConv Head Transposed Self-Attention (MDTA) The original version of MDTA in "Restormer: Efficient Transformer for High-Resolution Image Restoration". Args: dim (int): Channel number of inputs. num_heads (int): Number of attention heads. bias (bool): The bias of convolution. """ def __init__(self, dim, num_heads, bias): super(Attention, self).__init__() self.num_heads = num_heads self.temperature = nn.Parameter(torch.ones(num_heads, 1, 1)) self.qkv = nn.Conv2d(dim, dim * 3, kernel_size=1, bias=bias) self.qkv_dwconv = nn.Conv2d( dim * 3, dim * 3, kernel_size=3, stride=1, padding=1, groups=dim * 3, bias=bias) self.project_out = nn.Conv2d(dim, dim, kernel_size=1, bias=bias) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ b, c, h, w = x.shape qkv = self.qkv_dwconv(self.qkv(x)) q, k, v = qkv.chunk(3, dim=1) q = rearrange( q, 'b (head c) h w -> b head c (h w)', head=self.num_heads) k = rearrange( k, 'b (head c) h w -> b head c (h w)', head=self.num_heads) v = rearrange( v, 'b (head c) h w -> b head c (h w)', head=self.num_heads) q = torch.nn.functional.normalize(q, dim=-1) k = torch.nn.functional.normalize(k, dim=-1) attn = (q @ k.transpose(-2, -1)) * self.temperature attn = attn.softmax(dim=-1) out = (attn @ v) out = rearrange( out, 'b head c (h w) -> b (head c) h w', head=self.num_heads, h=h, w=w) out = self.project_out(out) return out class TransformerBlock(BaseModule): """Transformer Block. The original version of Transformer Block in "Restormer: Efficient\ Transformer for High-Resolution Image Restoration". Args: dim (int): Channel number of inputs. num_heads (int): Number of attention heads. ffn_expansion_factor (float): channel expansion factor. Default: 2.66 bias (bool): The bias of convolution. LayerNorm_type (str): Layer Normalization type. """ def __init__(self, dim, num_heads, ffn_expansion_factor, bias, LayerNorm_type): super(TransformerBlock, self).__init__() self.norm1 = LayerNorm(dim, LayerNorm_type) self.attn = Attention(dim, num_heads, bias) self.norm2 = LayerNorm(dim, LayerNorm_type) self.ffn = FeedForward(dim, ffn_expansion_factor, bias) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ x = x + self.attn(self.norm1(x)) x = x + self.ffn(self.norm2(x)) return x class OverlapPatchEmbed(BaseModule): """Overlapped image patch embedding with 3x3 Conv. Args: in_c (int, optional): Channel number of inputs. Default: 3 embed_dim (int, optional): embedding dimension. Default: 48 bias (bool, optional): The bias of convolution. Default: False """ def __init__(self, in_c=3, embed_dim=48, bias=False): super(OverlapPatchEmbed, self).__init__() self.proj = nn.Conv2d( in_c, embed_dim, kernel_size=3, stride=1, padding=1, bias=bias) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ x = self.proj(x) return x class Downsample(BaseModule): """Downsample modules. Args: n_feat(int): Channel number of features. """ def __init__(self, n_feat): super(Downsample, self).__init__() self.body = nn.Sequential( nn.Conv2d( n_feat, n_feat // 2, kernel_size=3, stride=1, padding=1, bias=False), nn.PixelUnshuffle(2)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ return self.body(x) class Upsample(BaseModule): """Upsample modules. Args: n_feat(int): Channel number of features. """ def __init__(self, n_feat): super(Upsample, self).__init__() self.body = nn.Sequential( nn.Conv2d( n_feat, n_feat * 2, kernel_size=3, stride=1, padding=1, bias=False), nn.PixelShuffle(2)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ return self.body(x) @MODELS.register_module() class Restormer(BaseModule): """Restormer A PyTorch impl of: `Restormer: Efficient Transformer for High- Resolution Image Restoration`. Ref repo: https://github.com/swz30/Restormer. Args: inp_channels (int): Number of input image channels. Default: 3. out_channels (int): Number of output image channels: 3. dim (int): Number of feature dimension. Default: 48. num_blocks (List(int)): Depth of each Transformer layer. Default: [4, 6, 6, 8]. num_refinement_blocks (int): Number of refinement blocks. Default: 4. heads (List(int)): Number of attention heads in different layers. Default: 7. ffn_expansion_factor (float): Ratio of feed forward network expansion. Default: 2.66. bias (bool): The bias of convolution. Default: False LayerNorm_type (str|optional): Select layer Normalization type. Optional: 'WithBias','BiasFree' Default: 'WithBias'. dual_pixel_task (bool): True for dual-pixel defocus deblurring only. Also set inp_channels=6. Default: False. dual_keys (List): Keys of dual images in inputs. Default: ['imgL', 'imgR']. """ def __init__(self, inp_channels=3, out_channels=3, dim=48, num_blocks=[4, 6, 6, 8], num_refinement_blocks=4, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False, dual_keys=['imgL', 'imgR']): super(Restormer, self).__init__() self.patch_embed = OverlapPatchEmbed(inp_channels, dim) self.encoder_level1 = nn.Sequential(*[ TransformerBlock( dim=dim, num_heads=heads[0], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[0]) ]) self.down1_2 = Downsample(dim) self.encoder_level2 = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**1), num_heads=heads[1], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[1]) ]) self.down2_3 = Downsample(int(dim * 2**1)) self.encoder_level3 = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**2), num_heads=heads[2], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[2]) ]) self.down3_4 = Downsample(int(dim * 2**2)) self.latent = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**3), num_heads=heads[3], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[3]) ]) self.up4_3 = Upsample(int(dim * 2**3)) self.reduce_chan_level3 = nn.Conv2d( int(dim * 2**3), int(dim * 2**2), kernel_size=1, bias=bias) self.decoder_level3 = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**2), num_heads=heads[2], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[2]) ]) self.up3_2 = Upsample(int(dim * 2**2)) self.reduce_chan_level2 = nn.Conv2d( int(dim * 2**2), int(dim * 2**1), kernel_size=1, bias=bias) self.decoder_level2 = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**1), num_heads=heads[1], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[1]) ]) self.up2_1 = Upsample(int(dim * 2**1)) self.decoder_level1 = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**1), num_heads=heads[0], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_blocks[0]) ]) self.refinement = nn.Sequential(*[ TransformerBlock( dim=int(dim * 2**1), num_heads=heads[0], ffn_expansion_factor=ffn_expansion_factor, bias=bias, LayerNorm_type=LayerNorm_type) for i in range(num_refinement_blocks) ]) self.dual_pixel_task = dual_pixel_task self.dual_keys = dual_keys if self.dual_pixel_task: self.skip_conv = nn.Conv2d( dim, int(dim * 2**1), kernel_size=1, bias=bias) self.output = nn.Conv2d( int(dim * 2**1), out_channels, kernel_size=3, stride=1, padding=1, bias=bias) def forward(self, inp_img): """Forward function. Args: inp_img (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ if self.dual_pixel_task: dual_images = [inp_img[key] for key in self.dual_keys] inp_img = torch.cat(dual_images, dim=1) _, _, h, w = inp_img.shape if h % 8 == 0: padding_h = 0 else: padding_h = 8 - h % 8 if w % 8 == 0: padding_w = 0 else: padding_w = 8 - w % 8 inp_img = F.pad(inp_img, (0, padding_w, 0, padding_h), 'reflect') inp_enc_level1 = self.patch_embed(inp_img) out_enc_level1 = self.encoder_level1(inp_enc_level1) inp_enc_level2 = self.down1_2(out_enc_level1) out_enc_level2 = self.encoder_level2(inp_enc_level2) inp_enc_level3 = self.down2_3(out_enc_level2) out_enc_level3 = self.encoder_level3(inp_enc_level3) inp_enc_level4 = self.down3_4(out_enc_level3) latent = self.latent(inp_enc_level4) inp_dec_level3 = self.up4_3(latent) inp_dec_level3 = torch.cat([inp_dec_level3, out_enc_level3], 1) inp_dec_level3 = self.reduce_chan_level3(inp_dec_level3) out_dec_level3 = self.decoder_level3(inp_dec_level3) inp_dec_level2 = self.up3_2(out_dec_level3) inp_dec_level2 = torch.cat([inp_dec_level2, out_enc_level2], 1) inp_dec_level2 = self.reduce_chan_level2(inp_dec_level2) out_dec_level2 = self.decoder_level2(inp_dec_level2) inp_dec_level1 = self.up2_1(out_dec_level2) inp_dec_level1 = torch.cat([inp_dec_level1, out_enc_level1], 1) out_dec_level1 = self.decoder_level1(inp_dec_level1) out_dec_level1 = self.refinement(out_dec_level1) if self.dual_pixel_task: out_dec_level1 = out_dec_level1 + self.skip_conv(inp_enc_level1) out_dec_level1 = self.output(out_dec_level1) else: out_dec_level1 = self.output(out_dec_level1) + inp_img return out_dec_level1[:, :, :h, :w] ================================================ FILE: mmagic/models/editors/sagan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .sagan import SAGAN from .sagan_discriminator import ProjDiscriminator from .sagan_generator import SNGANGenerator from .sagan_modules import (SNGANDiscHeadResBlock, SNGANDiscResBlock, SNGANGenResBlock) __all__ = [ 'SAGAN', 'SNGANGenerator', 'ProjDiscriminator', 'SNGANDiscHeadResBlock', 'SNGANDiscResBlock', 'SNGANGenResBlock' ] ================================================ FILE: mmagic/models/editors/sagan/sagan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import Config from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseConditionalGAN ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module('SNGAN') @MODELS.register_module() class SAGAN(BaseConditionalGAN): """Implementation of `Self-Attention Generative Adversarial Networks`. `_ (SAGAN), `Spectral Normalization for Generative Adversarial Networks `_ (SNGAN), and `cGANs with Projection Discriminator `_ (Proj-GAN). Detailed architecture can be found in :class:`~mmagic.models.editors.sagan.SNGANGenerator` and :class:`~mmagic.models.editors.sagan.ProjDiscriminator` Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): Number of times the generator was completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): Number of times the discriminator was completely updated before the generator is updated. Defaults to 1. noise_size (Optional[int]): Size of the input noise vector. Default to 128. num_classes (Optional[int]): The number classes you would like to generate. Defaults to None. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, noise_size: Optional[int] = 128, num_classes: Optional[int] = None, ema_config: Optional[Dict] = None): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, noise_size, num_classes, ema_config) def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple[Tensor, dict]: r"""Get disc loss. SAGAN, SNGAN and Proj-GAN use hinge loss to train the discriminator. .. math: L_{D} = -\mathbb{E}_{\left(x, y\right)\sim{p}_{data}} \left[\min\left(0, -1 + D\left(x, y\right)\right)\right] -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}}\left[\min \left(0, -1 - D\left(G\left(z\right), y\right)\right)\right] Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.relu(1 + disc_pred_fake).mean() losses_dict['loss_disc_real'] = F.relu(1 - disc_pred_real).mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple[Tensor, dict]: r"""Get disc loss. SAGAN, SNGAN and Proj-GAN use hinge loss to train the generator. .. math: L_{G} = -\mathbb{E}_{z\sim{p_{z}}, y\sim{p_{data}}} D\left(G\left(z\right), y\right) Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img real_labels = self.data_sample_to_label(data_samples) assert real_labels is not None, ( 'Cannot found \'gt_label\' in \'data_sample\'.') num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise=noise_batch, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) disc_pred_real = self.discriminator(real_imgs, label=real_labels) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_labels = self.label_fn(num_batches=num_batches) fake_imgs = self.generator( noise=noise, label=fake_labels, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs, label=fake_labels) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/sagan/sagan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch import torch.nn as nn from mmengine.logging import MMLogger from mmengine.model import BaseModule, xavier_init from mmengine.runner import load_checkpoint from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from torch.nn.init import xavier_uniform_ from torch.nn.utils import spectral_norm from mmagic.registry import MODELS @MODELS.register_module('SAGANDiscriminator') @MODELS.register_module() class ProjDiscriminator(BaseModule): r"""Discriminator for SNGAN / Proj-GAN. The implementation is refer to https://github.com/pfnet-research/sngan_projection/tree/master/dis_models The overall structure of the projection discriminator can be split into a ``from_rgb`` layer, a group of ResBlocks, a linear decision layer, and a projection layer. To support defining custom layers, we introduce ``from_rgb_cfg`` and ``blocks_cfg``. The design of the model structure is highly corresponding to the output resolution. Therefore, we provide `channels_cfg` and `downsample_cfg` to control the input channels and the downsample behavior of the intermediate blocks. ``downsample_cfg``: In default config of SNGAN / Proj-GAN, whether to apply downsample in each intermediate blocks is quite flexible and corresponding to the resolution of the output image. Therefore, we support user to define the ``downsample_cfg`` by themselves, and to control the structure of the discriminator. ``channels_cfg``: In default config of SNGAN / Proj-GAN, the number of ResBlocks and the channels of those blocks are corresponding to the resolution of the output image. Therefore, we allow user to define `channels_cfg` for try their own models. We also provide a default config to allow users to build the model only from the output resolution. Args: input_scale (int): The scale of the input image. num_classes (int, optional): The number classes you would like to generate. If num_classes=0, no label projection would be used. Default to 0. base_channels (int, optional): The basic channel number of the discriminator. The other layers contains channels based on this number. Defaults to 128. input_channels (int, optional): Channels of the input image. Defaults to 3. attention_cfg (dict, optional): Config for the self-attention block. Default to ``dict(type='SelfAttentionBlock')``. attention_after_nth_block (int | list[int], optional): Self-attention block would be added after which *ConvBlock* (including the head block). If ``int`` is passed, only one attention block would be added. If ``list`` is passed, self-attention blocks would be added after multiple ConvBlocks. To be noted that if the input is smaller than ``1``, self-attention corresponding to this index would be ignored. Default to 0. channels_cfg (list | dict[list], optional): Config for input channels of the intermediate blocks. If list is passed, each element of the list means the input channels of current block is how many times compared to the ``base_channels``. For block ``i``, the input and output channels should be ``channels_cfg[i]`` and ``channels_cfg[i+1]`` If dict is provided, the key of the dict should be the output scale and corresponding value should be a list to define channels. Default: Please refer to ``_defualt_channels_cfg``. downsample_cfg (list[bool] | dict[list], optional): Config for downsample behavior of the intermediate layers. If a list is passed, ``downsample_cfg[idx] == True`` means apply downsample in idx-th block, and vice versa. If dict is provided, the key dict should be the input scale of the image and corresponding value should be a list ti define the downsample behavior. Default: Please refer to ``_default_downsample_cfg``. from_rgb_cfg (dict, optional): Config for the first layer to convert rgb image to feature map. Defaults to ``dict(type='SNGANDiscHeadResBlock')``. blocks_cfg (dict, optional): Config for the intermediate blocks. Defaults to ``dict(type='SNGANDiscResBlock')`` act_cfg (dict, optional): Activation config for the final output layer. Defaults to ``dict(type='ReLU')``. with_spectral_norm (bool, optional): Whether use spectral norm for all conv blocks or not. Default to True. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. sn_eps (float, optional): eps for spectral normalization operation. Defaults to `1e-12`. init_cfg (dict, optional): Config for weight initialization. Default to ``dict(type='BigGAN')``. pretrained (str | dict , optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ # default channel factors _defualt_channels_cfg = { 32: [1, 1, 1], 64: [2, 4, 8, 16], 128: [2, 4, 8, 16, 16], } # default downsample behavior _defualt_downsample_cfg = { 32: [True, False, False], 64: [True, True, True, True], 128: [True, True, True, True, False] } def __init__(self, input_scale, num_classes=0, base_channels=128, input_channels=3, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=-1, channels_cfg=None, downsample_cfg=None, from_rgb_cfg=dict(type='SNGANDiscHeadResBlock'), blocks_cfg=dict(type='SNGANDiscResBlock'), act_cfg=dict(type='ReLU'), with_spectral_norm=True, sn_style='torch', sn_eps=1e-12, init_cfg=dict(type='BigGAN'), pretrained=None): super().__init__() self.init_type = init_cfg.get('type', None) # add SN options and activation function options to cfg self.from_rgb_cfg = deepcopy(from_rgb_cfg) self.from_rgb_cfg.setdefault('act_cfg', act_cfg) self.from_rgb_cfg.setdefault('with_spectral_norm', with_spectral_norm) self.from_rgb_cfg.setdefault('sn_style', sn_style) self.from_rgb_cfg.setdefault('init_cfg', init_cfg) # add SN options and activation function options to cfg self.blocks_cfg = deepcopy(blocks_cfg) self.blocks_cfg.setdefault('act_cfg', act_cfg) self.blocks_cfg.setdefault('with_spectral_norm', with_spectral_norm) self.blocks_cfg.setdefault('sn_style', sn_style) self.blocks_cfg.setdefault('sn_eps', sn_eps) self.blocks_cfg.setdefault('init_cfg', init_cfg) channels_cfg = deepcopy(self._defualt_channels_cfg) \ if channels_cfg is None else deepcopy(channels_cfg) if isinstance(channels_cfg, dict): if input_scale not in channels_cfg: raise KeyError(f'`input_scale={input_scale} is not found in ' '`channel_cfg`, only support configs for ' f'{[chn for chn in channels_cfg.keys()]}') self.channel_factor_list = channels_cfg[input_scale] elif isinstance(channels_cfg, list): self.channel_factor_list = channels_cfg else: raise ValueError('Only support list or dict for `channel_cfg`, ' f'receive {type(channels_cfg)}') downsample_cfg = deepcopy(self._defualt_downsample_cfg) \ if downsample_cfg is None else deepcopy(downsample_cfg) if isinstance(downsample_cfg, dict): if input_scale not in downsample_cfg: raise KeyError(f'`output_scale={input_scale} is not found in ' '`downsample_cfg`, only support configs for ' f'{[chn for chn in downsample_cfg.keys()]}') self.downsample_list = downsample_cfg[input_scale] elif isinstance(downsample_cfg, list): self.downsample_list = downsample_cfg else: raise ValueError('Only support list or dict for `channel_cfg`, ' f'receive {type(downsample_cfg)}') if len(self.downsample_list) != len(self.channel_factor_list): raise ValueError('`downsample_cfg` should have same length with ' '`channels_cfg`, but receive ' f'{len(self.downsample_list)} and ' f'{len(self.channel_factor_list)}.') # check `attention_after_nth_block` if not isinstance(attention_after_nth_block, list): attention_after_nth_block = [attention_after_nth_block] if not all([isinstance(idx, int) for idx in attention_after_nth_block]): raise ValueError('`attention_after_nth_block` only support int or ' 'a list of int. Please check your input type.') self.from_rgb = MODELS.build( self.from_rgb_cfg, default_args=dict( in_channels=input_channels, out_channels=base_channels)) self.conv_blocks = nn.ModuleList() # add self-attention block after the first block if 1 in attention_after_nth_block: attn_cfg_ = deepcopy(attention_cfg) attn_cfg_['in_channels'] = base_channels attn_cfg_['sn_style'] = sn_style self.conv_blocks.append(MODELS.build(attn_cfg_)) for idx in range(len(self.downsample_list)): factor_input = 1 if idx == 0 else self.channel_factor_list[idx - 1] factor_output = self.channel_factor_list[idx] # get block-specific config block_cfg_ = deepcopy(self.blocks_cfg) block_cfg_['downsample'] = self.downsample_list[idx] block_cfg_['in_channels'] = factor_input * base_channels block_cfg_['out_channels'] = factor_output * base_channels self.conv_blocks.append(MODELS.build(block_cfg_)) # build self-attention block # the first ConvBlock is `from_rgb` block, # add 2 to get the index of the ConvBlocks if idx + 2 in attention_after_nth_block: attn_cfg_ = deepcopy(attention_cfg) attn_cfg_['in_channels'] = factor_output * base_channels self.conv_blocks.append(MODELS.build(attn_cfg_)) self.decision = nn.Linear(factor_output * base_channels, 1) if with_spectral_norm: self.decision = spectral_norm(self.decision) self.num_classes = num_classes # In this case, discriminator is designed for conditional synthesis. if num_classes > 0: self.proj_y = nn.Embedding(num_classes, factor_output * base_channels) if with_spectral_norm: self.proj_y = spectral_norm(self.proj_y) self.activate = MODELS.build(act_cfg) self.init_weights(pretrained) def forward(self, x, label=None): """Forward function. If `self.num_classes` is larger than 0, label projection would be used. Args: x (torch.Tensor): Fake or real image tensor. label (torch.Tensor, options): Label correspond to the input image. Noted that, if `self.num_classed` is larger than 0, `label` should not be None. Default to None. Returns: torch.Tensor: Prediction for the reality of the input image. """ h = self.from_rgb(x) for conv_block in self.conv_blocks: h = conv_block(h) h = self.activate(h) h = torch.sum(h, dim=[2, 3]) out = self.decision(h) if self.num_classes > 0: w_y = self.proj_y(label) out = out + torch.sum(w_y * h, dim=1, keepdim=True) return out.view(out.size(0), -1) def init_weights(self, pretrained=None, strict=True): """Init weights for SNGAN-Proj and SAGAN. If ``pretrained=None`` and weight initialization would follow the ``INIT_TYPE`` in ``init_cfg=dict(type=INIT_TYPE)``. For SNGAN-Proj (``INIT_TYPE.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']``), we follow the initialization method in the official Chainer's implementation (https://github.com/pfnet-research/sngan_projection). For SAGAN (``INIT_TYPE.upper() == 'SAGAN'``), we follow the initialization method in official tensorflow's implementation (https://github.com/brain-research/self-attention-gan). Besides the reimplementation of the official code's initialization, we provide BigGAN's and Pytorch-StudioGAN's style initialization (``INIT_TYPE.upper() == BIGGAN`` and ``INIT_TYPE.upper() == STUDIO``). Please refer to https://github.com/ajbrock/BigGAN-PyTorch and https://github.com/POSTECH-CVLab/PyTorch-StudioGAN. Args: pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=strict, logger=logger) elif isinstance(pretrained, dict): ckpt_path = pretrained.get('ckpt_path', None) assert ckpt_path is not None prefix = pretrained.get('prefix', '') map_location = pretrained.get('map_location', 'cpu') strict = pretrained.get('strict', True) state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) elif pretrained is None: if self.init_type.upper() == 'STUDIO': # initialization method from Pytorch-StudioGAN # * weight: orthogonal_init gain=1 # * bias : 0 for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): nn.init.orthogonal_(m.weight, gain=1) if hasattr(m, 'bias') and m.bias is not None: m.bias.data.fill_(0.) elif self.init_type.upper() == 'BIGGAN': # initialization method from BigGAN-pytorch # * weight: xavier_init gain=1 # * bias : default for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): xavier_uniform_(m.weight, gain=1) elif self.init_type.upper() == 'SAGAN': # initialization method from official tensorflow code # * weight: xavier_init gain=1 # * bias : 0 for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): xavier_init(m, gain=1, distribution='uniform') elif self.init_type.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']: # initialization method from the official chainer code # * embedding.weight: xavier_init gain=1 # * conv.weight : xavier_init gain=sqrt(2) # * shortcut.weight : xavier_init gain=1 # * bias : 0 for n, m in self.named_modules(): if isinstance(m, nn.Conv2d): if 'shortcut' in n: xavier_init(m, gain=1, distribution='uniform') else: xavier_init( m, gain=np.sqrt(2), distribution='uniform') if isinstance(m, (nn.Linear, nn.Embedding)): xavier_init(m, gain=1, distribution='uniform') else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') else: raise TypeError("'pretrained' must by a str or None. " f'But receive {type(pretrained)}.') ================================================ FILE: mmagic/models/editors/sagan/sagan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine import is_list_of from mmengine.dist import is_distributed from mmengine.logging import MMLogger from mmengine.model import BaseModule, constant_init, xavier_init from mmengine.runner import load_checkpoint from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from torch.nn.init import xavier_uniform_ from torch.nn.utils import spectral_norm from mmagic.models.utils import get_module_device from mmagic.registry import MODELS @MODELS.register_module('SAGANGenerator') @MODELS.register_module() class SNGANGenerator(BaseModule): r"""Generator for SNGAN / Proj-GAN. The implementation refers to https://github.com/pfnet-research/sngan_projection/tree/master/gen_models In our implementation, we have two notable design. Namely, ``channels_cfg`` and ``blocks_cfg``. ``channels_cfg``: In default config of SNGAN / Proj-GAN, the number of ResBlocks and the channels of those blocks are corresponding to the resolution of the output image. Therefore, we allow user to define ``channels_cfg`` to try their own models. We also provide a default config to allow users to build the model only from the output resolution. ``block_cfg``: In reference code, the generator consists of a group of ResBlock. However, in our implementation, to make this model more generalize, we support defining ``blocks_cfg`` by users and loading the blocks by calling the build_module method. Args: output_scale (int): Output scale for the generated image. num_classes (int, optional): The number classes you would like to generate. This arguments would influence the structure of the intermediate blocks and label sampling operation in ``forward`` (e.g. If num_classes=0, ConditionalNormalization layers would degrade to unconditional ones.). This arguments would be passed to intermediate blocks by overwrite their config. Defaults to 0. base_channels (int, optional): The basic channel number of the generator. The other layers contains channels based on this number. Default to 64. out_channels (int, optional): Channels of the output images. Default to 3. input_scale (int, optional): Input scale for the features. Defaults to 4. noise_size (int, optional): Size of the input noise vector. Default to 128. attention_cfg (dict, optional): Config for the self-attention block. Default to ``dict(type='SelfAttentionBlock')``. attention_after_nth_block (int | list[int], optional): Self attention block would be added after which *ConvBlock*. If ``int`` is passed, only one attention block would be added. If ``list`` is passed, self-attention blocks would be added after multiple ConvBlocks. To be noted that if the input is smaller than ``1``, self-attention corresponding to this index would be ignored. Default to 0. channels_cfg (list | dict[list], optional): Config for input channels of the intermediate blocks. If list is passed, each element of the list means the input channels of current block is how many times compared to the ``base_channels``. For block ``i``, the input and output channels should be ``channels_cfg[i]`` and ``channels_cfg[i+1]`` If dict is provided, the key of the dict should be the output scale and corresponding value should be a list to define channels. Default: Please refer to ``_defualt_channels_cfg``. blocks_cfg (dict, optional): Config for the intermediate blocks. Defaults to ``dict(type='SNGANGenResBlock')`` act_cfg (dict, optional): Activation config for the final output layer. Defaults to ``dict(type='ReLU')``. use_cbn (bool, optional): Whether use conditional normalization. This argument would pass to norm layers. Defaults to True. auto_sync_bn (bool, optional): Whether convert Batch Norm to Synchronized ones when Distributed training is on. Defaults to True. with_spectral_norm (bool, optional): Whether use spectral norm for conv blocks or not. Default to False. with_embedding_spectral_norm (bool, optional): Whether use spectral norm for embedding layers in normalization blocks or not. If not specified (set as ``None``), ``with_embedding_spectral_norm`` would be set as the same value as ``with_spectral_norm``. Defaults to None. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. norm_eps (float, optional): eps for Normalization layers (both conditional and non-conditional ones). Default to `1e-4`. sn_eps (float, optional): eps for spectral normalization operation. Defaults to `1e-12`. init_cfg (string, optional): Config for weight initialization. Defaults to ``dict(type='BigGAN')``. pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. rgb_to_bgr (bool, optional): Whether to reformat the output channels with order `bgr`. We provide several pre-trained BigGAN weights whose output channels order is `rgb`. You can set this argument to True to use the weights. """ # default channel factors _default_channels_cfg = { 32: [1, 1, 1], 64: [16, 8, 4, 2], 128: [16, 16, 8, 4, 2] } def __init__(self, output_scale, num_classes=0, base_channels=64, out_channels=3, input_scale=4, noise_size=128, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=0, channels_cfg=None, blocks_cfg=dict(type='SNGANGenResBlock'), act_cfg=dict(type='ReLU'), use_cbn=True, auto_sync_bn=True, with_spectral_norm=False, with_embedding_spectral_norm=None, sn_style='torch', norm_eps=1e-4, sn_eps=1e-12, init_cfg=dict(type='BigGAN'), pretrained=None, rgb_to_bgr=False): super().__init__() self.input_scale = input_scale self.output_scale = output_scale self.noise_size = noise_size self.num_classes = num_classes self.init_type = init_cfg.get('type', None) self.rgb_to_bgr = rgb_to_bgr self.blocks_cfg = deepcopy(blocks_cfg) self.blocks_cfg.setdefault('num_classes', num_classes) self.blocks_cfg.setdefault('act_cfg', act_cfg) self.blocks_cfg.setdefault('use_cbn', use_cbn) self.blocks_cfg.setdefault('auto_sync_bn', auto_sync_bn) self.blocks_cfg.setdefault('with_spectral_norm', with_spectral_norm) # set `norm_spectral_norm` as `with_spectral_norm` if not defined with_embedding_spectral_norm = with_embedding_spectral_norm \ if with_embedding_spectral_norm is not None else with_spectral_norm self.blocks_cfg.setdefault('with_embedding_spectral_norm', with_embedding_spectral_norm) self.blocks_cfg.setdefault('init_cfg', init_cfg) self.blocks_cfg.setdefault('sn_style', sn_style) self.blocks_cfg.setdefault('norm_eps', norm_eps) self.blocks_cfg.setdefault('sn_eps', sn_eps) channels_cfg = deepcopy(self._default_channels_cfg) \ if channels_cfg is None else deepcopy(channels_cfg) if isinstance(channels_cfg, dict): if output_scale not in channels_cfg: raise KeyError(f'`output_scale={output_scale} is not found in ' '`channel_cfg`, only support configs for ' f'{[chn for chn in channels_cfg.keys()]}') self.channel_factor_list = channels_cfg[output_scale] elif isinstance(channels_cfg, list): self.channel_factor_list = channels_cfg else: raise ValueError('Only support list or dict for `channel_cfg`, ' f'receive {type(channels_cfg)}') self.noise2feat = nn.Linear( noise_size, input_scale**2 * base_channels * self.channel_factor_list[0]) if with_spectral_norm: self.noise2feat = spectral_norm(self.noise2feat) # check `attention_after_nth_block` if not isinstance(attention_after_nth_block, list): attention_after_nth_block = [attention_after_nth_block] if not is_list_of(attention_after_nth_block, int): raise ValueError('`attention_after_nth_block` only support int or ' 'a list of int. Please check your input type.') self.conv_blocks = nn.ModuleList() self.attention_block_idx = [] for idx in range(len(self.channel_factor_list)): factor_input = self.channel_factor_list[idx] factor_output = self.channel_factor_list[idx+1] \ if idx < len(self.channel_factor_list)-1 else 1 # get block-specific config block_cfg_ = deepcopy(self.blocks_cfg) block_cfg_['in_channels'] = factor_input * base_channels block_cfg_['out_channels'] = factor_output * base_channels self.conv_blocks.append(MODELS.build(block_cfg_)) # build self-attention block # `idx` is start from 0, add 1 to get the index if idx + 1 in attention_after_nth_block: self.attention_block_idx.append(len(self.conv_blocks)) attn_cfg_ = deepcopy(attention_cfg) attn_cfg_['in_channels'] = factor_output * base_channels attn_cfg_['sn_style'] = sn_style self.conv_blocks.append(MODELS.build(attn_cfg_)) to_rgb_norm_cfg = dict(type='BN', eps=norm_eps) if is_distributed() and auto_sync_bn: to_rgb_norm_cfg['type'] = 'SyncBN' self.to_rgb = ConvModule( factor_output * base_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True, norm_cfg=to_rgb_norm_cfg, act_cfg=act_cfg, order=('norm', 'act', 'conv'), with_spectral_norm=with_spectral_norm) self.final_act = MODELS.build(dict(type='Tanh')) self.init_weights(pretrained) def forward(self, noise, num_batches=0, label=None, return_noise=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. label (torch.Tensor | callable | None): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_image``, ``noise_batch`` and ``label_batch`` would be returned. """ if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size)) if isinstance(label, torch.Tensor): if label.ndim != 1: assert all([s == 1 for s in label.shape[1:]]) label = label.view(-1) assert label.ndim == 1, ('The label should be in shape of (n, )' f'but got {label.shape}.') label_batch = label elif callable(label): label_generator = label assert num_batches > 0 label_batch = label_generator(num_batches) elif self.num_classes == 0: label_batch = None else: assert num_batches > 0 label_batch = torch.randint(0, self.num_classes, (num_batches, )) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) if label_batch is not None: label_batch = label_batch.to(get_module_device(self)) x = self.noise2feat(noise_batch) x = x.reshape(x.size(0), -1, self.input_scale, self.input_scale) for idx, conv_block in enumerate(self.conv_blocks): if idx in self.attention_block_idx: x = conv_block(x) else: x = conv_block(x, label_batch) out_feat = self.to_rgb(x) out_img = self.final_act(out_feat) if self.rgb_to_bgr: out_img = out_img[:, [2, 1, 0], ...] if return_noise: return dict( fake_img=out_img, noise_batch=noise_batch, label=label_batch) return out_img def init_weights(self, pretrained=None, strict=True): """Init weights for SNGAN-Proj and SAGAN. If ``pretrained=None``, weight initialization would follow the ``INIT_TYPE`` in ``init_cfg=dict(type=INIT_TYPE)``. For SNGAN-Proj, (``INIT_TYPE.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']``), we follow the initialization method in the official Chainer's implementation (https://github.com/pfnet-research/sngan_projection). For SAGAN (``INIT_TYPE.upper() == 'SAGAN'``), we follow the initialization method in official tensorflow's implementation (https://github.com/brain-research/self-attention-gan). Besides the reimplementation of the official code's initialization, we provide BigGAN's and Pytorch-StudioGAN's style initialization (``INIT_TYPE.upper() == BIGGAN`` and ``INIT_TYPE.upper() == STUDIO``). Please refer to https://github.com/ajbrock/BigGAN-PyTorch and https://github.com/POSTECH-CVLab/PyTorch-StudioGAN. Args: pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=strict, logger=logger) elif isinstance(pretrained, dict): ckpt_path = pretrained.get('ckpt_path', None) assert ckpt_path is not None prefix = pretrained.get('prefix', '') map_location = pretrained.get('map_location', 'cpu') strict = pretrained.get('strict', True) state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) elif pretrained is None: if self.init_type.upper() in 'STUDIO': # initialization method from Pytorch-StudioGAN # * weight: orthogonal_init gain=1 # * bias : 0 for m in self.modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): nn.init.orthogonal_(m.weight) if hasattr(m, 'bias') and m.bias is not None: m.bias.data.fill_(0.) elif self.init_type.upper() == 'BIGGAN': # initialization method from BigGAN-pytorch # * weight: xavier_init gain=1 # * bias : default for n, m in self.named_modules(): if isinstance(m, (nn.Conv2d, nn.Linear, nn.Embedding)): xavier_uniform_(m.weight, gain=1) elif self.init_type.upper() == 'SAGAN': # initialization method from official tensorflow code # * weight : xavier_init gain=1 # * bias : 0 # * weight_embedding: 1 # * bias_embedding : 0 for n, m in self.named_modules(): if isinstance(m, (nn.Conv2d, nn.Linear)): xavier_init(m, gain=1, distribution='uniform') if isinstance(m, nn.Embedding): # To be noted that here we initialize the embedding # layer in cBN with specific prefix. If you implement # your own cBN and want to use this initialization # method, please make sure the embedding layers in # your implementation have the same prefix as ours. if 'weight' in n: constant_init(m, 1) if 'bias' in n: constant_init(m, 0) elif self.init_type.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']: # initialization method from the official chainer code # * conv.weight : xavier_init gain=sqrt(2) # * shortcut.weight : xavier_init gain=1 # * bias : 0 # * weight_embedding: 1 # * bias_embedding : 0 for n, m in self.named_modules(): if isinstance(m, nn.Conv2d): if 'shortcut' in n or 'to_rgb' in n: xavier_init(m, gain=1, distribution='uniform') else: xavier_init( m, gain=np.sqrt(2), distribution='uniform') if isinstance(m, nn.Linear): xavier_init(m, gain=1, distribution='uniform') if isinstance(m, nn.Embedding): # To be noted that here we initialize the embedding # layer in cBN with specific prefix. If you implement # your own cBN and want to use this initialization # method, please make sure the embedding layers in # your implementation have the same prefix as ours. if 'weight' in n: constant_init(m, 1) if 'bias' in n: constant_init(m, 0) else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') else: raise TypeError("'pretrained' must be a str or None. " f'But receive {type(pretrained)}.') ================================================ FILE: mmagic/models/editors/sagan/sagan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch.nn as nn from mmcv.cnn import build_norm_layer from mmengine.dist import is_distributed from mmengine.model import BaseModule, constant_init, xavier_init from torch import Tensor from torch.nn.init import xavier_uniform_ from torch.nn.utils import spectral_norm from mmagic.models.editors.biggan.biggan_modules import SNConvModule from mmagic.models.editors.biggan.biggan_snmodule import SNEmbedding from mmagic.registry import MODELS @MODELS.register_module() class SNGANGenResBlock(BaseModule): """ResBlock used in Generator of SNGAN / Proj-GAN. Args: in_channels (int): Input channels. out_channels (int): Output channels. hidden_channels (int, optional): Input channels of the second Conv layer of the block. If ``None`` is given, would be set as ``out_channels``. Default to None. num_classes (int, optional): Number of classes would like to generate. This argument would pass to norm layers and influence the structure and behavior of the normalization process. Default to 0. use_cbn (bool, optional): Whether use conditional normalization. This argument would pass to norm layers. Default to True. use_norm_affine (bool, optional): Whether use learnable affine parameters in norm operation when cbn is off. Default False. act_cfg (dict, optional): Config for activate function. Default to ``dict(type='ReLU')``. upsample_cfg (dict, optional): Config for the upsample method. Default to ``dict(type='nearest', scale_factor=2)``. upsample (bool, optional): Whether apply upsample operation in this module. Default to True. auto_sync_bn (bool, optional): Whether convert Batch Norm to Synchronized ones when Distributed training is on. Default to True. conv_cfg (dict | None): Config for conv blocks of this module. If pass ``None``, would use ``_default_conv_cfg``. Default to ``None``. with_spectral_norm (bool, optional): Whether use spectral norm for conv blocks and norm layers. Default to True. with_embedding_spectral_norm (bool, optional): Whether use spectral norm for embedding layers in normalization blocks or not. If not specified (set as ``None``), ``with_embedding_spectral_norm`` would be set as the same value as ``with_spectral_norm``. Default to None. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. norm_eps (float, optional): eps for Normalization layers (both conditional and non-conditional ones). Default to `1e-4`. sn_eps (float, optional): eps for spectral normalization operation. Default to `1e-12`. init_cfg (dict, optional): Config for weight initialization. Default to ``dict(type='BigGAN')``. """ _default_conv_cfg = dict(kernel_size=3, stride=1, padding=1, act_cfg=None) def __init__(self, in_channels, out_channels, hidden_channels=None, num_classes=0, use_cbn=True, use_norm_affine=False, act_cfg=dict(type='ReLU'), norm_cfg=dict(type='BN'), upsample_cfg=dict(type='nearest', scale_factor=2), upsample=True, auto_sync_bn=True, conv_cfg=None, with_spectral_norm=False, with_embedding_spectral_norm=None, sn_style='torch', norm_eps=1e-4, sn_eps=1e-12, init_cfg=dict(type='BigGAN')): super().__init__() self.learnable_sc = in_channels != out_channels or upsample self.with_upsample = upsample self.init_type = init_cfg.get('type', None) self.activate = MODELS.build(act_cfg) hidden_channels = out_channels if hidden_channels is None \ else hidden_channels if self.with_upsample: self.upsample = MODELS.build(upsample_cfg) self.conv_cfg = deepcopy(self._default_conv_cfg) if conv_cfg is not None: self.conv_cfg.update(conv_cfg) # set `norm_spectral_norm` as `with_spectral_norm` if not defined with_embedding_spectral_norm = with_embedding_spectral_norm \ if with_embedding_spectral_norm is not None else with_spectral_norm sn_cfg = dict(eps=sn_eps, sn_style=sn_style) self.conv_1 = SNConvModule( in_channels, hidden_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) self.conv_2 = SNConvModule( hidden_channels, out_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) self.norm_1 = SNConditionNorm(in_channels, num_classes, use_cbn, norm_cfg, use_norm_affine, auto_sync_bn, with_embedding_spectral_norm, sn_style, norm_eps, sn_eps, init_cfg) self.norm_2 = SNConditionNorm(hidden_channels, num_classes, use_cbn, norm_cfg, use_norm_affine, auto_sync_bn, with_embedding_spectral_norm, sn_style, norm_eps, sn_eps, init_cfg) if self.learnable_sc: # use hyperparameters-fixed shortcut here self.shortcut = SNConvModule( in_channels, out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg) self.init_weights() def forward(self, x, y=None): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). y (Tensor): Input label with shape (n, ). Default None. Returns: Tensor: Forward results. """ out = self.norm_1(x, y) out = self.activate(out) if self.with_upsample: out = self.upsample(out) out = self.conv_1(out) out = self.norm_2(out, y) out = self.activate(out) out = self.conv_2(out) shortcut = self.forward_shortcut(x) return out + shortcut def forward_shortcut(self, x): """Forward the shortcut branch. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = x if self.learnable_sc: if self.with_upsample: out = self.upsample(out) out = self.shortcut(out) return out def init_weights(self): """Initialize weights for the model.""" if self.init_type.upper() == 'STUDIO': nn.init.orthogonal_(self.conv_1.conv.weight) nn.init.orthogonal_(self.conv_2.conv.weight) self.conv_1.conv.bias.data.fill_(0.) self.conv_2.conv.bias.data.fill_(0.) if self.learnable_sc: nn.init.orthogonal_(self.shortcut.conv.weight) self.shortcut.conv.bias.data.fill_(0.) elif self.init_type.upper() == 'BIGGAN': xavier_uniform_(self.conv_1.conv.weight, gain=1) xavier_uniform_(self.conv_2.conv.weight, gain=1) if self.learnable_sc: xavier_uniform_(self.shortcut.conv.weight, gain=1) elif self.init_type.upper() == 'SAGAN': xavier_init(self.conv_1, gain=1, distribution='uniform') xavier_init(self.conv_2, gain=1, distribution='uniform') if self.learnable_sc: xavier_init(self.shortcut, gain=1, distribution='uniform') elif self.init_type.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']: xavier_init(self.conv_1, gain=np.sqrt(2), distribution='uniform') xavier_init(self.conv_2, gain=np.sqrt(2), distribution='uniform') if self.learnable_sc: xavier_init(self.shortcut, gain=1, distribution='uniform') else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') @MODELS.register_module() class SNGANDiscResBlock(BaseModule): """resblock used in discriminator of sngan / proj-gan. args: in_channels (int): input channels. out_channels (int): output channels. hidden_channels (int, optional): input channels of the second conv layer of the block. if ``none`` is given, would be set as ``out_channels``. Defaults to none. downsample (bool, optional): whether apply downsample operation in this module. Defaults to false. act_cfg (dict, optional): config for activate function. default to ``dict(type='relu')``. conv_cfg (dict | none): config for conv blocks of this module. if pass ``none``, would use ``_default_conv_cfg``. default to ``none``. with_spectral_norm (bool, optional): whether use spectral norm for conv blocks and norm layers. Defaults to true. sn_eps (float, optional): eps for spectral normalization operation. Default to `1e-12`. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. init_cfg (dict, optional): Config for weight initialization. Defaults to ``dict(type='BigGAN')``. """ _default_conv_cfg = dict(kernel_size=3, stride=1, padding=1, act_cfg=None) def __init__(self, in_channels, out_channels, hidden_channels=None, downsample=False, act_cfg=dict(type='ReLU'), conv_cfg=None, with_spectral_norm=True, sn_style='torch', sn_eps=1e-12, init_cfg=dict(type='BigGAN')): super().__init__() hidden_channels = out_channels if hidden_channels is None \ else hidden_channels self.with_downsample = downsample self.init_type = init_cfg.get('type', None) self.conv_cfg = deepcopy(self._default_conv_cfg) if conv_cfg is not None: self.conv_cfg.update(conv_cfg) self.activate = MODELS.build(act_cfg) sn_cfg = dict(eps=sn_eps, sn_style=sn_style) self.conv_1 = SNConvModule( in_channels, hidden_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) self.conv_2 = SNConvModule( hidden_channels, out_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) if self.with_downsample: self.downsample = nn.AvgPool2d(2, 2) self.learnable_sc = in_channels != out_channels or downsample if self.learnable_sc: # use hyperparameters-fixed shortcut here self.shortcut = SNConvModule( in_channels, out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg) self.init_weights() def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = self.activate(x) out = self.conv_1(out) out = self.activate(out) out = self.conv_2(out) if self.with_downsample: out = self.downsample(out) shortcut = self.forward_shortcut(x) return out + shortcut def forward_shortcut(self, x: Tensor) -> Tensor: """Forward the shortcut branch. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = x if self.learnable_sc: out = self.shortcut(out) if self.with_downsample: out = self.downsample(out) return out def init_weights(self): """Initialize weights.""" if self.init_type.upper() == 'STUDIO': nn.init.orthogonal_(self.conv_1.conv.weight) nn.init.orthogonal_(self.conv_2.conv.weight) self.conv_1.conv.bias.data.fill_(0.) self.conv_2.conv.bias.data.fill_(0.) if self.learnable_sc: nn.init.orthogonal_(self.shortcut.conv.weight) self.shortcut.conv.bias.data.fill_(0.) elif self.init_type.upper() == 'BIGGAN': xavier_uniform_(self.conv_1.conv.weight, gain=1) xavier_uniform_(self.conv_2.conv.weight, gain=1) if self.learnable_sc: xavier_uniform_(self.shortcut.conv.weight, gain=1) elif self.init_type.upper() == 'SAGAN': xavier_init(self.conv_1, gain=1, distribution='uniform') xavier_init(self.conv_2, gain=1, distribution='uniform') if self.learnable_sc: xavier_init(self.shortcut, gain=1, distribution='uniform') elif self.init_type.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']: xavier_init(self.conv_1, gain=np.sqrt(2), distribution='uniform') xavier_init(self.conv_2, gain=np.sqrt(2), distribution='uniform') if self.learnable_sc: xavier_init(self.shortcut, gain=1, distribution='uniform') else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') @MODELS.register_module() class SNGANDiscHeadResBlock(BaseModule): """The first ResBlock used in discriminator of sngan / proj-gan. Compared to ``SNGANDisResBlock``, this module has a different forward order. args: in_channels (int): Input channels. out_channels (int): Output channels. downsample (bool, optional): whether apply downsample operation in this module. default to false. conv_cfg (dict | none): config for conv blocks of this module. if pass ``none``, would use ``_default_conv_cfg``. default to ``none``. act_cfg (dict, optional): config for activate function. default to ``dict(type='relu')``. with_spectral_norm (bool, optional): whether use spectral norm for conv blocks and norm layers. default to true. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. sn_eps (float, optional): eps for spectral normalization operation. Default to `1e-12`. init_cfg (dict, optional): Config for weight initialization. Default to ``dict(type='BigGAN')``. """ _default_conv_cfg = dict(kernel_size=3, stride=1, padding=1, act_cfg=None) def __init__(self, in_channels, out_channels, conv_cfg=None, act_cfg=dict(type='ReLU'), with_spectral_norm=True, sn_eps=1e-12, sn_style='torch', init_cfg=dict(type='BigGAN')): super().__init__() self.init_type = init_cfg.get('type', None) self.conv_cfg = deepcopy(self._default_conv_cfg) if conv_cfg is not None: self.conv_cfg.update(conv_cfg) self.activate = MODELS.build(act_cfg) sn_cfg = dict(eps=sn_eps, sn_style=sn_style) self.conv_1 = SNConvModule( in_channels, out_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) self.conv_2 = SNConvModule( out_channels, out_channels, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg, **self.conv_cfg) self.downsample = nn.AvgPool2d(2, 2) # use hyperparameters-fixed shortcut here self.shortcut = SNConvModule( in_channels, out_channels, kernel_size=1, stride=1, padding=0, act_cfg=None, with_spectral_norm=with_spectral_norm, spectral_norm_cfg=sn_cfg) self.init_weights() def forward(self, x: Tensor) -> Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = self.conv_1(x) out = self.activate(out) out = self.conv_2(out) out = self.downsample(out) shortcut = self.forward_shortcut(x) return out + shortcut def forward_shortcut(self, x: Tensor) -> Tensor: """Forward the shortcut branch. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ out = self.downsample(x) out = self.shortcut(out) return out def init_weights(self): """Initialize weights.""" if self.init_type.upper() == 'STUDIO': for m in [self.conv_1, self.conv_2, self.shortcut]: nn.init.orthogonal_(m.conv.weight) m.conv.bias.data.fill_(0.) elif self.init_type.upper() == 'BIGGAN': xavier_uniform_(self.conv_1.conv.weight, gain=1) xavier_uniform_(self.conv_2.conv.weight, gain=1) xavier_uniform_(self.shortcut.conv.weight, gain=1) elif self.init_type.upper() == 'SAGAN': xavier_init(self.conv_1, gain=1, distribution='uniform') xavier_init(self.conv_2, gain=1, distribution='uniform') xavier_init(self.shortcut, gain=1, distribution='uniform') elif self.init_type.upper() in ['SNGAN', 'SNGAN-PROJ', 'GAN-PROJ']: xavier_init(self.conv_1, gain=np.sqrt(2), distribution='uniform') xavier_init(self.conv_2, gain=np.sqrt(2), distribution='uniform') xavier_init(self.shortcut, gain=1, distribution='uniform') else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') @MODELS.register_module() class SNConditionNorm(BaseModule): """Conditional Normalization for SNGAN / Proj-GAN. The implementation refers to. https://github.com/pfnet-research/sngan_projection/blob/master/source/links/conditional_batch_normalization.py # noda and https://github.com/POSTECH-CVLab/PyTorch-StudioGAN/blob/master/src/utils/model_ops.py # noqa Args: in_channels (int): Number of the channels of the input feature map. num_classes (int): Number of the classes in the dataset. If ``use_cbn`` is True, ``num_classes`` must larger than 0. use_cbn (bool, optional): Whether use conditional normalization. If ``use_cbn`` is True, two embedding layers would be used to mapping label to weight and bias used in normalization process. norm_cfg (dict, optional): Config for normalization method. Defaults to ``dict(type='BN')``. cbn_norm_affine (bool): Whether set ``affine=True`` when use conditional batch norm. This argument only work when ``use_cbn`` is True. Defaults to False. auto_sync_bn (bool, optional): Whether convert Batch Norm to Synchronized ones when Distributed training is on. Defaults to True. with_spectral_norm (bool, optional): whether use spectral norm for conv blocks and norm layers. Defaults to true. norm_eps (float, optional): eps for Normalization layers (both conditional and non-conditional ones). Defaults to `1e-4`. sn_style (str, optional): The style of spectral normalization. If set to `ajbrock`, implementation by ajbrock(https://github.com/ajbrock/BigGAN-PyTorch/blob/master/layers.py) will be adopted. If set to `torch`, implementation by `PyTorch` will be adopted. Defaults to `torch`. sn_eps (float, optional): eps for spectral normalization operation. Defaults to `1e-12`. init_cfg (dict, optional): Config for weight initialization. Defaults to ``dict(type='BigGAN')``. """ def __init__(self, in_channels, num_classes, use_cbn=True, norm_cfg=dict(type='BN'), cbn_norm_affine=False, auto_sync_bn=True, with_spectral_norm=False, sn_style='torch', norm_eps=1e-4, sn_eps=1e-12, init_cfg=dict(type='BigGAN')): super().__init__() self.use_cbn = use_cbn self.init_type = init_cfg.get('type', None) norm_cfg = deepcopy(norm_cfg) norm_type = norm_cfg['type'] if norm_type not in ['IN', 'BN', 'SyncBN']: raise ValueError('Only support `IN` (InstanceNorm), ' '`BN` (BatcnNorm) and `SyncBN` for ' 'Class-conditional bn. ' f'Receive norm_type: {norm_type}') if self.use_cbn: norm_cfg.setdefault('affine', cbn_norm_affine) norm_cfg.setdefault('eps', norm_eps) if is_distributed() and auto_sync_bn and norm_type == 'BN': norm_cfg['type'] = 'SyncBN' _, self.norm = build_norm_layer(norm_cfg, in_channels) if self.use_cbn: if num_classes <= 0: raise ValueError('`num_classes` must be larger ' 'than 0 with `use_cbn=True`') self.reweight_embedding = ( self.init_type.upper() == 'BIGGAN' or self.init_type.upper() == 'STUDIO') if with_spectral_norm: if sn_style == 'torch': self.weight_embedding = spectral_norm( nn.Embedding(num_classes, in_channels), eps=sn_eps) self.bias_embedding = spectral_norm( nn.Embedding(num_classes, in_channels), eps=sn_eps) elif sn_style == 'ajbrock': self.weight_embedding = SNEmbedding( num_classes, in_channels, eps=sn_eps) self.bias_embedding = SNEmbedding( num_classes, in_channels, eps=sn_eps) else: raise NotImplementedError( f'{sn_style} style spectral Norm is not ' 'supported yet') else: self.weight_embedding = nn.Embedding(num_classes, in_channels) self.bias_embedding = nn.Embedding(num_classes, in_channels) self.init_weights() def forward(self, x, y=None): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). y (Tensor, optional): Input label with shape (n, ). Default None. Returns: Tensor: Forward results. """ out = self.norm(x) if self.use_cbn: weight = self.weight_embedding(y)[:, :, None, None] bias = self.bias_embedding(y)[:, :, None, None] if self.reweight_embedding: # print('reweight_called --> correct') weight = weight + 1. out = out * weight + bias return out def init_weights(self): """Initialize weights.""" if self.use_cbn: if self.init_type.upper() == 'STUDIO': nn.init.orthogonal_(self.weight_embedding.weight) nn.init.orthogonal_(self.bias_embedding.weight) elif self.init_type.upper() == 'BIGGAN': xavier_uniform_(self.weight_embedding.weight, gain=1) xavier_uniform_(self.bias_embedding.weight, gain=1) elif self.init_type.upper() in [ 'SNGAN', 'SNGAN-PROJ', 'GAN-PROJ', 'SAGAN' ]: constant_init(self.weight_embedding, 1) constant_init(self.bias_embedding, 0) else: raise NotImplementedError('Unknown initialization method: ' f'\'{self.init_type}\'') ================================================ FILE: mmagic/models/editors/singan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .singan import SinGAN from .singan_discriminator import SinGANMultiScaleDiscriminator from .singan_generator import SinGANMultiScaleGenerator __all__ = [ 'SinGAN', 'SinGANMultiScaleDiscriminator', 'SinGANMultiScaleGenerator' ] ================================================ FILE: mmagic/models/editors/singan/singan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pickle from copy import deepcopy from typing import Dict, List, Optional, Tuple, Union import numpy as np import torch import torch.autograd as autograd import torch.nn as nn import torch.nn.functional as F from mmengine import Config, MessageHub, print_log from mmengine.model import is_model_wrapper from mmengine.optim import OptimWrapper, OptimWrapperDict from torch import Tensor from mmagic.models.utils import get_module_device from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import ForwardInputs, SampleList from ...base_models import BaseGAN from ...utils import set_requires_grad ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module() class SinGAN(BaseGAN): """SinGAN. This model implement the single image generative adversarial model proposed in: Singan: Learning a Generative Model from a Single Natural Image, ICCV'19. Notes for training: - This model should be trained with our dataset ``SinGANDataset``. - In training, the ``total_iters`` arguments is related to the number of scales in the image pyramid and ``iters_per_scale`` in the ``train_cfg``. You should set it carefully in the training config file. Notes for model architectures: - The generator and discriminator need ``num_scales`` in initialization. However, this arguments is generated by ``create_real_pyramid`` function from the ``singan_dataset.py``. The last element in the returned list (``stop_scale``) is the value for ``num_scales``. Pay attention that this scale is counted from zero. Please see our tutorial for SinGAN to obtain more details or our standard config for reference. Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): The number of times the generator is completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): The number of times the discriminator is completely updated before the generator is updated. Defaults to 1. num_scales (int): The number of scales/stages in generator/ discriminator. Note that this number is counted from zero, which is the same as the original paper. Defaults to None. iters_per_scale (int): The training iteration for each resolution scale. Defaults to 2000. noise_weight_init (float): The initialize weight of fixed noise. Defaults to 0.1 lr_scheduler_args (Optional[dict]): Arguments for learning schedulers. Note that in SinGAN, we use MultiStepLR, which is the same as the original paper. If not passed, no learning schedule will be used. Defaults to None. test_pkl_data (Optional[str]): The path of pickle file which contains fixed noise and noise weight. This is must for test. Defaults to None. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, num_scales: Optional[int] = None, iters_per_scale: int = 2000, noise_weight_init: int = 0.1, lr_scheduler_args: Optional[dict] = None, test_pkl_data: Optional[str] = None, ema_confg: Optional[dict] = None): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, None, ema_confg) self.iters_per_scale = iters_per_scale self.noise_weight_init = noise_weight_init if lr_scheduler_args: self.lr_scheduler_args = deepcopy(lr_scheduler_args) else: self.lr_scheduler_args = None # related to train self.num_scales = num_scales self.curr_stage = -1 self.noise_weights = [1] self.fixed_noises = [] self.reals = [] # related to test self.loaded_test_pkl = False self.pkl_data = test_pkl_data def load_test_pkl(self): """Load pickle for test.""" if self.pkl_data is not None: with open(self.pkl_data, 'rb') as f: data = pickle.load(f) self.fixed_noises = self._from_numpy(data['fixed_noises']) self.noise_weights = self._from_numpy(data['noise_weights']) self.curr_stage = data['curr_stage'] print_log(f'Load pkl data from {self.pkl_data}', 'current') self.pkl_data = self.pkl_data self.loaded_test_pkl = True def _from_numpy(self, data: Tuple[list, np.ndarray]) -> Tuple[Tensor, List[Tensor]]: """Convert input numpy array or list of numpy array to Tensor or list of Tensor. Args: data (Tuple[list, np.ndarray]): Input data to convert. Returns: Tuple[Tensor, List[Tensor]]: Converted Tensor or list of tensor. """ if isinstance(data, list): return [self._from_numpy(x) for x in data] if isinstance(data, np.ndarray): data = torch.from_numpy(data) device = get_module_device(self.generator) data = data.to(device) return data return data def get_module(self, model: nn.Module, module_name: str) -> nn.Module: """Get an inner module from model. Since we will wrapper DDP for some model, we have to judge whether the module can be indexed directly. Args: model (nn.Module): This model may wrapped with DDP or not. module_name (str): The name of specific module. Return: nn.Module: Returned sub module. """ module = model.module if hasattr(model, 'module') else model return getattr(module, module_name) def construct_fixed_noises(self): """Construct the fixed noises list used in SinGAN.""" for i, real in enumerate(self.reals): h, w = real.shape[-2:] if i == 0: noise = torch.randn(1, 1, h, w).to(real) self.fixed_noises.append(noise) else: noise = torch.zeros_like(real) self.fixed_noises.append(noise) def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode=None) -> List[DataSample]: """Forward function for SinGAN. For SinGAN, `inputs` should be a dict contains 'num_batches', 'mode' and other input arguments for the generator. Args: inputs (dict): Dict containing the necessary information (e.g., noise, num_batches, mode) to generate image. data_samples (Optional[list]): Data samples collated by :attr:`data_preprocessor`. Defaults to None. mode (Optional[str]): `mode` is not used in :class:`BaseConditionalGAN`. Defaults to None. """ # handle batch_inputs assert isinstance(inputs, dict), ( 'SinGAN only support dict type inputs in forward function.') gen_kwargs = deepcopy(inputs) num_batches = gen_kwargs.pop('num_batches', 1) assert num_batches == 1, ( 'SinGAN only support \'num_batches\' as 1, but receive ' f'{num_batches}.') sample_model = self._get_valid_model(inputs) gen_kwargs.pop('sample_model', None) # remove sample_model mode = gen_kwargs.pop('mode', mode) mode = 'rand' if mode is None else mode curr_scale = gen_kwargs.pop('curr_scale', self.curr_stage) self.fixed_noises = [ x.to(self.data_preprocessor.device) for x in self.fixed_noises ] batch_sample_list = [] if sample_model in ['ema', 'orig']: if sample_model == 'ema': generator = self.generator_ema else: generator = self.generator outputs = generator( None, fixed_noises=self.fixed_noises, noise_weights=self.noise_weights, rand_mode=mode, num_batches=1, curr_scale=curr_scale, **gen_kwargs) gen_sample = DataSample() # destruct if isinstance(outputs, dict): outputs['fake_img'] = self.data_preprocessor.destruct( outputs['fake_img'], data_samples) outputs['prev_res_list'] = [ self.data_preprocessor.destruct(r, data_samples) for r in outputs['prev_res_list'] ] gen_sample.fake_img = self.data_preprocessor.destruct( outputs['fake_img'], data_samples) # gen_sample.prev_res_list = self.data_preprocessor.destruct( # outputs['fake_img'], data_samples) else: outputs = self.data_preprocessor.destruct( outputs, data_samples) # save to data sample for idx in range(num_batches): gen_sample = DataSample() # save inputs to data sample if data_samples: gen_sample.update(data_samples[idx]) if isinstance(outputs, dict): gen_sample.fake_img = outputs['fake_img'][idx] gen_sample.prev_res_list = [ r[idx] for r in outputs['prev_res_list'] ] else: gen_sample.fake_img = outputs[idx] gen_sample.sample_model = sample_model batch_sample_list.append(gen_sample) else: # sample model is 'ema/orig' outputs_orig = self.generator( None, fixed_noises=self.fixed_noises, noise_weights=self.noise_weights, rand_mode=mode, num_batches=1, curr_scale=curr_scale, **gen_kwargs) outputs_ema = self.generator_ema( None, fixed_noises=self.fixed_noises, noise_weights=self.noise_weights, rand_mode=mode, num_batches=1, curr_scale=curr_scale, **gen_kwargs) # destruct if isinstance(outputs_orig, dict): outputs_orig['fake_img'] = self.data_preprocessor.destruct( outputs_orig['fake_img'], data_samples) outputs_orig['prev_res_list'] = [ self.data_preprocessor.destruct(r, data_samples) for r in outputs_orig['prev_res_list'] ] outputs_ema['fake_img'] = self.data_preprocessor.destruct( outputs_ema['fake_img'], data_samples) outputs_ema['prev_res_list'] = [ self.data_preprocessor.destruct(r, data_samples) for r in outputs_ema['prev_res_list'] ] else: outputs_orig = self.data_preprocessor.destruct( outputs_orig, data_samples) outputs_ema = self.data_preprocessor.destruct( outputs_ema, data_samples) # save to data sample for idx in range(num_batches): gen_sample = DataSample() gen_sample.ema = DataSample() gen_sample.orig = DataSample() # save inputs to data sample if data_samples: gen_sample.update(data_samples[idx]) if isinstance(outputs_orig, dict): gen_sample.ema.fake_img = outputs_ema['fake_img'][idx] gen_sample.ema.prev_res_list = [ r[idx] for r in outputs_ema['prev_res_list'] ] gen_sample.orig.fake_img = outputs_orig['fake_img'][idx] gen_sample.orig.prev_res_list = [ r[idx] for r in outputs_orig['prev_res_list'] ] else: gen_sample.ema.fake_img = outputs_ema[idx] gen_sample.orig.fake_img = outputs_orig[idx] gen_sample.sample_model = sample_model batch_sample_list.append(gen_sample) return batch_sample_list def gen_loss(self, disc_pred_fake: Tensor, recon_imgs: Tensor) -> Tuple[Tensor, dict]: r"""Generator loss for SinGAN. SinGAN use WGAN's loss and MSE loss to train the generator. .. math: L_{D} = -\mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) + L_{MSE} L_{MSE} = \text{mean} \Vert x - G(z) \Vert_2 Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. recon_imgs (Tensor): Reconstructive images. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() losses_dict['loss_mse'] = 10 * F.mse_loss(recon_imgs, self.reals[self.curr_stage]) loss, log_vars = self.parse_losses(losses_dict) return loss, log_vars def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor, fake_data: Tensor, real_data: Tensor) -> Tuple[Tensor, dict]: r"""Get disc loss. SAGAN, SNGAN and Proj-GAN use hinge loss to train the generator. .. math: L_{D} = \mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) - \mathbb{E}_{x\sim{p_{data}}}D\left\(x\right\) + L_{GP} \\ L_{GP} = \lambda\mathbb{E}(\Vert\nabla_{\tilde{x}}D(\tilde{x}) \Vert_2-1)^2 \\ \tilde{x} = \epsilon x + (1-\epsilon)G(z) Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. fake_data (Tensor): Generated images, used to calculate gradient penalty. real_data (Tensor): Real images, used to calculate gradient penalty. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = disc_pred_fake.mean() losses_dict['loss_disc_real'] = -disc_pred_real.mean() # gradient penalty batch_size = real_data.size(0) alpha = torch.rand(batch_size, 1, 1, 1).to(real_data) # interpolate between real_data and fake_data interpolates = alpha * real_data + (1. - alpha) * fake_data interpolates = autograd.Variable(interpolates, requires_grad=True) disc_interpolates = self.discriminator( interpolates, curr_scale=self.curr_stage) gradients = autograd.grad( outputs=disc_interpolates, inputs=interpolates, grad_outputs=torch.ones_like(disc_interpolates), create_graph=True, retain_graph=True, only_inputs=True)[0] # norm_mode is 'pixel' gradients_penalty = ((gradients.norm(2, dim=1) - 1)**2).mean() losses_dict['loss_gp'] = 0.1 * gradients_penalty parsed_loss, log_vars = self.parse_losses(losses_dict) return parsed_loss, log_vars def train_generator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ fake_imgs = self.generator( inputs['input_sample'], self.fixed_noises, self.noise_weights, rand_mode='rand', curr_scale=self.curr_stage) disc_pred_fake_g = self.discriminator( fake_imgs, curr_scale=self.curr_stage) recon_imgs = self.generator( inputs['input_sample'], self.fixed_noises, self.noise_weights, rand_mode='recon', curr_scale=self.curr_stage) parsed_loss, log_vars = self.gen_loss(disc_pred_fake_g, recon_imgs) optimizer_wrapper.update_params(parsed_loss) return log_vars def train_discriminator(self, inputs: dict, data_samples: List[DataSample], optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (List[DataSample]): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ input_sample = inputs['input_sample'] fake_imgs = self.generator( input_sample, self.fixed_noises, self.noise_weights, rand_mode='rand', curr_scale=self.curr_stage) # disc pred for fake imgs and real_imgs real_imgs = self.reals[self.curr_stage] disc_pred_fake = self.discriminator(fake_imgs.detach(), self.curr_stage) disc_pred_real = self.discriminator(real_imgs, self.curr_stage) parsed_loss, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real, fake_imgs, real_imgs) optimizer_wrapper.update_params(parsed_loss) return log_vars def train_gan(self, inputs_dict: dict, data_sample: List[DataSample], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train GAN model. In the training of GAN models, generator and discriminator are updated alternatively. In MMagic's design, `self.train_step` is called with data input. Therefore we always update discriminator, whose updating is relay on real data, and then determine if the generator needs to be updated based on the current number of iterations. More details about whether to update generator can be found in :meth:`should_gen_update`. Args: data (dict): Data sampled from dataloader. data_sample (List[DataSample]): List of data sample contains GT and meta information. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts with disc_optimizer_wrapper.optim_context(self.discriminator): log_vars = self.train_discriminator(inputs_dict, data_sample, disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) for _ in range(self.generator_steps * gen_accu_iters): with gen_optimizer_wrapper.optim_context(self.generator): log_vars_gen = self.train_generator( inputs_dict, data_sample, gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = self.gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) # if not update buffer, copy buffer from orig model if not self.generator_ema.update_buffers: self.generator_ema.sync_buffers( self.generator.module if is_model_wrapper( self.generator) else self.generator) elif self.with_ema_gen: # before ema, copy weights from orig self.generator_ema.sync_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) return log_vars def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: """Train step for SinGAN model. SinGAN is trained with multi-resolution images, and each resolution is trained for `:attr:self.iters_per_scale` times. We initialize the weight and learning rate scheduler of the corresponding module at the start of each resolution's training. At the end of each resolution's training, we update the weight of the noise of current resolution by mse loss between reconstructed image and real image. Args: data (dict): Data sampled from dataloader. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') if curr_iter % (self.iters_per_scale * self.discriminator_steps) == 0: self.curr_stage += 1 # load weights from prev scale self.get_module(self.generator, 'check_and_load_prev_weight')( self.curr_stage) self.get_module(self.discriminator, 'check_and_load_prev_weight')( self.curr_stage) # assert grad_accumulation step is 1 curr_gen_optim = optim_wrapper[f'generator_{self.curr_stage}'] curr_disc_optim = optim_wrapper[f'discriminator_{self.curr_stage}'] _warning_msg = ('SinGAN do set batch size as 1 during training ' 'and do not support gradient accumulation.') assert curr_gen_optim._accumulative_counts == 1, _warning_msg assert curr_disc_optim._accumulative_counts == 1, _warning_msg # build parameters scheduler manually, because parameters_schedule # hook update all scheduler at the same if self.lr_scheduler_args: self.gen_scheduler = torch.optim.lr_scheduler.MultiStepLR( curr_gen_optim.optimizer, **self.lr_scheduler_args) self.disc_scheduler = torch.optim.lr_scheduler.MultiStepLR( curr_disc_optim.optimizer, **self.lr_scheduler_args) # get current optimizer_wrapper curr_optimizer_wrapper = OptimWrapperDict( generator=optim_wrapper[f'generator_{self.curr_stage}'], discriminator=optim_wrapper[f'discriminator_{self.curr_stage}']) # handle inputs data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] # setup fixed noises and reals pyramid if curr_iter == 0 or len(self.reals) == 0: keys = [k for k in inputs_dict.keys() if 'real_scale' in k] scales = len(keys) self.reals = [inputs_dict[f'real_scale{s}'] for s in range(scales)] # here we do not padding fixed noises self.construct_fixed_noises() # standard train step log_vars = self.train_gan(inputs_dict, data_samples, curr_optimizer_wrapper) log_vars['curr_stage'] = self.curr_stage # update noise weight if ((curr_iter + 1) % (self.iters_per_scale * self.discriminator_steps) == 0) and (self.curr_stage < len(self.reals) - 1): with torch.no_grad(): g_recon = self.generator( inputs_dict['input_sample'], self.fixed_noises, self.noise_weights, rand_mode='recon', curr_scale=self.curr_stage) if isinstance(g_recon, dict): g_recon = g_recon['fake_img'] g_recon = F.interpolate( g_recon, self.reals[self.curr_stage + 1].shape[-2:]) mse = F.mse_loss(g_recon.detach(), self.reals[self.curr_stage + 1]) rmse = torch.sqrt(mse) self.noise_weights.append(self.noise_weight_init * rmse.item()) # call scheduler when all submodules are fully updated. if (curr_iter + 1) % self.discriminator_steps == 0: if self.lr_scheduler_args: self.disc_scheduler.step() self.gen_scheduler.step() return log_vars def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data in test progress. Before generate images, we call `:meth:self.load_test_pkl` to load the fixed noise and current stage of the model from the pickle file. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ if not self.loaded_test_pkl: self.load_test_pkl() return super().test_step(data) ================================================ FILE: mmagic/models/editors/singan/singan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch.nn as nn from mmengine import print_log from mmengine.model import BaseModule from mmagic.registry import MODELS from .singan_modules import DiscriminatorBlock @MODELS.register_module() class SinGANMultiScaleDiscriminator(BaseModule): """Multi-Scale Discriminator used in SinGAN. More details can be found in: Singan: Learning a Generative Model from a Single Natural Image, ICCV'19. Args: in_channels (int): Input channels. num_scales (int): The number of scales/stages in generator. Note that this number is counted from zero, which is the same as the original paper. kernel_size (int, optional): Kernel size, same as :obj:`nn.Conv2d`. Defaults to 3. padding (int, optional): Padding for the convolutional layer, same as :obj:`nn.Conv2d`. Defaults to 0. num_layers (int, optional): The number of convolutional layers in each generator block. Defaults to 5. base_channels (int, optional): The basic channels for convolutional layers in the generator block. Defaults to 32. min_feat_channels (int, optional): Minimum channels for the feature maps in the generator block. Defaults to 32. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, in_channels, num_scales, kernel_size=3, padding=0, num_layers=5, base_channels=32, min_feat_channels=32, init_cfg=None, **kwargs): super().__init__(init_cfg=init_cfg) self.blocks = nn.ModuleList() for scale in range(num_scales + 1): base_ch = min(base_channels * pow(2, int(np.floor(scale / 4))), 128) min_feat_ch = min( min_feat_channels * pow(2, int(np.floor(scale / 4))), 128) self.blocks.append( DiscriminatorBlock( in_channels=in_channels, kernel_size=kernel_size, padding=padding, num_layers=num_layers, base_channels=base_ch, min_feat_channels=min_feat_ch, **kwargs)) def forward(self, x, curr_scale): """Forward function. Args: x (Tensor): Input feature map. curr_scale (int): Current scale for discriminator. If in testing, you need to set it to the last scale. Returns: Tensor: Discriminative results. """ out = self.blocks[curr_scale](x) return out def check_and_load_prev_weight(self, curr_scale): if curr_scale == 0: return prev_ch = self.blocks[curr_scale - 1].base_channels curr_ch = self.blocks[curr_scale].base_channels if prev_ch == curr_ch: self.blocks[curr_scale].load_state_dict( self.blocks[curr_scale - 1].state_dict()) print_log('Successfully load pretrained model from last scale.') else: print_log('Cannot load pretrained model from last scale since' f' prev_ch({prev_ch}) != curr_ch({curr_ch})') ================================================ FILE: mmagic/models/editors/singan/singan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine.logging import MMLogger from mmengine.model import BaseModule from mmengine.runner import load_state_dict from mmagic.registry import MODELS from .singan_modules import GeneratorBlock @MODELS.register_module() class SinGANMultiScaleGenerator(BaseModule): """Multi-Scale Generator used in SinGAN. More details can be found in: Singan: Learning a Generative Model from a Single Natural Image, ICCV'19. Notes: - In this version, we adopt the interpolation function from the official PyTorch APIs, which is different from the original implementation by the authors. However, in our experiments, this influence can be ignored. Args: in_channels (int): Input channels. out_channels (int): Output channels. num_scales (int): The number of scales/stages in generator. Note that this number is counted from zero, which is the same as the original paper. kernel_size (int, optional): Kernel size, same as :obj:`nn.Conv2d`. Defaults to 3. padding (int, optional): Padding for the convolutional layer, same as :obj:`nn.Conv2d`. Defaults to 0. num_layers (int, optional): The number of convolutional layers in each generator block. Defaults to 5. base_channels (int, optional): The basic channels for convolutional layers in the generator block. Defaults to 32. min_feat_channels (int, optional): Minimum channels for the feature maps in the generator block. Defaults to 32. out_act_cfg (dict | None, optional): Configs for output activation layer. Defaults to dict(type='Tanh'). init_cfg (dict, optional): Initialization config dict. """ def __init__(self, in_channels, out_channels, num_scales, kernel_size=3, padding=0, num_layers=5, base_channels=32, min_feat_channels=32, out_act_cfg=dict(type='Tanh'), init_cfg=None, **kwargs): super().__init__(init_cfg=init_cfg) self.pad_head = int((kernel_size - 1) / 2 * num_layers) self.blocks = nn.ModuleList() self.upsample = partial( F.interpolate, mode='bicubic', align_corners=True) for scale in range(num_scales + 1): base_ch = min(base_channels * pow(2, int(np.floor(scale / 4))), 128) min_feat_ch = min( min_feat_channels * pow(2, int(np.floor(scale / 4))), 128) self.blocks.append( GeneratorBlock( in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, padding=padding, num_layers=num_layers, base_channels=base_ch, min_feat_channels=min_feat_ch, out_act_cfg=out_act_cfg, **kwargs)) self.noise_padding_layer = nn.ZeroPad2d(self.pad_head) self.img_padding_layer = nn.ZeroPad2d(self.pad_head) def forward(self, input_sample, fixed_noises, noise_weights, rand_mode, curr_scale, num_batches=1, get_prev_res=False, return_noise=False): """Forward function. Args: input_sample (Tensor | None): The input for generator. In the original implementation, a tensor filled with zeros is adopted. If None is given, we will construct it from the first fixed noises. fixed_noises (list[Tensor]): List of the fixed noises in SinGAN. noise_weights (list[float]): List of the weights for random noises. rand_mode (str): Choices from ['rand', 'recon']. In ``rand`` mode, it will sample from random noises. Otherwise, the reconstruction for the single image will be returned. curr_scale (int): The scale for the current inference or training. num_batches (int, optional): The number of batches. Defaults to 1. get_prev_res (bool, optional): Whether to return results from previous stages. Defaults to False. return_noise (bool, optional): Whether to return noises tensor. Defaults to False. Returns: Tensor | dict: Generated image tensor or dictionary containing \ more data. """ if get_prev_res or return_noise: prev_res_list = [] noise_list = [] if input_sample is None: input_sample = torch.zeros( (num_batches, 3, fixed_noises[0].shape[-2], fixed_noises[0].shape[-1])).to(fixed_noises[0]) g_res = input_sample for stage in range(curr_scale + 1): if rand_mode == 'recon': noise_ = fixed_noises[stage] else: noise_ = torch.randn(num_batches, *fixed_noises[stage].shape[1:]).to(g_res) if return_noise: noise_list.append(noise_) # add padding at head pad_ = (self.pad_head, ) * 4 noise_ = F.pad(noise_, pad_) g_res_pad = F.pad(g_res, pad_) noise = noise_ * noise_weights[stage] + g_res_pad g_res = self.blocks[stage](noise.detach(), g_res) if get_prev_res and stage != curr_scale: prev_res_list.append(g_res) # upsample, here we use interpolation from PyTorch if stage != curr_scale: h_next, w_next = fixed_noises[stage + 1].shape[-2:] g_res = self.upsample(g_res, (h_next, w_next)) if get_prev_res or return_noise: output_dict = dict( fake_img=g_res, prev_res_list=prev_res_list, # noise_batch=noise_list ) return output_dict return g_res def check_and_load_prev_weight(self, curr_scale): logger = MMLogger.get_current_instance() if curr_scale == 0: return prev_ch = self.blocks[curr_scale - 1].base_channels curr_ch = self.blocks[curr_scale].base_channels prev_in_ch = self.blocks[curr_scale - 1].in_channels curr_in_ch = self.blocks[curr_scale].in_channels if prev_ch == curr_ch and prev_in_ch == curr_in_ch: load_state_dict( self.blocks[curr_scale], self.blocks[curr_scale - 1].state_dict(), logger=MMLogger.get_current_instance()) logger.info('Successfully load pretrained model from last scale.') else: logger.info( 'Cannot load pretrained model from last scale since' f' prev_ch({prev_ch}) != curr_ch({curr_ch})' f' or prev_in_ch({prev_in_ch}) != curr_in_ch({curr_in_ch})') ================================================ FILE: mmagic/models/editors/singan/singan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.logging import MMLogger from mmengine.model import constant_init, normal_init from mmengine.runner import load_checkpoint from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm class GeneratorBlock(nn.Module): """Generator block used in SinGAN. Args: in_channels (int): Input channels. out_channels (int): Output channels. num_scales (int): The number of scales/stages in generator. Note that this number is counted from zero, which is the same as the original paper. kernel_size (int, optional): Kernel size, same as :obj:`nn.Conv2d`. Defaults to 3. padding (int, optional): Padding for the convolutional layer, same as :obj:`nn.Conv2d`. Defaults to 0. num_layers (int, optional): The number of convolutional layers in each generator block. Defaults to 5. base_channels (int, optional): The basic channels for convolutional layers in the generator block. Defaults to 32. min_feat_channels (int, optional): Minimum channels for the feature maps in the generator block. Defaults to 32. out_act_cfg (dict | None, optional): Configs for output activation layer. Defaults to dict(type='Tanh'). stride (int, optional): Same as :obj:`nn.Conv2d`. Defaults to 1. allow_no_residual (bool, optional): Whether to allow no residual link in this block. Defaults to False. """ def __init__(self, in_channels, out_channels, kernel_size, padding, num_layers, base_channels, min_feat_channels, out_act_cfg=dict(type='Tanh'), stride=1, allow_no_residual=False, **kwargs): super().__init__() self.in_channels = in_channels self.base_channels = base_channels self.kernel_size = kernel_size self.num_layers = num_layers self.allow_no_residual = allow_no_residual self.head = ConvModule( in_channels=in_channels, out_channels=base_channels, kernel_size=kernel_size, padding=padding, stride=1, norm_cfg=dict(type='BN'), act_cfg=dict(type='LeakyReLU', negative_slope=0.2), **kwargs) self.body = nn.Sequential() for i in range(num_layers - 2): feat_channels_ = int(base_channels / pow(2, (i + 1))) block = ConvModule( max(2 * feat_channels_, min_feat_channels), max(feat_channels_, min_feat_channels), kernel_size=kernel_size, padding=padding, stride=stride, norm_cfg=dict(type='BN'), act_cfg=dict(type='LeakyReLU', negative_slope=0.2), **kwargs) self.body.add_module(f'block{i+1}', block) self.tail = ConvModule( max(feat_channels_, min_feat_channels), out_channels, kernel_size=kernel_size, padding=padding, stride=1, norm_cfg=None, act_cfg=out_act_cfg, **kwargs) self.init_weights() def forward(self, x, prev): """Forward function. Args: x (Tensor): Input feature map. prev (Tensor): Previous feature map. Returns: Tensor: Output feature map with the shape of (N, C, H, W). """ x = self.head(x) x = self.body(x) x = self.tail(x) # if prev and x are not in the same shape at the channel dimension if self.allow_no_residual and x.shape[1] != prev.shape[1]: return x return x + prev def init_weights(self, pretrained=None): if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, nn.Conv2d): normal_init(m, 0, 0.02) elif isinstance(m, (_BatchNorm, nn.InstanceNorm2d)): constant_init(m, 1) else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') class DiscriminatorBlock(nn.Module): """Discriminator Block used in SinGAN. Args: in_channels (int): Input channels. base_channels (int): Base channels for this block. min_feat_channels (int): The minimum channels for feature map. kernel_size (int): Size of convolutional kernel, same as :obj:`nn.Conv2d`. padding (int): Padding for convolutional layer, same as :obj:`nn.Conv2d`. num_layers (int): The number of convolutional layers in this block. norm_cfg (dict | None, optional): Config for the normalization layer. Defaults to dict(type='BN'). act_cfg (dict | None, optional): Config for the activation layer. Defaults to dict(type='LeakyReLU', negative_slope=0.2). stride (int, optional): The stride for the convolutional layer, same as :obj:`nn.Conv2d`. Defaults to 1. """ def __init__(self, in_channels, base_channels, min_feat_channels, kernel_size, padding, num_layers, norm_cfg=dict(type='BN'), act_cfg=dict(type='LeakyReLU', negative_slope=0.2), stride=1, **kwargs): super().__init__() self.base_channels = base_channels self.stride = stride self.head = ConvModule( in_channels, base_channels, kernel_size=kernel_size, padding=padding, stride=1, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs) self.body = nn.Sequential() for i in range(num_layers - 2): feat_channels_ = int(base_channels / pow(2, (i + 1))) block = ConvModule( max(2 * feat_channels_, min_feat_channels), max(feat_channels_, min_feat_channels), kernel_size=kernel_size, padding=padding, stride=stride, conv_cfg=None, norm_cfg=norm_cfg, act_cfg=act_cfg, **kwargs) self.body.add_module(f'block{i+1}', block) self.tail = ConvModule( max(feat_channels_, min_feat_channels), 1, kernel_size=kernel_size, padding=padding, stride=1, norm_cfg=None, act_cfg=None, **kwargs) self.init_weights() def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map. """ x = self.head(x) x = self.body(x) x = self.tail(x) return x # TODO: study the effects of init functions def init_weights(self, pretrained=None): if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=False, logger=logger) elif pretrained is None: for m in self.modules(): if isinstance(m, nn.Conv2d): normal_init(m, 0, 0.02) elif isinstance(m, (_BatchNorm, nn.InstanceNorm2d)): constant_init(m, 1) else: raise TypeError('pretrained must be a str or None but' f' got {type(pretrained)} instead.') ================================================ FILE: mmagic/models/editors/srcnn/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .srcnn_net import SRCNNNet __all__ = ['SRCNNNet'] ================================================ FILE: mmagic/models/editors/srcnn/srcnn_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class SRCNNNet(BaseModule): """SRCNN network structure for image super resolution. SRCNN has three conv layers. For each layer, we can define the `in_channels`, `out_channels` and `kernel_size`. The input image will first be upsampled with a bicubic upsampler, and then super-resolved in the HR spatial size. Paper: Learning a Deep Convolutional Network for Image Super-Resolution. Args: channels (tuple[int]): A tuple of channel numbers for each layer including channels of input and output . Default: (3, 64, 32, 3). kernel_sizes (tuple[int]): A tuple of kernel sizes for each conv layer. Default: (9, 1, 5). upscale_factor (int): Upsampling factor. Default: 4. """ def __init__(self, channels=(3, 64, 32, 3), kernel_sizes=(9, 1, 5), upscale_factor=4): super().__init__() assert len(channels) == 4, ('The length of channel tuple should be 4, ' f'but got {len(channels)}') assert len(kernel_sizes) == 3, ( 'The length of kernel tuple should be 3, ' f'but got {len(kernel_sizes)}') self.upscale_factor = upscale_factor self.img_upsampler = nn.Upsample( scale_factor=self.upscale_factor, mode='bicubic', align_corners=False) self.conv1 = nn.Conv2d( channels[0], channels[1], kernel_size=kernel_sizes[0], padding=kernel_sizes[0] // 2) self.conv2 = nn.Conv2d( channels[1], channels[2], kernel_size=kernel_sizes[1], padding=kernel_sizes[1] // 2) self.conv3 = nn.Conv2d( channels[2], channels[3], kernel_size=kernel_sizes[2], padding=kernel_sizes[2] // 2) self.relu = nn.ReLU() def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.img_upsampler(x) out = self.relu(self.conv1(x)) out = self.relu(self.conv2(out)) out = self.conv3(out) return out ================================================ FILE: mmagic/models/editors/srgan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .modified_vgg import ModifiedVGG from .sr_resnet import MSRResNet from .srgan import SRGAN __all__ = [ 'ModifiedVGG', 'MSRResNet', 'SRGAN', ] ================================================ FILE: mmagic/models/editors/srgan/modified_vgg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class ModifiedVGG(BaseModule): """A modified VGG discriminator with input size 128 x 128. It is used to train SRGAN and ESRGAN. Args: in_channels (int): Channel number of inputs. Default: 3. mid_channels (int): Channel number of base intermediate features. Default: 64. """ def __init__(self, in_channels, mid_channels): super().__init__() self.conv0_0 = nn.Conv2d(in_channels, mid_channels, 3, 1, 1, bias=True) self.conv0_1 = nn.Conv2d( mid_channels, mid_channels, 4, 2, 1, bias=False) self.bn0_1 = nn.BatchNorm2d(mid_channels, affine=True) self.conv1_0 = nn.Conv2d( mid_channels, mid_channels * 2, 3, 1, 1, bias=False) self.bn1_0 = nn.BatchNorm2d(mid_channels * 2, affine=True) self.conv1_1 = nn.Conv2d( mid_channels * 2, mid_channels * 2, 4, 2, 1, bias=False) self.bn1_1 = nn.BatchNorm2d(mid_channels * 2, affine=True) self.conv2_0 = nn.Conv2d( mid_channels * 2, mid_channels * 4, 3, 1, 1, bias=False) self.bn2_0 = nn.BatchNorm2d(mid_channels * 4, affine=True) self.conv2_1 = nn.Conv2d( mid_channels * 4, mid_channels * 4, 4, 2, 1, bias=False) self.bn2_1 = nn.BatchNorm2d(mid_channels * 4, affine=True) self.conv3_0 = nn.Conv2d( mid_channels * 4, mid_channels * 8, 3, 1, 1, bias=False) self.bn3_0 = nn.BatchNorm2d(mid_channels * 8, affine=True) self.conv3_1 = nn.Conv2d( mid_channels * 8, mid_channels * 8, 4, 2, 1, bias=False) self.bn3_1 = nn.BatchNorm2d(mid_channels * 8, affine=True) self.conv4_0 = nn.Conv2d( mid_channels * 8, mid_channels * 8, 3, 1, 1, bias=False) self.bn4_0 = nn.BatchNorm2d(mid_channels * 8, affine=True) self.conv4_1 = nn.Conv2d( mid_channels * 8, mid_channels * 8, 4, 2, 1, bias=False) self.bn4_1 = nn.BatchNorm2d(mid_channels * 8, affine=True) self.linear1 = nn.Linear(mid_channels * 8 * 4 * 4, 100) self.linear2 = nn.Linear(100, 1) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ assert x.size(2) == 128 and x.size(3) == 128, ( f'Input spatial size must be 128x128, ' f'but received {x.size()}.') feat = self.lrelu(self.conv0_0(x)) feat = self.lrelu(self.bn0_1( self.conv0_1(feat))) # output spatial size: (64, 64) feat = self.lrelu(self.bn1_0(self.conv1_0(feat))) feat = self.lrelu(self.bn1_1( self.conv1_1(feat))) # output spatial size: (32, 32) feat = self.lrelu(self.bn2_0(self.conv2_0(feat))) feat = self.lrelu(self.bn2_1( self.conv2_1(feat))) # output spatial size: (16, 16) feat = self.lrelu(self.bn3_0(self.conv3_0(feat))) feat = self.lrelu(self.bn3_1( self.conv3_1(feat))) # output spatial size: (8, 8) feat = self.lrelu(self.bn4_0(self.conv4_0(feat))) feat = self.lrelu(self.bn4_1( self.conv4_1(feat))) # output spatial size: (4, 4) feat = feat.view(feat.size(0), -1) feat = self.lrelu(self.linear1(feat)) out = self.linear2(feat) return out ================================================ FILE: mmagic/models/editors/srgan/sr_resnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import default_init_weights, make_layer from mmagic.registry import MODELS @MODELS.register_module() class MSRResNet(BaseModule): """Modified SRResNet. A compacted version modified from SRResNet in "Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network". It uses residual blocks without BN, similar to EDSR. Currently, it supports x2, x3 and x4 upsampling scale factor. Args: in_channels (int): Channel number of inputs. out_channels (int): Channel number of outputs. mid_channels (int): Channel number of intermediate features. Default: 64. num_blocks (int): Block number in the trunk network. Default: 16. upscale_factor (int): Upsampling factor. Support x2, x3 and x4. Default: 4. """ _supported_upscale_factors = [2, 3, 4] def __init__(self, in_channels, out_channels, mid_channels=64, num_blocks=16, upscale_factor=4): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.mid_channels = mid_channels self.num_blocks = num_blocks self.upscale_factor = upscale_factor self.conv_first = nn.Conv2d( in_channels, mid_channels, 3, 1, 1, bias=True) self.trunk_net = make_layer( ResidualBlockNoBN, num_blocks, mid_channels=mid_channels) # upsampling if self.upscale_factor in [2, 3]: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, self.upscale_factor, upsample_kernel=3) elif self.upscale_factor == 4: self.upsample1 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) self.upsample2 = PixelShufflePack( mid_channels, mid_channels, 2, upsample_kernel=3) else: raise ValueError( f'Unsupported scale factor {self.upscale_factor}. ' f'Currently supported ones are ' f'{self._supported_upscale_factors}.') self.conv_hr = nn.Conv2d( mid_channels, mid_channels, 3, 1, 1, bias=True) self.conv_last = nn.Conv2d( mid_channels, out_channels, 3, 1, 1, bias=True) self.img_upsampler = nn.Upsample( scale_factor=self.upscale_factor, mode='bilinear', align_corners=False) # activation function self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True) self.init_weights() def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ feat = self.lrelu(self.conv_first(x)) out = self.trunk_net(feat) if self.upscale_factor in [2, 3]: out = self.upsample1(out) elif self.upscale_factor == 4: out = self.upsample1(out) out = self.upsample2(out) out = self.conv_last(self.lrelu(self.conv_hr(out))) upsampled_img = self.img_upsampler(x) out += upsampled_img return out def init_weights(self): """Init weights for models.""" for m in [self.conv_first, self.conv_hr, self.conv_last]: default_init_weights(m, 0.1) ================================================ FILE: mmagic/models/editors/srgan/srgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List import torch from mmengine.optim import OptimWrapperDict from mmagic.models.base_models import BaseEditModel from mmagic.models.utils import set_requires_grad from mmagic.registry import MODELS @MODELS.register_module() class SRGAN(BaseEditModel): """SRGAN model for single image super-resolution. Ref: Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network. Args: generator (dict): Config for the generator. discriminator (dict): Config for the discriminator. Default: None. gan_loss (dict): Config for the gan loss. Note that the loss weight in gan loss is only for the generator. pixel_loss (dict): Config for the pixel loss. Default: None. perceptual_loss (dict): Config for the perceptual loss. Default: None. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Default: None. """ def __init__(self, generator, discriminator=None, gan_loss=None, pixel_loss=None, perceptual_loss=None, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) # discriminator self.discriminator = MODELS.build( discriminator) if discriminator else None # loss self.gan_loss = MODELS.build(gan_loss) if gan_loss else None self.perceptual_loss = MODELS.build( perceptual_loss) if perceptual_loss else None self.disc_steps = 1 if self.train_cfg is None else self.train_cfg.get( 'disc_steps', 1) self.disc_repeat = 1 if self.train_cfg is None else self.train_cfg.get( 'disc_repeat', 1) self.disc_init_steps = (0 if self.train_cfg is None else self.train_cfg.get('disc_init_steps', 0)) self.register_buffer('step_counter', torch.tensor(0), False) if self.discriminator is None or self.gan_loss is None: # No GAN model or loss. self.disc_repeat = 0 def forward_train(self, inputs, data_samples=None, **kwargs): """Forward training. Losses of training is calculated in train_step. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: Tensor: Result of ``forward_tensor`` with ``training=True``. """ return self.forward_tensor( inputs, data_samples, training=True, **kwargs) def forward_tensor(self, inputs, data_samples=None, training=False): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. training (bool): Whether is training. Default: False. Returns: Tensor: result of simple forward. """ feats = self.generator(inputs) return feats def if_run_g(self): """Calculates whether need to run the generator step.""" return (self.step_counter % self.disc_steps == 0 and self.step_counter >= self.disc_init_steps) def if_run_d(self): """Calculates whether need to run the discriminator step.""" return self.discriminator and self.gan_loss def g_step(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ losses = dict() # pix loss if self.pixel_loss: losses['loss_pix'] = self.pixel_loss(batch_outputs, batch_gt_data) # perceptual loss if self.perceptual_loss: loss_percep, loss_style = self.perceptual_loss( batch_outputs, batch_gt_data) if loss_percep is not None: losses['loss_perceptual'] = loss_percep if loss_style is not None: losses['loss_style'] = loss_style # gan loss for generator if self.gan_loss and self.discriminator: fake_g_pred = self.discriminator(batch_outputs) losses['loss_gan'] = self.gan_loss( fake_g_pred, target_is_real=True, is_disc=False) return losses def d_step_real(self, batch_outputs, batch_gt_data: torch.Tensor): """Real part of D step. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: Tensor: Real part of gan_loss for discriminator. """ # real real_d_pred = self.discriminator(batch_gt_data) loss_d_real = self.gan_loss( real_d_pred, target_is_real=True, is_disc=True) return loss_d_real def d_step_fake(self, batch_outputs: torch.Tensor, batch_gt_data): """Fake part of D step. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: Tensor: Fake part of gan_loss for discriminator. """ # fake fake_d_pred = self.discriminator(batch_outputs.detach()) loss_d_fake = self.gan_loss( fake_d_pred, target_is_real=False, is_disc=True) return loss_d_fake def g_step_with_optim(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor, optim_wrapper: OptimWrapperDict): """G step with optim of GAN: Calculate losses of generator and run optim. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. optim_wrapper (OptimWrapperDict): Optim wrapper dict. Returns: dict: Dict of parsed losses. """ g_optim_wrapper = optim_wrapper['generator'] with g_optim_wrapper.optim_context(self): losses_g = self.g_step(batch_outputs, batch_gt_data) parsed_losses_g, log_vars_g = self.parse_losses(losses_g) g_optim_wrapper.update_params(parsed_losses_g) return log_vars_g def d_step_with_optim(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor, optim_wrapper: OptimWrapperDict): """D step with optim of GAN: Calculate losses of discriminator and run optim. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. optim_wrapper (OptimWrapperDict): Optim wrapper dict. Returns: dict: Dict of parsed losses. """ log_vars = dict() d_optim_wrapper = optim_wrapper['discriminator'] with d_optim_wrapper.optim_context(self): loss_d_real = self.d_step_real(batch_outputs, batch_gt_data) parsed_losses_dr, log_vars_dr = self.parse_losses( dict(loss_d_real=loss_d_real)) log_vars.update(log_vars_dr) loss_dr = d_optim_wrapper.scale_loss(parsed_losses_dr) d_optim_wrapper.backward(loss_dr) with d_optim_wrapper.optim_context(self): loss_d_fake = self.d_step_fake(batch_outputs, batch_gt_data) parsed_losses_df, log_vars_df = self.parse_losses( dict(loss_d_fake=loss_d_fake)) log_vars.update(log_vars_df) loss_df = d_optim_wrapper.scale_loss(parsed_losses_df) d_optim_wrapper.backward(loss_df) if d_optim_wrapper.should_update(): d_optim_wrapper.step() d_optim_wrapper.zero_grad() return log_vars def extract_gt_data(self, data_samples): """extract gt data from data samples. Args: data_samples (list): List of DataSample. Returns: Tensor: Extract gt data. """ batch_gt_data = data_samples.gt_img return batch_gt_data def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step of GAN-based method. Args: data (List[dict]): Data sampled from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ g_optim_wrapper = optim_wrapper['generator'] data = self.data_preprocessor(data, True) batch_inputs = data['inputs'] data_samples = data['data_samples'] batch_gt_data = self.extract_gt_data(data_samples) log_vars = dict() with g_optim_wrapper.optim_context(self): batch_outputs = self.forward_train(batch_inputs, data_samples) if self.if_run_g(): set_requires_grad(self.discriminator, False) log_vars_d = self.g_step_with_optim( batch_outputs=batch_outputs, batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if self.if_run_d(): set_requires_grad(self.discriminator, True) for _ in range(self.disc_repeat): # detach before function call to resolve PyTorch2.0 compile bug log_vars_d = self.d_step_with_optim( batch_outputs=batch_outputs.detach(), batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if 'loss' in log_vars: log_vars.pop('loss') self.step_counter += 1 return log_vars ================================================ FILE: mmagic/models/editors/stable_diffusion/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .stable_diffusion import StableDiffusion from .stable_diffusion_inpaint import StableDiffusionInpaint from .vae import AutoencoderKL __all__ = ['StableDiffusion', 'AutoencoderKL', 'StableDiffusionInpaint'] ================================================ FILE: mmagic/models/editors/stable_diffusion/clip_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import torch import torch.nn as nn from mmengine.logging import MMLogger from mmagic.utils import try_import transformers = try_import('transformers') if transformers is not None: from transformers import CLIPConfig, CLIPVisionModel, PreTrainedModel from transformers.models.clip.feature_extraction_clip import \ CLIPFeatureExtractor # noqa from transformers.models.clip.modeling_clip import CLIPTextModel from transformers.models.clip.tokenization_clip import CLIPTokenizer logger = MMLogger.get_current_instance() def cosine_distance(image_embeds, text_embeds): """compute the cosine distance of image embeddings and text embeddings.""" normalized_image_embeds = nn.functional.normalize(image_embeds) normalized_text_embeds = nn.functional.normalize(text_embeds) return torch.mm(normalized_image_embeds, normalized_text_embeds.t()) class StableDiffusionSafetyChecker(PreTrainedModel): config_class = CLIPConfig _no_split_modules = ['CLIPEncoderLayer'] def __init__(self, config: CLIPConfig): """check result image for stable diffusion to prevent NSFW content generated. Args: config(CLIPConfig): config for transformers clip. """ super().__init__(config) self.vision_model = CLIPVisionModel(config.vision_config) self.visual_projection = nn.Linear( config.vision_config.hidden_size, config.projection_dim, bias=False) self.concept_embeds = nn.Parameter( torch.ones(17, config.projection_dim), requires_grad=False) self.special_care_embeds = nn.Parameter( torch.ones(3, config.projection_dim), requires_grad=False) self.concept_embeds_weights = nn.Parameter( torch.ones(17), requires_grad=False) self.special_care_embeds_weights = nn.Parameter( torch.ones(3), requires_grad=False) @torch.no_grad() def forward(self, clip_input, images): """return black image if input image has nsfw content. Args: clip_input(torch.Tensor): image feature extracted by clip feature extractor. images(torch.Tensor): image generated by stable diffusion. Returns: images(torch.Tensor): black images if input images have nsfw content, otherwise return input images. has_nsfw_concepts(list[bool]): flag list to indicate whether input images have nsfw content. """ pooled_output = self.vision_model(clip_input)[1] image_embeds = self.visual_projection(pooled_output) # we always cast to float32 as this does not cause # significant overhead and is compatible with bfloa16 special_cos_dist = cosine_distance( image_embeds, self.special_care_embeds).cpu().float().numpy() cos_dist = cosine_distance( image_embeds, self.concept_embeds).cpu().float().numpy() result = [] batch_size = image_embeds.shape[0] for i in range(batch_size): result_img = { 'special_scores': {}, 'special_care': [], 'concept_scores': {}, 'bad_concepts': [] } # increase this value to create a stronger `nfsw` filter # at the cost of increasing the possibility of # filtering benign images adjustment = 0.0 for concept_idx in range(len(special_cos_dist[0])): concept_cos = special_cos_dist[i][concept_idx] concept_threshold = self.special_care_embeds_weights[ concept_idx].item() result_img['special_scores'][concept_idx] = round( concept_cos - concept_threshold + adjustment, 3) if result_img['special_scores'][concept_idx] > 0: result_img['special_care'].append({ concept_idx, result_img['special_scores'][concept_idx] }) adjustment = 0.01 for concept_idx in range(len(cos_dist[0])): concept_cos = cos_dist[i][concept_idx] concept_threshold = self.concept_embeds_weights[ concept_idx].item() result_img['concept_scores'][concept_idx] = round( concept_cos - concept_threshold + adjustment, 3) if result_img['concept_scores'][concept_idx] > 0: result_img['bad_concepts'].append(concept_idx) result.append(result_img) has_nsfw_concepts = [ len(res['bad_concepts']) > 0 for res in result ] for idx, has_nsfw_concept in enumerate(has_nsfw_concepts): if has_nsfw_concept: images[idx] = torch.zeros(images[idx].shape) # black image if any(has_nsfw_concepts): logger.warning( 'NSFW content was detected in one or more images.' ' A black image will be returned instead.' ' Try again with a different prompt and/or seed.') return images, has_nsfw_concepts def load_clip_submodels(init_cfg, submodels, requires_safety_checker): """ Args: init_cfg (dict): ckpt path of clip models. submodels (List): list of stable diffusion submodels. requires_safety_checker (bool): whether to load safety checker Returns: tokenizer(CLIPTokenizer): tokenizer with ckpt loaded. feature_extractor(CLIPFeatureExtractor): feature_extractor with ckpt loaded. text_encoder(CLIPTextModel): text_encoder with ckpt loaded. safety_checker(StableDiffusionSafetyChecker): safety_checker with ckpt loaded. """ pretrained_model_path = init_cfg.get('pretrained_model_path', None) tokenizer, feature_extractor, text_encoder, safety_checker = \ None, None, None, None if pretrained_model_path: tokenizer = CLIPTokenizer.from_pretrained( os.path.join(pretrained_model_path, 'tokenizer')) feature_extractor = CLIPFeatureExtractor.from_pretrained( os.path.join(pretrained_model_path, 'feature_extractor')) text_encoder = CLIPTextModel.from_pretrained( os.path.join(pretrained_model_path, 'text_encoder')) if requires_safety_checker: submodels.append('safety_checker') safety_checker = StableDiffusionSafetyChecker.from_pretrained( os.path.join(pretrained_model_path, 'safety_checker')) return tokenizer, feature_extractor, text_encoder, safety_checker else: def load_clip_submodels(init_cfg, submodels, requires_safety_checker): raise ImportError('Please install transformers via ' '\'pip install transformers\'') ================================================ FILE: mmagic/models/editors/stable_diffusion/stable_diffusion.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import inspect from copy import deepcopy from typing import Dict, List, Optional, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from mmengine.logging import MMLogger from mmengine.model import BaseModel from mmengine.runner import set_random_seed from PIL import Image from tqdm.auto import tqdm from mmagic.models.archs import TokenizerWrapper from mmagic.models.utils import build_module, set_tomesd, set_xformers from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList logger = MMLogger.get_current_instance() ModelType = Union[Dict, nn.Module] @MODELS.register_module('sd') @MODELS.register_module() class StableDiffusion(BaseModel): """Class for Stable Diffusion. Refers to https://github.com/Stability- AI/stablediffusion and https://github.com/huggingface/diffusers/blob/main/s rc/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_attend_an d_excite.py # noqa. Args: unet (Union[dict, nn.Module]): The config or module for Unet model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. vae (Union[dict, nn.Module]): The config or module for VAE model. tokenizer (str): The **name** for CLIP tokenizer. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. dtype (str, optional): The dtype for the model This argument will not work when dtype is defined for submodels. Defaults to None. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise Defaults to 0. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. """ def __init__(self, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: Optional[str] = None, enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), init_cfg: Optional[dict] = None): # TODO: support `from_pretrained` for this class super().__init__(data_preprocessor, init_cfg) default_args = dict() if dtype is not None: default_args['dtype'] = dtype self.dtype = torch.float32 if dtype in ['float16', 'fp16', 'half']: self.dtype = torch.float16 elif dtype == 'bf16': self.dtype = torch.bfloat16 else: assert dtype in [ 'fp32', None ], ('dtype must be one of \'fp32\', \'fp16\', \'bf16\' or None.') self.vae = build_module(vae, MODELS, default_args=default_args) self.unet = build_module(unet, MODELS) # NOTE: initialize unet as fp32 self._unet_ori_dtype = next(self.unet.parameters()).dtype print_log(f'Set UNet dtype to \'{self._unet_ori_dtype}\'.', 'current') self.scheduler = build_module(scheduler, DIFFUSION_SCHEDULERS) if test_scheduler is None: self.test_scheduler = deepcopy(self.scheduler) else: self.test_scheduler = build_module(test_scheduler, DIFFUSION_SCHEDULERS) self.text_encoder = build_module(text_encoder, MODELS) if not isinstance(tokenizer, str): self.tokenizer = tokenizer else: # NOTE: here we assume tokenizer is an string self.tokenizer = TokenizerWrapper(tokenizer, subfolder='tokenizer') self.unet_sample_size = self.unet.sample_size self.vae_scale_factor = 2**(len(self.vae.block_out_channels) - 1) self.enable_noise_offset = noise_offset_weight > 0 self.noise_offset_weight = noise_offset_weight self.enable_xformers = enable_xformers self.set_xformers() self.tomesd_cfg = tomesd_cfg self.set_tomesd() def set_xformers(self, module: Optional[nn.Module] = None) -> nn.Module: """Set xformers for the model. Returns: nn.Module: The model with xformers. """ if self.enable_xformers: if module is None: set_xformers(self) else: set_xformers(module) def set_tomesd(self) -> nn.Module: """Set ToMe for the stable diffusion model. Returns: nn.Module: The model with ToMe. """ if self.tomesd_cfg is not None: set_tomesd(self, **self.tomesd_cfg) @property def device(self): return next(self.parameters()).device def train(self, mode: bool = True): """Set train/eval mode. Args: mode (bool, optional): Whether set train mode. Defaults to True. """ if mode: if next(self.unet.parameters()).dtype != self._unet_ori_dtype: print_log( f'Set UNet dtype to \'{self._unet_ori_dtype}\' ' 'in the train mode.', 'current') self.unet.to(self._unet_ori_dtype) else: self.unet.to(self.dtype) print_log(f'Set UNet dtype to \'{self.dtype}\' in the eval mode.', 'current') return super().train(mode) @torch.no_grad() def infer(self, prompt: Union[str, List[str]], height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, show_progress=True, seed=1, return_type='image'): """Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`): The prompt or prompts to guide the image generation. height (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The height in pixels of the generated image. width (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The width in pixels of the generated image. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance] (https://arxiv.org/abs/2207.12598). negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator`, *optional*): A [torch generator] to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images. """ assert return_type in ['image', 'tensor', 'numpy'] set_random_seed(seed=seed) # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device img_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype latent_dtype = next(self.unet.parameters()).dtype # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt text_embeddings = self._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) # 4. Prepare timesteps self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare latent variables if hasattr(self.unet, 'module'): num_channels_latents = self.unet.module.in_channels else: num_channels_latents = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, text_embeddings.dtype, device, generator, latents, ) # 6. Prepare extra step kwargs. # TODO: Logic should ideally just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) latent_model_input = latent_model_input.to(latent_dtype) text_embeddings = text_embeddings.to(latent_dtype) # predict the noise residual noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings)['sample'] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if return_type == 'image': image = self.output_to_pil(image) elif return_type == 'numpy': image = image.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image} def output_to_pil(self, image) -> List[Image.Image]: """Convert output tensor to PIL image. Output tensor will be de-normed to [0, 255] by `DataPreprocessor.destruct`. Due to no `data_samples` is passed, color order conversion will not be performed. Args: image (torch.Tensor): The output tensor of the decoder. Returns: List[Image.Image]: The list of processed PIL images. """ image = self.data_preprocessor.destruct(image) image = image.permute(0, 2, 3, 1).to(torch.uint8).cpu().numpy() image = [Image.fromarray(img) for img in image] return image def _encode_prompt(self, prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt): """Encodes the prompt into text encoder hidden states. Args: prompt (str or list(int)): prompt to be encoded. device: (torch.device): torch device. num_images_per_prompt (int): number of images that should be generated per prompt. do_classifier_free_guidance (`bool`): whether to use classifier free guidance or not. negative_prompt (str or List[str]): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). Returns: text_embeddings (torch.Tensor): text embeddings generated by clip text encoder. """ batch_size = len(prompt) if isinstance(prompt, list) else 1 text_inputs = self.tokenizer( prompt, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_input_ids = text_inputs.input_ids untruncated_ids = self.tokenizer( prompt, padding='max_length', return_tensors='pt').input_ids if not torch.equal(text_input_ids, untruncated_ids): removed_text = self.tokenizer.batch_decode( untruncated_ids[:, self.tokenizer.model_max_length - 1:-1]) logger.warning( 'The following part of your input was truncated because CLIP' ' can only handle sequences up to' f' {self.tokenizer.model_max_length} tokens: {removed_text}') text_encoder = self.text_encoder.module if hasattr( self.text_encoder, 'module') else self.text_encoder if hasattr(text_encoder.config, 'use_attention_mask' ) and text_encoder.config.use_attention_mask: attention_mask = text_inputs.attention_mask.to(device) else: attention_mask = None text_embeddings = text_encoder( text_input_ids.to(device), attention_mask=attention_mask, ) text_embeddings = text_embeddings[0] # duplicate text embeddings for each generation per prompt, bs_embed, seq_len, _ = text_embeddings.shape text_embeddings = text_embeddings.repeat(1, num_images_per_prompt, 1) text_embeddings = text_embeddings.view( bs_embed * num_images_per_prompt, seq_len, -1) # get unconditional embeddings for classifier free guidance if do_classifier_free_guidance: uncond_tokens: List[str] if negative_prompt is None: uncond_tokens = [''] * batch_size elif type(prompt) is not type(negative_prompt): raise TypeError( f'`negative_prompt` should be the same type to `prompt`,' f'but got {type(negative_prompt)} !=' f' {type(prompt)}.') elif isinstance(negative_prompt, str): uncond_tokens = [negative_prompt] elif batch_size != len(negative_prompt): raise ValueError( f'`negative_prompt`: {negative_prompt} has ' f'batch size {len(negative_prompt)}, but `prompt`:' f' {prompt} has batch size {batch_size}.' f' Please make sure that passed `negative_prompt` matches' ' the batch size of `prompt`.') else: uncond_tokens = negative_prompt max_length = text_input_ids.shape[-1] uncond_input = self.tokenizer( uncond_tokens, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) if hasattr(text_encoder.config, 'use_attention_mask' ) and text_encoder.config.use_attention_mask: attention_mask = uncond_input.attention_mask.to(device) else: attention_mask = None uncond_embeddings = text_encoder( uncond_input.input_ids.to(device), attention_mask=attention_mask, ) uncond_embeddings = uncond_embeddings[0] # duplicate unconditional embeddings for # each generation per prompt, using mps friendly method seq_len = uncond_embeddings.shape[1] uncond_embeddings = uncond_embeddings.repeat( 1, num_images_per_prompt, 1) uncond_embeddings = uncond_embeddings.view( batch_size * num_images_per_prompt, seq_len, -1) # For classifier free guidance, we need to do two forward passes. # Here we concatenate the unconditional # and text embeddings into a single batch # to avoid doing two forward passes text_embeddings = torch.cat([uncond_embeddings, text_embeddings]) return text_embeddings def decode_latents(self, latents): """use vae to decode latents. Args: latents (torch.Tensor): latents to decode. Returns: image (torch.Tensor): image result. """ latents = 1 / 0.18215 * latents if hasattr(self.vae, 'module'): image = self.vae.module.decode(latents)['sample'] else: image = self.vae.decode(latents)['sample'] # we always cast to float32 as this does not cause # significant overhead and is compatible with bfloa16 return image.float() def prepare_extra_step_kwargs(self, generator, eta): """prepare extra kwargs for the scheduler step. Args: generator (torch.Generator): generator for random functions. eta (float): eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers. eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 and should be between [0, 1] Return: extra_step_kwargs (dict): dict contains 'generator' and 'eta' """ accepts_eta = 'eta' in set( inspect.signature(self.scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def prepare_test_scheduler_extra_step_kwargs(self, generator, eta): """prepare extra kwargs for the scheduler step. Args: generator (torch.Generator): generator for random functions. eta (float): eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers. eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 and should be between [0, 1] Return: extra_step_kwargs (dict): dict contains 'generator' and 'eta' """ accepts_eta = 'eta' in set( inspect.signature(self.test_scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.test_scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def check_inputs(self, prompt, height, width): """check whether inputs are in suitable format or not.""" if not isinstance(prompt, str) and not isinstance(prompt, list): raise ValueError(f'`prompt` has to be of ' f'type `str` or `list` but is {type(prompt)}') if height % 8 != 0 or width % 8 != 0: raise ValueError(f'`height` and `width` have to be divisible ' f'by 8 but are {height} and {width}.') def prepare_latents(self, batch_size, num_channels_latents, height, width, dtype, device, generator, latents=None): """prepare latents for diffusion to run in latent space. Args: batch_size (int): batch size. num_channels_latents (int): latent channel nums. height (int): image height. width (int): image width. dtype (torch.dtype): float type. device (torch.device): torch device. generator (torch.Generator): generator for random functions, defaults to None. latents (torch.Tensor): Pre-generated noisy latents, defaults to None. Return: latents (torch.Tensor): prepared latents. """ shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) if latents is None: latents = torch.randn( shape, generator=generator, device=device, dtype=dtype) else: if latents.shape != shape: raise ValueError(f'Unexpected latents shape, ' f'got {latents.shape}, expected {shape}') latents = latents.to(device) # scale the initial noise by the standard # deviation required by the scheduler latents = latents * self.scheduler.init_noise_sigma return latents @torch.no_grad() def val_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) gt_img = self.data_preprocessor.destruct(data['inputs'], data_samples) out_data_sample = DataSample( fake_img=samples, gt_img=gt_img, prompt=prompt) # out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) gt_img = self.data_preprocessor.destruct(data['inputs'], data_samples) out_data_sample = DataSample( fake_img=samples, gt_img=gt_img, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list def train_step(self, data, optim_wrapper_dict): data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] vae = self.vae.module if hasattr(self.vae, 'module') else self.vae optim_wrapper = optim_wrapper_dict['unet'] with optim_wrapper.optim_context(self.unet): image = inputs prompt = data_samples.prompt num_batches = image.shape[0] image = image.to(self.dtype) latents = vae.encode(image).latent_dist.sample() latents = latents * vae.config.scaling_factor noise = torch.randn_like(latents) if self.enable_noise_offset: noise = noise + self.noise_offset_weight * torch.randn( latents.shape[0], latents.shape[1], 1, 1, device=noise.device) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) input_ids = self.tokenizer( prompt, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) encoder_hidden_states = self.text_encoder(input_ids)[0] if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') # NOTE: we train unet in fp32, convert to float manually model_output = self.unet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float()) model_pred = model_output['sample'] loss_dict = dict() # calculate loss in FP32 loss_mse = F.mse_loss(model_pred.float(), gt.float()) loss_dict['loss_mse'] = loss_mse parsed_loss, log_vars = self.parse_losses(loss_dict) optim_wrapper.update_params(parsed_loss) return log_vars def forward(self, inputs: torch.Tensor, data_samples: Optional[list] = None, mode: str = 'tensor') -> Union[Dict[str, torch.Tensor], list]: """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') ================================================ FILE: mmagic/models/editors/stable_diffusion/stable_diffusion_inpaint.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # Copyright 2023 The HuggingFace Team. All rights reserved. from typing import Dict, List, Optional, Union import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine.logging import MMLogger from mmengine.runner import set_random_seed from PIL import Image from tqdm.auto import tqdm from mmagic.registry import MODELS from mmagic.utils.typing import SampleList from .stable_diffusion import StableDiffusion logger = MMLogger.get_current_instance() ModelType = Union[Dict, nn.Module] @MODELS.register_module('sd-inpaint') @MODELS.register_module() class StableDiffusionInpaint(StableDiffusion): def __init__(self, *args, **kwargs): """Initializes the current class using the same parameters as its parent, StableDiffusion. This constructor is primarily a pass-through to the parent class's constructor. All arguments and keyword arguments provided are directly passed to the parent class, StableDiffusion. """ super().__init__(*args, **kwargs) @torch.no_grad() def infer(self, prompt: Union[str, List[str]], image: Union[torch.FloatTensor, Image.Image] = None, mask_image: Union[torch.FloatTensor, Image.Image] = None, height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, show_progress=True, seed=1, return_type='image'): """Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`): The prompt or prompts to guide the image generation. image (`Union[torch.FloatTensor, Image.Image]`): The image to inpaint. mask_image (`Union[torch.FloatTensor, Image.Image]`): The mask to apply to the image, i.e. regions to inpaint. height (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The height in pixels of the generated image. width (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The width in pixels of the generated image. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance] (https://arxiv.org/abs/2207.12598). negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator`, *optional*): A [torch generator] to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images. """ assert return_type in ['image', 'tensor', 'numpy'] set_random_seed(seed=seed) # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device img_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype latent_dtype = next(self.unet.parameters()).dtype # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt text_embeddings = self._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) # 4. Prepare timesteps self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare mask and image mask, masked_image = prepare_mask_and_masked_image( image, mask_image, height, width) # 6. Prepare latent variables if hasattr(self.unet, 'module'): num_channels_latents = self.vae.module.latent_channels num_channels_unet = self.unet.module.in_channels else: num_channels_latents = self.vae.latent_channels num_channels_unet = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, text_embeddings.dtype, device, generator, latents, ) # 7. Prepare masked image latents mask, masked_image_latents = self.prepare_mask_latents( mask, masked_image, batch_size * num_images_per_prompt, num_channels_latents, height, width, text_embeddings.dtype, device, generator, do_classifier_free_guidance, ) # 8. Check that sizes of mask, masked image and latents match if num_channels_unet == 9: # default case for runwayml/stable-diffusion-inpainting num_channels_mask = mask.shape[1] num_channels_masked_image = masked_image_latents.shape[1] total_channels = num_channels_latents + \ num_channels_masked_image + num_channels_mask if total_channels != self.unet.in_channels: raise ValueError( 'Incorrect configuration settings! The config of ' f'`pipeline.unet`: {self.unet.config} expects' f' {self.unet.in_channels} but received ' f'`num_channels_latents`: {num_channels_latents} +' f' `num_channels_mask`: {num_channels_mask} + ' '`num_channels_masked_image`: ' f'{num_channels_masked_image} = {total_channels}.' 'Please verify the config of `pipeline.unet` ' 'or your `mask_image` or `image` input.') elif num_channels_unet != 4: raise ValueError( f'The unet {self.unet.__class__} should have either 4 or 9 ' f'input channels, not {self.unet.config.in_channels}.') # 9. Prepare extra step kwargs. # TODO: Logic should ideally just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 10. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) # concat latents with mask if num_channels_unet == 9: latent_model_input = torch.cat( [latent_model_input, mask, masked_image_latents], dim=1) latent_model_input = latent_model_input.to(latent_dtype) text_embeddings = text_embeddings.to(latent_dtype) # predict the noise residual noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings)['sample'] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] if num_channels_unet == 4: assert NotImplementedError # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if return_type == 'image': image = self.output_to_pil(image) elif return_type == 'numpy': image = image.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image} def prepare_mask_latents(self, mask, masked_image, batch_size, num_channels_latents, height, width, dtype, device, generator, do_classifier_free_guidance): """prepare latents for diffusion to run in latent space. Args: mask (torch.Tensor): The mask to apply to the image, i.e. regions to inpaint. image (torch.Tensor): The image to be masked. batch_size (int): batch size. num_channels_latents (int): latent channel nums. height (int): image height. width (int): image width. dtype (torch.dtype): float type. device (torch.device): torch device. generator (torch.Generator): generator for random functions, defaults to None. latents (torch.Tensor): Pre-generated noisy latents, defaults to None. do_classifier_free_guidance (bool): Whether to apply classifier-free guidance. Return: latents (torch.Tensor): prepared latents. """ shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) mask = F.interpolate( mask, size=shape[2:]).to( device=device, dtype=dtype) masked_image = masked_image.to(device=device, dtype=dtype) masked_image_latents = self.vae.encode( masked_image).latent_dist.sample(generator) masked_image_latents = self.vae.config.scaling_factor * \ masked_image_latents # duplicate mask and masked_image_latents for each generation per # prompt, using mps friendly method if mask.shape[0] < batch_size: if not batch_size % mask.shape[0] == 0: raise ValueError( "The passed mask and the required batch size don't match." 'Masks are supposed to be duplicated to a total batch' f' size of {batch_size}, but {mask.shape[0]} masks were ' 'passed. Make sure the number of masks that you pass' ' is divisible by the total requested batch size.') mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1) if masked_image_latents.shape[0] < batch_size: if not batch_size % masked_image_latents.shape[0] == 0: raise ValueError( "The passed images and the required batch size don't " 'match. Images are supposed to be duplicated to a total' f' batch size of {batch_size}, but ' f'{masked_image_latents.shape[0]} images were passed.' ' Make sure the number of images that you pass is' 'divisible by the total requested batch size.') masked_image_latents = masked_image_latents.repeat( batch_size // masked_image_latents.shape[0], 1, 1, 1) mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask masked_image_latents = ( torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents) # aligning device to prevent device errors when concatenating it with # the latent model input masked_image_latents = masked_image_latents.to( device=device, dtype=dtype) return mask, masked_image_latents @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Performs a validation step on the provided data. This method is decorated with `torch.no_grad()` which indicates no gradients will be computed during the operations. This ensures efficient memory usage during testing. Args: data (dict): Dictionary containing input data for testing. Returns: SampleList: List of samples processed during the testing step. Raises: NotImplementedError: This method has not been implemented. """ raise NotImplementedError @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Performs a testing step on the provided data. This method is decorated with `torch.no_grad()` which indicates no gradients will be computed during the operations. This ensures efficient memory usage during testing. Args: data (dict): Dictionary containing input data for testing. Returns: SampleList: List of samples processed during the testing step. Raises: NotImplementedError: This method has not been implemented. """ raise NotImplementedError def train_step(self, data, optim_wrapper_dict): """Performs a training step on the provided data. Args: data: Input data for training. optim_wrapper_dict: Dictionary containing optimizer wrappers which may contain optimizers, schedulers, etc. required for the training step. Raises: NotImplementedError: This method has not been implemented. """ raise NotImplementedError def prepare_mask_and_masked_image(image: torch.Tensor, mask: torch.Tensor, height: int = 512, width: int = 512, return_image: bool = False): """Prepare latents for diffusion to run in latent space. Args: image (torch.Tensor): The image to be masked. mask (torch.Tensor): The mask to apply to the image, i.e. regions to inpaint. height (int): Image height. width (int): Image width. return_image (bool): Whether to return the original image. Default to `False`. Returns: mask (torch.Tensor): A binary mask image. masked_image (torch.Tensor): An image that applied mask. """ if image is None: raise ValueError('`image` input cannot be undefined.') if mask is None: raise ValueError('`mask_image` input cannot be undefined.') if isinstance(image, torch.Tensor): if not isinstance(mask, torch.Tensor): raise TypeError('`image` is a torch.Tensor but `mask` (type: ' f'{type(mask)} is not') # Batch single image if image.ndim == 3: assert image.shape[ 0] == 3, 'Image outside a batch should be of shape (3, H, W)' image = image.unsqueeze(0) # Batch and add channel dim for single mask if mask.ndim == 2: mask = mask.unsqueeze(0).unsqueeze(0) # Batch single mask or add channel dim if mask.ndim == 3: # Single batched mask, no channel dim or single mask # not batched but channel dim if mask.shape[0] == 1: mask = mask.unsqueeze(0) # Batched masks no channel dim else: mask = mask.unsqueeze(1) assert (image.ndim == 4 and mask.ndim == 4), 'Image and Mask must have 4 dimensions' assert image.shape[-2:] == mask.shape[ -2:], 'Image and Mask must have the same spatial dimensions' assert image.shape[0] == mask.shape[ 0], 'Image and Mask must have the same batch size' # Check image is in [-1, 1] if image.min() < -1 or image.max() > 1: raise ValueError('Image should be in [-1, 1] range') # Check mask is in [0, 1] if mask.min() < 0 or mask.max() > 1: raise ValueError('Mask should be in [0, 1] range') # Binarize mask mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 # Image as float32 image = image.to(dtype=torch.float32) elif isinstance(mask, torch.Tensor): raise TypeError( f'`mask` is a torch.Tensor but `image` (type: {type(image)} is not' ) else: # preprocess image if isinstance(image, (Image.Image, np.ndarray)): image = [image] if isinstance(image, list) and isinstance(image[0], Image.Image): # resize all images w.r.t passed height an width image = [ i.resize((width, height), resample=Image.LANCZOS) for i in image ] image = [np.array(i.convert('RGB'))[None, :] for i in image] image = np.concatenate(image, axis=0) elif isinstance(image, list) and isinstance(image[0], np.ndarray): image = np.concatenate([i[None, :] for i in image], axis=0) image = image.transpose(0, 3, 1, 2) image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0 # preprocess mask if isinstance(mask, (Image.Image, np.ndarray)): mask = [mask] if isinstance(mask, list) and isinstance(mask[0], Image.Image): mask = [ i.resize((width, height), resample=Image.LANCZOS) for i in mask ] mask = np.concatenate( [np.array(m.convert('L'))[None, None, :] for m in mask], axis=0) mask = mask.astype(np.float32) / 255.0 elif isinstance(mask, list) and isinstance(mask[0], np.ndarray): mask = np.concatenate([m[None, None, :] for m in mask], axis=0) mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 mask = torch.from_numpy(mask) masked_image = image * (mask < 0.5) # n.b. ensure backwards compatibility as old function does not return image if return_image: return mask, masked_image, image return mask, masked_image ================================================ FILE: mmagic/models/editors/stable_diffusion/vae.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import Optional, Tuple, Union import mmengine import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from addict import Dict from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from mmagic.registry import MODELS class Downsample2D(nn.Module): """A downsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. out_channels (int): output channels padding (int): padding num """ def __init__(self, channels, use_conv=False, out_channels=None, padding=1, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.padding = padding stride = 2 self.name = name if use_conv: conv = nn.Conv2d( self.channels, self.out_channels, 3, stride=stride, padding=padding) else: assert self.channels == self.out_channels conv = nn.AvgPool2d(kernel_size=stride, stride=stride) self.conv = conv def forward(self, hidden_states): """forward hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv and self.padding == 0: pad = (0, 1, 0, 1) hidden_states = F.pad(hidden_states, pad, mode='constant', value=0) assert hidden_states.shape[1] == self.channels hidden_states = self.conv(hidden_states) return hidden_states class Upsample2D(nn.Module): """An upsampling layer with an optional convolution. Args: channels (int): channels in the inputs and outputs. use_conv (bool): a bool determining if a convolution is applied. use_conv_transpose (bool): whether to use conv transpose. out_channels (int): output channels. """ def __init__(self, channels, use_conv=False, use_conv_transpose=False, out_channels=None, name='conv'): super().__init__() self.channels = channels self.out_channels = out_channels or channels self.use_conv = use_conv self.use_conv_transpose = use_conv_transpose self.name = name conv = None if use_conv: conv = nn.Conv2d(self.channels, self.out_channels, 3, padding=1) else: conv = nn.ConvTranspose2d(channels, self.out_channels, 4, 2, 1) self.conv = conv def forward(self, hidden_states, output_size=None): """forward with hidden states.""" assert hidden_states.shape[1] == self.channels if self.use_conv_transpose: return self.conv(hidden_states) # if `output_size` is passed we force the interpolation output # size and do not make use of `scale_factor=2` if output_size is None: hidden_states = F.interpolate( hidden_states, scale_factor=2.0, mode='nearest') else: hidden_states = F.interpolate( hidden_states, size=output_size, mode='nearest') # TODO(Suraj, Patrick) # - clean up after weight dicts are correctly renamed hidden_states = self.conv(hidden_states) return hidden_states class ResnetBlock2D(nn.Module): """resnet block support down sample and up sample. Args: in_channels (int): input channels. out_channels (int): output channels. conv_shortcut (bool): whether to use conv shortcut. dropout (float): dropout rate. temb_channels (int): time embedding channels. groups (int): conv groups. groups_out (int): conv out groups. pre_norm (bool): whether to norm before conv. Todo: remove. eps (float): eps for groupnorm. non_linearity (str): non linearity type. time_embedding_norm (str): time embedding norm type. output_scale_factor (float): factor to scale input and output. use_in_shortcut (bool): whether to use conv in shortcut. up (bool): whether to upsample. down (bool): whether to downsample. """ def __init__( self, in_channels, out_channels=None, conv_shortcut=False, dropout=0.0, temb_channels=512, groups=32, groups_out=None, pre_norm=True, eps=1e-6, non_linearity='silu', time_embedding_norm='default', kernel=None, output_scale_factor=1.0, use_in_shortcut=None, up=False, down=False, ): super().__init__() self.pre_norm = pre_norm self.pre_norm = True self.in_channels = in_channels out_channels = in_channels if out_channels is None else out_channels self.out_channels = out_channels self.use_conv_shortcut = conv_shortcut self.time_embedding_norm = time_embedding_norm self.up = up self.down = down self.output_scale_factor = output_scale_factor if groups_out is None: groups_out = groups self.norm1 = torch.nn.GroupNorm( num_groups=groups, num_channels=in_channels, eps=eps, affine=True) self.conv1 = torch.nn.Conv2d( in_channels, out_channels, kernel_size=3, stride=1, padding=1) if temb_channels is not None: self.time_emb_proj = torch.nn.Linear(temb_channels, out_channels) else: self.time_emb_proj = None self.norm2 = torch.nn.GroupNorm( num_groups=groups_out, num_channels=out_channels, eps=eps, affine=True) self.dropout = torch.nn.Dropout(dropout) self.conv2 = torch.nn.Conv2d( out_channels, out_channels, kernel_size=3, stride=1, padding=1) if non_linearity == 'silu' and \ digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.nonlinearity = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.nonlinearity = nn.ReLU() self.upsample = self.downsample = None if self.up: self.upsample = Upsample2D(in_channels, use_conv=False) elif self.down: self.downsample = \ Downsample2D( in_channels, use_conv=False, padding=1, name='op') self.use_in_shortcut = self.in_channels != self.out_channels if use_in_shortcut is None else use_in_shortcut # noqa self.conv_shortcut = None if self.use_in_shortcut: self.conv_shortcut = torch.nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0) def forward(self, input_tensor, temb): """forward with hidden states and time embeddings.""" hidden_states = input_tensor hidden_states = self.norm1(hidden_states) hidden_states = self.nonlinearity(hidden_states) if self.upsample is not None: # upsample_nearest_nhwc fails with large batch sizes. # see https://github.com/huggingface/diffusers/issues/984 if hidden_states.shape[0] >= 64: input_tensor = input_tensor.contiguous() hidden_states = hidden_states.contiguous() input_tensor = self.upsample(input_tensor) hidden_states = self.upsample(hidden_states) elif self.downsample is not None: input_tensor = self.downsample(input_tensor) hidden_states = self.downsample(hidden_states) hidden_states = self.conv1(hidden_states) if temb is not None: temb = \ self.time_emb_proj(self.nonlinearity(temb))[:, :, None, None] hidden_states = hidden_states + temb hidden_states = self.norm2(hidden_states) hidden_states = self.nonlinearity(hidden_states) hidden_states = self.dropout(hidden_states) hidden_states = self.conv2(hidden_states) if self.conv_shortcut is not None: input_tensor = self.conv_shortcut(input_tensor) output_tensor = \ (input_tensor + hidden_states) / self.output_scale_factor return output_tensor class AttentionBlock(nn.Module): """An attention block that allows spatial positions to attend to each other. Originally ported from here, but adapted to the N-d case. https://github.com/hojonathanho/diffusion/blob/ 1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66. Uses three q, k, v linear layers to compute attention. Args: channels (int): The number of channels in the input and output. num_head_channels (int, *optional*): The number of channels in each head. If None, then `num_heads` = 1. norm_num_groups (int, *optional*, defaults to 32): The number of groups to use for group norm. rescale_output_factor (float, *optional*, defaults to 1.0): The factor to rescale the output by. eps (float, *optional*, defaults to 1e-5): The epsilon value to use for group norm. """ def __init__( self, channels: int, num_head_channels: Optional[int] = None, norm_num_groups: int = 32, rescale_output_factor: float = 1.0, eps: float = 1e-5, ): super().__init__() self.channels = channels self.num_heads = channels // num_head_channels if num_head_channels is not None else 1 # noqa self.num_head_size = num_head_channels self.group_norm = nn.GroupNorm( num_channels=channels, num_groups=norm_num_groups, eps=eps, affine=True) # define q,k,v as linear layers self.query = nn.Linear(channels, channels) self.key = nn.Linear(channels, channels) self.value = nn.Linear(channels, channels) self.rescale_output_factor = rescale_output_factor self.proj_attn = nn.Linear(channels, channels, 1) def transpose_for_scores(self, projection: torch.Tensor) -> torch.Tensor: """transpose projection.""" new_projection_shape = projection.size()[:-1] + (self.num_heads, -1) # move heads to 2nd position (B, T, H * D) # -> (B, T, H, D) -> (B, H, T, D) new_projection = \ projection.view(new_projection_shape).permute(0, 2, 1, 3) return new_projection def forward(self, hidden_states): """forward hidden states.""" residual = hidden_states batch, channel, height, width = hidden_states.shape # norm hidden_states = self.group_norm(hidden_states) hidden_states = hidden_states.view(batch, channel, height * width).transpose(1, 2) # proj to q, k, v query_proj = self.query(hidden_states) key_proj = self.key(hidden_states) value_proj = self.value(hidden_states) scale = 1 / math.sqrt(self.channels / self.num_heads) # get scores if self.num_heads > 1: query_states = self.transpose_for_scores(query_proj) key_states = self.transpose_for_scores(key_proj) value_states = self.transpose_for_scores(value_proj) attention_scores = torch.matmul( query_states, key_states.transpose(-1, -2)) * scale else: query_states, key_states, value_states = \ query_proj, key_proj, value_proj attention_scores = torch.baddbmm( torch.empty( query_states.shape[0], query_states.shape[1], key_states.shape[1], dtype=query_states.dtype, device=query_states.device, ), query_states, key_states.transpose(-1, -2), beta=0, alpha=scale, ) attention_probs = torch.softmax( attention_scores.float(), dim=-1).type(attention_scores.dtype) # compute attention output if self.num_heads > 1: hidden_states = torch.matmul(attention_probs, value_states) hidden_states = hidden_states.permute(0, 2, 1, 3).contiguous() new_hidden_states_shape = \ hidden_states.size()[:-2] + (self.channels,) hidden_states = hidden_states.view(new_hidden_states_shape) else: hidden_states = torch.bmm(attention_probs, value_states) # compute next hidden_states hidden_states = self.proj_attn(hidden_states) hidden_states = hidden_states.transpose(-1, -2).reshape( batch, channel, height, width) # res connect and rescale hidden_states = \ (hidden_states + residual) / self.rescale_output_factor return hidden_states class UNetMidBlock2D(nn.Module): """middle block in unet. Args: in_channels (int): input channels. temb_channels (int): time embedding channels. dropout (float): dropout rate, defaults to 0.0. num_layers (int): layer num. resnet_eps (float): resnet eps, defaults to 1e-6. resnet_time_scale_shift (str): time scale shift, defaults to 'default'. resnet_act_fn (str): act function in resnet, defaults to 'silu'. resnet_groups (int): conv groups in resnet, defaults to 32. resnet_pre_norm (bool): pre norm in resnet, defaults to True. attn_num_head_channels (int): attention head channels, defaults to 1. attention_type (str): attention type ,defaults to 'default'. output_scale_factor (float): output scale factor, defaults to 1.0. """ def __init__( self, in_channels: int, temb_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'silu', resnet_groups: int = 32, resnet_pre_norm: bool = True, attn_num_head_channels=1, attention_type='default', output_scale_factor=1.0, ): super().__init__() self.attention_type = attention_type resnet_groups = resnet_groups if resnet_groups is not None else min( in_channels // 4, 32) # noqa # there is always at least one resnet resnets = [ ResnetBlock2D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, ) ] attentions = [] for _ in range(num_layers): attentions.append( AttentionBlock( in_channels, num_head_channels=attn_num_head_channels, rescale_output_factor=output_scale_factor, eps=resnet_eps, norm_num_groups=resnet_groups, )) resnets.append( ResnetBlock2D( in_channels=in_channels, out_channels=in_channels, temb_channels=temb_channels, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.attentions = nn.ModuleList(attentions) self.resnets = nn.ModuleList(resnets) def forward(self, hidden_states, temb=None, encoder_states=None): """forward with hidden states, time embedding and encoder states.""" hidden_states = self.resnets[0](hidden_states, temb) for attn, resnet in zip(self.attentions, self.resnets[1:]): if self.attention_type == 'default': hidden_states = attn(hidden_states) else: hidden_states = attn(hidden_states, encoder_states) hidden_states = resnet(hidden_states, temb) return hidden_states class DownEncoderBlock2D(nn.Module): """Down encoder block in vae. Args: in_channels (int): input channels. out_channels (int): output channels. dropout (float): dropout rate, defaults to 0.0. num_layers (int): layer nums, defaults to 1. resnet_eps (float): resnet eps, defaults to 1e-6. resnet_time_scale_shift (str): time scale shift in resnet, defaults to 'default'. resnet_act_fn (str): act function in resnet, defaults to 'silu'. resnet_groups (int): group num in resnet, defaults to 32. resnet_pre_norm (bool): whether to pre norm in resnet, defaults to True. output_scale_factor (float): output scale factor, defaults to 1.0. add_downsample (bool): whether to add downsample, defaults to True, downsample_padding (int): downsample padding num, defaults to 1. """ def __init__( self, in_channels: int, out_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'silu', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_downsample=True, downsample_padding=1, ): super().__init__() resnets = [] for i in range(num_layers): in_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=in_channels, out_channels=out_channels, temb_channels=None, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.resnets = nn.ModuleList(resnets) if add_downsample: self.downsamplers = nn.ModuleList([ Downsample2D( out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name='op') ]) else: self.downsamplers = None def forward(self, hidden_states): """forward with hidden states.""" for resnet in self.resnets: hidden_states = resnet(hidden_states, temb=None) if self.downsamplers is not None: for downsampler in self.downsamplers: hidden_states = downsampler(hidden_states) return hidden_states class Encoder(nn.Module): """construct encoder in vae.""" def __init__( self, in_channels=3, out_channels=3, down_block_types=('DownEncoderBlock2D', ), block_out_channels=(64, ), layers_per_block=2, norm_num_groups=32, act_fn='silu', double_z=True, ): super().__init__() self.layers_per_block = layers_per_block self.conv_in = torch.nn.Conv2d( in_channels, block_out_channels[0], kernel_size=3, stride=1, padding=1) self.mid_block = None self.down_blocks = nn.ModuleList([]) # down output_channel = block_out_channels[0] for i, down_block_type in enumerate(down_block_types): input_channel = output_channel output_channel = block_out_channels[i] is_final_block = i == len(block_out_channels) - 1 down_block = DownEncoderBlock2D( num_layers=self.layers_per_block, in_channels=input_channel, out_channels=output_channel, add_downsample=not is_final_block, resnet_eps=1e-6, resnet_act_fn=act_fn, resnet_groups=norm_num_groups, downsample_padding=0, ) self.down_blocks.append(down_block) # mid self.mid_block = UNetMidBlock2D( in_channels=block_out_channels[-1], resnet_eps=1e-6, resnet_act_fn=act_fn, output_scale_factor=1, resnet_time_scale_shift='default', attn_num_head_channels=None, resnet_groups=norm_num_groups, temb_channels=None, ) # out self.conv_norm_out = nn.GroupNorm( num_channels=block_out_channels[-1], num_groups=norm_num_groups, eps=1e-6) if digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.conv_act = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.conv_act = nn.ReLU() conv_out_channels = 2 * out_channels if double_z else out_channels self.conv_out = nn.Conv2d( block_out_channels[-1], conv_out_channels, 3, padding=1) def forward(self, x): """encoder forward.""" sample = x sample = self.conv_in(sample) # down for down_block in self.down_blocks: sample = down_block(sample) # middle sample = self.mid_block(sample) # post-process sample = self.conv_norm_out(sample) sample = self.conv_act(sample) sample = self.conv_out(sample) return sample class UpDecoderBlock2D(nn.Module): """construct up decoder block.""" def __init__( self, in_channels: int, out_channels: int, dropout: float = 0.0, num_layers: int = 1, resnet_eps: float = 1e-6, resnet_time_scale_shift: str = 'default', resnet_act_fn: str = 'swish', resnet_groups: int = 32, resnet_pre_norm: bool = True, output_scale_factor=1.0, add_upsample=True, ): super().__init__() resnets = [] for i in range(num_layers): input_channels = in_channels if i == 0 else out_channels resnets.append( ResnetBlock2D( in_channels=input_channels, out_channels=out_channels, temb_channels=None, eps=resnet_eps, groups=resnet_groups, dropout=dropout, time_embedding_norm=resnet_time_scale_shift, non_linearity=resnet_act_fn, output_scale_factor=output_scale_factor, pre_norm=resnet_pre_norm, )) self.resnets = nn.ModuleList(resnets) if add_upsample: self.upsamplers = nn.ModuleList([ Upsample2D( out_channels, use_conv=True, out_channels=out_channels) ]) else: self.upsamplers = None def forward(self, hidden_states): """forward hidden states.""" for resnet in self.resnets: hidden_states = resnet(hidden_states, temb=None) if self.upsamplers is not None: for upsampler in self.upsamplers: hidden_states = upsampler(hidden_states) return hidden_states class Decoder(nn.Module): """construct decoder in vae.""" def __init__( self, in_channels=3, out_channels=3, up_block_types=('UpDecoderBlock2D', ), block_out_channels=(64, ), layers_per_block=2, norm_num_groups=32, act_fn='silu', ): super().__init__() self.layers_per_block = layers_per_block self.conv_in = nn.Conv2d( in_channels, block_out_channels[-1], kernel_size=3, stride=1, padding=1) self.mid_block = None self.up_blocks = nn.ModuleList([]) # mid self.mid_block = UNetMidBlock2D( in_channels=block_out_channels[-1], resnet_eps=1e-6, resnet_act_fn=act_fn, output_scale_factor=1, resnet_time_scale_shift='default', attn_num_head_channels=None, resnet_groups=norm_num_groups, temb_channels=None, ) # up reversed_block_out_channels = list(reversed(block_out_channels)) output_channel = reversed_block_out_channels[0] for i, up_block_type in enumerate(up_block_types): prev_output_channel = output_channel output_channel = reversed_block_out_channels[i] is_final_block = i == len(block_out_channels) - 1 up_block = UpDecoderBlock2D( num_layers=self.layers_per_block + 1, in_channels=prev_output_channel, out_channels=output_channel, add_upsample=not is_final_block, resnet_eps=1e-6, resnet_act_fn=act_fn, resnet_groups=norm_num_groups, ) self.up_blocks.append(up_block) prev_output_channel = output_channel # out self.conv_norm_out = nn.GroupNorm( num_channels=block_out_channels[0], num_groups=norm_num_groups, eps=1e-6) if digit_version(TORCH_VERSION) > digit_version('1.6.0'): self.conv_act = nn.SiLU() else: mmengine.print_log('\'SiLU\' is not supported for ' f'torch < 1.6.0, found \'{torch.version}\'.' 'Use ReLu instead but result maybe wrong') self.conv_act = nn.ReLU() self.conv_out = nn.Conv2d( block_out_channels[0], out_channels, 3, padding=1) def forward(self, z): """decoder forward.""" sample = z sample = self.conv_in(sample) # middle sample = self.mid_block(sample) # up for up_block in self.up_blocks: sample = up_block(sample) # post-process sample = self.conv_norm_out(sample) sample = self.conv_act(sample) sample = self.conv_out(sample) return sample class DiagonalGaussianDistribution(object): """Calculate diagonal gaussian distribution.""" def __init__(self, parameters, deterministic=False): self.parameters = parameters self.mean, self.logvar = torch.chunk(parameters, 2, dim=1) self.logvar = torch.clamp(self.logvar, -30.0, 20.0) self.deterministic = deterministic self.std = torch.exp(0.5 * self.logvar) self.var = torch.exp(self.logvar) if self.deterministic: self.var = self.std = torch.zeros_like( self.mean, device=self.parameters.device, dtype=self.parameters.dtype) def sample(self, generator: Optional[torch.Generator] = None) \ -> torch.FloatTensor: """sample function.""" device = self.parameters.device sample_device = device sample = torch.randn( self.mean.shape, generator=generator, device=sample_device) # make sure sample is on the same device # as the parameters and has same dtype sample = sample.to(device=device, dtype=self.parameters.dtype) x = self.mean + self.std * sample return x def kl(self, other=None): """calculate kl divergence.""" if self.deterministic: return torch.Tensor([0.0]) else: if other is None: return 0.5 * torch.sum( torch.pow(self.mean, 2) + self.var - 1.0 - self.logvar, dim=[1, 2, 3]) else: return 0.5 * torch.sum( torch.pow(self.mean - other.mean, 2) / other.var + self.var / other.var - 1.0 - self.logvar + other.logvar, dim=[1, 2, 3], ) def nll(self, sample, dims=[1, 2, 3]): """calculate negative log likelihood.""" if self.deterministic: return torch.Tensor([0.0]) logtwopi = np.log(2.0 * np.pi) return 0.5 * torch.sum( logtwopi + self.logvar + torch.pow(sample - self.mean, 2) / self.var, dim=dims) # noqa def mode(self): """return self.mean.""" return self.mean @MODELS.register_module('EditAutoencoderKL') class AutoencoderKL(nn.Module): r"""Variational Autoencoder (VAE) model with KL loss from the paper Auto-Encoding Variational Bayes by Diederik P. Kingma and Max Welling. Args: in_channels (int, *optional*, defaults to 3): Number of channels in the input image. out_channels (int, *optional*, defaults to 3): Number of channels in the output. down_block_types (`Tuple[str]`, *optional*, defaults to : obj:`("DownEncoderBlock2D",)`): Tuple of downsample block types. up_block_types (`Tuple[str]`, *optional*, defaults to : obj:`("UpDecoderBlock2D",)`): Tuple of upsample block types. block_out_channels (`Tuple[int]`, *optional*, defaults to : obj:`(64,)`): Tuple of block output channels. act_fn (`str`, *optional*, defaults to `"silu"`): The activation function to use. latent_channels (`int`, *optional*, defaults to `4`): Number of channels in the latent space. sample_size (`int`, *optional*, defaults to `32`): sample size is now not supported. """ def __init__( self, in_channels: int = 3, out_channels: int = 3, down_block_types: Tuple[str] = ('DownEncoderBlock2D', ), up_block_types: Tuple[str] = ('UpDecoderBlock2D', ), block_out_channels: Tuple[int] = (64, ), layers_per_block: int = 1, act_fn: str = 'silu', latent_channels: int = 4, norm_num_groups: int = 32, sample_size: int = 32, ): super().__init__() self.block_out_channels = block_out_channels self.latent_channels = latent_channels # pass init params to Encoder self.encoder = Encoder( in_channels=in_channels, out_channels=latent_channels, down_block_types=down_block_types, block_out_channels=block_out_channels, layers_per_block=layers_per_block, act_fn=act_fn, norm_num_groups=norm_num_groups, double_z=True, ) # pass init params to Decoder self.decoder = Decoder( in_channels=latent_channels, out_channels=out_channels, up_block_types=up_block_types, block_out_channels=block_out_channels, layers_per_block=layers_per_block, norm_num_groups=norm_num_groups, act_fn=act_fn, ) self.quant_conv = torch.nn.Conv2d(2 * latent_channels, 2 * latent_channels, 1) self.post_quant_conv = torch.nn.Conv2d(latent_channels, latent_channels, 1) @property def dtype(self): """The data type of the parameters of VAE.""" return next(self.parameters()).dtype def encode(self, x: torch.FloatTensor, return_dict: bool = True) -> Dict: """encode input.""" h = self.encoder(x) moments = self.quant_conv(h) posterior = DiagonalGaussianDistribution(moments) if not return_dict: return (posterior, ) return Dict(latent_dist=posterior) def decode(self, z: torch.FloatTensor, return_dict: bool = True) \ -> Union[Dict, torch.FloatTensor]: """decode z.""" z = self.post_quant_conv(z) dec = self.decoder(z) if not return_dict: return (dec, ) return Dict(sample=dec) def forward( self, sample: torch.FloatTensor, sample_posterior: bool = False, return_dict: bool = True, generator: Optional[torch.Generator] = None, ) -> Union[Dict, torch.FloatTensor]: """ Args: sample (torch.FloatTensor): Input sample. sample_posterior (bool): Whether to sample from the posterior. defaults to `False`. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`Dict`] instead of a plain tuple. Returns: Dict(sample=dec): decode results. """ x = sample posterior = self.encode(x).latent_dist if sample_posterior: z = posterior.sample(generator=generator) else: z = posterior.mode() dec = self.decode(z).sample if not return_dict: return (dec, ) return Dict(sample=dec) ================================================ FILE: mmagic/models/editors/stable_diffusion_xl/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .stable_diffusion_xl import StableDiffusionXL __all__ = ['StableDiffusionXL'] ================================================ FILE: mmagic/models/editors/stable_diffusion_xl/stable_diffusion_xl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import inspect from copy import deepcopy from typing import Dict, List, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import print_log from mmengine.logging import MMLogger from mmengine.model import BaseModel from mmengine.optim import OptimWrapperDict from mmengine.runner import set_random_seed from PIL import Image from tqdm.auto import tqdm from mmagic.models.archs import TokenizerWrapper, set_lora from mmagic.models.utils import build_module, set_tomesd, set_xformers from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList logger = MMLogger.get_current_instance() ModelType = Union[Dict, nn.Module] @MODELS.register_module('sdxl') @MODELS.register_module() class StableDiffusionXL(BaseModel): """Class for Stable Diffusion XL. Refers to https://github.com/Stability- AI. /generative-models and https://github.com/huggingface/diffusers/blob/main/ src/diffusers/pipelines/stable_diffusion_xl/pipeline_stable_diffusion_xl.py Args: unet (Union[dict, nn.Module]): The config or module for Unet model. text_encoder_one (Union[dict, nn.Module]): The config or module for text encoder. tokenizer_one (str): The **name** for CLIP tokenizer. text_encoder_two (Union[dict, nn.Module]): The config or module for text encoder. tokenizer_two (str): The **name** for CLIP tokenizer. vae (Union[dict, nn.Module]): The config or module for VAE model. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. dtype (str, optional): The dtype for the model This argument will not work when dtype is defined for submodels. Defaults to None. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise Defaults to 0. tomesd_cfg (dict, optional): The config for TOMESD. Please refers to https://github.com/dbolya/tomesd and https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/utils/tome_utils.py for detail. # noqa Defaults to None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. lora_config (dict, optional): The config for LoRA finetuning. Defaults to None. val_prompts (Union[str, List[str]], optional): The prompts for validation. Defaults to None. finetune_text_encoder (bool, optional): Whether to fine-tune text encoder. Defaults to False. force_zeros_for_empty_prompt (bool): Whether the negative prompt embeddings shall be forced to always be set to 0. Defaults to True. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. """ def __init__(self, vae: ModelType, text_encoder_one: ModelType, tokenizer_one: str, text_encoder_two: ModelType, tokenizer_two: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: Optional[str] = None, enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), lora_config: Optional[dict] = None, val_prompts: Union[str, List[str]] = None, finetune_text_encoder: bool = False, force_zeros_for_empty_prompt: bool = True, init_cfg: Optional[dict] = None): # TODO: support `from_pretrained` for this class super().__init__(data_preprocessor, init_cfg) default_args = dict() if dtype is not None: default_args['dtype'] = dtype self.dtype = torch.float32 if dtype in ['float16', 'fp16', 'half']: self.dtype = torch.float16 elif dtype == 'bf16': self.dtype = torch.bfloat16 else: assert dtype in [ 'fp32', None ], ('dtype must be one of \'fp32\', \'fp16\', \'bf16\' or None.') self.vae = build_module(vae, MODELS, default_args=default_args) self.unet = build_module(unet, MODELS) # NOTE: initialize unet as fp32 self._unet_ori_dtype = next(self.unet.parameters()).dtype print_log(f'Set UNet dtype to \'{self._unet_ori_dtype}\'.', 'current') self.scheduler = build_module(scheduler, DIFFUSION_SCHEDULERS) if test_scheduler is None: self.test_scheduler = deepcopy(self.scheduler) else: self.test_scheduler = build_module(test_scheduler, DIFFUSION_SCHEDULERS) self.text_encoder_one = build_module(text_encoder_one, MODELS) if not isinstance(tokenizer_one, str): self.tokenizer_one = tokenizer_one else: # NOTE: here we assume tokenizer is an string self.tokenizer_one = TokenizerWrapper( tokenizer_one, subfolder='tokenizer') self.text_encoder_two = build_module(text_encoder_two, MODELS) if not isinstance(tokenizer_two, str): self.tokenizer_two = tokenizer_two else: # NOTE: here we assume tokenizer is an string self.tokenizer_two = TokenizerWrapper( tokenizer_two, subfolder='tokenizer_2') self.unet_sample_size = self.unet.sample_size self.vae_scale_factor = 2**(len(self.vae.block_out_channels) - 1) self.enable_noise_offset = noise_offset_weight > 0 self.noise_offset_weight = noise_offset_weight self.finetune_text_encoder = finetune_text_encoder self.val_prompts = val_prompts self.lora_config = deepcopy(lora_config) self.force_zeros_for_empty_prompt = force_zeros_for_empty_prompt self.prepare_model() self.set_lora() self.enable_xformers = enable_xformers self.set_xformers() self.tomesd_cfg = tomesd_cfg self.set_tomesd() def prepare_model(self): """Prepare model for training. Move model to target dtype and disable gradient for some models. """ self.vae.requires_grad_(False) print_log('Set VAE untrainable.', 'current') self.vae.to(self.dtype) print_log(f'Move VAE to {self.dtype}.', 'current') if not self.finetune_text_encoder or self.lora_config: self.text_encoder_one.requires_grad_(False) self.text_encoder_two.requires_grad_(False) print_log('Set Text Encoder untrainable.', 'current') self.text_encoder_one.to(self.dtype) self.text_encoder_two.to(self.dtype) print_log(f'Move Text Encoder to {self.dtype}.', 'current') if self.lora_config: self.unet.requires_grad_(False) print_log('Set Unet untrainable.', 'current') def set_lora(self): """Set LORA for model.""" if self.lora_config: set_lora(self.unet, self.lora_config) def set_xformers(self, module: Optional[nn.Module] = None) -> nn.Module: """Set xformers for the model. Returns: nn.Module: The model with xformers. """ if self.enable_xformers: if module is None: set_xformers(self) else: set_xformers(module) def set_tomesd(self) -> nn.Module: """Set ToMe for the stable diffusion model. Returns: nn.Module: The model with ToMe. """ if self.tomesd_cfg is not None: set_tomesd(self, **self.tomesd_cfg) @property def device(self): return next(self.parameters()).device def train(self, mode: bool = True): """Set train/eval mode. Args: mode (bool, optional): Whether set train mode. Defaults to True. """ if mode: if next(self.unet.parameters()).dtype != self._unet_ori_dtype: print_log( f'Set UNet dtype to \'{self._unet_ori_dtype}\' ' 'in the train mode.', 'current') self.unet.to(self._unet_ori_dtype) else: self.unet.to(self.dtype) print_log(f'Set UNet dtype to \'{self.dtype}\' in the eval mode.', 'current') return super().train(mode) @torch.no_grad() def infer(self, prompt: Union[str, List[str]], prompt_2: Optional[Union[str, List[str]]] = None, height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, denoising_end: Optional[float] = None, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, negative_prompt_2: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, show_progress: bool = True, seed: int = 1, original_size: Optional[Tuple[int, int]] = None, crops_coords_top_left: Tuple[int, int] = (0, 0), target_size: Optional[Tuple[int, int]] = None, negative_original_size: Optional[Tuple[int, int]] = None, negative_crops_coords_top_left: Tuple[int, int] = (0, 0), negative_target_size: Optional[Tuple[int, int]] = None, return_type='image'): """Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`): The prompt or prompts to guide the image generation. prompt2 (`str` or `List[str]`, *optional*): The prompt or prompts to be sent to the `tokenizer_two` and `text_encoder_two`. If not defined, `prompt` is used in both text-encoders. Defaults to None. height (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The height in pixels of the generated image. width (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The width in pixels of the generated image. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. denoising_end (`float`, *optional*): When specified, determines the fraction (between 0.0 and 1.0) of the total denoising process to be completed before it is intentionally prematurely terminated. As a result, the returned sample will still retain a substantial amount of noise as determined by the discrete timesteps selected by the scheduler. The denoising_end parameter should ideally be utilized when this pipeline forms a part of a "Mixture of Denoisers" multi-pipeline setup, as elaborated in [**Refining the Image Output**]( https://huggingface.co/docs/diffusers/api/pipelines/ stable_diffusion/stable_diffusion_xl#refining-the-image-output) guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance] (https://arxiv.org/abs/2207.12598). negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). negative_prompt_2 (`str` or `List[str]`, *optional*)): The `negative_prompt` to be sent to the `tokenizer_two` and `text_encoder_two`. If not defined, `negative_prompt` is used in both text-encoders. Defaults to None. num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator`, *optional*): A [torch generator] to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. show_progress (bool): Whether to show progress. Defaults to False. seed (int): Seed to be used. Defaults to 1. original_size (`Tuple[int]`, *optional*): If `original_size` is not the same as `target_size` the image will appear to be down- or upsampled. If `original_size` is `(width, height)` if not specified. Defaults to None. crops_coords_top_left (`Tuple[int]`, *optional*): `crops_coords_top_left` can be used to generate an image that appears to be "cropped" from the position. Favorable, well-centered images are usually achieved by setting `crops_coords_top_left` to (0, 0). Defaults to (0, 0). target_size (`Tuple[int]`, *optional*): For most cases, `target_size` should be set to the desired height and width of the generated image. If not specified it will be `(width, height)`. Defaults to None. negative_original_size (`Tuple[int]`, *optional*): To negatively condition the generation process based on a specific image resolution. For more information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208. Defaults to None. negative_crops_coords_top_left (`Tuple[int]`, *optional*): To negatively condition the generation process based on a specific crop coordinates. For more information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208. Defaults to (0, 0). negative_target_size (`Tuple[int]`, *optional*): To negatively condition the generation process based on a target image resolution. It should be as same as the `target_size` for most cases. For more information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208. Defaults to None. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images. """ assert return_type in ['image', 'tensor', 'numpy'] set_random_seed(seed=seed) # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor original_size = original_size or (height, width) target_size = target_size or (height, width) # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device img_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype latent_dtype = next(self.unet.parameters()).dtype # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt ( prompt_embeds, negative_prompt_embeds, pooled_prompt_embeds, negative_pooled_prompt_embeds, ) = self._encode_prompt(prompt, prompt_2, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt, negative_prompt_2) # 4. Prepare timesteps self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare latent variables if hasattr(self.unet, 'module'): num_channels_latents = self.unet.module.in_channels else: num_channels_latents = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, prompt_embeds.dtype, device, generator, latents, ) # 6. Prepare extra step kwargs. # TODO: Logic should ideally just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7. Prepare added time ids & embeddings add_text_embeds = pooled_prompt_embeds add_time_ids = self._get_add_time_ids( original_size, crops_coords_top_left, target_size, dtype=prompt_embeds.dtype) if (negative_original_size is not None) and (negative_target_size is not None): negative_add_time_ids = self._get_add_time_ids( negative_original_size, negative_crops_coords_top_left, negative_target_size, dtype=prompt_embeds.dtype, ) else: negative_add_time_ids = add_time_ids if do_classifier_free_guidance: prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds], dim=0) add_text_embeds = torch.cat( [negative_pooled_prompt_embeds, add_text_embeds], dim=0) add_time_ids = torch.cat([negative_add_time_ids, add_time_ids], dim=0) prompt_embeds = prompt_embeds.to(device) add_text_embeds = add_text_embeds.to(device) add_time_ids = add_time_ids.to(device).repeat( batch_size * num_images_per_prompt, 1) # 9 Apply denoising_end if denoising_end is not None and isinstance( denoising_end, float) and denoising_end > 0 and denoising_end < 1: discrete_timestep_cutoff = int( round(self.scheduler.config.num_train_timesteps - (denoising_end * self.scheduler.config.num_train_timesteps))) num_inference_steps = len( list( filter(lambda ts: ts >= discrete_timestep_cutoff, timesteps))) timesteps = timesteps[:num_inference_steps] # 10. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.test_scheduler.scale_model_input( latent_model_input, t) latent_model_input = latent_model_input.to(latent_dtype) prompt_embeds = prompt_embeds.to(latent_dtype) # predict the noise residual added_cond_kwargs = { 'text_embeds': add_text_embeds, 'time_ids': add_time_ids } noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=prompt_embeds, added_cond_kwargs=added_cond_kwargs, return_dict=False, )[0] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.test_scheduler.step( noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if return_type == 'image': image = self.output_to_pil(image) elif return_type == 'numpy': image = image.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image} def _get_add_time_ids(self, original_size: Optional[Tuple[int, int]], crops_coords_top_left: Tuple[int, int], target_size: Optional[Tuple[int, int]], dtype): """Get `add_time_ids`. Args: original_size (`Tuple[int]`, *optional*): If `original_size` is not the same as `target_size` the image will appear to be down- or upsampled. If `original_size` is `(width, height)` if not specified. Defaults to None. crops_coords_top_left (`Tuple[int]`, *optional*): `crops_coords_top_left` can be used to generate an image that appears to be "cropped" from the position. Favorable, well-centered images are usually achieved by setting `crops_coords_top_left` to (0, 0). Defaults to (0, 0). target_size (`Tuple[int]`, *optional*): For most cases, `target_size` should be set to the desired height and width of the generated image. If not specified it will be `(width, height)`. Defaults to None. dtype (str, optional): The dtype for the embeddings. Returns: add_time_ids (torch.Tensor): time ids for time embeddings layer. """ add_time_ids = list(original_size + crops_coords_top_left + target_size) passed_add_embed_dim = ( self.unet.config.addition_time_embed_dim * len(add_time_ids) + self.text_encoder_two.config.projection_dim) expected_add_embed_dim = self.unet.add_embedding.linear_1.in_features if expected_add_embed_dim != passed_add_embed_dim: raise ValueError( 'Model expects an added time embedding vector of length ' f'{expected_add_embed_dim}, but a vector of ' f'{passed_add_embed_dim} was created. The model has an ' 'incorrect config. Please check ' '`unet.config.time_embedding_type` and ' '`text_encoder_2.config.projection_dim`.') add_time_ids = torch.tensor([add_time_ids], dtype=dtype) return add_time_ids def output_to_pil(self, image) -> List[Image.Image]: """Convert output tensor to PIL image. Output tensor will be de-normed to [0, 255] by `DataPreprocessor.destruct`. Due to no `data_samples` is passed, color order conversion will not be performed. Args: image (torch.Tensor): The output tensor of the decoder. Returns: List[Image.Image]: The list of processed PIL images. """ image = self.data_preprocessor.destruct(image) image = image.permute(0, 2, 3, 1).to(torch.uint8).cpu().numpy() image = [Image.fromarray(img) for img in image] return image def _encode_prompt(self, prompt, prompt_2, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt, negative_prompt_2): """Encodes the prompt into text encoder hidden states. Args: prompt (str or list(int)): prompt to be encoded. prompt_2 (str or list(int)): prompt to be encoded. Send to the `tokenizer_two` and `text_encoder_two`. If not defined, `prompt` is used in both text-encoders. device: (torch.device): torch device. num_images_per_prompt (int): number of images that should be generated per prompt. do_classifier_free_guidance (`bool`): whether to use classifier free guidance or not. negative_prompt (str or List[str]): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). negative_prompt_2 (str or List[str]): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). Send to `tokenizer_two` and `text_encoder_two`. If not defined, `negative_prompt` is used in both text-encoders Returns: text_embeddings (torch.Tensor): text embeddings generated by clip text encoder. """ batch_size = len(prompt) if isinstance(prompt, list) else 1 prompt_2 = prompt_2 or prompt tokenizers = [self.tokenizer_one, self.tokenizer_two] text_encoders = [self.text_encoder_one, self.text_encoder_two] prompts = [prompt, prompt_2] prompt_embeds_list = [] for tokenizer, text_encoder, prompt in zip(tokenizers, text_encoders, prompts): text_inputs = tokenizer( prompt, padding='max_length', max_length=tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_input_ids = text_inputs.input_ids untruncated_ids = tokenizer( prompt, padding='max_length', return_tensors='pt').input_ids if not torch.equal(text_input_ids, untruncated_ids): removed_text = tokenizer.batch_decode( untruncated_ids[:, tokenizer.model_max_length - 1:-1]) logger.warning( 'The following part of your input was truncated because ' ' CLIP can only handle sequences up to' f' {tokenizer.model_max_length} tokens: {removed_text}') text_encoder = text_encoder.module if hasattr( text_encoder, 'module') else text_encoder text_embeddings = text_encoder( text_input_ids.to(device), output_hidden_states=True, ) pooled_prompt_embeds = text_embeddings.pooler_output text_embeddings = text_embeddings.hidden_states[-2] prompt_embeds_list.append(text_embeddings) text_embeddings = torch.concat(prompt_embeds_list, dim=-1) # duplicate text embeddings for each generation per prompt, bs_embed, seq_len, _ = text_embeddings.shape text_embeddings = text_embeddings.repeat(1, num_images_per_prompt, 1) text_embeddings = text_embeddings.view( bs_embed * num_images_per_prompt, seq_len, -1) # get unconditional embeddings for classifier free guidance if do_classifier_free_guidance and self.force_zeros_for_empty_prompt: negative_prompt_embeds = torch.zeros_like(text_embeddings) negative_pooled_prompt_embeds = torch.zeros_like( pooled_prompt_embeds) elif do_classifier_free_guidance: negative_prompt = negative_prompt or '' negative_prompt_2 = negative_prompt_2 or negative_prompt uncond_tokens: List[str] if prompt is not None and type(prompt) is not type( negative_prompt): raise TypeError( '`negative_prompt` should be the same type to `prompt`, ' f'but got {type(negative_prompt)} != {type(prompt)}.') elif isinstance(negative_prompt, str): uncond_tokens = [negative_prompt, negative_prompt_2] elif batch_size != len(negative_prompt): raise ValueError( f'`negative_prompt`: {negative_prompt} has batch size ' f'{len(negative_prompt)}, but `prompt`: {prompt} has batch' f' size {batch_size}. Please make sure that passed ' '`negative_prompt` matches the batch size of `prompt`.') else: uncond_tokens = [negative_prompt, negative_prompt_2] negative_prompt_embeds_list = [] for negative_prompt, tokenizer, text_encoder in zip( uncond_tokens, tokenizers, text_encoders): max_length = text_embeddings.shape[1] uncond_input = tokenizer( negative_prompt, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) negative_prompt_embeds = text_encoder( uncond_input.input_ids.to(device), output_hidden_states=True, ) # We are only ALWAYS interested in the pooled output of the # final text encoder negative_pooled_prompt_embeds = ( negative_prompt_embeds.pooler_output) negative_prompt_embeds = negative_prompt_embeds.hidden_states[ -2] negative_prompt_embeds_list.append(negative_prompt_embeds) negative_prompt_embeds = torch.concat( negative_prompt_embeds_list, dim=-1) bs_embed, seq_len, _ = text_embeddings.shape # duplicate text embeddings for each generation per prompt, using mps # friendly method text_embeddings = text_embeddings.repeat(1, num_images_per_prompt, 1) text_embeddings = text_embeddings.view( bs_embed * num_images_per_prompt, seq_len, -1) if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation per prompt # ,using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.repeat( 1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view( batch_size * num_images_per_prompt, seq_len, -1) pooled_prompt_embeds = pooled_prompt_embeds.repeat( 1, num_images_per_prompt).view(bs_embed * num_images_per_prompt, -1) if do_classifier_free_guidance: negative_pooled_prompt_embeds = ( negative_pooled_prompt_embeds.repeat( 1, num_images_per_prompt).view( bs_embed * num_images_per_prompt, -1)) return (text_embeddings, negative_prompt_embeds, pooled_prompt_embeds, negative_pooled_prompt_embeds) def decode_latents(self, latents): """use vae to decode latents. Args: latents (torch.Tensor): latents to decode. Returns: image (torch.Tensor): image result. """ latents = 1 / 0.18215 * latents if hasattr(self.vae, 'module'): image = self.vae.module.decode(latents)['sample'] else: image = self.vae.decode(latents)['sample'] # we always cast to float32 as this does not cause # significant overhead and is compatible with bfloa16 return image.float() def prepare_extra_step_kwargs(self, generator, eta): """prepare extra kwargs for the scheduler step. Args: generator (torch.Generator): generator for random functions. eta (float): eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers. eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 and should be between [0, 1] Return: extra_step_kwargs (dict): dict contains 'generator' and 'eta' """ accepts_eta = 'eta' in set( inspect.signature(self.scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def prepare_test_scheduler_extra_step_kwargs(self, generator, eta): """prepare extra kwargs for the scheduler step. Args: generator (torch.Generator): generator for random functions. eta (float): eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers. eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 and should be between [0, 1] Return: extra_step_kwargs (dict): dict contains 'generator' and 'eta' """ accepts_eta = 'eta' in set( inspect.signature(self.test_scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.test_scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def check_inputs(self, prompt, height, width): """check whether inputs are in suitable format or not.""" if not isinstance(prompt, str) and not isinstance(prompt, list): raise ValueError(f'`prompt` has to be of ' f'type `str` or `list` but is {type(prompt)}') if height % 8 != 0 or width % 8 != 0: raise ValueError(f'`height` and `width` have to be divisible ' f'by 8 but are {height} and {width}.') def prepare_latents(self, batch_size, num_channels_latents, height, width, dtype, device, generator, latents=None): """prepare latents for diffusion to run in latent space. Args: batch_size (int): batch size. num_channels_latents (int): latent channel nums. height (int): image height. width (int): image width. dtype (torch.dtype): float type. device (torch.device): torch device. generator (torch.Generator): generator for random functions, defaults to None. latents (torch.Tensor): Pre-generated noisy latents, defaults to None. Return: latents (torch.Tensor): prepared latents. """ shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) if latents is None: latents = torch.randn( shape, generator=generator, device=device, dtype=dtype) else: if latents.shape != shape: raise ValueError(f'Unexpected latents shape, ' f'got {latents.shape}, expected {shape}') latents = latents.to(device) # scale the initial noise by the standard # deviation required by the scheduler latents = latents * self.scheduler.init_noise_sigma return latents @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: Generated image or image dict. """ if self.val_prompts is None: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples = DataSample.stack(data['data_samples'] * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) if self.val_prompts is None: gt_img = self.data_preprocessor.destruct(data['inputs'], data_samples) out_data_sample = DataSample( fake_img=samples, gt_img=gt_img, prompt=prompt) else: out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ if self.val_prompts is None: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples = DataSample.stack(data['data_samples'] * len(prompt)) output = self.infer(prompt, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) if self.val_prompts is None: gt_img = self.data_preprocessor.destruct(data['inputs'], data_samples) out_data_sample = DataSample( fake_img=samples, gt_img=gt_img, prompt=prompt) else: out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list def encode_prompt_train(self, text_one, text_two): """Encode prompt for training. Args: text_one (torch.tensor): Input ids from tokenizer_one. text_two (torch.tensor): Input ids from tokenizer_two. Returns: prompt_embeds (torch.tensor): Prompt embedings. pooled_prompt_embeds (torch.tensor): Pooled prompt embeddings. """ prompt_embeds_list = [] text_encoders = [self.text_encoder_one, self.text_encoder_two] texts = [text_one, text_two] for text_encoder, text in zip(text_encoders, texts): prompt_embeds = text_encoder( text, output_hidden_states=True, ) # We are only ALWAYS interested in the pooled output of the # final text encoder pooled_prompt_embeds = prompt_embeds.pooler_output prompt_embeds = prompt_embeds.hidden_states[-2] bs_embed, seq_len, _ = prompt_embeds.shape prompt_embeds = prompt_embeds.view(bs_embed, seq_len, -1) prompt_embeds_list.append(prompt_embeds) prompt_embeds = torch.concat(prompt_embeds_list, dim=-1) pooled_prompt_embeds = pooled_prompt_embeds.view(bs_embed, -1) return prompt_embeds, pooled_prompt_embeds def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict): """Train step function. Args: data (List[dict]): Batch of data as input. optim_wrapper (OptimWrapperDict): Dict with optimizers for generator and discriminator (if have). Returns: dict: Dict with loss, information for logger, the number of \ samples and results for visualization. """ data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] vae = self.vae.module if hasattr(self.vae, 'module') else self.vae with optim_wrapper.optim_context(self.unet): image = inputs prompt = data_samples.prompt num_batches = image.shape[0] image = image.to(self.dtype) latents = vae.encode(image).latent_dist.sample() latents = latents * vae.config.scaling_factor noise = torch.randn_like(latents) if self.enable_noise_offset: noise = noise + self.noise_offset_weight * torch.randn( latents.shape[0], latents.shape[1], 1, 1, device=noise.device) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) input_ids_one = self.tokenizer_one( prompt, max_length=self.tokenizer_one.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) input_ids_two = self.tokenizer_two( prompt, max_length=self.tokenizer_two.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) (encoder_hidden_states, pooled_prompt_embeds) = self.encode_prompt_train( input_ids_one, input_ids_two) unet_added_conditions = { 'time_ids': data['time_ids'], 'text_embeds': pooled_prompt_embeds } if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') # NOTE: we train unet in fp32, convert to float manually model_output = self.unet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float(), added_cond_kwargs=unet_added_conditions) model_pred = model_output['sample'] loss_dict = dict() # calculate loss in FP32 loss_mse = F.mse_loss(model_pred.float(), gt.float()) loss_dict['loss_mse'] = loss_mse parsed_loss, log_vars = self.parse_losses(loss_dict) optim_wrapper.update_params(parsed_loss) return log_vars def forward(self, inputs: torch.Tensor, data_samples: Optional[list] = None, mode: str = 'tensor') -> Union[Dict[str, torch.Tensor], list]: """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') ================================================ FILE: mmagic/models/editors/stylegan1/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .stylegan1 import StyleGAN1 from .stylegan1_discriminator import StyleGAN1Discriminator from .stylegan1_generator import StyleGAN1Generator from .stylegan1_modules import (Blur, ConstantInput, EqualLinearActModule, NoiseInjection, make_kernel) from .stylegan_utils import get_mean_latent, style_mixing __all__ = [ 'Blur', 'ConstantInput', 'EqualLinearActModule', 'make_kernel', 'StyleGAN1', 'StyleGAN1Discriminator', 'StyleGAN1Generator', 'get_mean_latent', 'style_mixing', 'NoiseInjection' ] ================================================ FILE: mmagic/models/editors/stylegan1/stylegan1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Tuple, Union import torch import torch.autograd as autograd import torch.nn as nn import torch.nn.functional as F from mmengine import Config from torch import Tensor from mmagic.registry import MODELS from ..pggan import ProgressiveGrowingGAN ModelType = Union[Dict, nn.Module] TrainInput = Union[dict, Tensor] @MODELS.register_module('StyleGANV1') @MODELS.register_module('StyleGANv1') @MODELS.register_module() class StyleGAN1(ProgressiveGrowingGAN): """Implementation of `A Style-Based Generator Architecture for Generative Adversarial Networks`. `_ # noqa (StyleGANv1). This class is inherited from :class:`~ProgressiveGrowingGAN` to support progressive training. Detailed architecture can be found in :class:`~mmagic.models.editors.stylegan1.StyleGAN1Generator` and :class:`~mmagic.models.editors.stylegan1.StyleGAN1Discriminator` Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. style_channels (int): The number of channels for style code. Defaults to 128. nkimgs_per_scale (dict): The number of images need for each resolution's training. Defaults to `{}`. intep_real (dict, optional): The config of interpolation method for real images. If not passed, bilinear interpolation with align_corners will be used. Defaults to None. transition_kimgs (int, optional): The number of images during used to transit from the previous torgb layer to newer torgb layer. Defaults to 600. prev_stage (int, optional): The resolution of previous stage. Used for resume training. Defaults to 0. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, style_channels: int = 512, nkimgs_per_scale: dict = {}, interp_real: Optional[dict] = None, transition_kimgs: int = 600, prev_stage: int = 0, ema_config: Optional[Dict] = None): # get valid style_channels if isinstance(generator, dict): model_style_channels = generator.get('style_channels', None) else: model_style_channels = getattr(generator, 'style_channels', None) if style_channels is not None and model_style_channels is not None: assert style_channels == model_style_channels, ( 'Input \'style_channels\' is inconsistent with ' f'\'generator.style_channels\'. Receive \'{style_channels}\' ' f'and \'{model_style_channels}\'.') else: style_channels = style_channels or model_style_channels super().__init__(generator, discriminator, data_preprocessor, nkimgs_per_scale, None, interp_real, transition_kimgs, prev_stage, ema_config) self.noise_size = style_channels def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor, fake_data: Tensor, real_data: Tensor) -> Tuple[Tensor, dict]: r"""Get disc loss. StyleGANv1 use non-saturating gan loss and R1 gradient penalty. loss to train the discriminator. .. math: L_{D} = \mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) - \mathbb{E}_{x\sim{p_{data}}}D\left\(x\right\) + L_{GP} \\ L_{GP} = \lambda\mathbb{E}(\Vert\nabla_{\tilde{x}}D(\tilde{x}) \Vert_2-1)^2 \\ \tilde{x} = \epsilon x + (1-\epsilon)G(z) L_{shift} = Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. fake_data (Tensor): Generated images, used to calculate gradient penalty. real_data (Tensor): Real images, used to calculate gradient penalty. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = F.softplus(disc_pred_fake).mean() losses_dict['loss_disc_real'] = F.softplus(-disc_pred_real).mean() # R1 gradient penalty batch_size = real_data.size(0) real_data_ = real_data.clone().requires_grad_() disc_pred = self.discriminator( real_data_, curr_scale=self.curr_scale[0], transition_weight=self._curr_transition_weight) gradients = autograd.grad( outputs=disc_pred, inputs=real_data_, grad_outputs=torch.ones_like(disc_pred), create_graph=True, retain_graph=True, only_inputs=True)[0] # norm_mode is 'HWC' gradients_penalty = gradients.pow(2).reshape(batch_size, -1).sum(1).mean() losses_dict['loss_r1_gp'] = 10 * gradients_penalty parsed_loss, log_vars = self.parse_losses(losses_dict) return parsed_loss, log_vars def gen_loss(self, disc_pred_fake: Tensor) -> Tuple[Tensor, dict]: r"""Generator loss for PGGAN. PGGAN use WGAN's loss to train the generator. .. math: L_{G} = -\mathbb{E}_{z\sim{p_{z}}}D\left\(G\left\(z\right\)\right\) + L_{MSE} Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: Tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_vars = self.parse_losses(losses_dict) return loss, log_vars ================================================ FILE: mmagic/models/editors/stylegan1/stylegan1_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from ..pggan import (EqualizedLRConvDownModule, EqualizedLRConvModule, MiniBatchStddevLayer) from .stylegan1_modules import Blur, EqualLinearActModule @MODELS.register_module('StyleGANv1Discriminator') @MODELS.register_module() class StyleGAN1Discriminator(BaseModule): """StyleGAN1 Discriminator. The architecture of this discriminator is proposed in StyleGAN1. More details can be found in: A Style-Based Generator Architecture for Generative Adversarial Networks CVPR2019. Args: in_size (int): The input size of images. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 2, 1]. mbstd_cfg (dict, optional): Configs for minibatch-stddev layer. Defaults to dict(group_size=4). """ def __init__(self, in_size, blur_kernel=[1, 2, 1], mbstd_cfg=dict(group_size=4)): super().__init__() self.with_mbstd = mbstd_cfg is not None channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256, 128: 128, 256: 64, 512: 32, 1024: 16, } log_size = int(np.log2(in_size)) self.log_size = log_size in_channels = channels[in_size] self.convs = nn.ModuleList() self.from_rgb = nn.ModuleList() for i in range(log_size, 2, -1): out_channel = channels[2**(i - 1)] self.from_rgb.append( EqualizedLRConvModule( 3, in_channels, kernel_size=3, padding=1, act_cfg=dict(type='LeakyReLU', negative_slope=0.2))) self.convs.append( nn.Sequential( EqualizedLRConvModule( in_channels, out_channel, kernel_size=3, padding=1, bias=True, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), Blur(blur_kernel, pad=(1, 1)), EqualizedLRConvDownModule( out_channel, out_channel, kernel_size=3, stride=2, padding=1, act_cfg=None), nn.LeakyReLU(negative_slope=0.2, inplace=True))) in_channels = out_channel self.from_rgb.append( EqualizedLRConvModule( 3, in_channels, kernel_size=3, padding=0, act_cfg=dict(type='LeakyReLU', negative_slope=0.2))) self.convs.append( nn.Sequential( EqualizedLRConvModule( in_channels + 1, 512, kernel_size=3, padding=1, bias=True, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), EqualizedLRConvModule( 512, 512, kernel_size=4, padding=0, bias=True, norm_cfg=None, act_cfg=None), )) if self.with_mbstd: self.mbstd_layer = MiniBatchStddevLayer(**mbstd_cfg) self.final_linear = nn.Sequential(EqualLinearActModule(channels[4], 1)) self.n_layer = len(self.convs) def forward(self, input, transition_weight=1., curr_scale=-1): """Forward function. Args: input (torch.Tensor): Input image tensor. transition_weight (float, optional): The weight used in resolution transition. Defaults to 1.. curr_scale (int, optional): The resolution scale of image tensor. -1 means the max resolution scale of the StyleGAN1. Defaults to -1. Returns: torch.Tensor: Predict score for the input image. """ curr_log_size = self.log_size if curr_scale < 0 else int( np.log2(curr_scale)) step = curr_log_size - 2 for i in range(step, -1, -1): index = self.n_layer - i - 1 if i == step: out = self.from_rgb[index](input) # minibatch standard deviation if i == 0: out = self.mbstd_layer(out) out = self.convs[index](out) if i > 0: if i == step and 0 <= transition_weight < 1: skip_rgb = F.avg_pool2d(input, 2) skip_rgb = self.from_rgb[index + 1](skip_rgb) out = (1 - transition_weight ) * skip_rgb + transition_weight * out out = out.view(out.shape[0], -1) out = self.final_linear(out) return out ================================================ FILE: mmagic/models/editors/stylegan1/stylegan1_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random import mmengine import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS from ...utils import get_module_device from ..pggan import EqualizedLRConvModule, PixelNorm from .stylegan1_modules import EqualLinearActModule, StyleConv from .stylegan_utils import get_mean_latent, style_mixing @MODELS.register_module('StyleGANv1Generator') @MODELS.register_module() class StyleGAN1Generator(BaseModule): """StyleGAN1 Generator. In StyleGAN1, we use a progressive growing architecture composing of a style mapping module and number of convolutional style blocks. More details can be found in: A Style-Based Generator Architecture for Generative Adversarial Networks CVPR2019. Args: out_size (int): The output size of the StyleGAN1 generator. style_channels (int): The number of channels for style code. num_mlps (int, optional): The number of MLP layers. Defaults to 8. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 2, 1]. lr_mlp (float, optional): The learning rate for the style mapping layer. Defaults to 0.01. default_style_mode (str, optional): The default mode of style mixing. In training, we adopt mixing style mode in default. However, in the evaluation, we use 'single' style mode. `['mix', 'single']` are currently supported. Defaults to 'mix'. eval_style_mode (str, optional): The evaluation mode of style mixing. Defaults to 'single'. mix_prob (float, optional): Mixing probability. The value should be in range of [0, 1]. Defaults to 0.9. """ def __init__(self, out_size, style_channels, num_mlps=8, blur_kernel=[1, 2, 1], lr_mlp=0.01, default_style_mode='mix', eval_style_mode='single', mix_prob=0.9): super().__init__() self.out_size = out_size self.style_channels = style_channels self.num_mlps = num_mlps self.lr_mlp = lr_mlp self._default_style_mode = default_style_mode self.default_style_mode = default_style_mode self.eval_style_mode = eval_style_mode self.mix_prob = mix_prob # define style mapping layers mapping_layers = [PixelNorm()] for _ in range(num_mlps): mapping_layers.append( EqualLinearActModule( style_channels, style_channels, equalized_lr_cfg=dict(lr_mul=lr_mlp, gain=1.), act_cfg=dict(type='LeakyReLU', negative_slope=0.2))) self.style_mapping = nn.Sequential(*mapping_layers) self.channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256, 128: 128, 256: 64, 512: 32, 1024: 16, } # generator backbone (8x8 --> higher resolutions) self.log_size = int(np.log2(self.out_size)) self.convs = nn.ModuleList() self.to_rgbs = nn.ModuleList() in_channels_ = self.channels[4] for i in range(2, self.log_size + 1): out_channels_ = self.channels[2**i] self.convs.append( StyleConv( in_channels_, out_channels_, 3, style_channels, initial=(i == 2), upsample=True, fused=True)) self.to_rgbs.append( EqualizedLRConvModule(out_channels_, 3, 1, act_cfg=None)) in_channels_ = out_channels_ self.num_latents = self.log_size * 2 - 2 self.num_injected_noises = self.num_latents # register buffer for injected noises for layer_idx in range(self.num_injected_noises): res = (layer_idx + 4) // 2 shape = [1, 1, 2**res, 2**res] self.register_buffer(f'injected_noise_{layer_idx}', torch.randn(*shape)) def train(self, mode=True): if mode: if self.default_style_mode != self._default_style_mode: mmengine.print_log( f'Switch to train style mode: {self._default_style_mode}') self.default_style_mode = self._default_style_mode else: if self.default_style_mode != self.eval_style_mode: mmengine.print_log( f'Switch to evaluation style mode: {self.eval_style_mode}') self.default_style_mode = self.eval_style_mode return super(StyleGAN1Generator, self).train(mode) def make_injected_noise(self): """make noises that will be injected into feature maps. Returns: list[Tensor]: List of layer-wise noise tensor. """ device = get_module_device(self) # noises = [torch.randn(1, 1, 2**2, 2**2, device=device)] noises = [] for i in range(2, self.log_size + 1): for _ in range(2): noises.append(torch.randn(1, 1, 2**i, 2**i, device=device)) return noises def get_mean_latent(self, num_samples=4096, **kwargs): """Get mean latent of W space in this generator. Args: num_samples (int, optional): Number of sample times. Defaults to 4096. Returns: Tensor: Mean latent of this generator. """ return get_mean_latent(self, num_samples, **kwargs) def style_mixing(self, n_source, n_target, inject_index=1, truncation_latent=None, truncation=0.7, curr_scale=-1, transition_weight=1): return style_mixing( self, n_source=n_source, n_target=n_target, inject_index=inject_index, truncation=truncation, truncation_latent=truncation_latent, style_channels=self.style_channels, curr_scale=curr_scale, transition_weight=transition_weight) def forward(self, styles, num_batches=-1, return_noise=False, return_latents=False, inject_index=None, truncation=1, truncation_latent=None, input_is_latent=False, injected_noise=None, randomize_noise=True, transition_weight=1., curr_scale=-1): """Forward function. This function has been integrated with the truncation trick. Please refer to the usage of `truncation` and `truncation_latent`. Args: styles (torch.Tensor | list[torch.Tensor] | callable | None): In StyleGAN1, you can provide noise tensor or latent tensor. Given a list containing more than one noise or latent tensors, style mixing trick will be used in training. Of course, You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. return_latents (bool, optional): If True, ``latent`` will be returned in a dict with ``fake_img``. Defaults to False. inject_index (int | None, optional): The index number for mixing style codes. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. truncation_latent (torch.Tensor, optional): Mean truncation latent. Defaults to None. input_is_latent (bool, optional): If `True`, the input tensor is the latent tensor. Defaults to False. injected_noise (torch.Tensor | None, optional): Given a tensor, the random noise will be fixed as this input injected noise. Defaults to None. randomize_noise (bool, optional): If `False`, images are sampled with the buffered noise tensor injected to the style conv block. Defaults to True. transition_weight (float, optional): The weight used in resolution transition. Defaults to 1.. curr_scale (int, optional): The resolution scale of generated image tensor. -1 means the max resolution scale of the StyleGAN1. Defaults to -1. Returns: torch.Tensor | dict: Generated image tensor or dictionary \ containing more data. """ # receive noise and conduct sanity check. if isinstance(styles, torch.Tensor): assert styles.shape[1] == self.style_channels styles = [styles] elif mmengine.is_seq_of(styles, torch.Tensor): for t in styles: assert t.shape[-1] == self.style_channels # receive a noise generator and sample noise. elif callable(styles): device = get_module_device(self) noise_generator = styles assert num_batches > 0 if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ noise_generator((num_batches, self.style_channels)) for _ in range(2) ] else: styles = [noise_generator((num_batches, self.style_channels))] styles = [s.to(device) for s in styles] # otherwise, we will adopt default noise sampler. else: device = get_module_device(self) assert num_batches > 0 and not input_is_latent if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ torch.randn((num_batches, self.style_channels)) for _ in range(2) ] else: styles = [torch.randn((num_batches, self.style_channels))] styles = [s.to(device) for s in styles] if not input_is_latent: noise_batch = styles styles = [self.style_mapping(s) for s in styles] else: noise_batch = None if injected_noise is None: if randomize_noise: injected_noise = [None] * self.num_injected_noises else: injected_noise = [ getattr(self, f'injected_noise_{i}') for i in range(self.num_injected_noises) ] # use truncation trick if truncation < 1: style_t = [] # calculate truncation latent on the fly if truncation_latent is None and not hasattr( self, 'truncation_latent'): self.truncation_latent = self.get_mean_latent() truncation_latent = self.truncation_latent elif truncation_latent is None and hasattr(self, 'truncation_latent'): truncation_latent = self.truncation_latent for style in styles: style_t.append(truncation_latent + truncation * (style - truncation_latent)) styles = style_t # no style mixing if len(styles) < 2: inject_index = self.num_latents if styles[0].ndim < 3: latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) else: latent = styles[0] # style mixing else: if inject_index is None: inject_index = random.randint(1, self.num_latents - 1) latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) latent2 = styles[1].unsqueeze(1).repeat( 1, self.num_latents - inject_index, 1) latent = torch.cat([latent, latent2], 1) curr_log_size = self.log_size if curr_scale < 0 else int( np.log2(curr_scale)) step = curr_log_size - 2 _index = 0 out = latent # 4x4 ---> higher resolutions for i, (conv, to_rgb) in enumerate(zip(self.convs, self.to_rgbs)): if i > 0 and step > 0: out_prev = out out = conv( out, latent[:, _index], latent[:, _index + 1], noise1=injected_noise[2 * i], noise2=injected_noise[2 * i + 1]) if i == step: out = to_rgb(out) if i > 0 and 0 <= transition_weight < 1: skip_rgb = self.to_rgbs[i - 1](out_prev) skip_rgb = F.interpolate( skip_rgb, scale_factor=2, mode='nearest') out = (1 - transition_weight ) * skip_rgb + transition_weight * out break _index += 2 img = out if return_latents or return_noise: output_dict = dict( fake_img=img, latent=latent, inject_index=inject_index, noise_batch=noise_batch) return output_dict return img ================================================ FILE: mmagic/models/editors/stylegan1/stylegan1_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from functools import partial import mmengine import torch import torch.nn as nn from mmcv.ops.fused_bias_leakyrelu import fused_bias_leakyrelu from mmcv.ops.upfirdn2d import upfirdn2d from mmengine.model import BaseModule from mmagic.registry import MODELS from ..pggan import (EqualizedLRConvModule, EqualizedLRConvUpModule, EqualizedLRLinearModule) class EqualLinearActModule(BaseModule): """Equalized LR Linear Module with Activation Layer. This module is modified from ``EqualizedLRLinearModule`` defined in PGGAN. The major features updated in this module is adding support for activation layers used in StyleGAN2. Args: equalized_lr_cfg (dict | None, optional): Config for equalized lr. Defaults to dict(gain=1., lr_mul=1.). bias (bool, optional): Whether to use bias item. Defaults to True. bias_init (float, optional): The value for bias initialization. Defaults to ``0.``. act_cfg (dict | None, optional): Config for activation layer. Defaults to None. """ def __init__(self, *args, equalized_lr_cfg=dict(gain=1., lr_mul=1.), bias=True, bias_init=0., act_cfg=None, **kwargs): super().__init__() self.with_activation = act_cfg is not None # w/o bias in linear layer self.linear = EqualizedLRLinearModule( *args, bias=False, equalized_lr_cfg=equalized_lr_cfg, **kwargs) if equalized_lr_cfg is not None: self.lr_mul = equalized_lr_cfg.get('lr_mul', 1.) else: self.lr_mul = 1. # define bias outside linear layer if bias: self.bias = nn.Parameter( torch.zeros(self.linear.out_features).fill_(bias_init)) else: self.bias = None if self.with_activation: act_cfg = deepcopy(act_cfg) if act_cfg['type'] == 'fused_bias': self.act_type = act_cfg.pop('type') assert self.bias is not None self.activate = partial(fused_bias_leakyrelu, **act_cfg) else: self.act_type = 'normal' self.activate = MODELS.build(act_cfg) else: self.act_type = None def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, ...). Returns: Tensor: Output feature map. """ if x.ndim >= 3: x = x.reshape(x.size(0), -1) x = self.linear(x) if self.with_activation and self.act_type == 'fused_bias': x = self.activate(x, self.bias * self.lr_mul) elif self.bias is not None and self.with_activation: x = self.activate(x + self.bias * self.lr_mul) elif self.bias is not None: x = x + self.bias * self.lr_mul elif self.with_activation: x = self.activate(x) return x class NoiseInjection(BaseModule): """Noise Injection Module. In StyleGAN2, they adopt this module to inject spatial random noise map in the generators. Args: noise_weight_init (float, optional): Initialization weight for noise injection. Defaults to ``0.``. fixed_noise (bool, optional): Whether to inject a fixed noise. Defaults to ``False``. """ def __init__(self, noise_weight_init=0., fixed_noise=False): super().__init__() self.weight = nn.Parameter(torch.zeros(1).fill_(noise_weight_init)) self.fixed_noise = fixed_noise def forward(self, image, noise=None, return_noise=False): """Forward Function. Args: image (Tensor): Spatial features with a shape of (N, C, H, W). noise (Tensor, optional): Noises from the outside. Defaults to None. return_noise (bool, optional): Whether to return noise tensor. Defaults to False. Returns: Tensor: Output features. """ if noise is None: batch, _, height, width = image.shape noise = image.new_empty(batch, 1, height, width).normal_() if self.fixed_noise: torch.manual_seed(1024) noise = torch.randn(batch, 1, height, width).cuda() noise = noise.to(image.dtype) if return_noise: return image + self.weight.to(image.dtype) * noise, noise return image + self.weight.to(image.dtype) * noise class ConstantInput(BaseModule): """Constant Input. In StyleGAN2, they substitute the original head noise input with such a constant input module. Args: channel (int): Channels for the constant input tensor. size (int, optional): Spatial size for the constant input. Defaults to 4. """ def __init__(self, channel, size=4): super().__init__() if isinstance(size, int): size = [size, size] elif mmengine.is_seq_of(size, int): assert len( size ) == 2, f'The length of size should be 2 but got {len(size)}' else: raise ValueError(f'Got invalid value in size, {size}') self.input = nn.Parameter(torch.randn(1, channel, *size)) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, ...). Returns: Tensor: Output feature map. """ batch = x.shape[0] out = self.input.repeat(batch, 1, 1, 1) return out def make_kernel(k): k = torch.tensor(k, dtype=torch.float32) if k.ndim == 1: k = k[None, :] * k[:, None] k /= k.sum() return k class Blur(BaseModule): """Blur module. This module is adopted rightly after upsampling operation in StyleGAN2. Args: kernel (Array): Blur kernel/filter used in UpFIRDn. pad (list[int]): Padding for features. upsample_factor (int, optional): Upsampling factor. Defaults to 1. """ def __init__(self, kernel, pad, upsample_factor=1): super().__init__() kernel = make_kernel(kernel) if upsample_factor > 1: kernel = kernel * (upsample_factor**2) self.register_buffer('kernel', kernel) self.pad = pad def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map. """ # In Tero's implementation, he uses fp32 return upfirdn2d(x, self.kernel.to(x.dtype), padding=self.pad) class AdaptiveInstanceNorm(BaseModule): r"""Adaptive Instance Normalization Module. Ref: https://github.com/rosinality/style-based-gan-pytorch/blob/master/model.py # noqa Args: in_channel (int): The number of input's channel. style_dim (int): Style latent dimension. """ def __init__(self, in_channel, style_dim): super().__init__() self.norm = nn.InstanceNorm2d(in_channel) self.affine = EqualizedLRLinearModule(style_dim, in_channel * 2) self.affine.bias.data[:in_channel] = 1 self.affine.bias.data[in_channel:] = 0 def forward(self, input, style): """Forward function. Args: input (Tensor): Input tensor with shape (n, c, h, w). style (Tensor): Input style tensor with shape (n, c). Returns: Tensor: Forward results. """ style = self.affine(style).unsqueeze(2).unsqueeze(3) gamma, beta = style.chunk(2, 1) out = self.norm(input) out = gamma * out + beta return out class StyleConv(BaseModule): def __init__(self, in_channels, out_channels, kernel_size, style_channels, padding=1, initial=False, blur_kernel=[1, 2, 1], upsample=False, fused=False): """Convolutional style blocks composing of noise injector, AdaIN module and convolution layers. Args: in_channels (int): The channel number of the input tensor. out_channels (itn): The channel number of the output tensor. kernel_size (int): The kernel size of convolution layers. style_channels (int): The number of channels for style code. padding (int, optional): Padding of convolution layers. Defaults to 1. initial (bool, optional): Whether this is the first StyleConv of StyleGAN's generator. Defaults to False. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 2, 1]. upsample (bool, optional): Whether perform upsampling. Defaults to False. fused (bool, optional): Whether use fused upconv. Defaults to False. """ super().__init__() if initial: self.conv1 = ConstantInput(in_channels) else: if upsample: if fused: self.conv1 = nn.Sequential( EqualizedLRConvUpModule( in_channels, out_channels, kernel_size, padding=padding, act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), Blur(blur_kernel, pad=(1, 1)), ) else: self.conv1 = nn.Sequential( nn.Upsample(scale_factor=2, mode='nearest'), EqualizedLRConvModule( in_channels, out_channels, kernel_size, padding=padding, act_cfg=None), Blur(blur_kernel, pad=(1, 1))) else: self.conv1 = EqualizedLRConvModule( in_channels, out_channels, kernel_size, padding=padding, act_cfg=None) self.noise_injector1 = NoiseInjection() self.activate1 = nn.LeakyReLU(0.2) self.adain1 = AdaptiveInstanceNorm(out_channels, style_channels) self.conv2 = EqualizedLRConvModule( out_channels, out_channels, kernel_size, padding=padding, act_cfg=None) self.noise_injector2 = NoiseInjection() self.activate2 = nn.LeakyReLU(0.2) self.adain2 = AdaptiveInstanceNorm(out_channels, style_channels) def forward(self, x, style1, style2, noise1=None, noise2=None, return_noise=False): """Forward function. Args: x (Tensor): Input tensor. style1 (Tensor): Input style tensor with shape (n, c). style2 (Tensor): Input style tensor with shape (n, c). noise1 (Tensor, optional): Noise tensor with shape (n, c, h, w). Defaults to None. noise2 (Tensor, optional): Noise tensor with shape (n, c, h, w). Defaults to None. return_noise (bool, optional): If True, ``noise1`` and ``noise2`` will be returned with ``out``. Defaults to False. Returns: Tensor | tuple[Tensor]: Forward results. """ out = self.conv1(x) if return_noise: out, noise1 = self.noise_injector1( out, noise=noise1, return_noise=return_noise) else: out = self.noise_injector1( out, noise=noise1, return_noise=return_noise) out = self.activate1(out) out = self.adain1(out, style1) out = self.conv2(out) if return_noise: out, noise2 = self.noise_injector2( out, noise=noise2, return_noise=return_noise) else: out = self.noise_injector2( out, noise=noise2, return_noise=return_noise) out = self.activate2(out) out = self.adain2(out, style2) if return_noise: return out, noise1, noise2 return out ================================================ FILE: mmagic/models/editors/stylegan1/stylegan_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from ...utils import get_module_device @torch.no_grad() def get_mean_latent(generator, num_samples=4096, bs_per_repeat=1024): """Get mean latent of W space in Style-based GANs. Args: generator (BaseModule): Generator of a Style-based GAN. num_samples (int, optional): Number of sample times. Defaults to 4096. bs_per_repeat (int, optional): Batch size of noises per sample. Defaults to 1024. Returns: Tensor: Mean latent of this generator. """ device = get_module_device(generator) mean_style = None n_repeat = num_samples // bs_per_repeat assert n_repeat * bs_per_repeat == num_samples for _ in range(n_repeat): style = generator.style_mapping( torch.randn(bs_per_repeat, generator.style_channels).to(device)).mean( 0, keepdim=True) if mean_style is None: mean_style = style else: mean_style += style mean_style /= float(n_repeat) return mean_style @torch.no_grad() def style_mixing(generator, n_source, n_target, inject_index=1, truncation_latent=None, truncation=0.7, style_channels=512, **kwargs): device = get_module_device(generator) source_code = torch.randn(n_source, style_channels).to(device) target_code = torch.randn(n_target, style_channels).to(device) source_image = generator( source_code, truncation_latent=truncation_latent, truncation=truncation, **kwargs) h, w = source_image.shape[-2:] images = [torch.ones(1, 3, h, w).to(device) * -1] target_image = generator( target_code, truncation_latent=truncation_latent, truncation=truncation, **kwargs) images.append(source_image) for i in range(n_target): image = generator( [target_code[i].unsqueeze(0).repeat(n_source, 1), source_code], truncation_latent=truncation_latent, truncation=truncation, inject_index=inject_index, **kwargs) images.append(target_image[i].unsqueeze(0)) images.append(image) images = torch.cat(images, 0) return images ================================================ FILE: mmagic/models/editors/stylegan2/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .stylegan2 import StyleGAN2 from .stylegan2_discriminator import (ADAAug, ADAStyleGAN2Discriminator, StyleGAN2Discriminator) from .stylegan2_generator import StyleGAN2Generator from .stylegan2_modules import (ConvDownLayer, ModMBStddevLayer, ModulatedToRGB, ResBlock) __all__ = [ 'StyleGAN2', 'StyleGAN2Discriminator', 'StyleGAN2Generator', 'ADAStyleGAN2Discriminator', 'ADAAug', 'ConvDownLayer', 'ModMBStddevLayer', 'ModulatedToRGB', 'ResBlock' ] ================================================ FILE: mmagic/models/editors/stylegan2/ada/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. ================================================ FILE: mmagic/models/editors/stylegan2/ada/augment.py ================================================ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. # # NVIDIA CORPORATION and its licensors retain all intellectual property # and proprietary rights in and to this software, related documentation # and any modifications thereto. Any use, reproduction, disclosure or # distribution of this software and related documentation without an express # license agreement from NVIDIA CORPORATION is strictly prohibited. import numpy as np import scipy.signal import torch try: from mmcv.ops import conv2d except ImportError: conv2d = None print('Warning: mmcv.ops.conv2d are not available.') from . import grid_sample_gradfix, misc, upfirdn2d # ---------------------------------------------------------------------------- # Coefficients of various wavelet decomposition low-pass filters. wavelets = { 'haar': [0.7071067811865476, 0.7071067811865476], 'db1': [0.7071067811865476, 0.7071067811865476], 'db2': [ -0.12940952255092145, 0.22414386804185735, 0.836516303737469, 0.48296291314469025 ], 'db3': [ 0.035226291882100656, -0.08544127388224149, -0.13501102001039084, 0.4598775021193313, 0.8068915093133388, 0.3326705529509569 ], 'db4': [ -0.010597401784997278, 0.032883011666982945, 0.030841381835986965, -0.18703481171888114, -0.02798376941698385, 0.6308807679295904, 0.7148465705525415, 0.23037781330885523 ], 'db5': [ 0.003335725285001549, -0.012580751999015526, -0.006241490213011705, 0.07757149384006515, -0.03224486958502952, -0.24229488706619015, 0.13842814590110342, 0.7243085284385744, 0.6038292697974729, 0.160102397974125 ], 'db6': [ -0.00107730108499558, 0.004777257511010651, 0.0005538422009938016, -0.031582039318031156, 0.02752286553001629, 0.09750160558707936, -0.12976686756709563, -0.22626469396516913, 0.3152503517092432, 0.7511339080215775, 0.4946238903983854, 0.11154074335008017 ], 'db7': [ 0.0003537138000010399, -0.0018016407039998328, 0.00042957797300470274, 0.012550998556013784, -0.01657454163101562, -0.03802993693503463, 0.0806126091510659, 0.07130921926705004, -0.22403618499416572, -0.14390600392910627, 0.4697822874053586, 0.7291320908465551, 0.39653931948230575, 0.07785205408506236 ], 'db8': [ -0.00011747678400228192, 0.0006754494059985568, -0.0003917403729959771, -0.00487035299301066, 0.008746094047015655, 0.013981027917015516, -0.04408825393106472, -0.01736930100202211, 0.128747426620186, 0.00047248457399797254, -0.2840155429624281, -0.015829105256023893, 0.5853546836548691, 0.6756307362980128, 0.3128715909144659, 0.05441584224308161 ], 'sym2': [ -0.12940952255092145, 0.22414386804185735, 0.836516303737469, 0.48296291314469025 ], 'sym3': [ 0.035226291882100656, -0.08544127388224149, -0.13501102001039084, 0.4598775021193313, 0.8068915093133388, 0.3326705529509569 ], 'sym4': [ -0.07576571478927333, -0.02963552764599851, 0.49761866763201545, 0.8037387518059161, 0.29785779560527736, -0.09921954357684722, -0.012603967262037833, 0.0322231006040427 ], 'sym5': [ 0.027333068345077982, 0.029519490925774643, -0.039134249302383094, 0.1993975339773936, 0.7234076904024206, 0.6339789634582119, 0.01660210576452232, -0.17532808990845047, -0.021101834024758855, 0.019538882735286728 ], 'sym6': [ 0.015404109327027373, 0.0034907120842174702, -0.11799011114819057, -0.048311742585633, 0.4910559419267466, 0.787641141030194, 0.3379294217276218, -0.07263752278646252, -0.021060292512300564, 0.04472490177066578, 0.0017677118642428036, -0.007800708325034148 ], 'sym7': [ 0.002681814568257878, -0.0010473848886829163, -0.01263630340325193, 0.03051551316596357, 0.0678926935013727, -0.049552834937127255, 0.017441255086855827, 0.5361019170917628, 0.767764317003164, 0.2886296317515146, -0.14004724044296152, -0.10780823770381774, 0.004010244871533663, 0.010268176708511255 ], 'sym8': [ -0.0033824159510061256, -0.0005421323317911481, 0.03169508781149298, 0.007607487324917605, -0.1432942383508097, -0.061273359067658524, 0.4813596512583722, 0.7771857517005235, 0.3644418948353314, -0.05194583810770904, -0.027219029917056003, 0.049137179673607506, 0.003808752013890615, -0.01495225833704823, -0.0003029205147213668, 0.0018899503327594609 ], } # ---------------------------------------------------------------------------- # Helpers for constructing transformation matrices. def matrix(*rows, device=None): """Constructing transformation matrices. Args: device (str|torch.device, optional): Matrix device. Defaults to None. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ assert all(len(row) == len(rows[0]) for row in rows) elems = [x for row in rows for x in row] ref = [x for x in elems if isinstance(x, torch.Tensor)] if len(ref) == 0: return misc.constant(np.asarray(rows), device=device) assert device is None or device == ref[0].device # change `x.float()` to support pt1.5 elems = [ x.float() if isinstance(x, torch.Tensor) else misc.constant( x, shape=ref[0].shape, device=ref[0].device) for x in elems ] return torch.stack(elems, dim=-1).reshape(ref[0].shape + (len(rows), -1)) def translate2d(tx, ty, **kwargs): """Construct 2d translation matrix. Args: tx (float): X-direction translation amount. ty (float): Y-direction translation amount. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return matrix([1, 0, tx], [0, 1, ty], [0, 0, 1], **kwargs) def translate3d(tx, ty, tz, **kwargs): """Construct 3d translation matrix. Args: tx (float): X-direction translation amount. ty (float): Y-direction translation amount. tz (float): Z-direction translation amount. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return matrix([1, 0, 0, tx], [0, 1, 0, ty], [0, 0, 1, tz], [0, 0, 0, 1], **kwargs) def scale2d(sx, sy, **kwargs): """Construct 2d scaling matrix. Args: sx (float): X-direction scaling coefficient. sy (float): Y-direction scaling coefficient. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return matrix([sx, 0, 0], [0, sy, 0], [0, 0, 1], **kwargs) def scale3d(sx, sy, sz, **kwargs): """Construct 3d scaling matrix. Args: sx (float): X-direction scaling coefficient. sy (float): Y-direction scaling coefficient. sz (float): Z-direction scaling coefficient. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return matrix([sx, 0, 0, 0], [0, sy, 0, 0], [0, 0, sz, 0], [0, 0, 0, 1], **kwargs) def rotate2d(theta, **kwargs): """Construct 2d rotating matrix. Args: theta (float): Counter-clock wise rotation angle. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return matrix([torch.cos(theta), torch.sin(-theta), 0], [torch.sin(theta), torch.cos(theta), 0], [0, 0, 1], **kwargs) def rotate3d(v, theta, **kwargs): """Constructing 3d rotating matrix. Args: v (torch.Tensor): Luma axis. theta (float): Rotate theta counter-clock wise with ``v`` as the axis. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ vx = v[..., 0] vy = v[..., 1] vz = v[..., 2] s = torch.sin(theta) c = torch.cos(theta) cc = 1 - c return matrix( [vx * vx * cc + c, vx * vy * cc - vz * s, vx * vz * cc + vy * s, 0], [vy * vx * cc + vz * s, vy * vy * cc + c, vy * vz * cc - vx * s, 0], [vz * vx * cc - vy * s, vz * vy * cc + vx * s, vz * vz * cc + c, 0], [0, 0, 0, 1], **kwargs) def translate2d_inv(tx, ty, **kwargs): """Construct inverse matrix of 2d translation matrix. Args: tx (float): X-direction translation amount. ty (float): Y-direction translation amount. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return translate2d(-tx, -ty, **kwargs) def scale2d_inv(sx, sy, **kwargs): """Construct inverse matrix of 2d scaling matrix. Args: sx (float): X-direction scaling coefficient. sy (float): Y-direction scaling coefficient. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return scale2d(1 / sx, 1 / sy, **kwargs) def rotate2d_inv(theta, **kwargs): """Construct inverse matrix of 2d rotating matrix. Args: theta (float): Counter-clock wise rotation angle. Returns: ndarry | Tensor : Transformation matrices in np.ndarry or torch.Tensor format. """ return rotate2d(-theta, **kwargs) # ---------------------------------------------------------------------------- # Versatile image augmentation pipeline from the paper # "Training Generative Adversarial Networks with Limited Data". # # All augmentations are disabled by default; individual augmentations can # be enabled by setting their probability multipliers to 1. class AugmentPipe(torch.nn.Module): """Augmentation pipeline include multiple geometric and color transformations. Note: The meaning of arguments are written in the comments of ``__init__`` function. """ def __init__( self, xflip=0, rotate90=0, xint=0, xint_max=0.125, scale=0, rotate=0, aniso=0, xfrac=0, scale_std=0.2, rotate_max=1, aniso_std=0.2, xfrac_std=0.125, brightness=0, contrast=0, lumaflip=0, hue=0, saturation=0, brightness_std=0.2, contrast_std=0.5, hue_max=1, saturation_std=1, imgfilter=0, imgfilter_bands=[1, 1, 1, 1], imgfilter_std=1, noise=0, cutout=0, noise_std=0.1, cutout_size=0.5, ): super().__init__() self.register_buffer('p', torch.ones( [])) # Overall multiplier for augmentation probability. # Pixel blitting. self.xflip = float(xflip) # Probability multiplier for x-flip. self.rotate90 = float( rotate90) # Probability multiplier for 90 degree rotations. self.xint = float( xint) # Probability multiplier for integer translation. self.xint_max = float( xint_max ) # Range of integer translation, relative to image dimensions. # General geometric transformations. self.scale = float( scale) # Probability multiplier for isotropic scaling. self.rotate = float( rotate) # Probability multiplier for arbitrary rotation. self.aniso = float( aniso) # Probability multiplier for anisotropic scaling. self.xfrac = float( xfrac) # Probability multiplier for fractional translation. self.scale_std = float( scale_std) # Log2 standard deviation of isotropic scaling. self.rotate_max = float( rotate_max) # Range of arbitrary rotation, 1 = full circle. self.aniso_std = float( aniso_std) # Log2 standard deviation of anisotropic scaling. self.xfrac_std = float( xfrac_std ) # Standard deviation of frational translation, relative to img dims. # Color transformations. self.brightness = float( brightness) # Probability multiplier for brightness. self.contrast = float(contrast) # Probability multiplier for contrast. self.lumaflip = float( lumaflip) # Probability multiplier for luma flip. self.hue = float(hue) # Probability multiplier for hue rotation. self.saturation = float( saturation) # Probability multiplier for saturation. self.brightness_std = float( brightness_std) # Standard deviation of brightness. self.contrast_std = float( contrast_std) # Log2 standard deviation of contrast. self.hue_max = float( hue_max) # Range of hue rotation, 1 = full circle. self.saturation_std = float( saturation_std) # Log2 standard deviation of saturation. # Image-space filtering. self.imgfilter = float( imgfilter) # Probability multiplier for image-space filtering. self.imgfilter_bands = list( imgfilter_bands ) # Probability multipliers for individual frequency bands. self.imgfilter_std = float( imgfilter_std ) # Log2 standard deviation of image-space filter amplification. # Image-space corruptions. self.noise = float( noise) # Probability multiplier for additive RGB noise. self.cutout = float(cutout) # Probability multiplier for cutout. self.noise_std = float( noise_std) # Standard deviation of additive RGB noise. self.cutout_size = float( cutout_size ) # Size of the cutout rectangle, relative to image dimensions. # Setup orthogonal lowpass filter for geometric augmentations. self.register_buffer('Hz_geom', upfirdn2d.setup_filter(wavelets['sym6'])) # Construct filter bank for image-space filtering. Hz_lo = np.asarray(wavelets['sym2']) # H(z) Hz_hi = Hz_lo * ((-1)**np.arange(Hz_lo.size)) # H(-z) Hz_lo2 = np.convolve(Hz_lo, Hz_lo[::-1]) / 2 # H(z) * H(z^-1) / 2 Hz_hi2 = np.convolve(Hz_hi, Hz_hi[::-1]) / 2 # H(-z) * H(-z^-1) / 2 Hz_fbank = np.eye(4, 1) # Bandpass(H(z), b_i) for i in range(1, Hz_fbank.shape[0]): Hz_fbank = np.dstack([Hz_fbank, np.zeros_like(Hz_fbank) ]).reshape(Hz_fbank.shape[0], -1)[:, :-1] Hz_fbank = scipy.signal.convolve(Hz_fbank, [Hz_lo2]) Hz_fbank[i, (Hz_fbank.shape[1] - Hz_hi2.size) // 2:(Hz_fbank.shape[1] + Hz_hi2.size) // 2] += Hz_hi2 self.register_buffer('Hz_fbank', torch.as_tensor(Hz_fbank, dtype=torch.float32)) def forward(self, images, debug_percentile=None): assert isinstance(images, torch.Tensor) and images.ndim == 4 batch_size, num_channels, height, width = images.shape device = images.device if debug_percentile is not None: debug_percentile = torch.as_tensor( debug_percentile, dtype=torch.float32, device=device) # ------------------------------------- # Select parameters for pixel blitting. # ------------------------------------- # Initialize inverse homogeneous 2D transform: # G_inv @ pixel_out ==> pixel_in I_3 = torch.eye(3, device=device) G_inv = I_3 # Apply x-flip with probability (xflip * strength). if self.xflip > 0: i = torch.floor(torch.rand([batch_size], device=device) * 2) i = torch.where( torch.rand([batch_size], device=device) < self.xflip * self.p, i, torch.zeros_like(i)) if debug_percentile is not None: i = torch.full_like(i, torch.floor(debug_percentile * 2)) G_inv = G_inv @ scale2d_inv(1 - 2 * i, 1) # Apply 90 degree rotations with probability (rotate90 * strength). if self.rotate90 > 0: i = torch.floor(torch.rand([batch_size], device=device) * 4) i = torch.where( torch.rand([batch_size], device=device) < self.rotate90 * self.p, i, torch.zeros_like(i)) if debug_percentile is not None: i = torch.full_like(i, torch.floor(debug_percentile * 4)) G_inv = G_inv @ rotate2d_inv(-np.pi / 2 * i) # Apply integer translation with probability (xint * strength). if self.xint > 0: t = (torch.rand([batch_size, 2], device=device) * 2 - 1) * self.xint_max t = torch.where( torch.rand([batch_size, 1], device=device) < self.xint * self.p, t, torch.zeros_like(t)) if debug_percentile is not None: t = torch.full_like(t, (debug_percentile * 2 - 1) * self.xint_max) G_inv = G_inv @ translate2d_inv( torch.round(t[:, 0] * width), torch.round(t[:, 1] * height)) # -------------------------------------------------------- # Select parameters for general geometric transformations. # -------------------------------------------------------- # support for pt1.5 (pt1.5 does not contain exp2) _scalor_log2 = torch.log( torch.tensor(2., device=images.device, dtype=images.dtype)) # Apply isotropic scaling with probability (scale * strength). if self.scale > 0: s = torch.exp( torch.randn([batch_size], device=device) * self.scale_std * _scalor_log2) s = torch.where( torch.rand([batch_size], device=device) < self.scale * self.p, s, torch.ones_like(s)) if debug_percentile is not None: s = torch.full_like( s, torch.exp2( torch.erfinv(debug_percentile * 2 - 1) * self.scale_std)) G_inv = G_inv @ scale2d_inv(s, s) # Apply pre-rotation with probability p_rot. p_rot = 1 - torch.sqrt( (1 - self.rotate * self.p).clamp(0, 1)) # P(pre OR post) = p if self.rotate > 0: theta = (torch.rand([batch_size], device=device) * 2 - 1) * np.pi * self.rotate_max theta = torch.where( torch.rand([batch_size], device=device) < p_rot, theta, torch.zeros_like(theta)) if debug_percentile is not None: theta = torch.full_like(theta, (debug_percentile * 2 - 1) * np.pi * self.rotate_max) G_inv = G_inv @ rotate2d_inv(-theta) # Before anisotropic scaling. # Apply anisotropic scaling with probability (aniso * strength). if self.aniso > 0: s = torch.exp( torch.randn([batch_size], device=device) * self.aniso_std * _scalor_log2) s = torch.where( torch.rand([batch_size], device=device) < self.aniso * self.p, s, torch.ones_like(s)) if debug_percentile is not None: s = torch.full_like( s, torch.exp2( torch.erfinv(debug_percentile * 2 - 1) * self.aniso_std)) G_inv = G_inv @ scale2d_inv(s, 1 / s) # Apply post-rotation with probability p_rot. if self.rotate > 0: theta = (torch.rand([batch_size], device=device) * 2 - 1) * np.pi * self.rotate_max theta = torch.where( torch.rand([batch_size], device=device) < p_rot, theta, torch.zeros_like(theta)) if debug_percentile is not None: theta = torch.zeros_like(theta) G_inv = G_inv @ rotate2d_inv(-theta) # After anisotropic scaling. # Apply fractional translation with probability (xfrac * strength). if self.xfrac > 0: t = torch.randn([batch_size, 2], device=device) * self.xfrac_std t = torch.where( torch.rand([batch_size, 1], device=device) < self.xfrac * self.p, t, torch.zeros_like(t)) if debug_percentile is not None: t = torch.full_like( t, torch.erfinv(debug_percentile * 2 - 1) * self.xfrac_std) G_inv = G_inv @ translate2d_inv(t[:, 0] * width, t[:, 1] * height) # ---------------------------------- # Execute geometric transformations. # ---------------------------------- # Execute if the transform is not identity. if G_inv is not I_3: # Calculate padding. cx = (width - 1) / 2 cy = (height - 1) / 2 cp = matrix([-cx, -cy, 1], [cx, -cy, 1], [cx, cy, 1], [-cx, cy, 1], device=device) # [idx, xyz] cp = G_inv @ cp.t() # [batch, xyz, idx] Hz_pad = self.Hz_geom.shape[0] // 4 margin = cp[:, :2, :].permute(1, 0, 2).flatten(1) # [xy, batch * idx] margin = torch.cat([-margin, margin]).max(dim=1).values # [x0, y0, x1, y1] margin = margin + misc.constant( [Hz_pad * 2 - cx, Hz_pad * 2 - cy] * 2, device=device) margin = margin.max(misc.constant([0, 0] * 2, device=device)) margin = margin.min( misc.constant([width - 1, height - 1] * 2, device=device)) mx0, my0, mx1, my1 = margin.ceil().to(torch.int32) # Pad image and adjust origin. images = torch.nn.functional.pad( input=images, pad=[mx0, mx1, my0, my1], mode='reflect') G_inv = translate2d( torch.true_divide(mx0 - mx1, 2), torch.true_divide( my0 - my1, 2)) @ G_inv # Upsample. images = upfirdn2d.upsample2d(x=images, f=self.Hz_geom, up=2) G_inv = scale2d( 2, 2, device=device) @ G_inv @ scale2d_inv( 2, 2, device=device) G_inv = translate2d( -0.5, -0.5, device=device) @ G_inv @ translate2d_inv( -0.5, -0.5, device=device) # Execute transformation. shape = [ batch_size, num_channels, (height + Hz_pad * 2) * 2, (width + Hz_pad * 2) * 2 ] G_inv = scale2d( 2 / images.shape[3], 2 / images.shape[2], device=device) @ G_inv @ scale2d_inv( 2 / shape[3], 2 / shape[2], device=device) grid = torch.nn.functional.affine_grid( theta=G_inv[:, :2, :], size=shape, align_corners=False) images = grid_sample_gradfix.grid_sample(images, grid) # Downsample and crop. images = upfirdn2d.downsample2d( x=images, f=self.Hz_geom, down=2, padding=-Hz_pad * 2, flip_filter=True) # -------------------------------------------- # Select parameters for color transformations. # -------------------------------------------- # Initialize homogeneous 3D transformation matrix: # C @ color_in ==> color_out I_4 = torch.eye(4, device=device) C = I_4 # Apply brightness with probability (brightness * strength). if self.brightness > 0: b = torch.randn([batch_size], device=device) * self.brightness_std b = torch.where( torch.rand([batch_size], device=device) < self.brightness * self.p, b, torch.zeros_like(b)) if debug_percentile is not None: b = torch.full_like( b, torch.erfinv(debug_percentile * 2 - 1) * self.brightness_std) C = translate3d(b, b, b) @ C # Apply contrast with probability (contrast * strength). if self.contrast > 0: c = torch.exp( torch.randn([batch_size], device=device) * self.contrast_std * _scalor_log2) c = torch.where( torch.rand([batch_size], device=device) < self.contrast * self.p, c, torch.ones_like(c)) if debug_percentile is not None: c = torch.full_like( c, torch.exp2( torch.erfinv(debug_percentile * 2 - 1) * self.contrast_std)) C = scale3d(c, c, c) @ C # Apply luma flip with probability (lumaflip * strength). v = misc.constant( np.asarray([1, 1, 1, 0]) / np.sqrt(3), device=device) # Luma axis. if self.lumaflip > 0: i = torch.floor(torch.rand([batch_size, 1, 1], device=device) * 2) i = torch.where( torch.rand([batch_size, 1, 1], device=device) < self.lumaflip * self.p, i, torch.zeros_like(i)) if debug_percentile is not None: i = torch.full_like(i, torch.floor(debug_percentile * 2)) C = (I_4 - 2 * v.ger(v) * i) @ C # Householder reflection. # Apply hue rotation with probability (hue * strength). if self.hue > 0 and num_channels > 1: theta = (torch.rand([batch_size], device=device) * 2 - 1) * np.pi * self.hue_max theta = torch.where( torch.rand([batch_size], device=device) < self.hue * self.p, theta, torch.zeros_like(theta)) if debug_percentile is not None: theta = torch.full_like(theta, (debug_percentile * 2 - 1) * np.pi * self.hue_max) C = rotate3d(v, theta) @ C # Rotate around v. # Apply saturation with probability (saturation * strength). if self.saturation > 0 and num_channels > 1: s = torch.exp( torch.randn([batch_size, 1, 1], device=device) * self.saturation_std * _scalor_log2) s = torch.where( torch.rand([batch_size, 1, 1], device=device) < self.saturation * self.p, s, torch.ones_like(s)) if debug_percentile is not None: s = torch.full_like( s, torch.exp2( torch.erfinv(debug_percentile * 2 - 1) * self.saturation_std)) C = (v.ger(v) + (I_4 - v.ger(v)) * s) @ C # ------------------------------ # Execute color transformations. # ------------------------------ # Execute if the transform is not identity. if C is not I_4: images = images.reshape([batch_size, num_channels, height * width]) if num_channels == 3: images = C[:, :3, :3] @ images + C[:, :3, 3:] elif num_channels == 1: C = C[:, :3, :].mean(dim=1, keepdims=True) images = images * C[:, :, :3].sum( dim=2, keepdims=True) + C[:, :, 3:] else: raise ValueError( 'Image must be RGB (3 channels) or L (1 channel)') images = images.reshape([batch_size, num_channels, height, width]) # ---------------------- # Image-space filtering. # ---------------------- if self.imgfilter > 0: num_bands = self.Hz_fbank.shape[0] assert len(self.imgfilter_bands) == num_bands expected_power = misc.constant( np.array([10, 1, 1, 1]) / 13, device=device) # Expected power spectrum (1/f). # Apply amplification for each band with probability # (imgfilter * strength * band_strength). g = torch.ones([batch_size, num_bands], device=device) # Global gain vector (identity). for i, band_strength in enumerate(self.imgfilter_bands): t_i = torch.exp( torch.randn([batch_size], device=device) * self.imgfilter_std * _scalor_log2) t_i = torch.where( torch.rand([batch_size], device=device) < self.imgfilter * self.p * band_strength, t_i, torch.ones_like(t_i)) if debug_percentile is not None: t_i = torch.full_like( t_i, torch.exp2( torch.erfinv(debug_percentile * 2 - 1) * self.imgfilter_std) ) if band_strength > 0 else torch.ones_like(t_i) t = torch.ones([batch_size, num_bands], device=device) # Temporary gain vector. t[:, i] = t_i # Replace i'th element. t = t / (expected_power * t.square()).sum( dim=-1, keepdims=True).sqrt() # Normalize power. g = g * t # Accumulate into global gain. # Construct combined amplification filter. Hz_prime = g @ self.Hz_fbank # [batch, tap] Hz_prime = Hz_prime.unsqueeze(1).repeat( [1, num_channels, 1]) # [batch, channels, tap] Hz_prime = Hz_prime.reshape([batch_size * num_channels, 1, -1]) # [batch * channels, 1, tap] # Apply filter. p = self.Hz_fbank.shape[1] // 2 images = images.reshape( [1, batch_size * num_channels, height, width]) images = torch.nn.functional.pad( input=images, pad=[p, p, p, p], mode='reflect') images = conv2d( input=images, weight=Hz_prime.unsqueeze(2), groups=batch_size * num_channels) images = conv2d( input=images, weight=Hz_prime.unsqueeze(3), groups=batch_size * num_channels) images = images.reshape([batch_size, num_channels, height, width]) # ------------------------ # Image-space corruptions. # ------------------------ # Apply additive RGB noise with probability (noise * strength). if self.noise > 0: sigma = torch.randn([batch_size, 1, 1, 1], device=device).abs() * self.noise_std sigma = torch.where( torch.rand([batch_size, 1, 1, 1], device=device) < self.noise * self.p, sigma, torch.zeros_like(sigma)) if debug_percentile is not None: sigma = torch.full_like( sigma, torch.erfinv(debug_percentile) * self.noise_std) images = images + torch.randn( [batch_size, num_channels, height, width], device=device) * sigma # Apply cutout with probability (cutout * strength). if self.cutout > 0: size = torch.full([batch_size, 2, 1, 1, 1], self.cutout_size, device=device) size = torch.where( torch.rand([batch_size, 1, 1, 1, 1], device=device) < self.cutout * self.p, size, torch.zeros_like(size)) center = torch.rand([batch_size, 2, 1, 1, 1], device=device) if debug_percentile is not None: size = torch.full_like(size, self.cutout_size) center = torch.full_like(center, debug_percentile) coord_x = torch.arange(width, device=device).reshape([1, 1, 1, -1]) coord_y = torch.arange( height, device=device).reshape([1, 1, -1, 1]) mask_x = (((coord_x + 0.5) / width - center[:, 0]).abs() >= size[:, 0] / 2) mask_y = (((coord_y + 0.5) / height - center[:, 1]).abs() >= size[:, 1] / 2) mask = torch.logical_or(mask_x, mask_y).to(torch.float32) images = images * mask return images ================================================ FILE: mmagic/models/editors/stylegan2/ada/grid_sample_gradfix.py ================================================ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. # # NVIDIA CORPORATION and its licensors retain all intellectual property # and proprietary rights in and to this software, related documentation # and any modifications thereto. Any use, reproduction, disclosure or # distribution of this software and related documentation without an express # license agreement from NVIDIA CORPORATION is strictly prohibited. """Custom replacement for `torch.nn.functional.grid_sample` that supports arbitrarily high order gradients between the input and output. Only works on 2D images and assumes `mode='bilinear'`, `padding_mode='zeros'`, `align_corners=False`. """ import warnings import torch # pylint: disable=redefined-builtin # pylint: disable=arguments-differ # pylint: disable=protected-access # ---------------------------------------------------------------------------- enabled = True # Enable the custom op by setting this to true. # ---------------------------------------------------------------------------- def grid_sample(input, grid): if _should_use_custom_op(): return _GridSample2dForward.apply(input, grid) return torch.nn.functional.grid_sample( input=input, grid=grid, mode='bilinear', padding_mode='zeros', align_corners=False) # ---------------------------------------------------------------------------- def _should_use_custom_op(): if not enabled: return False if any( torch.__version__.startswith(x) for x in ['1.5.', '1.6.', '1.7.', '1.8.', '1.9.', '1.10.']): return True warnings.warn( f'grid_sample_gradfix not supported on PyTorch {torch.__version__}.' ' Falling back to torch.nn.functional.grid_sample().') return False # ---------------------------------------------------------------------------- class _GridSample2dForward(torch.autograd.Function): @staticmethod def forward(ctx, input, grid): assert input.ndim == 4 assert grid.ndim == 4 output = torch.nn.functional.grid_sample( input=input, grid=grid, mode='bilinear', padding_mode='zeros', align_corners=False) ctx.save_for_backward(input, grid) return output @staticmethod def backward(ctx, grad_output): input, grid = ctx.saved_tensors grad_input, grad_grid = _GridSample2dBackward.apply( grad_output, input, grid) return grad_input, grad_grid # ---------------------------------------------------------------------------- class _GridSample2dBackward(torch.autograd.Function): @staticmethod def forward(ctx, grad_output, input, grid): op = torch._C._jit_get_operation('aten::grid_sampler_2d_backward') grad_input, grad_grid = op(grad_output, input, grid, 0, 0, False) ctx.save_for_backward(grid) return grad_input, grad_grid @staticmethod def backward(ctx, grad2_grad_input, grad2_grad_grid): _ = grad2_grad_grid # unused grid, = ctx.saved_tensors grad2_grad_output = None grad2_input = None grad2_grid = None if ctx.needs_input_grad[0]: grad2_grad_output = _GridSample2dForward.apply( grad2_grad_input, grid) assert not ctx.needs_input_grad[2] return grad2_grad_output, grad2_input, grad2_grid ================================================ FILE: mmagic/models/editors/stylegan2/ada/misc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch # Cached construction of constant tensors. Avoids CPU=>GPU copy when the # same constant is used multiple times. _constant_cache = dict() def constant(value, shape=None, dtype=None, device=None, memory_format=None): value = np.asarray(value) if shape is not None: shape = tuple(shape) if dtype is None: dtype = torch.get_default_dtype() if device is None: device = torch.device('cpu') if memory_format is None: memory_format = torch.contiguous_format key = (value.shape, value.dtype, value.tobytes(), shape, dtype, device, memory_format) tensor = _constant_cache.get(key, None) if tensor is None: tensor = torch.as_tensor(value.copy(), dtype=dtype, device=device) if shape is not None: tensor, _ = torch.broadcast_tensors(tensor, torch.empty(shape)) tensor = tensor.contiguous(memory_format=memory_format) _constant_cache[key] = tensor return tensor ================================================ FILE: mmagic/models/editors/stylegan2/ada/upfirdn2d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch try: from mmcv.ops import upfirdn2d except ImportError: upfirdn2d = None print('Warning: mmcv.ops.upfirdn2d is not available.') def _parse_scaling(scaling): if isinstance(scaling, int): scaling = [scaling, scaling] assert isinstance(scaling, (list, tuple)) assert all(isinstance(x, int) for x in scaling) sx, sy = scaling assert sx >= 1 and sy >= 1 return sx, sy def _parse_padding(padding): if isinstance(padding, int): padding = [padding, padding] assert isinstance(padding, (list, tuple)) assert all(isinstance(x, int) for x in padding) if len(padding) == 2: padx, pady = padding padding = [padx, padx, pady, pady] padx0, padx1, pady0, pady1 = padding return padx0, padx1, pady0, pady1 def _get_filter_size(f): if f is None: return 1, 1 assert isinstance(f, torch.Tensor) and f.ndim in [1, 2] fw = f.shape[-1] fh = f.shape[0] fw = int(fw) fh = int(fh) assert fw >= 1 and fh >= 1 return fw, fh def upsample2d(x, f, up=2, padding=0, flip_filter=False, gain=1, impl='cuda'): r"""Upsample a batch of 2D images using the given 2D FIR filter. By default, the result is padded so that its shape is a multiple of the input. User-specified padding is applied on top of that, with negative values indicating cropping. Pixels outside the image are assumed to be zero. Args: x: Float32/float64/float16 input tensor of the shape `[batch_size, num_channels, in_height, in_width]`. f: Float32 FIR filter of the shape `[filter_height, filter_width]` (non-separable), `[filter_taps]` (separable), or `None` (identity). up: Integer upsampling factor. Can be a single int or a list/tuple `[x, y]` (default: 1). padding: Padding with respect to the output. Can be a single number or a list/tuple `[x, y]` or `[x_before, x_after, y_before, y_after]` (default: 0). flip_filter: False = convolution, True = correlation (default: False). gain: Overall scaling factor for signal magnitude (default: 1). impl: Implementation to use. Can be `'ref'` or `'cuda'` (default: `'cuda'`). Returns: Tensor of the shape `[batch_size, num_channels, out_height, out_width]` """ upx, upy = _parse_scaling(up) padx0, padx1, pady0, pady1 = _parse_padding(padding) fw, fh = _get_filter_size(f) p = [ padx0 + (fw + upx - 1) // 2, padx1 + (fw - upx) // 2, pady0 + (fh + upy - 1) // 2, pady1 + (fh - upy) // 2, ] gain = gain * upx * upy f = f * (gain**(f.ndim / 2)) if flip_filter: f = f.flip(list(range(f.ndim))) if f.ndim == 1: x = upfirdn2d( x, f.unsqueeze(0), up=(upx, 1), padding=(p[0], p[1], 0, 0)) x = upfirdn2d( x, f.unsqueeze(1), up=(1, upy), padding=(0, 0, p[2], p[3])) return x def setup_filter(f, device=torch.device('cpu'), normalize=True, flip_filter=False, gain=1, separable=None): r"""Convenience function to setup 2D FIR filter for `upfirdn2d()`. Args: f: Torch tensor, numpy array, or python list of the shape `[filter_height, filter_width]` (non-separable), `[filter_taps]` (separable), `[]` (impulse), or `None` (identity). device: Result device (default: cpu). normalize: Normalize the filter so that it retains the magnitude for constant input signal (DC)? (default: True). flip_filter: Flip the filter? (default: False). gain: Overall scaling factor for signal magnitude (default: 1). separable: Return a separable filter? (default: select automatically) Returns: Float32 tensor of the shape `[filter_height, filter_width]` (non-separable) or `[filter_taps]` (separable). """ # Validate. if f is None: f = 1 f = torch.as_tensor(f, dtype=torch.float32) assert f.ndim in [0, 1, 2] assert f.numel() > 0 if f.ndim == 0: f = f[np.newaxis] # Separable? if separable is None: separable = (f.ndim == 1 and f.numel() >= 8) if f.ndim == 1 and not separable: f = f.ger(f) assert f.ndim == (1 if separable else 2) # Apply normalize, flip, gain, and device. if normalize: f /= f.sum() if flip_filter: f = f.flip(list(range(f.ndim))) f = f * (gain**(f.ndim / 2)) f = f.to(device=device) return f def downsample2d(x, f, down=2, padding=0, flip_filter=False, gain=1, impl='cuda'): r"""Downsample a batch of 2D images using the given 2D FIR filter. By default, the result is padded so that its shape is a fraction of the input. User-specified padding is applied on top of that, with negative values indicating cropping. Pixels outside the image are assumed to be zero. Args: x: Float32/float64/float16 input tensor of the shape `[batch_size, num_channels, in_height, in_width]`. f: Float32 FIR filter of the shape `[filter_height, filter_width]` (non-separable), `[filter_taps]` (separable), or `None` (identity). down: Integer downsampling factor. Can be a single int or a list/tuple `[x, y]` (default: 1). padding: Padding with respect to the input. Can be a single number or a list/tuple `[x, y]` or `[x_before, x_after, y_before, y_after]` (default: 0). flip_filter: False = convolution, True = correlation (default: False). gain: Overall scaling factor for signal magnitude (default: 1). impl: Implementation to use. Can be `'ref'` or `'cuda'` (default: `'cuda'`). Returns: Tensor of the shape `[batch_size, num_channels, out_height, out_width]` """ downx, downy = _parse_scaling(down) padx0, padx1, pady0, pady1 = _parse_padding(padding) fw, fh = _get_filter_size(f) p = [ padx0 + (fw - downx + 1) // 2, padx1 + (fw - downx) // 2, pady0 + (fh - downy + 1) // 2, pady1 + (fh - downy) // 2, ] if flip_filter: f = f.flip(list(range(f.ndim))) if f.ndim == 1: x = upfirdn2d( x, f.unsqueeze(0), down=(downx, 1), padding=(p[0], p[1], 0, 0)) x = upfirdn2d( x, f.unsqueeze(1), down=(1, downy), padding=(0, 0, p[2], p[3])) return x ================================================ FILE: mmagic/models/editors/stylegan2/stylegan2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine import Config, MessageHub from mmengine.model import BaseModel, is_model_wrapper from mmengine.optim import OptimWrapper, OptimWrapperDict from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from ...base_models import BaseGAN from ...losses import gen_path_regularizer, r1_gradient_penalty_loss from ...utils import set_requires_grad ModelType = Union[Dict, nn.Module] @MODELS.register_module() class StyleGAN2(BaseGAN): """Implementation of `Analyzing and Improving the Image Quality of Stylegan`. # noqa. Paper link: https://openaccess.thecvf.com/content_CVPR_2020/html/Karras_Analyzing_and_Improving_the_Image_Quality_of_StyleGAN_CVPR_2020_paper.html. # noqa :class:`~mmagic.models.editors.stylegan2.StyleGAN2Generator` and :class:`~mmagic.models.editors.stylegan2.StyleGAN2Discriminator` Args: generator (ModelType): The config or model of the generator. discriminator (Optional[ModelType]): The config or model of the discriminator. Defaults to None. data_preprocessor (Optional[Union[dict, Config]]): The pre-process config or :class:`~mmagic.models.DataPreprocessor`. generator_steps (int): The number of times the generator is completely updated before the discriminator is updated. Defaults to 1. discriminator_steps (int): The number of times the discriminator is completely updated before the generator is updated. Defaults to 1. ema_config (Optional[Dict]): The config for generator's exponential moving average setting. Defaults to None. """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, ema_config: Optional[Dict] = None, loss_config=dict()): BaseModel.__init__(self, data_preprocessor=data_preprocessor) # build generator if isinstance(generator, dict): self._gen_cfg = deepcopy(generator) generator = MODELS.build(generator) self.generator = generator # get valid noise_size self.noise_size = getattr(self.generator, 'style_channels', 512) # build discriminator if discriminator: if isinstance(discriminator, dict): self._disc_cfg = deepcopy(discriminator) # build discriminator with default `num_classes` disc_args = dict() if hasattr(self, 'num_classes'): disc_args['num_classes'] = self.num_classes discriminator = MODELS.build( discriminator, default_args=disc_args) self.discriminator = discriminator self._gen_steps = generator_steps self._disc_steps = discriminator_steps if ema_config is None: self._ema_config = None self._with_ema_gen = False else: self._ema_config = deepcopy(ema_config) self._init_ema_model(self._ema_config) self._with_ema_gen = True # loss config self.loss_config = deepcopy(loss_config) # r1 settings self.r1_loss_weight = self.loss_config.get('r1_loss_weight', 80.0) self.r1_interval = self.loss_config.get('r1_interval', 16) self.norm_mode = self.loss_config.get('norm_mode', 'pixel') self.r1_use_apex_amp = self.loss_config.get('r1_use_apex_amp', False) self.scale_r1_loss = self.loss_config.get('scale_r1_loss', False) # gen path reg settings self.g_reg_interval = self.loss_config.get('g_reg_interval', 4) self.g_reg_weight = self.loss_config.get('g_reg_weight', 8.) self.pl_batch_shrink = self.loss_config.get('pl_batch_shrink', 2) self.g_reg_use_apex_amp = self.loss_config.get('g_reg_use_apex_amp', False) self.register_buffer('mean_path_length', torch.tensor(0.)) def disc_loss(self, disc_pred_fake: Tensor, disc_pred_real: Tensor, real_imgs: Tensor) -> Tuple: r"""Get disc loss. StyleGANv2 use the non-saturating loss and R1 gradient penalty to train the discriminator. Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. real_imgs (Tensor): Input real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() # no-saturating gan loss losses_dict['loss_disc_fake'] = F.softplus(disc_pred_fake).mean() losses_dict['loss_disc_real'] = F.softplus(-disc_pred_real).mean() # R1 Gradient Penalty message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') if curr_iter % self.r1_interval == 0: losses_dict[ 'loss_r1_gp'] = self.r1_loss_weight * r1_gradient_penalty_loss( self.discriminator, real_imgs, norm_mode=self.norm_mode, use_apex_amp=self.r1_use_apex_amp) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor, batch_size: int) -> Tuple: """Get gen loss. StyleGANv2 use the non-saturating loss and generator path regularization to train the generator. Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. batch_size (int): Batch size for generating fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() # no-saturating gan loss losses_dict['loss_gen'] = F.softplus(-disc_pred_fake).mean() # Generator Path Regularizer message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') if curr_iter % self.g_reg_interval == 0: path_penalty, self.mean_path_length, _ = gen_path_regularizer( self.generator, batch_size, self.mean_path_length, pl_batch_shrink=self.pl_batch_shrink, use_apex_amp=self.g_reg_use_apex_amp) losses_dict['loss_path_regular'] = self.g_reg_weight * path_penalty loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real, real_imgs) optimizer_wrapper.update_params(parsed_losses) # save ada info message_hub = MessageHub.get_current_instance() message_hub.update_info('disc_pred_real', disc_pred_real) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake, num_batches) optimizer_wrapper.update_params(parsed_loss) return log_vars def train_step(self, data: dict, optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: """Train GAN model. In the training of GAN models, generator and discriminator are updated alternatively. In MMagic's design, `self.train_step` is called with data input. Therefore we always update discriminator, whose updating is relay on real data, and then determine if the generator needs to be updated based on the current number of iterations. More details about whether to update generator can be found in :meth:`should_gen_update`. Args: data (dict): Data sampled from dataloader. optim_wrapper (OptimWrapperDict): OptimWrapperDict instance contains OptimWrapper of generator and discriminator. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') data = self.data_preprocessor(data, True) inputs_dict, data_samples = data['inputs'], data['data_samples'] disc_optimizer_wrapper: OptimWrapper = optim_wrapper['discriminator'] disc_accu_iters = disc_optimizer_wrapper._accumulative_counts # NOTE: Do not use context manager of optim_wrapper. Because # in mixed-precision training, StyleGAN2 only enable fp16 in # specified blocks (refers to `:attr:enable_fp16` in # :class:`~StyleGANv2Generator` and :class:`~StyleGAN2Discriminator` # for more details), but in :func:`~AmpOptimWrapper.optim_context`, # fp16 is applied to all modules. This may slow down gradient # accumulation because `no_sycn` in # :func:`~OptimWrapper.optim_context` will not be called any more. log_vars = self.train_discriminator(inputs_dict, data_samples, disc_optimizer_wrapper) # add 1 to `curr_iter` because iter is updated in train loop. # Whether to update the generator. We update generator with # discriminator is fully updated for `self.n_discriminator_steps` # iterations. And one full updating for discriminator contains # `disc_accu_counts` times of grad accumulations. if (curr_iter + 1) % (self.discriminator_steps * disc_accu_iters) == 0: set_requires_grad(self.discriminator, False) gen_optimizer_wrapper = optim_wrapper['generator'] gen_accu_iters = gen_optimizer_wrapper._accumulative_counts log_vars_gen_list = [] # init optimizer wrapper status for generator manually gen_optimizer_wrapper.initialize_count_status( self.generator, 0, self.generator_steps * gen_accu_iters) for _ in range(self.generator_steps * gen_accu_iters): log_vars_gen = self.train_generator(inputs_dict, data_samples, gen_optimizer_wrapper) log_vars_gen_list.append(log_vars_gen) log_vars_gen = self.gather_log_vars(log_vars_gen_list) log_vars_gen.pop('loss', None) # remove 'loss' from gen logs set_requires_grad(self.discriminator, True) # only do ema after generator update if self.with_ema_gen and (curr_iter + 1) >= ( self.ema_start * self.discriminator_steps * disc_accu_iters): self.generator_ema.update_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) # if not update buffer, copy buffer from orig model if not self.generator_ema.update_buffers: self.generator_ema.sync_buffers( self.generator.module if is_model_wrapper( self.generator) else self.generator) elif self.with_ema_gen: # before ema, copy weights from orig self.generator_ema.sync_parameters( self.generator.module if is_model_wrapper(self.generator) else self.generator) log_vars.update(log_vars_gen) batch_size = len(data['data_samples']) # update ada p if hasattr(self.discriminator, 'with_ada') and self.discriminator.with_ada: self.discriminator.ada_aug.log_buffer[0] += batch_size self.discriminator.ada_aug.log_buffer[1] += message_hub.get_info( 'disc_pred_real').sign().sum() self.discriminator.ada_aug.update( iteration=curr_iter, num_batches=batch_size) log_vars['augment'] = ( self.discriminator.ada_aug.aug_pipeline.p.data.cpu()) return log_vars ================================================ FILE: mmagic/models/editors/stylegan2/stylegan2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import mmengine import numpy as np import torch import torch.nn as nn from mmengine.model import BaseModule from mmengine.runner.amp import autocast from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from torch import Tensor from mmagic.registry import MODELS from ..stylegan1 import EqualLinearActModule from ..stylegan3.stylegan3_modules import MappingNetwork from .ada.augment import AugmentPipe from .ada.misc import constant from .stylegan2_modules import ConvDownLayer, ModMBStddevLayer, ResBlock @MODELS.register_module('StyleGANv2Discriminator') @MODELS.register_module() class StyleGAN2Discriminator(BaseModule): """StyleGAN2 Discriminator. The architecture of this discriminator is proposed in StyleGAN2. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN CVPR2020. You can load pretrained model through passing information into ``pretrained`` argument. We have already offered official weights as follows: - stylegan2-ffhq-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-ffhq-config-f-official_20210327_171224-bce9310c.pth # noqa - stylegan2-horse-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-horse-config-f-official_20210327_173203-ef3e69ca.pth # noqa - stylegan2-car-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-car-config-f-official_20210327_172340-8cfe053c.pth # noqa - stylegan2-cat-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-cat-config-f-official_20210327_172444-15bc485b.pth # noqa - stylegan2-church-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-church-config-f-official_20210327_172657-1d42b7d1.pth # noqa If you want to load the ema model, you can just use following codes: .. code-block:: python # ckpt_http is one of the valid path from http source discriminator = StyleGAN2Discriminator(1024, 512, pretrained=dict( ckpt_path=ckpt_http, prefix='discriminator')) Of course, you can also download the checkpoint in advance and set ``ckpt_path`` with local path. Note that our implementation adopts BGR image as input, while the original StyleGAN2 provides RGB images to the discriminator. Thus, we provide ``bgr2rgb`` argument to convert the image space. If your images follow the RGB order, please set it to ``True`` accordingly. Args: in_size (int): The input size of images. img_channels (int): The number of channels of the input image. Defaults to 3. channel_multiplier (int, optional): The multiplier factor for the channel number. Defaults to 2. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 3, 3, 1]. mbstd_cfg (dict, optional): Configs for minibatch-stddev layer. Defaults to dict(group_size=4, channel_groups=1). cond_size (int, optional): The size of conditional input. If None or less than 1, no conditional mapping will be applied. Defaults to None. cond_mapping_channels (int, optional): The dimension of the output of conditional mapping. Only work when :attr:`c_dim` is larger than 0. If :attr:`c_dim` is larger than 0 and :attr:`cmap_dim` is None, will. Defaults to None. cond_mapping_layers (int, optional): The number of mapping layer used to map conditional input. Only work when c_dim is larger than 0. If :attr:`cmapping_layer` is None and :attr:`c_dim` is larger than 0, cmapping_layer will set as 8. Defaults to None. num_fp16_scales (int, optional): The number of resolutions to use auto fp16 training. Defaults to 0. fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. out_fp32 (bool, optional): Whether to convert the output feature map to `torch.float32`. Defaults to `True`. convert_input_fp32 (bool, optional): Whether to convert input type to fp32 if not `fp16_enabled`. This argument is designed to deal with the cases where some modules are run in FP16 and others in FP32. Defaults to True. input_bgr2rgb (bool, optional): Whether to reformat the input channels with order `rgb`. Since we provide several converted weights, whose input order is `rgb`. You can set this argument to True if you want to finetune on converted weights. Defaults to False. pretrained (dict | None, optional): Information for pretrained models. The necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ def __init__(self, in_size, img_channels=3, channel_multiplier=2, blur_kernel=[1, 3, 3, 1], mbstd_cfg=dict(group_size=4, channel_groups=1), cond_size=None, cond_mapping_channels=None, cond_mapping_layers=None, num_fp16_scales=0, fp16_enabled=False, out_fp32=True, convert_input_fp32=True, input_bgr2rgb=False, init_cfg=None, pretrained=None): # TODO: pretrained can be deleted later super().__init__(init_cfg=init_cfg) self.num_fp16_scale = num_fp16_scales self.fp16_enabled = fp16_enabled self.convert_input_fp32 = convert_input_fp32 self.out_fp32 = out_fp32 channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256 * channel_multiplier, 128: 128 * channel_multiplier, 256: 64 * channel_multiplier, 512: 32 * channel_multiplier, 1024: 16 * channel_multiplier, } log_size = int(np.log2(in_size)) in_channels = channels[in_size] _use_fp16 = num_fp16_scales > 0 or fp16_enabled convs = [ ConvDownLayer( img_channels, channels[in_size], 1, fp16_enabled=_use_fp16) ] for i in range(log_size, 2, -1): out_channel = channels[2**(i - 1)] # add fp16 training for higher resolutions _use_fp16 = (log_size - i) < num_fp16_scales or fp16_enabled convs.append( ResBlock( in_channels, out_channel, blur_kernel, fp16_enabled=_use_fp16, convert_input_fp32=convert_input_fp32)) in_channels = out_channel if cond_size is not None and cond_size > 0: cond_mapping_channels = 512 if cond_mapping_channels is None \ else cond_mapping_channels cond_mapping_layers = 8 if cond_mapping_layers is None \ else cond_mapping_layers self.mapping = MappingNetwork( noise_size=0, style_channels=cond_mapping_channels, cond_size=cond_size, num_ws=None, num_layers=cond_mapping_layers, w_avg_beta=None) self.convs = nn.Sequential(*convs) self.mbstd_layer = ModMBStddevLayer(**mbstd_cfg) self.final_conv = ConvDownLayer( in_channels + 1, channels[4], 3, fp16_enabled=fp16_enabled) if cond_size is None or cond_size <= 0: final_linear_out_channels = 1 else: final_linear_out_channels = cond_mapping_channels self.final_linear = nn.Sequential( EqualLinearActModule( channels[4] * 4 * 4, channels[4], act_cfg=dict(type='fused_bias')), EqualLinearActModule(channels[4], final_linear_out_channels), ) self.input_bgr2rgb = input_bgr2rgb if pretrained is not None: self._load_pretrained_model(**pretrained) def _load_pretrained_model(self, ckpt_path, prefix='', map_location='cpu', strict=True): state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained model from {ckpt_path}') def forward(self, x: Tensor, label: Optional[Tensor] = None): """Forward function. Args: x (torch.Tensor): Input image tensor. label (torch.Tensor, optional): The conditional input feed to mapping layer. Defaults to None. Returns: torch.Tensor: Predict score for the input image. """ # This setting was used to finetune on converted weights if self.input_bgr2rgb: x = x[:, [2, 1, 0], ...] # convs has own fp-16 controller, do not wrap here x = self.convs(x) x = self.mbstd_layer(x) fp16_enabled = ( self.final_conv.fp16_enabled or not self.convert_input_fp32) with autocast(enabled=fp16_enabled): if not fp16_enabled: x = x.to(torch.float32) x = self.final_conv(x) x = x.view(x.shape[0], -1) x = self.final_linear(x) # conditioning if label is not None: assert self.mapping is not None, ( '\'self.mapping\' must not be None when conditional input ' 'is passed.') cmap = self.mapping(None, label) x = (x * cmap).sum( dim=1, keepdim=True) * (1 / np.sqrt(cmap.shape[1])) return x @MODELS.register_module() class ADAStyleGAN2Discriminator(StyleGAN2Discriminator): def __init__(self, in_size, *args, data_aug=None, **kwargs): """StyleGANv2 Discriminator with adaptive augmentation. Args: in_size (int): The input size of images. data_aug (dict, optional): Config for data augmentation. Defaults to None. """ super().__init__(in_size, *args, **kwargs) self.with_ada = data_aug is not None and data_aug != dict() if self.with_ada: self.ada_aug = MODELS.build(data_aug) self.ada_aug.requires_grad = False self.log_size = int(np.log2(in_size)) def forward(self, x): """Forward function.""" if self.with_ada: x = self.ada_aug.aug_pipeline(x) return super().forward(x) @MODELS.register_module() class ADAAug(BaseModule): """Data Augmentation Module for Adaptive Discriminator augmentation. Args: aug_pipeline (dict, optional): Config for augmentation pipeline. Defaults to None. update_interval (int, optional): Interval for updating augmentation probability. Defaults to 4. augment_initial_p (float, optional): Initial augmentation probability. Defaults to 0.. ada_target (float, optional): ADA target. Defaults to 0.6. ada_kimg (int, optional): ADA training duration. Defaults to 500. """ def __init__(self, aug_pipeline=None, update_interval=4, augment_initial_p=0., ada_target=0.6, ada_kimg=500): super().__init__() aug_pipeline = dict() if aug_pipeline is None else aug_pipeline self.aug_pipeline = AugmentPipe(**aug_pipeline) self.update_interval = update_interval self.ada_kimg = ada_kimg self.ada_target = ada_target self.aug_pipeline.p.copy_(torch.tensor(augment_initial_p)) # this log buffer stores two numbers: num_scalars, sum_scalars. self.register_buffer('log_buffer', torch.zeros((2, ))) def update(self, iteration=0, num_batches=0): """Update Augment probability. Args: iteration (int, optional): Training iteration. Defaults to 0. num_batches (int, optional): The number of reals batches. Defaults to 0. """ if (iteration + 1) % self.update_interval == 0: adjust_step = float(num_batches * self.update_interval) / float( self.ada_kimg * 1000.) # get the mean value as the ada heuristic ada_heuristic = self.log_buffer[1] / self.log_buffer[0] adjust = np.sign(ada_heuristic.item() - self.ada_target) * adjust_step # update the augment p # Note that p may be bigger than 1.0 self.aug_pipeline.p.copy_( (self.aug_pipeline.p + adjust).max(constant(0, device=self.log_buffer.device))) self.log_buffer = self.log_buffer * 0. ================================================ FILE: mmagic/models/editors/stylegan2/stylegan2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random import mmengine import numpy as np import torch import torch.nn as nn from mmengine.model import BaseModule from mmengine.runner.amp import autocast from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from mmagic.registry import MODELS from ...utils import get_module_device from ..pggan import PixelNorm from ..stylegan1 import (ConstantInput, EqualLinearActModule, get_mean_latent, style_mixing) from .stylegan2_modules import ModulatedStyleConv, ModulatedToRGB @MODELS.register_module('StyleGANv2Generator') @MODELS.register_module() class StyleGAN2Generator(BaseModule): r"""StyleGAN2 Generator. In StyleGAN2, we use a static architecture composing of a style mapping module and number of convolutional style blocks. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN CVPR2020. You can load pretrained model through passing information into ``pretrained`` argument. We have already offered official weights as follows: - stylegan2-ffhq-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-ffhq-config-f-official_20210327_171224-bce9310c.pth # noqa - stylegan2-horse-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-horse-config-f-official_20210327_173203-ef3e69ca.pth # noqa - stylegan2-car-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-car-config-f-official_20210327_172340-8cfe053c.pth # noqa - stylegan2-cat-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-cat-config-f-official_20210327_172444-15bc485b.pth # noqa - stylegan2-church-config-f: https://download.openmmlab.com/mmediting/stylegan2/official_weights/stylegan2-church-config-f-official_20210327_172657-1d42b7d1.pth # noqa If you want to load the ema model, you can just use following codes: .. code-block:: python # ckpt_http is one of the valid path from http source generator = StyleGANv2Generator(1024, 512, pretrained=dict( ckpt_path=ckpt_http, prefix='generator_ema')) Of course, you can also download the checkpoint in advance and set ``ckpt_path`` with local path. If you just want to load the original generator (not the ema model), please set the prefix with 'generator'. Note that our implementation allows to generate BGR image, while the original StyleGAN2 outputs RGB images by default. Thus, we provide ``bgr2rgb`` argument to convert the image space. Args: out_size (int): The output size of the StyleGAN2 generator. style_channels (int): The number of channels for style code. out_channels (int): The number of channels for output. Defaults to 3. noise_size (int, optional): The size of (number of channels) the input noise. If not passed, will be set the same value as :attr:`style_channels`. Defaults to None. cond_size (int, optional): The size of the conditional input. If not passed or less than 1, no conditional embedding will be used. Defaults to None. cond_mapping_channels (int, optional): The channels of the conditional mapping layers. If not passed, will use the same value as :attr:`style_channels`. Defaults to None. num_mlps (int, optional): The number of MLP layers. Defaults to 8. channel_multiplier (int, optional): The multiplier factor for the channel number. Defaults to 2. blur_kernel (list, optional): The blurry kernel. Defaults to [1, 3, 3, 1]. lr_mlp (float, optional): The learning rate for the style mapping layer. Defaults to 0.01. default_style_mode (str, optional): The default mode of style mixing. In training, we adopt mixing style mode in default. However, in the evaluation, we use 'single' style mode. `['mix', 'single']` are currently supported. Defaults to 'mix'. eval_style_mode (str, optional): The evaluation mode of style mixing. Defaults to 'single'. mix_prob (float, optional): Mixing probability. The value should be in range of [0, 1]. Defaults to ``0.9``. update_mean_latent_with_ema (bool, optional): Whether update mean latent code (w) with EMA. Defaults to False. w_avg_beta (float, optional): The value used for update `w_avg`. Defaults to 0.998. num_fp16_scales (int, optional): The number of resolutions to use auto fp16 training. Different from ``fp16_enabled``, this argument allows users to adopt FP16 training only in several blocks. This behaviour is much more similar to the official implementation by Tero. Defaults to 0. fp16_enabled (bool, optional): Whether to use fp16 training in this module. If this flag is `True`, the whole module will be wrapped with ``auto_fp16``. Defaults to False. pretrained (dict | None, optional): Information for pretrained models. The necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. """ def __init__(self, out_size, style_channels, out_channels=3, noise_size=None, cond_size=None, cond_mapping_channels=None, num_mlps=8, channel_multiplier=2, blur_kernel=[1, 3, 3, 1], lr_mlp=0.01, default_style_mode='mix', eval_style_mode='single', norm_eps=1e-6, mix_prob=0.9, update_mean_latent_with_ema=False, w_avg_beta=0.998, num_fp16_scales=0, fp16_enabled=False, bgr2rgb=False, pretrained=None, fixed_noise=False): super().__init__() self.out_size = out_size self.style_channels = style_channels self.out_channels = out_channels self.num_mlps = num_mlps self.channel_multiplier = channel_multiplier self.lr_mlp = lr_mlp self._default_style_mode = default_style_mode self.default_style_mode = default_style_mode self.eval_style_mode = eval_style_mode self.mix_prob = mix_prob self.num_fp16_scales = num_fp16_scales self.fp16_enabled = fp16_enabled self.bgr2rgb = bgr2rgb self.noise_size = style_channels if noise_size is None else noise_size self.cond_size = cond_size if self.cond_size is not None and self.cond_size > 0: cond_mapping_channels = style_channels \ if cond_mapping_channels is None else cond_mapping_channels self.embed = EqualLinearActModule(cond_size, cond_mapping_channels) # NOTE: conditional input is passed, do 2nd moment norm for # embedding and noise input respectively, therefore mapping layer # start with FC layer mapping_layers = [] else: cond_mapping_channels = 0 # NOTE: conditional input is not passed, put 2nd moment norm at # the start of mapping layers mapping_layers = [PixelNorm(eps=norm_eps)] in_feat = cond_mapping_channels + self.noise_size # define pixel norm self.pixel_norm = PixelNorm(eps=norm_eps) # define style mapping layers for idx in range(num_mlps): mapping_layers.append( EqualLinearActModule( in_feat if idx == 0 else style_channels, style_channels, equalized_lr_cfg=dict(lr_mul=lr_mlp, gain=1.), act_cfg=dict(type='fused_bias'))) self.style_mapping = nn.Sequential(*mapping_layers) self.channels = { 4: 512, 8: 512, 16: 512, 32: 512, 64: 256 * channel_multiplier, 128: 128 * channel_multiplier, 256: 64 * channel_multiplier, 512: 32 * channel_multiplier, 1024: 16 * channel_multiplier, } # constant input layer self.constant_input = ConstantInput(self.channels[4]) # 4x4 stage self.conv1 = ModulatedStyleConv( self.channels[4], self.channels[4], kernel_size=3, style_channels=style_channels, blur_kernel=blur_kernel, fp16_enabled=fp16_enabled, fixed_noise=fixed_noise) self.to_rgb1 = ModulatedToRGB( self.channels[4], style_channels, out_channels=out_channels, upsample=False, fp16_enabled=fp16_enabled) # generator backbone (8x8 --> higher resolutions) self.log_size = int(np.log2(self.out_size)) self.convs = nn.ModuleList() self.upsamples = nn.ModuleList() self.to_rgbs = nn.ModuleList() blk_in_channels_ = self.channels[4] # in channels of the conv blocks for i in range(3, self.log_size + 1): blk_out_channels_ = self.channels[2**i] # If `fp16_enabled` is True, all of layers will be run in auto # FP16. In the case of `num_fp16_scales` > 0, only partial # layers will be run in fp16. _use_fp16 = (self.log_size - i) < num_fp16_scales or fp16_enabled self.convs.append( ModulatedStyleConv( blk_in_channels_, blk_out_channels_, 3, style_channels, upsample=True, blur_kernel=blur_kernel, fp16_enabled=_use_fp16)) self.convs.append( ModulatedStyleConv( blk_out_channels_, blk_out_channels_, 3, style_channels, upsample=False, blur_kernel=blur_kernel, fp16_enabled=_use_fp16)) self.to_rgbs.append( ModulatedToRGB( blk_out_channels_, style_channels, out_channels=out_channels, upsample=True, fp16_enabled=_use_fp16)) # set to global fp16 blk_in_channels_ = blk_out_channels_ self.num_latents = self.log_size * 2 - 2 self.num_injected_noises = self.num_latents - 1 # register buffer for injected noises for layer_idx in range(self.num_injected_noises): res = (layer_idx + 5) // 2 shape = [1, 1, 2**res, 2**res] self.register_buffer(f'injected_noise_{layer_idx}', torch.randn(*shape)) if (self.cond_size is not None and self.cond_size > 0) or update_mean_latent_with_ema: # Due to `get_mean_latent` cannot handle conditional input, # assign avg style code here and update with EMA. self.register_buffer('w_avg', torch.zeros([style_channels])) self.w_avg_beta = w_avg_beta mmengine.print_log('Mean latent code (w) is updated with EMA.') if pretrained is not None: self._load_pretrained_model(**pretrained) def _load_pretrained_model(self, ckpt_path, prefix='', map_location='cpu', strict=True): state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained model from {ckpt_path}') def train(self, mode=True): if mode: if self.default_style_mode != self._default_style_mode: mmengine.print_log( f'Switch to train style mode: {self._default_style_mode}') self.default_style_mode = self._default_style_mode else: if self.default_style_mode != self.eval_style_mode: mmengine.print_log( f'Switch to evaluation style mode: {self.eval_style_mode}') self.default_style_mode = self.eval_style_mode return super(StyleGAN2Generator, self).train(mode) def make_injected_noise(self): """make noises that will be injected into feature maps. Returns: list[Tensor]: List of layer-wise noise tensor. """ device = get_module_device(self) noises = [torch.randn(1, 1, 2**2, 2**2, device=device)] for i in range(3, self.log_size + 1): for _ in range(2): noises.append(torch.randn(1, 1, 2**i, 2**i, device=device)) return noises def get_mean_latent(self, num_samples=4096, **kwargs): """Get mean latent of W space in this generator. Args: num_samples (int, optional): Number of sample times. Defaults to 4096. Returns: Tensor: Mean latent of this generator. """ if hasattr(self, 'w_avg'): mmengine.print_log('Get latent code (w) which is updated by EMA.') return self.w_avg return get_mean_latent(self, num_samples, **kwargs) def style_mixing(self, n_source, n_target, inject_index=1, truncation_latent=None, truncation=0.7): return style_mixing( self, n_source=n_source, n_target=n_target, inject_index=inject_index, truncation=truncation, truncation_latent=truncation_latent, style_channels=self.style_channels) # @auto_fp16() def forward(self, styles, label=None, num_batches=-1, return_noise=False, return_latents=False, inject_index=None, truncation=1, truncation_latent=None, input_is_latent=False, injected_noise=None, add_noise=True, randomize_noise=True, update_ws=False, return_features=False, feat_idx=5, return_latent_only=False): """Forward function. This function has been integrated with the truncation trick. Please refer to the usage of `truncation` and `truncation_latent`. Args: styles (torch.Tensor | list[torch.Tensor] | callable | None): In StyleGAN2, you can provide noise tensor or latent tensor. Given a list containing more than one noise or latent tensors, style mixing trick will be used in training. Of course, You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. label (torch.Tensor, optional): Conditional inputs for the generator. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. return_latents (bool, optional): If True, ``latent`` will be returned in a dict with ``fake_img``. Defaults to False. inject_index (int | None, optional): The index number for mixing style codes. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. truncation_latent (torch.Tensor, optional): Mean truncation latent. Defaults to None. input_is_latent (bool, optional): If `True`, the input tensor is the latent tensor. Defaults to False. injected_noise (torch.Tensor | None, optional): Given a tensor, the random noise will be fixed as this input injected noise. Defaults to None. add_noise (bool): Whether apply noise injection. Defaults to True. randomize_noise (bool, optional): If `False`, images are sampled with the buffered noise tensor injected to the style conv block. Defaults to True. update_ws (bool): Whether update latent code with EMA. Only work when `w_avg` is registered. Defaults to False. Returns: torch.Tensor | dict: Generated image tensor or dictionary \ containing more data. """ # device = styles.device input_dim = self.style_channels if input_is_latent else self.noise_size # receive noise and conduct sanity check. if isinstance(styles, torch.Tensor): assert styles.shape[1] == input_dim styles = [styles] elif mmengine.is_seq_of(styles, torch.Tensor): for t in styles: assert t.shape[-1] == input_dim # receive a noise generator and sample noise. elif callable(styles): device = get_module_device(self) noise_generator = styles assert num_batches > 0 if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ noise_generator((num_batches, input_dim)) for _ in range(2) ] else: styles = [noise_generator((num_batches, input_dim))] styles = [s.to(device) for s in styles] # otherwise, we will adopt default noise sampler. else: device = get_module_device(self) assert num_batches > 0 and not input_is_latent if self.default_style_mode == 'mix' and random.random( ) < self.mix_prob: styles = [ torch.randn((num_batches, input_dim)) for _ in range(2) ] else: styles = [torch.randn((num_batches, input_dim))] styles = [s.to(device) for s in styles] # no amp for style-mapping and condition-embedding if not input_is_latent: noise_batch = styles if self.cond_size is not None and self.cond_size > 0: assert label is not None, ( '\'cond_channels\' is not None, \'cond\' must be passed.') assert label.shape[1] == self.cond_size embedding = self.embed(label) # NOTE: If conditional input is passed, do norm for cond # embedding and noise input respectively # do pixel_norm (2nd_moment_norm) to cond embedding embedding = self.pixel_norm(embedding) # do pixel_norm (2nd_moment_norm) to noise input styles = [self.pixel_norm(s) for s in styles] styles_list = [] for s in styles: if self.cond_size is not None and self.cond_size > 0: s = torch.cat([s, embedding], dim=1) styles_list.append(self.style_mapping(s)) styles = styles_list else: noise_batch = None # update w_avg during training, if need if hasattr(self, 'w_avg') and self.training and update_ws: # only update w_avg with the first style code self.w_avg.copy_(styles[0].detach().mean( dim=0).lerp(self.w_avg, self.w_avg_beta)) if injected_noise is None: if randomize_noise: injected_noise = [None] * self.num_injected_noises else: injected_noise = [ getattr(self, f'injected_noise_{i}') for i in range(self.num_injected_noises) ] # use truncation trick if truncation < 1: style_t = [] # calculate truncation latent on the fly if truncation_latent is None and not hasattr( self, 'truncation_latent'): self.truncation_latent = self.get_mean_latent() truncation_latent = self.truncation_latent elif truncation_latent is None and hasattr(self, 'truncation_latent'): truncation_latent = self.truncation_latent for style in styles: style_t.append(truncation_latent + truncation * (style - truncation_latent)) styles = style_t # no style mixing if len(styles) < 2: inject_index = self.num_latents if styles[0].ndim < 3: latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) else: latent = styles[0] # style mixing else: if inject_index is None: inject_index = random.randint(1, self.num_latents - 1) latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1) latent2 = styles[1].unsqueeze(1).repeat( 1, self.num_latents - inject_index, 1) latent = torch.cat([latent, latent2], 1) if return_latent_only: return latent feats = [] with autocast(enabled=self.fp16_enabled): # 4x4 stage out = self.constant_input(latent) if self.fp16_enabled: out = out.to(torch.float16) out = self.conv1( out, latent[:, 0], noise=injected_noise[0], add_noise=add_noise) feats.append(out) skip = self.to_rgb1(out, latent[:, 1]) _index = 1 # 8x8 ---> higher resolutions for up_conv, conv, noise1, noise2, to_rgb in zip( self.convs[::2], self.convs[1::2], injected_noise[1::2], injected_noise[2::2], self.to_rgbs): out = up_conv( out, latent[:, _index], noise=noise1, add_noise=add_noise) out = conv( out, latent[:, _index + 1], noise=noise2, add_noise=add_noise) feats.append(out) skip = to_rgb(out, latent[:, _index + 2], skip) _index += 2 # make sure the output image is torch.float32 to avoid RunTime Error # in other modules img = skip.to(torch.float32) if self.bgr2rgb: img = torch.flip(img, dims=[1]) if return_latents or return_noise: if return_features: output_dict = dict( fake_img=img, latent=latent, inject_index=inject_index, noise_batch=noise_batch, feats=feats[feat_idx]) return output_dict output_dict = dict( fake_img=img, latent=latent, inject_index=inject_index, noise_batch=noise_batch) return output_dict return img ================================================ FILE: mmagic/models/editors/stylegan2/stylegan2_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmengine import numpy as np import torch import torch.nn as nn from mmcv.ops.fused_bias_leakyrelu import (FusedBiasLeakyReLU, fused_bias_leakyrelu) from mmcv.ops.upfirdn2d import upfirdn2d from mmengine.dist import get_dist_info from mmengine.model import BaseModule from mmengine.runner.amp import autocast from mmagic.models.archs import AllGatherLayer from ..pggan import EqualizedLRConvModule, equalized_lr from ..stylegan1 import Blur, EqualLinearActModule, NoiseInjection, make_kernel try: from mmcv.ops import conv2d, conv_transpose2d except ImportError: import torch.nn.functional as F conv2d = F.conv2d conv_transpose2d = F.conv_transpose2d print('Warning: mmcv.ops.conv2d, mmcv.ops.conv_transpose2d' ' and mmcv.ops.upfirdn2d are not available.') class _FusedBiasLeakyReLU(FusedBiasLeakyReLU): """Wrap FusedBiasLeakyReLU to support FP16 training.""" def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, ...). Returns: Tensor: Output feature map. """ return fused_bias_leakyrelu(x, self.bias.to(x.dtype), self.negative_slope, self.scale) class UpsampleUpFIRDn(BaseModule): """UpFIRDn for Upsampling. This module is used in the ``to_rgb`` layers in StyleGAN2 for upsampling the images. Args: kernel (Array): Blur kernel/filter used in UpFIRDn. factor (int, optional): Upsampling factor. Defaults to 2. """ def __init__(self, kernel, factor=2): super().__init__() self.factor = factor kernel = make_kernel(kernel) * (factor**2) self.register_buffer('kernel', kernel) p = kernel.shape[0] - factor pad0 = (p + 1) // 2 + factor - 1 pad1 = p // 2 self.pad = (pad0, pad1, pad0, pad1) def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map. """ out = upfirdn2d( x, self.kernel.to(x.dtype), up=self.factor, down=1, padding=self.pad) return out class DownsampleUpFIRDn(BaseModule): """UpFIRDn for Downsampling. This module is mentioned in StyleGAN2 for dowampling the feature maps. Args: kernel (Array): Blur kernel/filter used in UpFIRDn. factor (int, optional): Downsampling factor. Defaults to 2. """ def __init__(self, kernel, factor=2): super().__init__() self.factor = factor kernel = make_kernel(kernel) self.register_buffer('kernel', kernel) p = kernel.shape[0] - factor pad0 = (p + 1) // 2 pad1 = p // 2 self.pad = (pad0, pad1) def forward(self, input): """Forward function. Args: input (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map. """ out = upfirdn2d( input, self.kernel.to(input.dtype), up=1, down=self.factor, padding=self.pad) return out class ModulatedConv2d(BaseModule): r"""Modulated Conv2d in StyleGANv2. This module implements the modulated convolution layers proposed in StyleGAN2. Details can be found in Analyzing and Improving the Image Quality of StyleGAN, CVPR2020. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. style_channels (int): Channels for the style codes. demodulate (bool, optional): Whether to adopt demodulation. Defaults to True. upsample (bool, optional): Whether to adopt upsampling in features. Defaults to False. downsample (bool, optional): Whether to adopt downsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. equalized_lr_cfg (dict | None, optional): Configs for equalized lr. Defaults to dict(mode='fan_in', lr_mul=1., gain=1.). style_mod_cfg (dict, optional): Configs for style modulation module. Defaults to dict(bias_init=1.). style_bias (float, optional): Bias value for style code. Defaults to 0.. eps (float, optional): Epsilon value to avoid computation error. Defaults to 1e-8. """ def __init__( self, in_channels, out_channels, kernel_size, style_channels, demodulate=True, upsample=False, downsample=False, blur_kernel=[1, 3, 3, 1], equalized_lr_cfg=dict(mode='fan_in', lr_mul=1., gain=1.), style_mod_cfg=dict(bias_init=1.), style_bias=0., padding=None, # self define padding eps=1e-8, fp16_enabled=False): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.kernel_size = kernel_size self.style_channels = style_channels self.demodulate = demodulate self.fp16_enabled = fp16_enabled # sanity check for kernel size assert isinstance(self.kernel_size, int) and (self.kernel_size >= 1 and self.kernel_size % 2 == 1) self.upsample = upsample self.downsample = downsample self.style_bias = style_bias self.eps = eps # build style modulation module style_mod_cfg = dict() if style_mod_cfg is None else style_mod_cfg self.style_modulation = EqualLinearActModule(style_channels, in_channels, **style_mod_cfg) # set lr_mul for conv weight lr_mul_ = 1. if equalized_lr_cfg is not None: lr_mul_ = equalized_lr_cfg.get('lr_mul', 1.) self.weight = nn.Parameter( torch.randn(1, out_channels, in_channels, kernel_size, kernel_size).div_(lr_mul_)) # build blurry layer for upsampling if upsample: factor = 2 p = (len(blur_kernel) - factor) - (kernel_size - 1) pad0 = (p + 1) // 2 + factor - 1 pad1 = p // 2 + 1 self.blur = Blur(blur_kernel, (pad0, pad1), upsample_factor=factor) # build blurry layer for downsampling if downsample: factor = 2 p = (len(blur_kernel) - factor) + (kernel_size - 1) pad0 = (p + 1) // 2 pad1 = p // 2 self.blur = Blur(blur_kernel, pad=(pad0, pad1)) # add equalized_lr hook for conv weight if equalized_lr_cfg is not None: equalized_lr(self, **equalized_lr_cfg) self.padding = padding if padding else (kernel_size // 2) def forward(self, x, style, input_gain=None): n, c, h, w = x.shape weight = self.weight # Pre-normalize inputs to avoid FP16 overflow. # if x.dtype == torch.float16 and self.demodulate: if self.fp16_enabled and self.demodulate: weight = weight * ( 1 / np.sqrt( self.in_channels * self.kernel_size * self.kernel_size) / weight.norm(float('inf'), dim=[1, 2, 3], keepdim=True) ) # max_Ikk style = style / style.norm( float('inf'), dim=1, keepdim=True) # max_I with autocast(enabled=self.fp16_enabled): # process style code style = self.style_modulation(style).view(n, 1, c, 1, 1) + self.style_bias # combine weight and style weight = weight * style if self.demodulate: demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps) weight = weight * demod.view(n, self.out_channels, 1, 1, 1) if input_gain is not None: # input_gain shape [batch, in_ch] input_gain = input_gain.expand(n, self.in_channels) # weight shape [batch, out_ch, in_ch, kernel_size, kernel_size] weight = weight * input_gain.unsqueeze(1).unsqueeze( 3).unsqueeze(4) weight = weight.view(n * self.out_channels, c, self.kernel_size, self.kernel_size) if self.fp16_enabled: weight = weight.to(torch.float16) x = x.to(torch.float16) if self.upsample: x = x.reshape(1, n * c, h, w) weight = weight.view(n, self.out_channels, c, self.kernel_size, self.kernel_size) weight = weight.transpose(1, 2).reshape(n * c, self.out_channels, self.kernel_size, self.kernel_size) x = conv_transpose2d(x, weight, padding=0, stride=2, groups=n) x = x.reshape(n, self.out_channels, *x.shape[-2:]) x = self.blur(x) elif self.downsample: x = self.blur(x) x = x.view(1, n * self.in_channels, *x.shape[-2:]) x = conv2d(x, weight, stride=2, padding=0, groups=n) x = x.view(n, self.out_channels, *x.shape[-2:]) else: x = x.reshape(1, n * c, h, w) x = conv2d(x, weight, stride=1, padding=self.padding, groups=n) x = x.view(n, self.out_channels, *x.shape[-2:]) return x class ModulatedStyleConv(BaseModule): """Modulated Style Convolution. In this module, we integrate the modulated conv2d, noise injector and activation layers into together. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. style_channels (int): Channels for the style codes. demodulate (bool, optional): Whether to adopt demodulation. Defaults to True. upsample (bool, optional): Whether to adopt upsampling in features. Defaults to False. downsample (bool, optional): Whether to adopt downsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. equalized_lr_cfg (dict | None, optional): Configs for equalized lr. Defaults to dict(mode='fan_in', lr_mul=1., gain=1.). style_mod_cfg (dict, optional): Configs for style modulation module. Defaults to dict(bias_init=1.). style_bias (float, optional): Bias value for style code. Defaults to ``0.``. fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. conv_clamp (float, optional): Clamp the convolutional layer results to avoid gradient overflow. Defaults to `256.0`. """ def __init__(self, in_channels, out_channels, kernel_size, style_channels, upsample=False, blur_kernel=[1, 3, 3, 1], demodulate=True, style_mod_cfg=dict(bias_init=1.), style_bias=0., fp16_enabled=False, conv_clamp=256, fixed_noise=False): super().__init__() # add support for fp16 self.fp16_enabled = fp16_enabled self.conv_clamp = float(conv_clamp) self.conv = ModulatedConv2d( in_channels, out_channels, kernel_size, style_channels, demodulate=demodulate, upsample=upsample, blur_kernel=blur_kernel, style_mod_cfg=style_mod_cfg, style_bias=style_bias, fp16_enabled=fp16_enabled) self.noise_injector = NoiseInjection(fixed_noise=fixed_noise) self.activate = _FusedBiasLeakyReLU(out_channels) def forward(self, x, style, noise=None, add_noise=True, return_noise=False): """Forward Function. Args: x ([Tensor): Input features with shape of (N, C, H, W). style (Tensor): Style latent with shape of (N, C). noise (Tensor, optional): Noise for injection. Defaults to None. add_noise (bool, optional): Whether apply noise injection to feature. Defaults to True. return_noise (bool, optional): Whether to return noise tensors. Defaults to False. Returns: Tensor: Output features with shape of (N, C, H, W) """ with autocast(enabled=self.fp16_enabled): out = self.conv(x, style) if add_noise: if return_noise: out, noise = self.noise_injector( out, noise=noise, return_noise=return_noise) else: out = self.noise_injector( out, noise=noise, return_noise=return_noise) # TODO: FP16 in activate layers out = self.activate(out) if self.fp16_enabled: out = torch.clamp( out, min=-self.conv_clamp, max=self.conv_clamp) if return_noise: return out, noise return out class ModulatedToRGB(BaseModule): """To RGB layer. This module is designed to output image tensor in StyleGAN2. Args: in_channels (int): Input channels. style_channels (int): Channels for the style codes. out_channels (int, optional): Output channels. Defaults to 3. upsample (bool, optional): Whether to adopt upsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. style_mod_cfg (dict, optional): Configs for style modulation module. Defaults to dict(bias_init=1.). style_bias (float, optional): Bias value for style code. Defaults to 0.. fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. conv_clamp (float, optional): Clamp the convolutional layer results to avoid gradient overflow. Defaults to `256.0`. out_fp32 (bool, optional): Whether to convert the output feature map to `torch.float32`. Defaults to `True`. """ def __init__(self, in_channels, style_channels, out_channels=3, upsample=True, blur_kernel=[1, 3, 3, 1], style_mod_cfg=dict(bias_init=1.), style_bias=0., fp16_enabled=False, conv_clamp=256, out_fp32=True): super().__init__() if upsample: self.upsample = UpsampleUpFIRDn(blur_kernel) # add support for fp16 self.fp16_enabled = fp16_enabled self.conv_clamp = float(conv_clamp) self.conv = ModulatedConv2d( in_channels, out_channels=out_channels, kernel_size=1, style_channels=style_channels, demodulate=False, style_mod_cfg=style_mod_cfg, style_bias=style_bias, fp16_enabled=fp16_enabled) self.bias = nn.Parameter(torch.zeros(1, out_channels, 1, 1)) # enforece the output to be fp32 (follow Tero's implementation) self.out_fp32 = out_fp32 # @auto_fp16(apply_to=('x', 'style')) def forward(self, x, style, skip=None): """Forward Function. Args: x ([Tensor): Input features with shape of (N, C, H, W). style (Tensor): Style latent with shape of (N, C). skip (Tensor, optional): Tensor for skip link. Defaults to None. Returns: Tensor: Output features with shape of (N, C, H, W) """ with autocast(enabled=self.fp16_enabled): out = self.conv(x, style) out = out + self.bias.to(x.dtype) if self.fp16_enabled: out = torch.clamp( out, min=-self.conv_clamp, max=self.conv_clamp) # Here, Tero adopts FP16 at `skip`. if skip is not None: if hasattr(self, 'upsample'): skip = self.upsample(skip) out = out + skip if self.out_fp32: out = out.to(torch.float32) return out class ConvDownLayer(nn.Sequential): """Convolution and Downsampling layer. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. downsample (bool, optional): Whether to adopt downsampling in features. Defaults to False. blur_kernel (list[int], optional): Blurry kernel. Defaults to [1, 3, 3, 1]. bias (bool, optional): Whether to use bias parameter. Defaults to True. act_cfg (dict, optional): Activation configs. Defaults to dict(type='fused_bias'). fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. conv_clamp (float, optional): Clamp the convolutional layer results to avoid gradient overflow. Defaults to `256.0`. """ def __init__(self, in_channels, out_channels, kernel_size, downsample=False, blur_kernel=[1, 3, 3, 1], bias=True, act_cfg=dict(type='fused_bias'), fp16_enabled=False, conv_clamp=256.): self.fp16_enabled = fp16_enabled self.conv_clamp = float(conv_clamp) layers = [] if downsample: factor = 2 p = (len(blur_kernel) - factor) + (kernel_size - 1) pad0 = (p + 1) // 2 pad1 = p // 2 layers.append(Blur(blur_kernel, pad=(pad0, pad1))) stride = 2 self.padding = 0 else: stride = 1 self.padding = kernel_size // 2 self.with_fused_bias = act_cfg is not None and act_cfg.get( 'type') == 'fused_bias' if self.with_fused_bias: conv_act_cfg = None else: conv_act_cfg = act_cfg layers.append( EqualizedLRConvModule( in_channels, out_channels, kernel_size, padding=self.padding, stride=stride, bias=bias and not self.with_fused_bias, norm_cfg=None, act_cfg=conv_act_cfg, equalized_lr_cfg=dict(mode='fan_in', gain=1.))) if self.with_fused_bias: layers.append(_FusedBiasLeakyReLU(out_channels)) super(ConvDownLayer, self).__init__(*layers) # @auto_fp16(apply_to=('x', )) def forward(self, x): with autocast(enabled=self.fp16_enabled): x = super().forward(x) if self.fp16_enabled: x = torch.clamp(x, min=-self.conv_clamp, max=self.conv_clamp) return x class ResBlock(BaseModule): """Residual block used in the discriminator of StyleGAN2. Args: in_channels (int): Input channels. out_channels (int): Output channels. kernel_size (int): Kernel size, same as :obj:`nn.Con2d`. fp16_enabled (bool, optional): Whether to use fp16 training in this module. Defaults to False. convert_input_fp32 (bool, optional): Whether to convert input type to fp32 if not `fp16_enabled`. This argument is designed to deal with the cases where some modules are run in FP16 and others in FP32. Defaults to True. """ def __init__(self, in_channels, out_channels, blur_kernel=[1, 3, 3, 1], fp16_enabled=False, convert_input_fp32=True): super().__init__() self.fp16_enabled = fp16_enabled self.convert_input_fp32 = convert_input_fp32 self.conv1 = ConvDownLayer( in_channels, in_channels, 3, fp16_enabled=fp16_enabled, blur_kernel=blur_kernel) self.conv2 = ConvDownLayer( in_channels, out_channels, 3, downsample=True, fp16_enabled=fp16_enabled, blur_kernel=blur_kernel) self.skip = ConvDownLayer( in_channels, out_channels, 1, downsample=True, act_cfg=None, bias=False, fp16_enabled=fp16_enabled, blur_kernel=blur_kernel) def forward(self, input): """Forward function. Args: input (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map. """ # TODO: study whether this explicit datatype transfer will harm the # apex training speed if not self.fp16_enabled and self.convert_input_fp32: input = input.to(torch.float32) with autocast(enabled=self.fp16_enabled): out = self.conv1(input) out = self.conv2(out) skip = self.skip(input) out = (out + skip) / np.sqrt(2) return out class ModMBStddevLayer(BaseModule): """Modified MiniBatch Stddev Layer. This layer is modified from ``MiniBatchStddevLayer`` used in PGGAN. In StyleGAN2, the authors add a new feature, `channel_groups`, into this layer. Note that to accelerate the training procedure, we also add a new feature of ``sync_std`` to achieve multi-nodes/machine training. This feature is still in beta version and we have tested it on 256 scales. Args: group_size (int, optional): The size of groups in batch dimension. Defaults to 4. channel_groups (int, optional): The size of groups in channel dimension. Defaults to 1. sync_std (bool, optional): Whether to use synchronized std feature. Defaults to False. sync_groups (int | None, optional): The size of groups in node dimension. Defaults to None. eps (float, optional): Epsilon value to avoid computation error. Defaults to 1e-8. """ def __init__(self, group_size=4, channel_groups=1, sync_std=False, sync_groups=None, eps=1e-8): super().__init__() self.group_size = group_size self.eps = eps self.channel_groups = channel_groups self.sync_std = sync_std self.sync_groups = group_size if sync_groups is None else sync_groups if self.sync_std: assert torch.distributed.is_initialized( ), 'Only in distributed training can the sync_std be activated.' mmengine.print_log('Adopt synced minibatch stddev layer', 'mmagic') def forward(self, x): """Forward function. Args: x (Tensor): Input feature map with shape of (N, C, H, W). Returns: Tensor: Output feature map with shape of (N, C+1, H, W). """ if self.sync_std: # concatenate all features all_features = torch.cat(AllGatherLayer.apply(x), dim=0) # get the exact features we need in calculating std-dev rank, ws = get_dist_info() local_bs = all_features.shape[0] // ws start_idx = local_bs * rank # avoid the case where start idx near the tail of features if start_idx + self.sync_groups > all_features.shape[0]: start_idx = all_features.shape[0] - self.sync_groups end_idx = min(local_bs * rank + self.sync_groups, all_features.shape[0]) x = all_features[start_idx:end_idx] # batch size should be smaller than or equal to group size. Otherwise, # batch size should be divisible by the group size. assert x.shape[ 0] <= self.group_size or x.shape[0] % self.group_size == 0, ( 'Batch size be smaller than or equal ' 'to group size. Otherwise,' ' batch size should be divisible by the group size.' f'But got batch size {x.shape[0]},' f' group size {self.group_size}') assert x.shape[1] % self.channel_groups == 0, ( '"channel_groups" must be divided by the feature channels. ' f'channel_groups: {self.channel_groups}, ' f'feature channels: {x.shape[1]}') n, c, h, w = x.shape group_size = min(n, self.group_size) # [G, M, Gc, C', H, W] y = torch.reshape(x, (group_size, -1, self.channel_groups, c // self.channel_groups, h, w)) y = torch.var(y, dim=0, unbiased=False) y = torch.sqrt(y + self.eps) # [M, 1, 1, 1] y = y.mean(dim=(2, 3, 4), keepdim=True).squeeze(2) y = y.repeat(group_size, 1, h, w) return torch.cat([x, y], dim=1) ================================================ FILE: mmagic/models/editors/stylegan3/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .stylegan3 import StyleGAN3 from .stylegan3_generator import StyleGAN3Generator from .stylegan3_modules import SynthesisInput, SynthesisLayer, SynthesisNetwork __all__ = [ 'StyleGAN3', 'StyleGAN3Generator', 'SynthesisInput', 'SynthesisLayer', 'SynthesisNetwork', ] ================================================ FILE: mmagic/models/editors/stylegan3/stylegan3.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Union import numpy as np import torch import torch.nn as nn from mmengine import Config, MessageHub from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ...utils import get_module_device, get_valid_num_batches from ..stylegan2 import StyleGAN2 from .stylegan3_utils import (apply_fractional_pseudo_rotation, apply_fractional_rotation, apply_fractional_translation, apply_integer_translation, rotation_matrix) ModelType = Union[Dict, nn.Module] @MODELS.register_module() class StyleGAN3(StyleGAN2): """Implementation of `Alias-Free Generative Adversarial Networks`. # noqa. Paper link: https://nvlabs-fi-cdn.nvidia.com/stylegan3/stylegan3-paper.pdf # noqa Detailed architecture can be found in :class:`~mmagic.models.editors.stylegan3.StyleGAN3Generator` and :class:`~mmagic.models.editors.stylegan2.StyleGAN2Discriminator` """ def __init__(self, generator: ModelType, discriminator: Optional[ModelType] = None, data_preprocessor: Optional[Union[dict, Config]] = None, generator_steps: int = 1, discriminator_steps: int = 1, forward_kwargs: Optional[Dict] = None, ema_config: Optional[Dict] = None, loss_config=dict()): super().__init__(generator, discriminator, data_preprocessor, generator_steps, discriminator_steps, ema_config, loss_config) self.noise_size = getattr(self.generator, 'noise_size', 512) forward_kwargs = dict() if forward_kwargs is None else forward_kwargs disc_default_forward_kwargs = dict(update_emas=True, force_fp32=False) gen_default_forward_kwargs = dict(force_fp32=False) forward_kwargs.setdefault('disc', disc_default_forward_kwargs) forward_kwargs.setdefault('gen', gen_default_forward_kwargs) self.forward_kwargs = forward_kwargs def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] # hard code to compute equivarience if 'mode' in inputs_dict and 'eq_cfg' in inputs_dict['mode']: batch_size = get_valid_num_batches(inputs_dict, data_samples) outputs = self.sample_equivarience_pairs( batch_size, sample_mode=inputs_dict['mode']['sample_mode'], eq_cfg=inputs_dict['mode']['eq_cfg'], sample_kwargs=inputs_dict['mode']['sample_kwargs']) else: outputs = self(inputs_dict, data_samples) return outputs def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: A list of ``DataSample`` contain generated results. """ data = self.data_preprocessor(data) inputs_dict, data_samples = data['inputs'], data['data_samples'] # hard code to compute equivarience if 'mode' in inputs_dict and 'eq_cfg' in inputs_dict['mode']: batch_size = get_valid_num_batches(inputs_dict, data_samples) outputs = self.sample_equivarience_pairs( batch_size, sample_mode=inputs_dict['mode']['sample_mode'], eq_cfg=inputs_dict['mode']['eq_cfg'], sample_kwargs=inputs_dict['mode']['sample_kwargs']) else: outputs = self(inputs_dict, data_samples) return outputs def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator( noise_batch, return_noise=False, **self.forward_kwargs['disc']) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(disc_pred_fake, disc_pred_real, real_imgs) optimizer_wrapper.update_params(parsed_losses) # save ada info message_hub = MessageHub.get_current_instance() message_hub.update_info('disc_pred_real', disc_pred_real) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator( noise, return_noise=False, **self.forward_kwargs['gen']) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake, num_batches) optimizer_wrapper.update_params(parsed_loss) return log_vars def sample_equivarience_pairs(self, batch_size, sample_mode='ema', eq_cfg=dict( compute_eqt_int=False, compute_eqt_frac=False, compute_eqr=False, translate_max=0.125, rotate_max=1), sample_kwargs=dict()): generator = self.generator if (sample_mode == 'orig') else self.generator_ema if hasattr(generator, 'module'): generator = generator.module device = get_module_device(generator) identity_matrix = torch.eye(3, device=device) # Run mapping network. z = torch.randn([batch_size, self.noise_size], device=device) ws = generator.style_mapping(z=z) transform_matrix = getattr( getattr(getattr(generator, 'synthesis', None), 'input', None), 'transform', None) # Generate reference image. transform_matrix[:] = identity_matrix orig = generator.synthesis(ws=ws, **sample_kwargs) batch_sample = [DataSample() for _ in range(batch_size)] # Integer translation (EQ-T). if eq_cfg['compute_eqt_int']: t = (torch.rand(2, device=device) * 2 - 1) * eq_cfg['translate_max'] t = (t * generator.out_size).round() / generator.out_size transform_matrix[:] = identity_matrix transform_matrix[:2, 2] = -t img = generator.synthesis(ws=ws, **sample_kwargs) ref, mask = apply_integer_translation(orig, t[0], t[1]) diff = (ref - img).square() * mask for idx in range(batch_size): data_sample = batch_sample[idx] setattr(data_sample, 'eqt_int', DataSample(diff=diff, mask=mask)) # Fractional translation (EQ-T_frac). if eq_cfg['compute_eqt_frac']: t = (torch.rand(2, device=device) * 2 - 1) * eq_cfg['translate_max'] transform_matrix[:] = identity_matrix transform_matrix[:2, 2] = -t img = generator.synthesis(ws=ws, **sample_kwargs) ref, mask = apply_fractional_translation(orig, t[0], t[1]) diff = (ref - img).square() * mask for idx in range(batch_size): data_sample = batch_sample[idx] setattr(data_sample, 'eqt_frac', DataSample(diff=diff, mask=mask)) # Rotation (EQ-R). if eq_cfg['compute_eqr']: angle = (torch.rand([], device=device) * 2 - 1) * ( eq_cfg['rotate_max'] * np.pi) transform_matrix[:] = rotation_matrix(-angle) img = generator.synthesis(ws=ws, **sample_kwargs) ref, ref_mask = apply_fractional_rotation(orig, angle) pseudo, pseudo_mask = apply_fractional_pseudo_rotation(img, angle) mask = ref_mask * pseudo_mask diff = (ref - pseudo).square() * mask for idx in range(batch_size): data_sample = batch_sample[idx] setattr(data_sample, 'eqr', DataSample(diff=diff, mask=mask)) return batch_sample ================================================ FILE: mmagic/models/editors/stylegan3/stylegan3_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import mmengine import torch from mmengine.model import BaseModule from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from mmagic.registry import MODELS from ...utils import get_module_device from ..stylegan1 import get_mean_latent @MODELS.register_module('StyleGANv3Generator') @MODELS.register_module() class StyleGAN3Generator(BaseModule): """StyleGAN3 Generator. In StyleGAN3, we make several changes to StyleGANv2's generator which include transformed fourier features, filtered nonlinearity and non-critical sampling, etc. More details can be found in: Alias-Free Generative Adversarial Networks NeurIPS'2021. Ref: https://github.com/NVlabs/stylegan3 Args: out_size (int): The output size of the StyleGAN3 generator. style_channels (int): The number of channels for style code. img_channels (int): The number of output's channels. noise_size (int, optional): Size of the input noise vector. Defaults to 512. rgb2bgr (bool, optional): Whether to reformat the output channels with order `bgr`. We provide several pre-trained StyleGAN3 weights whose output channels order is `rgb`. You can set this argument to True to use the weights. pretrained (str | dict, optional): Path for the pretrained model or dict containing information for pretrained models whose necessary key is 'ckpt_path'. Besides, you can also provide 'prefix' to load the generator part from the whole state dict. Defaults to None. synthesis_cfg (dict, optional): Config for synthesis network. Defaults to dict(type='SynthesisNetwork'). mapping_cfg (dict, optional): Config for mapping network. Defaults to dict(type='MappingNetwork'). """ def __init__(self, out_size, style_channels, img_channels, noise_size=512, rgb2bgr=False, pretrained=None, synthesis_cfg=dict(type='SynthesisNetwork'), mapping_cfg=dict(type='MappingNetwork')): super().__init__() self.noise_size = noise_size self.style_channels = style_channels self.out_size = out_size self.img_channels = img_channels self.rgb2bgr = rgb2bgr self._synthesis_cfg = deepcopy(synthesis_cfg) self._synthesis_cfg.setdefault('style_channels', style_channels) self._synthesis_cfg.setdefault('out_size', out_size) self._synthesis_cfg.setdefault('img_channels', img_channels) self.synthesis = MODELS.build(self._synthesis_cfg) self.num_ws = self.synthesis.num_ws self._mapping_cfg = deepcopy(mapping_cfg) self._mapping_cfg.setdefault('noise_size', noise_size) self._mapping_cfg.setdefault('style_channels', style_channels) self._mapping_cfg.setdefault('num_ws', self.num_ws) self.style_mapping = MODELS.build(self._mapping_cfg) if pretrained is not None: self._load_pretrained_model(**pretrained) def _load_pretrained_model(self, ckpt_path, prefix='', map_location='cpu', strict=True): state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) self.load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained model from {ckpt_path}') def forward(self, noise, num_batches=0, input_is_latent=False, truncation=1, num_truncation_layer=None, update_emas=False, force_fp32=True, return_noise=False, return_latents=False): """Forward Function for stylegan3. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. input_is_latent (bool, optional): If `True`, the input tensor is the latent tensor. Defaults to False. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. num_truncation_layer (int, optional): Number of layers use truncated latent. Defaults to None. update_emas (bool, optional): Whether update moving average of mean latent. Defaults to False. force_fp32 (bool, optional): Force fp32 ignore the weights. Defaults to True. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. return_latents (bool, optional): If True, ``latent`` will be returned in a dict with ``fake_img``. Defaults to False. Returns: torch.Tensor | dict: Generated image tensor or dictionary \ containing more data. """ # if input is latent, set noise size as the style_channels noise_size = ( self.style_channels if input_is_latent else self.noise_size) if isinstance(noise, torch.Tensor): assert noise.shape[1] == noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, noise_size)) device = get_module_device(self) noise_batch = noise_batch.to(device) if input_is_latent: ws = noise_batch.unsqueeze(1).repeat([1, self.num_ws, 1]) else: ws = self.style_mapping( noise_batch, truncation=truncation, num_truncation_layer=num_truncation_layer, update_emas=update_emas) out_img = self.synthesis( ws, update_emas=update_emas, force_fp32=force_fp32) if self.rgb2bgr: out_img = out_img[:, [2, 1, 0], ...] if return_noise or return_latents: output = dict(fake_img=out_img, noise_batch=noise_batch, latent=ws) return output return out_img def get_mean_latent(self, num_samples=4096, **kwargs): """Get mean latent of W space in this generator. Args: num_samples (int, optional): Number of sample times. Defaults to 4096. Returns: Tensor: Mean latent of this generator. """ if hasattr(self.style_mapping, 'w_avg'): return self.style_mapping.w_avg return get_mean_latent(self, num_samples, **kwargs) def get_training_kwargs(self, phase): """Get training kwargs. In StyleGANv3, we enable fp16, and update magnitude ema during training of discriminator. This function is used to pass related arguments. Args: phase (str): Current training phase. Returns: dict: Training kwargs. """ if phase == 'disc': return dict(update_emas=True, force_fp32=False) if phase == 'gen': return dict(force_fp32=False) return {} ================================================ FILE: mmagic/models/editors/stylegan3/stylegan3_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import scipy import torch from mmengine.model import BaseModule try: from mmcv.ops import bias_act, conv2d_gradfix, filtered_lrelu except ImportError: bias_act = None conv2d_gradfix = None filtered_lrelu = None print('Warning: mmcv.ops.bias_act, mmcv.ops.conv2d_gradfix' ' and mmcv.ops.filtered_lrelu are not available.') from mmengine.runner.amp import autocast from mmagic.registry import MODELS def modulated_conv2d( x, w, s, demodulate=True, padding=0, input_gain=None, ): """Modulated Conv2d in StyleGANv3. Args: x (torch.Tensor): Input tensor with shape (batch_size, in_channels, height, width). w (torch.Tensor): Weight of modulated convolution with shape (out_channels, in_channels, kernel_height, kernel_width). s (torch.Tensor): Style tensor with shape (batch_size, in_channels). demodulate (bool): Whether apply weight demodulation. Defaults to True. padding (int or list[int]): Convolution padding. Defaults to 0. input_gain (list[int]): Scaling factors for input. Defaults to None. Returns: torch.Tensor: Convolution Output. """ batch_size = int(x.shape[0]) _, in_channels, kh, kw = w.shape # Pre-normalize inputs. if demodulate: w = w * w.square().mean([1, 2, 3], keepdim=True).rsqrt() s = s * s.square().mean().rsqrt() # Modulate weights. w = w.unsqueeze(0) # [NOIkk] w = w * s.unsqueeze(1).unsqueeze(3).unsqueeze(4) # [NOIkk] # Demodulate weights. if demodulate: dcoefs = (w.square().sum(dim=[2, 3, 4]) + 1e-8).rsqrt() # [NO] w = w * dcoefs.unsqueeze(2).unsqueeze(3).unsqueeze(4) # [NOIkk] # Apply input scaling. if input_gain is not None: input_gain = input_gain.expand(batch_size, in_channels) # [NI] w = w * input_gain.unsqueeze(1).unsqueeze(3).unsqueeze(4) # [NOIkk] # Execute as one fused op using grouped convolution. x = x.reshape(1, -1, *x.shape[2:]) w = w.reshape(-1, in_channels, kh, kw) x = conv2d_gradfix.conv2d( input=x, weight=w.to(x.dtype), padding=padding, groups=batch_size) x = x.reshape(batch_size, -1, *x.shape[2:]) return x class FullyConnectedLayer(BaseModule): """Fully connected layer used in StyleGANv3. Args: in_features (int): Number of channels in the input feature. out_features (int): Number of channels in the out feature. activation (str, optional): Activation function with choices 'relu', 'lrelu', 'linear'. 'linear' means no extra activation. Defaults to 'linear'. bias (bool, optional): Whether to use additive bias. Defaults to True. lr_multiplier (float, optional): Equalized learning rate multiplier. Defaults to 1.. weight_init (float, optional): Weight multiplier for initialization. Defaults to 1.. bias_init (float, optional): Initial bias. Defaults to 0.. """ def __init__(self, in_features, out_features, activation='linear', bias=True, lr_multiplier=1., weight_init=1., bias_init=0.): super().__init__() self.in_features = in_features self.out_features = out_features self.activation = activation self.weight = torch.nn.Parameter( torch.randn([out_features, in_features]) * (weight_init / lr_multiplier)) bias_init = np.broadcast_to( np.asarray(bias_init, dtype=np.float32), [out_features]) self.bias = torch.nn.Parameter( torch.from_numpy(bias_init / lr_multiplier)) if bias else None self.weight_gain = lr_multiplier / np.sqrt(in_features) self.bias_gain = lr_multiplier def forward(self, x): """Forward function.""" w = self.weight.to(x.dtype) * self.weight_gain b = self.bias if b is not None: b = b.to(x.dtype) if self.bias_gain != 1: b = b * self.bias_gain if self.activation == 'linear' and b is not None: x = torch.addmm(b.unsqueeze(0), x, w.t()) else: x = x.matmul(w.t()) x = bias_act(x, b, act=self.activation) return x @MODELS.register_module() class MappingNetwork(BaseModule): """Style mapping network used in StyleGAN3. The main difference between it and styleganv1,v2 is that mean latent is registered as a buffer and dynamic updated during training. Args: noise_size (int, optional): Size of the input noise vector. style_channels (int): The number of channels for style code. num_ws (int | None): The repeat times of w latent. If None is passed, the output will shape like (batch_size, 1), otherwise the output will shape like (bz, num_ws, 1). cond_size (int, optional): Size of the conditional input. Defaults to None. num_layers (int, optional): The number of layers of mapping network. Defaults to 2. lr_multiplier (float, optional): Equalized learning rate multiplier. Defaults to 0.01. w_avg_beta (float, optional): The value used for update `w_avg`. Defaults to 0.998. """ def __init__(self, noise_size, style_channels, num_ws, cond_size=0, num_layers=2, lr_multiplier=0.01, w_avg_beta=0.998): super().__init__() self.noise_size = noise_size self.cond_size = cond_size self.style_channels = style_channels self.num_ws = num_ws self.num_layers = num_layers self.w_avg_beta = w_avg_beta # Construct layers. if self.cond_size is not None and self.cond_size > 0: self.embed = FullyConnectedLayer(self.cond_size, self.style_channels) features = [ self.noise_size + (self.style_channels if self.cond_size > 0 else 0) ] + [self.style_channels] * self.num_layers for idx, in_features, out_features in zip( range(num_layers), features[:-1], features[1:]): layer = FullyConnectedLayer( in_features, out_features, activation='lrelu', lr_multiplier=lr_multiplier) setattr(self, f'fc{idx}', layer) if w_avg_beta is not None: self.register_buffer('w_avg', torch.zeros([style_channels])) def forward(self, z, label=None, truncation=1, num_truncation_layer=None, update_emas=False): """Style mapping function. Args: z (torch.Tensor): Input noise tensor. label (torch.Tensor, optional): The conditional input. Defaults to None. truncation (float, optional): Truncation factor. Give value less than 1., the truncation trick will be adopted. Defaults to 1. num_truncation_layer (int, optional): Number of layers use truncated latent. Defaults to None. update_emas (bool, optional): Whether update moving average of mean latent. Defaults to False. Returns: torch.Tensor: W-plus latent. """ if num_truncation_layer is None: num_truncation_layer = self.num_ws x = None # Embed, normalize, and concatenate inputs. if self.noise_size > 0: assert z is not None, ( '\'z\' must be passed since \'self.noise_size\'' f'({self.noise_size}) larger than 0.') x = z.to(torch.float32) x = x * (x.square().mean(1, keepdim=True) + 1e-8).rsqrt() if self.cond_size > 0: y = self.embed(label.to(torch.float32)) y = y * (y.square().mean(1, keepdim=True) + 1e-8).rsqrt() x = torch.cat([x, y], dim=1) if x is not None else y # Execute layers. for idx in range(self.num_layers): x = getattr(self, f'fc{idx}')(x) # Update moving average of W. if update_emas and self.w_avg_beta is not None: self.w_avg.copy_(x.detach().mean( dim=0).lerp(self.w_avg, self.w_avg_beta)) # Broadcast and apply truncation. if self.num_ws is not None: x = x.unsqueeze(1).repeat([1, self.num_ws, 1]) if truncation != 1: assert hasattr(self, 'w_avg'), ( '\'w_avg\' must not be None when truncation trick is used.') if num_truncation_layer is None: x = self.w_avg.lerp(x, truncation) else: x[:, :num_truncation_layer] = self.w_avg.lerp( x[:, :num_truncation_layer], truncation) return x class SynthesisInput(BaseModule): """Module which generate input for synthesis layer. Args: style_channels (int): The number of channels for style code. channels (int): The number of output channel. size (int): The size of sampling grid. sampling_rate (int): Sampling rate for construct sampling grid. bandwidth (float): Bandwidth of random frequencies. """ def __init__(self, style_channels, channels, size, sampling_rate, bandwidth): super().__init__() self.style_channels = style_channels self.channels = channels self.size = np.broadcast_to(np.asarray(size), [2]) self.sampling_rate = sampling_rate self.bandwidth = bandwidth # Draw random frequencies from uniform 2D disc. freqs = torch.randn([self.channels, 2]) radii = freqs.square().sum(dim=1, keepdim=True).sqrt() freqs /= radii * radii.square().exp().pow(0.25) freqs *= bandwidth phases = torch.rand([self.channels]) - 0.5 # Setup parameters and buffers. self.weight = torch.nn.Parameter( torch.randn([self.channels, self.channels])) self.affine = FullyConnectedLayer( style_channels, 4, weight_init=0, bias_init=[1, 0, 0, 0]) self.register_buffer('transform', torch.eye( 3, 3)) # User-specified inverse transform wrt. resulting image. self.register_buffer('freqs', freqs) self.register_buffer('phases', phases) def forward(self, w): """Forward function.""" # Introduce batch dimension. transforms = self.transform.unsqueeze(0) # [batch, row, col] freqs = self.freqs.unsqueeze(0) # [batch, channel, xy] phases = self.phases.unsqueeze(0) # [batch, channel] # Apply learned transformation. t = self.affine(w) # t = (r_c, r_s, t_x, t_y) t = t / t[:, :2].norm( dim=1, keepdim=True) # t' = (r'_c, r'_s, t'_x, t'_y) m_r = torch.eye( 3, device=w.device).unsqueeze(0).repeat( [w.shape[0], 1, 1]) # Inverse rotation wrt. resulting image. m_r[:, 0, 0] = t[:, 0] # r'_c m_r[:, 0, 1] = -t[:, 1] # r'_s m_r[:, 1, 0] = t[:, 1] # r'_s m_r[:, 1, 1] = t[:, 0] # r'_c m_t = torch.eye( 3, device=w.device).unsqueeze(0).repeat( [w.shape[0], 1, 1]) # Inverse translation wrt. resulting image. m_t[:, 0, 2] = -t[:, 2] # t'_x m_t[:, 1, 2] = -t[:, 3] # t'_y # First rotate resulting image, then translate # and finally apply user-specified transform. transforms = m_r @ m_t @ transforms # Transform frequencies. phases = phases + (freqs @ transforms[:, :2, 2:]).squeeze(2) freqs = freqs @ transforms[:, :2, :2] # Dampen out-of-band frequencies # that may occur due to the user-specified transform. amplitudes = (1 - (freqs.norm(dim=2) - self.bandwidth) / (self.sampling_rate / 2 - self.bandwidth)).clamp(0, 1) # Construct sampling grid. theta = torch.eye(2, 3, device=w.device) theta[0, 0] = 0.5 * self.size[0] / self.sampling_rate theta[1, 1] = 0.5 * self.size[1] / self.sampling_rate grids = torch.nn.functional.affine_grid( theta.unsqueeze(0), [1, 1, self.size[1], self.size[0]], align_corners=False) # Compute Fourier features. x = (grids.unsqueeze(3) @ freqs.permute( 0, 2, 1).unsqueeze(1).unsqueeze(2)).squeeze( 3) # [batch, height, width, channel] x = x + phases.unsqueeze(1).unsqueeze(2) x = torch.sin(x * (np.pi * 2)) x = x * amplitudes.unsqueeze(1).unsqueeze(2) # Apply trainable mapping. weight = self.weight / np.sqrt(self.channels) x = x @ weight.t() # Ensure correct shape. x = x.permute(0, 3, 1, 2) # [batch, channel, height, width] return x class SynthesisLayer(BaseModule): """Layer of Synthesis network for stylegan3. Args: style_channels (int): The number of channels for style code. is_torgb (bool): Whether output of this layer is transformed to rgb image. is_critically_sampled (bool): Whether filter cutoff is set exactly at the bandlimit. use_fp16 (bool, optional): Whether to use fp16 training in this module. If this flag is `True`, the whole module will be wrapped with ``auto_fp16``. in_channels (int): The channel number of the input feature map. out_channels (int): The channel number of the output feature map. in_size (int): The input size of feature map. out_size (int): The output size of feature map. in_sampling_rate (int): Sampling rate for upsampling filter. out_sampling_rate (int): Sampling rate for downsampling filter. in_cutoff (float): Cutoff frequency for upsampling filter. out_cutoff (float): Cutoff frequency for downsampling filter. in_half_width (float): The approximate width of the transition region for upsampling filter. out_half_width (float): The approximate width of the transition region for downsampling filter. conv_kernel (int, optional): The kernel of modulated convolution. Defaults to 3. filter_size (int, optional): Base filter size. Defaults to 6. lrelu_upsampling (int, optional): Upsamling rate for `filtered_lrelu`. Defaults to 2. use_radial_filters (bool, optional): Whether use radially symmetric jinc-based filter in downsamping filter. Defaults to False. conv_clamp (int, optional): Clamp bound for convolution. Defaults to 256. magnitude_ema_beta (float, optional): Beta coefficient for calculating input magnitude ema. Defaults to 0.999. """ def __init__( self, style_channels, is_torgb, is_critically_sampled, use_fp16, in_channels, out_channels, in_size, out_size, in_sampling_rate, out_sampling_rate, in_cutoff, out_cutoff, in_half_width, out_half_width, conv_kernel=3, filter_size=6, lrelu_upsampling=2, use_radial_filters=False, conv_clamp=256, magnitude_ema_beta=0.999, ): super().__init__() self.style_channels = style_channels self.is_torgb = is_torgb self.is_critically_sampled = is_critically_sampled self.use_fp16 = use_fp16 self.in_channels = in_channels self.out_channels = out_channels self.in_size = np.broadcast_to(np.asarray(in_size), [2]) self.out_size = np.broadcast_to(np.asarray(out_size), [2]) self.in_sampling_rate = in_sampling_rate self.out_sampling_rate = out_sampling_rate self.tmp_sampling_rate = max(in_sampling_rate, out_sampling_rate) * ( 1 if is_torgb else lrelu_upsampling) self.in_cutoff = in_cutoff self.out_cutoff = out_cutoff self.in_half_width = in_half_width self.out_half_width = out_half_width self.conv_kernel = 1 if is_torgb else conv_kernel self.conv_clamp = conv_clamp self.magnitude_ema_beta = magnitude_ema_beta # Setup parameters and buffers. self.affine = FullyConnectedLayer( self.style_channels, self.in_channels, bias_init=1) self.weight = torch.nn.Parameter( torch.randn([ self.out_channels, self.in_channels, self.conv_kernel, self.conv_kernel ])) self.bias = torch.nn.Parameter(torch.zeros([self.out_channels])) self.register_buffer('magnitude_ema', torch.ones([])) # Design upsampling filter. self.up_factor = int( np.rint(self.tmp_sampling_rate / self.in_sampling_rate)) assert self.in_sampling_rate * self.up_factor == self.tmp_sampling_rate self.up_taps = ( filter_size * self.up_factor if self.up_factor > 1 and not self.is_torgb else 1) self.register_buffer( 'up_filter', self.design_lowpass_filter( numtaps=self.up_taps, cutoff=self.in_cutoff, width=self.in_half_width * 2, fs=self.tmp_sampling_rate)) # Design downsampling filter. self.down_factor = int( np.rint(self.tmp_sampling_rate / self.out_sampling_rate)) assert (self.out_sampling_rate * self.down_factor == self.tmp_sampling_rate) self.down_taps = ( filter_size * self.down_factor if self.down_factor > 1 and not self.is_torgb else 1) self.down_radial = ( use_radial_filters and not self.is_critically_sampled) self.register_buffer( 'down_filter', self.design_lowpass_filter( numtaps=self.down_taps, cutoff=self.out_cutoff, width=self.out_half_width * 2, fs=self.tmp_sampling_rate, radial=self.down_radial)) # Compute padding. pad_total = ( self.out_size - 1 ) * self.down_factor + 1 # Desired output size before downsampling. pad_total -= (self.in_size + self.conv_kernel - 1) * self.up_factor # Input size after upsampling. pad_total += self.up_taps + self.down_taps - 2 pad_lo = (pad_total + self.up_factor) // 2 pad_hi = pad_total - pad_lo self.padding = [ int(pad_lo[0]), int(pad_hi[0]), int(pad_lo[1]), int(pad_hi[1]) ] def forward(self, x, w, force_fp32=False, update_emas=False): """Forward function for synthesis layer. Args: x (torch.Tensor): Input feature map tensor. w (torch.Tensor): Input style tensor. force_fp32 (bool, optional): Force fp32 ignore the weights. Defaults to True. update_emas (bool, optional): Whether update moving average of input magnitude. Defaults to False. Returns: torch.Tensor: Output feature map tensor. """ # Track input magnitude. if update_emas: with torch.autograd.profiler.record_function( 'update_magnitude_ema'): magnitude_cur = x.detach().to(torch.float32).square().mean() self.magnitude_ema.copy_( magnitude_cur.lerp(self.magnitude_ema, self.magnitude_ema_beta)) input_gain = self.magnitude_ema.rsqrt() # Execute affine layer. styles = self.affine(w) if self.is_torgb: weight_gain = 1 / np.sqrt(self.in_channels * (self.conv_kernel**2)) styles = styles * weight_gain # Execute modulated conv2d. dtype = torch.float16 if (self.use_fp16 and not force_fp32 and x.device.type == 'cuda') else torch.float32 with autocast(enabled=dtype == torch.float16): x = modulated_conv2d( x=x.to(dtype), w=self.weight, s=styles, padding=self.conv_kernel - 1, demodulate=(not self.is_torgb), input_gain=input_gain) # Execute bias, filtered leaky ReLU, and clamping. gain = 1 if self.is_torgb else np.sqrt(2) slope = 1 if self.is_torgb else 0.2 x = filtered_lrelu( input=x, filter_up=self.up_filter, filter_down=self.down_filter, bias=self.bias.to(x.dtype), up=self.up_factor, down=self.down_factor, padding=self.padding, gain=gain, slope=slope, clamp=self.conv_clamp) # Ensure correct shape and dtype. assert x.dtype == dtype return x @staticmethod def design_lowpass_filter(numtaps, cutoff, width, fs, radial=False): """Design lowpass filter giving related arguments. Args: numtaps (int): Length of the filter. `numtaps` must be odd if a passband includes the Nyquist frequency. cutoff (float): Cutoff frequency of filter width (float): The approximate width of the transition region. fs (float): The sampling frequency of the signal. radial (bool, optional): Whether use radially symmetric jinc-based filter. Defaults to False. Returns: torch.Tensor: Kernel of lowpass filter. """ assert numtaps >= 1 # Identity filter. if numtaps == 1: return None # Separable Kaiser low-pass filter. if not radial: f = scipy.signal.firwin( numtaps=numtaps, cutoff=cutoff, width=width, fs=fs) return torch.as_tensor(f, dtype=torch.float32) # Radially symmetric jinc-based filter. x = (np.arange(numtaps) - (numtaps - 1) / 2) / fs r = np.hypot(*np.meshgrid(x, x)) f = scipy.special.j1(2 * cutoff * (np.pi * r)) / (np.pi * r) beta = scipy.signal.kaiser_beta( scipy.signal.kaiser_atten(numtaps, width / (fs / 2))) w = np.kaiser(numtaps, beta) f *= np.outer(w, w) f /= np.sum(f) return torch.as_tensor(f, dtype=torch.float32) @MODELS.register_module() class SynthesisNetwork(BaseModule): """Synthesis network for stylegan3. Args: style_channels (int): The number of channels for style code. out_size (int): The resolution of output image. img_channels (int): The number of channels for output image. channel_base (int, optional): Overall multiplier for the number of channels. Defaults to 32768. channel_max (int, optional): Maximum number of channels in any layer. Defaults to 512. num_layers (int, optional): Total number of layers, excluding Fourier features and ToRGB. Defaults to 14. num_critical (int, optional): Number of critically sampled layers at the end. Defaults to 2. first_cutoff (int, optional): Cutoff frequency of the first layer. Defaults to 2. first_stopband (int, optional): Minimum stopband of the first layer. Defaults to 2**2.1. last_stopband_rel (float, optional): Minimum stopband of the last layer, expressed relative to the cutoff. Defaults to 2**0.3. margin_size (int, optional): Number of additional pixels outside the image. Defaults to 10. output_scale (float, optional): Scale factor for output value. Defaults to 0.25. num_fp16_res (int, optional): Number of first few layers use fp16. Defaults to 4. """ def __init__( self, style_channels, out_size, img_channels, channel_base=32768, channel_max=512, num_layers=14, num_critical=2, first_cutoff=2, first_stopband=2**2.1, last_stopband_rel=2**0.3, margin_size=10, output_scale=0.25, num_fp16_res=4, **layer_kwargs, ): super().__init__() self.style_channels = style_channels self.num_ws = num_layers + 2 self.out_size = out_size self.img_channels = img_channels self.num_layers = num_layers self.num_critical = num_critical self.margin_size = margin_size self.output_scale = output_scale self.num_fp16_res = num_fp16_res # Geometric progression of layer cutoffs and min. stopbands. last_cutoff = self.out_size / 2 # f_{c,N} last_stopband = last_cutoff * last_stopband_rel # f_{t,N} exponents = np.minimum( np.arange(self.num_layers + 1) / (self.num_layers - self.num_critical), 1) cutoffs = first_cutoff * (last_cutoff / first_cutoff)**exponents # f_c[i] stopbands = first_stopband * (last_stopband / first_stopband)**exponents # f_t[i] # Compute remaining layer parameters. sampling_rates = np.exp2( np.ceil(np.log2(np.minimum(stopbands * 2, self.out_size)))) # s[i] half_widths = np.maximum(stopbands, sampling_rates / 2) - cutoffs # f_h[i] sizes = sampling_rates + self.margin_size * 2 sizes[-2:] = self.out_size channels = np.rint( np.minimum((channel_base / 2) / cutoffs, channel_max)) channels[-1] = self.img_channels # Construct layers. self.input = SynthesisInput( style_channels=self.style_channels, channels=int(channels[0]), size=int(sizes[0]), sampling_rate=sampling_rates[0], bandwidth=cutoffs[0]) self.layer_names = [] for idx in range(self.num_layers + 1): prev = max(idx - 1, 0) is_torgb = (idx == self.num_layers) is_critically_sampled = ( idx >= self.num_layers - self.num_critical) use_fp16 = ( sampling_rates[idx] * (2**self.num_fp16_res) > self.out_size) layer = SynthesisLayer( style_channels=self.style_channels, is_torgb=is_torgb, is_critically_sampled=is_critically_sampled, use_fp16=use_fp16, in_channels=int(channels[prev]), out_channels=int(channels[idx]), in_size=int(sizes[prev]), out_size=int(sizes[idx]), in_sampling_rate=int(sampling_rates[prev]), out_sampling_rate=int(sampling_rates[idx]), in_cutoff=cutoffs[prev], out_cutoff=cutoffs[idx], in_half_width=half_widths[prev], out_half_width=half_widths[idx], **layer_kwargs) name = f'L{idx}_{layer.out_size[0]}_{layer.out_channels}' setattr(self, name, layer) self.layer_names.append(name) def forward(self, ws, **layer_kwargs): """Forward function.""" ws = ws.to(torch.float32).unbind(dim=1) # Execute layers. x = self.input(ws[0]) for name, w in zip(self.layer_names, ws[1:]): x = getattr(self, name)(x, w, **layer_kwargs) if self.output_scale != 1: x = x * self.output_scale # Ensure correct shape and dtype. x = x.to(torch.float32) return x ================================================ FILE: mmagic/models/editors/stylegan3/stylegan3_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch try: from mmcv.ops import filter2d, upsample2d except ImportError: filter2d = None upsample2d = None print( 'Warning: mmcv.ops.filter2d and mmcv.ops.upsample2d are not available.' ) def apply_integer_translation(x, tx, ty): _N, _C, H, W = x.shape tx = torch.as_tensor(tx * W).to(dtype=torch.float32, device=x.device) ty = torch.as_tensor(ty * H).to(dtype=torch.float32, device=x.device) ix = tx.round().to(torch.int64) iy = ty.round().to(torch.int64) z = torch.zeros_like(x) m = torch.zeros_like(x) if abs(ix) < W and abs(iy) < H: y = x[:, :, max(-iy, 0):H + min(-iy, 0), max(-ix, 0):W + min(-ix, 0)] z[:, :, max(iy, 0):H + min(iy, 0), max(ix, 0):W + min(ix, 0)] = y m[:, :, max(iy, 0):H + min(iy, 0), max(ix, 0):W + min(ix, 0)] = 1 return z, m def sinc(x): y = (x * np.pi).abs() z = torch.sin(y) / y.clamp(1e-30, float('inf')) return torch.where(y < 1e-30, torch.ones_like(x), z) def apply_fractional_translation(x, tx, ty, a=3): _N, _C, H, W = x.shape tx = torch.as_tensor(tx * W).to(dtype=torch.float32, device=x.device) ty = torch.as_tensor(ty * H).to(dtype=torch.float32, device=x.device) ix = tx.floor().to(torch.int64) iy = ty.floor().to(torch.int64) fx = tx - ix fy = ty - iy b = a - 1 z = torch.zeros_like(x) zx0 = max(ix - b, 0) zy0 = max(iy - b, 0) zx1 = min(ix + a, 0) + W zy1 = min(iy + a, 0) + H if zx0 < zx1 and zy0 < zy1: taps = torch.arange(a * 2, device=x.device) - b filter_x = (sinc(taps - fx) * sinc((taps - fx) / a)).unsqueeze(0) filter_y = (sinc(taps - fy) * sinc((taps - fy) / a)).unsqueeze(1) y = x y = filter2d(y, filter_x / filter_x.sum(), padding=[b, a, 0, 0]) y = filter2d(y, filter_y / filter_y.sum(), padding=[0, 0, b, a]) y = y[:, :, max(b - iy, 0):H + b + a + min(-iy - a, 0), max(b - ix, 0):W + b + a + min(-ix - a, 0)] z[:, :, zy0:zy1, zx0:zx1] = y m = torch.zeros_like(x) mx0 = max(ix + a, 0) my0 = max(iy + a, 0) mx1 = min(ix - b, 0) + W my1 = min(iy - b, 0) + H if mx0 < mx1 and my0 < my1: m[:, :, my0:my1, mx0:mx1] = 1 return z, m def rotation_matrix(angle): angle = torch.as_tensor(angle).to(torch.float32) mat = torch.eye(3, device=angle.device) mat[0, 0] = angle.cos() mat[0, 1] = angle.sin() mat[1, 0] = -angle.sin() mat[1, 1] = angle.cos() return mat def lanczos_window(x, a): x = x.abs() / a return torch.where(x < 1, sinc(x), torch.zeros_like(x)) def construct_affine_bandlimit_filter(mat, a=3, amax=16, aflt=64, up=4, cutoff_in=1, cutoff_out=1): assert a <= amax < aflt mat = torch.as_tensor(mat).to(torch.float32) # Construct 2D filter taps in input & output coordinate spaces. taps = ((torch.arange(aflt * up * 2 - 1, device=mat.device) + 1) / up - aflt).roll(1 - aflt * up) yi, xi = torch.meshgrid(taps, taps) xo, yo = (torch.stack([xi, yi], dim=2) @ mat[:2, :2].t()).unbind(2) # Convolution of two oriented 2D sinc filters. fin = sinc(xi * cutoff_in) * sinc(yi * cutoff_in) fout = sinc(xo * cutoff_out) * sinc(yo * cutoff_out) f = torch.fft.ifftn(torch.fft.fftn(fin) * torch.fft.fftn(fout)).real # Convolution of two oriented 2D Lanczos windows. wi = lanczos_window(xi, a) * lanczos_window(yi, a) wo = lanczos_window(xo, a) * lanczos_window(yo, a) w = torch.fft.ifftn(torch.fft.fftn(wi) * torch.fft.fftn(wo)).real # Construct windowed FIR filter. f = f * w # Finalize. c = (aflt - amax) * up f = f.roll([aflt * up - 1] * 2, dims=[0, 1])[c:-c, c:-c] f = torch.nn.functional.pad(f, [0, 1, 0, 1]).reshape(amax * 2, up, amax * 2, up) f = f / f.sum([0, 2], keepdim=True) / (up**2) f = f.reshape(amax * 2 * up, amax * 2 * up)[:-1, :-1] return f def apply_affine_transformation(x, mat, up=4, **filter_kwargs): _N, _C, H, W = x.shape mat = torch.as_tensor(mat).to(dtype=torch.float32, device=x.device) # Construct filter. f = construct_affine_bandlimit_filter(mat, up=up, **filter_kwargs) assert f.ndim == 2 and f.shape[0] == f.shape[1] and f.shape[0] % 2 == 1 p = f.shape[0] // 2 # Construct sampling grid. theta = mat.inverse() theta[:2, 2] *= 2 theta[0, 2] += 1 / up / W theta[1, 2] += 1 / up / H theta[0, :] *= W / (W + p / up * 2) theta[1, :] *= H / (H + p / up * 2) theta = theta[:2, :3].unsqueeze(0).repeat([x.shape[0], 1, 1]) g = torch.nn.functional.affine_grid(theta, x.shape, align_corners=False) # Resample image. y = upsample2d(input=x, filter=f, up=up, padding=p) z = torch.nn.functional.grid_sample( y, g, mode='bilinear', padding_mode='zeros', align_corners=False) # Form mask. m = torch.zeros_like(y) c = p * 2 + 1 m[:, :, c:-c, c:-c] = 1 m = torch.nn.functional.grid_sample( m, g, mode='nearest', padding_mode='zeros', align_corners=False) return z, m def apply_fractional_rotation(x, angle, a=3, **filter_kwargs): angle = torch.as_tensor(angle).to(dtype=torch.float32, device=x.device) mat = rotation_matrix(angle) return apply_affine_transformation( x, mat, a=a, amax=a * 2, **filter_kwargs) def apply_fractional_pseudo_rotation(x, angle, a=3, **filter_kwargs): angle = torch.as_tensor(angle).to(dtype=torch.float32, device=x.device) mat = rotation_matrix(-angle) f = construct_affine_bandlimit_filter( mat, a=a, amax=a * 2, up=1, **filter_kwargs) y = filter2d(input=x, filter=f) m = torch.zeros_like(y) c = f.shape[0] // 2 m[:, :, c:-c, c:-c] = 1 return y, m ================================================ FILE: mmagic/models/editors/swinir/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .swinir_net import SwinIRNet __all__ = ['SwinIRNet'] ================================================ FILE: mmagic/models/editors/swinir/swinir_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import torch.nn as nn from .swinir_utils import to_2tuple class PatchEmbed(nn.Module): r""" Image to Patch Embedding Args: img_size (int): Image size. Default: 224. patch_size (int): Patch token size. Default: 4. in_chans (int): Number of input image channels. Default: 3. embed_dim (int): Number of linear projection output channels. Default: 96. norm_layer (nn.Module, optional): Normalization layer. Default: None """ def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None): super().__init__() img_size = to_2tuple(img_size) patch_size = to_2tuple(patch_size) patches_resolution = [ img_size[0] // patch_size[0], img_size[1] // patch_size[1] ] self.img_size = img_size self.patch_size = patch_size self.patches_resolution = patches_resolution self.num_patches = patches_resolution[0] * patches_resolution[1] self.in_chans = in_chans self.embed_dim = embed_dim if norm_layer is not None: self.norm = norm_layer(embed_dim) else: self.norm = None def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, Ph, Pw). Returns: Tensor: Forward results. """ x = x.flatten(2).transpose(1, 2) # B Ph*Pw C if self.norm is not None: x = self.norm(x) return x class PatchUnEmbed(nn.Module): r""" Image to Patch Unembedding Args: img_size (int): Image size. Default: 224. patch_size (int): Patch token size. Default: 4. in_chans (int): Number of input image channels. Default: 3. embed_dim (int): Number of linear projection output channels. Default: 96. norm_layer (nn.Module, optional): Normalization layer. Default: None """ def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None): super().__init__() img_size = to_2tuple(img_size) patch_size = to_2tuple(patch_size) patches_resolution = [ img_size[0] // patch_size[0], img_size[1] // patch_size[1] ] self.img_size = img_size self.patch_size = patch_size self.patches_resolution = patches_resolution self.num_patches = patches_resolution[0] * patches_resolution[1] self.in_chans = in_chans self.embed_dim = embed_dim def forward(self, x, x_size): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). x_size (tuple[int]): Resolution of input feature. Returns: Tensor: Forward results. """ B, HW, C = x.shape x = x.transpose(1, 2).view(B, self.embed_dim, x_size[0], x_size[1]) # B Ph*Pw C return x class Upsample(nn.Sequential): """Upsample module. Args: scale (int): Scale factor. Supported scales: 2^n and 3. num_feat (int): Channel number of intermediate features. """ def __init__(self, scale, num_feat): m = [] if (scale & (scale - 1)) == 0: # scale = 2^n for _ in range(int(math.log(scale, 2))): m.append(nn.Conv2d(num_feat, 4 * num_feat, 3, 1, 1)) m.append(nn.PixelShuffle(2)) elif scale == 3: m.append(nn.Conv2d(num_feat, 9 * num_feat, 3, 1, 1)) m.append(nn.PixelShuffle(3)) else: raise ValueError(f'scale {scale} is not supported. ' 'Supported scales: 2^n and 3.') super(Upsample, self).__init__(*m) class UpsampleOneStep(nn.Sequential): """UpsampleOneStep module (the difference with Upsample is that it always only has 1conv + 1pixelshuffle) Used in lightweight SR to save parameters. Args: scale (int): Scale factor. Supported scales: 2^n and 3. num_feat (int): Channel number of intermediate features. num_out_ch (int): Channel number for PixelShuffle. input_resolution (tuple[int], optional): Input resolution. Default: None """ def __init__(self, scale, num_feat, num_out_ch, input_resolution=None): self.num_feat = num_feat self.input_resolution = input_resolution m = [] m.append(nn.Conv2d(num_feat, (scale**2) * num_out_ch, 3, 1, 1)) m.append(nn.PixelShuffle(scale)) super(UpsampleOneStep, self).__init__(*m) ================================================ FILE: mmagic/models/editors/swinir/swinir_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmengine.model import BaseModule from mmengine.model.weight_init import trunc_normal_ from mmagic.registry import MODELS from .swinir_modules import PatchEmbed, PatchUnEmbed, Upsample, UpsampleOneStep from .swinir_rstb import RSTB @MODELS.register_module() class SwinIRNet(BaseModule): r""" SwinIR A PyTorch impl of: `SwinIR: Image Restoration Using Swin Transformer`, based on Swin Transformer. Ref repo: https://github.com/JingyunLiang/SwinIR Args: img_size (int | tuple(int)): Input image size. Default 64 patch_size (int | tuple(int)): Patch size. Default: 1 in_chans (int): Number of input image channels. Default: 3 embed_dim (int): Patch embedding dimension. Default: 96 depths (tuple(int)): Depth of each Swin Transformer layer. Default: [6, 6, 6, 6] num_heads (tuple(int)): Number of attention heads in different layers. Default: [6, 6, 6, 6] window_size (int): Window size. Default: 7 mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4 qkv_bias (bool): If True, add a learnable bias to query, key, value. Default: True qk_scale (float): Override default qk scale of head_dim ** -0.5 if set. Default: None drop_rate (float): Dropout rate. Default: 0 attn_drop_rate (float): Attention dropout rate. Default: 0 drop_path_rate (float): Stochastic depth rate. Default: 0.1 norm_layer (nn.Module): Normalization layer. Default: nn.LayerNorm. ape (bool): If True, add absolute position embedding to the patch embedding. Default: False patch_norm (bool): If True, add normalization after patch embedding. Default: True use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False upscale (int): Upscale factor. 2/3/4/8 for image SR, 1 for denoising and compress artifact reduction. Default: 2 img_range (float): Image range. 1. or 255. Default: 1.0 upsampler (string, optional): The reconstruction module. 'pixelshuffle' / 'pixelshuffledirect' /'nearest+conv'/None. Default: '' resi_connection (string): The convolutional block before residual connection. '1conv'/'3conv'. Default: '1conv' """ def __init__(self, img_size=64, patch_size=1, in_chans=3, embed_dim=96, depths=[6, 6, 6, 6], num_heads=[6, 6, 6, 6], window_size=7, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0., drop_path_rate=0.1, norm_layer=nn.LayerNorm, ape=False, patch_norm=True, use_checkpoint=False, upscale=2, img_range=1., upsampler='', resi_connection='1conv', **kwargs): super(SwinIRNet, self).__init__() num_in_ch = in_chans num_out_ch = in_chans num_feat = 64 self.img_range = img_range if in_chans == 3: rgb_mean = (0.4488, 0.4371, 0.4040) self.mean = torch.Tensor(rgb_mean).view(1, 3, 1, 1) else: self.mean = torch.zeros(1, 1, 1, 1) self.upscale = upscale self.upsampler = upsampler self.window_size = window_size # 1, shallow feature extraction self.conv_first = nn.Conv2d(num_in_ch, embed_dim, 3, 1, 1) # 2, deep feature extraction self.num_layers = len(depths) self.embed_dim = embed_dim self.ape = ape self.patch_norm = patch_norm self.num_features = embed_dim self.mlp_ratio = mlp_ratio # split image into non-overlapping patches self.patch_embed = PatchEmbed( img_size=img_size, patch_size=patch_size, in_chans=embed_dim, embed_dim=embed_dim, norm_layer=norm_layer if self.patch_norm else None) num_patches = self.patch_embed.num_patches patches_resolution = self.patch_embed.patches_resolution self.patches_resolution = patches_resolution # merge non-overlapping patches into image self.patch_unembed = PatchUnEmbed( img_size=img_size, patch_size=patch_size, in_chans=embed_dim, embed_dim=embed_dim, norm_layer=norm_layer if self.patch_norm else None) # absolute position embedding if self.ape: self.absolute_pos_embed = nn.Parameter( torch.zeros(1, num_patches, embed_dim)) trunc_normal_(self.absolute_pos_embed, std=.02) self.pos_drop = nn.Dropout(p=drop_rate) # stochastic depth decay rule dpr = [ x.item() for x in torch.linspace(0, drop_path_rate, sum(depths)) ] # build Residual Swin Transformer blocks (RSTB) self.layers = nn.ModuleList() for i_layer in range(self.num_layers): layer = RSTB( dim=embed_dim, input_resolution=(patches_resolution[0], patches_resolution[1]), depth=depths[i_layer], num_heads=num_heads[i_layer], window_size=window_size, mlp_ratio=self.mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])], norm_layer=norm_layer, downsample=None, use_checkpoint=use_checkpoint, img_size=img_size, patch_size=patch_size, resi_connection=resi_connection) self.layers.append(layer) self.norm = norm_layer(self.num_features) # build the last conv layer in deep feature extraction if resi_connection == '1conv': self.conv_after_body = nn.Conv2d(embed_dim, embed_dim, 3, 1, 1) elif resi_connection == '3conv': # to save parameters and memory self.conv_after_body = nn.Sequential( nn.Conv2d(embed_dim, embed_dim // 4, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(embed_dim // 4, embed_dim // 4, 1, 1, 0), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(embed_dim // 4, embed_dim, 3, 1, 1)) # 3, high quality image reconstruction if self.upsampler == 'pixelshuffle': # for classical SR self.conv_before_upsample = nn.Sequential( nn.Conv2d(embed_dim, num_feat, 3, 1, 1), nn.LeakyReLU(inplace=True)) self.upsample = Upsample(upscale, num_feat) self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) elif self.upsampler == 'pixelshuffledirect': # for lightweight SR (to save parameters) self.upsample = UpsampleOneStep(upscale, embed_dim, num_out_ch, (patches_resolution[0], patches_resolution[1])) elif self.upsampler == 'nearest+conv': # for real-world SR (less artifacts) self.conv_before_upsample = nn.Sequential( nn.Conv2d(embed_dim, num_feat, 3, 1, 1), nn.LeakyReLU(inplace=True)) self.conv_up1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1) if self.upscale == 4: self.conv_up2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1) self.conv_hr = nn.Conv2d(num_feat, num_feat, 3, 1, 1) self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) else: # for image denoising and JPEG compression artifact reduction self.conv_last = nn.Conv2d(embed_dim, num_out_ch, 3, 1, 1) self.apply(self._init_weights) def _init_weights(self, m): if isinstance(m, nn.Linear): trunc_normal_(m.weight, std=.02) if isinstance(m, nn.Linear) and m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.LayerNorm): nn.init.constant_(m.bias, 0) nn.init.constant_(m.weight, 1.0) @torch.jit.ignore def no_weight_decay(self): return {'absolute_pos_embed'} @torch.jit.ignore def no_weight_decay_keywords(self): return {'relative_position_bias_table'} def check_image_size(self, x): """Check image size and pad images so that it has enough dimension do window size. args: x: input tensor image with (B, C, H, W) shape. """ _, _, h, w = x.size() mod_pad_h = (self.window_size - h % self.window_size) % self.window_size mod_pad_w = (self.window_size - w % self.window_size) % self.window_size x = F.pad(x, (0, mod_pad_w, 0, mod_pad_h), 'reflect') return x def forward_features(self, x): """Forward function of Deep Feature Extraction. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ x_size = (x.shape[2], x.shape[3]) x = self.patch_embed(x) if self.ape: x = x + self.absolute_pos_embed x = self.pos_drop(x) for layer in self.layers: x = layer(x, x_size) x = self.norm(x) # B L C x = self.patch_unembed(x, x_size) return x def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, C, H, W). Returns: Tensor: Forward results. """ H, W = x.shape[2:] x = self.check_image_size(x) self.mean = self.mean.type_as(x) x = (x - self.mean) * self.img_range if self.upsampler == 'pixelshuffle': # for classical SR x = self.conv_first(x) x = self.conv_after_body(self.forward_features(x)) + x x = self.conv_before_upsample(x) x = self.conv_last(self.upsample(x)) elif self.upsampler == 'pixelshuffledirect': # for lightweight SR x = self.conv_first(x) x = self.conv_after_body(self.forward_features(x)) + x x = self.upsample(x) elif self.upsampler == 'nearest+conv': # for real-world SR x = self.conv_first(x) x = self.conv_after_body(self.forward_features(x)) + x x = self.conv_before_upsample(x) x = self.lrelu( self.conv_up1( torch.nn.functional.interpolate( x, scale_factor=2, mode='nearest'))) if self.upscale == 4: x = self.lrelu( self.conv_up2( torch.nn.functional.interpolate( x, scale_factor=2, mode='nearest'))) x = self.conv_last(self.lrelu(self.conv_hr(x))) else: # for image denoising and JPEG compression artifact reduction x_first = self.conv_first(x) res = self.conv_after_body( self.forward_features(x_first)) + x_first x = x + self.conv_last(res) x = x / self.img_range + self.mean return x[:, :, :H * self.upscale, :W * self.upscale] ================================================ FILE: mmagic/models/editors/swinir/swinir_rstb.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.utils.checkpoint as checkpoint from mmengine.model.weight_init import trunc_normal_ from .swinir_modules import PatchEmbed, PatchUnEmbed from .swinir_utils import (drop_path, to_2tuple, window_partition, window_reverse) class DropPath(nn.Module): """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).""" def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True): super(DropPath, self).__init__() self.drop_prob = drop_prob self.scale_by_keep = scale_by_keep def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). Returns: Tensor: Forward results. """ return drop_path(x, self.drop_prob, self.training, self.scale_by_keep) def extra_repr(self): return f'drop_prob={round(self.drop_prob, 3):0.3f}' class Mlp(nn.Module): """Multilayer Perceptron layer. Args: in_features (int): Number of input channels. hidden_features (int | None, optional): Number of hidden layer channels. Default: None out_features (int | None, optional): Number of output channels. Default: None act_layer (nn.Module, optional): Activation layer. Default: nn.GELU drop (float, optional): Dropout ratio of attention weight. Default: 0.0 """ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.): super().__init__() out_features = out_features or in_features hidden_features = hidden_features or in_features self.fc1 = nn.Linear(in_features, hidden_features) self.act = act_layer() self.fc2 = nn.Linear(hidden_features, out_features) self.drop = nn.Dropout(drop) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). Returns: Tensor: Forward results. """ x = self.fc1(x) x = self.act(x) x = self.drop(x) x = self.fc2(x) x = self.drop(x) return x class WindowAttention(nn.Module): r""" Window based multi-head self attention (W-MSA) module with relative position bias. It supports both of shifted and non-shifted window. Args: dim (int): Number of input channels. window_size (tuple[int]): The height and width of the window. num_heads (int): Number of attention heads. qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0 proj_drop (float, optional): Dropout ratio of output. Default: 0.0 """ def __init__(self, dim, window_size, num_heads, qkv_bias=True, qk_scale=None, attn_drop=0., proj_drop=0.): super().__init__() self.dim = dim self.window_size = window_size # Wh, Ww self.num_heads = num_heads head_dim = dim // num_heads self.scale = qk_scale or head_dim**-0.5 # define a parameter table of relative position bias # 2*Wh-1 * 2*Ww-1, nH self.relative_position_bias_table = nn.Parameter( torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)) # get pair-wise relative position index # for each token inside the window coords_h = torch.arange(self.window_size[0]) coords_w = torch.arange(self.window_size[1]) coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww relative_coords = \ coords_flatten[:, :, None] - coords_flatten[:, None, :] # Wh*Ww, Wh*Ww, 2 relative_coords = relative_coords.permute(1, 2, 0).contiguous() # shift to start from 0 relative_coords[:, :, 0] += self.window_size[0] - 1 relative_coords[:, :, 1] += self.window_size[1] - 1 relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1 relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww self.register_buffer('relative_position_index', relative_position_index) self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) self.proj = nn.Linear(dim, dim) self.proj_drop = nn.Dropout(proj_drop) trunc_normal_(self.relative_position_bias_table, std=.02) self.softmax = nn.Softmax(dim=-1) def forward(self, x, mask=None): """ Args: x: input features with shape of (num_windows*B, N, C) mask: (0/-inf) mask with shape of (num_windows, Wh*Ww, Wh*Ww) or None """ B_, N, C = x.shape qkv = self.qkv(x).reshape(B_, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) # make torchscript happy (cannot use tensor as tuple) q, k, v = qkv[0], qkv[1], qkv[2] q = q * self.scale attn = (q @ k.transpose(-2, -1)) relative_position_bias = self.relative_position_bias_table[ self.relative_position_index.view(-1)].view( self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1) # Wh*Ww,Wh*Ww,nH relative_position_bias = relative_position_bias.permute( 2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww attn = attn + relative_position_bias.unsqueeze(0) if mask is not None: nW = mask.shape[0] attn = attn.view(B_ // nW, nW, self.num_heads, N, N) + mask.unsqueeze(1).unsqueeze(0) attn = attn.view(-1, self.num_heads, N, N) attn = self.softmax(attn) else: attn = self.softmax(attn) attn = self.attn_drop(attn) x = (attn @ v).transpose(1, 2).reshape(B_, N, C) x = self.proj(x) x = self.proj_drop(x) return x def extra_repr(self) -> str: return f'dim={self.dim}, window_size={self.window_size}, ' \ f'num_heads={self.num_heads}' class SwinTransformerBlock(nn.Module): r""" Swin Transformer Block. Args: dim (int): Number of input channels. input_resolution (tuple[int]): Input resolution. num_heads (int): Number of attention heads. window_size (int): Window size. shift_size (int): Shift size for SW-MSA. mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set. drop (float, optional): Dropout rate. Default: 0.0 attn_drop (float, optional): Attention dropout rate. Default: 0.0 drop_path (float, optional): Stochastic depth rate. Default: 0.0 act_layer (nn.Module, optional): Activation layer. Default: nn.GELU norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm """ def __init__(self, dim, input_resolution, num_heads, window_size=7, shift_size=0, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop=0., attn_drop=0., drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm): super().__init__() self.dim = dim self.input_resolution = input_resolution self.num_heads = num_heads self.window_size = window_size self.shift_size = shift_size self.mlp_ratio = mlp_ratio if min(self.input_resolution) <= self.window_size: # if window size is larger than input resolution, # we don't partition windows self.shift_size = 0 self.window_size = min(self.input_resolution) assert 0 <= self.shift_size < self.window_size, \ 'shift_size must in 0-window_size' self.norm1 = norm_layer(dim) self.attn = WindowAttention( dim, window_size=to_2tuple(self.window_size), num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop) self.drop_path = DropPath( drop_path) if drop_path > 0. else nn.Identity() self.norm2 = norm_layer(dim) mlp_hidden_dim = int(dim * mlp_ratio) self.mlp = Mlp( in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) if self.shift_size > 0: attn_mask = self.calculate_mask(self.input_resolution) else: attn_mask = None self.register_buffer('attn_mask', attn_mask) def calculate_mask(self, x_size): # calculate attention mask for SW-MSA """Calculate attention mask for SW-MSA. Args: x_size (tuple[int]): Resolution of input feature. Returns: Tensor: Attention mask """ H, W = x_size img_mask = torch.zeros((1, H, W, 1)) # 1 H W 1 h_slices = (slice(0, -self.window_size), slice(-self.window_size, -self.shift_size), slice(-self.shift_size, None)) w_slices = (slice(0, -self.window_size), slice(-self.window_size, -self.shift_size), slice(-self.shift_size, None)) cnt = 0 for h in h_slices: for w in w_slices: img_mask[:, h, w, :] = cnt cnt += 1 mask_windows = window_partition( img_mask, self.window_size) # nW, window_size, window_size, 1 mask_windows = mask_windows.view(-1, self.window_size * self.window_size) attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill( attn_mask == 0, float(0.0)) return attn_mask def forward(self, x, x_size): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). x_size (tuple[int]): Resolution of input feature. Returns: Tensor: Forward results. """ H, W = x_size B, L, C = x.shape # assert L == H * W, "input feature has wrong size" shortcut = x x = self.norm1(x) x = x.view(B, H, W, C) # cyclic shift if self.shift_size > 0: shifted_x = torch.roll( x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) else: shifted_x = x # partition windows x_windows = window_partition( shifted_x, self.window_size) # nW*B, window_size, window_size, C x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # nW*B, window_size*window_size, C # W-MSA/SW-MSA (to be compatible for testing on images # whose shapes are the multiple of window size if self.input_resolution == x_size: attn_windows = self.attn( x_windows, mask=self.attn_mask) # nW*B, window_size*window_size, C else: attn_windows = self.attn( x_windows, mask=self.calculate_mask(x_size).to(x.device)) # merge windows attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) shifted_x = window_reverse(attn_windows, self.window_size, H, W) # B H' W' C # reverse cyclic shift if self.shift_size > 0: x = torch.roll( shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) else: x = shifted_x x = x.view(B, H * W, C) # FFN x = shortcut + self.drop_path(x) x = x + self.drop_path(self.mlp(self.norm2(x))) return x def extra_repr(self) -> str: return f'dim={self.dim}, ' \ f'input_resolution={self.input_resolution}, ' \ f'num_heads={self.num_heads}, ' \ f'window_size={self.window_size}, ' \ f'shift_size={self.shift_size}, ' \ f'mlp_ratio={self.mlp_ratio}' class BasicLayer(nn.Module): """A basic Swin Transformer layer for one stage. Args: dim (int): Number of input channels. input_resolution (tuple[int]): Input resolution. depth (int): Number of blocks. num_heads (int): Number of attention heads. window_size (int): Local window size. mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set. drop (float, optional): Dropout rate. Default: 0.0 attn_drop (float, optional): Attention dropout rate. Default: 0.0 drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0 norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. """ def __init__(self, dim, input_resolution, depth, num_heads, window_size, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop=0., attn_drop=0., drop_path=0., norm_layer=nn.LayerNorm, downsample=None, use_checkpoint=False): super().__init__() self.dim = dim self.input_resolution = input_resolution self.depth = depth self.use_checkpoint = use_checkpoint # build blocks self.blocks = nn.ModuleList([ SwinTransformerBlock( dim=dim, input_resolution=input_resolution, num_heads=num_heads, window_size=window_size, shift_size=0 if (i % 2 == 0) else window_size // 2, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop, attn_drop=attn_drop, drop_path=drop_path[i] if isinstance(drop_path, list) else drop_path, norm_layer=norm_layer) for i in range(depth) ]) # patch merging layer if downsample is not None: self.downsample = downsample( input_resolution, dim=dim, norm_layer=norm_layer) else: self.downsample = None def forward(self, x, x_size): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). x_size (tuple[int]): Resolution of input feature. Returns: Tensor: Forward results. """ for blk in self.blocks: if self.use_checkpoint: x = checkpoint.checkpoint(blk, x, x_size) else: x = blk(x, x_size) if self.downsample is not None: x = self.downsample(x) return x def extra_repr(self) -> str: return f'dim={self.dim}, ' \ f'input_resolution={self.input_resolution}, ' \ f'depth={self.depth}' class RSTB(nn.Module): """Residual Swin Transformer Block (RSTB). Args: dim (int): Number of input channels. input_resolution (tuple[int]): Input resolution. depth (int): Number of blocks. num_heads (int): Number of attention heads. window_size (int): Local window size. mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4.0 qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set. drop (float, optional): Dropout rate. Default: 0.0 attn_drop (float, optional): Attention dropout rate. Default: 0.0 drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0 norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. img_size (int): Input image size. Default: 224 patch_size (int): Patch size. Default: 4 resi_connection (string): The convolutional block before residual connection. Default: '1conv' """ def __init__(self, dim, input_resolution, depth, num_heads, window_size, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop=0., attn_drop=0., drop_path=0., norm_layer=nn.LayerNorm, downsample=None, use_checkpoint=False, img_size=224, patch_size=4, resi_connection='1conv'): super(RSTB, self).__init__() self.dim = dim self.input_resolution = input_resolution self.residual_group = BasicLayer( dim=dim, input_resolution=input_resolution, depth=depth, num_heads=num_heads, window_size=window_size, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop, attn_drop=attn_drop, drop_path=drop_path, norm_layer=norm_layer, downsample=downsample, use_checkpoint=use_checkpoint) if resi_connection == '1conv': self.conv = nn.Conv2d(dim, dim, 3, 1, 1) elif resi_connection == '3conv': # to save parameters and memory self.conv = nn.Sequential( nn.Conv2d(dim, dim // 4, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(dim // 4, dim // 4, 1, 1, 0), nn.LeakyReLU(negative_slope=0.2, inplace=True), nn.Conv2d(dim // 4, dim, 3, 1, 1)) self.patch_embed = PatchEmbed( img_size=img_size, patch_size=patch_size, in_chans=0, embed_dim=dim, norm_layer=None) self.patch_unembed = PatchUnEmbed( img_size=img_size, patch_size=patch_size, in_chans=0, embed_dim=dim, norm_layer=None) def forward(self, x, x_size): """Forward function. Args: x (Tensor): Input tensor with shape (B, L, C). x_size (tuple[int]): Resolution of input feature. Returns: Tensor: Forward results. """ return self.patch_embed( self.conv( self.patch_unembed(self.residual_group(x, x_size), x_size))) + x ================================================ FILE: mmagic/models/editors/swinir/swinir_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import collections.abc from itertools import repeat # From PyTorch internals def _ntuple(n): """A `to_tuple` function generator. It returns a function, this function will repeat the input to a tuple of length ``n`` if the input is not an Iterable object, otherwise, return the input directly. Args: n (int): The number of the target length. """ def parse(x): if isinstance(x, collections.abc.Iterable) and not isinstance(x, str): return x return tuple(repeat(x, n)) return parse to_2tuple = _ntuple(2) def drop_path(x, drop_prob: float = 0., training: bool = False, scale_by_keep: bool = True): """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks). This is the same as the DropConnect impl I created for EfficientNet, etc networks, however, the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper... See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 I've opted for changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use 'survival rate' as the argument. """ if drop_prob == 0. or not training: return x keep_prob = 1 - drop_prob # work with diff dim tensors, not just 2D ConvNets shape = (x.shape[0], ) + (1, ) * (x.ndim - 1) random_tensor = x.new_empty(shape).bernoulli_(keep_prob) if keep_prob > 0.0 and scale_by_keep: random_tensor.div_(keep_prob) return x * random_tensor def window_partition(x, window_size): """ Args: x: (B, H, W, C) window_size (int): window size Returns: windows: (num_windows*B, window_size, window_size, C) """ B, H, W, C = x.shape x = x.view(B, H // window_size, window_size, W // window_size, window_size, C) windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C) return windows def window_reverse(windows, window_size, H, W): """ Args: windows: (num_windows*B, window_size, window_size, C) window_size (int): Window size H (int): Height of image W (int): Width of image Returns: x: (B, H, W, C) """ B = int(windows.shape[0] / (H * W / window_size / window_size)) x = windows.view(B, H // window_size, W // window_size, window_size, window_size, -1) x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1) return x ================================================ FILE: mmagic/models/editors/tdan/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .tdan import TDAN from .tdan_net import TDANNet __all__ = ['TDAN', 'TDANNet'] ================================================ FILE: mmagic/models/editors/tdan/tdan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models import BaseEditModel from mmagic.registry import MODELS @MODELS.register_module() class TDAN(BaseEditModel): """TDAN model for video super-resolution. Paper: TDAN: Temporally-Deformable Alignment Network for Video Super- Resolution, CVPR, 2020 Args: generator (dict): Config for the generator structure. pixel_loss (dict): Config for pixel-wise loss. lq_pixel_loss (dict): Config for pixel-wise loss for the LQ images. train_cfg (dict): Config for training. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. """ def __init__(self, generator, pixel_loss, lq_pixel_loss, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, pixel_loss=pixel_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.lq_pixel_loss = MODELS.build(lq_pixel_loss) def forward_train(self, inputs, data_samples=None, **kwargs): """Forward training. Returns dict of losses of training. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. Returns: dict: Dict of losses. """ feats, aligned_img = self.forward_tensor( inputs, data_samples, training=True, **kwargs) batch_gt_data = data_samples.gt_img losses = dict() # loss on the HR image losses['loss_pix'] = self.pixel_loss(feats, batch_gt_data) # loss on the aligned LR images t = aligned_img.size(1) lq_ref = inputs[:, t // 2:t // 2 + 1, :, :, :].expand(-1, t, -1, -1, -1) loss_pix_lq = self.lq_pixel_loss(aligned_img, lq_ref) losses['loss_pix_lq'] = loss_pix_lq return losses def forward_tensor(self, inputs, data_samples=None, training=False, **kwargs): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. training (bool): Whether is training. Default: False. Returns: (Tensor | List[Tensor]): results of forward inference and forward train. """ outputs = self.generator(inputs, **kwargs) return outputs if training else outputs[0] ================================================ FILE: mmagic/models/editors/tdan/tdan_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmcv.ops import DeformConv2d, DeformConv2dPack, deform_conv2d from mmengine.model import BaseModule from mmengine.model.weight_init import constant_init from torch.nn.modules.utils import _pair from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import make_layer from mmagic.registry import MODELS @MODELS.register_module() class TDANNet(BaseModule): """TDAN network structure for video super-resolution. Support only x4 upsampling. Paper: TDAN: Temporally-Deformable Alignment Network for Video Super- Resolution, CVPR, 2020 Args: in_channels (int): Number of channels of the input image. Default: 3. mid_channels (int): Number of channels of the intermediate features. Default: 64. out_channels (int): Number of channels of the output image. Default: 3. num_blocks_before_align (int): Number of residual blocks before temporal alignment. Default: 5. num_blocks_after_align (int): Number of residual blocks after temporal alignment. Default: 10. """ def __init__(self, in_channels=3, mid_channels=64, out_channels=3, num_blocks_before_align=5, num_blocks_after_align=10): super().__init__() self.feat_extract = nn.Sequential( ConvModule(in_channels, mid_channels, 3, padding=1), make_layer( ResidualBlockNoBN, num_blocks_before_align, mid_channels=mid_channels)) self.feat_aggregate = nn.Sequential( nn.Conv2d(mid_channels * 2, mid_channels, 3, padding=1, bias=True), DeformConv2dPack( mid_channels, mid_channels, 3, padding=1, deform_groups=8), DeformConv2dPack( mid_channels, mid_channels, 3, padding=1, deform_groups=8)) self.align_1 = AugmentedDeformConv2dPack( mid_channels, mid_channels, 3, padding=1, deform_groups=8) self.align_2 = DeformConv2dPack( mid_channels, mid_channels, 3, padding=1, deform_groups=8) self.to_rgb = nn.Conv2d(mid_channels, 3, 3, padding=1, bias=True) self.reconstruct = nn.Sequential( ConvModule(in_channels * 5, mid_channels, 3, padding=1), make_layer( ResidualBlockNoBN, num_blocks_after_align, mid_channels=mid_channels), PixelShufflePack(mid_channels, mid_channels, 2, upsample_kernel=3), PixelShufflePack(mid_channels, mid_channels, 2, upsample_kernel=3), nn.Conv2d(mid_channels, out_channels, 3, 1, 1, bias=False)) def forward(self, lrs): """Forward function for TDANNet. Args: lrs (Tensor): Input LR sequence with shape (n, t, c, h, w). Returns: tuple[Tensor]: Output HR image with shape (n, c, 4h, 4w) and aligned LR images with shape (n, t, c, h, w). """ n, t, c, h, w = lrs.size() lr_center = lrs[:, t // 2, :, :, :] # LR center frame # extract features feats = self.feat_extract(lrs.view(-1, c, h, w)).view(n, t, -1, h, w) # alignment of LR frames feat_center = feats[:, t // 2, :, :, :].contiguous() aligned_lrs = [] for i in range(0, t): if i == t // 2: aligned_lrs.append(lr_center) else: feat_neig = feats[:, i, :, :, :].contiguous() feat_agg = torch.cat([feat_center, feat_neig], dim=1) feat_agg = self.feat_aggregate(feat_agg) aligned_feat = self.align_2(self.align_1(feat_neig, feat_agg)) aligned_lrs.append(self.to_rgb(aligned_feat)) aligned_lrs = torch.cat(aligned_lrs, dim=1) # output HR center frame and the aligned LR frames return self.reconstruct(aligned_lrs), aligned_lrs.view(n, t, c, h, w) class AugmentedDeformConv2dPack(DeformConv2d): """Augmented Deformable Convolution Pack. Different from DeformConv2dPack, which generates offsets from the preceding feature, this AugmentedDeformConv2dPack takes another feature to generate the offsets. Args: in_channels (int): Number of channels in the input feature. out_channels (int): Number of channels produced by the convolution. kernel_size (int or tuple[int]): Size of the convolving kernel. stride (int or tuple[int]): Stride of the convolution. Default: 1. padding (int or tuple[int]): Zero-padding added to both sides of the input. Default: 0. dilation (int or tuple[int]): Spacing between kernel elements. Default: 1. groups (int): Number of blocked connections from input channels to output channels. Default: 1. deform_groups (int): Number of deformable group partitions. bias (bool or str): If specified as `auto`, it will be decided by the norm_cfg. Bias will be set as True if norm_cfg is None, otherwise False. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.conv_offset = nn.Conv2d( self.in_channels, self.deform_groups * 2 * self.kernel_size[0] * self.kernel_size[1], kernel_size=self.kernel_size, stride=_pair(self.stride), padding=_pair(self.padding), bias=True) self.init_offset() def init_offset(self): """Init constant offset.""" constant_init(self.conv_offset, val=0, bias=0) def forward(self, x, extra_feat): """Forward function.""" offset = self.conv_offset(extra_feat) return deform_conv2d(x, offset, self.weight, self.stride, self.padding, self.dilation, self.groups, self.deform_groups) ================================================ FILE: mmagic/models/editors/textual_inversion/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .textual_inversion import TextualInversion __all__ = ['TextualInversion'] ================================================ FILE: mmagic/models/editors/textual_inversion/textual_inversion.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Optional, Union import torch import torch.nn as nn import torch.nn.functional as F from mmengine.logging import MMLogger from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ..stable_diffusion.stable_diffusion import StableDiffusion logger = MMLogger.get_current_instance() ModelType = Union[Dict, nn.Module] @MODELS.register_module() class TextualInversion(StableDiffusion): """Implementation of `An Image is Worth One Word: Personalizing Text-to- Image Generation using Textual Inversion. `_ (Textual Inversion). Args: vae (Union[dict, nn.Module]): The config or module for VAE model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. tokenizer (str): The **name** for CLIP tokenizer. unet (Union[dict, nn.Module]): The config or module for Unet model. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. dtype (str, optional): The dtype for the model. Defaults to 'fp16'. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise # noqa Defaults to 0. tomesd_cfg (dict, optional): The config for TOMESD. Please refers to https://github.com/dbolya/tomesd and https://github.com/open-mmlab/mmagic/blob/main/mmagic/models/utils/tome_utils.py for detail. # noqa Defaults to None. initialize_token (str, optional): The initialization token for textual embedding to train. Defaults to None. num_vefctor_per_token (int): The length of the learnable embedding. Defaults to 1. val_prompts (Union[str, List[str]], optional): The prompts for validation. Defaults to None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Defaults to dict(type='DataPreprocessor'). init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Defaults to None/ """ def __init__(self, placeholder_token: str, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, dtype: Optional[str] = None, enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, initialize_token: Optional[str] = None, num_vectors_per_token: int = 1, val_prompts=None, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), init_cfg: Optional[dict] = None): super().__init__(vae, text_encoder, tokenizer, unet, scheduler, test_scheduler, dtype, enable_xformers, noise_offset_weight, tomesd_cfg, data_preprocessor, init_cfg) self.val_prompts = val_prompts self.placeholder_token = placeholder_token self.add_tokens(placeholder_token, initialize_token, num_vectors_per_token) self.prepare_models() def prepare_models(self): """Disable gradient for untrainable modules to save memory.""" self.vae.requires_grad_(False) self.unet.requires_grad_(False) self.text_encoder.set_only_embedding_trainable() @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) data_samples = data['data_samples'] if self.val_prompts is None: prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples.split() * len(prompt) data_samples = DataSample.stack(data_samples.split() * len(prompt)) unet_dtype = next(self.unet.parameters()).dtype self.unet.to(self.dtype) output = self.infer(prompt, return_type='tensor') samples = output['samples'] self.unet.to(unet_dtype) samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ if self.val_prompts is None: data = self.data_preprocessor(data) data_samples = data['data_samples'] prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples = DataSample.stack(data['data_samples'] * len(prompt)) unet_dtype = next(self.unet.parameters()).dtype self.unet.to(self.dtype) output = self.infer(prompt, return_type='tensor') samples = output['samples'] self.unet.to(unet_dtype) samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list def add_tokens(self, placeholder_token: str, initialize_token: str = None, num_vectors_per_token: int = 1): """Add token for training. # TODO: support add tokens as dict, then we can load pretrained tokens. """ self.tokenizer.add_placeholder_token( placeholder_token, num_vec_per_token=num_vectors_per_token) self.text_encoder.set_embedding_layer() embedding_layer = self.text_encoder.get_embedding_layer() assert embedding_layer is not None, ( 'Do not support get embedding layer for current text encoder. ' 'Please check your configuration.') if initialize_token: init_id = self.tokenizer(initialize_token).input_ids[1] initialize_embedding = embedding_layer.weight[init_id] initialize_embedding = initialize_embedding[None, ...].repeat( num_vectors_per_token, 1) else: emb_dim = embedding_layer.weight.shape[1] initialize_embedding = torch.zeros(num_vectors_per_token, emb_dim) token_info = self.tokenizer.get_token_info(placeholder_token) token_info['embedding'] = initialize_embedding token_info['trainable'] = True self.token_info = token_info embedding_layer.add_embeddings(token_info) def train_step(self, data, optim_wrapper): """Training step.""" data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] vae = self.vae.module if hasattr(self.vae, 'module') else self.vae vae_dtype = next(vae.parameters()).dtype unet_dtype = next(self.unet.parameters()).dtype with optim_wrapper.optim_context(self.unet): image = inputs # image for new concept prompt = data_samples.prompt num_batches = image.shape[0] image = image.to(vae_dtype) latents = vae.encode(image).latent_dist.sample() latents = latents * vae.config.scaling_factor noise = torch.randn_like(latents) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) input_ids = self.tokenizer( prompt, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) encoder_hidden_states = self.text_encoder(input_ids)[0] if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') model_output = self.unet( noisy_latents.to(unet_dtype), timesteps, encoder_hidden_states=encoder_hidden_states.to(unet_dtype)) model_pred = model_output['sample'] loss_dict = dict() # calculate loss in FP32 loss = F.mse_loss(model_pred.float(), gt.float()) loss_dict['loss'] = loss parsed_loss, log_vars = self.parse_losses(loss_dict) optim_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/tof/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .tof_vfi_net import TOFlowVFINet, ToFResBlock from .tof_vsr_net import TOFlowVSRNet __all__ = ['TOFlowVFINet', 'TOFlowVSRNet', 'ToFResBlock'] ================================================ FILE: mmagic/models/editors/tof/tof_vfi_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine import MMLogger from mmengine.model import BaseModule from mmengine.runner import load_checkpoint from mmagic.models.utils import flow_warp from mmagic.registry import MODELS @MODELS.register_module() class TOFlowVFINet(BaseModule): """PyTorch implementation of TOFlow for video frame interpolation. Paper: Xue et al., Video Enhancement with Task-Oriented Flow, IJCV 2018 Code reference: 1. https://github.com/anchen1011/toflow 2. https://github.com/Coldog2333/pytoflow Args: rgb_mean (list[float]): Image mean in RGB orders. Default: [0.485, 0.456, 0.406] rgb_std (list[float]): Image std in RGB orders. Default: [0.229, 0.224, 0.225] flow_cfg (dict): Config of SPyNet. Default: dict(norm_cfg=None, pretrained=None) init_cfg (dict, optional): Initialization config dict. Default: None. """ def __init__(self, rgb_mean=[0.485, 0.456, 0.406], rgb_std=[0.229, 0.224, 0.225], flow_cfg=dict(norm_cfg=None, pretrained=None), init_cfg=None): super().__init__(init_cfg=init_cfg) # The mean and std are for img with range (0, 1) self.register_buffer('mean', torch.Tensor(rgb_mean).view(1, -1, 1, 1)) self.register_buffer('std', torch.Tensor(rgb_std).view(1, -1, 1, 1)) # flow estimation module self.spynet = SPyNet(**flow_cfg) # reconstruction module self.resnet = ToFResBlock() def forward(self, imgs): """ Args: imgs: Input frames with shape of (b, 2, 3, h, w). Returns: Tensor: Interpolated frame with shape of (b, 3, h, w). """ flow_10 = self.spynet(imgs[:, 0], imgs[:, 1]).permute(0, 2, 3, 1) flow_01 = self.spynet(imgs[:, 1], imgs[:, 0]).permute(0, 2, 3, 1) warp_frame0 = flow_warp(imgs[:, 0], flow_01 / 2) warp_frame1 = flow_warp(imgs[:, 1], flow_10 / 2) warp_frames = torch.stack([warp_frame0, warp_frame1], dim=1) output = self.resnet(warp_frames) return output class BasicModule(nn.Module): """Basic module of SPyNet. Note that unlike the common spynet architecture, the basic module here could contain batch normalization. Args: norm_cfg (dict | None): Config of normalization. """ def __init__(self, norm_cfg): super().__init__() self.basic_module = nn.Sequential( ConvModule( in_channels=8, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=64, kernel_size=7, stride=1, padding=3, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')), ConvModule( in_channels=64, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=16, kernel_size=7, stride=1, padding=3, norm_cfg=norm_cfg, act_cfg=dict(type='ReLU')), ConvModule( in_channels=16, out_channels=2, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=None)) def forward(self, tensor_input): """ Args: tensor_input (Tensor): Input tensor with shape (b, 8, h, w). 8 channels contain: [reference image (3), neighbor image (3), initial flow (2)]. Returns: Tensor: Estimated flow with shape (b, 2, h, w) """ return self.basic_module(tensor_input) class SPyNet(nn.Module): """SPyNet architecture. Note that this implementation is specifically for TOFlow. It differs from the common SPyNet in the following aspects: 1. The basic modules in paper of TOFlow contain BatchNorm. 2. Normalization and denormalization are not done here, as they are done in TOFlow. Paper: Optical Flow Estimation using a Spatial Pyramid Network Code reference: https://github.com/Coldog2333/pytoflow Args: norm_cfg (dict | None): Config of normalization. pretrained (str): path for pre-trained SPyNet. Default: None. """ def __init__(self, norm_cfg, pretrained=None): super().__init__() self.basic_module = nn.ModuleList( [BasicModule(norm_cfg) for _ in range(4)]) if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=True, logger=logger) elif pretrained is not None: raise TypeError('[pretrained] should be str or None, ' f'but got {type(pretrained)}.') def forward(self, ref, supp): """ Args: ref (Tensor): Reference image with shape of (b, 3, h, w). supp: The supporting image to be warped: (b, 3, h, w). Returns: Tensor: Estimated optical flow: (b, 2, h, w). """ num_batches, _, h, w = ref.size() ref = [ref] supp = [supp] # generate downsampled frames for _ in range(3): ref.insert( 0, F.avg_pool2d( input=ref[0], kernel_size=2, stride=2, count_include_pad=False)) supp.insert( 0, F.avg_pool2d( input=supp[0], kernel_size=2, stride=2, count_include_pad=False)) # flow computation flow = ref[0].new_zeros(num_batches, 2, h // 16, w // 16) for i in range(4): flow_up = F.interpolate( input=flow, scale_factor=2, mode='bilinear', align_corners=True) * 2.0 flow = flow_up + self.basic_module[i]( torch.cat([ ref[i], flow_warp( supp[i], flow_up.permute(0, 2, 3, 1), padding_mode='border'), flow_up ], 1)) return flow class ToFResBlock(nn.Module): """ResNet architecture. Three-layers ResNet/ResBlock """ def __init__(self): super().__init__() self.res_block = nn.Sequential( nn.Conv2d(6, 64, kernel_size=9, stride=1, padding=4), nn.ReLU(inplace=True), nn.Conv2d(64, 64, kernel_size=1, stride=1, padding=0), nn.ReLU(inplace=True), nn.Conv2d(64, 3, kernel_size=1, stride=1, padding=0)) def forward(self, frames): """ Args: frames (Tensor): Tensor with shape of (b, 2, 3, h, w). Returns: Tensor: Interpolated frame with shape of (b, 3, h, w). """ num_batches, _, _, h, w = frames.size() average = frames.mean(dim=1) x = frames.view(num_batches, -1, h, w) result = self.res_block(x) return result + average ================================================ FILE: mmagic/models/editors/tof/tof_vsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.utils import flow_warp from mmagic.registry import MODELS @MODELS.register_module() class TOFlowVSRNet(BaseModule): """PyTorch implementation of TOFlow. In TOFlow, the LR frames are pre-upsampled and have the same size with the GT frames. Paper: Xue et al., Video Enhancement with Task-Oriented Flow, IJCV 2018 Code reference: 1. https://github.com/anchen1011/toflow 2. https://github.com/Coldog2333/pytoflow Args: adapt_official_weights (bool): Whether to adapt the weights translated from the official implementation. Set to false if you want to train from scratch. Default: False """ def __init__(self, adapt_official_weights=False, init_cfg=None): super().__init__(init_cfg=init_cfg) self.adapt_official_weights = adapt_official_weights self.ref_idx = 0 if adapt_official_weights else 3 # flow estimation module self.spynet = SPyNet() # reconstruction module self.conv1 = nn.Conv2d(3 * 7, 64, 9, 1, 4) self.conv2 = nn.Conv2d(64, 64, 9, 1, 4) self.conv3 = nn.Conv2d(64, 64, 1) self.conv4 = nn.Conv2d(64, 3, 1) # activation function self.relu = nn.ReLU(inplace=True) def forward(self, lrs): """ Args: lrs: Input lr frames: (b, 7, 3, h, w). Returns: Tensor: SR frame: (b, 3, h, w). """ # In the official implementation, the 0-th frame is the reference frame if self.adapt_official_weights: lrs = lrs[:, [3, 0, 1, 2, 4, 5, 6], :, :, :] num_batches, _, _, h, w = lrs.size() lr_ref = lrs[:, self.ref_idx, :, :, :] lr_aligned = [] for i in range(7): # 7 frames if i == self.ref_idx: lr_aligned.append(lr_ref) else: lr_supp = lrs[:, i, :, :, :] flow = self.spynet(lr_ref, lr_supp) lr_aligned.append(flow_warp(lr_supp, flow.permute(0, 2, 3, 1))) # reconstruction hr = torch.stack(lr_aligned, dim=1) hr = hr.view(num_batches, -1, h, w) hr = self.relu(self.conv1(hr)) hr = self.relu(self.conv2(hr)) hr = self.relu(self.conv3(hr)) hr = self.conv4(hr) + lr_ref return hr class BasicModule(nn.Module): """Basic module of SPyNet. Note that unlike the common spynet architecture, the basic module here contains batch normalization. """ def __init__(self): super().__init__() self.basic_module = nn.Sequential( ConvModule( in_channels=8, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=64, kernel_size=7, stride=1, padding=3, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU')), ConvModule( in_channels=64, out_channels=32, kernel_size=7, stride=1, padding=3, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU')), ConvModule( in_channels=32, out_channels=16, kernel_size=7, stride=1, padding=3, norm_cfg=dict(type='BN'), act_cfg=dict(type='ReLU')), ConvModule( in_channels=16, out_channels=2, kernel_size=7, stride=1, padding=3, norm_cfg=None, act_cfg=None)) def forward(self, tensor_input): """ Args: tensor_input (Tensor): Input tensor with shape (b, 8, h, w). 8 channels contain: [reference image (3), neighbor image (3), initial flow (2)]. Returns: Tensor: Estimated flow with shape (b, 2, h, w) """ return self.basic_module(tensor_input) class SPyNet(nn.Module): """SPyNet architecture. Note that this implementation is specifically for TOFlow. It differs from the common SPyNet in the following aspects: 1. The basic modules here contain BatchNorm. 2. Normalization and denormalization are not done here, as they are done in TOFlow. Paper: Optical Flow Estimation using a Spatial Pyramid Network Code reference: https://github.com/Coldog2333/pytoflow """ def __init__(self): super().__init__() self.basic_module = nn.ModuleList([BasicModule() for _ in range(4)]) def forward(self, ref, supp): """ Args: ref (Tensor): Reference image with shape of (b, 3, h, w). supp: The supporting image to be warped: (b, 3, h, w). Returns: Tensor: Estimated optical flow: (b, 2, h, w). """ num_batches, _, h, w = ref.size() ref = [ref] supp = [supp] # generate downsampled frames for _ in range(3): ref.insert( 0, F.avg_pool2d( input=ref[0], kernel_size=2, stride=2, count_include_pad=False)) supp.insert( 0, F.avg_pool2d( input=supp[0], kernel_size=2, stride=2, count_include_pad=False)) # flow computation flow = ref[0].new_zeros(num_batches, 2, h // 16, w // 16) for i in range(4): flow_up = F.interpolate( input=flow, scale_factor=2, mode='bilinear', align_corners=True) * 2.0 flow = flow_up + self.basic_module[i]( torch.cat([ ref[i], flow_warp(supp[i], flow_up.permute(0, 2, 3, 1)), flow_up ], 1)) return flow ================================================ FILE: mmagic/models/editors/ttsr/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .lte import LTE from .search_transformer import SearchTransformer from .ttsr import TTSR from .ttsr_disc import TTSRDiscriminator from .ttsr_net import TTSRNet __all__ = [ 'LTE', 'SearchTransformer', 'TTSR', 'TTSRDiscriminator', 'TTSRNet', ] ================================================ FILE: mmagic/models/editors/ttsr/lte.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine.model import BaseModule from torchvision import models from mmagic.models.archs import ImgNormalize from mmagic.registry import MODELS @MODELS.register_module() class LTE(BaseModule): """Learnable Texture Extractor. Based on pretrained VGG19. Generate features in 3 levels. Args: requires_grad (bool): Require grad or not. Default: True. pixel_range (float): Pixel range of feature. Default: 1. load_pretrained_vgg (bool): Load pretrained VGG from torchvision. Default: True. Train: must load pretrained VGG. Eval: needn't load pretrained VGG, because we will load pretrained LTE. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, requires_grad=True, pixel_range=1., load_pretrained_vgg=True, init_cfg=None): super().__init__(init_cfg=init_cfg) vgg_mean = (0.485, 0.456, 0.406) vgg_std = (0.229 * pixel_range, 0.224 * pixel_range, 0.225 * pixel_range) self.img_normalize = ImgNormalize( pixel_range=pixel_range, img_mean=vgg_mean, img_std=vgg_std) # use vgg19 weights to initialize vgg_pretrained_features = models.vgg19( pretrained=load_pretrained_vgg).features self.slice1 = torch.nn.Sequential() self.slice2 = torch.nn.Sequential() self.slice3 = torch.nn.Sequential() for x in range(2): self.slice1.add_module(str(x), vgg_pretrained_features[x]) for x in range(2, 7): self.slice2.add_module(str(x), vgg_pretrained_features[x]) for x in range(7, 12): self.slice3.add_module(str(x), vgg_pretrained_features[x]) if not requires_grad: for param in self.slice1.parameters(): param.requires_grad = requires_grad for param in self.slice2.parameters(): param.requires_grad = requires_grad for param in self.slice3.parameters(): param.requires_grad = requires_grad def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, 3, h, w). Returns: Tuple[Tensor]: Forward results in 3 levels. x_level3: Forward results in level 3 (n, 256, h/4, w/4). x_level2: Forward results in level 2 (n, 128, h/2, w/2). x_level1: Forward results in level 1 (n, 64, h, w). """ x = self.img_normalize(x) x_level1 = x = self.slice1(x) x_level2 = x = self.slice2(x) x_level3 = x = self.slice3(x) return [x_level3, x_level2, x_level1] ================================================ FILE: mmagic/models/editors/ttsr/search_transformer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class SearchTransformer(BaseModule): """Search texture reference by transformer. Include relevance embedding, hard-attention and soft-attention. """ def gather(self, inputs, dim, index): """Hard Attention. Gathers values along an axis specified by dim. Args: inputs (Tensor): The source tensor. (N, C*k*k, H*W) dim (int): The axis along which to index. index (Tensor): The indices of elements to gather. (N, H*W) results: outputs (Tensor): The result tensor. (N, C*k*k, H*W) """ views = [inputs.size(0) ] + [1 if i != dim else -1 for i in range(1, inputs.ndim)] expansion = [ -1 if i in (0, dim) else d for i, d in enumerate(inputs.size()) ] index = index.view(views).expand(expansion) outputs = torch.gather(inputs, dim, index) return outputs def forward(self, img_lq, ref_lq, refs): """Texture transformer. Q = LTE(img_lq) K = LTE(ref_lq) V = LTE(ref), from V_level_n to V_level_1 Relevance embedding aims to embed the relevance between the LQ and Ref image by estimating the similarity between Q and K. Hard-Attention: Only transfer features from the most relevant position in V for each query. Soft-Attention: synthesize features from the transferred GT texture features T and the LQ features F from the backbone. Args: All args are features come from extractor (such as LTE). These features contain 3 levels. When upscale_factor=4, the size ratio of these features is level3:level2:level1 = 1:2:4. img_lq (Tensor): Tensor of 4x bicubic-upsampled lq image. (N, C, H, W) ref_lq (Tensor): Tensor of ref_lq. ref_lq is obtained by applying bicubic down-sampling and up-sampling with factor 4x on ref. (N, C, H, W) refs (Tuple[Tensor]): Tuple of ref tensors. [(N, C, H, W), (N, C/2, 2H, 2W), ...] Returns: tuple: tuple contains: soft_attention (Tensor): Soft-Attention tensor. (N, 1, H, W) \n textures (Tuple[Tensor]): Transferred GT textures. [(N, C, H, W), (N, C/2, 2H, 2W), ...] """ levels = len(refs) # query query = F.unfold(img_lq, kernel_size=(3, 3), padding=1) # key key = F.unfold(ref_lq, kernel_size=(3, 3), padding=1) key_t = key.permute(0, 2, 1) # values values = [ F.unfold( refs[i], kernel_size=3 * pow(2, i), padding=pow(2, i), stride=pow(2, i)) for i in range(levels) ] key_t = F.normalize(key_t, dim=2) # [N, H*W, C*k*k] query = F.normalize(query, dim=1) # [N, C*k*k, H*W] # Relevance embedding rel_embedding = torch.bmm(key_t, query) # [N, H*W, H*W] max_val, max_index = torch.max(rel_embedding, dim=1) # [N, H*W] # hard-attention textures = [self.gather(value, 2, max_index) for value in values] # to tensor h, w = img_lq.size()[-2:] textures = [ F.fold( textures[i], output_size=(h * pow(2, i), w * pow(2, i)), kernel_size=3 * pow(2, i), padding=pow(2, i), stride=pow(2, i)) / 9. for i in range(levels) ] soft_attention = max_val.view(max_val.size(0), 1, h, w) return soft_attention, textures ================================================ FILE: mmagic/models/editors/ttsr/ttsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List import torch from mmengine.optim import OptimWrapperDict from mmagic.models.utils import set_requires_grad from mmagic.registry import MODELS from mmagic.structures import DataSample from ..srgan import SRGAN @MODELS.register_module() class TTSR(SRGAN): """TTSR model for Reference-based Image Super-Resolution. Paper: Learning Texture Transformer Network for Image Super-Resolution. Args: generator (dict): Config for the generator. extractor (dict): Config for the extractor. transformer (dict): Config for the transformer. pixel_loss (dict): Config for the pixel loss. discriminator (dict): Config for the discriminator. Default: None. perceptual_loss (dict): Config for the perceptual loss. Default: None. transferal_perceptual_loss (dict): Config for the transferal perceptual loss. Default: None. gan_loss (dict): Config for the GAN loss. Default: None train_cfg (dict): Config for train. Default: None. test_cfg (dict): Config for testing. Default: None. init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Default: None. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Default: None. """ def __init__(self, generator, extractor, transformer, pixel_loss, discriminator=None, perceptual_loss=None, transferal_perceptual_loss=None, gan_loss=None, train_cfg=None, test_cfg=None, init_cfg=None, data_preprocessor=None): super().__init__( generator=generator, discriminator=discriminator, gan_loss=gan_loss, pixel_loss=pixel_loss, perceptual_loss=perceptual_loss, train_cfg=train_cfg, test_cfg=test_cfg, init_cfg=init_cfg, data_preprocessor=data_preprocessor) self.transformer = MODELS.build(transformer) self.extractor = MODELS.build(extractor) extractor['requires_grad'] = False self.extractor_copy = MODELS.build(extractor) set_requires_grad(self.extractor_copy, False) if transferal_perceptual_loss: self.transferal_perceptual_loss = MODELS.build( transferal_perceptual_loss) else: self.transferal_perceptual_loss = None self.pixel_init = train_cfg.get('pixel_init', 0) if train_cfg else 0 def forward_tensor(self, inputs, data_samples=None, training=False): """Forward tensor. Returns result of simple forward. Args: inputs (torch.Tensor): batch input tensor collated by :attr:`data_preprocessor`. data_samples (List[BaseDataElement], optional): data samples collated by :attr:`data_preprocessor`. training (bool): Whether is training. Default: False. Returns: (Tensor | Tuple[List[Tensor]]): results of forward inference and forward train. """ img_lq = [] ref_lq = [] ref = [] img_lq = data_samples.img_lq / 255. ref_lq = data_samples.ref_lq / 255. ref = data_samples.ref_img / 255. img_lq, _, _ = self.extractor(img_lq) ref_lq, _, _ = self.extractor(ref_lq) refs = self.extractor(ref) soft_attention, textures = self.transformer(img_lq, ref_lq, refs) pred = self.generator(inputs, soft_attention, textures) if training: return pred, soft_attention, textures else: return pred def if_run_g(self): """Calculates whether need to run the generator step.""" return True def if_run_d(self): """Calculates whether need to run the discriminator step.""" return self.step_counter >= self.pixel_init and super().if_run_d() def g_step(self, batch_outputs, batch_gt_data: DataSample): """G step of GAN: Calculate losses of generator. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. Returns: dict: Dict of losses. """ losses = dict() pred, soft_attention, textures = batch_outputs # pix loss if self.pixel_loss: losses['loss_pix'] = self.pixel_loss(pred, batch_gt_data) if self.step_counter >= self.pixel_init: # perceptual loss if self.perceptual_loss: loss_percep, loss_style = self.perceptual_loss( pred, batch_gt_data) if loss_percep is not None: losses['loss_perceptual'] = loss_percep if loss_style is not None: losses['loss_style'] = loss_style # transform loss if self.transferal_perceptual_loss: state_dict = self.extractor.module.state_dict() if hasattr( self.extractor, 'module') else self.extractor.state_dict() self.extractor_copy.load_state_dict(state_dict) sr_textures = self.extractor_copy((pred + 1.) / 2.) losses['loss_transferal'] = self.transferal_perceptual_loss( sr_textures, soft_attention, textures) # gan loss for generator if self.gan_loss and self.discriminator: fake_g_pred = self.discriminator(pred) losses['loss_gan'] = self.gan_loss( fake_g_pred, target_is_real=True, is_disc=False) return losses def g_step_with_optim(self, batch_outputs: torch.Tensor, batch_gt_data: torch.Tensor, optim_wrapper: OptimWrapperDict): """G step with optim of GAN: Calculate losses of generator and run optim. Args: batch_outputs (Tensor): Batch output of generator. batch_gt_data (Tensor): Batch GT data. optim_wrapper (OptimWrapperDict): Optim wrapper dict. Returns: dict: Dict of parsed losses. """ g_optim_wrapper = optim_wrapper['generator'] e_optim_wrapper = optim_wrapper['extractor'] losses_g = self.g_step(batch_outputs, batch_gt_data) parsed_losses_g, log_vars_g = self.parse_losses(losses_g) if g_optim_wrapper.should_update(): g_optim_wrapper.backward(parsed_losses_g) g_optim_wrapper.step() g_optim_wrapper.zero_grad() if e_optim_wrapper.should_update(): e_optim_wrapper.step() e_optim_wrapper.zero_grad() return log_vars_g def train_step(self, data: List[dict], optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: """Train step of GAN-based method. Args: data (List[dict]): Data sampled from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ g_optim_wrapper = optim_wrapper['generator'] data = self.data_preprocessor(data, True) batch_inputs = data['inputs'] data_samples = data['data_samples'] batch_gt_data = self.extract_gt_data(data_samples) log_vars = dict() with g_optim_wrapper.optim_context(self): batch_outputs = self.forward_train(batch_inputs, data_samples) if self.if_run_g(): set_requires_grad(self.discriminator, False) log_vars_d = self.g_step_with_optim( batch_outputs=batch_outputs, batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if self.if_run_d(): set_requires_grad(self.discriminator, True) pred, _, _ = batch_outputs for _ in range(self.disc_repeat): # detach before function call to resolve PyTorch2.0 compile bug log_vars_d = self.d_step_with_optim( batch_outputs=pred.detach(), batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) log_vars.update(log_vars_d) if 'loss' in log_vars: log_vars.pop('loss') self.step_counter += 1 return log_vars ================================================ FILE: mmagic/models/editors/ttsr/ttsr_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch.nn as nn from mmengine.model import BaseModule from mmagic.registry import MODELS @MODELS.register_module() class TTSRDiscriminator(BaseModule): """A discriminator for TTSR. Args: in_channels (int): Channel number of inputs. Default: 3. in_size (int): Size of input image. Default: 160. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, in_channels=3, in_size=160, init_cfg=None): super().__init__(init_cfg=init_cfg) self.body = nn.Sequential( nn.Conv2d(in_channels, 32, 3, 1, 1), nn.LeakyReLU(0.2), nn.Conv2d(32, 32, 3, 2, 1), nn.LeakyReLU(0.2), nn.Conv2d(32, 64, 3, 1, 1), nn.LeakyReLU(0.2), nn.Conv2d(64, 64, 3, 2, 1), nn.LeakyReLU(0.2), nn.Conv2d(64, 128, 3, 1, 1), nn.LeakyReLU(0.2), nn.Conv2d(128, 128, 3, 2, 1), nn.LeakyReLU(0.2), nn.Conv2d(128, 256, 3, 1, 1), nn.LeakyReLU(0.2), nn.Conv2d(256, 256, 3, 2, 1), nn.LeakyReLU(0.2), nn.Conv2d(256, 512, 3, 1, 1), nn.LeakyReLU(0.2), nn.Conv2d(512, 512, 3, 2, 1), nn.LeakyReLU(0.2)) self.last = nn.Sequential( nn.Linear(in_size // 32 * in_size // 32 * 512, 1024), nn.LeakyReLU(0.2), nn.Linear(1024, 1)) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.body(x) x = x.view(x.size(0), -1) x = self.last(x) return x ================================================ FILE: mmagic/models/editors/ttsr/ttsr_net.py ================================================ from functools import partial import torch import torch.nn as nn import torch.nn.functional as F from mmcv.cnn import build_conv_layer from mmengine.model import BaseModule from mmagic.models.archs import PixelShufflePack, ResidualBlockNoBN from mmagic.models.utils import make_layer from mmagic.registry import MODELS # Use partial to specify some default arguments _conv3x3_layer = partial( build_conv_layer, dict(type='Conv2d'), kernel_size=3, padding=1) _conv1x1_layer = partial( build_conv_layer, dict(type='Conv2d'), kernel_size=1, padding=0) @MODELS.register_module() class TTSRNet(BaseModule): """TTSR network structure (main-net) for reference-based super-resolution. Paper: Learning Texture Transformer Network for Image Super-Resolution Adapted from 'https://github.com/researchmm/TTSR.git' 'https://github.com/researchmm/TTSR' Copyright permission at 'https://github.com/researchmm/TTSR/issues/38'. Args: in_channels (int): Number of channels in the input image out_channels (int): Number of channels in the output image mid_channels (int): Channel number of intermediate features. Default: 64 texture_channels (int): Number of texture channels. Default: 64. num_blocks (tuple[int]): Block numbers in the trunk network. Default: (16, 16, 8, 4) res_scale (float): Used to scale the residual in residual block. Default: 1. init_cfg (dict, optional): Initialization config dict. """ def __init__(self, in_channels, out_channels, mid_channels=64, texture_channels=64, num_blocks=(16, 16, 8, 4), res_scale=1.0, init_cfg=None): super().__init__(init_cfg=init_cfg) self.texture_channels = texture_channels self.sfe = SFE(in_channels, mid_channels, num_blocks[0], res_scale) # stage 1 self.conv_first1 = _conv3x3_layer(4 * texture_channels + mid_channels, mid_channels) self.res_block1 = make_layer( ResidualBlockNoBN, num_blocks[1], mid_channels=mid_channels, res_scale=res_scale) self.conv_last1 = _conv3x3_layer(mid_channels, mid_channels) # up-sampling 1 -> 2 self.up1 = PixelShufflePack( in_channels=mid_channels, out_channels=mid_channels, scale_factor=2, upsample_kernel=3) # stage 2 self.conv_first2 = _conv3x3_layer(2 * texture_channels + mid_channels, mid_channels) self.csfi2 = CSFI2(mid_channels) self.res_block2_1 = make_layer( ResidualBlockNoBN, num_blocks[2], mid_channels=mid_channels, res_scale=res_scale) self.res_block2_2 = make_layer( ResidualBlockNoBN, num_blocks[2], mid_channels=mid_channels, res_scale=res_scale) self.conv_last2_1 = _conv3x3_layer(mid_channels, mid_channels) self.conv_last2_2 = _conv3x3_layer(mid_channels, mid_channels) # up-sampling 2 -> 3 self.up2 = PixelShufflePack( in_channels=mid_channels, out_channels=mid_channels, scale_factor=2, upsample_kernel=3) # stage 3 self.conv_first3 = _conv3x3_layer(texture_channels + mid_channels, mid_channels) self.csfi3 = CSFI3(mid_channels) self.res_block3_1 = make_layer( ResidualBlockNoBN, num_blocks[3], mid_channels=mid_channels, res_scale=res_scale) self.res_block3_2 = make_layer( ResidualBlockNoBN, num_blocks[3], mid_channels=mid_channels, res_scale=res_scale) self.res_block3_3 = make_layer( ResidualBlockNoBN, num_blocks[3], mid_channels=mid_channels, res_scale=res_scale) self.conv_last3_1 = _conv3x3_layer(mid_channels, mid_channels) self.conv_last3_2 = _conv3x3_layer(mid_channels, mid_channels) self.conv_last3_3 = _conv3x3_layer(mid_channels, mid_channels) # end, merge features self.merge_features = MergeFeatures(mid_channels, out_channels) def forward(self, x, soft_attention, textures): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). soft_attention (Tensor): Soft-Attention tensor with shape (n, 1, h, w). textures (Tuple[Tensor]): Transferred HR texture tensors. [(N, C, H, W), (N, C/2, 2H, 2W), ...] Returns: Tensor: Forward results. """ assert textures[-1].shape[1] == self.texture_channels x1 = self.sfe(x) # stage 1 x1_res = torch.cat((x1, textures[0]), dim=1) x1_res = self.conv_first1(x1_res) # soft-attention x1 = x1 + x1_res * soft_attention x1_res = self.res_block1(x1) x1_res = self.conv_last1(x1_res) x1 = x1 + x1_res # stage 2 x21 = x1 x22 = self.up1(x1) x22 = F.relu(x22) x22_res = torch.cat((x22, textures[1]), dim=1) x22_res = self.conv_first2(x22_res) # soft-attention x22_res = x22_res * F.interpolate( soft_attention, scale_factor=2, mode='bicubic', align_corners=False) x22 = x22 + x22_res x21_res, x22_res = self.csfi2(x21, x22) x21_res = self.res_block2_1(x21_res) x22_res = self.res_block2_2(x22_res) x21_res = self.conv_last2_1(x21_res) x22_res = self.conv_last2_2(x22_res) x21 = x21 + x21_res x22 = x22 + x22_res # stage 3 x31 = x21 x32 = x22 x33 = self.up2(x22) x33 = F.relu(x33) x33_res = torch.cat((x33, textures[2]), dim=1) x33_res = self.conv_first3(x33_res) # soft-attention x33_res = x33_res * F.interpolate( soft_attention, scale_factor=4, mode='bicubic', align_corners=False) x33 = x33 + x33_res x31_res, x32_res, x33_res = self.csfi3(x31, x32, x33) x31_res = self.res_block3_1(x31_res) x32_res = self.res_block3_2(x32_res) x33_res = self.res_block3_3(x33_res) x31_res = self.conv_last3_1(x31_res) x32_res = self.conv_last3_2(x32_res) x33_res = self.conv_last3_3(x33_res) x31 = x31 + x31_res x32 = x32 + x32_res x33 = x33 + x33_res x = self.merge_features(x31, x32, x33) return x class SFE(nn.Module): """Structural Feature Encoder. Backbone of Texture Transformer Network for Image Super-Resolution. Args: in_channels (int): Number of channels in the input image mid_channels (int): Channel number of intermediate features num_blocks (int): Block number in the trunk network res_scale (float): Used to scale the residual in residual block. Default: 1. """ def __init__(self, in_channels, mid_channels, num_blocks, res_scale): super().__init__() self.num_blocks = num_blocks self.conv_first = _conv3x3_layer(in_channels, mid_channels) self.body = make_layer( ResidualBlockNoBN, num_blocks, mid_channels=mid_channels, res_scale=res_scale) self.conv_last = _conv3x3_layer(mid_channels, mid_channels) def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x1 = x = F.relu(self.conv_first(x)) x = self.body(x) x = self.conv_last(x) x = x + x1 return x class CSFI2(nn.Module): """Cross-Scale Feature Integration between 1x and 2x features. Cross-Scale Feature Integration in Texture Transformer Network for Image Super-Resolution. It is cross-scale feature integration between 1x and 2x features. For example, `conv2to1` means conv layer from 2x feature to 1x feature. Down-sampling is achieved by conv layer with stride=2, and up-sampling is achieved by bicubic interpolate and conv layer. Args: mid_channels (int): Channel number of intermediate features """ def __init__(self, mid_channels): super().__init__() self.conv1to2 = _conv1x1_layer(mid_channels, mid_channels) self.conv2to1 = _conv3x3_layer(mid_channels, mid_channels, stride=2) self.conv_merge1 = _conv3x3_layer(mid_channels * 2, mid_channels) self.conv_merge2 = _conv3x3_layer(mid_channels * 2, mid_channels) def forward(self, x1, x2): """Forward function. Args: x1 (Tensor): Input tensor with shape (n, c, h, w). x2 (Tensor): Input tensor with shape (n, c, 2h, 2w). Returns: x1 (Tensor): Output tensor with shape (n, c, h, w). x2 (Tensor): Output tensor with shape (n, c, 2h, 2w). """ x12 = F.interpolate( x1, scale_factor=2, mode='bicubic', align_corners=False) x12 = F.relu(self.conv1to2(x12)) x21 = F.relu(self.conv2to1(x2)) x1 = F.relu(self.conv_merge1(torch.cat((x1, x21), dim=1))) x2 = F.relu(self.conv_merge2(torch.cat((x2, x12), dim=1))) return x1, x2 class CSFI3(nn.Module): """Cross-Scale Feature Integration between 1x, 2x, and 4x features. Cross-Scale Feature Integration in Texture Transformer Network for Image Super-Resolution. It is cross-scale feature integration between 1x and 2x features. For example, `conv2to1` means conv layer from 2x feature to 1x feature. Down-sampling is achieved by conv layer with stride=2, and up-sampling is achieved by bicubic interpolate and conv layer. Args: mid_channels (int): Channel number of intermediate features """ def __init__(self, mid_channels): super().__init__() self.conv1to2 = _conv1x1_layer(mid_channels, mid_channels) self.conv1to4 = _conv1x1_layer(mid_channels, mid_channels) self.conv2to1 = _conv3x3_layer(mid_channels, mid_channels, stride=2) self.conv2to4 = _conv1x1_layer(mid_channels, mid_channels) self.conv4to1_1 = _conv3x3_layer(mid_channels, mid_channels, stride=2) self.conv4to1_2 = _conv3x3_layer(mid_channels, mid_channels, stride=2) self.conv4to2 = _conv3x3_layer(mid_channels, mid_channels, stride=2) self.conv_merge1 = _conv3x3_layer(mid_channels * 3, mid_channels) self.conv_merge2 = _conv3x3_layer(mid_channels * 3, mid_channels) self.conv_merge4 = _conv3x3_layer(mid_channels * 3, mid_channels) def forward(self, x1, x2, x4): """Forward function. Args: x1 (Tensor): Input tensor with shape (n, c, h, w). x2 (Tensor): Input tensor with shape (n, c, 2h, 2w). x4 (Tensor): Input tensor with shape (n, c, 4h, 4w). Returns: x1 (Tensor): Output tensor with shape (n, c, h, w). x2 (Tensor): Output tensor with shape (n, c, 2h, 2w). x4 (Tensor): Output tensor with shape (n, c, 4h, 4w). """ x12 = F.interpolate( x1, scale_factor=2, mode='bicubic', align_corners=False) x12 = F.relu(self.conv1to2(x12)) x14 = F.interpolate( x1, scale_factor=4, mode='bicubic', align_corners=False) x14 = F.relu(self.conv1to4(x14)) x21 = F.relu(self.conv2to1(x2)) x24 = F.interpolate( x2, scale_factor=2, mode='bicubic', align_corners=False) x24 = F.relu(self.conv2to4(x24)) x41 = F.relu(self.conv4to1_1(x4)) x41 = F.relu(self.conv4to1_2(x41)) x42 = F.relu(self.conv4to2(x4)) x1 = F.relu(self.conv_merge1(torch.cat((x1, x21, x41), dim=1))) x2 = F.relu(self.conv_merge2(torch.cat((x2, x12, x42), dim=1))) x4 = F.relu(self.conv_merge4(torch.cat((x4, x14, x24), dim=1))) return x1, x2, x4 class MergeFeatures(nn.Module): """Merge Features. Merge 1x, 2x, and 4x features. Final module of Texture Transformer Network for Image Super-Resolution. Args: mid_channels (int): Channel number of intermediate features out_channels (int): Number of channels in the output image """ def __init__(self, mid_channels, out_channels): super().__init__() self.conv1to4 = _conv1x1_layer(mid_channels, mid_channels) self.conv2to4 = _conv1x1_layer(mid_channels, mid_channels) self.conv_merge = _conv3x3_layer(mid_channels * 3, mid_channels) self.conv_last1 = _conv3x3_layer(mid_channels, mid_channels // 2) self.conv_last2 = _conv1x1_layer(mid_channels // 2, out_channels) def forward(self, x1, x2, x4): """Forward function. Args: x1 (Tensor): Input tensor with shape (n, c, h, w). x2 (Tensor): Input tensor with shape (n, c, 2h, 2w). x4 (Tensor): Input tensor with shape (n, c, 4h, 4w). Returns: x (Tensor): Output tensor with shape (n, c_out, 4h, 4w). """ x14 = F.interpolate( x1, scale_factor=4, mode='bicubic', align_corners=False) x14 = F.relu(self.conv1to4(x14)) x24 = F.interpolate( x2, scale_factor=2, mode='bicubic', align_corners=False) x24 = F.relu(self.conv2to4(x24)) x = F.relu(self.conv_merge(torch.cat((x4, x14, x24), dim=1))) x = self.conv_last1(x) x = self.conv_last2(x) x = torch.clamp(x, -1, 1) return x ================================================ FILE: mmagic/models/editors/vico/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .vico import ViCo from .vico_utils import set_vico_modules __all__ = ['ViCo', 'set_vico_modules'] ================================================ FILE: mmagic/models/editors/vico/vico.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, List, Optional, Union import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from mmengine.runner import set_random_seed from PIL import Image from tqdm.auto import tqdm from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList from ..stable_diffusion.stable_diffusion import StableDiffusion from .vico_utils import set_vico_modules ModelType = Union[Dict, nn.Module] @MODELS.register_module() class ViCo(StableDiffusion): """Implementation of `ViCo with Stable Diffusion. `_ (ViCo). Args: vae (Union[dict, nn.Module]): The config or module for VAE model. text_encoder (Union[dict, nn.Module]): The config or module for text encoder. tokenizer (str): The **name** for CLIP tokenizer. unet (Union[dict, nn.Module]): The config or module for Unet model. schedule (Union[dict, nn.Module]): The config or module for diffusion scheduler. test_scheduler (Union[dict, nn.Module], optional): The config or module for diffusion scheduler in test stage (`self.infer`). If not passed, will use the same scheduler as `schedule`. Defaults to None. val_prompts (Union[str, List[str]], optional): The prompts for validation. Defaults to None. num_class_images (int, optional): The number of images for class prior. Defaults to 3. dtype (str, optional): The dtype for the model. Defaults to 'fp16'. enable_xformers (bool, optional): Whether to use xformers. Defaults to True. noise_offset_weight (bool, optional): The weight of noise offset introduced in https://www.crosslabs.org/blog/diffusion-with-offset-noise # noqa Defaults to 0. data_preprocessor (dict, optional): The pre-process config of :class:`BaseDataPreprocessor`. Defaults to dict(type='DataPreprocessor'). init_cfg (dict, optional): The weight initialized config for :class:`BaseModule`. Defaults to None/ image_cross_layers (List[int], optional): The layers to use image cross attention. Defaults to None. reg_loss_weight (float, optional): The weight of regularization loss. Defaults to 0. placeholder (str, optional): The placeholder token. Defaults to None. initialize_token (str, optional): The token to initialize the placeholder. Defaults to None. num_vectors_per_token (int, optional): The number of vectors per token. """ def __init__(self, vae: ModelType, text_encoder: ModelType, tokenizer: str, unet: ModelType, scheduler: ModelType, test_scheduler: Optional[ModelType] = None, val_prompts: Union[str, List[str]] = None, dtype: str = 'fp16', enable_xformers: bool = True, noise_offset_weight: float = 0, tomesd_cfg: Optional[dict] = None, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), init_cfg: Optional[dict] = None, image_cross_layers: List[int] = None, reg_loss_weight: float = 0, placeholder: str = None, initialize_token: str = None, num_vectors_per_token: int = 1): super().__init__(vae, text_encoder, tokenizer, unet, scheduler, test_scheduler, dtype, enable_xformers, noise_offset_weight, tomesd_cfg, data_preprocessor, init_cfg) self.reg_loss_weight = reg_loss_weight self.placeholder = placeholder self.dtype = torch.float32 if dtype == 'fp16': self.dtype = torch.float16 elif dtype == 'bf16': self.dtype = torch.bfloat16 else: assert dtype in [ 'fp32', None ], ('dtype must be one of \'fp32\', \'fp16\', \'bf16\' or None.') self.val_prompts = val_prompts self.add_tokens(placeholder, initialize_token, num_vectors_per_token) self.set_vico(image_cross_layers) self.prepare_models() def prepare_models(self): """Prepare model for training. Move model to target dtype and disable gradient for some models. """ """Disable gradient for untrainable modules to save memory.""" self.vae.requires_grad_(False) self.unet.requires_grad_(False) self.text_encoder.set_only_embedding_trainable() self.set_only_imca_trainable() def set_vico(self, have_image_cross_attention: List[int]): """Set ViCo for model.""" set_vico_modules(self.unet, have_image_cross_attention) def set_only_imca_trainable(self): """Set only image cross attention trainable.""" for _, layer in self.unet.named_modules(): if layer.__class__.__name__ == 'ViCoTransformer2D': if hasattr(layer, 'image_cross_attention'): layer.image_cross_attention.train() for name, param in ( layer.image_cross_attention.named_parameters()): param.requires_grad = True def add_tokens(self, placeholder_token: str, initialize_token: str = None, num_vectors_per_token: int = 1): """Add token for training. # TODO: support add tokens as dict, then we can load pretrained tokens. """ self.tokenizer.add_placeholder_token( placeholder_token, num_vec_per_token=num_vectors_per_token) self.text_encoder.set_embedding_layer() embedding_layer = self.text_encoder.get_embedding_layer() assert embedding_layer is not None, ( 'Do not support get embedding layer for current text encoder. ' 'Please check your configuration.') if initialize_token: init_id = self.tokenizer(initialize_token).input_ids[1] initialize_embedding = embedding_layer.weight[init_id] initialize_embedding = initialize_embedding[None, ...].repeat( num_vectors_per_token, 1) else: emb_dim = embedding_layer.weight.shape[1] initialize_embedding = torch.zeros(num_vectors_per_token, emb_dim) token_info = self.tokenizer.get_token_info(placeholder_token) token_info['embedding'] = initialize_embedding token_info['trainable'] = True self.token_info = token_info embedding_layer.add_embeddings(token_info) @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) image_reference = data['inputs']['img_ref'] data_samples = data['data_samples'] if self.val_prompts is None: prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples.split() * len(prompt) data_samples = DataSample.stack(data_samples.split() * len(prompt)) output = self.infer(prompt, image_reference, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor`` and ``self.infer`` in order. Return the generated results which will be passed to evaluator or visualizer. Args: data (dict or tuple or list): Data sampled from dataset. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) image_reference = data['inputs']['img_ref'] data_samples = data['data_samples'] if self.val_prompts is None: prompt = data_samples.prompt else: prompt = self.val_prompts # construct a fake data_sample for destruct data_samples.split() * len(prompt) data_samples = DataSample.stack(data_samples.split() * len(prompt)) output = self.infer(prompt, image_reference, return_type='tensor') samples = output['samples'] samples = self.data_preprocessor.destruct(samples, data_samples) out_data_sample = DataSample(fake_img=samples, prompt=prompt) data_sample_list = out_data_sample.split() return data_sample_list def prepare_reference(self, image_ref: Union[Image.Image, torch.Tensor], height: Optional[int] = 512, width: Optional[int] = 512): if isinstance(image_ref, Image.Image): if not image_ref.mode == 'RGB': image_ref = image_ref.convert('RGB') img = np.array(image_ref).astype(np.uint8) image_ref = Image.fromarray(img) image_ref = image_ref.resize((height, width), resample=Image.BILINEAR) image_ref = np.array(image_ref).astype(np.uint8) image_ref = (image_ref / 127.5 - 1.0).astype(np.float32) image_ref = torch.from_numpy(image_ref).permute(2, 0, 1).unsqueeze(0) return image_ref def train_step(self, data, optim_wrapper): """Training step.""" data = self.data_preprocessor(data) inputs, data_samples = data['inputs'], data['data_samples'] with optim_wrapper.optim_context(self.unet): image = inputs['img'] # image for new concept num_batches = image.shape[0] image_ref = inputs['img_ref'] # cat image and image reference to avoid forward twice image = torch.cat([image, image_ref], dim=0) prompt_init = data_samples.prompt placeholder_string = self.placeholder image = image.to(self.dtype) latents = self.vae.encode(image).latent_dist.sample() latents = latents * self.vae.config.scaling_factor noise = torch.randn_like(latents[:num_batches, ...]) timesteps = torch.randint( 0, self.scheduler.num_train_timesteps, (num_batches, ), device=self.device) timesteps = timesteps.long() # image reference shares the same timesteps # only add noise to source image noisy_latents = self.scheduler.add_noise( latents[:num_batches, ...], noise, timesteps) noisy_latents = torch.cat( [noisy_latents, latents[num_batches:, ...]], dim=0) timesteps = torch.cat([timesteps, timesteps]) input_ids = self.tokenizer( prompt_init, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) ph_tokens = self.tokenizer( [placeholder_string], max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'].to(self.device) ph_tok = ph_tokens[0, 1] placeholder_idx = torch.where(input_ids == ph_tok) clip_eot_token_id = self.tokenizer.encode( self.tokenizer.eos_token)['input_ids'][1] endoftext_idx = (torch.arange(input_ids.shape[0]), (input_ids == clip_eot_token_id).nonzero( as_tuple=False)[0, 1]) placeholder_position = [placeholder_idx, endoftext_idx] encoder_hidden_states = self.text_encoder(input_ids)[0] encoder_hidden_states = torch.cat( [encoder_hidden_states, encoder_hidden_states], dim=0) if self.scheduler.config.prediction_type == 'epsilon': gt = noise elif self.scheduler.config.prediction_type == 'v_prediction': gt = self.scheduler.get_velocity(latents, noise, timesteps) else: raise ValueError('Unknown prediction type ' f'{self.scheduler.config.prediction_type}') # NOTE: we train unet in fp32, convert to float manually model_output = self.unet( noisy_latents.float(), timesteps, encoder_hidden_states=encoder_hidden_states.float(), placeholder_position=placeholder_position) model_pred = model_output['sample'] loss_reg = model_output['loss_reg'] loss_dict = dict() if loss_reg != 0: loss_dict['loss_reg'] = loss_reg * self.reg_loss_weight vico_loss = F.mse_loss(model_pred[:1].float(), gt.float()) loss_dict['vico_loss'] = vico_loss parsed_loss, log_vars = self.parse_losses(loss_dict) optim_wrapper.update_params(parsed_loss) return log_vars @torch.no_grad() def infer(self, prompt: Union[str, List[str]], image_reference: Image.Image = None, height: Optional[int] = None, width: Optional[int] = None, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_prompt: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, show_progress=True, seed=1, return_type='image'): """Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`): The prompt or prompts to guide the image generation. height (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The height in pixels of the generated image. width (`int`, *optional*, defaults to self.unet_sample_size * self.vae_scale_factor): The width in pixels of the generated image. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance] (https://arxiv.org/abs/2207.12598). negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator`, *optional*): A [torch generator] to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. return_type (str): The return type of the inference results. Supported types are 'image', 'numpy', 'tensor'. If 'image' is passed, a list of PIL images will be returned. If 'numpy' is passed, a numpy array with shape [N, C, H, W] will be returned, and the value range will be same as decoder's output range. If 'tensor' is passed, the decoder's output will be returned. Defaults to 'image'. Returns: dict: A dict containing the generated images. """ assert return_type in ['image', 'tensor', 'numpy'] set_random_seed(seed=seed) # 0. Default height and width to unet height = height or self.unet_sample_size * self.vae_scale_factor width = width or self.unet_sample_size * self.vae_scale_factor # 1. Check inputs. Raise error if not correct self.check_inputs(prompt, height, width) # 2. Define call parameters batch_size = 1 if isinstance(prompt, str) else len(prompt) device = self.device img_dtype = self.vae.module.dtype if hasattr(self.vae, 'module') \ else self.vae.dtype latent_dtype = next(self.unet.parameters()).dtype # here `guidance_scale` is defined analog to the # guidance weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt text_embeddings = self._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt) uncond_embeddings, text_embeddings = text_embeddings.chunk(2) uncond_embeddings = torch.cat([uncond_embeddings] * 2) text_embeddings = torch.cat([text_embeddings] * 2) ph_tokens = self.tokenizer( num_images_per_prompt * [self.placeholder], max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'] input_ids = self.tokenizer( num_images_per_prompt * prompt, max_length=self.tokenizer.model_max_length, return_tensors='pt', padding='max_length', truncation=True)['input_ids'] ph_tok = ph_tokens[0, 1] # TODO fix hard code clip_eot_token_id = 49407 endoftext_idx = (torch.arange(input_ids.shape[0]), torch.nonzero(input_ids == clip_eot_token_id) [:batch_size, 1].repeat(num_images_per_prompt)) placeholder_idx = torch.where(input_ids == ph_tok) if self.placeholder in prompt[0]: ph_pos = [placeholder_idx, endoftext_idx] else: ph_pos = [endoftext_idx, endoftext_idx] # 4. Prepare timesteps self.test_scheduler.set_timesteps(num_inference_steps) timesteps = self.test_scheduler.timesteps # 5. Prepare latent variables if hasattr(self.unet, 'module'): num_channels_latents = self.unet.module.in_channels else: num_channels_latents = self.unet.in_channels latents = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, text_embeddings.dtype, device, generator, latents, ) image_reference = self.prepare_reference( image_reference, height, width, ) image_reference = self.vae.encode( image_reference.to(dtype=img_dtype, device=device)).latent_dist.sample() image_reference = image_reference.expand( batch_size * num_images_per_prompt, -1, -1, -1) image_reference = image_reference * self.vae.config.scaling_factor # 6. Prepare extra step kwargs. # TODO: Logic should ideally just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7. Denoising loop if show_progress: timesteps = tqdm(timesteps) for i, t in enumerate(timesteps): latents = torch.cat([latents, image_reference], dim=0) latent_model_input = self.test_scheduler.scale_model_input( latents, t) latent_model_input = latent_model_input.to(latent_dtype) text_embeddings = text_embeddings.to(latent_dtype) uncond_embeddings = uncond_embeddings.to(latent_dtype) # predict the noise residual noise_pred_uncond = self.unet( latent_model_input, t, encoder_hidden_states=uncond_embeddings, placeholder_position=ph_pos)['sample'][:batch_size * num_images_per_prompt] noise_pred_text = self.unet( latent_model_input, t, encoder_hidden_states=text_embeddings, placeholder_position=ph_pos)['sample'][:batch_size * num_images_per_prompt] # perform guidance if do_classifier_free_guidance: noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents_to_denoise = latents[:batch_size * num_images_per_prompt, ...] latents = self.test_scheduler.step( noise_pred, t, latents_to_denoise, **extra_step_kwargs)['prev_sample'] # 8. Post-processing image = self.decode_latents(latents.to(img_dtype)) if return_type == 'image': image = self.output_to_pil(image) elif return_type == 'numpy': image = image.cpu().numpy() else: assert return_type == 'tensor', ( 'Only support \'image\', \'numpy\' and \'tensor\' for ' f'return_type, but receive {return_type}') return {'samples': image} def forward(self, inputs: torch.Tensor, data_samples: Optional[list] = None, mode: str = 'tensor') -> Union[Dict[str, torch.Tensor], list]: """forward is not implemented now.""" raise NotImplementedError( 'Forward is not implemented now, please use infer.') ================================================ FILE: mmagic/models/editors/vico/vico_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from dataclasses import dataclass from typing import Any, Dict, List, Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F from diffusers import Transformer2DModel from diffusers.models.attention import Attention, BasicTransformerBlock from diffusers.models.unet_2d_condition import UNet2DConditionOutput from diffusers.utils import BaseOutput, is_torch_version class ViCoCrossAttnProcessor: """Processor for implementing attention for the ViCo method.""" def __call__(self, attn: Attention, hidden_states, encoder_hidden_states=None, attention_mask=None): """ Args: attn (Attention): Attention module. hidden_states (torch.Tensor): Input hidden states. encoder_hidden_states (torch.Tensor): Encoder hidden states. attention_mask (torch.Tensor): Attention mask. Returns: torch.Tensor: Output hidden states. """ batch_size, sequence_length, _ = hidden_states.shape attention_mask = attn.prepare_attention_mask( attention_mask, sequence_length, batch_size=batch_size) query = attn.to_q(hidden_states) encoder_hidden_states = encoder_hidden_states \ if encoder_hidden_states is not None else hidden_states key = attn.to_k(encoder_hidden_states) value = attn.to_v(encoder_hidden_states) query = attn.head_to_batch_dim(query) key = attn.head_to_batch_dim(key) value = attn.head_to_batch_dim(value) attention_probs = attn.get_attention_scores(query, key, attention_mask) # new bookkeeping to save the attn probs attn.attn_probs = attention_probs hidden_states = torch.bmm(attention_probs, value) hidden_states = attn.batch_to_head_dim(hidden_states) # linear proj hidden_states = attn.to_out[0](hidden_states) # dropout hidden_states = attn.to_out[1](hidden_states) return hidden_states def replace_cross_attention(unet): """Replace Cross Attention processor in UNet.""" for name, module in unet.named_modules(): name: str if name.endswith('attn2'): module.set_processor(ViCoCrossAttnProcessor()) @dataclass class ViCoTransformer2DModelOutput(BaseOutput): """Output for ViCoTransformer2DModel.""" sample: torch.FloatTensor loss_reg: torch.FloatTensor def otsu(mask_in): """Apply otsu for mask. Args: mask_in (torch.Tensor): Input mask. """ # normalize mask_norm = (mask_in - mask_in.min(-1, keepdim=True)[0]) / \ (mask_in.max(-1, keepdim=True)[0] - mask_in.min(-1, keepdim=True)[0]) bs = mask_in.shape[0] h = mask_in.shape[1] mask = [] for i in range(bs): threshold_t = 0. max_g = 0. for t in range(10): mask_i = mask_norm[i] low = mask_i[mask_i < t * 0.1] high = mask_i[mask_i >= t * 0.1] low_num = low.shape[0] / h high_num = high.shape[0] / h low_mean = low.mean() high_mean = high.mean() g = low_num * high_num * ((low_mean - high_mean)**2) if g > max_g: max_g = g threshold_t = t * 0.1 mask_i[mask_i < threshold_t] = 0 mask_i[mask_i > threshold_t] = 1 mask.append(mask_i) mask_out = torch.stack(mask, dim=0) return mask_out class ViCoTransformer2D(nn.Module): """New ViCo-Transformer2D to replace the original Transformer2D model.""" def __init__(self, org_transformer2d: Transformer2DModel, have_image_cross) -> None: """ Args: org_transformer2d (Transformer2DModel): Original Transformer2DModel. have_image_cross (bool): Flag indicating if the model has image_cross_attention modules. """ super().__init__() self.transformer_blocks = org_transformer2d.transformer_blocks self.is_input_continuous = org_transformer2d.is_input_continuous self.norm = org_transformer2d.norm self.use_linear_projection = org_transformer2d.use_linear_projection self.proj_in = org_transformer2d.proj_in self.proj_out = org_transformer2d.proj_out self.is_input_vectorized = org_transformer2d.is_input_vectorized self.is_input_patches = org_transformer2d.is_input_patches num_attention_heads = org_transformer2d.num_attention_heads attention_head_dim = org_transformer2d.attention_head_dim inner_dim = num_attention_heads * attention_head_dim self.have_image_cross = have_image_cross if self.have_image_cross: image_cross_attention = BasicTransformerBlock( inner_dim, num_attention_heads, attention_head_dim, cross_attention_dim=inner_dim) self.image_cross_attention = image_cross_attention.to( org_transformer2d.device, dtype=org_transformer2d.dtype) def forward( self, hidden_states: torch.Tensor, encoder_hidden_states: Optional[torch.Tensor] = None, timestep: Optional[torch.LongTensor] = None, placeholder_position: list = None, class_labels: Optional[torch.LongTensor] = None, cross_attention_kwargs: Dict[str, Any] = None, attention_mask: Optional[torch.Tensor] = None, encoder_attention_mask: Optional[torch.Tensor] = None, return_dict: bool = True, ): if attention_mask is not None and attention_mask.ndim == 2: # assume that mask is expressed as: # (1 = keep, 0 = discard) # convert mask into a bias that can be added to attention scores: # (keep = +0, discard = -10000.0) attention_mask = ( 1 - attention_mask.to(hidden_states.dtype)) * -10000.0 attention_mask = attention_mask.unsqueeze(1) if encoder_attention_mask is not None and (encoder_attention_mask.ndim == 2): encoder_attention_mask = ( 1 - encoder_attention_mask.to(hidden_states.dtype)) * -10000.0 encoder_attention_mask = encoder_attention_mask.unsqueeze(1) # 1. Input if self.is_input_continuous: batch, _, height, width = hidden_states.shape residual = hidden_states hidden_states = self.norm(hidden_states) if not self.use_linear_projection: hidden_states = self.proj_in(hidden_states) inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * width, inner_dim) else: inner_dim = hidden_states.shape[1] hidden_states = hidden_states.permute(0, 2, 3, 1).reshape( batch, height * width, inner_dim) hidden_states = self.proj_in(hidden_states) elif self.is_input_vectorized: hidden_states = self.latent_image_embedding(hidden_states) elif self.is_input_patches: hidden_states = self.pos_embed(hidden_states) # 2. Blocks for block in self.transformer_blocks: hidden_states = block( hidden_states, attention_mask=attention_mask, encoder_hidden_states=encoder_hidden_states, encoder_attention_mask=encoder_attention_mask, timestep=timestep, cross_attention_kwargs=cross_attention_kwargs, class_labels=class_labels, ) attention_probs = block.attn2.attn_probs[batch // 2:batch, ...] loss_reg = None if self.have_image_cross: # 2.5. image cross attention ph_idx, eot_idx = placeholder_position[ 0], placeholder_position[1] attn = attention_probs.transpose(1, 2) attn_ph = attn[ph_idx].squeeze(1) # bs, n_patch attn_eot = attn[eot_idx].squeeze(1).detach() # ######################## # attention reg if self.image_cross_attention.training: loss_reg = F.mse_loss( attn_ph / attn_ph.max(-1, keepdim=True)[0], attn_eot / attn_eot.max(-1, keepdim=True)[0]) # ######################## mask = attn_ph.detach() mask = otsu(mask) if mask.dim() == 2: mask = mask.unsqueeze(1) hidden_states, image_reference = hidden_states[:batch // 2], \ hidden_states[batch // 2:] hidden_states = self.image_cross_attention( hidden_states, attention_mask=attention_mask, encoder_hidden_states=image_reference, encoder_attention_mask=mask, timestep=timestep, cross_attention_kwargs=cross_attention_kwargs, class_labels=class_labels, ) hidden_states = torch.cat([hidden_states, image_reference], dim=0) # 3. Output if self.is_input_continuous: if not self.use_linear_projection: hidden_states = hidden_states.reshape(batch, height, width, inner_dim).permute( 0, 3, 1, 2).contiguous() hidden_states = self.proj_out(hidden_states) else: hidden_states = self.proj_out(hidden_states) hidden_states = hidden_states.reshape(batch, height, width, inner_dim).permute( 0, 3, 1, 2).contiguous() output = hidden_states + residual elif self.is_input_vectorized: hidden_states = self.norm_out(hidden_states) logits = self.out(hidden_states) # (batch, self.num_vector_embeds - 1, self.num_latent_pixels) logits = logits.permute(0, 2, 1) # log(p(x_0)) output = F.log_softmax(logits.double(), dim=1).float() elif self.is_input_patches: # TODO: cleanup! conditioning = self.transformer_blocks[0].norm1.emb( timestep, class_labels, hidden_dtype=hidden_states.dtype) shift, scale = self.proj_out_1(F.silu(conditioning)).chunk( 2, dim=1) hidden_states = self.norm_out(hidden_states) * ( 1 + scale[:, None]) + shift[:, None] hidden_states = self.proj_out_2(hidden_states) # unpatchify height = width = int(hidden_states.shape[1]**0.5) hidden_states = hidden_states.reshape( shape=(-1, height, width, self.patch_size, self.patch_size, self.out_channels)) hidden_states = torch.einsum('nhwpqc->nchpwq', hidden_states) output = hidden_states.reshape( shape=(-1, self.out_channels, height * self.patch_size, width * self.patch_size)) if not return_dict: return (output, loss_reg) return ViCoTransformer2DModelOutput(sample=output, loss_reg=loss_reg) def replace_transformer2d(module: nn.Module, have_image_cross: Dict[str, List[bool]]): """Replace the the Transformer2DModel in UNet. Args: module (nn.Module): Parent module of Transformer2D. have_image_cross (List): List of flag indicating which transformer2D modules have image_cross_attention modules. """ down_transformer2d_modules = [(k.rsplit('.', 1), v) for k, v in module.named_modules() if isinstance(v, Transformer2DModel)] for i, ((parent, k), v) in enumerate(down_transformer2d_modules): parent = module.get_submodule(parent) setattr(parent, k, ViCoTransformer2D(v, have_image_cross[i])) class ViCoBlockWrapper(nn.Module): """Wrapper for ViCo blocks.""" def apply_to(self, org_module): self.org_module = org_module self.org_module.forward = self.forward class ViCoCrossAttnDownBlock2D(ViCoBlockWrapper): def forward( self, hidden_states: torch.FloatTensor, temb: Optional[torch.FloatTensor] = None, encoder_hidden_states: Optional[torch.FloatTensor] = None, placeholder_position: torch.Tensor = None, attention_mask: Optional[torch.FloatTensor] = None, cross_attention_kwargs: Optional[Dict[str, Any]] = None, encoder_attention_mask: Optional[torch.FloatTensor] = None, ): """ Args: hidden_states (torch.FloatTensor): Hidden states. temb (Optional[torch.FloatTensor]): Time embedding. encoder_hidden_states (Optional[torch.FloatTensor]): Encoder hidden states. placeholder_position (torch.Tensor): Placeholder position. attention_mask (Optional[torch.FloatTensor]): Attention mask. cross_attention_kwargs (Optional[Dict[str, Any]]): Cross attention keyword arguments. encoder_attention_mask (Optional[torch.FloatTensor]): Encoder attention mask. Returns: torch.FloatTensor: Output hidden states. Tuple[torch.FloatTensor]: Output hidden states of each block. torch.FloatTensor: Attention regularization loss. """ output_states = () loss_reg_all = 0.0 for resnet, attn in zip(self.org_module.resnets, self.org_module.attentions): attn: ViCoTransformer2D if self.org_module.training and ( self.org_module.gradient_checkpointing): def create_custom_forward(module, return_dict=None): def custom_forward(*inputs): if return_dict is not None: return module(*inputs, return_dict=return_dict) else: return module(*inputs) return custom_forward ckpt_kwargs: Dict[str, Any] = { 'use_reentrant': False } if is_torch_version('>=', '1.11.0') else {} hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb, **ckpt_kwargs, ) hidden_states, loss_reg = torch.utils.checkpoint.checkpoint( create_custom_forward(attn, return_dict=False), hidden_states, encoder_hidden_states, None, # timestep placeholder_position, None, # class_labels cross_attention_kwargs, attention_mask, encoder_attention_mask, **ckpt_kwargs, ) else: hidden_states = resnet(hidden_states, temb) hidden_states, loss_reg = attn( hidden_states, encoder_hidden_states=encoder_hidden_states, placeholder_position=placeholder_position, cross_attention_kwargs=cross_attention_kwargs, attention_mask=attention_mask, encoder_attention_mask=encoder_attention_mask, return_dict=False, ) output_states = output_states + (hidden_states, ) if loss_reg is not None: loss_reg_all += loss_reg if self.org_module.downsamplers is not None: for downsampler in self.org_module.downsamplers: hidden_states = downsampler(hidden_states) output_states = output_states + (hidden_states, ) return hidden_states, output_states, loss_reg_all class ViCoUNetMidBlock2DCrossAttn(ViCoBlockWrapper): def forward( self, hidden_states: torch.FloatTensor, temb: Optional[torch.FloatTensor] = None, encoder_hidden_states: Optional[torch.FloatTensor] = None, placeholder_position: torch.Tensor = None, attention_mask: Optional[torch.FloatTensor] = None, cross_attention_kwargs: Optional[Dict[str, Any]] = None, encoder_attention_mask: Optional[torch.FloatTensor] = None, ) -> torch.FloatTensor: """ Args: hidden_states (torch.FloatTensor): Hidden states. temb (Optional[torch.FloatTensor]): Time embedding. encoder_hidden_states (Optional[torch.FloatTensor]): Encoder hidden states. placeholder_position (torch.Tensor): Placeholder position. attention_mask (Optional[torch.FloatTensor]): Attention mask. cross_attention_kwargs (Optional[Dict[str, Any]]): Cross attention keyword arguments. encoder_attention_mask (Optional[torch.FloatTensor]): Encoder attention mask. Returns: torch.FloatTensor: Output hidden states. torch.FloatTensor: Attention regularization loss. """ loss_reg_all = 0.0 hidden_states = self.org_module.resnets[0](hidden_states, temb) for attn, resnet in zip(self.org_module.attentions, self.org_module.resnets[1:]): hidden_states, loss_reg = attn( hidden_states, encoder_hidden_states=encoder_hidden_states, placeholder_position=placeholder_position, cross_attention_kwargs=cross_attention_kwargs, attention_mask=attention_mask, encoder_attention_mask=encoder_attention_mask, return_dict=False, ) hidden_states = resnet(hidden_states, temb) if loss_reg is not None: loss_reg_all += loss_reg return hidden_states, loss_reg_all class ViCoCrossAttnUpBlock2D(ViCoBlockWrapper): def forward( self, hidden_states: torch.FloatTensor, res_hidden_states_tuple: Tuple[torch.FloatTensor, ...], temb: Optional[torch.FloatTensor] = None, encoder_hidden_states: Optional[torch.FloatTensor] = None, placeholder_position: torch.Tensor = None, cross_attention_kwargs: Optional[Dict[str, Any]] = None, upsample_size: Optional[int] = None, attention_mask: Optional[torch.FloatTensor] = None, encoder_attention_mask: Optional[torch.FloatTensor] = None, ): """Performs the forward pass through the ViCoCrossAttnUpBlock2D module. Args: hidden_states (torch.FloatTensor): Input hidden states. res_hidden_states_tuple (Tuple[torch.FloatTensor, ...]): Tuple of residual hidden states. temb (Optional[torch.FloatTensor], optional): Temporal embeddings. Defaults to None. encoder_hidden_states (Optional[torch.FloatTensor], optional): Encoder hidden states. Defaults to None. placeholder_position (torch.Tensor, optional): Placeholder positions. Defaults to None. cross_attention_kwargs (Optional[Dict[str, Any]], optional): Keyword arguments for cross-attention. Defaults to None. upsample_size (Optional[int], optional): Upsample size. attention_mask (Optional[torch.FloatTensor], optional): Attention mask. encoder_attention_mask (Optional[torch.FloatTensor], optional): Encoder attention mask. Returns: Tuple[torch.FloatTensor, torch.FloatTensor]: A tuple containing the output hidden states and the total regularization loss. """ loss_reg_all = 0.0 for resnet, attn in zip(self.org_module.resnets, self.org_module.attentions): attn: ViCoTransformer2D # pop res hidden states res_hidden_states = res_hidden_states_tuple[-1] res_hidden_states_tuple = res_hidden_states_tuple[:-1] hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) if self.org_module.training and ( self.org_module.gradient_checkpointing): def create_custom_forward(module, return_dict=None): def custom_forward(*inputs): if return_dict is not None: return module(*inputs, return_dict=return_dict) else: return module(*inputs) return custom_forward ckpt_kwargs: Dict[str, Any] = { 'use_reentrant': False } if is_torch_version('>=', '1.11.0') else {} hidden_states = torch.utils.checkpoint.checkpoint( create_custom_forward(resnet), hidden_states, temb, **ckpt_kwargs, ) hidden_states, loss_reg = torch.utils.checkpoint.checkpoint( create_custom_forward(attn, return_dict=False), hidden_states, encoder_hidden_states, None, # timestep placeholder_position, None, # class_labels cross_attention_kwargs, attention_mask, encoder_attention_mask, **ckpt_kwargs, ) else: hidden_states = resnet(hidden_states, temb) hidden_states, loss_reg = attn( hidden_states, encoder_hidden_states=encoder_hidden_states, placeholder_position=placeholder_position, cross_attention_kwargs=cross_attention_kwargs, attention_mask=attention_mask, encoder_attention_mask=encoder_attention_mask, return_dict=False, ) if loss_reg is not None: loss_reg_all += loss_reg if self.org_module.upsamplers is not None: for upsampler in self.org_module.upsamplers: hidden_states = upsampler(hidden_states, upsample_size) return hidden_states, loss_reg_all class ViCoUNet2DConditionOutput(BaseOutput): """Output for ViCoUNet2DConditionModel.""" sample: torch.FloatTensor loss_reg: torch.FloatTensor class ViCoUNet2DConditionModel(ViCoBlockWrapper): """UNet2DConditionModel for ViCo Method.""" def forward( self, sample: torch.FloatTensor, timestep: Union[torch.Tensor, float, int], encoder_hidden_states: torch.Tensor, placeholder_position: torch.Tensor, class_labels: Optional[torch.Tensor] = None, timestep_cond: Optional[torch.Tensor] = None, attention_mask: Optional[torch.Tensor] = None, cross_attention_kwargs: Optional[Dict[str, Any]] = None, added_cond_kwargs: Optional[Dict[str, torch.Tensor]] = None, down_block_additional_residuals: Optional[Tuple[torch.Tensor]] = None, mid_block_additional_residual: Optional[torch.Tensor] = None, encoder_attention_mask: Optional[torch.Tensor] = None, return_dict: bool = True, ) -> Union[UNet2DConditionOutput, Tuple]: """Performs the forward pass through the ViCoBlock2D module. Args: sample (torch.FloatTensor): Input sample. timestep (Union[torch.Tensor, float, int]): Timestep value. encoder_hidden_states (torch.Tensor): Encoder hidden states. placeholder_position (torch.Tensor): Placeholder positions. class_labels (Optional[torch.Tensor], optional): Class labels. Defaults to None. timestep_cond (Optional[torch.Tensor], optional): Timestep condition. Defaults to None. attention_mask (Optional[torch.Tensor], optional): Attention mask. Defaults to None. cross_attention_kwargs (Optional[Dict[str, Any]], optional): Keyword arguments for cross-attention. Defaults to None. added_cond_kwargs (Optional[Dict[str, torch.Tensor]], optional): Additional condition arguments. Defaults to None. down_block_additional_residuals (Optional[Tuple[torch.Tensor]], optional): Additional residuals for down-blocks. Defaults to None. mid_block_additional_residual (Optional[torch.Tensor], optional): Additional residual for mid-block. Defaults to None. encoder_attention_mask (Optional[torch.Tensor], optional): Encoder attention mask. Defaults to None. return_dict (bool, optional): Whether to return a dictionary or a tuple. Returns: Union[UNet2DConditionOutput, Tuple]: The output of the forward pass, which can be either a UNet2DConditionOutput object or a tuple of tensors. """ default_overall_up_factor = 2**self.org_module.num_upsamplers forward_upsample_size = False upsample_size = None if any(s % default_overall_up_factor != 0 for s in sample.shape[-2:]): forward_upsample_size = True if attention_mask is not None: # assume that mask is expressed as: # (1 = keep, 0 = discard) # convert mask into a bias that can be added to attention scores: # (keep = +0, discard = -10000.0) attention_mask = (1 - attention_mask.to(sample.dtype)) * -10000.0 attention_mask = attention_mask.unsqueeze(1) if encoder_attention_mask is not None: encoder_attention_mask = ( 1 - encoder_attention_mask.to(sample.dtype)) * -10000.0 encoder_attention_mask = encoder_attention_mask.unsqueeze(1) # 0. center input if necessary if self.org_module.config.center_input_sample: sample = 2 * sample - 1.0 # 1. time timesteps = timestep if not torch.is_tensor(timesteps): is_mps = sample.device.type == 'mps' if isinstance(timestep, float): dtype = torch.float32 if is_mps else torch.float64 else: dtype = torch.int32 if is_mps else torch.int64 timesteps = torch.tensor([timesteps], dtype=dtype, device=sample.device) elif len(timesteps.shape) == 0: timesteps = timesteps[None].to(sample.device) t_emb = self.org_module.time_proj(timesteps) t_emb = t_emb.to(dtype=sample.dtype) emb = self.org_module.time_embedding(t_emb, timestep_cond) if self.org_module.class_embedding is not None: if class_labels is None: raise ValueError('class_labels should be provided \ when num_class_embeds > 0') if self.org_module.config.class_embed_type == 'timestep': class_labels = self.org_module.time_proj(class_labels) class_labels = class_labels.to(dtype=sample.dtype) class_emb = self.org_module.class_embedding(class_labels).to( dtype=sample.dtype) if self.org_module.config.class_embeddings_concat: emb = torch.cat([emb, class_emb], dim=-1) else: emb = emb + class_emb if self.org_module.config.addition_embed_type == 'text': aug_emb = self.org_module.add_embedding(encoder_hidden_states) emb = emb + aug_emb elif self.org_module.config.addition_embed_type == 'text_image': # Kadinsky 2.1 - style if 'image_embeds' not in added_cond_kwargs: raise ValueError( f"{self.org_module.__class__} has the config param \ `addition_embed_type` set to 'text_image' which \ requires the keyword argument `image_embeds` \ to be passed in `added_cond_kwargs`") image_embs = added_cond_kwargs.get('image_embeds') text_embs = added_cond_kwargs.get('text_embeds', encoder_hidden_states) aug_emb = self.org_module.add_embedding(text_embs, image_embs) emb = emb + aug_emb if self.org_module.time_embed_act is not None: emb = self.org_module.time_embed_act(emb) if self.org_module.encoder_hid_proj is not None and ( self.org_module.config.encoder_hid_dim_type == 'text_proj'): encoder_hidden_states = self.org_module.encoder_hid_proj( encoder_hidden_states) elif self.org_module.encoder_hid_proj is not None and ( self.org_module.config.encoder_hid_dim_type == 'text_image_proj'): # Kadinsky 2.1 - style if 'image_embeds' not in added_cond_kwargs: raise ValueError( f"{self.org_module.__class__} has the config param \ `encoder_hid_dim_type` set to 'text_image_proj' which \ requires the keyword argument `image_embeds` to be \ passed in `added_conditions`") image_embeds = added_cond_kwargs.get('image_embeds') encoder_hidden_states = self.org_module.encoder_hid_proj( encoder_hidden_states, image_embeds) # 2. pre-process sample = self.org_module.conv_in(sample) loss_reg_all = 0.0 if self.training else None # 3. down down_block_res_samples = (sample, ) for downsample_block in self.org_module.down_blocks: if hasattr(downsample_block, 'has_cross_attention' ) and downsample_block.has_cross_attention: sample, res_samples, loss_reg = downsample_block( hidden_states=sample, temb=emb, encoder_hidden_states=encoder_hidden_states, placeholder_position=placeholder_position, attention_mask=attention_mask, cross_attention_kwargs=cross_attention_kwargs, encoder_attention_mask=encoder_attention_mask, ) if self.training: loss_reg_all += loss_reg else: sample, res_samples = downsample_block( hidden_states=sample, temb=emb) down_block_res_samples += res_samples if down_block_additional_residuals is not None: new_down_block_res_samples = () for down_block_res_sample, down_block_additional_residual in zip( down_block_res_samples, down_block_additional_residuals): down_block_res_sample = down_block_res_sample + \ down_block_additional_residual new_down_block_res_samples = new_down_block_res_samples + ( down_block_res_sample, ) down_block_res_samples = new_down_block_res_samples # 4. mid if self.org_module.mid_block is not None: sample, loss_reg = self.org_module.mid_block( sample, emb, encoder_hidden_states=encoder_hidden_states, attention_mask=attention_mask, cross_attention_kwargs=cross_attention_kwargs, encoder_attention_mask=encoder_attention_mask, ) if self.training: loss_reg_all += loss_reg if mid_block_additional_residual is not None: sample = sample + mid_block_additional_residual # 5. up for i, upsample_block in enumerate(self.org_module.up_blocks): is_final_block = i == len(self.org_module.up_blocks) - 1 res_samples = down_block_res_samples[-len(upsample_block.resnets):] down_block_res_samples = down_block_res_samples[:-len( upsample_block.resnets)] # if we have not reached the final block and need to forward the # upsample size, we do it here if not is_final_block and forward_upsample_size: upsample_size = down_block_res_samples[-1].shape[2:] if hasattr(upsample_block, 'has_cross_attention' ) and upsample_block.has_cross_attention: sample, loss_reg = upsample_block( hidden_states=sample, temb=emb, res_hidden_states_tuple=res_samples, encoder_hidden_states=encoder_hidden_states, placeholder_position=placeholder_position, cross_attention_kwargs=cross_attention_kwargs, upsample_size=upsample_size, attention_mask=attention_mask, encoder_attention_mask=encoder_attention_mask, ) if self.training: loss_reg_all += loss_reg else: sample = upsample_block( hidden_states=sample, temb=emb, res_hidden_states_tuple=res_samples, upsample_size=upsample_size) # 6. post-process if self.org_module.conv_norm_out: sample = self.org_module.conv_norm_out(sample) sample = self.org_module.conv_act(sample) sample = self.org_module.conv_out(sample) if not return_dict: return (sample, loss_reg_all) return ViCoUNet2DConditionOutput(sample=sample, loss_reg=loss_reg_all) def set_vico_modules(unet, image_cross_layers): """Set all modules for ViCo method after the UNet initialized normally. Args: unet (nn.Module): UNet model. image_cross_layers (List): List of flag indicating which transformer2D modules have image_cross_attention modules. """ # replace transformer2d blocks replace_transformer2d(unet, image_cross_layers) # replace cross attention layer replace_cross_attention(unet) # replace forward for _, layer in unet.named_modules(): if layer.__class__.__name__ == 'UNet2DConditionModel': vico_unet = ViCoUNet2DConditionModel() vico_unet.apply_to(unet) elif layer.__class__.__name__ == 'CrossAttnDownBlock2D': vico_down_block = ViCoCrossAttnDownBlock2D() vico_down_block.apply_to(layer) elif layer.__class__.__name__ == 'UNetMidBlock2DCrossAttn': vico_mid_block = ViCoUNetMidBlock2DCrossAttn() vico_mid_block.apply_to(layer) elif layer.__class__.__name__ == 'CrossAttnUpBlock2D': vico_up_block = ViCoCrossAttnUpBlock2D() vico_up_block.apply_to(layer) ================================================ FILE: mmagic/models/editors/wgan_gp/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .wgan_discriminator import WGANGPDiscriminator from .wgan_generator import WGANGPGenerator from .wgan_gp import WGANGP __all__ = ['WGANGPDiscriminator', 'WGANGPGenerator', 'WGANGP'] ================================================ FILE: mmagic/models/editors/wgan_gp/wgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.registry import MODELS from .wgan_gp_module import ConvLNModule, WGANDecisionHead @MODELS.register_module() class WGANGPDiscriminator(BaseModule): r"""Discriminator for WGANGP. Implementation Details for WGANGP discriminator the same as training configuration (a) described in PGGAN paper: PROGRESSIVE GROWING OF GANS FOR IMPROVED QUALITY, STABILITY, AND VARIATION https://research.nvidia.com/sites/default/files/pubs/2017-10_Progressive-Growing-of/karras2018iclr-paper.pdf # noqa #. Adopt convolution architecture specified in appendix A.2; #. Add layer normalization to all conv3x3 and conv4x4 layers; #. Use LeakyReLU in the discriminator except for the final output layer; #. Initialize all weights using He’s initializer. Args: in_channel (int): The channel number of the input image. in_scale (int): The scale of the input image. conv_module_cfg (dict, optional): Config for the convolution module used in this discriminator. Defaults to None. init_cfg (dict, optional): Initialization config dict. """ _default_channels_per_scale = { '4': 512, '8': 512, '16': 256, '32': 128, '64': 64, '128': 32 } _default_conv_module_cfg = dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='LN2d'), order=('conv', 'norm', 'act')) _default_upsample_cfg = dict(type='nearest', scale_factor=2) def __init__(self, in_channel, in_scale, conv_module_cfg=None, init_cfg=None): super().__init__(init_cfg=init_cfg) # set initial params self.in_channel = in_channel self.in_scale = in_scale self.conv_module_cfg = deepcopy(self._default_conv_module_cfg) if conv_module_cfg is not None: self.conv_module_cfg.update(conv_module_cfg) # set from_rgb head self.from_rgb = ConvModule( 3, kernel_size=1, out_channels=self._default_channels_per_scale[str(self.in_scale)], act_cfg=dict(type='LeakyReLU', negative_slope=0.2)) # set conv_blocks self.conv_blocks = nn.ModuleList() log2scale = int(np.log2(self.in_scale)) for i in range(log2scale, 2, -1): self.conv_blocks.append( ConvLNModule( self._default_channels_per_scale[str(2**i)], self._default_channels_per_scale[str(2**i)], feature_shape=(self._default_channels_per_scale[str(2**i)], 2**i, 2**i), **self.conv_module_cfg)) self.conv_blocks.append( ConvLNModule( self._default_channels_per_scale[str(2**i)], self._default_channels_per_scale[str(2**(i - 1))], feature_shape=(self._default_channels_per_scale[str( 2**(i - 1))], 2**i, 2**i), **self.conv_module_cfg)) self.conv_blocks.append(nn.AvgPool2d(kernel_size=2, stride=2)) self.decision = WGANDecisionHead( self._default_channels_per_scale['4'], self._default_channels_per_scale['4'], 1, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=self.conv_module_cfg['norm_cfg']) def forward(self, x): """Forward function. Args: x (torch.Tensor): Fake or real image tensor. Returns: torch.Tensor: Prediction for the reality of the input image. """ # noise vector to 2D feature x = self.from_rgb(x) for conv in self.conv_blocks: x = conv(x) x = self.decision(x) return x ================================================ FILE: mmagic/models/editors/wgan_gp/wgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.model import BaseModule from mmagic.models.utils import get_module_device from mmagic.registry import MODELS from .wgan_gp_module import WGANNoiseTo2DFeat @MODELS.register_module() class WGANGPGenerator(BaseModule): r"""Generator for WGANGP. Implementation Details for WGANGP generator the same as training configuration (a) described in PGGAN paper: PROGRESSIVE GROWING OF GANS FOR IMPROVED QUALITY, STABILITY, AND VARIATION https://research.nvidia.com/sites/default/files/pubs/2017-10_Progressive-Growing-of/karras2018iclr-paper.pdf # noqa #. Adopt convolution architecture specified in appendix A.2; #. Use batchnorm in the generator except for the final output layer; #. Use ReLU in the generator except for the final output layer; #. Use Tanh in the last layer; #. Initialize all weights using He’s initializer. Args: noise_size (int): Size of the input noise vector. out_scale (int): Output scale for the generated image. conv_module_cfg (dict, optional): Config for the convolution module used in this generator. Defaults to None. upsample_cfg (dict, optional): Config for the upsampling operation. Defaults to None. init_cfg (dict, optional): Initialization config dict. """ _default_channels_per_scale = { '4': 512, '8': 512, '16': 256, '32': 128, '64': 64, '128': 32 } _default_conv_module_cfg = dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='ReLU'), norm_cfg=dict(type='BN'), order=('conv', 'norm', 'act')) _default_upsample_cfg = dict(type='nearest', scale_factor=2) def __init__(self, noise_size, out_scale, conv_module_cfg=None, upsample_cfg=None, init_cfg=None): super().__init__(init_cfg=init_cfg) # set initial params self.noise_size = noise_size self.out_scale = out_scale self.conv_module_cfg = deepcopy(self._default_conv_module_cfg) if conv_module_cfg is not None: self.conv_module_cfg.update(conv_module_cfg) self.upsample_cfg = upsample_cfg if upsample_cfg else deepcopy( self._default_upsample_cfg) # set noise2feat head self.noise2feat = WGANNoiseTo2DFeat( self.noise_size, self._default_channels_per_scale['4']) # set conv_blocks self.conv_blocks = nn.ModuleList() self.conv_blocks.append(ConvModule(512, 512, **self.conv_module_cfg)) log2scale = int(np.log2(self.out_scale)) for i in range(3, log2scale + 1): self.conv_blocks.append(MODELS.build(self._default_upsample_cfg)) self.conv_blocks.append( ConvModule(self._default_channels_per_scale[str(2**(i - 1))], self._default_channels_per_scale[str(2**i)], **self.conv_module_cfg)) self.conv_blocks.append( ConvModule(self._default_channels_per_scale[str(2**i)], self._default_channels_per_scale[str(2**i)], **self.conv_module_cfg)) self.to_rgb = ConvModule( self._default_channels_per_scale[str(self.out_scale)], kernel_size=1, out_channels=3, act_cfg=dict(type='Tanh')) def forward(self, noise, num_batches=0, return_noise=False): """Forward function. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. num_batches (int, optional): The number of batch size. Defaults to 0. return_noise (bool, optional): If True, ``noise_batch`` will be returned in a dict with ``fake_img``. Defaults to False. Returns: torch.Tensor | dict: If not ``return_noise``, only the output image will be returned. Otherwise, a dict contains ``fake_img`` and ``noise_batch`` will be returned. """ # receive noise and conduct sanity check. if isinstance(noise, torch.Tensor): assert noise.shape[1] == self.noise_size assert noise.ndim == 2, ('The noise should be in shape of (n, c), ' f'but got {noise.shape}') noise_batch = noise # receive a noise generator and sample noise. elif callable(noise): noise_generator = noise assert num_batches > 0 noise_batch = noise_generator((num_batches, self.noise_size)) # otherwise, we will adopt default noise sampler. else: assert num_batches > 0 noise_batch = torch.randn((num_batches, self.noise_size)) # dirty code for putting data on the right device noise_batch = noise_batch.to(get_module_device(self)) # noise vector to 2D feature x = self.noise2feat(noise_batch) for conv in self.conv_blocks: x = conv(x) out_img = self.to_rgb(x) if return_noise: output = dict(fake_img=out_img, noise_batch=noise_batch) return output return out_img ================================================ FILE: mmagic/models/editors/wgan_gp/wgan_gp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Dict, Tuple import torch from mmengine.optim import OptimWrapper from torch import Tensor from mmagic.models.base_models import BaseGAN from mmagic.models.losses import gradient_penalty_loss from mmagic.registry import MODELS from mmagic.structures import DataSample @MODELS.register_module() class WGANGP(BaseGAN): """Implementation of `Improved Training of Wasserstein GANs`. Paper link: https://arxiv.org/pdf/1704.00028 Detailed architecture can be found in :class:`~mmagic.models.editors.wgan_gp.WGANGPGenerator` and :class:`~mmagic.models.editors.wgan_gp.WGANGPDiscriminator` """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # gradient penalty loss settings self.gp_norm_mode = self.loss_config.get('norm_mode', 'HWC') self.gp_loss_weight = self.loss_config.get('loss_weight', 10) def disc_loss(self, real_data: Tensor, fake_data: Tensor, disc_pred_fake: Tensor, disc_pred_real: Tensor) -> Tuple: r"""Get disc loss. WGAN-GP use the wgan loss and gradient penalty to train the discriminator. Args: real_data (Tensor): Real input data. fake_data (Tensor): Fake input data. disc_pred_fake (Tensor): Discriminator's prediction of the fake images. disc_pred_real (Tensor): Discriminator's prediction of the real images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_disc_fake'] = disc_pred_fake.mean() losses_dict['loss_disc_real'] = -disc_pred_real.mean() # Gradient Penalty loss losses_dict['loss_gp'] = self.gp_loss_weight * gradient_penalty_loss( self.discriminator, real_data, fake_data, norm_mode=self.gp_norm_mode) loss, log_var = self.parse_losses(losses_dict) return loss, log_var def gen_loss(self, disc_pred_fake: Tensor) -> Tuple: """Get gen loss. DCGAN use the wgan loss to train the generator. Args: disc_pred_fake (Tensor): Discriminator's prediction of the fake images. Returns: tuple[Tensor, dict]: Loss value and a dict of log variables. """ losses_dict = dict() losses_dict['loss_gen'] = -disc_pred_fake.mean() loss, log_var = self.parse_losses(losses_dict) return loss, log_var def train_discriminator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper ) -> Dict[str, Tensor]: """Train discriminator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ real_imgs = data_samples.gt_img num_batches = real_imgs.shape[0] noise_batch = self.noise_fn(num_batches=num_batches) with torch.no_grad(): fake_imgs = self.generator(noise=noise_batch, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) disc_pred_real = self.discriminator(real_imgs) parsed_losses, log_vars = self.disc_loss(real_imgs, fake_imgs, disc_pred_fake, disc_pred_real) optimizer_wrapper.update_params(parsed_losses) return log_vars def train_generator(self, inputs: dict, data_samples: DataSample, optimizer_wrapper: OptimWrapper) -> Dict[str, Tensor]: """Train generator. Args: inputs (dict): Inputs from dataloader. data_samples (DataSample): Data samples from dataloader. Do not used in generator's training. optim_wrapper (OptimWrapper): OptimWrapper instance used to update model parameters. Returns: Dict[str, Tensor]: A ``dict`` of tensor for logging. """ num_batches = len(data_samples) noise = self.noise_fn(num_batches=num_batches) fake_imgs = self.generator(noise=noise, return_noise=False) disc_pred_fake = self.discriminator(fake_imgs) parsed_loss, log_vars = self.gen_loss(disc_pred_fake) optimizer_wrapper.update_params(parsed_loss) return log_vars ================================================ FILE: mmagic/models/editors/wgan_gp/wgan_gp_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import torch import torch.nn as nn from mmcv.cnn import ConvModule, build_norm_layer from mmengine.model import constant_init from mmagic.registry import MODELS @MODELS.register_module() class WGANNoiseTo2DFeat(nn.Module): """Module used in WGAN-GP to transform 1D noise tensor in order [N, C] to 2D shape feature tensor in order [N, C, H, W]. Args: noise_size (int): Size of the input noise vector. out_channels (int): The channel number of the output feature. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). norm_cfg (dict, optional): Config dict to build norm layer. Defaults to dict(type='BN'). order (tuple, optional): The order of conv/norm/activation layers. It is a sequence of "conv", "norm" and "act". Common examples are ("conv", "norm", "act") and ("act", "conv", "norm"). Defaults to ('linear', 'act', 'norm'). """ def __init__(self, noise_size, out_channels, act_cfg=dict(type='ReLU'), norm_cfg=dict(type='BN'), order=('linear', 'act', 'norm')): super().__init__() self.noise_size = noise_size self.out_channels = out_channels self.with_activation = act_cfg is not None self.with_norm = norm_cfg is not None self.order = order assert len(order) == 3 and set(order) == set(['linear', 'act', 'norm']) # w/o bias, because the bias is added after reshaping the tensor to # 2D feature self.linear = nn.Linear(noise_size, out_channels * 16, bias=False) if self.with_activation: self.activation = MODELS.build(act_cfg) # add bias for reshaped 2D feature. self.register_parameter( 'bias', nn.Parameter(torch.zeros(1, out_channels, 1, 1))) if self.with_norm: _, self.norm = build_norm_layer(norm_cfg, out_channels) self._init_weight() def forward(self, x): """Forward function. Args: x (Tensor): Input noise tensor with shape (n, c). Returns: Tensor: Forward results with shape (n, c, 4, 4). """ assert x.ndim == 2 for order in self.order: if order == 'linear': x = self.linear(x) # [n, c, 4, 4] x = torch.reshape(x, (-1, self.out_channels, 4, 4)) x = x + self.bias elif order == 'act' and self.with_activation: x = self.activation(x) elif order == 'norm' and self.with_norm: x = self.norm(x) return x def _init_weight(self): """Initialize weights for the model.""" nn.init.normal_(self.linear.weight, 0., 1.) if self.bias is not None: nn.init.constant_(self.bias, 0.) if self.with_norm: constant_init(self.norm, 1, bias=0) class WGANDecisionHead(nn.Module): """Module used in WGAN-GP to get the final prediction result with 4x4 resolution input tensor in the bottom of the discriminator. Args: in_channels (int): Number of channels in input feature map. mid_channels (int): Number of channels in feature map after convolution. out_channels (int): The channel number of the final output layer. bias (bool, optional): Whether to use bias parameter. Defaults to True. act_cfg (dict, optional): Config for the activation layer. Defaults to dict(type='ReLU'). out_act (dict, optional): Config for the activation layer of output layer. Defaults to None. norm_cfg (dict, optional): Config dict to build norm layer. Defaults to dict(type='LN2d'). """ def __init__(self, in_channels, mid_channels, out_channels, bias=True, act_cfg=dict(type='ReLU'), out_act=None, norm_cfg=dict(type='LN2d')): super().__init__() self.in_channels = in_channels self.mid_channels = mid_channels self.out_channels = out_channels self.with_out_activation = out_act is not None # setup conv layer self.conv = ConvLNModule( in_channels, feature_shape=(mid_channels, 1, 1), kernel_size=4, out_channels=mid_channels, act_cfg=act_cfg, norm_cfg=norm_cfg, order=('conv', 'norm', 'act')) # setup linear layer self.linear = nn.Linear( self.mid_channels, self.out_channels, bias=bias) if self.with_out_activation: self.out_activation = MODELS.build(out_act) self._init_weight() def forward(self, x): """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ x = self.conv(x) x = torch.reshape(x, (x.shape[0], -1)) x = self.linear(x) if self.with_out_activation: x = self.out_activation(x) return x def _init_weight(self): """Initialize weights for the model.""" nn.init.normal_(self.linear.weight, 0., 1.) nn.init.constant_(self.linear.bias, 0.) @MODELS.register_module() class ConvLNModule(ConvModule): r"""ConvModule with Layer Normalization. In this module, we inherit default ``mmcv.cnn.ConvModule`` and deal with the situation that 'norm_cfg' is 'LN2d' or 'GN'. We adopt 'GN' as a replacement for layer normalization referring to: https://github.com/LynnHo/DCGAN-LSGAN-WGAN-GP-DRAGAN-Pytorch/blob/master/module.py # noqa Args: feature_shape (tuple): The shape of feature map that will be. """ def __init__(self, *args, feature_shape=None, **kwargs): if 'norm_cfg' in kwargs and kwargs['norm_cfg'] is not None and kwargs[ 'norm_cfg']['type'] in ['LN2d', 'GN']: nkwargs = deepcopy(kwargs) nkwargs['norm_cfg'] = None super().__init__(*args, **nkwargs) self.with_norm = True self.norm_name = kwargs['norm_cfg']['type'] if self.norm_name == 'LN2d': norm = nn.LayerNorm(feature_shape) self.add_module(self.norm_name, norm) else: norm = nn.GroupNorm(1, feature_shape[0]) self.add_module(self.norm_name, norm) else: super().__init__(*args, **kwargs) ================================================ FILE: mmagic/models/losses/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .adv_loss import AdvLoss from .clip_loss import CLIPLoss from .composition_loss import (CharbonnierCompLoss, L1CompositionLoss, MSECompositionLoss) from .face_id_loss import FaceIdLoss from .feature_loss import LightCNNFeatureLoss from .gan_loss import (DiscShiftLoss, GANLoss, GaussianBlur, GradientPenaltyLoss, disc_shift_loss, gen_path_regularizer, gradient_penalty_loss, r1_gradient_penalty_loss) from .gradient_loss import GradientLoss from .loss_comps import (CLIPLossComps, DiscShiftLossComps, FaceIdLossComps, GANLossComps, GeneratorPathRegularizerComps, GradientPenaltyLossComps, R1GradientPenaltyComps) from .loss_wrapper import mask_reduce_loss, reduce_loss from .perceptual_loss import (PerceptualLoss, PerceptualVGG, TransferalPerceptualLoss) from .pixelwise_loss import (CharbonnierLoss, L1Loss, MaskedTVLoss, MSELoss, PSNRLoss, tv_loss) __all__ = [ 'L1Loss', 'MSELoss', 'CharbonnierLoss', 'L1CompositionLoss', 'MSECompositionLoss', 'CharbonnierCompLoss', 'GANLoss', 'GaussianBlur', 'GradientPenaltyLoss', 'PerceptualLoss', 'PerceptualVGG', 'reduce_loss', 'mask_reduce_loss', 'DiscShiftLoss', 'MaskedTVLoss', 'GradientLoss', 'TransferalPerceptualLoss', 'LightCNNFeatureLoss', 'gradient_penalty_loss', 'r1_gradient_penalty_loss', 'gen_path_regularizer', 'FaceIdLoss', 'CLIPLoss', 'CLIPLossComps', 'DiscShiftLossComps', 'FaceIdLossComps', 'GANLossComps', 'GeneratorPathRegularizerComps', 'GradientPenaltyLossComps', 'R1GradientPenaltyComps', 'disc_shift_loss', 'tv_loss', 'PSNRLoss', 'AdvLoss' ] ================================================ FILE: mmagic/models/losses/adv_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import random from collections import deque import torch import torch.nn as nn from mmagic.registry import MODELS from .gan_loss import GANLoss, gradient_penalty_loss class ImagePool: """Defined a image pool for RelativisticDiscLoss.""" def __init__(self, pool_size): self.pool_size = pool_size self.sample_size = pool_size if self.pool_size > 0: self.num_imgs = 0 self.images = deque() def add(self, images): if self.pool_size == 0: return images for image in images.data: image = torch.unsqueeze(image, 0) if self.num_imgs < self.pool_size: self.num_imgs = self.num_imgs + 1 self.images.append(image) else: self.images.popleft() self.images.append(image) def query(self): if len(self.images) > self.sample_size: return_images = list(random.sample(self.images, self.sample_size)) else: return_images = list(self.images) return torch.cat(return_images, 0) class DiscLoss(nn.Module): """Defined a criterion to calculator loss.""" def name(self): """return name of criterion.""" return 'DiscLoss' def __init__(self, gan_type='vanilla'): super(DiscLoss, self).__init__() self.criterionGAN = GANLoss(gan_type=gan_type) def forward(self, net, fakeB, realB, model='discriminator'): """Get discriminator or generator loss.""" if model == 'discriminator': self.pred_fake = net.forward(fakeB.detach()) self.loss_D_fake = self.criterionGAN(self.pred_fake, 0) # Real self.pred_real = net.forward(realB) self.loss_D_real = self.criterionGAN(self.pred_real, 1) # Combined loss self.loss_D = (self.loss_D_fake + self.loss_D_real) * 0.5 return self.loss_D else: pred_fake = net.forward(fakeB) return self.criterionGAN(pred_fake, 1) class RelativisticDiscLoss(nn.Module): """Defined a criterion to calculator loss.""" def name(self): """return name of criterion.""" return 'RelativisticDiscLoss' def __init__(self): super(RelativisticDiscLoss, self).__init__() self.criterionGAN = GANLoss(gan_type='vanilla') self.fake_pool = ImagePool(50) self.real_pool = ImagePool(50) def forward(self, net, fakeB, realB, model='discriminator'): """Get discriminator or generator loss.""" if model == 'discriminator': self.fake_B = fakeB.detach() self.real_B = realB self.pred_fake = net.forward(self.fake_B) self.fake_pool.add(self.pred_fake) # Real self.pred_real = net.forward(self.real_B) self.real_pool.add(self.pred_real) # Combined loss self.loss_D = (self.criterionGAN( self.pred_real - torch.mean(self.fake_pool.query()), 1) + self.criterionGAN( self.pred_fake - torch.mean(self.real_pool.query()), 0)) / 2 return self.loss_D else: self.pred_fake = net.forward(fakeB) # Real self.pred_real = net.forward(realB) errG = (self.criterionGAN( self.pred_real - torch.mean(self.fake_pool.query()), 0) + self.criterionGAN( self.pred_fake - torch.mean(self.real_pool.query()), 1)) / 2 return errG class RelativisticDiscLossLS(nn.Module): """Defined a criterion to calculator loss.""" def name(self): """return name of criterion.""" return 'RelativisticDiscLossLS' def __init__(self): super(RelativisticDiscLossLS, self).__init__() self.criterionGAN = GANLoss(gan_type='l1') self.fake_pool = ImagePool(50) self.real_pool = ImagePool(50) def forward(self, net, fakeB, realB, model='discriminator'): """Get discriminator or generator loss.""" if model == 'discriminator': self.fake_B = fakeB.detach() self.real_B = realB self.pred_fake = net.forward(fakeB.detach()) self.fake_pool.add(self.pred_fake) # Real self.pred_real = net.forward(realB) self.real_pool.add(self.pred_real) # Combined loss ex_pdata = torch.mean( (self.pred_real - torch.mean(self.fake_pool.query()) - 1)**2) ex_pz = torch.mean( (self.pred_fake - torch.mean(self.real_pool.query()) + 1)**2) self.loss_D = (ex_pdata + ex_pz) / 2 return self.loss_D else: self.pred_fake = net.forward(fakeB) # Real self.pred_real = net.forward(realB) ex_pdata = torch.mean( (self.pred_real - torch.mean(self.fake_pool.query()) + 1)**2) ez_pz = torch.mean( (self.pred_fake - torch.mean(self.real_pool.query()) - 1)**2) errG = (ex_pdata + ez_pz) / 2 return errG class DiscLossWGANGP(DiscLoss): """Defined a criterion to calculator loss.""" def name(self): """return name of criterion.""" return 'DiscLossWGAN-GP' def __init__(self): super(DiscLossWGANGP, self).__init__() self.LAMBDA = 10 def forward(self, net, fakeB, realB, model='discriminator'): """Get discriminator or generator loss.""" if model == 'discriminator': self.D_fake = net.forward(fakeB.detach()) self.D_fake = self.D_fake.mean() # Real self.D_real = net.forward(realB) self.D_real = self.D_real.mean() # Combined loss self.loss_D = self.D_fake - self.D_real gradient_penalty = gradient_penalty_loss(net, realB.data, fakeB.data) * self.LAMBDA return self.loss_D + gradient_penalty else: self.D_fake = net.forward(fakeB) return -self.D_fake.mean() @MODELS.register_module() class AdvLoss: """Returns the loss of discriminator with the specified type for DeblurGanv2. Args: loss_type (Str): One of value in [wgan-gp,lsgan,gan,ragan,ragan-ls]. """ def __new__(cls, loss_type: str): if loss_type == 'wgan-gp': disc_loss = DiscLossWGANGP() elif loss_type == 'lsgan': disc_loss = DiscLoss(gan_type='l1') elif loss_type == 'gan': disc_loss = DiscLoss() elif loss_type == 'ragan': disc_loss = RelativisticDiscLoss() elif loss_type == 'ragan-ls': disc_loss = RelativisticDiscLossLS() else: raise ValueError('GAN Loss [%s] not recognized.' % loss_type) return disc_loss ================================================ FILE: mmagic/models/losses/clip_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS from mmagic.utils import try_import clip = try_import('clip') class CLIPLossModel(torch.nn.Module): """Wrapped clip model to calculate clip loss. Ref: https://github.com/orpatashnik/StyleCLIP/blob/main/criteria/clip_loss.py # noqa Args: in_size (int, optional): Input image size. Defaults to 1024. scale_factor (int, optional): Unsampling factor. Defaults to 7. pool_size (int, optional): Pooling output size. Defaults to 224. clip_type (str, optional): A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict. For more details, you can refer to https://github.com/openai/CLIP/blob/573315e83f07b53a61ff5098757e8fc885f1703e/clip/clip.py#L91 # noqa Defaults to 'ViT-B/32'. """ def __init__(self, in_size: int = 1024, scale_factor: int = 7, pool_size: int = 224, clip_type: str = 'ViT-B/32') -> None: super(CLIPLossModel, self).__init__() try: import clip except ImportError: raise 'To use clip loss, openai clip need to be installed first' assert clip is not None, ( "Cannot import 'clip'. Please install 'clip' via " "\"pip install git+https://github.com/openai/CLIP.git\".") self.model, self.preprocess = clip.load(clip_type, device='cpu') self.upsample = torch.nn.Upsample(scale_factor=scale_factor) self.avg_pool = torch.nn.AvgPool2d( kernel_size=(scale_factor * in_size // pool_size)) def forward(self, image: torch.Tensor, text: torch.Tensor) -> torch.Tensor: """Forward function.""" assert image is not None assert text is not None image = self.avg_pool(self.upsample(image)) loss = 1 - self.model(image, text)[0] / 100 return loss @MODELS.register_module() class CLIPLoss(nn.Module): """Clip loss. In styleclip, this loss is used to optimize the latent code to generate image that match the text. In this loss, we may need to provide ``image``, ``text``. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( image='fake_imgs', text='descriptions') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. clip_model (dict, optional): Kwargs for clip loss model. Defaults to dict(). loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_clip'. """ def __init__(self, loss_weight: float = 1.0, data_info: Optional[dict] = None, clip_model: dict = dict(), loss_name: str = 'loss_clip') -> None: super(CLIPLoss, self).__init__() self.loss_weight = loss_weight self.data_info = data_info self.net = CLIPLossModel(**clip_model) self._loss_name = loss_name def forward(self, image: torch.Tensor, text: torch.Tensor) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``third_party_net_loss``. """ return self.net(image, text) * self.loss_weight ================================================ FILE: mmagic/models/losses/composition_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS from .pixelwise_loss import charbonnier_loss, l1_loss, mse_loss _reduction_modes = ['none', 'mean', 'sum'] @MODELS.register_module() class L1CompositionLoss(nn.Module): """L1 composition loss. Args: loss_weight (float): Loss weight for L1 loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise def forward(self, pred_alpha: torch.Tensor, fg: torch.Tensor, bg: torch.Tensor, ori_merged: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """ Args: pred_alpha (Tensor): of shape (N, 1, H, W). Predicted alpha matte. fg (Tensor): of shape (N, 3, H, W). Tensor of foreground object. bg (Tensor): of shape (N, 3, H, W). Tensor of background object. ori_merged (Tensor): of shape (N, 3, H, W). Tensor of origin merged image before normalized by ImageNet mean and std. weight (Tensor, optional): of shape (N, 1, H, W). It is an indicating matrix: weight[trimap == 128] = 1. Default: None. """ pred_merged = pred_alpha * fg + (1. - pred_alpha) * bg if weight is not None: weight = weight.expand(-1, 3, -1, -1) return self.loss_weight * l1_loss( pred_merged, ori_merged, weight, reduction=self.reduction, sample_wise=self.sample_wise) @MODELS.register_module() class MSECompositionLoss(nn.Module): """MSE (L2) composition loss. Args: loss_weight (float): Loss weight for MSE loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise def forward(self, pred_alpha: torch.Tensor, fg: torch.Tensor, bg: torch.Tensor, ori_merged: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """ Args: pred_alpha (Tensor): of shape (N, 1, H, W). Predicted alpha matte. fg (Tensor): of shape (N, 3, H, W). Tensor of foreground object. bg (Tensor): of shape (N, 3, H, W). Tensor of background object. ori_merged (Tensor): of shape (N, 3, H, W). Tensor of origin merged image before normalized by ImageNet mean and std. weight (Tensor, optional): of shape (N, 1, H, W). It is an indicating matrix: weight[trimap == 128] = 1. Default: None. """ pred_merged = pred_alpha * fg + (1. - pred_alpha) * bg if weight is not None: weight = weight.expand(-1, 3, -1, -1) return self.loss_weight * mse_loss( pred_merged, ori_merged, weight, reduction=self.reduction, sample_wise=self.sample_wise) @MODELS.register_module() class CharbonnierCompLoss(nn.Module): """Charbonnier composition loss. Args: loss_weight (float): Loss weight for L1 loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. eps (float): A value used to control the curvature near zero. Default: 1e-12. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False, eps: bool = 1e-12) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise self.eps = eps def forward(self, pred_alpha: torch.Tensor, fg: torch.Tensor, bg: torch.Tensor, ori_merged: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """ Args: pred_alpha (Tensor): of shape (N, 1, H, W). Predicted alpha matte. fg (Tensor): of shape (N, 3, H, W). Tensor of foreground object. bg (Tensor): of shape (N, 3, H, W). Tensor of background object. ori_merged (Tensor): of shape (N, 3, H, W). Tensor of origin merged image before normalized by ImageNet mean and std. weight (Tensor, optional): of shape (N, 1, H, W). It is an indicating matrix: weight[trimap == 128] = 1. Default: None. """ pred_merged = pred_alpha * fg + (1. - pred_alpha) * bg if weight is not None: weight = weight.expand(-1, 3, -1, -1) return self.loss_weight * charbonnier_loss( pred_merged, ori_merged, weight, eps=self.eps, reduction=self.reduction, sample_wise=self.sample_wise) ================================================ FILE: mmagic/models/losses/face_id_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS @MODELS.register_module() class FaceIdLoss(nn.Module): """Face similarity loss. Generally this loss is used to keep the id consistency of the input face image and output face image. In this loss, we may need to provide ``gt``, ``pred`` and ``x``. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( gt='real_imgs', pred='fake_imgs') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. facenet (dict, optional): Config dict for facenet. Defaults to dict(type='ArcFace', ir_se50_weights=None, device='cuda'). loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_id'. """ def __init__(self, loss_weight: float = 1.0, data_info: Optional[dict] = None, facenet: dict = dict(type='ArcFace', ir_se50_weights=None), loss_name: str = 'loss_id') -> None: super(FaceIdLoss, self).__init__() self.loss_weight = loss_weight self.data_info = data_info self.net = MODELS.build(facenet) self._loss_name = loss_name def forward(self, pred: torch.Tensor, gt: torch.Tensor) -> torch.Tensor: """Forward function.""" # NOTE: only return the loss term return self.net(pred, gt)[0] * self.loss_weight ================================================ FILE: mmagic/models/losses/feature_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import warnings from typing import Optional import torch import torch.nn as nn from mmengine import MMLogger from mmengine.runner import load_checkpoint from mmagic.models.editors.dic import LightCNN from mmagic.registry import MODELS class LightCNNFeature(nn.Module): """Feature of LightCNN. It is used to train DICGAN. """ def __init__(self) -> None: super().__init__() model = LightCNN(3) self.features = nn.Sequential(*list(model.features.children())) self.features.requires_grad_(False) def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward function. Args: x (Tensor): Input tensor. Returns: Tensor: Forward results. """ return self.features(x) def init_weights(self, pretrained: Optional[str] = None, strict: bool = True) -> None: """Init weights for models. Args: pretrained (str, optional): Path for pretrained weights. If given None, pretrained weights will not be loaded. Defaults to None. strict (boo, optional): Whether strictly load the pretrained model. Defaults to True. """ if isinstance(pretrained, str): logger = MMLogger.get_current_instance() load_checkpoint(self, pretrained, strict=strict, logger=logger) elif pretrained is not None: raise TypeError(f'"pretrained" must be a str or None. ' f'But received {type(pretrained)}.') @MODELS.register_module() class LightCNNFeatureLoss(nn.Module): """Feature loss of DICGAN, based on LightCNN. Args: pretrained (str): Path for pretrained weights. loss_weight (float): Loss weight. Default: 1.0. criterion (str): Criterion type. Options are 'l1' and 'mse'. Default: 'l1'. """ def __init__(self, pretrained: str, loss_weight: float = 1.0, criterion: str = 'l1') -> None: super().__init__() self.model = LightCNNFeature() if not isinstance(pretrained, str): warnings.warn('`LightCNNFeature` model in FeatureLoss ' + 'should be pretrained') self.model.init_weights(pretrained) self.model.eval() self.loss_weight = loss_weight if criterion == 'l1': self.criterion = torch.nn.L1Loss() elif criterion == 'mse': self.criterion = torch.nn.MSELoss() else: raise ValueError("'criterion' should be 'l1' or 'mse', " f'but got {criterion}') def forward(self, pred: torch.Tensor, gt: torch.Tensor) -> torch.Tensor: """Forward function. Args: pred (Tensor): Predicted tensor. gt (Tensor): GT tensor. Returns: Tensor: Forward results. """ self.model.eval() pred_feature = self.model(pred) gt_feature = self.model(gt).detach() feature_loss = self.criterion(pred_feature, gt_feature) return feature_loss * self.loss_weight ================================================ FILE: mmagic/models/losses/gan_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional, Tuple, Union import numpy as np import torch import torch.autograd as autograd import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F from mmengine.dist import is_distributed from torch.cuda.amp.grad_scaler import GradScaler from torch.nn.functional import conv2d from mmagic.registry import MODELS @MODELS.register_module() class GANLoss(nn.Module): """Define GAN loss. Args: gan_type (str): Support 'vanilla', 'lsgan', 'wgan', 'hinge', 'l1'. real_label_val (float): The value for real label. Default: 1.0. fake_label_val (float): The value for fake label. Default: 0.0. loss_weight (float): Loss weight. Default: 1.0. Note that loss_weight is only for generators; and it is always 1.0 for discriminators. """ def __init__(self, gan_type: str, real_label_val: float = 1.0, fake_label_val: float = 0.0, loss_weight: float = 1.0) -> None: super().__init__() self.gan_type = gan_type self.real_label_val = real_label_val self.fake_label_val = fake_label_val self.loss_weight = loss_weight if self.gan_type == 'smgan': self.gaussian_blur = GaussianBlur() if self.gan_type == 'vanilla': self.loss = nn.BCEWithLogitsLoss() elif self.gan_type == 'lsgan' or self.gan_type == 'smgan': self.loss = nn.MSELoss() elif self.gan_type == 'wgan': self.loss = self._wgan_loss elif self.gan_type == 'hinge': self.loss = nn.ReLU() elif self.gan_type == 'l1': self.loss = nn.L1Loss() else: raise NotImplementedError( f'GAN type {self.gan_type} is not implemented.') def _wgan_loss(self, input: torch.Tensor, target: bool) -> torch.Tensor: """wgan loss. Args: input (Tensor): Input tensor. target (bool): Target label. Returns: Tensor: wgan loss. """ return -input.mean() if target else input.mean() def get_target_label(self, input: torch.Tensor, target_is_real: bool) -> Union[bool, torch.Tensor]: """Get target label. Args: input (Tensor): Input tensor. target_is_real (bool): Whether the target is real or fake. Returns: (bool | Tensor): Target tensor. Return bool for wgan, otherwise, return Tensor. """ if self.gan_type == 'wgan': return target_is_real target_val = ( self.real_label_val if target_is_real else self.fake_label_val) return input.new_ones(input.size()) * target_val def forward(self, input: torch.Tensor, target_is_real: bool, is_disc: bool = False, mask: Optional[torch.Tensor] = None) -> torch.Tensor: """ Args: input (Tensor): The input for the loss module, i.e., the network prediction. target_is_real (bool): Whether the target is real or fake. is_disc (bool): Whether the loss for discriminators or not. Default: False. mask (Tensor): The mask tensor. Default: None. Returns: Tensor: GAN loss value. """ target_label = self.get_target_label(input, target_is_real) if self.gan_type == 'hinge': if is_disc: # for discriminators in hinge-gan input = -input if target_is_real else input loss = self.loss(1 + input).mean() else: # for generators in hinge-gan loss = -input.mean() elif self.gan_type == 'smgan': input_height, input_width = input.shape[2:] mask_height, mask_width = mask.shape[2:] # Handle inconsistent size between outputs and masks if input_height != mask_height or input_width != mask_width: input = F.interpolate( input, size=(mask_height, mask_width), mode='bilinear', align_corners=True) target_label = self.get_target_label(input, target_is_real) if is_disc: if target_is_real: target_label = target_label else: target_label = self.gaussian_blur(mask).detach().cuda( ) if mask.is_cuda else self.gaussian_blur( mask).detach().cpu() # target_label = self.gaussian_blur(mask).detach().cpu() loss = self.loss(input, target_label) else: loss = self.loss(input, target_label) * mask / mask.mean() loss = loss.mean() else: # other gan types loss = self.loss(input, target_label) # loss_weight is always 1.0 for discriminators return loss if is_disc else loss * self.loss_weight @MODELS.register_module() class GaussianBlur(nn.Module): """A Gaussian filter which blurs a given tensor with a two-dimensional gaussian kernel by convolving it along each channel. Batch operation is supported. This function is modified from kornia.filters.gaussian: ``. Args: kernel_size (tuple[int]): The size of the kernel. Default: (71, 71). sigma (tuple[float]): The standard deviation of the kernel. Default (10.0, 10.0) Returns: Tensor: The Gaussian-blurred tensor. Shape: - input: Tensor with shape of (n, c, h, w) - output: Tensor with shape of (n, c, h, w) """ def __init__( self, kernel_size: Tuple[int, int] = (71, 71), sigma: Tuple[float, float] = (10.0, 10.0) ) -> None: super(GaussianBlur, self).__init__() self.kernel_size = kernel_size self.sigma = sigma self.padding = self.compute_zero_padding(kernel_size) self.kernel = self.get_2d_gaussian_kernel(kernel_size, sigma) @staticmethod def compute_zero_padding(kernel_size: Tuple[int, int]) -> tuple: """Compute zero padding tuple. Args: kernel_size (tuple[int]): The size of the kernel. Returns: tuple: Padding of height and weight. """ padding = [(ks - 1) // 2 for ks in kernel_size] return padding[0], padding[1] def get_2d_gaussian_kernel(self, kernel_size: Tuple[int, int], sigma: Tuple[float, float]) -> torch.Tensor: """Get the two-dimensional Gaussian filter matrix coefficients. Args: kernel_size (tuple[int]): Kernel filter size in the x and y direction. The kernel sizes should be odd and positive. sigma (tuple[int]): Gaussian standard deviation in the x and y direction. Returns: kernel_2d (Tensor): A 2D torch tensor with gaussian filter matrix coefficients. """ if not isinstance(kernel_size, tuple) or len(kernel_size) != 2: raise TypeError( 'kernel_size must be a tuple of length two. Got {}'.format( kernel_size)) if not isinstance(sigma, tuple) or len(sigma) != 2: raise TypeError( 'sigma must be a tuple of length two. Got {}'.format(sigma)) kernel_size_x, kernel_size_y = kernel_size sigma_x, sigma_y = sigma kernel_x = self.get_1d_gaussian_kernel(kernel_size_x, sigma_x) kernel_y = self.get_1d_gaussian_kernel(kernel_size_y, sigma_y) kernel_2d = torch.matmul( kernel_x.unsqueeze(-1), kernel_y.unsqueeze(-1).t()) return kernel_2d def get_1d_gaussian_kernel(self, kernel_size: int, sigma: float) -> torch.Tensor: """Get the Gaussian filter coefficients in one dimension (x or y direction). Args: kernel_size (int): Kernel filter size in x or y direction. Should be odd and positive. sigma (float): Gaussian standard deviation in x or y direction. Returns: kernel_1d (Tensor): A 1D torch tensor with gaussian filter coefficients in x or y direction. """ if not isinstance(kernel_size, int) or kernel_size % 2 == 0 or kernel_size <= 0: raise TypeError( 'kernel_size must be an odd positive integer. Got {}'.format( kernel_size)) kernel_1d = self.gaussian(kernel_size, sigma) return kernel_1d def gaussian(self, kernel_size: int, sigma: float) -> torch.Tensor: """Gaussian function. Args: kernel_size (int): Kernel filter size in x or y direction. Should be odd and positive. sigma (float): Gaussian standard deviation in x or y direction. Returns: Tensor: A 1D torch tensor with gaussian filter coefficients in x or y direction. """ def gauss_arg(x): return -(x - kernel_size // 2)**2 / float(2 * sigma**2) gauss = torch.stack([ torch.exp(torch.tensor(gauss_arg(x))) for x in range(kernel_size) ]) return gauss / gauss.sum() def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward function. Args: x (Tensor): Tensor with shape (n, c, h, w) Returns: Tensor: The Gaussian-blurred tensor. """ if not torch.is_tensor(x): raise TypeError( 'Input x type is not a torch.Tensor. Got {}'.format(type(x))) if not len(x.shape) == 4: raise ValueError( 'Invalid input shape, we expect BxCxHxW. Got: {}'.format( x.shape)) _, c, _, _ = x.shape tmp_kernel = self.kernel.to(x.device).to(x.dtype) kernel = tmp_kernel.repeat(c, 1, 1, 1) return conv2d(x, kernel, padding=self.padding, stride=1, groups=c) def gradient_penalty_loss(discriminator: nn.Module, real_data: torch.Tensor, fake_data: torch.Tensor, mask: Optional[torch.Tensor] = None, norm_mode: str = 'pixel') -> torch.Tensor: """Calculate gradient penalty for wgan-gp. Args: discriminator (nn.Module): Network for the discriminator. real_data (Tensor): Real input data. fake_data (Tensor): Fake input data. mask (Tensor): Masks for inpainting. Default: None. Returns: Tensor: A tensor for gradient penalty. """ batch_size = real_data.size(0) alpha = torch.rand(batch_size, 1, 1, 1).to(real_data) # interpolate between real_data and fake_data interpolates = alpha * real_data + (1. - alpha) * fake_data interpolates = autograd.Variable(interpolates, requires_grad=True) disc_interpolates = discriminator(interpolates) gradients = autograd.grad( outputs=disc_interpolates, inputs=interpolates, grad_outputs=torch.ones_like(disc_interpolates), create_graph=True, retain_graph=True, only_inputs=True)[0] if mask is not None: gradients = gradients * mask if norm_mode == 'pixel': gradients_penalty = ((gradients.norm(2, dim=1) - 1)**2).mean() elif norm_mode == 'HWC': gradients_penalty = (( gradients.reshape(batch_size, -1).norm(2, dim=1) - 1)**2).mean() else: raise NotImplementedError( 'Currently, we only support ["pixel", "HWC"] ' f'norm mode but got {norm_mode}.') if mask is not None: gradients_penalty /= torch.mean(mask) return gradients_penalty @MODELS.register_module() class GradientPenaltyLoss(nn.Module): """Gradient penalty loss for wgan-gp. Args: loss_weight (float): Loss weight. Default: 1.0. """ def __init__(self, loss_weight: float = 1.) -> None: super().__init__() self.loss_weight = loss_weight def forward(self, discriminator: nn.Module, real_data: torch.Tensor, fake_data: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor: """Forward function. Args: discriminator (nn.Module): Network for the discriminator. real_data (Tensor): Real input data. fake_data (Tensor): Fake input data. mask (Tensor): Masks for inpainting. Default: None. Returns: Tensor: Loss. """ loss = gradient_penalty_loss( discriminator, real_data, fake_data, mask=mask) return loss * self.loss_weight def disc_shift_loss(pred: torch.Tensor) -> torch.Tensor: """Disc Shift loss. This loss is proposed in PGGAN as an auxiliary loss for discriminator. Args: pred (Tensor): Input tensor. Returns: torch.Tensor: loss tensor. """ return pred**2 @MODELS.register_module() class DiscShiftLoss(nn.Module): """Disc shift loss. Args: loss_weight (float, optional): Loss weight. Defaults to 1.0. """ def __init__(self, loss_weight: float = 0.1) -> None: super().__init__() self.loss_weight = loss_weight def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward function. Args: x (Tensor): Tensor with shape (n, c, h, w) Returns: Tensor: Loss. """ loss = torch.mean(disc_shift_loss(x)) return loss * self.loss_weight def r1_gradient_penalty_loss(discriminator: nn.Module, real_data: torch.Tensor, mask: Optional[torch.Tensor] = None, norm_mode: str = 'pixel', loss_scaler: Optional[GradScaler] = None, use_apex_amp: bool = False) -> torch.Tensor: """Calculate R1 gradient penalty for WGAN-GP. R1 regularizer comes from: "Which Training Methods for GANs do actually Converge?" ICML'2018 Different from original gradient penalty, this regularizer only penalized gradient w.r.t. real data. Args: discriminator (nn.Module): Network for the discriminator. real_data (Tensor): Real input data. mask (Tensor): Masks for inpainting. Default: None. norm_mode (str): This argument decides along which dimension the norm of the gradients will be calculated. Currently, we support ["pixel" , "HWC"]. Defaults to "pixel". Returns: Tensor: A tensor for gradient penalty. """ batch_size = real_data.shape[0] real_data = real_data.clone().requires_grad_() disc_pred = discriminator(real_data) if loss_scaler: disc_pred = loss_scaler.scale(disc_pred) elif use_apex_amp: from apex.amp._amp_state import _amp_state _loss_scaler = _amp_state.loss_scalers[0] disc_pred = _loss_scaler.loss_scale() * disc_pred.float() gradients = autograd.grad( outputs=disc_pred, inputs=real_data, grad_outputs=torch.ones_like(disc_pred), create_graph=True, retain_graph=True, only_inputs=True)[0] if loss_scaler: # unscale the gradient inv_scale = 1. / loss_scaler.get_scale() gradients = gradients * inv_scale elif use_apex_amp: inv_scale = 1. / _loss_scaler.loss_scale() gradients = gradients * inv_scale if mask is not None: gradients = gradients * mask if norm_mode == 'pixel': gradients_penalty = ((gradients.norm(2, dim=1))**2).mean() elif norm_mode == 'HWC': gradients_penalty = gradients.pow(2).reshape(batch_size, -1).sum(1).mean() else: raise NotImplementedError( 'Currently, we only support ["pixel", "HWC"] ' f'norm mode but got {norm_mode}.') if mask is not None: gradients_penalty /= torch.mean(mask) return gradients_penalty def gen_path_regularizer(generator: nn.Module, num_batches: int, mean_path_length: torch.Tensor, pl_batch_shrink: int = 1, decay: float = 0.01, weight: float = 1., pl_batch_size: Optional[int] = None, sync_mean_buffer: bool = False, loss_scaler: Optional[GradScaler] = None, use_apex_amp: bool = False) -> Tuple[torch.Tensor]: """Generator Path Regularization. Path regularization is proposed in StyleGAN2, which can help the improve the continuity of the latent space. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN, CVPR2020. Args: generator (nn.Module): The generator module. Note that this loss requires that the generator contains ``return_latents`` interface, with which we can get the latent code of the current sample. num_batches (int): The number of samples used in calculating this loss. mean_path_length (Tensor): The mean path length, calculated by moving average. pl_batch_shrink (int, optional): The factor of shrinking the batch size for saving GPU memory. Defaults to 1. decay (float, optional): Decay for moving average of mean path length. Defaults to 0.01. weight (float, optional): Weight of this loss item. Defaults to ``1.``. pl_batch_size (int | None, optional): The batch size in calculating generator path. Once this argument is set, the ``num_batches`` will be overridden with this argument and won't be affected by ``pl_batch_shrink``. Defaults to None. sync_mean_buffer (bool, optional): Whether to sync mean path length across all of GPUs. Defaults to False. Returns: tuple[Tensor]: The penalty loss, detached mean path tensor, and \ current path length. """ # reduce batch size for conserving GPU memory if pl_batch_shrink > 1: num_batches = max(1, num_batches // pl_batch_shrink) # reset the batch size if pl_batch_size is not None if pl_batch_size is not None: num_batches = pl_batch_size # get output from different generators output_dict = generator(None, num_batches=num_batches, return_latents=True) fake_img, latents = output_dict['fake_img'], output_dict['latent'] noise = torch.randn_like(fake_img) / np.sqrt( fake_img.shape[2] * fake_img.shape[3]) if loss_scaler: loss = loss_scaler.scale((fake_img * noise).sum())[0] grad = autograd.grad( outputs=loss, inputs=latents, grad_outputs=torch.ones(()).to(loss), create_graph=True, retain_graph=True, only_inputs=True)[0] # unscale the grad inv_scale = 1. / loss_scaler.get_scale() grad = grad * inv_scale elif use_apex_amp: from apex.amp._amp_state import _amp_state # by default, we use loss_scalers[0] for discriminator and # loss_scalers[1] for generator _loss_scaler = _amp_state.loss_scalers[1] loss = _loss_scaler.loss_scale() * ((fake_img * noise).sum()).float() grad = autograd.grad( outputs=loss, inputs=latents, grad_outputs=torch.ones(()).to(loss), create_graph=True, retain_graph=True, only_inputs=True)[0] # unscale the grad inv_scale = 1. / _loss_scaler.loss_scale() grad = grad * inv_scale else: grad = autograd.grad( outputs=(fake_img * noise).sum(), inputs=latents, grad_outputs=torch.ones(()).to(fake_img), create_graph=True, retain_graph=True, only_inputs=True)[0] path_lengths = torch.sqrt(grad.pow(2).sum(2).mean(1)) # update mean path path_mean = mean_path_length + decay * ( path_lengths.mean() - mean_path_length) if sync_mean_buffer and is_distributed(): dist.all_reduce(path_mean) path_mean = path_mean / float(dist.get_world_size()) path_penalty = (path_lengths - path_mean).pow(2).mean() * weight return path_penalty, path_mean.detach(), path_lengths ================================================ FILE: mmagic/models/losses/gradient_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS from .pixelwise_loss import l1_loss _reduction_modes = ['none', 'mean', 'sum'] @MODELS.register_module() class GradientLoss(nn.Module): """Gradient loss. Args: loss_weight (float): Loss weight for L1 loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean') -> None: super().__init__() self.loss_weight = loss_weight self.reduction = reduction if self.reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {self.reduction}. ' f'Supported ones are: {_reduction_modes}') def forward(self, pred: torch.Tensor, target: torch.Tensor, weight: Optional[torch.Tensor] = None) -> torch.Tensor: """ Args: pred (Tensor): of shape (N, C, H, W). Predicted tensor. target (Tensor): of shape (N, C, H, W). Ground truth tensor. weight (Tensor, optional): of shape (N, C, H, W). Element-wise weights. Default: None. """ kx = torch.Tensor([[1, 0, -1], [2, 0, -2], [1, 0, -1]]).view(1, 1, 3, 3).to(target) ky = torch.Tensor([[1, 2, 1], [0, 0, 0], [-1, -2, -1]]).view(1, 1, 3, 3).to(target) pred_grad_x = F.conv2d(pred, kx, padding=1) pred_grad_y = F.conv2d(pred, ky, padding=1) target_grad_x = F.conv2d(target, kx, padding=1) target_grad_y = F.conv2d(target, ky, padding=1) loss = ( l1_loss( pred_grad_x, target_grad_x, weight, reduction=self.reduction) + l1_loss( pred_grad_y, target_grad_y, weight, reduction=self.reduction)) return loss * self.loss_weight ================================================ FILE: mmagic/models/losses/loss_comps/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .clip_loss_comps import CLIPLossComps from .disc_auxiliary_loss_comps import (DiscShiftLossComps, GradientPenaltyLossComps, R1GradientPenaltyComps) from .face_id_loss_comps import FaceIdLossComps from .gan_loss_comps import GANLossComps from .gen_auxiliary_loss_comps import GeneratorPathRegularizerComps __all__ = [ 'CLIPLossComps', 'DiscShiftLossComps', 'GradientPenaltyLossComps', 'R1GradientPenaltyComps', 'FaceIdLossComps', 'GANLossComps', 'GeneratorPathRegularizerComps' ] ================================================ FILE: mmagic/models/losses/loss_comps/clip_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS from ..clip_loss import CLIPLossModel @MODELS.register_module() class CLIPLossComps(nn.Module): """Clip loss. In styleclip, this loss is used to optimize the latent code to generate image that match the text. In this loss, we may need to provide ``image``, ``text``. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( image='fake_imgs', text='descriptions') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. clip_model (dict, optional): Kwargs for clip loss model. Defaults to dict(). loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_clip'. """ def __init__(self, loss_weight: float = 1.0, data_info: Optional[dict] = None, clip_model: dict = dict(), loss_name: str = 'loss_clip') -> None: super().__init__() self.loss_weight = loss_weight self.data_info = data_info self.net = CLIPLossModel(**clip_model) self._loss_name = loss_name def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``third_party_net_loss``. """ # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) return self.net(*args, **kwargs) * self.loss_weight @staticmethod def loss_name() -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return 'clip_loss' ================================================ FILE: mmagic/models/losses/loss_comps/disc_auxiliary_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS from ..gan_loss import (disc_shift_loss, gradient_penalty_loss, r1_gradient_penalty_loss) @MODELS.register_module() class DiscShiftLossComps(nn.Module): """Disc Shift Loss. This loss is proposed in PGGAN as an auxiliary loss for discriminator. **Note for the design of ``data_info``:** In ``MMagic``, almost all of loss modules contain the argument ``data_info``, which can be used for constructing the link between the input items (needed in loss calculation) and the data from the generative model. For example, in the training of GAN model, we will collect all of important data/modules into a dictionary: .. code-block:: python :caption: Code from StaticUnconditionalGAN, train_step :linenos: data_dict_ = dict( gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs, iteration=curr_iter, batch_size=batch_size) But in this loss, we will need to provide ``pred`` as input. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( pred='disc_pred_fake') Then, the module will automatically construct this mapping from the input data dictionary. In addition, in general, ``disc_shift_loss`` will be applied over real and fake data. In this case, users just need to add this loss module twice, but with different ``data_info``. Our model will automatically add these two items. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_disc_shift'. """ def __init__(self, loss_weight: float = 1.0, data_info: Optional[dict] = None, loss_name: str = 'loss_disc_shift') -> None: super().__init__() self.loss_weight = loss_weight self.data_info = data_info self._loss_name = loss_name def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``disc_shift_loss``. """ # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) return disc_shift_loss(**kwargs) * self.loss_weight else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. return disc_shift_loss(*args, **kwargs) * self.loss_weight def loss_name(self) -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return self._loss_name @MODELS.register_module() class GradientPenaltyLossComps(nn.Module): """Gradient Penalty for WGAN-GP. In the detailed implementation, there are two streams where one uses the pixel-wise gradient norm, but the other adopts normalization along instance (HWC) dimensions. Thus, ``norm_mode`` are offered to define which mode you want. **Note for the design of ``data_info``:** In ``MMagic``, almost all of loss modules contain the argument ``data_info``, which can be used for constructing the link between the input items (needed in loss calculation) and the data from the generative model. For example, in the training of GAN model, we will collect all of important data/modules into a dictionary: .. code-block:: python :caption: Code from StaticUnconditionalGAN, train_step :linenos: data_dict_ = dict( gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs, iteration=curr_iter, batch_size=batch_size) But in this loss, we will need to provide ``discriminator``, ``real_data``, and ``fake_data`` as input. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( discriminator='disc', real_data='real_imgs', fake_data='fake_imgs') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. norm_mode (str): This argument decides along which dimension the norm of the gradients will be calculated. Currently, we support ["pixel" , "HWC"]. Defaults to "pixel". loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_gp'. """ def __init__(self, loss_weight: float = 1.0, norm_mode: str = 'pixel', data_info: Optional[dict] = None, loss_name: str = 'loss_gp') -> None: super().__init__() self.loss_weight = loss_weight self.norm_mode = norm_mode self.data_info = data_info self._loss_name = loss_name def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``gradient_penalty_loss``. """ # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) # kwargs.update( # dict(weight=self.loss_weight, norm_mode=self.norm_mode)) kwargs.update(dict(norm_mode=self.norm_mode)) return gradient_penalty_loss(**kwargs) * self.loss_weight else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. # return gradient_penalty_loss( # *args, weight=self.loss_weight, **kwargs) return gradient_penalty_loss(*args, **kwargs) * self.loss_weight def loss_name(self) -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return self._loss_name @MODELS.register_module() class R1GradientPenaltyComps(nn.Module): """R1 gradient penalty for WGAN-GP. R1 regularizer comes from: "Which Training Methods for GANs do actually Converge?" ICML'2018 Different from original gradient penalty, this regularizer only penalized gradient w.r.t. real data. **Note for the design of ``data_info``:** In ``MMagic``, almost all of loss modules contain the argument ``data_info``, which can be used for constructing the link between the input items (needed in loss calculation) and the data from the generative model. For example, in the training of GAN model, we will collect all of important data/modules into a dictionary: .. code-block:: python :caption: Code from StaticUnconditionalGAN, train_step :linenos: data_dict_ = dict( gen=self.generator, disc=self.discriminator, disc_pred_fake=disc_pred_fake, disc_pred_real=disc_pred_real, fake_imgs=fake_imgs, real_imgs=real_imgs, iteration=curr_iter, batch_size=batch_size) But in this loss, we will need to provide ``discriminator`` and ``real_data`` as input. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( discriminator='disc', real_data='real_imgs') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. norm_mode (str): This argument decides along which dimension the norm of the gradients will be calculated. Currently, we support ["pixel" , "HWC"]. Defaults to "pixel". interval (int, optional): The interval of calculating this loss. Defaults to 1. loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_r1_gp'. """ def __init__(self, loss_weight: float = 1.0, norm_mode: str = 'pixel', interval: int = 1, data_info: Optional[dict] = None, use_apex_amp: bool = False, loss_name: str = 'loss_r1_gp') -> None: super().__init__() self.loss_weight = loss_weight self.norm_mode = norm_mode self.interval = interval self.data_info = data_info self.use_apex_amp = use_apex_amp self._loss_name = loss_name def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``r1_gradient_penalty_loss``. """ if self.interval > 1: assert self.data_info is not None # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') if self.interval > 1 and outputs_dict[ 'iteration'] % self.interval != 0: return None # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) kwargs.update( dict(norm_mode=self.norm_mode, use_apex_amp=self.use_apex_amp)) return r1_gradient_penalty_loss(**kwargs) * self.loss_weight else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. return r1_gradient_penalty_loss( *args, norm_mode=self.norm_mode, **kwargs) * self.loss_weight def loss_name(self) -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return self._loss_name ================================================ FILE: mmagic/models/losses/loss_comps/face_id_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS @MODELS.register_module() class FaceIdLossComps(nn.Module): """Face similarity loss. Generally this loss is used to keep the id consistency of the input face image and output face image. In this loss, we may need to provide ``gt``, ``pred`` and ``x``. Thus, an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( gt='real_imgs', pred='fake_imgs') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. facenet (dict, optional): Config dict for facenet. Defaults to dict(type='ArcFace', ir_se50_weights=None). loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_id'. """ def __init__(self, loss_weight: float = 1.0, data_info: Optional[dict] = None, facenet: dict = dict(type='ArcFace', ir_se50_weights=None), loss_name: str = 'loss_id') -> None: super().__init__() self.loss_weight = loss_weight self.data_info = data_info self.net = MODELS.build(facenet) self._loss_name = loss_name def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``third_party_net_loss``. """ # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) # NOTE: only return the loss term return self.net(*args, **kwargs)[0] * self.loss_weight def loss_name(self) -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return self._loss_name ================================================ FILE: mmagic/models/losses/loss_comps/gan_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Union import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS @MODELS.register_module() class GANLossComps(nn.Module): """Define GAN loss. Args: gan_type (str): Support 'vanilla', 'lsgan', 'wgan', 'hinge', 'wgan-logistic-ns'. real_label_val (float): The value for real label. Default: 1.0. fake_label_val (float): The value for fake label. Default: 0.0. loss_weight (float): Loss weight. Default: 1.0. Note that loss_weight is only for generators; and it is always 1.0 for discriminators. """ def __init__(self, gan_type: str, real_label_val: float = 1.0, fake_label_val: float = 0.0, loss_weight: float = 1.0) -> None: super().__init__() self.gan_type = gan_type self.loss_weight = loss_weight self.real_label_val = real_label_val self.fake_label_val = fake_label_val if self.gan_type == 'vanilla': self.loss = nn.BCEWithLogitsLoss() elif self.gan_type == 'lsgan': self.loss = nn.MSELoss() elif self.gan_type == 'wgan': self.loss = self._wgan_loss elif self.gan_type == 'wgan-logistic-ns': self.loss = self._wgan_logistic_ns_loss elif self.gan_type == 'hinge': self.loss = nn.ReLU() else: raise NotImplementedError( f'GAN type {self.gan_type} is not implemented.') def _wgan_loss(self, input: torch.Tensor, target: bool) -> torch.Tensor: """wgan loss. Args: input (Tensor): Input tensor. target (bool): Target label. Returns: Tensor: wgan loss. """ return -input.mean() if target else input.mean() def _wgan_logistic_ns_loss(self, input: torch.Tensor, target: bool) -> torch.Tensor: """WGAN loss in logistically non-saturating mode. This loss is widely used in StyleGANv2. Args: input (Tensor): Input tensor. target (bool): Target label. Returns: Tensor: wgan loss. """ return F.softplus(-input).mean() if target else F.softplus( input).mean() def get_target_label(self, input: torch.Tensor, target_is_real: bool) -> Union[bool, torch.Tensor]: """Get target label. Args: input (Tensor): Input tensor. target_is_real (bool): Whether the target is real or fake. Returns: (bool | Tensor): Target tensor. Return bool for wgan, otherwise, \ return Tensor. """ if self.gan_type in ['wgan', 'wgan-logistic-ns']: return target_is_real target_val = ( self.real_label_val if target_is_real else self.fake_label_val) return input.new_ones(input.size()) * target_val def forward(self, input: torch.Tensor, target_is_real: bool, is_disc: bool = False) -> torch.Tensor: """ Args: input (Tensor): The input for the loss module, i.e., the network prediction. target_is_real (bool): Whether the targe is real or fake. is_disc (bool): Whether the loss for discriminators or not. Default: False. Returns: Tensor: GAN loss value. """ target_label = self.get_target_label(input, target_is_real) if self.gan_type == 'hinge': if is_disc: # for discriminators in hinge-gan input = -input if target_is_real else input loss = self.loss(1 + input).mean() else: # for generators in hinge-gan loss = -input.mean() else: # other gan types loss = self.loss(input, target_label) # loss_weight is always 1.0 for discriminators return loss if is_disc else loss * self.loss_weight ================================================ FILE: mmagic/models/losses/loss_comps/gen_auxiliary_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn from mmagic.registry import MODELS from ..gan_loss import gen_path_regularizer @MODELS.register_module() class GeneratorPathRegularizerComps(nn.Module): """Generator Path Regularizer. Path regularization is proposed in StyleGAN2, which can help the improve the continuity of the latent space. More details can be found in: Analyzing and Improving the Image Quality of StyleGAN, CVPR2020. Users can achieve lazy regularization by setting ``interval`` arguments here. **Note for the design of ``data_info``:** In ``MMagic``, almost all of loss modules contain the argument ``data_info``, which can be used for constructing the link between the input items (needed in loss calculation) and the data from the generative model. For example, in the training of GAN model, we will collect all of important data/modules into a dictionary: .. code-block:: python :caption: Code from StaticUnconditionalGAN, train_step :linenos: data_dict_ = dict( gen=self.generator, disc=self.discriminator, fake_imgs=fake_imgs, disc_pred_fake_g=disc_pred_fake_g, iteration=curr_iter, batch_size=batch_size) But in this loss, we will need to provide ``generator`` and ``num_batches`` as input. Thus an example of the ``data_info`` is: .. code-block:: python :linenos: data_info = dict( generator='gen', num_batches='batch_size') Then, the module will automatically construct this mapping from the input data dictionary. Args: loss_weight (float, optional): Weight of this loss item. Defaults to ``1.``. pl_batch_shrink (int, optional): The factor of shrinking the batch size for saving GPU memory. Defaults to 1. decay (float, optional): Decay for moving average of mean path length. Defaults to 0.01. pl_batch_size (int | None, optional): The batch size in calculating generator path. Once this argument is set, the ``num_batches`` will be overridden with this argument and won't be affected by ``pl_batch_shrink``. Defaults to None. sync_mean_buffer (bool, optional): Whether to sync mean path length across all of GPUs. Defaults to False. interval (int, optional): The interval of calculating this loss. This argument is used to support lazy regularization. Defaults to 1. data_info (dict, optional): Dictionary contains the mapping between loss input args and data dictionary. If ``None``, this module will directly pass the input data to the loss function. Defaults to None. loss_name (str, optional): Name of the loss item. If you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Defaults to 'loss_path_regular'. """ def __init__(self, loss_weight: float = 1., pl_batch_shrink: int = 1, decay: float = 0.01, pl_batch_size: Optional[int] = None, sync_mean_buffer: bool = False, interval: int = 1, data_info: Optional[dict] = None, use_apex_amp: bool = False, loss_name: str = 'loss_path_regular') -> None: super().__init__() self.loss_weight = loss_weight self.pl_batch_shrink = pl_batch_shrink self.decay = decay self.pl_batch_size = pl_batch_size self.sync_mean_buffer = sync_mean_buffer self.interval = interval self.data_info = data_info self.use_apex_amp = use_apex_amp self._loss_name = loss_name self.register_buffer('mean_path_length', torch.tensor(0.)) def forward(self, *args, **kwargs) -> torch.Tensor: """Forward function. If ``self.data_info`` is not ``None``, a dictionary containing all of the data and necessary modules should be passed into this function. If this dictionary is given as a non-keyword argument, it should be offered as the first argument. If you are using keyword argument, please name it as `outputs_dict`. If ``self.data_info`` is ``None``, the input argument or key-word argument will be directly passed to loss function, ``gen_path_regularizer``. """ if self.interval > 1: assert self.data_info is not None # use data_info to build computational path if self.data_info is not None: # parse the args and kwargs if len(args) == 1: assert isinstance(args[0], dict), ( 'You should offer a dictionary containing network outputs ' 'for building up computational graph of this loss module.') outputs_dict = args[0] elif 'outputs_dict' in kwargs: assert len(args) == 0, ( 'If the outputs dict is given in keyworded arguments, no' ' further non-keyworded arguments should be offered.') outputs_dict = kwargs.pop('outputs_dict') else: raise NotImplementedError( 'Cannot parsing your arguments passed to this loss module.' ' Please check the usage of this module') if self.interval > 1 and outputs_dict[ 'iteration'] % self.interval != 0: return None # link the outputs with loss input args according to self.data_info loss_input_dict = { k: outputs_dict[v] for k, v in self.data_info.items() } kwargs.update(loss_input_dict) kwargs.update( dict( # weight=self.loss_weight, mean_path_length=self.mean_path_length, pl_batch_shrink=self.pl_batch_shrink, decay=self.decay, use_apex_amp=self.use_apex_amp, pl_batch_size=self.pl_batch_size, sync_mean_buffer=self.sync_mean_buffer)) path_penalty, self.mean_path_length, _ = gen_path_regularizer( **kwargs) else: # if you have not define how to build computational graph, this # module will just directly return the loss as usual. path_penalty, self.mean_path_length, _ = gen_path_regularizer( *args, **kwargs) return path_penalty * self.loss_weight def loss_name(self) -> str: """Loss Name. This function must be implemented and will return the name of this loss function. This name will be used to combine different loss items by simple sum operation. In addition, if you want this loss item to be included into the backward graph, `loss_` must be the prefix of the name. Returns: str: The name of this loss item. """ return self._loss_name ================================================ FILE: mmagic/models/losses/loss_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import functools from typing import Optional import torch import torch.nn.functional as F def reduce_loss(loss: torch.Tensor, reduction: str) -> torch.Tensor: """Reduce loss as specified. Args: loss (Tensor): Elementwise loss tensor. reduction (str): Options are "none", "mean" and "sum". Returns: Tensor: Reduced loss tensor. """ reduction_enum = F._Reduction.get_enum(reduction) # none: 0, elementwise_mean:1, sum: 2 if reduction_enum == 0: return loss if reduction_enum == 1: return loss.mean() if reduction_enum == 2: return loss.sum() raise ValueError(f'reduction type {reduction} not supported') def mask_reduce_loss(loss: torch.Tensor, weight: Optional[torch.Tensor] = None, reduction: str = 'mean', sample_wise: bool = False) -> torch.Tensor: """Apply element-wise weight and reduce loss. Args: loss (Tensor): Element-wise loss. weight (Tensor): Element-wise weights. Default: None. reduction (str): Same as built-in losses of PyTorch. Options are "none", "mean" and "sum". Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. Returns: Tensor: Processed loss values. """ # if weight is specified, apply element-wise weight if weight is not None: assert weight.dim() == loss.dim() assert weight.size(1) == 1 or weight.size(1) == loss.size(1) loss = loss * weight # if weight is not specified or reduction is sum, just reduce the loss if weight is None or reduction == 'sum': loss = reduce_loss(loss, reduction) # if reduction is mean, then compute mean over masked region elif reduction == 'mean': # expand weight from N1HW to NCHW if weight.size(1) == 1: weight = weight.expand_as(loss) # small value to prevent division by zero eps = 1e-12 # perform sample-wise mean if sample_wise: weight = weight.sum(dim=[1, 2, 3], keepdim=True) # NCHW to N111 loss = (loss / (weight + eps)).sum() / weight.size(0) # perform pixel-wise mean else: loss = loss.sum() / (weight.sum() + eps) return loss def masked_loss(loss_func): """Create a masked version of a given loss function. To use this decorator, the loss function must have the signature like `loss_func(pred, target, **kwargs)`. The function only needs to compute element-wise loss without any reduction. This decorator will add weight and reduction arguments to the function. The decorated function will have the signature like `loss_func(pred, target, weight=None, reduction='mean', avg_factor=None, **kwargs)`. :Example: >>> import torch >>> @masked_loss >>> def l1_loss(pred, target): >>> return (pred - target).abs() >>> pred = torch.Tensor([0, 2, 3]) >>> target = torch.Tensor([1, 1, 1]) >>> weight = torch.Tensor([1, 0, 1]) >>> l1_loss(pred, target) tensor(1.3333) >>> l1_loss(pred, target, weight) tensor(1.5000) >>> l1_loss(pred, target, reduction='none') tensor([1., 1., 2.]) >>> l1_loss(pred, target, weight, reduction='sum') tensor(3.) """ @functools.wraps(loss_func) def wrapper(pred: torch.Tensor, target: torch.Tensor, weight: Optional[torch.Tensor] = None, reduction: str = 'mean', sample_wise: bool = False, **kwargs) -> torch.Tensor: # get element-wise loss loss = loss_func(pred, target, **kwargs) loss = mask_reduce_loss(loss, weight, reduction, sample_wise) return loss return wrapper ================================================ FILE: mmagic/models/losses/perceptual_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List, Optional, Tuple import torch import torch.nn as nn import torchvision.models.vgg as vgg from mmengine import MMLogger from mmengine.runner import load_checkpoint from torch.nn import functional as F from mmagic.registry import MODELS class PerceptualVGG(nn.Module): """VGG network used in calculating perceptual loss. In this implementation, we allow users to choose whether use normalization in the input feature and the type of vgg network. Note that the pretrained path must fit the vgg type. Args: layer_name_list (list[str]): According to the name in this list, forward function will return the corresponding features. This list contains the name each layer in `vgg.feature`. An example of this list is ['4', '10']. vgg_type (str): Set the type of vgg network. Default: 'vgg19'. use_input_norm (bool): If True, normalize the input image. Importantly, the input feature must in the range [0, 1]. Default: True. pretrained (str): Path for pretrained weights. Default: 'torchvision://vgg19' """ def __init__(self, layer_name_list: List[str], vgg_type: str = 'vgg19', use_input_norm: bool = True, pretrained: str = 'torchvision://vgg19') -> None: super().__init__() if pretrained.startswith('torchvision://'): assert vgg_type in pretrained self.layer_name_list = layer_name_list self.use_input_norm = use_input_norm # get vgg model and load pretrained vgg weight # remove _vgg from attributes to avoid `find_unused_parameters` bug _vgg = getattr(vgg, vgg_type)(pretrained=True) # self.init_weights(_vgg, pretrained) #TODO urlopen error num_layers = max(map(int, layer_name_list)) + 1 assert len(_vgg.features) >= num_layers # only borrow layers that will be used from _vgg to avoid unused params self.vgg_layers = _vgg.features[:num_layers] if self.use_input_norm: # the mean is for image with range [0, 1] self.register_buffer( 'mean', torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1)) # the std is for image with range [-1, 1] self.register_buffer( 'std', torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1)) for v in self.vgg_layers.parameters(): v.requires_grad = False def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.use_input_norm: x = (x - self.mean) / self.std output = {} for name, module in self.vgg_layers.named_children(): x = module(x) if name in self.layer_name_list: output[name] = x.clone() return output def init_weights(self, model: nn.Module, pretrained: str) -> None: """Init weights. Args: model (nn.Module): Models to be inited. pretrained (str): Path for pretrained weights. """ logger = MMLogger.get_current_instance() load_checkpoint(model, pretrained, logger=logger) @MODELS.register_module() class PerceptualLoss(nn.Module): """Perceptual loss with commonly used style loss. Args: layers_weights (dict): The weight for each layer of vgg feature for perceptual loss. Here is an example: {'4': 1., '9': 1., '18': 1.}, which means the 5th, 10th and 18th feature layer will be extracted with weight 1.0 in calculating losses. layers_weights_style (dict): The weight for each layer of vgg feature for style loss. If set to 'None', the weights are set equal to the weights for perceptual loss. Default: None. vgg_type (str): The type of vgg network used as feature extractor. Default: 'vgg19'. use_input_norm (bool): If True, normalize the input image in vgg. Default: True. perceptual_weight (float): If `perceptual_weight > 0`, the perceptual loss will be calculated and the loss will multiplied by the weight. Default: 1.0. style_weight (float): If `style_weight > 0`, the style loss will be calculated and the loss will multiplied by the weight. Default: 1.0. norm_img (bool): If True, the image will be normed to [0, 1]. Note that this is different from the `use_input_norm` which norm the input in in forward function of vgg according to the statistics of dataset. Importantly, the input image must be in range [-1, 1]. pretrained (str): Path for pretrained weights. Default: 'torchvision://vgg19'. criterion (str): Criterion type. Options are 'l1' and 'mse'. Default: 'l1'. """ def __init__(self, layer_weights: dict, layer_weights_style: Optional[dict] = None, vgg_type: str = 'vgg19', use_input_norm: bool = True, perceptual_weight: float = 1.0, style_weight: float = 1.0, norm_img: bool = True, pretrained: str = 'torchvision://vgg19', criterion: str = 'l1') -> None: super().__init__() self.norm_img = norm_img self.perceptual_weight = perceptual_weight self.style_weight = style_weight self.layer_weights = layer_weights self.layer_weights_style = layer_weights_style self.vgg = PerceptualVGG( layer_name_list=list(self.layer_weights.keys()), vgg_type=vgg_type, use_input_norm=use_input_norm, pretrained=pretrained) if self.layer_weights_style is not None and \ self.layer_weights_style != self.layer_weights: self.vgg_style = PerceptualVGG( layer_name_list=list(self.layer_weights_style.keys()), vgg_type=vgg_type, use_input_norm=use_input_norm, pretrained=pretrained) else: self.layer_weights_style = self.layer_weights self.vgg_style = None criterion = criterion.lower() if criterion == 'l1': self.criterion = torch.nn.L1Loss() elif criterion == 'mse': self.criterion = torch.nn.MSELoss() else: raise NotImplementedError( f'{criterion} criterion has not been supported in' ' this version.') def forward(self, x: torch.Tensor, gt: torch.Tensor) -> Tuple[torch.Tensor]: """Forward function. Args: x (Tensor): Input tensor with shape (n, c, h, w). gt (Tensor): Ground-truth tensor with shape (n, c, h, w). Returns: Tensor: Forward results. """ if self.norm_img: x = (x + 1.) * 0.5 gt = (gt + 1.) * 0.5 # extract vgg features x_features = self.vgg(x) gt_features = self.vgg(gt.detach()) # calculate perceptual loss if self.perceptual_weight > 0: percep_loss = 0 for k in x_features.keys(): percep_loss += self.criterion( x_features[k], gt_features[k]) * self.layer_weights[k] percep_loss *= self.perceptual_weight else: percep_loss = None # calculate style loss if self.style_weight > 0: if self.vgg_style is not None: x_features = self.vgg_style(x) gt_features = self.vgg_style(gt.detach()) style_loss = 0 for k in x_features.keys(): style_loss += self.criterion( self._gram_mat(x_features[k]), self._gram_mat( gt_features[k])) * self.layer_weights_style[k] style_loss *= self.style_weight else: style_loss = None return percep_loss, style_loss def _gram_mat(self, x: torch.Tensor) -> torch.Tensor: """Calculate Gram matrix. Args: x (torch.Tensor): Tensor with shape of (n, c, h, w). Returns: torch.Tensor: Gram matrix. """ (n, c, h, w) = x.size() features = x.view(n, c, w * h) features_t = features.transpose(1, 2) gram = features.bmm(features_t) / (c * h * w) return gram @MODELS.register_module() class TransferalPerceptualLoss(nn.Module): """Transferal perceptual loss. Args: loss_weight (float): Loss weight. Default: 1.0. use_attention (bool): If True, use soft-attention tensor. Default: True criterion (str): Criterion type. Options are 'l1' and 'mse'. Default: 'mse'. """ def __init__(self, loss_weight: float = 1.0, use_attention: bool = True, criterion: str = 'mse') -> None: super().__init__() self.use_attention = use_attention self.loss_weight = loss_weight criterion = criterion.lower() if criterion == 'l1': self.loss_function = torch.nn.L1Loss() elif criterion == 'mse': self.loss_function = torch.nn.MSELoss() else: raise ValueError( f"criterion should be 'l1' or 'mse', but got {criterion}") def forward(self, maps: Tuple[torch.Tensor], soft_attention: torch.Tensor, textures: Tuple[torch.Tensor]) -> torch.Tensor: """Forward function. Args: maps (Tuple[Tensor]): Input tensors. soft_attention (Tensor): Soft-attention tensor. textures (Tuple[Tensor]): Ground-truth tensors. Returns: Tensor: Forward results. """ if self.use_attention: h, w = soft_attention.shape[-2:] softs = [torch.sigmoid(soft_attention)] for i in range(1, len(maps)): softs.append( F.interpolate( soft_attention, size=(h * pow(2, i), w * pow(2, i)), mode='bicubic', align_corners=False)) else: softs = [1., 1., 1.] loss_texture = 0 for map, soft, texture in zip(maps, softs, textures): loss_texture += self.loss_function(map * soft, texture * soft) return loss_texture * self.loss_weight ================================================ FILE: mmagic/models/losses/pixelwise_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Optional import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS from .loss_wrapper import masked_loss _reduction_modes = ['none', 'mean', 'sum'] @masked_loss def l1_loss(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: """L1 loss. Args: pred (Tensor): Prediction Tensor with shape (n, c, h, w). target ([type]): Target Tensor with shape (n, c, h, w). Returns: Tensor: Calculated L1 loss. """ return F.l1_loss(pred, target, reduction='none') @masked_loss def mse_loss(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: """MSE loss. Args: pred (Tensor): Prediction Tensor with shape (n, c, h, w). target ([type]): Target Tensor with shape (n, c, h, w). Returns: Tensor: Calculated MSE loss. """ return F.mse_loss(pred, target, reduction='none') @masked_loss def charbonnier_loss(pred: torch.Tensor, target: torch.Tensor, eps: float = 1e-12) -> torch.Tensor: """Charbonnier loss. Args: pred (Tensor): Prediction Tensor with shape (n, c, h, w). target ([type]): Target Tensor with shape (n, c, h, w). eps (float): A value used to control the curvature near zero. Default: 1e-12. Returns: Tensor: Calculated Charbonnier loss. """ return torch.sqrt((pred - target)**2 + eps) def tv_loss(input: torch.Tensor) -> torch.Tensor: """L2 total variation loss, as in Mahendran et al.""" input = F.pad(input, (0, 1, 0, 1), 'replicate') x_diff = input[..., :-1, 1:] - input[..., :-1, :-1] y_diff = input[..., 1:, :-1] - input[..., :-1, :-1] return (x_diff**2 + y_diff**2).mean([1, 2, 3]) @MODELS.register_module() class L1Loss(nn.Module): """L1 (mean absolute error, MAE) loss. Args: loss_weight (float): Loss weight for L1 loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduce loss with 'mean' per-sample, and then it means over all the samples. Default: False. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise def forward(self, pred: torch.Tensor, target: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """Forward Function. Args: pred (Tensor): of shape (N, C, H, W). Predicted tensor. target (Tensor): of shape (N, C, H, W). Ground truth tensor. weight (Tensor, optional): of shape (N, C, H, W). Element-wise weights. Default: None. """ return self.loss_weight * l1_loss( pred, target, weight, reduction=self.reduction, sample_wise=self.sample_wise) @MODELS.register_module() class MSELoss(nn.Module): """MSE (L2) loss. Args: loss_weight (float): Loss weight for MSE loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise def forward(self, pred: torch.Tensor, target: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """Forward Function. Args: pred (Tensor): of shape (N, C, H, W). Predicted tensor. target (Tensor): of shape (N, C, H, W). Ground truth tensor. weight (Tensor, optional): of shape (N, C, H, W). Element-wise weights. Default: None. """ return self.loss_weight * mse_loss( pred, target, weight, reduction=self.reduction, sample_wise=self.sample_wise) @MODELS.register_module() class CharbonnierLoss(nn.Module): """Charbonnier loss (one variant of Robust L1Loss, a differentiable variant of L1Loss). Described in "Deep Laplacian Pyramid Networks for Fast and Accurate Super-Resolution". Args: loss_weight (float): Loss weight for L1 loss. Default: 1.0. reduction (str): Specifies the reduction to apply to the output. Supported choices are 'none' | 'mean' | 'sum'. Default: 'mean'. sample_wise (bool): Whether calculate the loss sample-wise. This argument only takes effect when `reduction` is 'mean' and `weight` (argument of `forward()`) is not None. It will first reduces loss with 'mean' per-sample, and then it means over all the samples. Default: False. eps (float): A value used to control the curvature near zero. Default: 1e-12. """ def __init__(self, loss_weight: float = 1.0, reduction: str = 'mean', sample_wise: bool = False, eps: float = 1e-12) -> None: super().__init__() if reduction not in ['none', 'mean', 'sum']: raise ValueError(f'Unsupported reduction mode: {reduction}. ' f'Supported ones are: {_reduction_modes}') self.loss_weight = loss_weight self.reduction = reduction self.sample_wise = sample_wise self.eps = eps def forward(self, pred: torch.Tensor, target: torch.Tensor, weight: Optional[torch.Tensor] = None, **kwargs) -> torch.Tensor: """Forward Function. Args: pred (Tensor): of shape (N, C, H, W). Predicted tensor. target (Tensor): of shape (N, C, H, W). Ground truth tensor. weight (Tensor, optional): of shape (N, C, H, W). Element-wise weights. Default: None. """ return self.loss_weight * charbonnier_loss( pred, target, weight, eps=self.eps, reduction=self.reduction, sample_wise=self.sample_wise) @MODELS.register_module() class MaskedTVLoss(L1Loss): """Masked TV loss. Args: loss_weight (float, optional): Loss weight. Defaults to 1.0. """ def __init__(self, loss_weight: float = 1.0) -> None: super().__init__(loss_weight=loss_weight) def forward(self, pred: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor: """Forward function. Args: pred (torch.Tensor): Tensor with shape of (n, c, h, w). mask (torch.Tensor, optional): Tensor with shape of (n, 1, h, w). Defaults to None. Returns: [type]: [description] """ y_diff = super().forward( pred[:, :, :-1, :], pred[:, :, 1:, :], weight=mask[:, :, :-1, :]) x_diff = super().forward( pred[:, :, :, :-1], pred[:, :, :, 1:], weight=mask[:, :, :, :-1]) loss = x_diff + y_diff return loss @MODELS.register_module() class PSNRLoss(nn.Module): """PSNR Loss in "HINet: Half Instance Normalization Network for Image Restoration". Args: loss_weight (float, optional): Loss weight. Defaults to 1.0. reduction: reduction for PSNR. Can only be mean here. toY: change to calculate the PSNR of Y channel in YCbCr format """ def __init__(self, loss_weight: float = 1.0, toY: bool = False) -> None: super(PSNRLoss, self).__init__() self.loss_weight = loss_weight import numpy as np self.scale = 10 / np.log(10) self.toY = toY self.coef = torch.tensor([65.481, 128.553, 24.966]).reshape(1, 3, 1, 1) self.first = True def forward(self, pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: assert len(pred.size()) == 4 return self.loss_weight * self.scale * torch.log(( (pred - target)**2).mean(dim=(1, 2, 3)) + 1e-8).mean() ================================================ FILE: mmagic/models/utils/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .bbox_utils import extract_around_bbox, extract_bbox_patch from .flow_warp import flow_warp from .model_utils import (build_module, default_init_weights, generation_init_weights, get_module_device, get_valid_noise_size, get_valid_num_batches, make_layer, remove_tomesd, set_requires_grad, set_tomesd, set_xformers, xformers_is_enable) from .sampling_utils import label_sample_fn, noise_sample_fn from .tensor_utils import get_unknown_tensor, normalize_vecs __all__ = [ 'default_init_weights', 'make_layer', 'flow_warp', 'generation_init_weights', 'set_requires_grad', 'extract_bbox_patch', 'extract_around_bbox', 'get_unknown_tensor', 'noise_sample_fn', 'label_sample_fn', 'get_valid_num_batches', 'get_valid_noise_size', 'get_module_device', 'normalize_vecs', 'build_module', 'set_xformers', 'xformers_is_enable', 'set_tomesd', 'remove_tomesd' ] ================================================ FILE: mmagic/models/utils/bbox_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch def extract_bbox_patch(bbox, img, channel_first=True): """Extract patch from a given bbox. Args: bbox (torch.Tensor | numpy.array): Bbox with (top, left, h, w). If `img` has batch dimension, the `bbox` must be stacked at first dimension. The shape should be (4,) or (n, 4). img (torch.Tensor | numpy.array): Image data to be extracted. If organized in batch dimension, the batch dimension must be the first order like (n, h, w, c) or (n, c, h, w). channel_first (bool): If True, the channel dimension of img is before height and width, e.g. (c, h, w). Otherwise, the img shape (samples in the batch) is like (h, w, c). Default: True. Returns: (torch.Tensor | numpy.array): Extracted patches. The dimension of the \ output should be the same as `img`. """ def _extract(bbox, img): assert len(bbox) == 4 t, l, h, w = bbox if channel_first: img_patch = img[..., t:t + h, l:l + w] else: img_patch = img[t:t + h, l:l + w, ...] return img_patch input_size = img.shape assert len(input_size) == 3 or len(input_size) == 4 bbox_size = bbox.shape assert bbox_size == (4, ) or (len(bbox_size) == 2 and bbox_size[0] == input_size[0]) # images with batch dimension if len(input_size) == 4: output_list = [] for i in range(input_size[0]): img_patch_ = _extract(bbox[i], img[i:i + 1, ...]) output_list.append(img_patch_) if isinstance(img, torch.Tensor): img_patch = torch.cat(output_list, dim=0) else: img_patch = np.concatenate(output_list, axis=0) # standardize image else: img_patch = _extract(bbox, img) return img_patch def scale_bbox(bbox, target_size): """Modify bbox to target size. The original bbox will be enlarged to the target size with the original bbox in the center of the new bbox. Args: bbox (np.ndarray | torch.Tensor): Bboxes to be modified. Bbox can be in batch or not. The shape should be (4,) or (n, 4). target_size (tuple[int]): Target size of final bbox. Returns: (np.ndarray | torch.Tensor): Modified bboxes. """ def _mod(bbox, target_size): top_ori, left_ori, h_ori, w_ori = bbox h, w = target_size assert h >= h_ori and w >= w_ori top = int(max(0, top_ori - (h - h_ori) // 2)) left = int(max(0, left_ori - (w - w_ori) // 2)) if isinstance(bbox, torch.Tensor): bbox_new = torch.Tensor([top, left, h, w]).type_as(bbox) else: bbox_new = np.asarray([top, left, h, w]) return bbox_new if isinstance(bbox, torch.Tensor): bbox_new = torch.zeros_like(bbox) elif isinstance(bbox, np.ndarray): bbox_new = np.zeros_like(bbox) else: raise TypeError('bbox mush be torch.Tensor or numpy.ndarray' f'but got type {type(bbox)}') bbox_shape = list(bbox.shape) if len(bbox_shape) == 2: for i in range(bbox_shape[0]): bbox_new[i, :] = _mod(bbox[i], target_size) else: bbox_new = _mod(bbox, target_size) return bbox_new def extract_around_bbox(img, bbox, target_size, channel_first=True): """Extract patches around the given bbox. Args: img (torch.Tensor | numpy.array): Image data to be extracted. If organized in batch dimension, the batch dimension must be the first order like (n, h, w, c) or (n, c, h, w). bbox (np.ndarray | torch.Tensor): Bboxes to be modified. Bbox can be in batch or not. target_size (List(int)): Target size of final bbox. channel_first (bool): If True, the channel dimension of img is before height and width, e.g. (c, h, w). Otherwise, the img shape (samples in the batch) is like (h, w, c). Default: True. Returns: (torch.Tensor | np.ndarray): Extracted patches. The dimension of the \ output should be the same as `img`. """ bbox_new = scale_bbox(bbox, target_size) img_patch = extract_bbox_patch(bbox_new, img, channel_first=channel_first) return img_patch, bbox_new ================================================ FILE: mmagic/models/utils/diffusion_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import numpy as np def betas_for_alpha_bar(num_diffusion_timesteps, max_beta=0.999): """Create a beta schedule that discretized the given alpha_t_bar function, which defines the cumulative product of (1-beta) over time from t = [0,1]. Source: https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_ddim.py#L49 # noqa """ def alpha_bar(time_step): return math.cos((time_step + 0.008) / 1.008 * math.pi / 2)**2 betas = [] for i in range(num_diffusion_timesteps): t1 = i / num_diffusion_timesteps t2 = (i + 1) / num_diffusion_timesteps betas.append(min(1 - alpha_bar(t2) / alpha_bar(t1), max_beta)) return np.array(betas, dtype=np.float64) ================================================ FILE: mmagic/models/utils/flow_warp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn.functional as F def flow_warp(x, flow, interpolation='bilinear', padding_mode='zeros', align_corners=True): """Warp an image or a feature map with optical flow. Args: x (Tensor): Tensor with size (n, c, h, w). flow (Tensor): Tensor with size (n, h, w, 2). The last dimension is a two-channel, denoting the width and height relative offsets. Note that the values are not normalized to [-1, 1]. interpolation (str): Interpolation mode: 'nearest' or 'bilinear'. Default: 'bilinear'. padding_mode (str): Padding mode: 'zeros' or 'border' or 'reflection'. Default: 'zeros'. align_corners (bool): Whether align corners. Default: True. Returns: Tensor: Warped image or feature map. """ if x.size()[-2:] != flow.size()[1:3]: raise ValueError(f'The spatial sizes of input ({x.size()[-2:]}) and ' f'flow ({flow.size()[1:3]}) are not the same.') _, _, h, w = x.size() # create mesh grid device = flow.device # torch.meshgrid has been modified in 1.10.0 (compatibility with previous # versions), and will be further modified in 1.12 (Breaking Change) if 'indexing' in torch.meshgrid.__code__.co_varnames: grid_y, grid_x = torch.meshgrid( torch.arange(0, h, device=device, dtype=x.dtype), torch.arange(0, w, device=device, dtype=x.dtype), indexing='ij') else: grid_y, grid_x = torch.meshgrid( torch.arange(0, h, device=device, dtype=x.dtype), torch.arange(0, w, device=device, dtype=x.dtype)) grid = torch.stack((grid_x, grid_y), 2) # h, w, 2 grid.requires_grad = False grid_flow = grid + flow # scale grid_flow to [-1,1] grid_flow_x = 2.0 * grid_flow[:, :, :, 0] / max(w - 1, 1) - 1.0 grid_flow_y = 2.0 * grid_flow[:, :, :, 1] / max(h - 1, 1) - 1.0 grid_flow = torch.stack((grid_flow_x, grid_flow_y), dim=3) grid_flow = grid_flow.type(x.type()) output = F.grid_sample( x, grid_flow, mode=interpolation, padding_mode=padding_mode, align_corners=align_corners) return output ================================================ FILE: mmagic/models/utils/model_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import logging from typing import Any, Dict, List, Optional, Union import torch import torch.nn as nn from mmengine import print_log from mmengine.model.weight_init import (constant_init, kaiming_init, normal_init, update_init_info, xavier_init) from mmengine.registry import Registry from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from torch import Tensor from torch.nn import init from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs from .tome_utils import (add_tome_cfg_hook, build_mmagic_tomesd_block, build_mmagic_wrapper_tomesd_block, isinstance_str) def default_init_weights(module, scale=1): """Initialize network weights. Args: modules (nn.Module): Modules to be initialized. scale (float): Scale initialized weights, especially for residual blocks. Default: 1. """ for m in module.modules(): if isinstance(m, nn.Conv2d): kaiming_init(m, a=0, mode='fan_in', bias=0) m.weight.data *= scale elif isinstance(m, nn.Linear): kaiming_init(m, a=0, mode='fan_in', bias=0) m.weight.data *= scale elif isinstance(m, _BatchNorm): constant_init(m.weight, val=1, bias=0) def make_layer(block, num_blocks, **kwarg): """Make layers by stacking the same blocks. Args: block (nn.module): nn.module class for basic block. num_blocks (int): number of blocks. Returns: nn.Sequential: Stacked blocks in nn.Sequential. """ layers = [] for _ in range(num_blocks): layers.append(block(**kwarg)) return nn.Sequential(*layers) def get_module_device(module): """Get the device of a module. Args: module (nn.Module): A module contains the parameters. Returns: torch.device: The device of the module. """ try: next(module.parameters()) except StopIteration: raise ValueError('The input module should contain parameters.') if next(module.parameters()).is_cuda: return next(module.parameters()).get_device() else: return torch.device('cpu') def set_requires_grad(nets, requires_grad=False): """Set requires_grad for all the networks. Args: nets (nn.Module | list[nn.Module]): A list of networks or a single network. requires_grad (bool): Whether the networks require gradients or not """ if not isinstance(nets, list): nets = [nets] for net in nets: if net is not None: for param in net.parameters(): param.requires_grad = requires_grad def generation_init_weights(module, init_type='normal', init_gain=0.02): """Default initialization of network weights for image generation. By default, we use normal init, but xavier and kaiming might work better for some applications. Args: module (nn.Module): Module to be initialized. init_type (str): The name of an initialization method: normal | xavier | kaiming | orthogonal. Default: 'normal'. init_gain (float): Scaling factor for normal, xavier and orthogonal. Default: 0.02. """ def init_func(m): """Initialization function. Args: m (nn.Module): Module to be initialized. """ classname = m.__class__.__name__ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): if init_type == 'normal': normal_init(m, 0.0, init_gain) elif init_type == 'xavier': xavier_init(m, gain=init_gain, distribution='normal') elif init_type == 'kaiming': kaiming_init( m, a=0, mode='fan_in', nonlinearity='leaky_relu', distribution='normal') elif init_type == 'orthogonal': init.orthogonal_(m.weight, gain=init_gain) init.constant_(m.bias.data, 0.0) else: raise NotImplementedError( f"Initialization method '{init_type}' is not implemented") init_info = (f'Initialize {m.__class__.__name__} by \'init_type\' ' f'{init_type}.') elif classname.find('BatchNorm2d') != -1: # BatchNorm Layer's weight is not a matrix; # only normal distribution applies. normal_init(m, 1.0, init_gain) init_info = (f'{m.__class__.__name__} is BatchNorm2d, initialize ' 'by Norm initialization with mean=1, ' f'std={init_gain}') if hasattr(m, '_params_init_info'): update_init_info(module, init_info) module.apply(init_func) def get_valid_noise_size(noise_size: Optional[int], generator: Union[Dict, nn.Module]) -> Optional[int]: """Get the value of `noise_size` from input, `generator` and check the consistency of these values. If no conflict is found, return that value. Args: noise_size (Optional[int]): `noise_size` passed to `BaseGAN_refactor`'s initialize function. generator (ModelType): The config or the model of generator. Returns: int | None: The noise size feed to generator. """ if isinstance(generator, dict): model_noise_size = generator.get('noise_size', None) else: model_noise_size = getattr(generator, 'noise_size', None) # get noise_size if noise_size is not None and model_noise_size is not None: assert noise_size == model_noise_size, ( 'Input \'noise_size\' is inconsistent with ' f'\'generator.noise_size\'. Receive \'{noise_size}\' and ' f'\'{model_noise_size}\'.') else: noise_size = noise_size or model_noise_size return noise_size def get_valid_num_batches(batch_inputs: Optional[ForwardInputs] = None, data_samples: List[DataSample] = None) -> int: """Try get the valid batch size from inputs. - If some values in `batch_inputs` are `Tensor` and 'num_batches' is in `batch_inputs`, we check whether the value of 'num_batches' and the the length of first dimension of all tensors are same. If the values are not same, `AssertionError` will be raised. If all values are the same, return the value. - If no values in `batch_inputs` is `Tensor`, 'num_batches' must be contained in `batch_inputs`. And this value will be returned. - If some values are `Tensor` and 'num_batches' is not contained in `batch_inputs`, we check whether all tensor have the same length on the first dimension. If the length are not same, `AssertionError` will be raised. If all length are the same, return the length as batch size. - If batch_inputs is a `Tensor`, directly return the length of the first dimension as batch size. Args: batch_inputs (ForwardInputs): Inputs passed to :meth:`forward`. Returns: int: The batch size of samples to generate. """ # attempt to infer num_batches from batch_inputs if batch_inputs is not None: if isinstance(batch_inputs, Tensor): return batch_inputs.shape[0] # get num_batches from batch_inputs num_batches_dict = { k: v.shape[0] for k, v in batch_inputs.items() if isinstance(v, Tensor) } if 'num_batches' in batch_inputs: num_batches_dict['num_batches'] = batch_inputs['num_batches'] if num_batches_dict: num_batches_inputs = list(num_batches_dict.values())[0] # ensure all num_batches are same assert all([ bz == num_batches_inputs for bz in num_batches_dict.values() ]), ('\'num_batches\' is inconsistency among the preprocessed ' f'input. \'num_batches\' parsed results: {num_batches_dict}') else: num_batches_inputs = None else: num_batches_inputs = None # attempt to infer num_batches from data_samples if data_samples is not None: num_batches_samples = len(data_samples) else: num_batches_samples = None if not (num_batches_inputs or num_batches_samples): print_log( 'Cannot get \'num_batches\' from both \'inputs\' and ' '\'data_samples\', automatically set \'num_batches\' as 1. ' 'This may leads to potential error.', 'current', logging.WARNING) return 1 elif num_batches_inputs and num_batches_samples: assert num_batches_inputs == num_batches_samples, ( '\'num_batches\' inferred from \'inputs\' and \'data_samples\' ' f'are different, ({num_batches_inputs} vs. {num_batches_samples}).' ' Please check your input carefully.') return num_batches_inputs or num_batches_samples def build_module(module: Union[dict, nn.Module], builder: Registry, *args, **kwargs) -> Any: """Build module from config or return the module itself. Args: module (Union[dict, nn.Module]): The module to build. builder (Registry): The registry to build module. *args, **kwargs: Arguments passed to build function. Returns: Any: The built module. """ if isinstance(module, dict): return builder.build(module, *args, **kwargs) elif isinstance(module, nn.Module): return module else: raise TypeError( f'Only support dict and nn.Module, but got {type(module)}.') def xformers_is_enable(verbose: bool = False) -> bool: """Check whether xformers is installed. Args: verbose (bool): Whether to print the log. Returns: bool: Whether xformers is installed. """ from mmagic.utils import try_import xformers = try_import('xformers') if xformers is None and verbose: print_log('Do not support Xformers.', 'current') return xformers is not None def set_xformers(module: nn.Module, prefix: str = '') -> nn.Module: """Set xformers' efficient Attention for attention modules. Args: module (nn.Module): The module to set xformers. prefix (str): The prefix of the module name. Returns: nn.Module: The module with xformers' efficient Attention. """ if not xformers_is_enable(): print_log('Do not support Xformers. Please install Xformers first. ' 'The program will run without Xformers.') return for n, m in module.named_children(): if hasattr(m, 'set_use_memory_efficient_attention_xformers'): # set xformers for Diffusers' Cross Attention m.set_use_memory_efficient_attention_xformers(True) module_name = f'{prefix}.{n}' if prefix else n print_log( 'Enable Xformers for HuggingFace Diffusers\' ' f'module \'{module_name}\'.', 'current') else: set_xformers(m, prefix=n) return module def set_tomesd(model: torch.nn.Module, ratio: float = 0.5, max_downsample: int = 1, sx: int = 2, sy: int = 2, use_rand: bool = True, merge_attn: bool = True, merge_crossattn: bool = False, merge_mlp: bool = False): """Patches a stable diffusion model with ToMe. Apply this to the highest level stable diffusion object. Refer to: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L173 # noqa Args: model (torch.nn.Module): A top level Stable Diffusion module to patch in place. ratio (float): The ratio of tokens to merge. I.e., 0.4 would reduce the total number of tokens by 40%.The maximum value for this is 1-(1/(`sx` * `sy`)). By default, the max ratio is 0.75 (usually <= 0.5 is recommended). Higher values result in more speed-up, but with more visual quality loss. max_downsample (int): Apply ToMe to layers with at most this amount of downsampling. E.g., 1 only applies to layers with no downsampling, while 8 applies to all layers. Should be chosen from [1, 2, 4, or 8]. 1 and 2 are recommended. sx, sy (int, int): The stride for computing dst sets. A higher stride means you can merge more tokens, default setting of (2, 2) works well in most cases. `sx` and `sy` do not need to divide image size. use_rand (bool): Whether or not to allow random perturbations when computing dst sets. By default: True, but if you're having weird artifacts you can try turning this off. merge_attn (bool): Whether or not to merge tokens for attention (recommended). merge_crossattn (bool): Whether or not to merge tokens for cross attention (not recommended). merge_mlp (bool): Whether or not to merge tokens for the mlp layers (particular not recommended). Returns: model (torch.nn.Module): Model patched by ToMe. """ # Make sure the module is not currently patched remove_tomesd(model) is_mmagic = isinstance_str(model, 'StableDiffusion') or isinstance_str( model, 'BaseModel') if is_mmagic: # Supports "StableDiffusion.unet" and "unet" diffusion_model = model.unet if hasattr(model, 'unet') else model if isinstance_str(diffusion_model, 'DenoisingUnet'): is_wrapper = False else: is_wrapper = True else: if not hasattr(model, 'model') or not hasattr(model.model, 'diffusion_model'): # Provided model not supported print('Expected a Stable Diffusion / Latent Diffusion model.') raise RuntimeError('Provided model was not supported.') diffusion_model = model.model.diffusion_model # TODO: can support more diffusion models, like Stability AI is_wrapper = None diffusion_model._tome_info = { 'size': None, 'hooks': [], 'args': { 'ratio': ratio, 'max_downsample': max_downsample, 'sx': sx, 'sy': sy, 'use_rand': use_rand, 'merge_attn': merge_attn, 'merge_crossattn': merge_crossattn, 'merge_mlp': merge_mlp } } add_tome_cfg_hook(diffusion_model) for _, module in diffusion_model.named_modules(): if isinstance_str(module, 'BasicTransformerBlock'): # TODO: can support more stable diffusion based models if is_mmagic: if is_wrapper is None: raise NotImplementedError( 'Specific ToMe block not implemented') elif not is_wrapper: make_tome_block_fn = build_mmagic_tomesd_block elif is_wrapper: make_tome_block_fn = build_mmagic_wrapper_tomesd_block else: raise TypeError( 'Currently `tome` only support *stable-diffusion* model!') module.__class__ = make_tome_block_fn(module.__class__) module._tome_info = diffusion_model._tome_info return model def remove_tomesd(model: torch.nn.Module): """Removes a patch from a ToMe Diffusion module if it was already patched. Refer to: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L251 # noqa """ # For mmagic Stable Diffusion models model = model.unet if hasattr(model, 'unet') else model for _, module in model.named_modules(): if hasattr(module, '_tome_info'): for hook in module._tome_info['hooks']: hook.remove() module._tome_info['hooks'].clear() if module.__class__.__name__ == 'ToMeBlock': module.__class__ = module._parent return model ================================================ FILE: mmagic/models/utils/sampling_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Callable, List, Optional, Sequence, Union import numpy as np import torch from mmengine import is_list_of from torch import Tensor def noise_sample_fn(noise: Union[Tensor, Callable, None] = None, *, num_batches: int = 1, noise_size: Union[int, Sequence[int], None] = None, device: Optional[str] = None) -> Tensor: """Sample noise with respect to the given `num_batches`, `noise_size` and `device`. Args: noise (torch.Tensor | callable | None): You can directly give a batch of noise through a ``torch.Tensor`` or offer a callable function to sample a batch of noise data. Otherwise, the ``None`` indicates to use the default noise sampler. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 1. noise_size (Union[int, Sequence[int], None], optional): The size of random noise. Defaults to None. device (Optional[str], optional): The target device of the random noise. Defaults to None. Returns: Tensor: Sampled random noise. """ if isinstance(noise, torch.Tensor): noise_batch = noise # unsqueeze if need if noise_batch.ndim == 1: noise_batch = noise_batch[None, ...] else: # generate noise automatically, prepare and check `num_batches` and # `noise_size` # num_batches = 1 if num_batches is None else num_batches assert num_batches > 0, ( 'If you want to generate noise automatically, \'num_batches\' ' 'must larger than 0.') assert noise_size is not None, ( 'If you want to generate noise automatically, \'noise_size\' ' 'must not be None.') noise_size = [noise_size] if isinstance(noise_size, int) \ else noise_size if callable(noise): # receive a noise generator and sample noise. noise_generator = noise noise_batch = noise_generator((num_batches, *noise_size)) else: # otherwise, we will adopt default noise sampler. assert num_batches > 0 noise_batch = torch.randn((num_batches, *noise_size)) # Check the shape if `noise_size` is passed. Ignore `num_batches` here # because `num_batches` has default value. if noise_size is not None: if isinstance(noise_size, int): noise_size = [noise_size] assert list(noise_batch.shape[1:]) == list(noise_size), ( 'Size of the input noise is inconsistency with \'noise_size\'\'. ' f'Receive \'{noise_batch.shape[1:]}\' and \'{noise_size}\' ' 'respectively.') if device is not None: return noise_batch.to(device) return noise_batch def label_sample_fn(label: Union[Tensor, Callable, List[int], None] = None, *, num_batches: int = 1, num_classes: Optional[int] = None, device: Optional[str] = None) -> Union[Tensor, None]: """Sample random label with respect to `num_batches`, `num_classes` and `device`. Args: label (Union[Tensor, Callable, List[int], None], optional): You can directly give a batch of label through a ``torch.Tensor`` or offer a callable function to sample a batch of label data. Otherwise, the ``None`` indicates to use the default label sampler. Defaults to None. num_batches (int, optional): The number of batch size. Defaults to 1. num_classes (Optional[int], optional): The number of classes. Defaults to None. device (Optional[str], optional): The target device of the label. Defaults to None. Returns: Union[Tensor, None]: Sampled random label. """ # label is not passed and do not have `num_classes` to sample label if (num_classes is None or num_classes <= 0) and (label is None): return None if isinstance(label, Tensor): label_batch = label elif isinstance(label, np.ndarray): label_batch = torch.from_numpy(label).long() elif isinstance(label, list): if is_list_of(label, (int, np.ndarray)): label = [torch.LongTensor([lab]).squeeze() for lab in label] else: assert is_list_of(label, torch.Tensor), ( 'Only support \'int\', \'np.ndarray\' and \'torch.Tensor\' ' 'type for list input. But receives ' f'\'{[type(lab) for lab in label]}\'') label = [lab.squeeze() for lab in label] label_batch = torch.stack(label, dim=0) else: # generate label_batch manually, prepare and check `num_batches` assert num_batches > 0, ( 'If you want to generate label automatically, \'num_batches\' ' 'must larger than 0.') if callable(label): # receive a noise generator and sample noise. label_generator = label label_batch = label_generator(num_batches) else: # otherwise, we will adopt default label sampler. label_batch = torch.randint(0, num_classes, (num_batches, )) # Check whether is LongTensor (torch.int64) and shape like [bz, ] assert label_batch.dtype == torch.int64, ( 'Input label cannot convert to torch.LongTensor (torch.int64). Please ' 'check your input.') assert label_batch.ndim == 1, ( 'Input label must shape like \'[num_batches, ]\', but shape like ' f'({label_batch.shape})') # Check the label if `num_classes` is passed. Ignore `num_batches` because # `num_batches` has default value. if num_classes is not None: invalid_index = torch.logical_or(label_batch < 0, label_batch >= num_classes) assert not (invalid_index).any(), ( f'Labels in label_batch must be in range [0, num_classes - 1] ' f'([0, {num_classes}-1]). But found {label_batch[invalid_index]} ' 'are out of range.') if device is not None: return label_batch.to(device) return label_batch ================================================ FILE: mmagic/models/utils/tensor_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch def get_unknown_tensor(trimap, unknown_value=128 / 255): """Get 1-channel unknown area tensor from the 3 or 1-channel trimap tensor. Args: trimap (Tensor): Tensor with shape (N, 3, H, W) or (N, 1, H, W). unknown_value (float): Scalar value indicating unknown region in trimap. If trimap is pre-processed using `'rescale_to_zero_one'`, then 0 for bg, 128/255 for unknown, 1 for fg, and unknown_value should set to 128 / 255. If trimap is pre-processed by :meth:`FormatTrimap(to_onehot=False)`, then 0 for bg, 1 for unknown, 2 for fg and unknown_value should set to 1. If trimap is pre-processed by :meth:`FormatTrimap(to_onehot=True)`, then trimap is 3-channeled, and this value is not used. Returns: Tensor: Unknown area mask of shape (N, 1, H, W). """ if trimap.shape[1] == 3: # The three channels correspond to (bg mask, unknown mask, fg mask) # respectively. weight = trimap[:, 1:2, :, :].float() # elif 'to_onehot' in meta[0]: # key 'to_onehot' is added by pipeline `FormatTrimap` # 0 for bg, 1 for unknown, 2 for fg # weight = trimap.eq(1).float() else: # trimap is simply processed by pipeline `RescaleToZeroOne` # 0 for bg, 128/255 for unknown, 1 for fg weight = trimap.eq(unknown_value).float() return weight def normalize_vecs(vectors: torch.Tensor) -> torch.Tensor: """Normalize vector with it's lengths at the last dimension. If `vector` is two-dimension tensor, this function is same as L2 normalization. Args: vector (torch.Tensor): Vectors to be normalized. Returns: torch.Tensor: Vectors after normalization. """ return vectors / (torch.norm(vectors, dim=-1, keepdim=True)) ================================================ FILE: mmagic/models/utils/tome_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import Any, Callable, Dict, Tuple, Type import torch def add_tome_cfg_hook(model: torch.nn.Module): """Add a forward pre hook to get the image size. This hook can be removed with remove_patch. Source: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L158 # noqa """ def hook(module, args): module._tome_info['size'] = (args[0].shape[2], args[0].shape[3]) return None model._tome_info['hooks'].append(model.register_forward_pre_hook(hook)) def build_mmagic_wrapper_tomesd_block(block_class: Type[torch.nn.Module] ) -> Type[torch.nn.Module]: """Make a patched class for a DiffusersWrapper model in mmagic. This patch applies ToMe to the forward function of the block. Refer to: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L67 # noqa Args: block_class (torch.nn.Module): original class need tome speedup. Returns: ToMeBlock (torch.nn.Module): patched class based on the original class. """ class ToMeBlock(block_class): # Save for unpatching later _parent = block_class def forward( self, hidden_states, encoder_hidden_states=None, timestep=None, attention_mask=None, cross_attention_kwargs=None, class_labels=None, ): # -> (1) ToMeBlock m_a, m_c, m_m, u_a, u_c, u_m = build_merge(hidden_states, self._tome_info) if self.use_ada_layer_norm: norm_hidden_states = self.norm1(hidden_states, timestep) elif self.use_ada_layer_norm_zero: norm_hidden_states, gate_msa,\ shift_mlp, scale_mlp, gate_mlp = self.norm1( hidden_states, timestep, class_labels, hidden_dtype=hidden_states.dtype) else: norm_hidden_states = self.norm1(hidden_states) # -> (2) ToMe m_a norm_hidden_states = m_a(norm_hidden_states) # 1. Self-Attention if cross_attention_kwargs is not None: cross_attention_kwargs = cross_attention_kwargs else: cross_attention_kwargs = {} attn_output = self.attn1( norm_hidden_states, encoder_hidden_states=encoder_hidden_states if self.only_cross_attention else None, attention_mask=attention_mask, **cross_attention_kwargs, ) if self.use_ada_layer_norm_zero: attn_output = gate_msa.unsqueeze(1) * attn_output # -> (3) ToMe u_a hidden_states = u_a(attn_output) + hidden_states if self.attn2 is not None: norm_hidden_states = ( self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states)) # -> (4) ToMe m_c norm_hidden_states = m_c(norm_hidden_states) # 2. Cross-Attention attn_output = self.attn2( norm_hidden_states, encoder_hidden_states=encoder_hidden_states, attention_mask=attention_mask, **cross_attention_kwargs, ) # -> (5) ToMe u_c hidden_states = u_c(attn_output) + hidden_states # 3. Feed-forward norm_hidden_states = self.norm3(hidden_states) if self.use_ada_layer_norm_zero: norm_hidden_states = norm_hidden_states * ( 1 + scale_mlp[:, None]) + shift_mlp[:, None] # -> (6) ToMe m_m norm_hidden_states = m_m(norm_hidden_states) ff_output = self.ff(norm_hidden_states) if self.use_ada_layer_norm_zero: ff_output = gate_mlp.unsqueeze(1) * ff_output # -> (7) ToMe u_m hidden_states = u_m(ff_output) + hidden_states return hidden_states return ToMeBlock def build_mmagic_tomesd_block(block_class: Type[torch.nn.Module] ) -> Type[torch.nn.Module]: """Make a patched class for a mmagic StableDiffusion model. This patch applies ToMe to the forward function of the block. Refer to: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L67 # noqa Args: block_class (torch.nn.Module): original class need tome speedup. Returns: ToMeBlock (torch.nn.Module): patched class based on the original class. """ class ToMeBlock(block_class): # Save for unpatching later _parent = block_class def forward(self, hidden_states, context=None, timestep=None): # ->(1) ToMeBlock m_a, m_c, m_m, u_a, u_c, u_m = build_merge(hidden_states, self._tome_info) # 1. Self-Attention # ->(2) ToMe m_a norm_hidden_states = (m_a(self.norm1(hidden_states))) # ->(3) ToMe u_a if self.only_cross_attention: hidden_states = u_a(self.attn1(norm_hidden_states, context)) + hidden_states else: hidden_states = u_a( self.attn1(norm_hidden_states)) + hidden_states # 2. Cross-Attention # ->(4) ToMe m_c norm_hidden_states = (m_c(self.norm2(hidden_states))) # ->(5) ToMe u_c hidden_states = u_c( self.attn2(norm_hidden_states, context=context)) + hidden_states # 3. Feed-forward # ->(6) ToMe m_m, u_m hidden_states = u_m(self.ff(m_m( self.norm3(hidden_states)))) + hidden_states return hidden_states return ToMeBlock def isinstance_str(x: object, cls_name: str): """Checks whether `x` has any class *named* `cls_name` in its ancestry. Doesn't require access to the class's implementation. Source: https://github.com/dbolya/tomesd/blob/main/tomesd/utils.py#L3 # noqa """ for _cls in x.__class__.__mro__: if _cls.__name__ == cls_name: return True return False def do_nothing(x: torch.Tensor, mode: str = None): """Build identical mapping function. Source: https://github.com/dbolya/tomesd/blob/main/tomesd/merge.py#L5 # noqa """ return x def mps_gather_workaround(input, dim, index): """Gather function specific for `mps` backend (Metal Performance Shaders). Source: https://github.com/dbolya/tomesd/blob/main/tomesd/merge.py#L9 # noqa """ if input.shape[-1] == 1: return torch.gather( input.unsqueeze(-1), dim - 1 if dim < 0 else dim, index.unsqueeze(-1)).squeeze(-1) else: return torch.gather(input, dim, index) def bipartite_soft_matching_random2d(metric: torch.Tensor, w: int, h: int, sx: int, sy: int, r: int, no_rand: bool = False ) -> Tuple[Callable, Callable]: """Partitions the tokens into src and dst and merges r tokens from src to dst, dst tokens are partitioned by choosing one randomy in each (`sx`, `sy`) region. More details refer to `Token Merging: Your ViT But Faster`, paper link: `_ # noqa. Source: https://github.com/dbolya/tomesd/blob/main/tomesd/merge.py#20 # noqa Args: metric (torch.Tensor): metric with size (B, N, C) for similarity computation. w (int): image width in tokens. h (int): image height in tokens. sx (int): stride in the x dimension for dst, must divide `w`. sy (int): stride in the y dimension for dst, must divide `h`. r (int): number of tokens to remove (by merging). no_rand (bool): if true, disable randomness (use top left corner only). Returns: merge (Callable): token merging function. unmerge (Callable): token unmerging function. """ B, N, _ = metric.shape if r <= 0: return do_nothing, do_nothing if metric.device.type == 'mps': gather = mps_gather_workaround else: gather = torch.gather with torch.no_grad(): hsy, wsx = h // sy, w // sx # For each sy by sx kernel, randomly assign one token to # be dst and the rest src if no_rand: rand_idx = torch.zeros( hsy, wsx, 1, device=metric.device, dtype=torch.int64) else: rand_idx = torch.randint( sy * sx, size=(hsy, wsx, 1), device=metric.device) # The image might not divide sx and sy, so we need to work # on a view of the top left if the idx buffer instead idx_buffer_view = torch.zeros( hsy, wsx, sy * sx, device=metric.device, dtype=torch.int64) idx_buffer_view.scatter_( dim=2, index=rand_idx, src=-torch.ones_like(rand_idx, dtype=rand_idx.dtype)) idx_buffer_view = idx_buffer_view.view(hsy, wsx, sy, sx).transpose( 1, 2).reshape(hsy * sy, wsx * sx) # Image is not divisible by sx or sy so we need to move it # into a new buffer if (hsy * sy) < h or (wsx * sx) < w: idx_buffer = torch.zeros( h, w, device=metric.device, dtype=torch.int64) idx_buffer[:(hsy * sy), :(wsx * sx)] = idx_buffer_view else: idx_buffer = idx_buffer_view # We set dst tokens to be -1 and src to be 0, so an argsort # gives us dst|src indices rand_idx = idx_buffer.reshape(1, -1, 1).argsort(dim=1) # We're finished with these del idx_buffer, idx_buffer_view # rand_idx is currently dst|src, so split them num_dst = hsy * wsx a_idx = rand_idx[:, num_dst:, :] # src b_idx = rand_idx[:, :num_dst, :] # dst def split(x): C = x.shape[-1] src = gather(x, dim=1, index=a_idx.expand(B, N - num_dst, C)) dst = gather(x, dim=1, index=b_idx.expand(B, num_dst, C)) return src, dst # Cosine similarity between A and B metric = metric / metric.norm(dim=-1, keepdim=True) a, b = split(metric) scores = a @ b.transpose(-1, -2) # Can't reduce more than the # tokens in src r = min(a.shape[1], r) # Find the most similar greedily node_max, node_idx = scores.max(dim=-1) edge_idx = node_max.argsort(dim=-1, descending=True)[..., None] unm_idx = edge_idx[..., r:, :] # Unmerged Tokens src_idx = edge_idx[..., :r, :] # Merged Tokens dst_idx = gather(node_idx[..., None], dim=-2, index=src_idx) def merge(x: torch.Tensor, mode='mean') -> torch.Tensor: src, dst = split(x) n, t1, c = src.shape unm = gather(src, dim=-2, index=unm_idx.expand(n, t1 - r, c)) src = gather(src, dim=-2, index=src_idx.expand(n, r, c)) if not hasattr(torch.Tensor, 'scatter_reduce') or torch.__version__ < '1.12.1': raise ImportError( 'Please upgrade torch >= 1.12.1 to enable \'scatter_reduce\'') dst = dst.scatter_reduce(-2, dst_idx.expand(n, r, c), src, reduce=mode) return torch.cat([unm, dst], dim=1) def unmerge(x: torch.Tensor) -> torch.Tensor: unm_len = unm_idx.shape[1] unm, dst = x[..., :unm_len, :], x[..., unm_len:, :] _, _, c = unm.shape src = gather(dst, dim=-2, index=dst_idx.expand(B, r, c)) # Combine back to the original shape out = torch.zeros(B, N, c, device=x.device, dtype=x.dtype) out.scatter_(dim=-2, index=b_idx.expand(B, num_dst, c), src=dst) out.scatter_( dim=-2, index=gather( a_idx.expand(B, a_idx.shape[1], 1), dim=1, index=unm_idx).expand(B, unm_len, c), src=unm) out.scatter_( dim=-2, index=gather( a_idx.expand(B, a_idx.shape[1], 1), dim=1, index=src_idx).expand(B, r, c), src=src) return out return merge, unmerge def build_merge(x: torch.Tensor, tome_info: Dict[str, Any]) -> Tuple[Callable, ...]: """Build the merge and unmerge functions for a given setting from `tome_info`. Source: https://github.com/dbolya/tomesd/blob/main/tomesd/patch.py#L10 # noqa """ original_h, original_w = tome_info['size'] original_tokens = original_h * original_w downsample = int(math.ceil(math.sqrt(original_tokens // x.shape[1]))) args = tome_info['args'] if downsample <= args['max_downsample']: w = int(math.ceil(original_w / downsample)) h = int(math.ceil(original_h / downsample)) r = int(x.shape[1] * args['ratio']) # If the batch size is odd, then it's not possible for promted and # unprompted images to be in the same batch, which causes artifacts # with use_rand, so force it to be off. use_rand = False if x.shape[0] % 2 == 1 else args['use_rand'] m, u = bipartite_soft_matching_random2d(x, w, h, args['sx'], args['sy'], r, not use_rand) else: m, u = (do_nothing, do_nothing) m_a, u_a = (m, u) if args['merge_attn'] else (do_nothing, do_nothing) m_c, u_c = (m, u) if args['merge_crossattn'] else (do_nothing, do_nothing) m_m, u_m = (m, u) if args['merge_mlp'] else (do_nothing, do_nothing) return m_a, m_c, m_m, u_a, u_c, u_m ================================================ FILE: mmagic/registry.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. """Registries and utilities in MMagic. MMagic provides 17 registry nodes to support using modules across projects. Each node is a child of the root registry in MMEngine. More details can be found at https://mmengine.readthedocs.io/en/latest/advanced_tutorials/registry.html. """ from mmengine.registry import DATA_SAMPLERS as MMENGINE_DATA_SAMPLERS from mmengine.registry import DATASETS as MMENGINE_DATASETS from mmengine.registry import EVALUATOR as MMENGINE_EVALUATOR from mmengine.registry import HOOKS as MMENGINE_HOOKS from mmengine.registry import LOG_PROCESSORS as MMENGINE_LOG_PROCESSORS from mmengine.registry import LOOPS as MMENGINE_LOOPS from mmengine.registry import METRICS as MMENGINE_METRICS from mmengine.registry import MODEL_WRAPPERS as MMENGINE_MODEL_WRAPPERS from mmengine.registry import MODELS as MMENGINE_MODELS from mmengine.registry import \ OPTIM_WRAPPER_CONSTRUCTORS as MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS from mmengine.registry import OPTIM_WRAPPERS as MMENGINE_OPTIM_WRAPPERS from mmengine.registry import OPTIMIZERS as MMENGINE_OPTIMIZERS from mmengine.registry import PARAM_SCHEDULERS as MMENGINE_PARAM_SCHEDULERS from mmengine.registry import \ RUNNER_CONSTRUCTORS as MMENGINE_RUNNER_CONSTRUCTORS from mmengine.registry import RUNNERS as MMENGINE_RUNNERS from mmengine.registry import TASK_UTILS as MMENGINE_TASK_UTILS from mmengine.registry import TRANSFORMS as MMENGINE_TRANSFORMS from mmengine.registry import VISBACKENDS as MMENGINE_VISBACKENDS from mmengine.registry import VISUALIZERS as MMENGINE_VISUALIZERS from mmengine.registry import \ WEIGHT_INITIALIZERS as MMENGINE_WEIGHT_INITIALIZERS from mmengine.registry import Registry __all__ = [ 'RUNNERS', 'RUNNER_CONSTRUCTORS', 'LOOPS', 'HOOKS', 'LOG_PROCESSORS', 'OPTIMIZERS', 'OPTIM_WRAPPERS', 'OPTIM_WRAPPER_CONSTRUCTORS', 'PARAM_SCHEDULERS', 'DATASETS', 'DATA_SAMPLERS', 'TRANSFORMS', 'MODELS', 'MODEL_WRAPPERS', 'WEIGHT_INITIALIZERS', 'TASK_UTILS', 'DIFFUSION_SCHEDULERS', 'METRICS', 'EVALUATORS', 'VISUALIZERS', 'VISBACKENDS' ] ####################################################################### # mmagic.engine # ####################################################################### # Runners like `EpochBasedRunner` and `IterBasedRunner` RUNNERS = Registry( 'runner', parent=MMENGINE_RUNNERS, locations=['mmagic.engine'], ) # Runner constructors that define how to initialize runners RUNNER_CONSTRUCTORS = Registry( 'runner constructor', parent=MMENGINE_RUNNER_CONSTRUCTORS, locations=['mmagic.engine'], ) # Loops which define the training or test process, like `EpochBasedTrainLoop` LOOPS = Registry( 'loop', parent=MMENGINE_LOOPS, locations=['mmagic.engine'], ) # Hooks to add additional functions during running, like `CheckpointHook` HOOKS = Registry( 'hook', parent=MMENGINE_HOOKS, locations=['mmagic.engine'], ) # Log processors to process the scalar log data. LOG_PROCESSORS = Registry( 'log processor', parent=MMENGINE_LOG_PROCESSORS, locations=['mmagic.engine'], ) # Optimizers to optimize the model weights, like `SGD` and `Adam`. OPTIMIZERS = Registry( 'optimizer', parent=MMENGINE_OPTIMIZERS, locations=['mmagic.engine'], ) # Optimizer wrappers to enhance the optimization process. OPTIM_WRAPPERS = Registry( 'optimizer_wrapper', parent=MMENGINE_OPTIM_WRAPPERS, locations=['mmagic.engine'], ) # Optimizer constructors to customize the hyper-parameters of optimizers. OPTIM_WRAPPER_CONSTRUCTORS = Registry( 'optimizer wrapper constructor', parent=MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS, locations=['mmagic.engine'], ) # Parameter schedulers to dynamically adjust optimization parameters. PARAM_SCHEDULERS = Registry( 'parameter scheduler', parent=MMENGINE_PARAM_SCHEDULERS, locations=['mmagic.engine'], ) ####################################################################### # mmagic.datasets # ####################################################################### # Datasets like `ImageNet` and `CIFAR10`. DATASETS = Registry( 'dataset', parent=MMENGINE_DATASETS, locations=['mmagic.datasets'], ) # Samplers to sample the dataset. DATA_SAMPLERS = Registry( 'data sampler', parent=MMENGINE_DATA_SAMPLERS, locations=['mmagic.datasets'], ) # Transforms to process the samples from the dataset. TRANSFORMS = Registry( 'transform', parent=MMENGINE_TRANSFORMS, locations=['mmagic.datasets.transforms'], ) ####################################################################### # mmagic.models # ####################################################################### # Neural network modules inheriting `nn.Module`. MODELS = Registry( 'model', parent=MMENGINE_MODELS, locations=['mmagic.models'], ) # Model wrappers like 'MMDistributedDataParallel' MODEL_WRAPPERS = Registry( 'model_wrapper', parent=MMENGINE_MODEL_WRAPPERS, locations=['mmagic.models'], ) # Weight initialization methods like uniform, xavier. WEIGHT_INITIALIZERS = Registry( 'weight initializer', parent=MMENGINE_WEIGHT_INITIALIZERS, locations=['mmagic.models'], ) # Task-specific modules like anchor generators and box coders TASK_UTILS = Registry( 'task util', parent=MMENGINE_TASK_UTILS, locations=['mmagic.models'], ) # modules for diffusion models that support adding noise and denoising DIFFUSION_SCHEDULERS = Registry( 'diffusion scheduler', locations=['mmagic.models.diffusion_schedulers'], ) ####################################################################### # mmagic.evaluation # ####################################################################### # Metrics to evaluate the model prediction results. METRICS = Registry( 'metric', parent=MMENGINE_METRICS, locations=['mmagic.evaluation'], ) # Evaluators to define the evaluation process. EVALUATORS = Registry( 'evaluator', parent=MMENGINE_EVALUATOR, locations=['mmagic.evaluation'], ) ####################################################################### # mmagic.visualization # ####################################################################### # Visualizers to display task-specific results. VISUALIZERS = Registry( 'visualizer', parent=MMENGINE_VISUALIZERS, locations=['mmagic.visualization'], ) # Backends to save the visualization results, like TensorBoard, WandB. VISBACKENDS = Registry( 'vis_backend', parent=MMENGINE_VISBACKENDS, locations=['mmagic.visualization'], ) ================================================ FILE: mmagic/structures/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .data_sample import DataSample __all__ = ['DataSample'] ================================================ FILE: mmagic/structures/data_sample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from collections import abc from copy import deepcopy from itertools import chain from numbers import Number from typing import Any, Sequence, Union import mmengine import numpy as np import torch from mmengine.structures import BaseDataElement, LabelData from mmagic.utils import all_to_tensor def format_label(value: Union[torch.Tensor, np.ndarray, Sequence, int], num_classes: int = None) -> LabelData: """Convert label of various python types to :obj:`mmengine.LabelData`. Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, :class:`Sequence`, :class:`int`. Args: value (torch.Tensor | numpy.ndarray | Sequence | int): Label value. num_classes (int, optional): The number of classes. If not None, set it to the metainfo. Defaults to None. Returns: :obj:`mmengine.LabelData`: The formatted label data. """ # Handle single number if isinstance(value, (torch.Tensor, np.ndarray)) and value.ndim == 0: value = int(value.item()) if isinstance(value, np.ndarray): value = torch.from_numpy(value) elif isinstance(value, Sequence) and not mmengine.is_str(value): value = torch.tensor(value) elif isinstance(value, int): value = torch.LongTensor([value]) elif not isinstance(value, torch.Tensor): raise TypeError(f'Type {type(value)} is not an available label type.') metainfo = {} if num_classes is not None: metainfo['num_classes'] = num_classes if value.max() >= num_classes: raise ValueError(f'The label data ({value}) should not ' f'exceed num_classes ({num_classes}).') label = LabelData(label=value, metainfo=metainfo) return label def is_splitable_var(var: Any) -> bool: """Check whether input is a splitable variable. Args: var (Any): The input variable to check. Returns: bool: Whether input variable is a splitable variable. """ if isinstance(var, DataSample): return True if isinstance(var, torch.Tensor): return True if isinstance(var, np.ndarray): return True if isinstance(var, abc.Sequence) and not isinstance(var, str): return True return False class DataSample(BaseDataElement): """A data structure interface of MMagic. They are used as interfaces between different components, e.g., model, visualizer, evaluator, etc. Typically, DataSample contains all the information and data from ground- truth and predictions. `DataSample` inherits from `BaseDataElement`. See more details in: https://mmengine.readthedocs.io/en/latest/advanced_tutorials/data_element.html Specifically, an instance of BaseDataElement consists of two components, - ``metainfo``, which contains some meta information, e.g., `img_shape`, `img_id`, `color_order`, etc. - ``data``, which contains the data used in the loop. The attributes in ``DataSample`` are divided into several parts: - ``gt_img``: Ground truth image(s). - ``pred_img``: Image(s) of model predictions. - ``ref_img``: Reference image(s). - ``mask``: Mask in Inpainting. - ``trimap``: Trimap in Matting. - ``gt_alpha``: Ground truth alpha image in Matting. - ``pred_alpha``: Predicted alpha image in Matting. - ``gt_fg``: Ground truth foreground image in Matting. - ``pred_fg``: Predicted foreground image in Matting. - ``gt_bg``: Ground truth background image in Matting. - ``pred_bg``: Predicted background image in Matting. - ``gt_merged``: Ground truth merged image in Matting. Examples:: >>> import torch >>> import numpy as np >>> from mmagic.structures import DataSample >>> img_meta = dict(img_shape=(800, 1196, 3)) >>> img = torch.rand((3, 800, 1196)) >>> data_sample = DataSample(gt_img=img, metainfo=img_meta) >>> assert 'img_shape' in data_sample.metainfo_keys() >>> data_sample We also support `stack` and `split` operation to handle a batch of data samples: >>> import torch >>> import numpy as np >>> from mmagic.structures import DataSample >>> img_meta1 = img_meta2 = dict(img_shape=(800, 1196, 3)) >>> img1 = torch.rand((3, 800, 1196)) >>> img2 = torch.rand((3, 800, 1196)) >>> data_sample1 = DataSample(gt_img=img1, metainfo=img_meta1) >>> data_sample2 = DataSample(gt_img=img2, metainfo=img_meta1) >>> # stack them and then use as batched-tensor! >>> data_sample = DataSample.stack([data_sample1, data_sample2]) >>> print(data_sample.gt_img.shape) torch.Size([2, 3, 800, 1196]) >>> print(data_sample.metainfo) {'img_shape': [(800, 1196, 3), (800, 1196, 3)]} >>> # split them if you want >>> data_sample1_, data_sample2_ = data_sample.split() >>> assert (data_sample1_.gt_img == img1).all() >>> assert (data_sample2_.gt_img == img2).all() """ # source_key_in_results: target_key_in_metainfo META_KEYS = { 'img_path': 'img_path', 'gt_path': 'gt_path', 'merged_path': 'merged_path', 'trimap_path': 'trimap_path', 'ori_shape': 'ori_shape', 'img_shape': 'img_shape', 'ori_merged_shape': 'ori_merged_shape', 'ori_trimap_shape': 'ori_trimap_shape', 'trimap_channel_order': 'trimap_channel_order', 'empty_box': 'empty_box', 'ori_img_shape': 'ori_img_shape', 'ori_gt_shape': 'ori_gt_shape', 'img_channel_order': 'img_channel_order', 'gt_channel_order': 'gt_channel_order', 'gt_color_type': 'gt_color_type', 'img_color_type': 'img_color_type', 'sample_idx': 'sample_idx', 'num_input_frames': 'num_input_frames', 'num_output_frames': 'num_output_frames', 'mask_bbox': 'mask_bbox', # for LIIF 'coord': 'coord', 'cell': 'cell', } # source_key_in_results: target_key_in_datafield DATA_KEYS = { 'gt': 'gt_img', 'gt_label': 'gt_label', 'gt_heatmap': 'gt_heatmap', 'gt_unsharp': 'gt_unsharp', 'merged': 'gt_merged', 'ori_alpha': 'ori_alpha', 'fg': 'gt_fg', 'bg': 'gt_bg', 'gt_rgb': 'gt_rgb', 'alpha': 'gt_alpha', 'img_lq': 'img_lq', 'ref': 'ref_img', 'ref_lq': 'ref_lq', 'mask': 'mask', 'trimap': 'trimap', 'gray': 'gray', 'cropped_img': 'cropped_img', 'pred_img': 'pred_img', 'ori_trimap': 'ori_trimap', # For text to images 'prompt': 'prompt', # For StyleGAN 'latent': 'latent', 'feats': 'feats' } def set_predefined_data(self, data: dict) -> None: """set or change pre-defined key-value pairs in ``data_field`` by parameter ``data``. Args: data (dict): A dict contains annotations of image or model predictions. """ metainfo = { self.META_KEYS[k]: v for (k, v) in data.items() if k in self.META_KEYS } self.set_metainfo(metainfo) data = { self.DATA_KEYS[k]: v for (k, v) in data.items() if k in self.DATA_KEYS } self.set_tensor_data(data) def set_tensor_data(self, data: dict) -> None: """convert input data to tensor, and then set or change key-value pairs in ``data_field`` by parameter ``data``. Args: data (dict): A dict contains annotations of image or model predictions. """ assert isinstance(data, dict), f'data should be a `dict` but got {data}' for k, v in data.items(): if k == 'gt_label': self.set_gt_label(v) elif k == 'prompt': self.set_field(v, k, dtype=(str, list)) else: self.set_field(all_to_tensor(v), k, dtype=torch.Tensor) def set_gt_label( self, value: Union[np.ndarray, torch.Tensor, Sequence[Number], Number] ) -> 'DataSample': """Set label of ``gt_label``.""" label = format_label(value, self.get('num_classes')) if 'gt_label' in self: self.gt_label.label = label.label else: self.gt_label = label return self @property def gt_label(self): """This the function to fetch gt label. Returns: LabelData: gt label. """ return self._gt_label @gt_label.setter def gt_label(self, value: LabelData): """This is the function to set gt label. Args: value (LabelData): gt label. """ self.set_field(value, '_gt_label', dtype=LabelData) @gt_label.deleter def gt_label(self): """Delete gt label.""" del self._gt_label @classmethod def stack(cls, data_samples: Sequence['DataSample']) -> 'DataSample': """Stack a list of data samples to one. All tensor fields will be stacked at first dimension. Otherwise the values will be saved in a list. Args: data_samples (Sequence['DataSample']): A sequence of `DataSample` to stack. Returns: DataSample: The stacked data sample. """ # 1. check key consistency keys = data_samples[0].keys() assert all([data.keys() == keys for data in data_samples]) meta_keys = data_samples[0].metainfo_keys() assert all( [data.metainfo_keys() == meta_keys for data in data_samples]) # 2. stack data stacked_data_sample = DataSample() for k in keys: values = [getattr(data, k) for data in data_samples] # 3. check type consistent value_type = type(values[0]) assert all([type(val) == value_type for val in values]) # 4. stack if isinstance(values[0], torch.Tensor): stacked_value = torch.stack(values) elif isinstance(values[0], LabelData): labels = [data.label for data in values] values = torch.stack(labels) stacked_value = LabelData(label=values) else: stacked_value = values stacked_data_sample.set_field(stacked_value, k) # 5. stack metainfo for k in meta_keys: values = [data.metainfo[k] for data in data_samples] stacked_data_sample.set_metainfo({k: values}) return stacked_data_sample def split(self, allow_nonseq_value: bool = False) -> Sequence['DataSample']: """Split a sequence of data sample in the first dimension. Args: allow_nonseq_value (bool): Whether allow non-sequential data in split operation. If True, non-sequential data will be copied for all split data samples. Otherwise, an error will be raised. Defaults to False. Returns: Sequence[DataSample]: The list of data samples after splitting. """ # 1. split data_sample_list = [DataSample() for _ in range(len(self))] for k in self.all_keys(): stacked_value = self.get(k) if isinstance(stacked_value, torch.Tensor): # split tensor shape like (N, *shape) to N (*shape) tensors values = [v for v in stacked_value] elif isinstance(stacked_value, LabelData): # split tensor shape like (N, *shape) to N (*shape) tensors labels = [l_ for l_ in stacked_value.label] values = [LabelData(label=l_) for l_ in labels] elif isinstance(stacked_value, DataSample): values = stacked_value.split() else: if is_splitable_var(stacked_value): values = stacked_value elif allow_nonseq_value: values = [deepcopy(stacked_value)] * len(self) else: raise TypeError( f'\'{k}\' is non-sequential data and ' '\'allow_nonseq_value\' is False. Please check your ' 'data sample or set \'allow_nonseq_value\' as True ' f'to copy field \'{k}\' for all split data sample.') field = 'metainfo' if k in self.metainfo_keys() else 'data' for data, v in zip(data_sample_list, values): data.set_field(v, k, field_type=field) return data_sample_list def __len__(self): """Get the length of the data sample.""" value_length = [] for v in chain(self.values(), self.metainfo_values()): if isinstance(v, LabelData): value_length.append(v.label.shape[0]) elif is_splitable_var(v): value_length.append(len(v)) else: continue # NOTE: If length of values are not same or the current data sample # is empty, return length as 1 if len(list(set(value_length))) != 1: return 1 length = value_length[0] return length ================================================ FILE: mmagic/utils/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .cli import modify_args from .img_utils import (all_to_tensor, can_convert_to_image, get_box_info, reorder_image, tensor2img, to_numpy) from .io_utils import MMAGIC_CACHE_DIR, download_from_url # TODO replace with engine's API from .logger import print_colored_log from .sampler import get_sampler from .setup_env import register_all_modules, try_import from .trans_utils import (add_gaussian_noise, adjust_gamma, bbox2mask, brush_stroke_mask, get_irregular_mask, make_coord, random_bbox, random_choose_unknown) from .typing import ConfigType, ForwardInputs, LabelVar, NoiseVar, SampleList __all__ = [ 'modify_args', 'print_colored_log', 'register_all_modules', 'try_import', 'ForwardInputs', 'SampleList', 'NoiseVar', 'ConfigType', 'LabelVar', 'MMAGIC_CACHE_DIR', 'download_from_url', 'get_sampler', 'tensor2img', 'random_choose_unknown', 'add_gaussian_noise', 'adjust_gamma', 'make_coord', 'bbox2mask', 'brush_stroke_mask', 'get_irregular_mask', 'random_bbox', 'reorder_image', 'to_numpy', 'get_box_info', 'can_convert_to_image', 'all_to_tensor' ] ================================================ FILE: mmagic/utils/cli.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import re import sys import warnings def modify_args(): """Modify args of argparse.ArgumentParser.""" for i, v in enumerate(sys.argv): if i == 0: assert v.endswith('.py') elif re.match(r'--\w+_.*', v): new_arg = v.replace('_', '-') warnings.warn( f'command line argument {v} is deprecated, ' f'please use {new_arg} instead.', category=DeprecationWarning, ) sys.argv[i] = new_arg ================================================ FILE: mmagic/utils/collect_env.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmcv.utils import collect_env as collect_base_env from mmengine.utils import get_git_hash import mmagic def collect_env(): """Collect the information of the running environments.""" env_info = collect_base_env() env_info['MMagic'] = f'{mmagic.__version__}+{get_git_hash()[:7]}' return env_info if __name__ == '__main__': for name, val in collect_env().items(): print('{}: {}'.format(name, val)) ================================================ FILE: mmagic/utils/img_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import List, Tuple import numpy as np import torch from mmcv.transforms import to_tensor from torchvision.utils import make_grid def can_convert_to_image(value): """Judge whether the input value can be converted to image tensor via :func:`images_to_tensor` function. Args: value (any): The input value. Returns: bool: If true, the input value can convert to image with :func:`images_to_tensor`, and vice versa. """ if isinstance(value, (List, Tuple)): return all([can_convert_to_image(v) for v in value]) elif isinstance(value, np.ndarray) and len(value.shape) > 1: return True elif isinstance(value, torch.Tensor): return True else: return False def image_to_tensor(img): """Trans image to tensor. Args: img (np.ndarray): The original image. Returns: Tensor: The output tensor. """ if len(img.shape) < 3: img = np.expand_dims(img, -1) img = np.ascontiguousarray(img) tensor = to_tensor(img).permute(2, 0, 1).contiguous() return tensor def all_to_tensor(value): """Trans image and sequence of frames to tensor. Args: value (np.ndarray | list[np.ndarray] | Tuple[np.ndarray]): The original image or list of frames. Returns: Tensor: The output tensor. """ if not can_convert_to_image(value): return value if isinstance(value, (List, Tuple)): # sequence of frames if len(value) == 1: tensor = image_to_tensor(value[0]) else: frames = [image_to_tensor(v) for v in value] tensor = torch.stack(frames, dim=0) elif isinstance(value, np.ndarray): tensor = image_to_tensor(value) else: # Maybe the data has been converted to Tensor. tensor = to_tensor(value) return tensor def tensor2img(tensor, out_type=np.uint8, min_max=(0, 1)): """Convert torch Tensors into image numpy arrays. After clamping to (min, max), image values will be normalized to [0, 1]. For different tensor shapes, this function will have different behaviors: 1. 4D mini-batch Tensor of shape (N x 3/1 x H x W): Use `make_grid` to stitch images in the batch dimension, and then convert it to numpy array. 2. 3D Tensor of shape (3/1 x H x W) and 2D Tensor of shape (H x W): Directly change to numpy array. Note that the image channel in input tensors should be RGB order. This function will convert it to cv2 convention, i.e., (H x W x C) with BGR order. Args: tensor (Tensor | list[Tensor]): Input tensors. out_type (numpy type): Output types. If ``np.uint8``, transform outputs to uint8 type with range [0, 255]; otherwise, float type with range [0, 1]. Default: ``np.uint8``. min_max (tuple): min and max values for clamp. Returns: (Tensor | list[Tensor]): 3D ndarray of shape (H x W x C) or 2D ndarray of shape (H x W). """ if not (torch.is_tensor(tensor) or (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))): raise TypeError( f'tensor or list of tensors expected, got {type(tensor)}') if torch.is_tensor(tensor): tensor = [tensor] result = [] for _tensor in tensor: # Squeeze two times so that: # 1. (1, 1, h, w) -> (h, w) or # 3. (1, 3, h, w) -> (3, h, w) or # 2. (n>1, 3/1, h, w) -> (n>1, 3/1, h, w) _tensor = _tensor.squeeze(0).squeeze(0) _tensor = _tensor.float().detach().cpu().clamp_(*min_max) _tensor = (_tensor - min_max[0]) / (min_max[1] - min_max[0]) n_dim = _tensor.dim() if n_dim == 4: img_np = make_grid( _tensor, nrow=int(math.sqrt(_tensor.size(0))), normalize=False).numpy() img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) elif n_dim == 3: img_np = _tensor.numpy() img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) elif n_dim == 2: img_np = _tensor.numpy() else: raise ValueError('Only support 4D, 3D or 2D tensor. ' f'But received with dimension: {n_dim}') if out_type == np.uint8: # Unlike MATLAB, numpy.unit8() WILL NOT round by default. img_np = (img_np * 255.0).round() img_np = img_np.astype(out_type) result.append(img_np) result = result[0] if len(result) == 1 else result return result def reorder_image(img, input_order='HWC'): """Reorder images to 'HWC' order. If the input_order is (h, w), return (h, w, 1); If the input_order is (c, h, w), return (h, w, c); If the input_order is (h, w, c), return as it is. Args: img (np.ndarray): Input image. input_order (str): Whether the input order is 'HWC' or 'CHW'. If the input image shape is (h, w), input_order will not have effects. Default: 'HWC'. Returns: np.ndarray: Reordered image. """ if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are ' '"HWC" and "CHW"') if len(img.shape) == 2: img = img[..., None] return img if input_order == 'CHW': if isinstance(img, np.ndarray): img = img.transpose(1, 2, 0) elif isinstance(img, torch.Tensor): img = img.permute(1, 2, 0) return img def to_numpy(img, dtype=np.float64): """Convert data into numpy arrays of dtype. Args: img (Tensor | np.ndarray): Input data. dtype (np.dtype): Set the data type of the output. Default: np.float64 Returns: img (np.ndarray): Converted numpy arrays data. """ if isinstance(img, torch.Tensor): img = img.cpu().numpy() elif not isinstance(img, np.ndarray): raise TypeError('Only support torch.tensor and np.ndarray, ' f'but got type {type(img)}') img = img.astype(dtype) return img def get_box_info(pred_bbox, original_shape, final_size): """ Args: pred_bbox: The bounding box for the instance original_shape: Original image shape final_size: Size of the final output Returns: List: [L_pad, R_pad, T_pad, B_pad, rh, rw] """ assert len(pred_bbox) == 4 resize_startx = int(pred_bbox[0] / original_shape[0] * final_size) resize_starty = int(pred_bbox[1] / original_shape[1] * final_size) resize_endx = int(pred_bbox[2] / original_shape[0] * final_size) resize_endy = int(pred_bbox[3] / original_shape[1] * final_size) rh = resize_endx - resize_startx rw = resize_endy - resize_starty if rh < 1: if final_size - resize_endx > 1: resize_endx += 1 else: resize_startx -= 1 rh = 1 if rw < 1: if final_size - resize_endy > 1: resize_endy += 1 else: resize_starty -= 1 rw = 1 L_pad = resize_startx R_pad = final_size - resize_endx T_pad = resize_starty B_pad = final_size - resize_endy return [L_pad, R_pad, T_pad, B_pad, rh, rw] ================================================ FILE: mmagic/utils/io_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import hashlib import os import click import mmengine import requests import torch.distributed as dist from mmengine.dist import get_dist_info from requests.exceptions import InvalidURL, RequestException, Timeout MMAGIC_CACHE_DIR = os.path.expanduser('~') + '/.cache/openmmlab/mmagic/' def get_content_from_url(url, timeout=15, stream=False): """Get content from url. Args: url (str): Url for getting content. timeout (int): Set the socket timeout. Default: 15. """ try: response = requests.get(url, timeout=timeout, stream=stream) except InvalidURL as err: raise err # type: ignore except Timeout as err: raise err # type: ignore except RequestException as err: raise err # type: ignore except Exception as err: raise err # type: ignore return response def download_from_url(url, dest_path=None, dest_dir=MMAGIC_CACHE_DIR, hash_prefix=None): """Download object at the given URL to a local path. Args: url (str): URL of the object to download. dest_path (str): Path where object will be saved. dest_dir (str): The directory of the destination. Defaults to ``'~/.cache/openmmlab/mmagic/'``. hash_prefix (string, optional): If not None, the SHA256 downloaded file should start with `hash_prefix`. Default: None. Return: str: path for the downloaded file. """ # get the exact destination path if dest_path is None: filename = url.split('/')[-1] dest_path = os.path.join(dest_dir, filename) if dest_path.startswith('~'): dest_path = os.path.expanduser('~') + dest_path[1:] # avoid downloading existed file if os.path.exists(dest_path): return dest_path rank, ws = get_dist_info() # only download from the master process if rank == 0: # mkdir _dir = os.path.dirname(dest_path) mmengine.mkdir_or_exist(_dir) if hash_prefix is not None: sha256 = hashlib.sha256() response = get_content_from_url(url, stream=True) size = int(response.headers.get('content-length')) with open(dest_path, 'wb') as fw: content_iter = response.iter_content(chunk_size=1024) with click.progressbar(content_iter, length=size / 1024) as chunks: for chunk in chunks: if chunk: fw.write(chunk) fw.flush() if hash_prefix is not None: sha256.update(chunk) if hash_prefix is not None: digest = sha256.hexdigest() if digest[:len(hash_prefix)] != hash_prefix: raise RuntimeError( f'invalid hash value, expected "{hash_prefix}", but got ' f'"{digest}"') # sync the other processes if ws > 1: dist.barrier() return dest_path ================================================ FILE: mmagic/utils/logger.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import logging from mmengine.logging import print_log from termcolor import colored def print_colored_log(msg, level=logging.INFO, color='magenta'): """Print colored log with default logger. Args: msg (str): Message to log. level (int): The root logger level. Note that only the process of rank 0 is affected, while other processes will set the level to "Error" and be silent most of the time.Log level, default to 'info'. color (str, optional): Color 'magenta'. """ print_log(colored(msg, color), 'current', level) ================================================ FILE: mmagic/utils/sampler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Optional from mmengine.dataset import pseudo_collate from mmengine.runner import Runner from torch.utils.data import ConcatDataset, DataLoader def _check_keys(sample_kwargs: dict, key: str) -> None: """Check whether target `key` is in the `sample_kwargs`.""" assert key in sample_kwargs, ( f'\'{key}\' must be set in \'sample_kwargs\'. But only find ' f'following keys: \'{list(sample_kwargs.keys())}\'.') def get_sampler(sample_kwargs: dict, runner: Optional[Runner]): """Get a sampler to loop input data. Args: sample_kwargs (dict): _description_ runner (Optional[Runner]): _description_ Returns: _type_: _description_ """ _check_keys(sample_kwargs, 'type') sampler_kwargs_ = deepcopy(sample_kwargs) sampler_type = sampler_kwargs_.pop('type') sampler = eval(f'{sampler_type}Sampler')(sampler_kwargs_, runner) return sampler class ArgumentsSampler: """Dummy sampler only return input args multiple times.""" def __init__(self, sample_kwargs: dict, runner: Optional[Runner] = None) -> None: _check_keys(sample_kwargs, 'max_times') assert isinstance(sample_kwargs['max_times'], int), ( '\'max_times\' in \'sample_kwargs\' must be type of int.\'.') self.sample_kwargs = deepcopy(sample_kwargs) self.max_times = self.sample_kwargs.pop('max_times') self.forward_kwargs = self.sample_kwargs.pop('forward_kwargs') # set default num_batches from forward_kwargs self.forward_kwargs.setdefault('num_batches', self.sample_kwargs['num_batches']) self.idx = 0 def __iter__(self): self.idx = 0 return self def __next__(self): if self.idx >= self.max_times: raise StopIteration self.idx += 1 return dict(inputs=deepcopy(self.forward_kwargs)) class NoiseSampler: """Noise sampler to by call `models.noise_fn` to generate noise.""" def __init__(self, sample_kwargs: dict, runner: Runner) -> None: _check_keys(sample_kwargs, 'max_times') _check_keys(sample_kwargs, 'num_batches') self.sample_kwargs = deepcopy(sample_kwargs) self.max_times = self.sample_kwargs.pop('max_times') self.num_batches = self.sample_kwargs.pop('num_batches') module = runner.model if hasattr(module, 'module'): module = module.module self.module = module self.idx = 0 def __iter__(self): self.idx = 0 return self def __next__(self): if self.idx >= self.max_times: raise StopIteration self.idx += 1 noise = self.module.noise_fn(num_batches=self.num_batches) sample_kwargs = deepcopy(self.sample_kwargs) sample_kwargs['noise'] = noise # return sample_kwargs return dict(inputs=sample_kwargs) class DataSampler: """Sampler loop the train_dataloader.""" def __init__(self, sample_kwargs: dict, runner: Runner) -> None: _check_keys(sample_kwargs, 'max_times') self.sample_kwargs = deepcopy(sample_kwargs) self.max_times = self.sample_kwargs.pop('max_times') # build a new vanilla dataloader, because we should not reset the one # used in the training process. dataset = runner.train_dataloader.dataset batch_size = runner.train_dataloader.batch_size self._dataloader = DataLoader( dataset, batch_size=batch_size, collate_fn=pseudo_collate) self._iterator = iter(self._dataloader) def __iter__(self): self.idx = 0 return self def __next__(self): if self.idx >= self.max_times: self._iterator = iter(self._dataloader) raise StopIteration self.idx += 1 return next(self._iterator) class ValDataSampler: """Sampler loop the val_dataloader.""" def __init__(self, sample_kwargs: dict, runner: Runner) -> None: _check_keys(sample_kwargs, 'max_times') self.sample_kwargs = deepcopy(sample_kwargs) self.max_times = self.sample_kwargs.pop('max_times') # build a new vanilla dataloader, because we should not reset the one # used in the training process. if hasattr(runner.val_loop, 'dataloader'): dataset = runner.val_loop.dataloader.dataset batch_size = runner.val_loop.dataloader.batch_size else: # MultiValLoop use `dataloaders` instead `dataloader` loaders = runner.val_loop.dataloaders dataset = ConcatDataset([loader.dataset for loader in loaders]) batch_size = loaders[0].batch_size self._dataloader = DataLoader( dataset, batch_size=batch_size, collate_fn=pseudo_collate) self._iterator = iter(self._dataloader) def __iter__(self): self.idx = 0 return self def __next__(self): if self.idx >= self.max_times: self._iterator = iter(self._dataloader) raise StopIteration self.idx += 1 return next(self._iterator) ================================================ FILE: mmagic/utils/setup_env.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import datetime import importlib import warnings from types import ModuleType from typing import Optional from mmengine import DefaultScope def register_all_modules(init_default_scope: bool = True) -> None: """Register all modules in mmagic into the registries. Args: init_default_scope (bool): Whether initialize the mmagic default scope. When `init_default_scope=True`, the global default scope will be set to `mmagic`, and all registries will build modules from mmagic's registry node. To understand more about the registry, please refer to https://mmengine.readthedocs.io/en/latest/advanced_tutorials/registry.html Defaults to True. """ # noqa import mmagic.datasets # noqa: F401,F403 import mmagic.engine # noqa: F401,F403 import mmagic.evaluation # noqa: F401,F403 import mmagic.models # noqa: F401,F403 import mmagic.visualization # noqa: F401,F403 if init_default_scope: never_created = DefaultScope.get_current_instance() is None \ or not DefaultScope.check_instance_created('mmagic') if never_created: DefaultScope.get_instance('mmagic', scope_name='mmagic') return current_scope = DefaultScope.get_current_instance() if current_scope.scope_name != 'mmagic': warnings.warn('The current default scope ' f'"{current_scope.scope_name}" is not "mmagic", ' '`register_all_modules` will force the current' 'default scope to be "mmagic". If this is not ' 'expected, please set `init_default_scope=False`.') # avoid name conflict new_instance_name = f'mmagic-{datetime.datetime.now()}' DefaultScope.get_instance(new_instance_name, scope_name='mmagic') def try_import(name: str) -> Optional[ModuleType]: """Try to import a module. Args: name (str): Specifies what module to import in absolute or relative terms (e.g. either pkg.mod or ..mod). Returns: ModuleType or None: If importing successfully, returns the imported module, otherwise returns None. """ try: return importlib.import_module(name) except ImportError: return None ================================================ FILE: mmagic/utils/trans_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import logging import math import cv2 import numpy as np import torch from mmengine.logging import print_log from mmengine.utils import is_tuple_of from PIL import Image, ImageDraw def make_coord(shape, ranges=None, flatten=True): """Make coordinates at grid centers. Args: shape (tuple): shape of image. ranges (tuple): range of coordinate value. Default: None. flatten (bool): flatten to (n, 2) or Not. Default: True. Returns: coord (Tensor): coordinates. """ coord_seqs = [] for i, n in enumerate(shape): if ranges is None: v0, v1 = -1, 1 else: v0, v1 = ranges[i] r = (v1 - v0) / (2 * n) seq = v0 + r + (2 * r) * torch.arange(n).float() coord_seqs.append(seq) if 'indexing' in torch.meshgrid.__code__.co_varnames: coord = torch.meshgrid(*coord_seqs, indexing='ij') else: coord = torch.meshgrid(*coord_seqs) coord = torch.stack(coord, dim=-1) if flatten: coord = coord.view(-1, coord.shape[-1]) return coord def bbox2mask(img_shape, bbox, dtype='uint8'): """Generate mask in np.ndarray from bbox. The returned mask has the shape of (h, w, 1). '1' indicates the hole and '0' indicates the valid regions. We prefer to use `uint8` as the data type of masks, which may be different from other codes in the community. Args: img_shape (tuple[int]): The size of the image. bbox (tuple[int]): Configuration tuple, (top, left, height, width) np.dtype (str): Indicate the data type of returned masks. Default: 'uint8' Returns: mask (np.ndarray): Mask in the shape of (h, w, 1). """ height, width = img_shape[:2] mask = np.zeros((height, width, 1), dtype=dtype) mask[bbox[0]:bbox[0] + bbox[2], bbox[1]:bbox[1] + bbox[3], :] = 1 return mask def brush_stroke_mask(img_shape, num_vertices=(4, 12), mean_angle=2 * math.pi / 5, angle_range=2 * math.pi / 15, brush_width=(12, 40), max_loops=4, dtype='uint8'): """Generate free-form mask. The method of generating free-form mask is in the following paper: Free-Form Image Inpainting with Gated Convolution. When you set the config of this type of mask. You may note the usage of `np.random.randint` and the range of `np.random.randint` is [left, right). We prefer to use `uint8` as the data type of masks, which may be different from other codes in the community. TODO: Rewrite the implementation of this function. Args: img_shape (tuple[int]): Size of the image. num_vertices (int | tuple[int]): Min and max number of vertices. If only give an integer, we will fix the number of vertices. Default: (4, 12). mean_angle (float): Mean value of the angle in each vertex. The angle is measured in radians. Default: 2 * math.pi / 5. angle_range (float): Range of the random angle. Default: 2 * math.pi / 15. brush_width (int | tuple[int]): (min_width, max_width). If only give an integer, we will fix the width of brush. Default: (12, 40). max_loops (int): The max number of for loops of drawing strokes. Default: 4. np.dtype (str): Indicate the data type of returned masks. Default: 'uint8'. Returns: mask (np.ndarray): Mask in the shape of (h, w, 1). """ img_h, img_w = img_shape[:2] if isinstance(num_vertices, int): min_num_vertices, max_num_vertices = num_vertices, num_vertices + 1 elif isinstance(num_vertices, tuple): min_num_vertices, max_num_vertices = num_vertices else: raise TypeError('The type of num_vertices should be int' f'or tuple[int], but got type: {num_vertices}') if isinstance(brush_width, tuple): min_width, max_width = brush_width elif isinstance(brush_width, int): min_width, max_width = brush_width, brush_width + 1 else: raise TypeError('The type of brush_width should be int' f'or tuple[int], but got type: {brush_width}') average_radius = math.sqrt(img_h * img_h + img_w * img_w) / 8 mask = Image.new('L', (img_w, img_h), 0) loop_num = np.random.randint(1, max_loops) num_vertex_list = np.random.randint( min_num_vertices, max_num_vertices, size=loop_num) angle_min_list = np.random.uniform(0, angle_range, size=loop_num) angle_max_list = np.random.uniform(0, angle_range, size=loop_num) for loop_n in range(loop_num): num_vertex = num_vertex_list[loop_n] angle_min = mean_angle - angle_min_list[loop_n] angle_max = mean_angle + angle_max_list[loop_n] angles = [] vertex = [] # set random angle on each vertex angles = np.random.uniform(angle_min, angle_max, size=num_vertex) reverse_mask = (np.arange(num_vertex, dtype=np.float32) % 2) == 0 angles[reverse_mask] = 2 * math.pi - angles[reverse_mask] h, w = mask.size # set random vertices vertex.append((np.random.randint(0, w), np.random.randint(0, h))) r_list = np.random.normal( loc=average_radius, scale=average_radius // 2, size=num_vertex) for i in range(num_vertex): r = np.clip(r_list[i], 0, 2 * average_radius) new_x = np.clip(vertex[-1][0] + r * math.cos(angles[i]), 0, w) new_y = np.clip(vertex[-1][1] + r * math.sin(angles[i]), 0, h) vertex.append((int(new_x), int(new_y))) # draw brush strokes according to the vertex and angle list draw = ImageDraw.Draw(mask) width = np.random.randint(min_width, max_width) draw.line(vertex, fill=1, width=width) for v in vertex: draw.ellipse((v[0] - width // 2, v[1] - width // 2, v[0] + width // 2, v[1] + width // 2), fill=1) # randomly flip the mask if np.random.normal() > 0: mask.transpose(Image.FLIP_LEFT_RIGHT) if np.random.normal() > 0: mask.transpose(Image.FLIP_TOP_BOTTOM) mask = np.array(mask).astype(dtype=getattr(np, dtype)) mask = mask[:, :, None] return mask def random_bbox(img_shape, max_bbox_shape, max_bbox_delta=40, min_margin=20): """Generate a random bbox for the mask on a given image. In our implementation, the max value cannot be obtained since we use `np.random.randint`. And this may be different with other standard scripts in the community. Args: img_shape (tuple[int]): The size of a image, in the form of (h, w). max_bbox_shape (int | tuple[int]): Maximum shape of the mask box, in the form of (h, w). If it is an integer, the mask box will be square. max_bbox_delta (int | tuple[int]): Maximum delta of the mask box, in the form of (delta_h, delta_w). If it is an integer, delta_h and delta_w will be the same. Mask shape will be randomly sampled from the range of `max_bbox_shape - max_bbox_delta` and `max_bbox_shape`. Default: (40, 40). min_margin (int | tuple[int]): The minimum margin size from the edges of mask box to the image boarder, in the form of (margin_h, margin_w). If it is an integer, margin_h and margin_w will be the same. Default: (20, 20). Returns: tuple[int]: The generated box, (top, left, h, w). """ if not isinstance(max_bbox_shape, tuple): max_bbox_shape = (max_bbox_shape, max_bbox_shape) if not isinstance(max_bbox_delta, tuple): max_bbox_delta = (max_bbox_delta, max_bbox_delta) if not isinstance(min_margin, tuple): min_margin = (min_margin, min_margin) assert is_tuple_of(max_bbox_shape, int) assert is_tuple_of(max_bbox_delta, int) assert is_tuple_of(min_margin, int) img_h, img_w = img_shape[:2] max_mask_h, max_mask_w = max_bbox_shape max_delta_h, max_delta_w = max_bbox_delta margin_h, margin_w = min_margin if max_mask_h > img_h or max_mask_w > img_w: raise ValueError(f'mask shape {max_bbox_shape} should be smaller than ' f'image shape {img_shape}') if (max_delta_h // 2 * 2 >= max_mask_h or max_delta_w // 2 * 2 >= max_mask_w): raise ValueError(f'mask delta {max_bbox_delta} should be smaller than' f'mask shape {max_bbox_shape}') if img_h - max_mask_h < 2 * margin_h or img_w - max_mask_w < 2 * margin_w: raise ValueError(f'Margin {min_margin} cannot be satisfied for img' f'shape {img_shape} and mask shape {max_bbox_shape}') # get the max value of (top, left) max_top = img_h - margin_h - max_mask_h max_left = img_w - margin_w - max_mask_w # randomly select a (top, left) top = np.random.randint(margin_h, max_top) left = np.random.randint(margin_w, max_left) # randomly shrink the shape of mask box according to `max_bbox_delta` # the center of box is fixed delta_top = np.random.randint(0, max_delta_h // 2 + 1) delta_left = np.random.randint(0, max_delta_w // 2 + 1) top = top + delta_top left = left + delta_left h = max_mask_h - delta_top w = max_mask_w - delta_left return (top, left, h, w) def random_irregular_mask(img_shape, num_vertices=(4, 8), max_angle=4, length_range=(10, 100), brush_width=(10, 40), dtype='uint8'): """Generate random irregular masks. This is a modified version of free-form mask implemented in 'brush_stroke_mask'. We prefer to use `uint8` as the data type of masks, which may be different from other codes in the community. TODO: Rewrite the implementation of this function. Args: img_shape (tuple[int]): Size of the image. num_vertices (int | tuple[int]): Min and max number of vertices. If only give an integer, we will fix the number of vertices. Default: (4, 8). max_angle (float): Max value of angle at each vertex. Default 4.0. length_range (int | tuple[int]): (min_length, max_length). If only give an integer, we will fix the length of brush. Default: (10, 100). brush_width (int | tuple[int]): (min_width, max_width). If only give an integer, we will fix the width of brush. Default: (10, 40). np.dtype (str): Indicate the data type of returned masks. Default: 'uint8' Returns: mask (np.ndarray): Mask in the shape of (h, w, 1). """ h, w = img_shape[:2] mask = np.zeros((h, w), dtype=dtype) if isinstance(length_range, int): min_length, max_length = length_range, length_range + 1 elif isinstance(length_range, tuple): min_length, max_length = length_range else: raise TypeError('The type of length_range should be int' f'or tuple[int], but got type: {length_range}') if isinstance(num_vertices, int): min_num_vertices, max_num_vertices = num_vertices, num_vertices + 1 elif isinstance(num_vertices, tuple): min_num_vertices, max_num_vertices = num_vertices else: raise TypeError('The type of num_vertices should be int' f'or tuple[int], but got type: {num_vertices}') if isinstance(brush_width, int): min_brush_width, max_brush_width = brush_width, brush_width + 1 elif isinstance(brush_width, tuple): min_brush_width, max_brush_width = brush_width else: raise TypeError('The type of brush_width should be int' f'or tuple[int], but got type: {brush_width}') num_v = np.random.randint(min_num_vertices, max_num_vertices) for i in range(num_v): start_x = np.random.randint(w) start_y = np.random.randint(h) # from the start point, randomly setlect n \in [1, 6] directions. direction_num = np.random.randint(1, 6) angle_list = np.random.randint(0, max_angle, size=direction_num) length_list = np.random.randint( min_length, max_length, size=direction_num) brush_width_list = np.random.randint( min_brush_width, max_brush_width, size=direction_num) for direct_n in range(direction_num): angle = 0.01 + angle_list[direct_n] if i % 2 == 0: angle = 2 * math.pi - angle length = length_list[direct_n] brush_w = brush_width_list[direct_n] # compute end point according to the random angle end_x = (start_x + length * np.sin(angle)).astype(np.int32) end_y = (start_y + length * np.cos(angle)).astype(np.int32) cv2.line(mask, (start_y, start_x), (end_y, end_x), 1, brush_w) start_x, start_y = end_x, end_y mask = np.expand_dims(mask, axis=2) return mask def get_irregular_mask(img_shape, area_ratio_range=(0.15, 0.5), **kwargs): """Get irregular mask with the constraints in mask ratio. Args: img_shape (tuple[int]): Size of the image. area_ratio_range (tuple(float)): Contain the minimum and maximum area ratio. Default: (0.15, 0.5). Returns: mask (np.ndarray): Mask in the shape of (h, w, 1). """ mask = random_irregular_mask(img_shape, **kwargs) min_ratio, max_ratio = area_ratio_range while not min_ratio < (np.sum(mask) / (img_shape[0] * img_shape[1])) < max_ratio: mask = random_irregular_mask(img_shape, **kwargs) return mask _integer_types = ( np.byte, np.ubyte, # 8 bits np.short, np.ushort, # 16 bits np.intc, np.uintc, # 16 or 32 or 64 bits np.int_, np.uint, # 32 or 64 bits np.longlong, np.ulonglong) # 64 bits _integer_ranges = { t: (np.iinfo(t).min, np.iinfo(t).max) for t in _integer_types } dtype_range = { np.bool_: (False, True), np.bool8: (False, True), np.float16: (-1, 1), np.float32: (-1, 1), np.float64: (-1, 1) } dtype_range.update(_integer_ranges) def dtype_limits(image, clip_negative=False): """Return intensity limits, i.e. (min, max) tuple, of the image's dtype. This function is adopted from skimage: https://github.com/scikit-image/scikit-image/blob/ 7e4840bd9439d1dfb6beaf549998452c99f97fdd/skimage/util/dtype.py#L35 Args: image (np.ndarray): Input image. clip_negative (bool, optional): If True, clip the negative range (i.e. return 0 for min intensity) even if the image dtype allows negative values. Default: False. Returns tuple: Lower and upper intensity limits. """ imin, imax = dtype_range[image.dtype.type] if clip_negative: imin = 0 return imin, imax def adjust_gamma(image, gamma=1, gain=1): """Performs Gamma Correction on the input image. This function is adopted from skimage: https://github.com/scikit-image/scikit-image/blob/ 7e4840bd9439d1dfb6beaf549998452c99f97fdd/skimage/exposure/ exposure.py#L439-L494 Also known as Power Law Transform. This function transforms the input image pixelwise according to the equation ``O = I**gamma`` after scaling each pixel to the range 0 to 1. Args: image (np.ndarray): Input image. gamma (float, optional): Non negative real number. Defaults to 1. gain (float, optional): The constant multiplier. Defaults to 1. Returns: np.ndarray: Gamma corrected output image. """ if np.any(image < 0): raise ValueError('Image Correction methods work correctly only on ' 'images with non-negative values. Use ' 'skimage.exposure.rescale_intensity.') dtype = image.dtype.type if gamma < 0: raise ValueError('Gamma should be a non-negative real number.') scale = float(dtype_limits(image, True)[1] - dtype_limits(image, True)[0]) out = ((image / scale)**gamma) * scale * gain return out.astype(dtype) def add_gaussian_noise(img: np.ndarray, mu, sigma): """Add Gaussian Noise on the input image. Args: img (np.ndarray): Input image. mu (float): The mu value of the Gaussian function. sigma (float): The sigma value of the Gaussian function. Returns: noisy_img (np.ndarray): Gaussian noisy output image. """ img = img.astype(np.float32) gauss_noise = np.random.normal(mu, sigma, img.shape) noisy_img = img + gauss_noise noisy_img = np.clip(noisy_img, 0, 255) return noisy_img def random_choose_unknown(unknown, crop_size): """Randomly choose an unknown start (top-left) point for a given crop_size. Args: unknown (np.ndarray): The binary unknown mask. crop_size (tuple[int]): The given crop size. Returns: tuple[int]: The top-left point of the chosen bbox. """ h, w = unknown.shape crop_h, crop_w = crop_size delta_h = center_h = crop_h // 2 delta_w = center_w = crop_w // 2 # mask out the validate area for selecting the cropping center mask = np.zeros_like(unknown) mask[delta_h:h - delta_h, delta_w:w - delta_w] = 1 if np.any(unknown & mask): center_h_list, center_w_list = np.where(unknown & mask) elif np.any(unknown): center_h_list, center_w_list = np.where(unknown) else: print_log('No unknown pixels found!', level=logging.WARNING) center_h_list = [center_h] center_w_list = [center_w] num_unknowns = len(center_h_list) rand_ind = np.random.randint(num_unknowns) center_h = center_h_list[rand_ind] center_w = center_w_list[rand_ind] # make sure the top-left point is valid top = np.clip(center_h - delta_h, 0, h - crop_h) left = np.clip(center_w - delta_w, 0, w - crop_w) return top, left ================================================ FILE: mmagic/utils/typing.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import Callable, Dict, List, Sequence, Tuple, Union from mmengine.config import ConfigDict from mmengine.structures import BaseDataElement from torch import Tensor ForwardInputs = Tuple[Dict[str, Union[Tensor, str, int]], Tensor] SampleList = Sequence[BaseDataElement] NoiseVar = Union[Tensor, Callable, None] LabelVar = Union[Tensor, Callable, List[int], None] ConfigType = Union[ConfigDict, Dict] ================================================ FILE: mmagic/version.py ================================================ # Copyright (c) Open-MMLab. All rights reserved. __version__ = '1.2.0dev0' def parse_version_info(version_str): ver_info = [] for x in version_str.split('.'): if x.isdigit(): ver_info.append(int(x)) elif x.find('rc') != -1: patch_version = x.split('rc') ver_info.append(int(patch_version[0])) ver_info.append(f'rc{patch_version[1]}') return tuple(ver_info) version_info = parse_version_info(__version__) ================================================ FILE: mmagic/visualization/__init__.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from .concat_visualizer import ConcatImageVisualizer from .vis_backend import (PaviVisBackend, TensorboardVisBackend, VisBackend, WandbVisBackend) from .visualizer import Visualizer __all__ = [ 'ConcatImageVisualizer', 'Visualizer', 'VisBackend', 'PaviVisBackend', 'TensorboardVisBackend', 'WandbVisBackend' ] ================================================ FILE: mmagic/visualization/concat_visualizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import logging import re from typing import Sequence import numpy as np import torch from mmengine.visualization import Visualizer from mmagic.registry import VISUALIZERS from mmagic.structures import DataSample from mmagic.utils import print_colored_log @VISUALIZERS.register_module() class ConcatImageVisualizer(Visualizer): """Visualize multiple images by concatenation. This visualizer will horizontally concatenate images belongs to different keys and vertically concatenate images belongs to different frames to visualize. Image to be visualized can be: - torch.Tensor or np.array - Image sequences of shape (T, C, H, W) - Multi-channel image of shape (1/3, H, W) - Single-channel image of shape (C, H, W) Args: fn_key (str): key used to determine file name for saving image. Usually it is the path of some input image. If the value is `dir/basename.ext`, the name used for saving will be basename. img_keys (str): keys, values of which are images to visualize. pixel_range (dict): min and max pixel value used to denormalize images, note that only float array or tensor will be denormalized, uint8 arrays are assumed to be unnormalized. bgr2rgb (bool): whether to convert the image from BGR to RGB. name (str): name of visualizer. Default: 'visualizer'. *args and \**kwargs: Other arguments are passed to `Visualizer`. # noqa """ def __init__(self, fn_key: str, img_keys: Sequence[str], pixel_range={}, bgr2rgb=False, name: str = 'visualizer', *args, **kwargs) -> None: super().__init__(name, *args, **kwargs) self.fn_key = fn_key self.img_keys = img_keys self.pixel_range = pixel_range self.bgr2rgb = bgr2rgb def add_datasample(self, data_sample: DataSample, step=0) -> None: """Concatenate image and draw. Args: input (torch.Tensor): Single input tensor from data_batch. data_sample (DataSample): Single data_sample from data_batch. output (DataSample): Single prediction output by model. step (int): Global step value to record. Default: 0. """ # Note: # with LocalVisBackend and default arguments, we have: # self.save_dir == runner._log_dir / 'vis_data' merged_dict = { **data_sample.to_dict(), } if 'output' in merged_dict.keys(): merged_dict.update(**merged_dict['output']) fn = merged_dict[self.fn_key] if isinstance(fn, list): fn = fn[0] fn = re.split(r' |/|\\', fn)[-1] fn = fn.split('.')[0] img_list = [] for k in self.img_keys: if k not in merged_dict: print_colored_log( f'Key "{k}" not in data_sample or outputs', level=logging.WARN) continue img = merged_dict[k] # PixelData if isinstance(img, dict) and ('data' in img): img = img['data'] # Tensor to array if isinstance(img, torch.Tensor): img = img.detach().cpu().numpy() if img.ndim == 3: img = img.transpose(1, 2, 0) elif img.ndim == 4: img = img.transpose(0, 2, 3, 1) # concat frame vertically if img.ndim == 4: img = np.concatenate(img, axis=0) # gray to 3 channel if (img.ndim == 3 and img.shape[2] == 1): img = np.concatenate((img, img, img), axis=2) # gray to 3 channel if img.ndim == 2: img = np.stack((img, img, img), axis=2) if self.bgr2rgb: img = img[..., ::-1] if img.dtype != np.uint8: # We assume uint8 type are not normalized if k in self.pixel_range: min_, max_ = self.pixel_range.get(k) img = ((img - min_) / (max_ - min_)) * 255 img = img.clip(0, 255).round().astype(np.uint8) img_list.append(img) max_height = max(img.shape[0] for img in img_list) for i, img in enumerate(img_list): if img.shape[0] < max_height: img_list[i] = np.concatenate([ img, np.ones((max_height - img.shape[0], *img.shape[1:]), dtype=img.dtype) * 127 ], axis=0) img_cat = np.concatenate(img_list, axis=1) for vis_backend in self._vis_backends.values(): vis_backend.add_image(fn, img_cat, step) ================================================ FILE: mmagic/visualization/vis_backend.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from typing import Optional, Union import cv2 import imageio import numpy as np import torch from mmengine import MessageHub from mmengine.config import Config from mmengine.fileio import dump, get_file_backend from mmengine.visualization import BaseVisBackend from mmengine.visualization import \ TensorboardVisBackend as BaseTensorboardVisBackend from mmengine.visualization import WandbVisBackend as BaseWandbVisBackend from mmengine.visualization.vis_backend import force_init_env from mmagic.registry import VISBACKENDS @VISBACKENDS.register_module() class VisBackend(BaseVisBackend): """MMagic visualization backend class. It can write image, config, scalars, etc. to the local hard disk and ceph path. You can get the drawing backend through the experiment property for custom drawing. Examples: >>> from mmagic.visualization import VisBackend >>> import numpy as np >>> vis_backend = VisBackend(save_dir='temp_dir', >>> ceph_path='s3://temp-bucket') >>> img = np.random.randint(0, 256, size=(10, 10, 3)) >>> vis_backend.add_image('img', img) >>> vis_backend.add_scalar('mAP', 0.6) >>> vis_backend.add_scalars({'loss': [1, 2, 3], 'acc': 0.8}) >>> cfg = Config(dict(a=1, b=dict(b1=[0, 1]))) >>> vis_backend.add_config(cfg) Args: save_dir (str): The root directory to save the files produced by the visualizer. img_save_dir (str): The directory to save images. Default to 'vis_image'. config_save_file (str): The file name to save config. Default to 'config.py'. scalar_save_file (str): The file name to save scalar values. Default to 'scalars.json'. ceph_path (Optional[str]): The remote path of Ceph cloud storage. Defaults to None. delete_local (bool): Whether delete local after uploading to ceph or not. If ``ceph_path`` is None, this will be ignored. Defaults to True. """ def __init__(self, save_dir: str, img_save_dir: str = 'vis_image', config_save_file: str = 'config.py', scalar_save_file: str = 'scalars.json', ceph_path: Optional[str] = None, delete_local_image: bool = True): assert config_save_file.split('.')[-1] == 'py' assert scalar_save_file.split('.')[-1] == 'json' super().__init__(save_dir) self._img_save_dir = img_save_dir self._config_save_file = config_save_file self._scalar_save_file = scalar_save_file self._ceph_path = ceph_path self._file_client = None self._delete_local_image = delete_local_image self._cfg = None def _init_env(self): if self._env_initialized: return self._env_initialized = True """Init save dir.""" os.makedirs(self._save_dir, exist_ok=True) self._img_save_dir = osp.join( self._save_dir, # type: ignore self._img_save_dir) self._config_save_file = osp.join( self._save_dir, # type: ignore self._config_save_file) self._scalar_save_file = osp.join( self._save_dir, # type: ignore self._scalar_save_file) if self._ceph_path is not None: # work_dir: A/B/.../C/D # ceph_path: s3://a/b # local_files: A/B/.../C/D/TIME_STAMP/vis_data/ # remote files: s3://a/b/D/TIME_STAMP/vis_data/ if self._cfg is None or self._cfg.get('work_dir', None) is None: message_hub = MessageHub.get_current_instance() cfg_str = message_hub.get_info('cfg') self._cfg = Config.fromstring(cfg_str, '.py') full_work_dir = osp.abspath(self._cfg['work_dir']) if full_work_dir.endswith('/'): full_work_dir = full_work_dir[:-1] # NOTE: handle src_path with `os.sep`, because may windows # and linux may have different separate. src_path = os.sep.join(full_work_dir.split(os.sep)[:-1]) # NOTE: handle tar_path with '/', because ceph use linux # environment tar_path = self._ceph_path[:-1] if \ self._ceph_path.endswith('/') else self._ceph_path backend_args = dict( backend='petrel', path_mapping={src_path: tar_path}) self._file_client = get_file_backend(backend_args=backend_args) @property # type: ignore @force_init_env def experiment(self) -> 'VisBackend': """Return the experiment object associated with this visualization backend.""" return self def add_config(self, config: Config, **kwargs) -> None: """Record the config to disk. Args: config (Config): The Config object """ assert isinstance(config, Config) self._cfg = config self._init_env() config.dump(self._config_save_file) self._upload(self._config_save_file) @force_init_env def add_image(self, name: str, image: np.array, step: int = 0, **kwargs) -> None: """Record the image to disk. Args: name (str): The image identifier. image (np.ndarray): The image to be saved. The format should be RGB. Default to None. step (int): Global step value to record. Default to 0. """ assert image.dtype == np.uint8 os.makedirs(self._img_save_dir, exist_ok=True) if image.ndim == 3: drawn_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) save_file_name = f'{name}_{step}.png' cv2.imwrite( osp.join(self._img_save_dir, save_file_name), drawn_image) elif image.ndim == 4: n_skip = kwargs.get('n_skip', 1) fps = kwargs.get('fps', 60) save_file_name = f'{name}_{step}.gif' save_file_path = osp.join(self._img_save_dir, save_file_name) frames_list = [] for frame in image[::n_skip]: frames_list.append(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) if not (image.shape[0] % n_skip == 0): frames_list.append(image[-1]) imageio.mimsave( save_file_path, frames_list, 'GIF', duration=1000. / fps) else: raise ValueError( 'Only support visualize image with dimension of 3 or 4. But ' f'receive input with shape \'{image.shape}\'.') self._upload( osp.join(self._img_save_dir, save_file_name), self._delete_local_image) @force_init_env def add_scalar(self, name: str, value: Union[int, float, torch.Tensor, np.ndarray], step: int = 0, **kwargs) -> None: """Record the scalar data to disk. Args: name (str): The scalar identifier. value (int, float, torch.Tensor, np.ndarray): Value to save. step (int): Global step value to record. Default to 0. """ if isinstance(value, torch.Tensor): value = value.item() self._dump({name: value, 'step': step}, self._scalar_save_file, 'json') @force_init_env def add_scalars(self, scalar_dict: dict, step: int = 0, file_path: Optional[str] = None, **kwargs) -> None: """Record the scalars to disk. The scalar dict will be written to the default and specified files if ``file_path`` is specified. Args: scalar_dict (dict): Key-value pair storing the tag and corresponding values. The value must be dumped into json format. step (int): Global step value to record. Default to 0. file_path (str, optional): The scalar's data will be saved to the ``file_path`` file at the same time if the ``file_path`` parameter is specified. Default to None. """ assert isinstance(scalar_dict, dict) scalar_dict_new = dict() for k, v in scalar_dict.items(): if isinstance(v, torch.Tensor): scalar_dict_new[k] = v.item() else: scalar_dict_new[k] = v scalar_dict_new.setdefault('step', step) if file_path is not None: assert file_path.split('.')[-1] == 'json' new_save_file_path = osp.join( self._save_dir, # type: ignore file_path) assert new_save_file_path != self._scalar_save_file, \ '``file_path`` and ``scalar_save_file`` have the ' \ 'same name, please set ``file_path`` to another value' self._dump(scalar_dict_new, new_save_file_path, 'json') self._dump(scalar_dict_new, self._scalar_save_file, 'json') self._upload(self._scalar_save_file) def _dump(self, value_dict: dict, file_path: str, file_format: str) -> None: """dump dict to file. Args: value_dict (dict) : The dict data to saved. file_path (str): The file path to save data. file_format (str): The file format to save data. """ with open(file_path, 'a+') as f: dump(value_dict, f, file_format=file_format) f.write('\n') def _upload(self, path: str, delete_local=False) -> None: """Upload file at path to remote. Args: path (str): Path of file to upload. """ if self._file_client is None: return with open(path, 'rb') as file: self._file_client.put(file, path) if delete_local: os.remove(path) @VISBACKENDS.register_module() class TensorboardVisBackend(BaseTensorboardVisBackend): @force_init_env def add_image(self, name: str, image: np.array, step: int = 0, **kwargs): """Record the image to Tensorboard. Additional support upload gif files. Args: name (str): The image identifier. image (np.ndarray): The image to be saved. The format should be RGB. step (int): Useless parameter. Wandb does not need this parameter. Default to 0. """ if image.ndim == 4: n_skip = kwargs.get('n_skip', 1) fps = kwargs.get('fps', 60) frames_list = [] for frame in image[::n_skip]: frames_list.append(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) if not (image.shape[0] % n_skip == 0): frames_list.append(image[-1]) frames_np = np.transpose( np.stack(frames_list, axis=0), (0, 3, 1, 2)) frames_tensor = torch.from_numpy(frames_np)[None, ...] self._tensorboard.add_video( name, frames_tensor, global_step=step, fps=fps) else: # write normal image self._tensorboard.add_image(name, image, step, dataformats='HWC') @VISBACKENDS.register_module() class PaviVisBackend(BaseVisBackend): """Visualization backend for Pavi.""" def __init__(self, save_dir: str, exp_name: Optional[str] = None, labels: Optional[str] = None, project: Optional[str] = None, model: Optional[str] = None, description: Optional[str] = None): self.save_dir = save_dir self._name = exp_name self._labels = labels self._project = project self._model = model self._description = description def _init_env(self): """Init save dir.""" try: import pavi except ImportError: raise ImportError( 'To use \'PaviVisBackend\' Pavi must be installed.') self._pavi = pavi.SummaryWriter( name=self._name, labels=self._labels, project=self._project, model=self._model, description=self._description, log_dir=self.save_dir) @property # type: ignore @force_init_env def experiment(self) -> 'VisBackend': """Return the experiment object associated with this visualization backend.""" return self._pavi @force_init_env def add_image(self, name: str, image: np.array, step: int = 0, **kwargs) -> None: """Record the image to Pavi. Args: name (str): The image identifier. image (np.ndarray): The image to be saved. The format should be RGB. Default to None. step (int): Global step value to record. Default to 0. """ assert image.dtype == np.uint8 drawn_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) self._pavi.add_image(name, drawn_image, step) @force_init_env def add_scalar(self, name: str, value: Union[int, float, torch.Tensor, np.ndarray], step: int = 0, **kwargs) -> None: """Record the scalar data to Pavi. Args: name (str): The scalar identifier. value (int, float, torch.Tensor, np.ndarray): Value to save. step (int): Global step value to record. Default to 0. """ if isinstance(value, torch.Tensor): value = value.item() self._pavi.add_scalar(name, value, step) @force_init_env def add_scalars(self, scalar_dict: dict, step: int = 0, file_path: Optional[str] = None, **kwargs) -> None: """Record the scalars to Pavi. The scalar dict will be written to the default and specified files if ``file_path`` is specified. Args: scalar_dict (dict): Key-value pair storing the tag and corresponding values. The value must be dumped into json format. step (int): Global step value to record. Default to 0. file_path (str, optional): The scalar's data will be saved to the ``file_path`` file at the same time if the ``file_path`` parameter is specified. Default to None. """ assert isinstance(scalar_dict, dict) for name, value in scalar_dict.items(): self.add_scalar(name, value, step) @VISBACKENDS.register_module() class WandbVisBackend(BaseWandbVisBackend): """Wandb visualization backend for MMagic.""" def _init_env(self): """Setup env for wandb.""" if not os.path.exists(self._save_dir): os.makedirs(self._save_dir, exist_ok=True) # type: ignore if self._init_kwargs is None: self._init_kwargs = {'dir': self._save_dir} else: self._init_kwargs.setdefault('dir', self._save_dir) try: import wandb except ImportError: raise ImportError( 'Please run "pip install wandb" to install wandb') # add timestamp at the end of name timestamp = self._save_dir.split('/')[-2] orig_name = self._init_kwargs.get('name', None) if orig_name: self._init_kwargs['name'] = f'{orig_name}_{timestamp}' wandb.init(**self._init_kwargs) self._wandb = wandb @force_init_env def add_image(self, name: str, image: np.array, step: int = 0, **kwargs): """Record the image to wandb. Additional support upload gif files. Args: name (str): The image identifier. image (np.ndarray): The image to be saved. The format should be RGB. step (int): Useless parameter. Wandb does not need this parameter. Default to 0. """ try: import wandb except ImportError: raise ImportError( 'Please run "pip install wandb" to install wandb') if image.ndim == 4: n_skip = kwargs.get('n_skip', 1) fps = kwargs.get('fps', 60) frames_list = [] for frame in image[::n_skip]: frames_list.append(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) if not (image.shape[0] % n_skip == 0): frames_list.append(image[-1]) frames_np = np.transpose( np.stack(frames_list, axis=0), (0, 3, 1, 2)) self._wandb.log( {name: wandb.Video(frames_np, fps=fps, format='gif')}, commit=self._commit) else: # write normal image self._wandb.log({name: wandb.Image(image)}, commit=self._commit) ================================================ FILE: mmagic/visualization/visualizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from typing import Dict, List, Optional, Sequence, Tuple, Union import numpy as np import torch from mmengine.dist import master_only from mmengine.visualization import Visualizer as BaseVisualizer from torch import Tensor from torchvision.utils import make_grid from mmagic.registry import VISUALIZERS from mmagic.structures import DataSample from mmagic.utils.typing import SampleList mean_std_type = Optional[Sequence[Union[float, int]]] @VISUALIZERS.register_module() class Visualizer(BaseVisualizer): """MMagic Visualizer. Args: name (str): Name of the instance. Defaults to 'visualizer'. vis_backends (list, optional): Visual backend config list. Defaults to None. save_dir (str, optional): Save file dir for all storage backends. If it is None, the backend storage will not save any data. Examples:: >>> # Draw image >>> vis = Visualizer() >>> vis.add_datasample( >>> 'random_noise', >>> gen_samples=torch.rand(2, 3, 10, 10), >>> gt_samples=dict(imgs=torch.randn(2, 3, 10, 10)), >>> gt_keys='imgs', >>> vis_mode='image', >>> n_rows=2, >>> step=10) """ def __init__(self, name='visualizer', vis_backends: Optional[List[Dict]] = None, save_dir: Optional[str] = None) -> None: super().__init__(name, vis_backends=vis_backends, save_dir=save_dir) @staticmethod def _post_process_image(image: Tensor) -> Tensor: """Post process images. Args: image (Tensor): Image to post process. The value range of image should be in [0, 255] and the channel order should be BGR. Returns: Tensor: Image in RGB color order. """ # input image should be [0, 255] and BGR if image.shape[1] == 1: image = torch.cat([image, image, image], dim=1) image = image[:, [2, 1, 0], ...] return image @staticmethod def _get_n_row_and_padding(samples: Tuple[dict, Tensor], n_row: Optional[int] = None ) -> Tuple[int, Optional[Tensor]]: """Get number of sample in each row and tensor for padding the empty position. Args: samples (Tuple[dict, Tensor]): Samples to visualize. n_row (int, optional): Number of images displayed in each row of. If not passed, n_row will be set as ``int(sqrt(batch_size))``. Returns: Tuple[int, Optional[int]]: Number of sample in each row and tensor for padding the empty position. """ if isinstance(samples, dict): for sample in iter(samples.values()): # NOTE: dirty way to get the shape of image tensor if isinstance(sample, Tensor) and sample.ndim in [4, 5]: sample_shape = sample.shape break else: sample_shape = samples.shape n_samples = sample_shape[0] if n_row is None: n_row = math.ceil(math.sqrt(n_samples)) if n_samples % n_row == 0: n_padding = 0 else: n_padding = n_row - (n_samples % n_row) if n_padding: return n_row, -1.0 * torch.ones(n_padding, *sample_shape[1:]) return n_row, None def _vis_gif_sample(self, gen_samples: SampleList, target_keys: Union[str, List[str], None], n_row: int) -> np.ndarray: """Visualize gif samples. Args: gen_samples (SampleList): List of data samples to visualize target_keys (Union[str, List[str], None]): Keys of the visualization target in data samples. n_rows (int, optional): Number of images in one row. Returns: np.ndarray: The visualization results. """ def post_process_sequence(samples): num_timesteps = samples.shape[1] seq_list = [ self._post_process_image(samples[:, t, ...].cpu()) for t in range(num_timesteps) ] return torch.stack(seq_list, dim=1) if target_keys is None: # get all the keys that are tensors with 4 dimensions target_keys = [ k for k, v in gen_samples[0].items() if ((not k.startswith('_')) and (isinstance(v, Tensor)) and ( v.data.ndim == 4)) ] target_keys = [target_keys] if isinstance(target_keys, str) \ else target_keys sample_list = list() for sample in gen_samples: sample_dict = dict() for k in target_keys: sample_dict[k] = self._get_vis_data_by_key(sample, k) sample_list.append(sample_dict) for k in sample_list[0].keys(): sample_ = torch.stack([samp[k] for samp in sample_list], dim=0) sample_ = post_process_sequence(sample_.cpu()) sample_dict[k] = sample_ n_row, padding_tensor = self._get_n_row_and_padding(sample_dict, n_row) num_timesteps = next(iter(sample_dict.values())).shape[1] vis_results = [] for sample in sample_dict.values(): if padding_tensor is not None: vis_results.append(torch.cat([sample, padding_tensor], dim=0)) else: vis_results.append(sample) # concatenate along batch size vis_results = torch.cat(vis_results) vis_results = [ make_grid(vis_results[:, t, ...].cpu(), nrow=n_row).cpu().permute(1, 2, 0) for t in range(num_timesteps) ] vis_results = torch.stack(vis_results, dim=0) # [t, H, W, 3] vis_results = vis_results.numpy().astype(np.uint8) return vis_results def _vis_image_sample(self, gen_samples: SampleList, target_keys: Union[str, List[str], None], n_row: int) -> np.ndarray: """Visualize image samples. Args: gen_samples (SampleList): List of data samples to visualize target_keys (Union[str, List[str], None]): Keys of the visualization target in data samples. color_order (str): The color order of the passed images. target_mean (Sequence[Union[float, int]]): The target mean of the visualization results. target_std (Sequence[Union[float, int]]): The target std of the visualization results. n_rows (int, optional): Number of images in one row. Returns: np.ndarray: The visualization results. """ if target_keys is None: # get all key of image tensor automatically target_keys = [ k for k, v in gen_samples[0].items() if ((not k.startswith('_')) and (isinstance(v, Tensor)) and ( v.data.ndim == 3)) ] target_keys = [target_keys] if isinstance(target_keys, str) \ else target_keys sample_list = list() for sample in gen_samples: sample_dict = dict() for k in target_keys: sample_dict[k] = self._get_vis_data_by_key(sample, k) sample_list.append(sample_dict) for k in sample_list[0].keys(): sample_ = torch.stack([samp[k] for samp in sample_list], dim=0) sample_ = self._post_process_image(sample_.cpu()) sample_dict[k] = sample_ n_row, padding_tensor = self._get_n_row_and_padding(sample_dict, n_row) vis_results = [] for sample in sample_dict.values(): if padding_tensor is not None: vis_results.append(torch.cat([sample, padding_tensor], dim=0)) else: vis_results.append(sample) # concatenate along batch size vis_results = torch.cat(vis_results, dim=0) vis_results = make_grid(vis_results, nrow=n_row).cpu().permute(1, 2, 0) vis_results = vis_results.numpy().astype(np.uint8) return vis_results def _get_vis_data_by_key(self, sample: DataSample, key: str) -> Tensor: """Get tensor in ``DataSample`` by the given key. Args: sample (DataSample): Input data sample. key (str): Name of the target tensor. Returns: Tensor: Tensor from the data sample. """ if '.' in key: key_list = key.split('.') else: key_list = [key] vis_data = sample for k in key_list: # get vis data step by step assert hasattr(vis_data, k) vis_data = getattr(vis_data, k) if isinstance(vis_data, Tensor): return vis_data else: # check only one tensor in current datasample to visualize elements = [ element for k, element in vis_data.items() if not k.startswith('_') and isinstance(element, Tensor) ] assert len(elements) == 1, ( f'Find {len(elements)} Tensor in DataSample with ' f'key {key}.') vis_data = elements[0] assert isinstance( vis_data, Tensor), (f'Element with key \'{key}\' is not a Tensor.') return vis_data def add_datasample(self, name: str, *, gen_samples: Sequence[DataSample], target_keys: Optional[Tuple[str, List[str]]] = None, vis_mode: Optional[str] = None, n_row: Optional[int] = None, show: bool = False, wait_time: int = 0, step: int = 0, **kwargs) -> None: """Draw datasample and save to all backends. If GT and prediction are plotted at the same time, they are displayed in a stitched image where the left image is the ground truth and the right image is the prediction. If ``show`` is True, all storage backends are ignored, and the images will be displayed in a local window. Args: name (str): The image identifier. gen_samples (List[DataSample]): Data samples to visualize. vis_mode (str, optional): Visualization mode. If not passed, will visualize results as image. Defaults to None. n_rows (int, optional): Number of images in one row. Defaults to None. color_order (str): The color order of the passed images. Defaults to 'bgr'. target_mean (Sequence[Union[float, int]]): The target mean of the visualization results. Defaults to 127.5. target_std (Sequence[Union[float, int]]): The target std of the visualization results. Defaults to 127.5. show (bool): Whether to display the drawn image. Default to False. wait_time (float): The interval of show (s). Defaults to 0. step (int): Global step value to record. Defaults to 0. """ # get visualize function if vis_mode is None: vis_func = self._vis_image_sample else: vis_func = getattr(self, f'_vis_{vis_mode}_sample') vis_sample = vis_func(gen_samples, target_keys, n_row) if show: self.show(vis_sample, win_name=name, wait_time=wait_time) self.add_image(name, vis_sample, step, **kwargs) @master_only def add_image(self, name: str, image: np.ndarray, step: int = 0, **kwargs) -> None: """Record the image. Support input kwargs. Args: name (str): The image identifier. image (np.ndarray, optional): The image to be saved. The format should be RGB. Default to None. step (int): Global step value to record. Default to 0. """ for vis_backend in self._vis_backends.values(): vis_backend.add_image(name, image, step, **kwargs) # type: ignore ================================================ FILE: model-index.yml ================================================ Import: - configs/animatediff/metafile.yml - configs/aot_gan/metafile.yml - configs/basicvsr/metafile.yml - configs/basicvsr_pp/metafile.yml - configs/biggan/metafile.yml - configs/cain/metafile.yml - configs/controlnet/metafile.yml - configs/controlnet_animation/metafile.yml - configs/cyclegan/metafile.yml - configs/dcgan/metafile.yml - configs/deblurganv2/metafile.yml - configs/deepfillv1/metafile.yml - configs/deepfillv2/metafile.yml - configs/dic/metafile.yml - configs/diffusers_pipeline/metafile.yml - configs/dim/metafile.yml - configs/disco_diffusion/metafile.yml - configs/draggan/metafile.yml - configs/dreambooth/metafile.yml - configs/edsr/metafile.yml - configs/edvr/metafile.yml - configs/eg3d/metafile.yml - configs/esrgan/metafile.yml - configs/fastcomposer/metafile.yml - configs/flavr/metafile.yml - configs/gca/metafile.yml - configs/ggan/metafile.yml - configs/glean/metafile.yml - configs/global_local/metafile.yml - configs/guided_diffusion/metafile.yml - configs/iconvsr/metafile.yml - configs/indexnet/metafile.yml - configs/inst_colorization/metafile.yml - configs/liif/metafile.yml - configs/lsgan/metafile.yml - configs/nafnet/metafile.yml - configs/partial_conv/metafile.yml - configs/pggan/metafile.yml - configs/pix2pix/metafile.yml - configs/positional_encoding_in_gans/metafile.yml - configs/rdn/metafile.yml - configs/real_basicvsr/metafile.yml - configs/real_esrgan/metafile.yml - configs/restormer/metafile.yml - configs/sagan/metafile.yml - configs/singan/metafile.yml - configs/sngan_proj/metafile.yml - configs/srcnn/metafile.yml - configs/srgan_resnet/metafile.yml - configs/stable_diffusion/metafile.yml - configs/stable_diffusion_xl/metafile.yml - configs/styleganv1/metafile.yml - configs/styleganv2/metafile.yml - configs/styleganv3/metafile.yml - configs/swinir/metafile.yml - configs/tdan/metafile.yml - configs/textual_inversion/metafile.yml - configs/tof/metafile.yml - configs/ttsr/metafile.yml - configs/vico/metafile.yml - configs/wgan-gp/metafile.yml ================================================ FILE: projects/README.md ================================================ # Welcome to Projects of MMagic Welcome to the MMagic community! The MMagic ecosystem consists of tutorials, libraries, and projects from a broad set of researchers in academia and industry, ML and application engineers. The goal of this ecosystem is to support, accelerate, and aid in your AIGC exploration with MMagic for image, video, 3D content generation, editing and processing. Here are a few projects that are built upon MMagic. They are examples of how to use MMagic as a library, to make your projects more maintainable. Please find more projects in [MMagic Ecosystem](https://openmmlab.com/ecosystem). ## Show your projects on OpenMMLab Ecosystem You can submit your project so that it can be shown on the homepage of [OpenMMLab](https://openmmlab.com/ecosystem). ## Add example projects to MMagic Here is an [example project](./example_project) about how to add your projects to MMagic. You can copy and create your own project from the [example project](./example_project). We also provide some documentation listed below for your reference: - [Contribution Guide](https://mmagic.readthedocs.io/en/latest/community/contributing.html) The guides for new contributors about how to add your projects to MMagic. - [New Model Guide](https://mmagic.readthedocs.io/en/latest/howto/models.html) The documentation of adding new models. - [Discussions](https://github.com/open-mmlab/mmagic/discussions) Welcome to start a discussion! ## Projects of libraries and toolboxes - [PowerVQE](https://github.com/ryanxingql/powervqe): Open framework for quality enhancement of compressed videos based on PyTorch and MMagic. - [VR-Baseline](https://github.com/linjing7/VR-Baseline): Video Restoration Toolbox. - [Derain-Toolbox](https://github.com/biubiubiiu/derain-toolbox): Single Image Deraining Toolbox and Benchmark ## Projects of research papers - [Towards Interpretable Video Super-Resolution via Alternating Optimization, ECCV 2022](https://arxiv.org/abs/2207.10765)[\[github\]](https://github.com/caojiezhang/DAVSR) - [SepLUT:Separable Image-adaptive Lookup Tables for Real-time Image Enhancement, ECCV 2022](https://arxiv.org/abs/2207.08351)[\[github\]](https://github.com/ImCharlesY/SepLUT) - [TTVSR: Learning Trajectory-Aware Transformer for Video Super-Resolution, CVPR 2022](https://arxiv.org/abs/2204.04216)[\[github\]](https://github.com/researchmm/TTVSR) - [Arbitrary-Scale Image Synthesis, CVPR 2022](https://arxiv.org/pdf/2204.02273.pdf)[\[github\]](https://github.com/vglsd/ScaleParty) - [Investigating Tradeoffs in Real-World Video Super-Resolution(RealBasicVSR), CVPR 2022](https://arxiv.org/abs/2111.12704)[\[github\]](https://github.com/ckkelvinchan/RealBasicVSR) - [BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment, CVPR 2022](https://arxiv.org/abs/2104.13371)[\[github\]](https://github.com/ckkelvinchan/BasicVSR_PlusPlus) - [Multi-Scale Memory-Based Video Deblurring, CVPR 2022](https://arxiv.org/abs/2204.02977)[\[github\]](https://github.com/jibo27/MemDeblur) - [AdaInt:Learning Adaptive Intervals for 3D Lookup Tables on Real-time Image Enhancement, CVPR 2022](https://arxiv.org/abs/2204.13983)[\[github\]](https://github.com/ImCharlesY/AdaInt) - [A New Dataset and Transformer for Stereoscopic Video Super-Resolution, CVPRW 2022](https://openaccess.thecvf.com/content/CVPR2022W/NTIRE/papers/Imani_A_New_Dataset_and_Transformer_for_Stereoscopic_Video_Super-Resolution_CVPRW_2022_paper.pdf)[\[github\]](https://github.com/H-deep/Trans-SVSR) - [Liquid warping GAN with attention: A unified framework for human image synthesis, TPAMI 2021](https://arxiv.org/pdf/2011.09055.pdf)[\[github\]](https://github.com/iPERDance/iPERCore) - [BasicVSR:The Search for Essential Components in Video Super-Resolution and Beyond, CVPR 2021](https://arxiv.org/abs/2012.02181)[\[github\]](https://github.com/ckkelvinchan/BasicVSR-IconVSR) - [GLEAN:Generative Latent Bank for Large-Factor Image Super-Resolution, CVPR 2021](https://arxiv.org/abs/2012.00739)[\[github\]](https://github.com/ckkelvinchan/GLEAN) - [DAN:Unfolding the Alternating Optimization for Blind Super Resolution, NeurIPS 2020](https://arxiv.org/abs/2010.02631v4)[\[github\]](https://github.com/AlexZou14/DAN-Basd-on-Openmmlab) ================================================ FILE: projects/animated_drawings/README.md ================================================ # Animated Drawings (SIGGRAPH'2023) > [A Method for Animating Children's Drawings of The Human Figure](https://arxiv.org/abs/2303.12741) > **Task**: Drawing ## Abstract Children’s drawings have a wonderful inventiveness, creativity, and variety to them. We present a system that automatically animates children’s drawings of the human figure, is robust to the variance inherent in these depictions, and is simple and straightforward enough for anyone to use. We demonstrate the value and broad appeal of our approach by building and releasing the Animated Drawings Demo, a freely available public website that has been used by millions of people around the world. We present a set of experiments exploring the amount of training data needed for fine-tuning, as well as a perceptual study demonstrating the appeal of a novel twisted perspective retargeting technique. Finally, we introduce the Amateur Drawings Dataset, a first-of-its-kind annotated dataset, collected via the public demo, containing over 178,000 amateur drawings and corresponding user-accepted character bounding boxes, segmentation masks, and joint location annotations.
## Quick Start ### 1. Install Animated Drawings ```shell cd mmagic/projects/animated_drawings pip install -e git+https://github.com/facebookresearch/AnimatedDrawings.git#egg=animated_drawings ``` ### 2. Download resources ```shell cd mmagic/projects/animated_drawings mkdir resources # download image wget -O sakuragi.png https://user-images.githubusercontent.com/12782558/236157945-452fb9d0-e02e-4f36-8338-34f0ca0fe962.png # download mask image wget -O sakuragi_mask.png https://user-images.githubusercontent.com/12782558/236157965-539a5467-edae-40d0-a9da-7bb5906bcdc4.png # download background image wget -O basketball_playground.png https://user-images.githubusercontent.com/12782558/236190727-0e456482-2ae3-4304-9e6c-6ba7d319ea71.png ``` ### 3. Generate character By running following codes, you will get texture and mask images for animated rendering in characters/slamdunk directory. ```shell cd mmagic/projects/animated_drawings python tools/generate_character.py ``` ### 3. Generate video By running following codes, you will get a Sakuragi moving like a zombie. ```shell cd mmagic/projects/animated_drawings python tools/generate_video.py ``` The output video will be saved at resources dir, and it looks like this:
## Citation ```bibtex @misc{smith2023method, title={A Method for Animating Children's Drawings of the Human Figure}, author={Harrison Jesse Smith and Qingyuan Zheng and Yifei Li and Somya Jain and Jessica K. Hodgins}, year={2023}, eprint={2303.12741}, archivePrefix={arXiv}, primaryClass={cs.CV} } ``` ================================================ FILE: projects/animated_drawings/bvh/zombie.bvh ================================================ HIERARCHY ROOT Hips { OFFSET 0.00 0.00 0.00 CHANNELS 6 Xposition Yposition Zposition Xrotation Yrotation Zrotation JOINT Spine { OFFSET 0.00000 1.15266 1.72900 CHANNELS 3 Xrotation Yrotation Zrotation JOINT Spine1 { OFFSET 0.00000 0.40032 2.27031 CHANNELS 3 Xrotation Yrotation Zrotation JOINT Spine2 { OFFSET 0.00000 0.20092 2.29656 CHANNELS 3 Xrotation Yrotation Zrotation JOINT Spine3 { OFFSET 0.00000 0.00000 2.30533 CHANNELS 3 Xrotation Yrotation Zrotation JOINT Neck { OFFSET 0.00000 -0.86449 6.05149 CHANNELS 3 Xrotation Yrotation Zrotation JOINT Head { OFFSET 0.00000 -0.55043 3.12167 CHANNELS 3 Xrotation Yrotation Zrotation End Site { OFFSET 0.00000 0.00000 3.73175 } } } JOINT RightShoulder { OFFSET -0.78828 -1.31380 4.25672 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightArm { OFFSET -3.91513 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightForeArm { OFFSET -6.91491 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightHand { OFFSET -6.09622 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightHandEnd { OFFSET -1.74995 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation End Site { OFFSET -1.74995 0.00000 0.00000 } } JOINT RightHandThumb1 { OFFSET -0.69998 -1.16663 -0.46665 CHANNELS 3 Yrotation Xrotation Zrotation End Site { OFFSET -1.69032 -0.45292 0.00000 } } } } } } JOINT LeftShoulder { OFFSET 0.78828 -1.31380 4.25672 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftArm { OFFSET 3.91513 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftForeArm { OFFSET 6.91491 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftHand { OFFSET 6.09622 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftHandEnd { OFFSET 1.74995 0.00000 0.00000 CHANNELS 3 Xrotation Yrotation Zrotation End Site { OFFSET 1.74995 0.00000 0.00000 } } JOINT LeftHandThumb1 { OFFSET 0.69998 -1.16663 -0.46665 CHANNELS 3 Yrotation Xrotation Zrotation End Site { OFFSET 1.69032 -0.45292 0.00000 } } } } } } } } } } JOINT RightUpLeg { OFFSET -2.33857 0.00000 -0.68318 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightLeg { OFFSET 0.00000 0.00000 -10.74496 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightFoot { OFFSET 0.00000 0.00000 -10.93085 CHANNELS 3 Xrotation Yrotation Zrotation JOINT RightToeBase { OFFSET 0.00000 -4.08727 -1.48765 CHANNELS 3 Xrotation Yrotation Zrotation End Site { OFFSET 0.00000 -1.89187 -0.00000 } } } } } JOINT LeftUpLeg { OFFSET 2.33857 0.00000 -0.68318 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftLeg { OFFSET 0.00000 0.00000 -10.74496 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftFoot { OFFSET 0.00000 0.00000 -10.93085 CHANNELS 3 Xrotation Yrotation Zrotation JOINT LeftToeBase { OFFSET 0.00000 -4.08727 -1.48765 CHANNELS 3 Xrotation Yrotation Zrotation End Site { OFFSET 0.00000 -1.89187 -0.00000 } } } } } } MOTION Frames: 779 Frame Time: 0.0333333 0.1081 -113.8641 24.4236 -6.3750 0.7993 174.1813 -0.0953 1.7897 0.3053 -0.3614 0.2761 0.1877 0.7990 -0.1400 4.9767 -1.4096 -0.8139 1.4970 -2.5341 -3.3677 -3.3142 3.3078 -1.2990 -7.1278 -6.4106 -0.5739 -2.4492 -10.4508 -2.0339 10.0589 0.0000 0.0000 12.1538 0.0637 4.7831 -15.3322 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -9.3109 1.9097 0.2116 -6.0004 0.1782 -15.5610 -0.0000 0.0000 2.3711 6.2266 11.8306 4.9716 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -15.1304 1.0672 -2.8595 12.2683 0.0000 0.0000 -4.2579 0.8079 4.6097 1.6031 0.0000 0.0000 -6.0430 1.7069 2.9203 1.2763 0.0000 0.0000 -5.2588 0.9797 4.8866 -10.1323 0.0000 -0.0000 0.1079 -113.8686 24.4224 -6.3199 0.8366 174.0418 -0.0988 1.7864 0.3152 -0.3659 0.2548 0.1921 0.8374 -0.0605 5.0930 -1.3909 -0.8112 1.4935 -2.4917 -3.2868 -3.4655 3.1313 -1.3927 -7.4013 -6.2072 -0.6167 -2.3347 -10.3995 -1.9826 10.0459 0.0000 0.0000 12.1126 -0.1044 4.8419 -15.1945 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -9.1497 2.0464 0.1636 -5.9267 0.1111 -15.3938 -0.0000 0.0000 2.3954 6.2524 11.7179 4.9499 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -15.1482 1.0814 -2.8012 12.3519 0.0000 0.0000 -4.2833 0.8585 4.6873 1.6347 0.0000 0.0000 -6.0401 1.7337 2.9826 1.3849 0.0000 0.0000 -5.3472 0.9041 4.9651 -10.0684 0.0000 -0.0000 0.1079 -113.8732 24.4215 -6.2277 0.8769 173.8209 -0.1314 1.7244 0.3367 -0.4035 0.1958 0.1984 0.9460 0.1383 5.2991 -1.3283 -0.7790 1.4777 -2.3977 -3.2255 -3.7001 2.8417 -1.4821 -7.8039 -5.8961 -0.7868 -2.2646 -10.3788 -1.8077 10.2038 0.0000 0.0000 11.9409 -0.2890 4.8491 -15.1174 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -8.9047 2.2548 0.0294 -5.9347 0.0171 -15.1029 -0.0000 0.0000 2.4298 6.3042 11.6357 4.9176 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -15.1107 1.0909 -2.7461 12.3784 0.0000 0.0000 -4.2626 0.8808 4.8474 1.6268 0.0000 0.0000 -5.9833 1.7663 3.0944 1.4746 0.0000 0.0000 -5.4348 0.7095 5.0934 -9.7424 0.0000 -0.0000 0.1087 -113.8780 24.4217 -6.1983 0.8995 173.6527 -0.1730 1.6524 0.3534 -0.4412 0.1469 0.2049 1.0357 0.3317 5.4612 -1.2835 -0.7393 1.4601 -2.3881 -3.2217 -3.9204 2.6532 -1.5105 -8.1725 -5.6820 -0.9430 -2.2244 -10.4151 -1.6737 10.3028 0.0000 0.0000 11.8120 -0.3784 4.8122 -15.1513 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -8.7325 2.4736 -0.0639 -6.0416 -0.0278 -14.8610 -0.0000 0.0000 2.4736 6.2846 11.6479 4.9282 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.0763 1.0885 -2.7506 12.2973 0.0000 0.0000 -4.1855 0.8665 5.0169 1.5819 0.0000 0.0000 -5.9804 1.7815 3.2145 1.5295 0.0000 0.0000 -5.4654 0.5082 5.1784 -9.3226 0.0000 -0.0000 0.1126 -113.8820 24.4232 -6.2059 0.8844 173.6270 -0.1447 1.6194 0.3491 -0.4358 0.1161 0.2028 1.0627 0.4618 5.5006 -1.3030 -0.7140 1.4457 -2.5604 -3.2676 -4.0955 2.6712 -1.5104 -8.4456 -5.6464 -0.9554 -2.1580 -10.4357 -1.7398 10.1353 0.0000 0.0000 11.8452 -0.3624 4.8209 -15.2210 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.7125 2.6046 -0.0595 -6.1169 0.0532 -14.7231 -0.0000 0.0000 2.5316 6.1832 11.6645 5.0114 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -15.0272 1.0639 -2.8288 12.1615 0.0000 0.0000 -4.0980 0.8639 5.1121 1.5446 0.0000 0.0000 -6.0331 1.7547 3.3263 1.6007 0.0000 0.0000 -5.4608 0.4466 5.1188 -9.1174 0.0000 -0.0000 0.1191 -113.8873 24.4242 -6.2037 0.8718 173.6878 -0.0783 1.6291 0.3364 -0.4107 0.1146 0.2037 1.0969 0.5531 5.4640 -1.3474 -0.6890 1.4309 -2.8110 -3.3321 -4.2654 2.7535 -1.5447 -8.6774 -5.6406 -0.8803 -2.0806 -10.3911 -1.9316 9.8328 0.0000 0.0000 11.8949 -0.3322 4.8781 -15.2454 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -8.7370 2.6204 -0.0728 -6.0662 0.2219 -14.5694 -0.0000 0.0000 2.5795 6.1085 11.5625 5.1285 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.0200 1.0471 -2.8934 12.1447 0.0000 0.0000 -4.0730 0.8946 5.1055 1.5409 0.0000 0.0000 -6.1119 1.7225 3.4608 1.7210 0.0000 0.0000 -5.4639 0.5086 4.9229 -9.1574 0.0000 -0.0000 0.1270 -113.8938 24.4235 -6.1692 0.8867 173.7455 -0.0330 1.6651 0.3303 -0.3987 0.1193 0.2063 1.1832 0.6688 5.4343 -1.3650 -0.6728 1.4083 -2.9620 -3.3869 -4.4362 2.7403 -1.6216 -8.9088 -5.5296 -0.8501 -2.0683 -10.3024 -2.0641 9.6841 0.0000 0.0000 11.7575 -0.3727 4.8768 -15.2365 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -8.6663 2.5952 -0.1534 -5.9543 0.3668 -14.3747 -0.0000 0.0000 2.5829 6.1113 11.3590 5.2133 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -15.0685 1.0516 -2.8718 12.2890 0.0000 0.0000 -4.1167 0.9260 5.0262 1.5453 0.0000 0.0000 -6.1595 1.7152 3.5784 1.8385 0.0000 0.0000 -5.4793 0.5657 4.7369 -9.2128 0.0000 -0.0000 0.1354 -113.8993 24.4220 -6.1299 0.9141 173.7782 0.0097 1.7316 0.3281 -0.3870 0.1454 0.2107 1.2507 0.7500 5.4053 -1.3832 -0.6862 1.3833 -3.0033 -3.3937 -4.5680 2.6890 -1.7032 -9.1335 -5.3831 -0.8729 -2.1530 -10.2161 -2.1009 9.7342 0.0000 0.0000 11.5122 -0.4515 4.7769 -15.2629 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.5323 2.6400 -0.1482 -5.9049 0.4273 -14.2983 -0.0000 0.0000 2.5516 6.1151 11.1850 5.2588 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -15.1266 1.0617 -2.8062 12.4568 0.0000 0.0000 -4.1744 0.9404 4.9402 1.5292 0.0000 0.0000 -6.1623 1.7242 3.6221 1.8893 0.0000 0.0000 -5.4836 0.5683 4.6650 -9.1666 0.0000 -0.0000 0.1446 -113.9027 24.4214 -6.1217 0.9239 173.7954 0.0877 1.8197 0.3242 -0.3425 0.1909 0.2120 1.2284 0.7530 5.3502 -1.4490 -0.7131 1.3659 -3.0773 -3.3501 -4.6595 2.7479 -1.7501 -9.3423 -5.3531 -0.9081 -2.3161 -10.1288 -2.1131 9.8424 0.0000 0.0000 11.3886 -0.4703 4.6843 -15.3389 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.5045 2.7765 0.0646 -5.9261 0.4239 -14.4273 -0.0000 0.0000 2.5444 6.0657 11.0956 5.3035 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.1490 1.0508 -2.7957 12.5043 0.0000 0.0000 -4.1904 0.9591 4.9201 1.5015 0.0000 0.0000 -6.1437 1.7153 3.6007 1.8537 0.0000 0.0000 -5.4617 0.5734 4.6850 -9.1236 0.0000 -0.0000 0.1555 -113.9041 24.4225 -6.1303 0.9028 173.7754 0.1828 1.8866 0.3192 -0.2681 0.2338 0.2152 1.1435 0.7296 5.2899 -1.5380 -0.7207 1.3570 -3.2150 -3.2997 -4.7414 2.8966 -1.7515 -9.5261 -5.4248 -0.9779 -2.4983 -10.0440 -2.0962 9.9275 0.0000 0.0000 11.4197 -0.3887 4.6730 -15.3994 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.6315 2.9479 0.3627 -5.9474 0.3674 -14.5987 -0.0000 0.0000 2.5856 6.0268 11.0244 5.3775 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -15.1119 1.0024 -2.8698 12.4137 0.0000 0.0000 -4.1506 0.9933 5.0003 1.4921 0.0000 0.0000 -6.0990 1.6664 3.5664 1.7544 0.0000 0.0000 -5.4261 0.6161 4.7408 -9.1558 0.0000 -0.0000 0.1678 -113.9039 24.4238 -6.1127 0.8701 173.6864 0.2698 1.9221 0.3197 -0.2019 0.2428 0.2151 1.0444 0.7669 5.2767 -1.5990 -0.7141 1.3439 -3.2723 -3.2875 -4.8068 2.9666 -1.7232 -9.6638 -5.4416 -1.1257 -2.6070 -10.0079 -1.9732 9.9807 0.0000 0.0000 11.4302 -0.2846 4.6694 -15.3788 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.7670 3.1035 0.5368 -5.9558 0.2356 -14.5922 -0.0000 0.0000 2.6208 6.0238 10.9111 5.4741 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.0203 0.9289 -2.9451 12.2675 0.0000 0.0000 -4.0881 1.0312 5.1389 1.5100 0.0000 0.0000 -6.0138 1.5959 3.5373 1.6516 0.0000 0.0000 -5.4063 0.6597 4.8392 -9.1872 0.0000 -0.0000 0.1817 -113.9026 24.4244 -6.0681 0.8413 173.5454 0.3459 1.9508 0.3214 -0.1437 0.2418 0.2164 0.9297 0.8412 5.3118 -1.6323 -0.7239 1.3279 -3.1987 -3.2925 -4.8357 2.8972 -1.7053 -9.7597 -5.3540 -1.3126 -2.6099 -10.0330 -1.7475 9.9759 0.0000 0.0000 11.3313 -0.2768 4.6114 -15.3292 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -8.7797 3.2601 0.5709 -6.0512 0.0335 -14.4394 -0.0000 0.0000 2.6269 5.9368 10.7812 5.5605 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -14.9046 0.8433 -2.9509 12.1214 0.0000 0.0000 -4.0257 1.0680 5.2640 1.5266 0.0000 0.0000 -5.9224 1.5235 3.4590 1.6071 0.0000 0.0000 -5.4196 0.6713 5.0362 -9.1769 0.0000 -0.0000 0.1977 -113.9036 24.4251 -6.0477 0.8277 173.3990 0.4168 1.9713 0.3288 -0.0958 0.2420 0.2218 0.8235 0.9505 5.3813 -1.6669 -0.7235 1.3160 -3.1826 -3.3199 -4.8728 2.8104 -1.7119 -9.8493 -5.3065 -1.4887 -2.6017 -10.0639 -1.5407 9.8900 0.0000 0.0000 11.2267 -0.3784 4.5980 -15.3700 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -8.7598 3.3749 0.5611 -6.2975 -0.1516 -14.3093 -0.0000 0.0000 2.6551 5.6786 10.6350 5.6174 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -14.8320 0.7597 -2.9143 11.9929 0.0000 0.0000 -3.9584 1.1084 5.3582 1.5160 0.0000 0.0000 -5.8935 1.4593 3.3438 1.6240 0.0000 0.0000 -5.4466 0.6715 5.2863 -9.1938 0.0000 -0.0000 0.2175 -113.9081 24.4267 -6.0625 0.8167 173.3018 0.4898 1.9512 0.3395 -0.0598 0.2210 0.2287 0.7666 1.1505 5.4653 -1.7029 -0.6751 1.3119 -3.3799 -3.4139 -4.9738 2.8148 -1.7200 -9.9486 -5.4271 -1.6361 -2.6725 -10.0571 -1.4732 9.7325 0.0000 0.0000 11.2313 -0.4631 4.7449 -15.5049 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.8501 3.3987 0.5370 -6.6121 -0.2946 -14.2666 -0.0000 0.0000 2.7444 5.3657 10.4129 5.6587 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -14.7986 0.6779 -2.9409 11.8650 0.0000 0.0000 -3.8767 1.1527 5.4629 1.4924 0.0000 0.0000 -5.9064 1.3899 3.2082 1.6263 0.0000 0.0000 -5.4511 0.6957 5.5090 -9.2646 0.0000 -0.0000 0.2420 -113.9146 24.4288 -6.1188 0.7917 173.2982 0.5363 1.9180 0.3488 -0.0271 0.1817 0.2321 0.7414 1.3984 5.4928 -1.7408 -0.6109 1.2994 -3.6654 -3.5618 -5.0923 2.8594 -1.7095 -10.0361 -5.6160 -1.7818 -2.7589 -10.0446 -1.4897 9.5578 0.0000 0.0000 11.3061 -0.4324 4.9555 -15.6011 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -8.9955 3.4111 0.5091 -6.8569 -0.5092 -14.2754 -0.0000 0.0000 2.8518 5.1706 10.1253 5.7091 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -14.7801 0.5899 -3.0923 11.7029 0.0000 0.0000 -3.7873 1.2071 5.5951 1.4869 0.0000 0.0000 -5.9499 1.2958 3.0909 1.5855 0.0000 0.0000 -5.4294 0.7562 5.6147 -9.3178 0.0000 -0.0000 0.2712 -113.9187 24.4312 -6.1838 0.7218 173.3996 0.5738 1.9106 0.3473 0.0200 0.1645 0.2314 0.6859 1.5568 5.4148 -1.7911 -0.5919 1.2639 -3.8391 -3.6634 -5.1571 2.8636 -1.6903 -10.0971 -5.6888 -1.9671 -2.7721 -10.0770 -1.4197 9.4497 0.0000 0.0000 11.3496 -0.3483 5.0395 -15.6018 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -9.0535 3.5225 0.5176 -6.9983 -0.8424 -14.3179 -0.0000 0.0000 2.9184 5.1070 9.8719 5.7745 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -14.6764 0.4705 -3.3916 11.4085 0.0000 0.0000 -3.6681 1.2830 5.7672 1.4936 0.0000 0.0000 -6.0082 1.1494 3.0084 1.5642 0.0000 0.0000 -5.4171 0.8449 5.5847 -9.3146 0.0000 -0.0000 0.3040 -113.9178 24.4351 -6.2027 0.5965 173.5468 0.6404 1.8950 0.3414 0.0654 0.1558 0.2291 0.6454 1.6328 5.2974 -1.8441 -0.6020 1.2190 -3.9517 -3.6616 -5.1907 2.8679 -1.6676 -10.1435 -5.6461 -2.2122 -2.7639 -10.1461 -1.1994 9.4622 0.0000 0.0000 11.3388 -0.3198 5.0073 -15.6028 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -9.0539 3.6723 0.5602 -7.1105 -1.1401 -14.3977 -0.0000 0.0000 2.9446 5.1060 9.7146 5.8473 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -14.3949 0.3047 -3.8132 10.9068 0.0000 0.0000 -3.4737 1.3685 6.0077 1.4820 0.0000 0.0000 -6.0238 0.9457 2.9523 1.5817 0.0000 0.0000 -5.4212 0.9492 5.4913 -9.2978 0.0000 -0.0000 0.3365 -113.9197 24.4398 -6.2969 0.4872 173.6508 0.6294 1.8357 0.3489 0.0604 0.1206 0.2295 0.7110 1.7393 5.2503 -1.8797 -0.5737 1.1906 -4.1902 -3.5924 -5.2512 2.9499 -1.6351 -10.1711 -5.6337 -2.4874 -2.8312 -10.2082 -0.9222 9.5500 0.0000 0.0000 11.3347 -0.3452 5.0212 -15.6599 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.1270 3.7503 0.6247 -7.2266 -1.2801 -14.5397 -0.0000 0.0000 2.9665 5.1227 9.6310 5.9137 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -14.1569 0.1386 -4.2702 10.3084 0.0000 0.0000 -3.2189 1.4388 6.3281 1.4592 0.0000 0.0000 -6.1252 0.7455 2.8820 1.6036 0.0000 0.0000 -5.4087 1.0492 5.4572 -9.2844 0.0000 -0.0000 0.3671 -113.9236 24.4443 -6.4370 0.4124 173.6916 0.6172 1.7661 0.3623 0.0542 0.0781 0.2329 0.7682 1.8603 5.2666 -1.9300 -0.5312 1.1820 -4.4935 -3.4743 -5.3009 3.0863 -1.6238 -10.1646 -5.6417 -2.7079 -2.9592 -10.2472 -0.6994 9.6659 0.0000 0.0000 11.3585 -0.3574 5.0988 -15.6979 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -9.2215 3.7795 0.7939 -7.2939 -1.3138 -14.7738 -0.0000 0.0000 2.9839 5.1279 9.5914 5.9692 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -13.9771 -0.0118 -4.6763 9.6998 0.0000 0.0000 -2.9590 1.4990 6.6685 1.4574 0.0000 0.0000 -6.2349 0.5773 2.7071 1.5421 0.0000 0.0000 -5.3609 1.1321 5.5859 -9.2435 0.0000 -0.0000 0.3962 -113.9254 24.4480 -6.5563 0.3549 173.7085 0.7425 1.7732 0.3632 0.1447 0.0846 0.2348 0.5653 1.8609 5.2572 -2.0550 -0.5572 1.1694 -4.6096 -3.2832 -5.2667 3.1725 -1.6809 -10.1513 -5.5162 -2.8398 -3.0702 -10.2937 -0.5314 9.8511 0.0000 0.0000 11.3684 -0.3494 5.1112 -15.6855 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -9.1495 3.8904 1.1794 -7.3183 -1.3813 -15.1205 -0.0000 0.0000 3.0062 5.1058 9.6134 6.0033 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -13.7905 -0.1538 -4.9849 9.1210 0.0000 0.0000 -2.7302 1.5731 6.9429 1.4778 0.0000 0.0000 -6.2929 0.4361 2.4608 1.4302 0.0000 0.0000 -5.3089 1.1955 5.8200 -9.1867 0.0000 -0.0000 0.4245 -113.9241 24.4511 -6.6041 0.2989 173.7199 1.0447 1.8445 0.3445 0.3275 0.1453 0.2362 0.1010 1.7419 5.2112 -2.2406 -0.6437 1.1497 -4.4992 -3.0370 -5.1999 3.1748 -1.8003 -10.1790 -5.2329 -2.9265 -3.1606 -10.3840 -0.3740 10.1244 0.0000 0.0000 11.3523 -0.3721 5.0428 -15.7032 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -8.9216 4.0557 1.7004 -7.3737 -1.4745 -15.4890 -0.0000 0.0000 3.0566 5.1093 9.6551 6.0432 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -13.5463 -0.2912 -5.2286 8.5856 0.0000 0.0000 -2.5248 1.6552 7.1577 1.4785 0.0000 0.0000 -6.2901 0.3082 2.2985 1.3590 0.0000 0.0000 -5.2849 1.2546 5.9939 -9.1846 0.0000 -0.0000 0.4524 -113.9256 24.4536 -6.6868 0.2585 173.7179 1.3061 1.8805 0.3278 0.4810 0.1864 0.2402 -0.3043 1.6803 5.1956 -2.3890 -0.6867 1.1422 -4.4342 -2.8256 -5.2233 3.1543 -1.9163 -10.2495 -4.9913 -3.0136 -3.2897 -10.5014 -0.2404 10.3785 0.0000 0.0000 11.3526 -0.4129 5.0415 -15.7572 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -8.7815 4.1169 2.1288 -7.4525 -1.5209 -15.6992 -0.0000 0.0000 3.0966 5.1777 9.6128 6.1403 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -13.3915 -0.4175 -5.4512 8.1336 0.0000 0.0000 -2.3338 1.7153 7.3608 1.4421 0.0000 0.0000 -6.3792 0.1850 2.3129 1.3836 0.0000 0.0000 -5.2934 1.3317 6.0002 -9.2583 0.0000 -0.0000 0.4813 -113.9279 24.4557 -6.8190 0.2188 173.7207 1.4024 1.8469 0.3222 0.5379 0.1604 0.2445 -0.3886 1.7428 5.2307 -2.4609 -0.6473 1.1619 -4.6199 -2.6795 -5.3622 3.1787 -1.9933 -10.3255 -4.9351 -3.0639 -3.4753 -10.5797 -0.1703 10.4975 0.0000 0.0000 11.4037 -0.4200 5.1456 -15.7653 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.8530 4.0183 2.3915 -7.4679 -1.5046 -15.6937 -0.0000 0.0000 3.0625 5.2468 9.4515 6.2781 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -13.3137 -0.5487 -5.6766 7.7308 0.0000 0.0000 -2.1587 1.7487 7.5617 1.3985 0.0000 0.0000 -6.5395 0.0457 2.4217 1.4455 0.0000 0.0000 -5.3227 1.4315 5.8772 -9.3370 0.0000 -0.0000 0.5112 -113.9254 24.4578 -6.9318 0.1647 173.7479 1.4438 1.8108 0.3221 0.5552 0.1254 0.2494 -0.2962 1.7886 5.2641 -2.5070 -0.5860 1.1844 -4.9254 -2.5413 -5.5078 3.2517 -2.0666 -10.3943 -4.9745 -3.0396 -3.6613 -10.6049 -0.1501 10.5043 0.0000 0.0000 11.4782 -0.3872 5.2181 -15.7367 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -8.9929 3.8708 2.6129 -7.4061 -1.4634 -15.5674 -0.0000 0.0000 2.9690 5.2323 9.2725 6.3708 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -13.1951 -0.6883 -5.9296 7.3190 0.0000 0.0000 -1.9928 1.7768 7.7697 1.3804 0.0000 0.0000 -6.6699 -0.1081 2.5668 1.5106 0.0000 0.0000 -5.3723 1.5348 5.6769 -9.3563 0.0000 -0.0000 0.5391 -113.9220 24.4599 -7.0765 0.1103 173.8044 1.5004 1.7886 0.3099 0.5916 0.0895 0.2526 -0.3083 1.8261 5.2803 -2.5722 -0.5594 1.1946 -5.1048 -2.4027 -5.5820 3.3337 -2.1640 -10.4357 -4.9819 -3.0162 -3.8077 -10.6388 -0.1128 10.4753 0.0000 0.0000 11.5239 -0.3674 5.1930 -15.7386 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -9.0599 3.7849 2.8326 -7.3342 -1.4552 -15.4014 -0.0000 0.0000 2.9042 5.1802 9.1987 6.3858 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -13.0942 -0.8156 -6.2861 6.8878 0.0000 0.0000 -1.8180 1.8023 8.0516 1.3822 0.0000 0.0000 -6.8866 -0.2577 2.8123 1.6793 0.0000 0.0000 -5.4660 1.6338 5.3587 -9.3408 0.0000 -0.0000 0.5602 -113.9209 24.4613 -7.3134 0.0922 173.8970 1.5364 1.7373 0.3023 0.6262 0.0372 0.2543 -0.4650 1.9318 5.2979 -2.6329 -0.5211 1.1745 -5.0942 -2.3241 -5.5511 3.3976 -2.2423 -10.3682 -4.9733 -3.0902 -3.8873 -10.7173 0.0050 10.3926 0.0000 0.0000 11.5094 -0.4141 5.1503 -15.6963 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.1022 3.7662 2.9864 -7.2589 -1.5049 -15.2073 -0.0000 0.0000 2.8837 5.1867 9.2018 6.3797 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -13.0908 -0.8844 -6.7933 6.4506 0.0000 0.0000 -1.6622 1.8048 8.4522 1.3913 0.0000 0.0000 -7.2744 -0.3605 3.1222 1.9691 0.0000 0.0000 -5.5875 1.7264 4.9549 -9.3258 0.0000 -0.0000 0.5737 -113.9114 24.4628 -7.5119 0.0539 174.0700 1.5665 1.6190 0.2975 0.6664 -0.0543 0.2495 -0.6076 2.0895 5.3202 -2.6699 -0.4409 1.1371 -5.0102 -2.3101 -5.4068 3.4476 -2.2327 -10.1049 -5.0435 -3.2214 -3.9167 -10.7642 0.1934 10.2263 0.0000 0.0000 11.4503 -0.5246 5.1314 -15.5529 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.1851 3.8129 3.0490 -7.1458 -1.5839 -15.0243 -0.0000 0.0000 2.8609 5.2140 9.1103 6.3424 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -12.9642 -0.9378 -7.3920 5.9078 0.0000 0.0000 -1.5036 1.7633 8.8663 1.4027 0.0000 0.0000 -7.5866 -0.4453 3.2587 2.2115 0.0000 0.0000 -5.6944 1.8067 4.6395 -9.3021 0.0000 -0.0000 0.5776 -113.8918 24.4651 -7.6344 -0.0110 174.2775 1.5928 1.4765 0.2951 0.7114 -0.1514 0.2394 -0.6477 2.1985 5.3588 -2.7014 -0.3554 1.1126 -4.9711 -2.2938 -5.1600 3.4806 -2.1285 -9.6509 -5.2219 -3.2975 -3.9258 -10.6973 0.3718 10.0763 0.0000 0.0000 11.3663 -0.6369 5.0976 -15.4640 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -9.2684 3.9385 3.0493 -7.0044 -1.6115 -14.9159 -0.0000 0.0000 2.8553 5.1510 8.7910 6.1625 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -12.7285 -0.9906 -7.8671 5.3534 0.0000 0.0000 -1.3255 1.6959 9.1247 1.4133 0.0000 0.0000 -7.7389 -0.5103 3.2043 2.3311 0.0000 0.0000 -5.7572 1.8506 4.4824 -9.2675 0.0000 -0.0000 0.5691 -113.8764 24.4671 -7.7922 -0.0409 174.3972 1.5864 1.3288 0.2915 0.7107 -0.2325 0.2362 -0.6151 2.3108 5.4648 -2.7265 -0.2983 1.1158 -4.9942 -2.2622 -4.8483 3.4543 -2.0050 -9.0939 -5.4167 -3.3204 -3.8783 -10.5534 0.4774 10.0662 0.0000 0.0000 11.2585 -0.6810 5.0620 -15.5458 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.2769 4.0911 2.9499 -6.8495 -1.5536 -14.8993 -0.0000 0.0000 2.9265 5.0091 8.3387 5.8590 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -12.6905 -0.9993 -8.0444 5.0559 0.0000 0.0000 -1.1845 1.6443 9.1763 1.4132 0.0000 0.0000 -7.9760 -0.5213 3.2595 2.5248 0.0000 0.0000 -5.8183 1.8489 4.3268 -9.2649 0.0000 -0.0000 0.5478 -113.8785 24.4664 -8.1405 0.0304 174.4152 1.4032 1.1957 0.2941 0.5931 -0.2774 0.2439 -0.4284 2.4749 5.6243 -2.7236 -0.2473 1.1251 -5.1090 -2.2363 -4.5006 3.3516 -1.9453 -8.5175 -5.5060 -3.3753 -3.6765 -10.4325 0.5246 10.2132 0.0000 0.0000 11.1418 -0.6392 5.0533 -15.6459 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -9.1930 4.2340 2.7346 -6.6602 -1.4976 -15.0639 -0.0000 0.0000 3.0609 4.9065 8.0359 5.6780 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -13.1352 -0.8968 -8.0100 5.1904 0.0000 0.0000 -1.2027 1.6252 9.1311 1.4279 0.0000 0.0000 -8.6458 -0.4452 3.6926 3.0907 0.0000 0.0000 -5.9669 1.8099 3.9160 -9.2596 0.0000 -0.0000 0.5238 -113.8699 24.4658 -8.2209 0.0291 174.5245 1.2784 1.0830 0.2754 0.4443 -0.3168 0.2471 0.0908 2.5750 5.7249 -2.6997 -0.1836 1.1277 -5.4189 -2.1931 -4.1593 3.2901 -1.9557 -7.9892 -5.4345 -3.3655 -3.2880 -10.3631 0.4081 10.4798 0.0000 0.0000 11.0647 -0.5312 5.0169 -15.6694 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -8.9834 4.3181 2.4513 -6.5000 -1.4160 -15.6003 -0.0000 0.0000 3.2437 4.8633 8.0603 5.7906 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -13.2758 -0.8070 -8.1101 5.3539 0.0000 0.0000 -1.3058 1.5838 9.1283 1.5074 0.0000 0.0000 -9.1488 -0.4091 4.2013 3.9189 0.0000 0.0000 -6.2535 1.7481 3.3197 -9.1398 0.0000 -0.0000 0.5021 -113.8364 24.4680 -7.8530 -0.1389 174.7733 1.2859 1.0395 0.2351 0.3500 -0.3771 0.2338 0.9553 2.4808 5.7527 -2.6782 -0.1314 1.1350 -6.0019 -2.0842 -3.8862 3.3926 -1.9830 -7.5773 -5.2680 -3.1073 -2.7560 -10.3157 -0.0444 10.9344 0.0000 0.0000 11.0031 -0.4128 4.8847 -15.7487 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.6246 4.3169 2.0932 -6.5286 -1.1746 -16.6011 -0.0000 0.0000 3.5537 4.7728 8.3179 6.0536 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -12.7683 -0.8186 -8.4451 5.3288 0.0000 0.0000 -1.3604 1.4759 9.2010 1.6564 0.0000 0.0000 -9.1185 -0.4810 4.4512 4.7340 0.0000 0.0000 -6.6249 1.6582 2.8081 -8.9073 0.0000 -0.0000 0.4755 -113.7997 24.4713 -7.3143 -0.3492 174.9201 1.3289 1.0471 0.2004 0.2475 -0.4552 0.2191 1.9319 2.3206 5.8624 -2.6263 -0.1085 1.1704 -6.7146 -1.9474 -3.6787 3.5825 -1.9996 -7.2946 -5.0785 -2.6065 -2.0708 -10.3172 -0.8323 11.7287 0.0000 0.0000 10.8030 -0.4240 4.7009 -15.7531 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.1698 4.1792 1.5349 -6.7701 -0.7473 -17.9089 -0.0000 0.0000 3.9753 4.5627 8.5628 6.2166 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -12.0786 -0.8637 -8.7864 5.2939 0.0000 0.0000 -1.3653 1.3218 9.3738 1.7805 0.0000 0.0000 -8.8102 -0.5710 4.4893 5.3954 0.0000 0.0000 -6.9915 1.5361 2.6024 -8.7640 0.0000 -0.0000 0.4335 -113.7907 24.4702 -7.0713 -0.4264 174.7200 1.1485 1.0393 0.2037 0.0420 -0.5627 0.2168 2.8125 2.3458 6.1881 -2.4911 -0.0960 1.2267 -7.3277 -1.8605 -3.4293 3.6350 -2.0244 -7.0503 -4.8586 -2.1420 -1.1675 -10.4781 -1.6075 12.9671 0.0000 0.0000 10.4237 -0.7343 4.5555 -15.1607 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -7.7422 3.9795 0.7589 -7.0350 -0.4256 -19.3844 -0.0000 0.0000 4.2174 4.2402 8.6103 6.1825 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -11.8975 -0.8186 -8.9017 5.4415 0.0000 0.0000 -1.4055 1.1753 9.6804 1.8047 0.0000 0.0000 -8.8246 -0.5574 4.6134 6.0095 0.0000 0.0000 -7.3349 1.3822 2.6669 -8.8566 0.0000 -0.0000 0.3762 -113.7941 24.4656 -6.9879 -0.4506 174.2563 0.8407 0.9449 0.2294 -0.2336 -0.7291 0.2178 3.6254 2.5630 6.6863 -2.3082 -0.0626 1.2877 -7.8067 -1.8164 -3.0755 3.5071 -2.0691 -6.7501 -4.5754 -1.8805 -0.1338 -10.8497 -2.1032 14.6949 0.0000 0.0000 10.1227 -1.3249 4.5360 -13.7945 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -7.3739 3.8297 -0.0292 -7.1907 -0.4031 -21.2209 -0.0000 0.0000 4.0855 3.7346 8.3496 5.9128 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -11.8781 -0.7529 -8.8934 5.4599 0.0000 0.0000 -1.3598 1.0257 10.1270 1.7929 0.0000 0.0000 -8.9869 -0.4982 4.8630 6.5810 0.0000 0.0000 -7.6995 1.1921 2.8569 -9.0847 0.0000 -0.0000 0.3055 -113.7827 24.4620 -6.8583 -0.5466 173.7264 0.5192 0.7912 0.2605 -0.4737 -0.9344 0.2124 4.4203 2.7349 7.2399 -2.1640 -0.0055 1.3826 -8.3430 -1.6978 -2.7160 3.4242 -2.1398 -6.4049 -4.2665 -1.6583 0.7834 -11.2888 -2.4787 16.9674 0.0000 0.0000 10.1618 -1.9950 4.8255 -12.1498 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -7.0525 3.6796 -0.5968 -7.2598 -0.3597 -23.8300 -0.0000 0.0000 3.9280 2.8753 7.6929 5.3252 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -11.6362 -0.7488 -8.8504 5.1903 0.0000 0.0000 -1.1187 0.8210 10.5865 1.8414 0.0000 0.0000 -8.9907 -0.4710 5.1428 7.0356 0.0000 0.0000 -8.0976 0.9311 3.0561 -9.2547 0.0000 -0.0000 0.2146 -113.7491 24.4600 -6.5889 -0.6581 173.1520 0.3084 0.6734 0.2933 -0.6506 -1.1082 0.2105 5.1145 2.6983 7.8375 -2.0668 0.0722 1.5554 -9.0510 -1.4073 -2.4855 3.5878 -2.2864 -6.0916 -3.9527 -1.2150 1.4549 -11.5916 -3.0200 19.8109 0.0000 0.0000 10.4429 -2.6564 5.5257 -10.6821 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.7711 3.3353 -0.8592 -7.3076 0.2291 -27.5415 -0.0000 0.0000 4.3167 1.7072 6.6633 4.4354 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -11.2110 -0.6957 -8.6350 4.9362 0.0000 0.0000 -0.9066 0.5392 10.9293 1.8720 0.0000 0.0000 -8.6881 -0.3687 5.3291 7.2782 0.0000 0.0000 -8.4654 0.5566 3.3893 -9.3209 0.0000 -0.0000 0.0962 -113.7070 24.4558 -6.3048 -0.6753 172.4968 0.1178 0.5923 0.3359 -0.7987 -1.2284 0.2171 5.6748 2.5723 8.4952 -1.9546 0.1693 1.7800 -9.8686 -1.0304 -2.3667 3.9419 -2.5337 -5.8388 -3.5662 -0.6317 1.9883 -11.8261 -3.5971 23.1973 0.0000 0.0000 10.6672 -3.4756 6.2204 -9.3601 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.5412 2.7424 -0.8570 -7.3609 1.4209 -32.3714 -0.0000 0.0000 5.2400 0.6570 5.3544 3.3244 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -10.9599 -0.4583 -8.2306 5.0533 0.0000 0.0000 -0.9939 0.2110 11.2048 1.7151 0.0000 0.0000 -8.2966 -0.0781 5.3859 7.3797 0.0000 0.0000 -8.7546 0.0822 3.9486 -9.3403 0.0000 -0.0000 -0.0447 -113.6536 24.4496 -5.9181 -0.6943 171.9228 -0.0431 0.4366 0.3691 -0.9350 -1.3082 0.2230 6.2438 2.4989 9.0984 -1.8304 0.2814 1.9854 -10.6589 -0.7783 -2.2717 4.3139 -2.7859 -5.6042 -3.0212 -0.2071 2.4960 -12.3398 -3.9518 27.0729 0.0000 0.0000 10.7695 -4.4923 6.2827 -8.1242 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.3119 2.0397 -0.8146 -7.5012 2.8394 -37.8369 -0.0000 0.0000 5.9863 0.0568 3.8376 1.9195 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -10.7791 -0.1009 -7.9390 5.5595 0.0000 0.0000 -1.2888 -0.1236 11.5206 1.3981 0.0000 0.0000 -7.7737 0.2988 5.4476 7.4301 0.0000 0.0000 -8.9704 -0.3941 4.4364 -9.2966 0.0000 -0.0000 -0.2002 -113.5902 24.4400 -5.5231 -0.7352 171.6508 -0.2472 0.2563 0.3686 -1.0882 -1.2759 0.2285 6.8530 2.4159 9.4268 -1.7561 0.3463 2.1479 -11.3097 -0.7949 -2.1930 4.6258 -2.9008 -5.3286 -2.3309 -0.0221 2.9085 -13.2048 -4.2420 31.4551 0.0000 0.0000 10.8921 -5.2998 5.8877 -7.0001 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -5.9656 1.2773 -1.0768 -7.8748 4.3096 -43.1706 -0.0000 0.0000 6.0013 -0.2495 2.1989 0.1732 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -10.9771 0.3717 -7.6610 6.9120 0.0000 0.0000 -1.8728 -0.4581 11.5414 1.1599 0.0000 0.0000 -7.3273 0.6814 5.9209 7.6139 0.0000 0.0000 -9.1698 -0.7853 4.2448 -9.0880 0.0000 -0.0000 -0.3706 -113.5380 24.4125 -5.3886 -0.3778 171.6793 -0.5787 0.5047 0.3602 -1.3004 -0.9603 0.2697 7.2368 2.1599 9.3516 -1.7458 0.2569 2.2682 -11.6975 -1.0863 -2.1683 4.8772 -2.8780 -4.9800 -1.5566 0.1528 3.2219 -13.9431 -4.7451 36.1774 0.0000 0.0000 11.1968 -5.5498 6.0020 -5.7705 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.3888 0.2595 -1.9044 -8.4765 5.8867 -47.7814 -0.0000 0.0000 5.4503 -0.6163 0.5439 -1.5135 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -12.5032 1.3226 -6.3920 10.2424 0.0000 0.0000 -3.4700 -0.8987 10.4078 1.1154 0.0000 0.0000 -7.4361 1.4102 7.1812 8.1228 0.0000 0.0000 -9.4042 -1.1555 3.0646 -8.6302 0.0000 -0.0000 -0.5488 -113.5011 24.3496 -5.4202 0.7703 171.9271 -0.9567 1.6518 0.3508 -1.4622 -0.4224 0.3457 7.2203 1.8345 8.9286 -1.7703 -0.0141 2.3431 -11.8254 -1.6381 -2.2298 5.1172 -2.8552 -4.5900 -0.7475 0.4999 3.5243 -14.2410 -5.4653 40.8741 0.0000 0.0000 11.7852 -5.4432 7.1969 -4.3205 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -4.6027 -1.2194 -3.1975 -9.2110 7.4459 -51.7204 -0.0000 0.0000 4.8214 -1.0645 -1.1854 -2.6001 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -15.4680 2.9640 -3.7314 15.7711 0.0000 0.0000 -6.2213 -1.6143 7.9891 1.0574 0.0000 0.0000 -8.0260 2.8967 8.8454 8.9188 0.0000 0.0000 -9.7158 -1.6660 1.4091 -7.9670 0.0000 -0.0000 -0.7089 -113.4341 24.2685 -4.8851 2.2253 172.3606 -0.9363 3.2918 0.2988 -1.3991 0.0817 0.4074 7.1132 1.6834 8.3727 -1.8188 -0.3148 2.3633 -11.9192 -2.3520 -2.4043 5.4319 -2.9227 -4.2638 -0.0178 0.8695 3.8126 -14.4300 -6.3963 45.3161 0.0000 0.0000 12.6369 -5.2473 9.0769 -3.0731 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -3.8885 -2.8854 -4.6056 -9.9581 8.6618 -55.4441 -0.0000 0.0000 4.2413 -1.3512 -3.1739 -3.1262 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -18.2377 4.7522 -1.0175 22.0284 0.0000 0.0000 -8.7670 -2.5105 5.3615 0.7723 0.0000 0.0000 -7.8948 4.7975 10.0012 9.5261 0.0000 0.0000 -10.0611 -2.2952 0.1115 -7.3199 0.0000 -0.0000 -0.8332 -113.3218 24.2060 -3.8270 3.2017 172.7720 -0.6184 4.5182 0.2409 -1.2037 0.3940 0.4405 7.3038 1.7482 7.9206 -1.9058 -0.4908 2.3747 -12.1760 -2.9537 -2.6742 5.8885 -3.0228 -4.0704 0.4560 0.9656 4.0611 -14.7896 -7.6249 49.5167 0.0000 0.0000 13.5613 -4.8025 10.8784 -2.2971 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.5900 -4.1241 -5.7987 -10.5360 9.5544 -59.3318 -0.0000 0.0000 3.5673 -1.3302 -5.3627 -3.6271 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -20.2383 5.8663 0.8536 27.9464 0.0000 0.0000 -9.8167 -3.2934 2.7934 0.3831 0.0000 0.0000 -6.8134 6.2849 10.3497 9.7346 0.0000 0.0000 -10.3777 -2.8383 -0.5127 -6.8979 0.0000 -0.0000 -0.9263 -113.1823 24.1753 -2.7535 3.5326 172.9422 -0.3236 5.0819 0.2371 -1.0521 0.5044 0.4455 7.6347 1.8430 7.6948 -1.9867 -0.5470 2.3868 -12.3671 -3.1856 -2.8801 6.4449 -3.0511 -3.9777 0.6794 0.7700 4.5055 -14.9645 -8.8514 53.4135 0.0000 0.0000 14.2545 -4.0069 12.2172 -1.5927 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.8468 -4.8014 -6.7464 -10.6252 10.6543 -63.1894 -0.0000 0.0000 2.7051 -1.0948 -7.4451 -4.2117 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -21.8896 6.0581 1.9261 33.1432 0.0000 0.0000 -9.6929 -3.7384 -0.0204 0.1629 0.0000 0.0000 -5.4153 7.0670 10.3582 9.6999 0.0000 0.0000 -10.6654 -3.1853 -0.6903 -6.6345 0.0000 -0.0000 -0.9969 -113.0391 24.1642 -2.0473 3.4644 172.9430 -0.2784 5.2816 0.2461 -0.9921 0.5215 0.4400 7.8104 1.7490 7.5664 -1.9931 -0.5910 2.3754 -12.2899 -3.0170 -2.8550 6.9920 -3.0134 -3.8754 0.6469 0.4838 5.4258 -14.5593 -9.7295 56.8025 0.0000 0.0000 14.5195 -3.3297 12.9042 -0.6971 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -4.3986 -5.0535 -7.6036 -10.1784 11.7428 -66.6784 -0.0000 0.0000 1.9487 -0.9241 -8.9693 -4.5314 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -23.4475 5.5947 2.4541 37.1729 0.0000 0.0000 -9.6627 -3.6809 -2.9826 0.1293 0.0000 0.0000 -4.3929 7.3036 10.5290 9.8119 0.0000 0.0000 -11.0463 -3.3988 -0.8660 -6.3004 0.0000 -0.0000 -1.0449 -112.8938 24.1611 -1.5294 3.2032 172.9917 -0.3148 5.3800 0.2383 -0.9969 0.5485 0.4281 7.9233 1.4866 7.3462 -1.9421 -0.6718 2.3441 -12.1813 -2.6946 -2.6817 7.4758 -2.9583 -3.6918 0.3432 0.1783 6.6728 -13.7790 -10.6030 59.6697 0.0000 0.0000 14.2666 -3.5090 12.4520 0.0118 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.9457 -5.0914 -8.5304 -9.5213 12.1454 -69.7261 -0.0000 0.0000 1.6970 -0.9512 -9.6634 -4.3514 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -24.6270 4.8283 2.7013 39.7107 0.0000 0.0000 -10.1153 -3.1986 -5.4663 0.1356 0.0000 0.0000 -3.6027 7.2209 10.9135 10.0915 0.0000 0.0000 -11.5219 -3.5189 -1.2924 -5.8849 0.0000 -0.0000 -1.0733 -112.7509 24.1622 -1.1153 2.8873 173.1300 -0.4073 5.4467 0.2408 -1.0385 0.5987 0.4190 8.2275 1.2534 7.0445 -1.9201 -0.7367 2.3241 -12.3832 -2.4962 -2.5968 7.8954 -2.8846 -3.4521 -0.3302 -0.0561 7.8125 -12.8541 -12.4533 62.1206 0.0000 0.0000 13.6253 -4.4580 10.5938 0.1118 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.5339 -5.2950 -9.5679 -8.8497 12.1039 -72.4039 -0.0000 0.0000 1.9894 -1.0014 -9.5570 -3.8908 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -25.5837 3.9993 2.9288 40.8861 0.0000 0.0000 -10.2312 -2.7892 -6.7589 0.1824 0.0000 0.0000 -2.8627 6.9996 11.3568 10.2812 0.0000 0.0000 -11.9381 -3.4500 -1.8817 -5.6043 0.0000 -0.0000 -1.0964 -112.6243 24.1653 -0.8864 2.7065 173.1489 -0.5351 5.5419 0.2647 -1.1223 0.6743 0.4234 8.5883 1.1382 6.8314 -1.9587 -0.7494 2.3414 -12.7897 -2.3880 -2.6414 8.2074 -2.8146 -3.2456 -1.1204 -0.1556 8.6952 -11.7104 -14.8827 64.2723 0.0000 0.0000 12.8102 -5.3691 7.8567 -0.2157 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.2403 -5.9362 -10.6342 -8.0928 12.4143 -74.6909 -0.0000 0.0000 2.5289 -0.9620 -8.9097 -3.5075 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -26.7434 3.3490 3.2387 41.0321 0.0000 0.0000 -9.4945 -2.8506 -6.5405 0.3046 0.0000 0.0000 -2.2350 6.8863 11.8640 10.1858 0.0000 0.0000 -12.1397 -3.1602 -2.4208 -5.5008 0.0000 -0.0000 -1.1207 -112.5244 24.1659 -1.0506 2.7337 173.0261 -0.7966 5.6895 0.2655 -1.2192 0.7807 0.4441 8.6902 1.0834 6.7309 -2.0068 -0.7226 2.3080 -13.0988 -2.1709 -2.5963 8.3646 -2.8071 -3.1638 -1.7234 -0.2185 9.5539 -10.1625 -16.3635 66.1722 0.0000 0.0000 12.0345 -5.4852 5.2055 -0.3990 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -6.9829 -6.8396 -11.5792 -7.1949 13.2034 -76.5597 -0.0000 0.0000 3.0790 -0.9078 -8.0569 -3.3271 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -28.3251 2.9992 3.4111 40.2295 0.0000 0.0000 -8.3018 -3.2431 -5.1631 0.4417 0.0000 0.0000 -2.0985 6.9505 12.3660 10.0541 0.0000 0.0000 -12.2170 -2.8692 -2.7735 -5.3590 0.0000 -0.0000 -1.1281 -112.4168 24.1676 -1.2165 2.6923 173.0914 -0.9607 5.8061 0.2346 -1.2726 0.8300 0.4409 8.6190 1.0170 6.5290 -2.0295 -0.6742 2.1467 -13.2699 -1.7629 -2.3496 8.4443 -2.8168 -3.2154 -2.0230 -0.4707 10.5166 -8.4808 -16.2782 67.7694 0.0000 0.0000 11.4336 -4.9641 3.1936 -0.2644 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -7.6293 -7.5857 -12.3350 -6.2771 13.9555 -78.0998 -0.0000 0.0000 3.5539 -0.8009 -7.2229 -3.2590 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -29.5233 2.7994 3.1150 38.3030 0.0000 0.0000 -7.1575 -3.6524 -3.4999 0.4990 0.0000 0.0000 -1.9978 6.9230 12.5478 10.0539 0.0000 0.0000 -12.3546 -2.7768 -2.9794 -5.0907 0.0000 -0.0000 -1.1011 -112.2699 24.1747 -1.1374 2.3205 173.6199 -1.0230 5.7602 0.2045 -1.2938 0.8086 0.4019 8.7431 0.8446 6.0811 -2.0178 -0.5820 1.9048 -13.5131 -1.2177 -2.0301 8.6089 -2.6456 -3.3090 -2.2071 -0.9738 11.3940 -7.1529 -15.7339 68.9454 0.0000 0.0000 11.0795 -4.4601 1.5794 -0.2066 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -8.1143 -7.9527 -12.9059 -5.5126 14.3892 -79.4909 -0.0000 0.0000 3.8587 -0.4155 -6.4102 -3.2095 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -29.8447 2.5269 2.2623 35.3083 0.0000 0.0000 -6.0845 -3.9507 -2.3237 0.3769 0.0000 0.0000 -1.5739 6.5150 12.2202 10.2339 0.0000 0.0000 -12.6715 -2.8007 -3.1669 -4.8901 0.0000 -0.0000 -1.0554 -112.0908 24.1802 -0.8503 1.8549 174.3902 -1.0258 5.6500 0.1975 -1.3195 0.7384 0.3464 9.0631 0.6326 5.5744 -1.9925 -0.4272 1.6778 -13.8076 -0.5334 -1.7332 8.9371 -2.1590 -3.3461 -2.3983 -1.5033 12.0863 -6.3986 -15.7143 69.6255 0.0000 0.0000 10.9956 -4.1061 -0.2181 -0.4962 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -8.4570 -8.2136 -13.3766 -4.8798 14.9726 -80.7113 -0.0000 0.0000 3.8986 0.2709 -5.5239 -3.1966 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -29.5578 2.2871 1.1214 31.7403 0.0000 0.0000 -5.1338 -4.1466 -1.7062 -0.0241 0.0000 -0.0000 -0.8523 5.9799 11.6577 10.4483 0.0000 0.0000 -13.0846 -2.7408 -3.3975 -4.9127 0.0000 -0.0000 -1.0182 -111.9192 24.1710 -0.7678 1.7099 175.0743 -1.1237 5.6243 0.1888 -1.3711 0.6636 0.3056 9.2352 0.5257 5.2031 -1.9715 -0.1893 1.4743 -13.9827 0.3806 -1.3836 9.3443 -1.4709 -3.3314 -2.5544 -1.9532 12.6869 -6.0838 -15.8147 69.9608 0.0000 0.0000 11.1157 -3.5259 -2.2913 -0.9396 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -8.6294 -8.6443 -13.7965 -4.2607 15.9616 -81.6818 -0.0000 0.0000 3.8389 0.8275 -4.5259 -3.2601 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -29.4379 2.3442 -0.0964 28.1489 0.0000 0.0000 -4.4360 -4.1987 -1.1693 -0.5838 0.0000 -0.0000 -0.4392 5.7362 11.2382 10.7521 0.0000 0.0000 -13.5319 -2.5619 -3.6802 -5.0521 0.0000 -0.0000 -0.9848 -111.7589 24.1512 -0.9016 1.7875 175.7531 -1.2449 5.5851 0.1621 -1.4255 0.6018 0.2796 9.2086 0.5315 4.8798 -1.9790 0.1365 1.2257 -14.0287 1.6157 -0.9335 9.7003 -0.8104 -3.3211 -2.7082 -2.3887 13.1761 -5.9860 -15.5991 70.2231 0.0000 0.0000 11.3990 -2.6431 -4.2509 -1.2684 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.6876 -9.1710 -14.1876 -3.4944 17.1002 -82.4652 -0.0000 0.0000 3.9900 1.0578 -3.6214 -3.3307 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -29.4761 2.6163 -1.3925 24.7229 0.0000 0.0000 -3.8194 -3.9102 -0.4152 -1.0084 0.0000 -0.0000 -0.3793 5.6614 11.0081 11.2256 0.0000 0.0000 -14.0515 -2.2777 -4.1192 -5.1451 0.0000 -0.0000 -0.9319 -111.5804 24.1323 -1.0794 1.7742 176.6972 -1.4022 5.4345 0.1478 -1.4680 0.5052 0.2406 9.2331 0.5382 4.4356 -1.9976 0.5568 0.9379 -14.0673 3.1452 -0.4889 9.9766 -0.2440 -3.2999 -3.0122 -2.8298 13.3424 -5.9959 -15.5088 70.5266 0.0000 0.0000 11.9044 -1.8922 -5.7813 -1.5038 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -8.7016 -9.6204 -14.5848 -2.4875 18.0793 -83.2536 -0.0000 0.0000 4.4840 1.3337 -3.0591 -3.3391 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -29.3712 2.8351 -2.5821 21.6391 0.0000 0.0000 -3.1847 -3.1614 0.3497 -1.2921 0.0000 -0.0000 -0.3600 5.3990 10.7468 11.8069 0.0000 0.0000 -14.6615 -1.8370 -4.7718 -5.1938 0.0000 -0.0000 -0.8545 -111.3598 24.1166 -1.0735 1.6371 177.8552 -1.4952 5.2118 0.1625 -1.5072 0.3789 0.1959 9.3669 0.4950 3.9267 -1.9990 1.0314 0.6884 -14.0818 4.9448 -0.1327 10.2599 0.3042 -3.1724 -3.4499 -3.0686 13.1623 -6.0930 -15.7630 70.7737 0.0000 0.0000 12.5742 -1.6150 -6.8724 -1.7073 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -8.5578 -9.8384 -15.0188 -1.3319 18.7256 -84.0920 -0.0000 0.0000 5.1786 1.9528 -2.7133 -3.3356 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -28.8929 2.9392 -3.3495 19.1894 0.0000 0.0000 -2.9986 -2.1659 0.8892 -1.6537 0.0000 -0.0000 0.0902 4.9657 10.3238 12.1320 0.0000 0.0000 -15.2362 -1.2579 -5.5020 -5.3047 0.0000 -0.0000 -0.7719 -111.1149 24.0936 -1.1528 1.7090 178.9308 -1.6627 5.0645 0.2223 -1.5883 0.2736 0.1664 9.4456 0.5187 3.4889 -1.9931 1.5371 0.5033 -14.0385 6.9679 0.2217 10.6231 0.8850 -2.8535 -3.8364 -3.0975 12.9284 -6.3018 -15.6401 70.8900 0.0000 0.0000 13.1733 -1.5806 -7.7152 -1.8072 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.1139 -9.6532 -15.4040 -0.2096 18.8793 -84.8767 -0.0000 0.0000 5.9071 2.6415 -2.1578 -3.3928 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -28.4696 3.1985 -3.6294 17.5550 0.0000 0.0000 -3.4338 -1.2993 1.3811 -2.0621 0.0000 -0.0000 0.7765 4.7945 9.6999 11.9027 0.0000 0.0000 -15.6433 -0.7561 -5.9812 -5.4602 0.0000 -0.0000 -0.6892 -110.8594 24.0625 -1.4997 1.9954 179.8270 -1.9879 4.8856 0.3428 -1.7415 0.2104 0.1494 9.4933 0.7119 3.1218 -2.0057 2.0792 0.3034 -14.0592 9.1443 0.7390 11.0067 1.4814 -2.3208 -4.0971 -3.2475 12.7876 -6.6823 -14.6660 71.0524 0.0000 0.0000 13.5186 -1.3330 -8.5246 -1.8213 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -7.5539 -8.9393 -15.6184 0.8622 18.6145 -85.5114 -0.0000 0.0000 6.5891 3.1503 -1.1353 -3.4860 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -28.2955 3.6299 -3.5572 16.6066 0.0000 0.0000 -3.6667 -0.6803 1.8476 -2.2295 0.0000 -0.0000 1.4840 4.9079 8.8480 11.1224 0.0000 0.0000 -15.9040 -0.4068 -6.0644 -5.5157 0.0000 -0.0000 -0.5964 -110.5791 24.0297 -1.9535 2.3033 -179.4030 -2.3753 4.5656 0.5191 -1.9523 0.1462 0.1330 9.6411 1.0600 2.7900 -2.0199 2.6431 0.0520 -14.2343 11.4266 1.4991 11.2609 2.1208 -1.5741 -4.3554 -3.6612 12.5595 -7.2500 -13.6112 71.4409 0.0000 0.0000 13.7254 -0.7402 -9.3447 -1.8934 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -7.1338 -7.9189 -15.6433 1.9211 18.2476 -86.0059 -0.0000 0.0000 7.2206 3.6018 0.2701 -3.5949 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -28.2501 4.0231 -3.0746 16.5341 0.0000 0.0000 -3.1950 -0.2278 1.8633 -2.0201 0.0000 -0.0000 2.2956 5.0349 7.8466 10.0433 0.0000 0.0000 -16.0766 -0.0238 -5.8839 -5.4429 0.0000 -0.0000 -0.4880 -110.2597 23.9916 -2.4267 2.6077 -178.7666 -2.7803 4.1653 0.6881 -2.1674 0.0621 0.1177 9.7882 1.5141 2.5507 -2.0022 3.1729 -0.2071 -14.4493 13.8275 2.4833 11.2857 2.8759 -0.6518 -4.6604 -4.0912 12.1564 -7.9079 -13.3240 71.9884 0.0000 0.0000 13.9696 -0.0937 -9.9467 -2.0044 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.8209 -7.0808 -15.5728 2.9218 18.0104 -86.3492 -0.0000 0.0000 7.7686 4.1270 1.8410 -3.7208 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -28.2156 4.2748 -2.3968 17.5200 0.0000 0.0000 -2.8312 -0.0882 1.3479 -1.6056 0.0000 -0.0000 3.1350 5.0835 6.9387 9.0746 0.0000 0.0000 -16.2495 0.5093 -5.6899 -5.4046 0.0000 -0.0000 -0.3632 -109.9021 23.9446 -2.9950 2.8907 -178.3387 -3.2168 3.6303 0.8351 -2.4211 -0.0169 0.1147 9.8276 2.0659 2.4227 -1.9751 3.6620 -0.4566 -14.6759 16.3633 3.6612 11.1426 3.8173 0.3341 -4.8495 -4.4901 11.8395 -8.5756 -13.2403 72.4882 0.0000 0.0000 14.2612 0.2162 -10.1382 -2.0237 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -6.4258 -6.5683 -15.3856 3.8037 17.5725 -86.5808 -0.0000 0.0000 8.2213 4.5376 3.5286 -3.7923 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -27.8738 4.3233 -2.1286 18.6497 0.0000 0.0000 -3.1462 -0.3618 0.8497 -1.2889 0.0000 -0.0000 3.7795 5.0263 6.3922 8.4901 0.0000 0.0000 -16.5541 1.1089 -5.6315 -5.4831 0.0000 -0.0000 -0.2110 -109.5085 23.9060 -3.6899 2.7678 -178.1740 -3.7922 2.5437 1.0310 -2.7945 -0.2340 0.0811 10.0549 2.8571 2.3766 -2.0170 4.1389 -0.7181 -15.2384 19.1152 5.0701 11.0047 5.0079 1.2963 -4.8144 -5.3357 11.7873 -9.3110 -12.1546 72.9874 0.0000 0.0000 14.4759 0.1368 -10.1059 -1.9467 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.0452 -5.8114 -14.9064 4.6315 16.3056 -86.8415 -0.0000 0.0000 8.5656 4.7886 5.4172 -3.6803 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -26.9062 3.7945 -2.5275 18.4355 0.0000 0.0000 -2.9393 -0.5418 0.7233 -1.1236 0.0000 -0.0000 4.1112 4.4489 6.3456 8.3966 0.0000 0.0000 -17.0806 1.8356 -5.6843 -5.5627 0.0000 -0.0000 -0.0295 -109.0662 23.8971 -4.1231 2.0428 -178.3369 -4.2462 0.7502 1.2423 -3.2506 -0.7988 -0.0071 10.6841 3.9443 2.4862 -2.1759 4.6541 -0.9753 -16.3852 22.2469 6.8381 10.9683 6.4371 2.3254 -4.8491 -6.5954 11.8756 -9.9723 -10.5860 73.5457 0.0000 0.0000 14.6248 0.0270 -10.1554 -1.8892 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -5.9157 -4.3931 -14.1341 5.4532 14.3789 -87.1024 -0.0000 0.0000 8.7420 5.1585 7.3364 -3.4378 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -25.3300 2.4669 -3.0479 16.8794 0.0000 0.0000 -1.0894 0.0449 0.6978 -0.8107 0.0000 -0.0000 4.6008 3.1497 6.6576 8.6813 0.0000 0.0000 -17.5914 2.8821 -5.6734 -5.7013 0.0000 -0.0000 0.1475 -108.5926 23.9081 -4.2192 1.4971 -178.7638 -4.3166 -0.9515 1.3704 -3.4398 -1.7564 -0.1698 11.0189 5.3318 2.8245 -2.4066 5.2762 -1.2013 -17.8559 25.6007 9.0370 10.8710 7.8379 3.5567 -5.2896 -7.3122 12.0679 -10.1981 -10.3313 73.8257 0.0000 0.0000 14.7869 0.0365 -10.3938 -1.8682 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -5.8031 -2.9402 -13.4329 6.0292 12.8184 -87.0096 -0.0000 0.0000 8.7687 5.6448 8.7513 -3.2901 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -24.3037 1.1625 -2.5040 16.3940 0.0000 0.0000 0.8578 1.2027 -0.0147 -0.1644 0.0000 -0.0000 5.3635 2.0399 6.9672 9.2198 0.0000 0.0000 -17.6066 4.0867 -5.5023 -6.3088 0.0000 -0.0000 0.2792 -108.1334 23.9143 -4.3622 2.1294 -178.9868 -3.9914 -1.6820 1.3705 -3.1803 -2.5651 -0.2954 10.2393 6.7490 3.1783 -2.6129 6.0291 -1.4957 -19.2382 28.5247 11.4263 10.4673 8.7741 4.8623 -5.9327 -6.7424 12.5751 -9.9974 -11.4444 73.4260 0.0000 0.0000 14.8310 -0.1805 -10.7909 -1.8113 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -5.3815 -2.4020 -13.2551 6.2535 12.4799 -86.2669 -0.0000 0.0000 8.7490 5.8420 9.1203 -3.2644 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -24.9118 1.0791 -0.6964 19.0529 0.0000 0.0000 0.3084 2.0656 -1.5947 0.4883 0.0000 0.0000 5.8715 2.2139 6.9086 9.9823 0.0000 0.0000 -16.9018 5.1155 -5.4030 -7.5651 0.0000 -0.0000 0.3790 -107.6876 23.9153 -4.6411 3.5689 -178.2594 -3.5499 -1.6443 1.2267 -2.7099 -2.7801 -0.3310 8.8886 7.7903 3.0585 -2.7973 6.8099 -1.9728 -20.5321 30.2885 13.5296 9.8496 9.1689 5.8609 -6.4557 -5.3222 13.4059 -9.7820 -12.0499 72.3979 0.0000 0.0000 14.6375 -0.5941 -11.3449 -1.7723 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.8156 -2.8276 -13.5805 6.3575 13.0661 -85.1803 -0.0000 0.0000 8.6897 5.5209 8.4904 -3.2104 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -26.0255 2.0436 1.2076 23.1100 0.0000 0.0000 -2.4535 2.3772 -3.5609 0.6777 0.0000 0.0000 5.9844 3.0867 6.6289 11.0006 0.0000 0.0000 -15.7482 6.2690 -6.1091 -8.9556 0.0000 -0.0000 0.4955 -107.2311 23.9270 -4.9835 4.4956 -176.5491 -3.3089 -1.6997 1.0582 -2.4575 -2.8358 -0.3634 8.1077 8.5714 2.3461 -3.0101 7.3798 -2.5082 -21.9791 30.7657 14.9496 9.3212 9.3684 6.2902 -6.8667 -4.2546 13.9965 -9.8228 -11.0525 71.2659 0.0000 0.0000 14.3632 -0.5690 -11.9908 -1.8503 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.4893 -3.2884 -14.0449 6.6124 13.6070 -84.4299 -0.0000 0.0000 8.4835 5.0030 7.5233 -3.1538 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -26.2846 2.7308 2.4481 25.9744 0.0000 0.0000 -5.1735 2.6622 -5.8276 0.5204 0.0000 0.0000 5.8314 3.1070 6.6938 12.3900 0.0000 0.0000 -14.5425 7.9694 -8.0439 -9.9029 0.0000 -0.0000 0.6456 -106.7521 23.9448 -5.3443 4.3464 -174.7179 -3.4525 -2.1793 0.9679 -2.4832 -3.0372 -0.4284 8.0920 8.9756 1.5708 -3.2423 7.6441 -2.8624 -23.5227 30.3969 15.6913 8.9448 9.6538 6.2085 -7.2056 -4.0897 14.1192 -10.2522 -9.4384 70.2783 0.0000 0.0000 14.2838 -0.0643 -12.3614 -2.0012 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.3611 -3.2310 -14.4304 6.9527 13.9432 -84.2008 -0.0000 0.0000 8.1429 4.5936 6.8830 -3.2786 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -25.6870 2.3402 2.9381 27.1025 0.0000 0.0000 -6.8192 3.3096 -8.1341 0.4660 0.0000 0.0000 5.4975 1.8375 7.2006 14.1000 0.0000 0.0000 -13.5316 9.5777 -10.4947 -10.5442 0.0000 -0.0000 0.8018 -106.2510 23.9538 -5.3968 3.6996 -173.5932 -3.5764 -2.6832 0.8825 -2.5542 -3.2859 -0.4931 8.1694 8.7633 1.2186 -3.4534 7.6746 -2.9126 -24.7368 29.6371 15.9783 8.4706 9.9018 5.8792 -7.4097 -4.1850 14.2905 -10.9853 -8.7045 69.2431 0.0000 0.0000 14.4985 0.0621 -11.9444 -2.1446 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.1886 -3.0929 -14.9068 7.1798 14.8728 -83.8987 -0.0000 0.0000 7.8495 4.3136 6.7625 -3.5771 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -24.4076 1.3174 2.7062 27.1837 0.0000 0.0000 -8.0936 4.1750 -9.6991 0.6804 0.0000 0.0000 5.4131 0.1538 7.6792 15.9436 0.0000 0.0000 -12.9341 10.0370 -12.2051 -11.2649 0.0000 -0.0000 0.9318 -105.7635 23.9530 -5.3613 3.3883 -173.2652 -3.6050 -2.8463 0.7795 -2.5101 -3.3936 -0.5094 7.9061 8.2430 1.2374 -3.6387 7.6244 -2.8104 -25.3570 28.4714 15.8997 7.6974 9.8309 5.5803 -7.4156 -3.9885 14.8454 -11.6162 -8.7869 68.2831 0.0000 0.0000 14.8027 -0.5331 -10.6875 -2.1990 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.9661 -3.2718 -15.5834 7.2450 16.3357 -83.0747 -0.0000 0.0000 7.8046 4.3870 7.0777 -3.7779 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -23.0485 0.6492 1.8580 27.0431 0.0000 0.0000 -9.6521 4.9254 -9.9239 1.0554 0.0000 0.0000 5.0133 -0.9899 7.8658 18.5418 0.0000 0.0000 -12.5667 9.7944 -12.8172 -11.7627 0.0000 -0.0000 1.0370 -105.3089 23.9549 -5.2058 3.5043 -173.3318 -3.3656 -2.8514 0.6857 -2.3536 -3.4167 -0.4976 7.4221 8.0427 1.3261 -3.8428 7.5530 -2.7345 -25.4971 26.5783 15.3811 6.7850 9.4357 5.4945 -7.4061 -3.5918 15.3572 -11.6530 -8.9040 67.9848 0.0000 0.0000 14.8507 -0.9560 -9.1226 -2.1164 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.8604 -3.4552 -16.2197 7.2650 17.1657 -82.0502 -0.0000 0.0000 7.9896 5.2269 7.6665 -3.6864 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -21.6633 0.4821 0.8834 26.9332 0.0000 0.0000 -11.1766 5.4745 -9.3521 1.4580 0.0000 0.0000 3.7083 -1.7648 7.9866 22.9282 0.0000 0.0000 -11.6681 10.7498 -13.0974 -11.2767 0.0000 -0.0000 1.1427 -104.8953 23.9537 -5.0845 3.5564 -173.4393 -3.0569 -3.0163 0.5876 -2.1629 -3.4647 -0.4746 6.9488 8.3199 1.3629 -4.0867 7.4464 -2.7450 -25.3637 23.8790 14.4306 5.9983 8.8874 5.5727 -7.4931 -3.2583 15.4043 -11.1165 -8.8561 68.5891 0.0000 0.0000 14.4585 -0.5757 -8.0832 -1.9781 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.7960 -3.2150 -16.5228 7.2181 16.6591 -81.3624 -0.0000 0.0000 8.1827 6.5332 8.2349 -3.4789 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -20.4844 0.1807 0.4229 26.8947 0.0000 0.0000 -12.2724 5.9910 -9.0933 1.7435 0.0000 0.0000 1.0842 -2.9363 8.4105 29.2825 0.0000 0.0000 -10.1956 13.3036 -13.5120 -9.6749 0.0000 -0.0000 1.2556 -104.5086 23.9413 -4.9257 3.3731 -173.5837 -2.7686 -3.3770 0.4997 -2.0209 -3.4146 -0.4266 6.6353 8.7046 1.3686 -4.2977 7.2975 -2.7435 -25.0187 20.8594 13.2067 5.3385 8.2480 5.5427 -7.5263 -2.8364 15.1871 -10.4682 -8.9753 69.5924 0.0000 0.0000 13.7285 0.0905 -8.1477 -1.8885 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.5814 -2.7116 -16.5875 6.8879 15.6754 -80.9586 -0.0000 0.0000 8.1327 7.2177 8.3377 -3.3965 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -19.4318 -0.5411 0.6838 27.0236 0.0000 0.0000 -13.1358 6.5312 -9.4484 1.7973 0.0000 0.0000 -2.0701 -4.6489 9.3197 35.9770 0.0000 0.0000 -9.7240 14.9002 -13.0656 -8.1293 0.0000 -0.0000 1.3566 -104.1314 23.9340 -4.6741 3.2617 -173.9494 -2.6225 -3.7372 0.4497 -1.9649 -3.2544 -0.3585 6.6273 9.0730 1.4933 -4.3733 7.1531 -2.7026 -24.6034 18.2560 11.9749 4.6967 7.5002 5.1917 -7.2543 -2.2715 15.1365 -10.0491 -9.0138 70.5012 0.0000 0.0000 12.8567 0.3649 -9.1638 -1.9134 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.2875 -2.3155 -16.6776 6.2989 15.3697 -80.4371 -0.0000 0.0000 7.7544 6.4788 7.8267 -3.4624 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -18.3649 -1.2161 1.2387 27.3554 0.0000 0.0000 -13.9382 6.8991 -9.6139 1.6419 0.0000 0.0000 -4.8525 -6.3618 10.8109 41.0588 0.0000 0.0000 -11.7156 13.1743 -10.3566 -7.6791 0.0000 -0.0000 1.4308 -103.7554 23.9494 -4.3323 3.4037 -174.6713 -2.5915 -4.0189 0.4409 -1.9882 -3.1310 -0.3063 6.8944 9.5135 1.8580 -4.3249 7.0784 -2.6299 -24.3606 16.5062 11.0095 4.2160 6.7636 4.5903 -6.9396 -1.6353 15.3359 -9.5249 -8.8779 71.2572 0.0000 0.0000 12.0445 0.5228 -10.2980 -2.0074 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.1213 -2.1786 -16.8189 5.7942 15.7730 -79.7201 -0.0000 0.0000 7.1883 4.7615 7.1497 -3.5888 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -17.1780 -1.4153 1.4369 27.6750 0.0000 0.0000 -14.5889 6.9577 -8.7783 1.4224 0.0000 0.0000 -6.9247 -7.7661 12.9624 43.3921 0.0000 0.0000 -14.5328 8.8558 -5.8680 -7.7016 0.0000 -0.0000 1.4857 -103.3775 23.9811 -3.9285 3.6483 -175.7181 -2.5563 -4.2753 0.4313 -1.9793 -3.0747 -0.2440 7.1819 9.9551 2.4197 -4.2513 7.0546 -2.5221 -24.4153 15.6024 10.4618 4.1128 6.1589 3.9780 -6.9450 -1.0010 15.5867 -8.5143 -8.9388 72.0122 0.0000 0.0000 11.4321 0.9736 -10.8787 -1.9981 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.1248 -2.1822 -16.8375 5.6362 16.0917 -79.1111 -0.0000 0.0000 6.7286 3.4529 6.9236 -3.6522 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.7596 -1.2502 0.9906 27.5690 0.0000 0.0000 -15.0738 6.8410 -7.0181 1.2098 0.0000 0.0000 -8.4179 -9.0781 15.5634 43.0318 0.0000 0.0000 -15.6970 5.1655 -1.5872 -7.4338 0.0000 -0.0000 1.5315 -103.0036 24.0073 -3.5334 3.9114 -176.9205 -2.4539 -4.4138 0.4169 -1.9068 -3.0563 -0.2078 7.3338 10.2831 3.1192 -4.2077 7.0854 -2.4404 -24.6434 15.1833 10.2689 4.2947 5.6755 3.5231 -7.1303 -0.4313 15.7999 -7.3022 -9.4061 72.7302 0.0000 0.0000 11.0754 1.3956 -10.9602 -1.8468 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.2542 -2.3124 -16.6509 5.8020 16.0207 -78.8431 -0.0000 0.0000 6.5716 3.3412 7.2376 -3.5984 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -14.2037 -0.9614 0.2175 27.0417 0.0000 0.0000 -15.6051 6.7363 -5.0355 0.9850 0.0000 0.0000 -9.6416 -10.3537 18.0761 40.8631 0.0000 0.0000 -15.3242 3.9877 1.0240 -7.1987 0.0000 -0.0000 1.5623 -102.6473 24.0123 -3.2426 4.2097 -178.1085 -2.3615 -4.4719 0.3917 -1.8193 -2.9973 -0.1649 7.4154 10.5532 3.8028 -4.1766 7.1372 -2.3707 -24.8304 14.9373 10.2548 4.5113 5.2639 3.2313 -7.1189 0.1146 16.0187 -6.4560 -10.0044 73.2580 0.0000 0.0000 10.8902 1.3866 -10.9472 -1.6845 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -3.5156 -2.5499 -16.4018 6.0602 15.9274 -78.7797 -0.0000 0.0000 6.6368 4.0524 7.6767 -3.5343 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -12.9013 -0.6704 -0.2227 26.6893 0.0000 0.0000 -16.3347 6.6134 -3.5182 0.8206 0.0000 0.0000 -10.9701 -11.3474 19.7732 37.7841 0.0000 0.0000 -14.6239 4.1670 1.7629 -7.3168 0.0000 -0.0000 1.5624 -102.3137 23.9947 -3.0117 4.5890 -179.2447 -2.2587 -4.5208 0.3740 -1.7681 -2.9541 -0.1268 7.5177 10.8901 4.4664 -4.1254 7.2230 -2.3162 -24.8919 14.7649 10.3076 4.7105 4.9388 3.0436 -6.9221 0.6426 16.2812 -6.0357 -10.4184 73.5646 0.0000 0.0000 10.7201 1.2218 -10.9921 -1.6129 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.8553 -2.7452 -16.2332 6.2020 15.9762 -78.6744 -0.0000 0.0000 6.7304 4.9040 7.8161 -3.5700 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -12.0833 -0.3315 0.0586 27.0733 0.0000 0.0000 -17.2736 6.3427 -2.6851 0.8436 0.0000 0.0000 -12.5274 -11.8086 20.0042 34.2413 0.0000 0.0000 -13.8213 4.3404 1.3048 -7.5933 0.0000 -0.0000 1.5243 -101.9958 23.9578 -2.8905 5.0381 179.6774 -2.2132 -4.5765 0.3568 -1.7632 -2.9626 -0.0875 7.6317 11.2796 5.0853 -4.0675 7.3241 -2.2271 -24.8215 14.7097 10.3680 4.9360 4.6719 2.9168 -6.8103 1.0368 16.5450 -5.6775 -10.5730 73.7367 0.0000 0.0000 10.5118 1.3045 -11.0197 -1.5972 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.1063 -2.7048 -16.1390 6.1991 15.8174 -78.4989 -0.0000 0.0000 6.8159 5.6302 7.5827 -3.7069 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -11.7488 0.1358 0.7289 28.1094 0.0000 0.0000 -18.4078 5.9422 -2.2108 1.0448 0.0000 0.0000 -14.3199 -11.7619 18.7407 30.3756 0.0000 0.0000 -12.5666 4.6627 0.4143 -7.9503 0.0000 -0.0000 1.4538 -101.6664 23.9112 -2.7801 5.4467 178.6797 -2.2373 -4.6867 0.3333 -1.7636 -2.9755 -0.0699 7.7294 11.6284 5.6640 -3.9918 7.4077 -2.1324 -24.5845 14.7081 10.3753 5.1248 4.3731 2.8330 -6.8329 1.1767 16.7597 -5.1990 -10.5406 73.8223 0.0000 0.0000 10.3697 1.5020 -11.0438 -1.5717 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.2220 -2.4809 -16.0022 6.2225 15.4120 -78.4036 -0.0000 0.0000 6.9701 6.2236 7.1950 -3.8696 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -11.3943 0.6955 1.2312 29.1279 0.0000 0.0000 -19.6292 5.5682 -1.6738 1.2649 0.0000 0.0000 -15.9431 -11.4729 16.8089 26.1049 0.0000 0.0000 -10.9834 5.6725 -0.6965 -8.7075 0.0000 -0.0000 1.3525 -101.3067 23.8697 -2.6406 5.7665 177.7587 -2.3749 -4.8748 0.2918 -1.8181 -2.9561 -0.0492 7.9228 11.8868 6.1544 -3.8777 7.4606 -2.0328 -24.2450 14.6335 10.3009 5.2680 4.0352 2.7801 -6.8835 1.1365 16.8636 -4.6707 -10.5080 73.8726 0.0000 0.0000 10.3309 1.4729 -11.1391 -1.5339 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.3305 -2.2169 -15.7749 6.4011 15.2242 -78.4254 -0.0000 0.0000 7.1608 6.6275 6.9907 -4.0444 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -10.7225 1.3265 1.4861 29.7177 0.0000 0.0000 -20.7647 5.2222 -0.9891 1.3774 0.0000 0.0000 -17.1628 -11.0631 14.9427 21.4401 0.0000 0.0000 -9.3782 7.2467 -1.9762 -10.0606 0.0000 -0.0000 1.2188 -100.9164 23.8410 -2.4130 5.9845 176.9029 -2.5325 -5.1267 0.2403 -1.8976 -2.9529 -0.0432 8.1909 12.0867 6.5677 -3.7452 7.4668 -1.9353 -23.9283 14.4364 10.1718 5.4738 3.7569 2.7276 -6.9743 1.1143 16.8436 -4.1096 -10.7240 73.9856 0.0000 0.0000 10.2176 1.2444 -11.3095 -1.5150 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -4.4790 -1.9841 -15.5290 6.6813 15.4438 -78.4280 -0.0000 0.0000 7.2547 6.8691 7.1663 -4.2837 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -9.6774 1.9940 1.7416 29.8894 0.0000 0.0000 -21.6964 4.7391 -0.3746 1.3902 0.0000 0.0000 -18.1237 -10.5575 13.0250 16.9226 0.0000 0.0000 -7.6748 8.8782 -2.8744 -11.4968 0.0000 -0.0000 1.0561 -100.5109 23.8196 -2.1855 6.0762 176.1164 -2.6458 -5.4557 0.1967 -1.9148 -2.9594 -0.0481 8.3289 12.2412 6.9257 -3.6467 7.4252 -1.8478 -23.5964 14.0968 9.9743 5.6601 3.4500 2.6385 -7.1466 1.1867 16.7878 -3.4553 -11.1461 74.1473 0.0000 0.0000 9.9034 1.0834 -11.4852 -1.5450 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.5785 -1.7164 -15.3210 6.9678 15.6096 -78.3764 -0.0000 0.0000 7.2461 7.2165 7.5694 -4.5633 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -8.4877 2.6467 2.0188 29.8275 0.0000 0.0000 -22.4237 4.1004 0.1116 1.3781 0.0000 0.0000 -19.3409 -10.0748 11.0841 13.5441 0.0000 0.0000 -6.1175 10.0909 -2.8489 -12.0906 0.0000 -0.0000 0.8726 -100.0914 23.8021 -1.9820 6.0046 175.2676 -2.6510 -5.9041 0.1647 -1.8866 -2.9835 -0.0402 8.1980 12.4520 7.3619 -3.5628 7.3413 -1.7648 -23.0085 13.4219 9.6289 5.4910 2.7184 2.5364 -7.2410 1.3178 16.8088 -2.7633 -11.3216 74.1558 0.0000 0.0000 9.5803 0.9871 -11.5629 -1.6368 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.6462 -1.2345 -15.0697 7.2443 15.4249 -78.4543 -0.0000 0.0000 7.2725 7.7924 7.8686 -4.8621 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -7.2147 3.2517 2.1487 29.5495 0.0000 0.0000 -22.9475 3.4439 0.7524 1.3471 0.0000 0.0000 -20.8421 -9.7258 10.1548 11.6822 0.0000 0.0000 -5.5426 10.5682 -2.2858 -11.6560 0.0000 -0.0000 0.6755 -99.6473 23.7893 -1.8952 5.7839 174.1041 -2.7332 -6.4138 0.1467 -1.8737 -3.1089 -0.0315 7.8641 12.8643 8.1015 -3.4121 7.1874 -1.6516 -22.0911 12.0541 9.0875 4.8867 1.2790 2.5205 -7.0889 1.4187 16.8850 -2.1239 -10.8294 73.9127 0.0000 0.0000 9.4618 0.6161 -11.4642 -1.7354 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -4.8699 -0.4118 -14.6834 7.4520 15.3196 -78.7195 -0.0000 0.0000 7.2925 8.2068 7.9420 -5.2775 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.9493 3.8154 2.2267 29.0175 0.0000 0.0000 -23.2508 2.7528 1.7376 1.1896 0.0000 0.0000 -22.2239 -9.5078 10.6240 10.5832 0.0000 0.0000 -6.0282 10.2952 -1.7823 -10.8414 0.0000 -0.0000 0.4708 -99.1694 23.7736 -1.9385 5.4222 172.6932 -2.9829 -6.7718 0.1115 -1.9497 -3.4064 -0.0431 7.5256 13.3923 9.0708 -3.2134 6.8746 -1.4496 -21.0702 9.8580 8.3404 4.2707 -0.6161 2.6307 -6.7116 1.3111 16.8200 -1.5768 -9.7081 73.6724 0.0000 0.0000 9.3831 -0.1774 -11.3033 -1.7695 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -5.2932 0.6195 -14.2718 7.4484 15.6114 -78.9184 -0.0000 0.0000 7.0492 7.8621 7.8417 -5.9063 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -4.6869 4.3108 2.4194 28.2910 0.0000 0.0000 -23.3822 1.8934 2.8103 0.8300 0.0000 0.0000 -23.2222 -9.3486 11.1279 9.4539 0.0000 0.0000 -6.4117 9.8519 -1.2788 -10.1971 0.0000 -0.0000 0.2573 -98.6458 23.7389 -1.9231 4.9133 171.5213 -3.2483 -6.9039 0.0441 -2.0496 -3.5949 -0.0469 7.2569 13.6095 9.8049 -3.0680 6.3350 -1.1546 -20.1301 7.2176 7.3787 4.0390 -2.4054 2.7275 -6.2674 0.9279 16.4719 -1.1176 -8.5197 73.7483 0.0000 0.0000 9.0953 -0.9209 -11.3009 -1.7640 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -5.6914 1.5088 -14.0216 7.2150 15.8262 -78.8520 -0.0000 0.0000 6.4580 6.6710 7.4183 -6.5737 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -3.1920 4.7296 2.5557 27.5647 0.0000 0.0000 -23.4746 0.9285 3.6196 0.3795 0.0000 0.0000 -23.8344 -9.0228 10.4127 8.3991 0.0000 0.0000 -6.0309 9.8011 -0.4622 -9.6790 0.0000 -0.0000 0.0239 -98.0606 23.6808 -1.7624 4.2717 170.8406 -3.4824 -6.9600 -0.0508 -2.1097 -3.5026 -0.0359 7.0391 13.3123 10.0908 -2.9831 5.6688 -0.8507 -19.2870 4.7194 6.2944 4.0747 -3.8046 2.6327 -5.8288 0.4556 15.9768 -0.7352 -7.8121 74.1083 0.0000 0.0000 8.7470 -1.0788 -11.4029 -1.7652 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.9020 2.0638 -13.8589 6.9286 15.3382 -78.7045 -0.0000 0.0000 5.8246 5.2362 6.4412 -6.9807 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -1.3468 5.1310 2.3841 26.9399 0.0000 0.0000 -23.5701 -0.0150 4.2254 -0.0576 0.0000 -0.0000 -23.9171 -8.2679 9.1111 7.5918 0.0000 0.0000 -5.4955 9.7640 0.3394 -9.2348 0.0000 -0.0000 -0.2476 -97.4020 23.6144 -1.5344 3.7237 170.1876 -3.8075 -6.8338 -0.1966 -2.2648 -3.5534 -0.0550 6.9594 12.8425 10.2854 -2.8582 5.0432 -0.5507 -18.6657 2.6220 5.3160 4.1092 -4.9304 2.3576 -5.4162 -0.0082 15.5963 -0.3445 -7.5047 74.5358 0.0000 0.0000 8.6016 -0.9129 -11.3539 -1.6929 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.0478 2.5541 -13.4806 6.7147 14.0736 -78.7711 -0.0000 0.0000 5.5220 4.2439 5.2932 -7.1039 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 0.6621 5.8788 1.9428 26.3578 0.0000 0.0000 -23.5722 -1.1662 5.1340 -0.6089 0.0000 -0.0000 -22.9206 -6.9569 8.4086 6.2977 0.0000 0.0000 -4.6675 8.8196 0.5925 -9.2822 0.0000 -0.0000 -0.5712 -96.6670 23.5529 -1.2342 3.7418 169.0875 -4.3518 -5.9868 -0.3986 -2.6695 -4.2239 -0.1845 7.2323 12.6826 10.7410 -2.6719 4.4803 -0.2136 -18.4630 0.6746 4.5295 4.2127 -6.0105 2.0389 -4.9855 -1.0710 15.3823 0.0217 -6.6806 74.9878 0.0000 0.0000 8.5229 -1.1465 -11.3014 -1.5030 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -6.3302 3.3305 -12.8152 6.5146 12.2727 -79.0271 -0.0000 0.0000 5.5332 3.8830 4.7580 -7.1325 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 2.5441 7.6190 1.3256 25.9810 0.0000 0.0000 -23.3523 -2.8435 6.7493 -1.4517 0.0000 -0.0000 -20.7172 -5.0622 7.8465 4.0371 0.0000 0.0000 -1.9474 7.0114 0.8168 -9.8980 0.0000 -0.0000 -0.9477 -95.8360 23.5113 -0.1942 4.9143 167.8951 -4.8686 -3.8860 -0.5238 -3.1821 -5.1892 -0.4247 7.9450 13.1172 11.1764 -2.5112 3.8277 0.1245 -18.4418 -1.6606 3.6286 4.6234 -7.3777 1.7089 -4.3478 -3.4011 15.0955 0.1731 -4.7925 75.4414 0.0000 0.0000 8.3177 -1.6526 -11.5343 -1.3652 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.7935 4.2648 -12.2856 6.3253 10.2556 -79.1984 -0.0000 0.0000 5.5221 3.9020 4.9399 -7.1609 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 4.7925 11.0366 0.3601 26.1358 0.0000 0.0000 -22.7089 -4.8273 8.8660 -2.6075 0.0000 -0.0000 -17.5706 -2.1635 5.9667 1.7774 0.0000 0.0000 2.8709 5.6149 2.4259 -10.2162 0.0000 -0.0000 -1.3557 -94.9052 23.5171 2.0446 7.1748 167.2462 -5.0691 -1.2325 -0.4529 -3.4804 -5.2673 -0.5105 8.6758 14.1326 11.1649 -2.3812 2.9938 0.3734 -17.8961 -4.9431 2.2531 5.2731 -9.4795 1.2994 -3.4915 -6.1642 14.5536 0.3929 -3.1624 75.5599 0.0000 0.0000 8.3000 -1.5189 -11.5168 -1.3874 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -7.3061 4.9172 -12.3406 6.3080 8.6272 -79.2205 -0.0000 0.0000 5.2936 3.9493 5.1527 -7.1319 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 8.0917 15.8214 -0.9305 26.7779 0.0000 0.0000 -21.1899 -6.5024 10.6781 -4.2250 0.0000 -0.0000 -14.0684 1.9265 2.2491 1.2699 0.0000 0.0000 6.4639 5.6589 6.0505 -9.6400 0.0000 -0.0000 -1.7512 -93.9502 23.5933 4.3510 9.3792 166.8545 -5.3388 0.4061 -0.1768 -3.5375 -4.2990 -0.2891 8.7740 15.5297 11.0952 -2.1265 2.2279 0.5312 -16.5996 -9.4053 0.5778 5.7864 -12.3654 0.8032 -2.6188 -7.5909 13.8385 1.4092 -3.3576 75.1368 0.0000 0.0000 8.6491 -0.9758 -10.5458 -1.3154 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.8716 5.2072 -12.7591 6.6786 8.1422 -79.4020 -0.0000 0.0000 4.9190 3.8497 4.8851 -7.0472 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 11.1597 20.2092 -1.5020 27.9471 0.0000 0.0000 -18.3153 -7.5699 11.5167 -6.5406 0.0000 -0.0000 -10.9109 6.0829 -0.6320 2.2764 0.0000 0.0000 6.1670 5.6898 9.3161 -8.9162 0.0000 -0.0000 -2.0806 -93.0525 23.7256 6.0046 10.3035 165.8941 -5.7386 0.8988 0.2583 -3.4832 -3.5471 -0.0781 8.2781 16.6496 11.5901 -1.7345 1.7639 0.6870 -15.2562 -14.4113 -0.7774 5.8946 -15.2021 0.2252 -2.0600 -7.1161 13.3853 3.4842 -5.0673 74.4701 0.0000 0.0000 8.8621 -1.2744 -9.2820 -1.0027 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.5770 5.3469 -12.8137 7.3478 8.7332 -80.0234 -0.0000 0.0000 4.5087 3.5758 4.4190 -6.9987 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 12.1838 22.8633 -0.2202 30.5782 0.0000 0.0000 -14.1206 -8.0963 11.6609 -8.9334 0.0000 -0.0000 -7.4606 8.7767 -0.7692 2.3768 0.0000 0.0000 3.8759 4.1986 10.2829 -8.7096 0.0000 -0.0000 -2.3358 -92.2535 23.8441 7.5154 10.2041 164.2837 -5.7628 1.3296 0.7021 -3.3254 -3.1445 0.0558 7.8079 16.7642 12.2957 -1.4436 1.3341 0.9484 -14.5405 -18.6720 -1.6523 5.5504 -16.8335 -0.5219 -1.9619 -6.1598 13.4119 5.7255 -6.4431 74.0020 0.0000 0.0000 8.4541 -2.2842 -9.2654 -0.7743 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -9.2044 5.0674 -12.4191 7.6998 9.3271 -80.9338 -0.0000 0.0000 4.2262 3.2682 4.2665 -7.0026 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 10.5795 24.2880 2.3387 36.2899 0.0000 0.0000 -9.1876 -8.1131 11.8899 -9.4927 0.0000 -0.0000 -3.3723 10.2504 0.0391 1.0059 0.0000 0.0000 2.2444 2.2917 10.3418 -8.7458 0.0000 -0.0000 -2.5527 -91.5830 23.8757 9.1266 10.6052 162.7390 -5.4328 2.8015 1.2049 -3.1300 -2.1628 0.2658 7.7967 15.7859 12.4775 -1.3876 0.6195 1.3040 -14.4482 -21.0482 -2.4811 4.9146 -17.0949 -1.4432 -2.0219 -6.1235 13.4763 6.8449 -6.5311 73.8655 0.0000 0.0000 7.8211 -2.2383 -10.4957 -0.9366 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.4151 4.0934 -12.1986 7.0365 8.8758 -81.7571 -0.0000 0.0000 4.2686 3.1680 4.4441 -6.9500 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 6.5401 25.8866 4.8603 45.2984 0.0000 0.0000 -4.5309 -7.8771 11.7345 -6.8391 0.0000 -0.0000 0.2654 12.1016 -0.3409 -0.4544 0.0000 -0.0000 1.5673 1.1445 11.4095 -8.6589 0.0000 -0.0000 -2.7477 -91.0355 23.8330 10.4919 11.9927 161.8182 -5.2509 5.0497 1.7567 -3.0401 -0.4751 0.6518 8.2624 14.2830 11.9862 -1.4058 -0.1404 1.6325 -14.4833 -21.3864 -3.5050 4.3119 -16.8070 -2.3996 -1.7137 -6.6050 13.3021 6.5742 -6.3587 73.8675 0.0000 0.0000 7.8678 -0.7309 -10.9677 -1.0470 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -9.4110 2.9761 -12.3805 5.5960 7.3781 -82.3550 -0.0000 0.0000 4.6493 3.3782 4.4684 -6.6933 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 1.0574 27.8130 6.9321 55.0619 0.0000 0.0000 -1.9280 -8.2101 9.4994 -3.6807 0.0000 -0.0000 2.8077 14.7067 -2.2290 -1.4337 0.0000 -0.0000 0.8748 0.4868 13.5052 -8.5293 0.0000 -0.0000 -2.8872 -90.5713 23.8041 11.3229 12.8370 161.5811 -5.2571 6.5418 2.1663 -3.0192 0.6273 0.8982 8.9099 13.3326 11.3490 -1.2776 -0.4899 1.7739 -14.2261 -20.6030 -4.4041 4.0014 -16.5552 -3.2636 -1.0136 -6.6559 13.1735 5.9627 -7.2283 73.7345 0.0000 0.0000 8.7143 0.0713 -9.4445 -0.6505 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -9.7071 2.4685 -12.5189 4.4299 5.7381 -83.0750 -0.0000 0.0000 5.1193 3.6672 3.8403 -6.0570 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -4.2797 28.2169 8.4128 62.6488 0.0000 0.0000 -3.0408 -8.8143 4.6145 -3.6056 0.0000 -0.0000 4.9764 16.4398 -4.0734 -2.4354 0.0000 -0.0000 0.0698 -0.2816 14.8961 -8.4799 0.0000 -0.0000 -2.9616 -90.1791 23.8298 11.4569 12.4872 161.9527 -5.3551 6.9347 2.3754 -3.0671 0.7984 0.9157 9.5433 12.8129 10.7578 -1.0237 -0.3908 1.6840 -13.6655 -19.3885 -4.7195 4.0482 -16.3110 -3.9179 -0.4851 -6.1688 13.3657 6.0714 -9.0343 73.3652 0.0000 0.0000 9.4770 -1.3729 -7.3877 0.0856 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -10.0183 2.6734 -12.2164 3.7598 4.7479 -84.3691 -0.0000 0.0000 5.3317 3.7243 2.7312 -5.2112 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -8.9590 26.5356 8.7642 66.8541 0.0000 0.0000 -6.8215 -7.7729 -0.7201 -4.8610 0.0000 -0.0000 6.5431 16.5984 -4.3125 -2.9307 0.0000 -0.0000 -0.6810 -0.8085 14.3360 -8.5180 0.0000 -0.0000 -2.9897 -89.8543 23.8808 11.2335 11.7341 162.8456 -5.3394 7.2192 2.4252 -3.0811 0.7376 0.8598 9.9682 12.0378 10.1695 -0.8149 -0.2382 1.5662 -13.0584 -17.8439 -4.5208 4.4868 -15.8166 -4.2035 -0.4996 -5.6788 13.6330 6.9034 -10.6305 72.8953 0.0000 0.0000 9.4750 -3.2990 -6.8857 0.4926 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -9.0831 2.9548 -11.9242 2.4162 4.4384 -86.1431 -0.0000 0.0000 5.1320 3.3941 2.0573 -4.7351 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -13.0370 24.0589 8.2189 67.7164 0.0000 0.0000 -10.2202 -5.1491 -3.4071 -4.2106 0.0000 -0.0000 7.0408 16.0762 -3.0574 -2.0049 0.0000 -0.0000 -1.8250 -0.6126 12.2300 -8.7745 0.0000 -0.0000 -2.9859 -89.5790 23.9194 10.9928 11.1626 163.9713 -5.1492 7.8327 2.3850 -2.9917 0.9484 0.8717 10.2133 10.8644 9.6895 -0.7124 -0.2698 1.5653 -12.6773 -16.0911 -4.1838 5.2846 -14.9900 -4.0025 -0.7831 -5.4714 13.6212 7.8362 -10.9262 72.5621 0.0000 0.0000 8.9150 -3.2841 -7.9590 0.2239 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -6.6392 2.8754 -12.2517 -0.1350 4.2951 -87.9614 -0.0000 0.0000 4.7825 2.8321 2.4724 -4.9057 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -16.6213 21.7124 7.7263 65.6775 0.0000 0.0000 -11.9623 -3.4325 -2.9134 -2.0259 0.0000 -0.0000 6.9059 15.5724 -1.6355 -0.1621 0.0000 -0.0000 -3.4522 -0.2625 9.9565 -9.2190 0.0000 -0.0000 -2.9610 -89.3174 23.9431 10.9382 10.6253 164.9796 -4.8326 8.3349 2.3417 -2.8554 1.2474 0.9124 10.5329 9.7680 9.3357 -0.6297 -0.3811 1.6561 -12.5593 -14.4065 -3.8667 6.1537 -14.0829 -3.4420 -0.9535 -5.3628 13.4157 8.5288 -10.0816 72.4373 0.0000 0.0000 8.4190 -1.6119 -9.1755 -0.0834 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -4.3763 2.5219 -13.0028 -2.4690 4.0936 -89.5536 -0.0000 0.0000 4.6339 2.6284 3.4892 -5.2718 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -19.3122 19.6933 7.3822 60.6755 0.0000 0.0000 -12.1639 -3.9591 -1.3604 -0.7305 0.0000 -0.0000 7.2700 15.0848 -0.9887 1.0109 0.0000 0.0000 -4.8042 -0.6328 8.3847 -9.4028 0.0000 -0.0000 -2.9368 -89.0503 23.9590 10.8689 10.1772 165.9096 -4.6836 8.4612 2.3561 -2.7759 1.4535 0.9291 11.0823 9.1126 8.9209 -0.5357 -0.3927 1.6677 -12.5495 -13.0641 -3.5522 6.7136 -13.4479 -2.8713 -0.9264 -5.3339 13.3750 8.9155 -9.3791 72.2639 0.0000 0.0000 8.3393 -0.6208 -9.5663 -0.1170 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.7419 2.1902 -13.5273 -3.1185 4.0142 -90.9642 -0.0000 0.0000 4.7410 3.2135 4.1878 -5.2626 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -20.9749 18.5459 5.9957 52.7224 0.0000 0.0000 -10.4705 -5.3060 -0.6129 -0.6221 0.0000 -0.0000 8.2080 14.6579 -1.3069 0.9963 0.0000 0.0000 -5.3556 -1.6397 7.6250 -8.9996 0.0000 -0.0000 -2.9262 -88.7735 23.9642 10.6963 10.0458 166.9703 -4.6193 8.4253 2.3624 -2.7632 1.6089 0.9286 11.6094 8.8471 8.4027 -0.4673 -0.3127 1.5676 -12.5128 -12.1542 -3.3586 6.8353 -13.1259 -2.6258 -0.8720 -5.4131 13.5044 9.0611 -9.8964 71.8557 0.0000 0.0000 8.5749 -1.4519 -9.4166 -0.1809 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.2523 1.9448 -13.6485 -2.4341 4.1634 -92.2875 -0.0000 0.0000 4.9241 4.1419 4.3982 -4.9445 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -21.7141 18.6910 2.3696 42.7649 0.0000 0.0000 -6.1837 -5.9531 -0.4162 -0.4716 0.0000 -0.0000 9.2442 14.4640 -2.3016 0.4741 0.0000 0.0000 -5.5066 -2.4099 7.3731 -8.3558 0.0000 -0.0000 -2.9160 -88.4965 23.9651 10.2939 10.0732 168.1322 -4.6298 8.2255 2.3459 -2.8161 1.7849 0.9446 12.0193 8.7382 7.9569 -0.4313 -0.2700 1.4620 -12.5249 -11.5943 -3.5042 6.5909 -12.6620 -2.8861 -0.7707 -5.7810 13.5268 8.9427 -10.7846 71.3786 0.0000 0.0000 8.7959 -2.8881 -9.4036 -0.3666 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.3801 1.9031 -13.6797 -1.9953 4.2699 -93.3946 -0.0000 0.0000 4.9885 4.6320 4.5754 -4.7776 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -21.8652 19.3315 -3.2380 32.0499 0.0000 0.0000 0.5332 -6.2173 0.4561 -0.2711 0.0000 -0.0000 9.8848 14.3167 -3.0418 0.2061 0.0000 0.0000 -5.9813 -2.4598 6.8921 -7.9121 0.0000 -0.0000 -2.8785 -88.2122 23.9702 9.7057 9.9639 169.3100 -4.7910 7.9530 2.4046 -2.9556 1.8430 0.9508 12.4660 8.4457 7.6098 -0.3681 -0.3319 1.4424 -12.5904 -10.9857 -4.0945 6.1658 -11.5150 -3.7606 -0.5163 -6.4257 13.3366 8.6885 -10.5979 71.1686 0.0000 0.0000 8.7691 -3.3053 -9.6212 -0.5243 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.7300 2.0862 -13.8538 -2.2400 4.2273 -94.0648 -0.0000 0.0000 4.9167 4.4751 4.8076 -4.8798 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -21.3226 19.3750 -9.5039 21.0480 0.0000 0.0000 7.5116 -5.8597 2.8468 -1.0362 0.0000 -0.0000 10.1319 13.9295 -2.9938 0.4302 0.0000 0.0000 -6.9277 -2.1294 5.7323 -7.6199 0.0000 -0.0000 -2.7941 -87.8833 23.9620 9.3213 10.0069 170.6459 -4.9284 8.3961 2.6014 -3.0392 1.6331 0.8928 12.7577 7.5523 7.1755 -0.2515 -0.4550 1.4810 -12.3766 -9.8352 -5.0317 5.9116 -9.6464 -5.2443 -0.2619 -6.7620 13.0862 8.6750 -9.9046 71.2903 0.0000 0.0000 8.6143 -2.5497 -9.8004 -0.5627 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.4253 1.9277 -14.0499 -1.8740 4.6042 -94.3055 -0.0000 0.0000 4.8464 4.2299 4.6846 -4.9296 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -20.1700 18.9403 -14.2081 10.9414 0.0000 0.0000 11.2487 -4.2728 6.1827 -3.0992 0.0000 -0.0000 10.4926 13.5816 -2.7281 1.0692 0.0000 0.0000 -8.1256 -1.8194 4.1440 -7.3225 0.0000 -0.0000 -2.6705 -87.5069 23.9322 9.0989 10.3815 172.1933 -4.9936 9.5048 2.8465 -2.9572 1.2877 0.7833 12.6441 6.2456 6.6045 -0.1414 -0.5334 1.5083 -11.7927 -8.2323 -6.0695 6.0616 -7.6114 -6.9874 -0.1626 -6.6205 12.8661 8.9370 -10.0442 71.5281 0.0000 0.0000 8.6144 -1.7926 -9.9350 -0.5157 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.8112 1.3026 -14.1026 -0.5638 5.3178 -94.3901 -0.0000 0.0000 4.9728 4.4520 4.3324 -4.7484 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -19.7972 18.9711 -14.2023 4.6221 0.0000 0.0000 10.0527 -2.5802 7.6596 -5.3895 0.0000 -0.0000 10.9504 13.4283 -2.6431 2.0737 0.0000 0.0000 -9.5053 -1.5033 2.4584 -7.0944 0.0000 -0.0000 -2.5154 -87.0962 23.9148 9.1304 10.3208 173.7423 -4.8047 9.9595 2.8656 -2.7919 1.0663 0.6887 12.4567 5.0350 6.0446 -0.0728 -0.5215 1.4954 -11.1727 -6.6825 -6.7934 6.4164 -6.0409 -8.3460 -0.1800 -6.4287 12.6987 9.1476 -10.9733 71.7285 0.0000 0.0000 8.8465 -1.8512 -10.1976 -0.3658 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -3.8353 0.9124 -13.9949 0.2997 5.5306 -94.5068 -0.0000 0.0000 5.3972 4.9768 4.4795 -4.5108 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -20.2059 19.4193 -11.8655 2.9928 0.0000 0.0000 6.9201 -1.6637 8.1043 -6.5759 0.0000 -0.0000 11.8892 12.7490 -2.7138 2.9260 0.0000 0.0000 -10.8893 -1.0521 0.9248 -6.9756 0.0000 -0.0000 -2.3268 -86.6536 23.9153 9.3916 9.7278 175.0658 -4.5925 9.6401 2.7595 -2.6512 1.0147 0.6189 12.5426 3.9696 5.5621 0.0158 -0.4824 1.4829 -10.7196 -5.4463 -6.9430 6.6944 -5.1149 -8.8805 -0.2588 -6.3474 12.5943 9.1705 -11.7765 71.9164 0.0000 0.0000 9.1255 -2.3405 -10.5298 -0.1623 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.3854 0.8658 -13.8054 0.4055 5.4772 -94.5853 -0.0000 0.0000 5.8949 5.4242 5.1687 -4.3911 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -21.1310 19.8374 -9.8355 5.2287 0.0000 0.0000 4.9493 -2.0592 9.1804 -6.4855 0.0000 -0.0000 13.4857 11.4604 -3.2548 3.0669 0.0000 0.0000 -12.0047 -0.5826 0.0876 -6.8694 0.0000 -0.0000 -2.0909 -86.1648 23.9120 9.7436 8.9551 176.2141 -4.5945 9.0423 2.7121 -2.6420 1.0746 0.5791 12.9622 3.0315 5.1233 0.1596 -0.4648 1.4670 -10.4405 -4.5191 -6.6726 6.9395 -4.5224 -8.7577 -0.3889 -6.4466 12.5492 9.0621 -11.9395 72.0683 0.0000 0.0000 9.3173 -2.4806 -10.7595 -0.1410 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.2358 0.5040 -13.5903 1.6650 6.2234 -94.6144 -0.0000 0.0000 6.1263 5.8023 5.5373 -4.3473 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -22.1643 19.9679 -7.0900 9.7873 0.0000 0.0000 3.8373 -3.2354 9.1500 -5.6071 0.0000 -0.0000 15.5673 9.8416 -4.4932 2.5272 0.0000 0.0000 -12.8470 -0.1284 0.1653 -6.8235 0.0000 -0.0000 -1.8007 -85.6402 23.8858 9.7621 8.1973 177.1694 -4.9950 8.2229 2.7773 -2.8619 1.2149 0.5773 13.5699 2.4283 4.7704 0.2662 -0.4310 1.4065 -10.3397 -3.7516 -6.2807 7.2566 -3.8974 -8.4666 -0.5597 -6.9593 12.5606 8.8533 -11.5658 72.1112 0.0000 0.0000 9.4938 -2.1495 -10.9248 -0.3852 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -7.2086 -0.1322 -13.3564 5.0327 7.7475 -94.6556 -0.0000 0.0000 6.0621 6.1514 5.1063 -4.2629 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -23.6875 19.4353 -2.9759 15.9205 0.0000 0.0000 1.7749 -4.7882 6.8037 -4.4589 0.0000 -0.0000 17.3917 8.0703 -5.7774 1.8844 0.0000 0.0000 -13.7393 0.4199 0.6334 -6.9111 0.0000 -0.0000 -1.4607 -85.0741 23.8207 9.4937 7.6256 177.8410 -5.5688 7.3701 2.9457 -3.1875 1.3228 0.5949 14.0046 2.2065 4.4450 0.2615 -0.3066 1.2840 -10.2475 -2.9685 -5.8808 7.5743 -3.1901 -8.2506 -0.6922 -7.7520 12.5911 8.6285 -10.9788 72.2153 0.0000 0.0000 9.6922 -1.8162 -11.0555 -0.5253 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -10.5510 -0.4416 -13.1339 8.7507 9.2427 -94.5955 -0.0000 0.0000 6.0310 6.2653 4.3880 -4.0638 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -25.7272 18.1474 2.1601 23.4134 0.0000 0.0000 -1.1636 -7.6143 3.0741 -3.3870 0.0000 -0.0000 18.9183 6.3947 -6.6003 1.4067 0.0000 0.0000 -14.9571 1.0653 0.9709 -6.9200 0.0000 -0.0000 -1.0797 -84.4300 23.7034 9.4218 7.4637 178.4741 -5.9710 6.8762 3.1703 -3.3750 1.3153 0.5750 14.0603 2.2727 4.0182 0.2130 -0.0870 1.0473 -10.0232 -2.1338 -5.4479 7.8099 -2.4853 -7.9891 -0.8364 -8.3986 12.5669 8.5141 -10.5758 72.5087 0.0000 0.0000 9.8812 -1.7701 -11.0434 -0.3040 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -12.4773 -0.3189 -12.8794 10.9411 10.0419 -94.3504 -0.0000 0.0000 6.1820 6.2073 4.1293 -3.7459 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -26.6705 16.6460 6.6027 30.4576 0.0000 0.0000 -3.3436 -11.5249 1.0568 -2.4901 0.0000 -0.0000 20.7888 4.9732 -7.2756 0.9854 0.0000 0.0000 -16.4848 1.8581 1.1104 -6.7174 0.0000 -0.0000 -0.6613 -83.7134 23.5296 9.3169 7.6943 179.2244 -6.4377 6.4430 3.4029 -3.6165 1.3520 0.5910 14.1294 2.8116 3.5260 0.1640 0.2013 0.7598 -10.0100 -1.2491 -4.9787 8.0645 -1.6251 -7.5477 -1.1408 -9.0530 12.4051 8.2610 -10.6148 72.7491 0.0000 0.0000 10.1161 -1.9600 -11.2031 -0.0886 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -13.8117 -0.0484 -12.5357 12.3484 9.8388 -94.1955 -0.0000 0.0000 6.2540 6.4769 4.3123 -3.4422 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -25.9255 15.3628 9.2958 35.2083 0.0000 0.0000 -4.4523 -13.5876 2.3669 -1.5277 0.0000 -0.0000 22.5180 3.7440 -7.3820 1.0688 0.0000 0.0000 -18.3415 3.1386 0.6394 -6.6004 0.0000 -0.0000 -0.1853 -82.9638 23.2967 8.7131 7.9018 179.6090 -7.1300 5.4550 3.5851 -4.1051 1.1863 0.6110 14.3133 4.3133 3.4763 -0.0283 0.5710 0.4869 -10.5263 -0.1303 -4.4325 8.5225 -0.3511 -7.0463 -1.5523 -10.2401 12.1309 7.3523 -11.2985 72.7539 0.0000 0.0000 10.6069 -2.3048 -12.1603 -0.3735 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.4241 0.3851 -11.9402 14.0210 8.9755 -94.3251 -0.0000 0.0000 6.1300 6.8363 4.1932 -3.3136 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -25.0195 13.4642 11.5794 38.5446 0.0000 0.0000 -6.8437 -11.9540 4.0170 -0.3990 0.0000 -0.0000 23.2149 2.5016 -5.8095 2.4129 0.0000 0.0000 -20.7571 5.0390 -0.8509 -6.6262 0.0000 -0.0000 0.3860 -82.2043 23.0275 7.8789 7.1921 179.0547 -7.6220 3.7037 3.7008 -4.5612 0.0619 0.4059 14.1226 6.7088 4.0888 -0.5415 1.0244 0.2428 -11.3360 1.3905 -3.7185 9.1099 1.1926 -6.7234 -1.8303 -12.0730 12.0157 5.5276 -12.4607 72.6949 0.0000 0.0000 11.7073 -2.7052 -13.8340 -1.0288 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -15.4835 1.6595 -10.9584 14.5994 8.2535 -94.2828 -0.0000 0.0000 6.1056 5.9641 3.4387 -3.2092 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -24.9969 9.2601 15.2558 42.4621 0.0000 0.0000 -11.5385 -8.5956 1.8749 0.3465 0.0000 0.0000 23.1624 0.5150 -2.7523 5.0712 0.0000 0.0000 -23.7901 7.1258 -2.4443 -6.2498 0.0000 -0.0000 1.0455 -81.4464 22.8010 7.5031 5.0625 178.0442 -7.4607 1.8960 3.6915 -4.6492 -2.3108 -0.1579 13.3472 8.9016 4.8143 -1.2676 1.4440 -0.0133 -11.9767 2.8980 -2.9293 9.5238 2.4335 -6.6626 -2.0193 -13.8902 12.3356 3.1690 -13.6768 72.6363 0.0000 0.0000 13.9024 -2.6478 -14.9906 -1.4308 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -12.4684 4.2974 -9.9949 13.0923 8.1693 -93.5121 -0.0000 0.0000 6.3253 3.6228 2.6810 -3.0156 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -24.6659 2.7203 19.2479 46.5987 0.0000 0.0000 -15.9947 -5.9188 -3.6719 0.5443 0.0000 0.0000 23.2087 -2.8347 -0.1975 8.7433 0.0000 0.0000 -26.7305 8.8942 -2.5509 -5.5090 0.0000 -0.0000 1.7146 -80.7381 22.7258 7.3173 2.1577 177.9602 -7.2751 0.7599 3.4187 -4.7622 -4.4486 -0.7188 12.9272 9.3449 4.7472 -1.8400 1.6618 -0.2418 -12.4686 3.4006 -2.4010 9.5530 2.9697 -6.7029 -2.5664 -14.8438 12.8848 0.7599 -14.7750 72.3274 0.0000 0.0000 17.3158 -1.5430 -14.3699 -1.1879 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -8.5033 7.4222 -9.8141 11.7870 8.2828 -92.2572 -0.0000 0.0000 6.5265 1.7580 2.9296 -2.9850 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -23.1330 -3.5743 20.9174 48.4462 0.0000 0.0000 -18.2925 -4.0441 -8.5652 0.6199 0.0000 0.0000 22.2937 -7.1665 0.7697 14.1868 0.0000 0.0000 -28.0386 10.1438 -1.5153 -5.6082 0.0000 -0.0000 2.3207 -80.1431 22.8383 6.5125 -0.5134 179.4773 -7.7200 0.1959 2.7759 -5.3674 -4.6661 -0.8448 13.3278 7.7694 3.6503 -2.0291 1.5504 -0.3912 -13.0931 2.2236 -2.3778 9.2405 2.9132 -6.5588 -3.5171 -14.6597 13.0645 -1.8789 -16.1809 71.8119 0.0000 0.0000 21.2567 0.1155 -12.2868 -0.7950 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -5.9707 9.2954 -10.5235 12.8384 7.8304 -91.2620 -0.0000 0.0000 6.4657 1.8138 5.1933 -3.3703 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -21.1464 -7.5943 19.6524 46.7230 0.0000 0.0000 -18.5775 -1.9402 -10.6306 0.7235 0.0000 0.0000 18.1885 -11.7504 0.9721 22.6602 0.0000 0.0000 -26.3601 10.4423 -1.4106 -7.1910 0.0000 -0.0000 2.8428 -79.6733 23.0538 5.2493 -2.7230 -178.0117 -8.1463 -0.3319 1.8381 -5.6538 -3.2414 -0.5257 13.0761 5.3358 2.1573 -1.9789 1.1704 -0.4600 -13.7286 -0.1297 -2.8080 8.7181 2.5246 -6.1464 -4.3363 -13.2601 12.4795 -4.9495 -18.6104 71.6499 0.0000 0.0000 24.5230 0.6490 -9.9401 -0.6387 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -4.2374 9.4985 -11.8677 14.8739 7.2131 -90.7890 -0.0000 0.0000 6.1694 3.0830 9.2014 -4.1618 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -19.3161 -9.8968 16.9157 42.7651 0.0000 0.0000 -17.8315 0.2579 -11.2349 0.7315 0.0000 0.0000 10.8786 -16.0111 0.4919 33.6528 0.0000 0.0000 -22.2162 8.5263 -2.4269 -8.8686 0.0000 -0.0000 3.2626 -79.2833 23.2590 4.5796 -4.4331 -175.6000 -7.5464 -1.0162 1.0004 -5.0170 -1.9301 -0.2578 11.6607 3.6453 0.8414 -2.0417 0.7710 -0.5171 -14.1666 -2.5907 -3.4538 7.9530 1.8629 -5.7899 -4.8662 -10.7518 11.3944 -8.0707 -21.8318 72.0750 0.0000 0.0000 26.2494 -1.2674 -7.6484 -0.4541 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -2.2627 8.7703 -13.2653 15.8301 8.0506 -90.6419 -0.0000 0.0000 5.8532 3.3291 12.8293 -4.7358 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -17.3785 -11.5937 14.6067 38.8651 0.0000 0.0000 -16.9196 1.6564 -12.0383 0.7322 0.0000 0.0000 2.8499 -18.8911 -1.3036 44.8613 0.0000 0.0000 -18.4694 5.2574 -2.6527 -9.1228 0.0000 -0.0000 3.5625 -78.9407 23.4042 4.6817 -5.2535 -174.0693 -6.1682 -1.6157 0.5212 -4.0877 -1.4065 -0.1668 10.4007 3.0147 0.0370 -2.2868 0.5634 -0.5909 -14.4927 -4.5192 -4.1565 6.9571 0.9489 -5.9101 -5.4962 -7.8920 10.3739 -10.7501 -24.3373 72.6780 0.0000 0.0000 26.4529 -4.5884 -4.9918 -0.0558 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.7996 8.0969 -13.9824 15.9543 10.5322 -90.6427 -0.0000 0.0000 5.5501 2.3198 14.1567 -4.5596 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -15.3398 -12.5270 13.0473 36.1494 0.0000 0.0000 -16.3039 2.2497 -12.2913 0.8862 0.0000 0.0000 -4.1023 -19.6403 -3.3058 54.3800 0.0000 0.0000 -17.5205 3.5498 -1.9580 -8.6830 0.0000 -0.0000 3.7674 -78.6347 23.4972 4.8459 -5.2783 -173.8513 -5.0337 -2.1155 0.3162 -3.4678 -1.4039 -0.1558 10.0349 3.1135 0.1354 -2.4738 0.5170 -0.5778 -14.7412 -5.7848 -4.8773 6.1507 -0.0436 -6.5810 -6.3493 -5.7243 9.7947 -12.7995 -24.9526 72.9908 0.0000 0.0000 25.8564 -6.4809 -1.8860 0.2828 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.4687 7.9014 -13.9813 16.1805 12.7990 -90.6214 -0.0000 0.0000 5.0617 1.9082 12.7944 -4.4096 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -13.6332 -12.4745 11.4315 34.3934 0.0000 0.0000 -16.1041 2.6617 -10.6273 1.0771 0.0000 0.0000 -9.7472 -19.0527 -3.5716 61.0463 0.0000 0.0000 -18.8606 3.6680 -1.4169 -8.6325 0.0000 -0.0000 3.9207 -78.3465 23.5611 4.6637 -4.9890 -174.9231 -4.6174 -2.6620 0.2446 -3.2698 -1.6160 -0.1399 10.3603 3.5549 1.0335 -2.4559 0.5140 -0.3716 -14.8227 -6.4283 -5.5116 6.0537 -1.0208 -7.4576 -7.0699 -4.6398 9.7090 -14.1912 -24.2110 73.0526 0.0000 0.0000 25.1811 -5.6957 1.1002 0.2269 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.7538 7.8303 -13.7503 16.4152 13.7949 -90.3141 -0.0000 0.0000 4.5000 2.4802 10.1381 -4.7875 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -12.5199 -11.9389 9.7952 33.2975 0.0000 0.0000 -16.2877 3.0947 -7.6286 1.1467 0.0000 0.0000 -14.2823 -18.4677 -1.4434 64.2623 0.0000 0.0000 -20.0772 3.7769 -0.9151 -8.6371 0.0000 -0.0000 4.0450 -78.0511 23.6109 4.4255 -4.7340 -176.5575 -4.5728 -3.2709 0.2281 -3.2261 -1.8321 -0.1279 10.9019 3.9436 2.0523 -2.2797 0.5366 -0.1319 -14.7070 -6.7837 -5.8881 6.7003 -2.1740 -8.1190 -7.4602 -4.1259 9.9630 -14.7971 -23.7400 73.0035 0.0000 0.0000 24.8980 -3.8584 3.1222 -0.0649 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.1262 7.4340 -13.5762 16.2564 14.2883 -89.5780 -0.0000 0.0000 4.2446 3.0580 7.9920 -5.1723 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -11.5858 -11.5285 8.7400 32.5870 0.0000 0.0000 -16.6591 3.4739 -4.8784 1.1928 0.0000 0.0000 -17.6725 -18.3752 1.8716 64.2578 0.0000 0.0000 -19.9110 3.1854 0.4668 -8.0567 0.0000 -0.0000 4.1403 -77.7386 23.6583 4.4851 -4.5133 -177.8802 -4.4518 -3.7360 0.1912 -3.1278 -1.9093 -0.1211 11.4613 4.1373 2.5673 -2.0473 0.5399 -0.0237 -14.4880 -7.3909 -5.9982 7.6135 -3.6936 -8.3448 -7.6107 -3.4973 10.3023 -14.5830 -24.1839 72.7724 0.0000 0.0000 25.0873 -2.9182 3.7762 -0.1292 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -1.6939 6.7005 -13.4087 15.8898 15.0217 -88.6479 -0.0000 0.0000 4.3792 3.2943 7.2076 -5.1398 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -10.2271 -11.2036 8.0908 31.7586 0.0000 0.0000 -17.0165 3.8916 -2.7858 1.3439 0.0000 0.0000 -19.9867 -18.2871 4.6277 61.7213 0.0000 0.0000 -18.7954 2.7858 2.6484 -7.2874 0.0000 -0.0000 4.2108 -77.4030 23.7155 5.0409 -4.2871 -178.6711 -3.9978 -3.9474 0.1165 -2.9193 -1.8174 -0.1015 11.9555 4.1912 2.6910 -1.7801 0.4117 0.0073 -14.1909 -8.5028 -5.9807 8.2737 -5.3396 -8.1886 -7.6390 -2.5242 10.5302 -13.7304 -24.8682 72.2823 0.0000 0.0000 25.3455 -2.6459 3.4423 0.2656 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -2.4242 5.7926 -13.1975 15.6122 15.6127 -87.9757 -0.0000 0.0000 4.5154 3.4721 7.2867 -4.8505 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.0523 -10.7636 7.3143 30.4255 0.0000 0.0000 -17.3122 4.3780 -0.8988 1.4978 0.0000 0.0000 -21.2768 -17.9305 6.1206 57.3958 0.0000 0.0000 -17.2084 3.2498 4.3061 -7.0699 0.0000 -0.0000 4.2705 -77.0458 23.7771 5.8483 -4.2160 -179.3292 -3.3580 -4.1038 0.0549 -2.6171 -1.5836 -0.0485 12.2331 4.1032 2.9259 -1.4716 0.0801 0.1659 -13.7454 -9.8038 -5.9645 8.4419 -6.6036 -7.8531 -7.5248 -1.4599 10.5405 -12.5021 -25.1033 71.7969 0.0000 0.0000 25.0580 -1.8567 2.6866 1.1040 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.9222 4.8032 -13.1015 15.4013 15.9093 -87.6932 -0.0000 0.0000 4.2930 3.5080 7.2400 -4.7523 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -5.3932 -10.4237 6.5597 28.7338 0.0000 0.0000 -17.5560 4.7598 0.8196 1.5199 0.0000 0.0000 -21.9133 -17.6759 6.7456 52.1949 0.0000 0.0000 -15.1875 4.4511 4.5190 -7.2917 0.0000 -0.0000 4.3149 -76.6755 23.8290 6.5296 -4.2759 179.8322 -2.7777 -4.3236 0.0206 -2.3367 -1.3504 0.0204 12.3116 3.9596 3.4800 -1.1614 -0.3190 0.4409 -13.2020 -10.8496 -5.9279 8.2257 -7.2978 -7.5240 -7.2402 -0.7040 10.4037 -11.0571 -24.8859 71.7234 0.0000 0.0000 23.9827 -0.8853 1.6060 2.1924 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -3.2100 3.8603 -13.2178 15.2141 16.7573 -87.4741 -0.0000 0.0000 3.8780 3.2334 6.9594 -4.9887 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -2.8315 -10.2271 6.2505 27.0802 0.0000 0.0000 -17.7871 4.9274 2.2093 1.4887 0.0000 0.0000 -22.3729 -17.5795 7.0927 46.9261 0.0000 0.0000 -13.1212 6.0050 3.5455 -7.5010 0.0000 -0.0000 4.3270 -76.3075 23.8648 6.7198 -4.2175 178.7986 -2.5414 -4.5541 -0.0125 -2.2134 -1.2642 0.0686 12.4130 3.9780 4.1178 -0.9023 -0.5589 0.6950 -12.7556 -11.4922 -5.8261 7.9683 -7.6893 -7.2710 -6.8354 -0.4263 10.4139 -9.5115 -24.3849 72.0518 0.0000 0.0000 22.5165 -1.0025 0.1644 3.2564 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -3.6486 3.1943 -13.4558 15.0566 18.4420 -86.9496 -0.0000 0.0000 3.6501 3.0864 7.1286 -5.3009 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.9612 -9.8626 6.2928 25.8232 0.0000 0.0000 -18.0999 4.9045 3.4451 1.5339 0.0000 0.0000 -23.1305 -17.2719 7.4093 41.8776 0.0000 0.0000 -11.3910 7.6765 1.8611 -8.0313 0.0000 -0.0000 4.3049 -75.9346 23.8880 6.6138 -3.9606 177.7207 -2.5169 -4.7403 -0.0687 -2.1841 -1.2739 0.0847 12.6000 4.1451 4.6523 -0.6950 -0.6071 0.8340 -12.5160 -11.7575 -5.7026 7.9949 -8.0672 -7.1160 -6.3801 -0.2564 10.8182 -7.9776 -23.7904 72.3660 0.0000 0.0000 21.2728 -2.1434 -1.1467 4.2261 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.2816 2.8677 -13.6986 14.8289 20.0999 -86.0790 -0.0000 0.0000 3.6582 3.7227 7.8062 -5.4915 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.3785 -9.2093 6.3647 25.0101 0.0000 0.0000 -18.5841 4.7441 4.6791 1.6474 0.0000 0.0000 -23.9352 -16.6850 7.7850 36.7668 0.0000 0.0000 -9.6084 9.5640 -0.3445 -9.2303 0.0000 -0.0000 4.2638 -75.5365 23.8960 6.5057 -3.7051 176.8275 -2.4548 -4.9031 -0.1234 -2.1526 -1.2363 0.0977 12.7475 4.2232 4.9807 -0.5217 -0.5948 0.9223 -12.4243 -11.7762 -5.7079 8.3072 -8.4025 -7.0958 -5.8894 0.1257 11.3705 -6.5330 -23.2977 72.5666 0.0000 0.0000 20.4748 -2.9823 -1.8575 5.1705 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -4.7876 2.6346 -14.0461 14.3680 21.2172 -85.0503 -0.0000 0.0000 3.7349 5.0489 8.3118 -5.7790 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 1.6346 -8.5243 6.3955 24.4320 0.0000 0.0000 -19.2595 4.5152 5.7135 1.7790 0.0000 0.0000 -24.3553 -16.0470 8.2545 31.3663 0.0000 0.0000 -7.4900 11.3783 -2.7959 -10.3100 0.0000 -0.0000 4.2115 -75.1100 23.8875 6.2801 -3.5795 176.3990 -2.4515 -4.9661 -0.1995 -2.1222 -1.1395 0.1005 12.7789 4.0469 5.0309 -0.3838 -0.6365 0.9734 -12.3727 -11.7064 -5.8719 8.5870 -8.5904 -7.2076 -5.2826 0.4853 11.6315 -5.2520 -22.8086 72.9898 0.0000 0.0000 19.9521 -2.9798 -2.2058 5.8301 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.1133 2.4087 -14.5865 13.7159 22.5098 -83.9783 -0.0000 0.0000 3.8643 6.4818 8.2822 -6.4653 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 2.8720 -7.9926 6.2343 23.7561 0.0000 0.0000 -19.9781 4.2589 6.4310 1.9247 0.0000 0.0000 -24.4774 -15.2441 8.5557 25.7345 0.0000 0.0000 -5.3673 12.0699 -5.2860 -10.4467 0.0000 -0.0000 4.1523 -74.6681 23.8720 5.6457 -3.6613 176.6257 -2.7038 -4.9340 -0.3559 -2.2560 -1.0783 0.0753 12.7729 3.6509 4.7126 -0.3006 -0.7075 0.9113 -12.3143 -11.7633 -6.0535 8.5717 -8.6481 -7.3996 -4.5017 0.2545 11.5744 -4.2052 -21.8421 73.7362 0.0000 0.0000 19.4555 -2.7996 -2.6932 5.9594 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.4092 2.3427 -15.1523 13.0245 24.2661 -82.9140 -0.0000 0.0000 4.0086 7.4504 7.9532 -7.4700 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 3.9436 -7.6950 5.4546 22.6064 0.0000 0.0000 -20.4562 3.9587 7.0909 2.0464 0.0000 0.0000 -24.7124 -14.1229 8.2843 19.8524 0.0000 0.0000 -2.6186 11.6900 -7.8339 -10.1591 0.0000 -0.0000 4.0954 -74.2006 23.8498 4.7227 -4.0840 177.4377 -3.1527 -4.9508 -0.5906 -2.4822 -0.9912 0.0364 12.6910 3.0403 4.0953 -0.2745 -0.8281 0.7843 -12.2921 -11.9790 -6.2572 8.3522 -8.6251 -7.6311 -3.7715 -0.4656 11.4465 -3.2856 -20.5540 74.3674 0.0000 0.0000 18.9478 -2.6680 -3.2707 5.8176 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.5962 2.4934 -15.5665 12.4018 25.4991 -82.0928 -0.0000 0.0000 3.9209 7.6494 7.6045 -8.3931 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 5.1926 -7.7468 3.9036 20.6412 0.0000 0.0000 -20.6487 3.6236 8.0252 2.0859 0.0000 0.0000 -24.9338 -12.9100 7.6640 13.7434 0.0000 0.0000 1.9760 12.3241 -9.5583 -10.1046 0.0000 -0.0000 4.0368 -73.6748 23.8081 3.9436 -4.6904 178.4920 -3.4899 -4.9756 -0.8550 -2.6187 -0.7870 0.0234 12.4576 2.3094 3.4926 -0.3358 -1.0853 0.7549 -12.4709 -12.1880 -6.6852 8.1935 -8.5216 -7.9571 -3.2973 -1.1851 11.1554 -2.2892 -19.5553 74.6842 0.0000 0.0000 18.5626 -1.9658 -3.4475 5.6786 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -5.6517 2.7958 -16.0909 11.7772 26.0384 -81.5288 -0.0000 0.0000 3.6198 7.6866 7.4123 -9.1619 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 7.2083 -7.9698 1.9072 17.8029 0.0000 0.0000 -20.7939 3.1728 9.3855 2.0872 0.0000 0.0000 -24.4757 -11.5969 7.2956 8.1803 0.0000 0.0000 6.3855 15.0095 -8.1920 -9.7336 0.0000 -0.0000 3.9511 -73.0944 23.7500 3.0905 -4.9018 179.2476 -3.8605 -4.5594 -1.1052 -2.7973 -0.6504 0.0301 12.3207 1.6826 3.2097 -0.5525 -1.4184 0.8706 -13.1256 -12.2845 -7.3411 8.1118 -8.3006 -8.3941 -2.8749 -2.1860 10.4547 -1.1680 -18.6657 75.1064 0.0000 0.0000 18.4937 -0.4593 -3.0345 5.3388 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.8615 3.6271 -16.9368 10.8959 26.7685 -80.7730 -0.0000 0.0000 3.5942 8.5775 7.6622 -10.2366 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 9.3624 -7.7405 -0.1282 14.8608 0.0000 0.0000 -21.0201 2.3558 11.0937 2.1640 0.0000 0.0000 -23.1063 -9.6227 7.3740 3.7088 0.0000 0.0000 6.4602 16.6131 -3.1284 -8.8846 0.0000 -0.0000 3.8328 -72.4808 23.6831 1.7174 -4.7185 179.2845 -4.5848 -3.6048 -1.2722 -3.2389 -0.8346 -0.0021 12.4962 1.0903 3.2009 -0.9105 -1.6739 1.0112 -14.2398 -12.2110 -7.8320 7.8099 -7.8816 -8.8551 -2.3698 -3.8911 9.6748 0.3004 -17.5928 75.8059 0.0000 0.0000 18.7985 1.1888 -2.3492 4.7642 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.2406 5.2926 -17.3416 9.8254 26.9813 -79.9832 -0.0000 0.0000 3.8799 9.7485 8.2223 -11.4987 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 10.5582 -6.9985 -1.7926 12.9059 0.0000 0.0000 -21.3080 1.1969 12.8851 2.2408 0.0000 0.0000 -21.2510 -7.1792 7.3817 -0.3250 0.0000 -0.0000 4.6232 12.8483 1.5779 -9.1942 0.0000 -0.0000 3.6977 -71.8399 23.5995 0.1474 -4.2697 178.8655 -5.4377 -2.1262 -1.2951 -3.8331 -1.0763 -0.0706 12.8649 0.0630 3.1203 -1.2980 -1.8384 1.0770 -15.4866 -11.8779 -7.9333 6.9390 -7.1645 -9.3265 -1.9438 -6.1095 9.5338 2.3532 -16.3565 76.2268 0.0000 0.0000 18.8939 1.7354 -1.9011 4.5518 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.2888 7.1300 -16.1381 9.0315 23.9635 -80.4054 -0.0000 0.0000 3.4333 9.0298 8.1949 -11.5877 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 10.8879 -5.8886 -3.0568 12.3519 0.0000 0.0000 -21.9267 0.0106 14.6109 2.0245 0.0000 0.0000 -19.8788 -4.9778 6.5956 -3.5544 0.0000 -0.0000 6.8836 5.6079 2.3880 -11.2516 0.0000 -0.0000 3.5239 -71.1624 23.5214 -0.7783 -2.6837 178.6864 -5.9296 0.1592 -1.2507 -4.3425 -0.8043 -0.0389 13.4785 -1.1354 2.9104 -1.6421 -1.9728 1.0987 -16.7116 -11.1992 -8.0323 5.4740 -6.1898 -10.0177 -1.5763 -8.5566 10.1678 4.7633 -14.5205 75.9604 0.0000 0.0000 17.6633 0.3756 -1.9165 4.6764 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -5.7774 8.2305 -13.4392 8.1226 16.9486 -82.3999 -0.0000 0.0000 1.5696 5.9973 6.6445 -10.2214 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 11.3803 -3.5242 -4.4968 12.8993 0.0000 0.0000 -23.0211 -1.2730 16.1367 1.2936 0.0000 0.0000 -19.5318 -2.4732 4.1009 -4.3073 0.0000 -0.0000 12.6171 0.2400 2.4384 -11.4536 0.0000 -0.0000 3.2573 -70.3938 23.5119 -0.3203 0.6229 178.5976 -5.7914 2.4569 -1.1332 -4.4902 -0.1479 0.1253 14.2202 -0.8456 3.2120 -1.8738 -1.8803 1.1136 -17.6911 -9.9962 -8.5555 4.0224 -5.2973 -11.2013 -0.8197 -10.6382 11.0332 7.4089 -11.7334 75.4562 0.0000 0.0000 14.5426 -2.0901 -2.2426 3.8529 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -5.0803 8.3710 -10.8139 6.1422 9.5795 -84.5696 -0.0000 -0.0000 -0.9834 3.0179 3.8672 -9.0951 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 13.1505 0.9011 -6.2615 14.0171 0.0000 0.0000 -23.5831 -3.1424 17.3256 0.0144 0.0000 0.0000 -18.6305 1.3133 0.7329 -2.8758 0.0000 -0.0000 16.4864 -0.5469 5.4141 -8.1621 0.0000 -0.0000 2.9074 -69.5382 23.6144 0.6869 4.3616 177.6716 -5.6298 3.2583 -0.8325 -4.3704 -0.1457 0.2202 14.5459 1.7380 4.5524 -1.8925 -1.1820 1.0830 -18.2401 -8.0462 -9.1428 3.3750 -4.8832 -12.8210 0.3261 -11.1996 11.8622 10.9421 -8.8682 75.3219 0.0000 0.0000 10.4236 -3.3660 -3.1935 1.4612 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.9137 8.0632 -9.2986 3.7847 5.9882 -85.7595 -0.0000 -0.0000 -3.4783 1.6492 1.3193 -8.7961 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 15.0965 6.2552 -7.4445 15.7319 0.0000 0.0000 -22.1738 -5.4211 18.3031 -2.0186 0.0000 -0.0000 -16.1572 5.6170 -0.8165 -1.7956 0.0000 -0.0000 15.4578 -0.1666 9.4720 -5.7611 0.0000 -0.0000 2.5600 -68.6986 23.7794 0.7493 6.6839 175.9836 -5.9026 2.3382 -0.4011 -4.2168 -0.9744 0.1433 13.8568 4.7378 6.5072 -1.7326 -0.0011 1.0091 -18.5768 -5.4580 -9.0896 3.5800 -5.0546 -14.2974 1.2962 -9.7317 12.9170 15.4569 -7.5458 75.5000 0.0000 0.0000 7.1788 -1.4467 -6.0314 -0.8927 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.4497 7.7966 -8.5698 1.7990 6.3819 -85.9651 -0.0000 -0.0000 -5.5195 1.2179 -0.1478 -8.7794 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 14.8692 10.4879 -7.3264 18.6948 0.0000 0.0000 -19.0578 -7.1473 19.6008 -5.0356 0.0000 -0.0000 -13.5923 8.6426 -0.4253 -2.3096 0.0000 -0.0000 12.4683 -1.9067 11.6716 -5.7347 0.0000 -0.0000 2.2579 -67.9487 23.9096 -0.0428 7.9654 174.5143 -6.0356 1.4582 -0.0481 -4.0296 -1.6268 0.0792 12.4538 6.3010 8.1600 -1.7127 0.9527 0.9613 -19.2190 -3.1151 -8.4827 3.8722 -5.5473 -15.0053 1.9944 -7.7565 14.0573 19.2890 -8.0542 75.5380 0.0000 0.0000 5.9229 2.7910 -10.8558 -0.9447 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -6.1122 7.4907 -8.1026 -0.5087 8.0597 -85.8266 -0.0000 -0.0000 -6.9189 1.1613 -0.9609 -8.4674 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 12.2838 13.6937 -6.9080 23.5848 0.0000 0.0000 -15.7731 -8.1987 21.6594 -8.6214 0.0000 -0.0000 -12.2595 10.5890 0.7193 -3.0124 0.0000 -0.0000 10.5373 -3.8053 11.7033 -6.4994 0.0000 -0.0000 1.9748 -67.2527 23.9596 -0.3369 9.7056 173.4195 -5.4400 1.9896 0.1721 -3.5837 -1.2964 0.2035 11.0649 6.6975 9.1055 -2.0522 1.1798 1.0860 -20.2278 -2.0079 -8.0464 3.6522 -6.0753 -14.8207 2.8372 -7.1427 14.5777 20.9516 -9.5030 75.1619 0.0000 0.0000 6.1326 5.0881 -15.2290 0.6431 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.4095 6.7818 -8.0120 -3.6859 8.8656 -85.5630 -0.0000 -0.0000 -7.9909 1.6026 -2.1819 -7.7567 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 8.4315 17.6654 -6.4997 31.1996 0.0000 0.0000 -11.9639 -10.0557 24.1089 -11.6555 0.0000 -0.0000 -11.2804 12.9915 1.5581 -2.9220 0.0000 -0.0000 9.2108 -4.3766 11.8817 -6.4190 0.0000 -0.0000 1.6940 -66.5683 23.9427 0.3899 12.1263 171.9171 -4.3075 3.5594 0.3390 -2.9703 -0.2449 0.4676 10.0756 6.8005 9.8332 -2.5997 0.8414 1.4796 -21.1322 -2.0184 -8.1452 3.1003 -6.6054 -14.0916 3.8751 -7.8235 14.2887 20.8143 -11.5307 74.6513 0.0000 0.0000 6.7640 2.6373 -16.3786 0.8369 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.4318 5.6886 -8.5692 -7.1721 8.6182 -84.8875 -0.0000 -0.0000 -9.1479 2.1654 -4.1504 -6.9944 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 2.8910 22.6696 -3.8691 41.8110 0.0000 0.0000 -4.9567 -13.6583 26.3152 -12.8410 0.0000 -0.0000 -9.4418 16.2107 1.8876 -2.8914 0.0000 -0.0000 7.4586 -5.0375 13.2636 -5.7913 0.0000 -0.0000 1.4389 -65.9151 23.8873 1.6228 14.6194 169.7638 -3.3118 5.5411 0.5876 -2.4294 0.8051 0.7348 9.5310 6.8388 10.6475 -3.0213 0.3025 2.0604 -21.6588 -2.2716 -8.6006 2.6721 -7.1747 -13.2558 4.7157 -8.4263 13.7507 20.1750 -14.0251 74.4745 0.0000 0.0000 7.3464 -1.2559 -13.2474 -0.2365 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.6439 4.4517 -9.6695 -10.0578 8.2662 -83.7955 -0.0000 -0.0000 -10.0694 2.1225 -6.0221 -6.5860 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -4.8354 26.9773 2.1223 53.4298 0.0000 0.0000 4.9087 -17.1543 27.9406 -10.7860 0.0000 -0.0000 -6.9613 19.6105 1.9562 -3.6834 0.0000 -0.0000 5.9446 -6.6383 14.8722 -5.5196 0.0000 -0.0000 1.2550 -65.3199 23.8407 2.8802 16.3710 168.0667 -2.6362 7.3691 0.7501 -2.0496 1.5299 0.9129 9.5544 6.6841 11.0284 -3.1691 -0.1449 2.5379 -22.0108 -2.4034 -9.1669 2.4722 -7.7154 -12.6404 5.1128 -8.3984 13.4536 19.8930 -16.1867 74.8094 0.0000 0.0000 7.8431 -2.1969 -8.0358 -0.7854 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -7.1573 3.4276 -10.9345 -12.1206 8.2221 -82.8252 -0.0000 -0.0000 -9.9797 1.6668 -6.9100 -6.5549 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -12.7279 28.6403 8.9973 63.3244 0.0000 0.0000 10.8155 -18.0518 27.2015 -7.5490 0.0000 -0.0000 -4.6435 22.2242 2.0116 -4.2762 0.0000 -0.0000 4.9497 -7.8041 15.4420 -5.5637 0.0000 -0.0000 1.1647 -64.7943 23.8476 3.5620 16.9090 167.9277 -2.2071 8.5375 0.7062 -1.8743 1.9654 0.9685 10.0323 6.2703 10.3981 -3.1431 -0.3852 2.6372 -22.2990 -2.6251 -9.7088 2.4140 -8.1988 -12.3566 5.2544 -8.1627 13.4213 20.1204 -17.2080 75.6303 0.0000 0.0000 8.0914 -1.1416 -4.0539 -0.8006 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -7.5852 2.8694 -11.9314 -13.4189 8.5501 -82.4580 -0.0000 -0.0000 -8.8887 1.7284 -7.1455 -6.3511 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -18.8220 27.4744 13.6411 70.3222 0.0000 0.0000 8.0220 -16.8854 22.3321 -5.8470 0.0000 -0.0000 -3.2404 23.3867 2.9632 -3.3266 0.0000 -0.0000 3.2873 -7.6985 13.9951 -5.6061 0.0000 -0.0000 1.1720 -64.3233 23.9181 3.3403 16.0710 169.2754 -2.0626 8.9318 0.5764 -1.9000 2.0807 0.9125 10.5740 5.4813 8.9591 -3.0328 -0.5285 2.4164 -22.3039 -3.0571 -10.1394 2.4969 -8.5653 -12.3408 5.1407 -7.8809 13.4113 20.8390 -17.6642 76.5985 0.0000 0.0000 7.9526 -0.4965 -3.3283 -0.4487 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -7.5459 2.6089 -12.5408 -13.6909 9.3999 -82.6497 -0.0000 -0.0000 -7.6223 2.1676 -7.5933 -5.6721 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -22.9959 24.1930 14.9457 73.7186 0.0000 0.0000 -0.1040 -13.8607 13.3164 -4.6662 0.0000 -0.0000 -2.6596 22.7895 4.9989 -1.2750 0.0000 -0.0000 0.6476 -7.1529 10.6105 -5.7156 0.0000 -0.0000 1.2528 -63.8820 24.0246 2.7036 14.3046 171.2593 -2.1129 8.9753 0.4984 -1.9798 2.0261 0.8128 10.9420 4.3040 7.4097 -2.8250 -0.8148 2.1739 -21.9294 -3.5616 -10.5132 2.6708 -8.6425 -12.3806 4.5137 -7.3322 13.2019 21.7294 -18.4611 77.1819 0.0000 0.0000 7.5293 -0.2406 -6.1494 0.1109 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -7.3064 2.1836 -13.3120 -12.5738 10.5617 -82.8958 -0.0000 -0.0000 -6.5402 2.0550 -8.1281 -5.0639 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -26.1037 19.9760 13.9257 73.3933 0.0000 0.0000 -6.5800 -8.8810 3.3642 -3.2225 0.0000 -0.0000 -2.0688 20.9506 6.7145 0.4191 0.0000 0.0000 -1.8038 -6.8355 6.9045 -5.8065 0.0000 -0.0000 1.3576 -63.4699 24.1163 2.2171 12.6963 173.3128 -2.1295 9.3369 0.4544 -1.9806 2.1730 0.7624 11.2338 3.0038 6.0967 -2.6042 -1.3653 2.0899 -21.3958 -4.0998 -10.9553 2.8141 -8.3675 -12.2196 3.4301 -6.6841 12.6477 22.0740 -19.2063 77.2357 0.0000 0.0000 7.0568 0.7296 -10.8470 0.4828 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -7.2904 1.4169 -14.8203 -10.3780 11.2440 -82.8775 -0.0000 -0.0000 -5.2456 1.6579 -7.8056 -5.0842 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -28.8697 16.4444 12.3034 70.2385 0.0000 0.0000 -9.4185 -4.2675 -3.7851 -2.1307 0.0000 -0.0000 -1.2628 19.1314 7.4850 1.5034 0.0000 0.0000 -3.4962 -6.5363 3.9581 -5.5213 0.0000 -0.0000 1.4535 -63.0776 24.1638 2.0780 11.8384 175.2033 -1.8954 10.1158 0.3897 -1.8819 2.6088 0.7765 11.5554 1.9583 4.8994 -2.5032 -1.9677 2.0535 -20.8461 -4.7888 -11.3615 2.9641 -7.9540 -11.6999 2.3925 -6.4526 11.8489 21.5169 -18.8649 77.1459 0.0000 0.0000 6.6844 2.1250 -14.4086 0.5716 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -7.1354 0.7719 -16.4269 -7.9530 10.8319 -82.9315 -0.0000 -0.0000 -3.8064 2.2142 -6.3000 -5.4926 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -31.2744 14.4366 10.9937 65.0283 0.0000 0.0000 -10.7283 -2.4461 -6.8369 -1.4293 0.0000 -0.0000 -0.2207 18.0430 7.5623 2.2889 0.0000 0.0000 -4.8531 -6.1578 1.8894 -4.8907 0.0000 -0.0000 1.5279 -62.6714 24.1762 2.0932 11.5648 176.7228 -1.5989 10.8619 0.3373 -1.7611 3.0733 0.7977 11.8561 1.3944 3.7262 -2.4630 -2.3000 1.8803 -20.2047 -5.5214 -11.4417 3.3032 -7.6050 -10.9648 1.6995 -6.7178 11.1241 20.4535 -17.6356 77.2396 0.0000 0.0000 6.5220 2.6003 -14.4481 0.3364 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.2523 0.6850 -16.9809 -5.6787 9.7827 -83.4839 -0.0000 -0.0000 -2.7262 3.5902 -4.6528 -5.9083 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -33.1256 13.7277 9.8465 57.8453 0.0000 0.0000 -10.3244 -3.3132 -6.1661 -0.9981 0.0000 -0.0000 1.1878 17.6002 7.1553 2.4986 0.0000 0.0000 -6.1413 -5.9634 0.5462 -4.4032 0.0000 -0.0000 1.5759 -62.2268 24.1663 2.0289 11.5914 177.7659 -1.6235 11.2596 0.3594 -1.7486 3.3600 0.7978 12.1875 1.3100 2.7505 -2.2899 -2.2775 1.5753 -19.4187 -5.9062 -11.1497 3.8498 -7.2379 -10.4302 1.1720 -7.0163 10.7246 19.2140 -16.9077 77.2330 0.0000 0.0000 6.7800 1.7062 -11.4024 -0.0291 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -5.2607 0.9501 -16.8347 -3.1014 9.9951 -84.0347 -0.0000 -0.0000 -1.7944 4.7271 -3.3292 -6.5431 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -34.2376 13.7665 8.1902 48.6008 0.0000 0.0000 -6.3649 -4.7877 -2.6124 -1.0656 0.0000 -0.0000 2.8515 17.5390 6.3457 2.0113 0.0000 0.0000 -7.2056 -5.9156 -0.1485 -4.1889 0.0000 -0.0000 1.6033 -61.7481 24.1321 1.7603 11.8462 178.3877 -2.1473 11.3678 0.5084 -1.9534 3.4898 0.8230 12.7659 1.5724 2.1444 -1.9525 -2.0311 1.2397 -18.6013 -5.6812 -10.7469 4.4831 -6.7072 -10.3905 0.6470 -7.2196 10.5351 17.5291 -17.3603 76.7223 0.0000 0.0000 7.6157 0.2335 -8.0827 -0.1078 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -5.3579 1.1398 -17.2605 0.1804 13.3870 -83.8809 -0.0000 -0.0000 -0.0484 6.4756 -1.2356 -7.8742 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -34.6168 14.0734 5.7027 37.5857 0.0000 0.0000 1.3073 -5.8840 2.9968 -1.3967 0.0000 -0.0000 4.3190 17.7359 5.3635 1.4594 0.0000 0.0000 -8.1874 -5.7955 -0.2684 -4.0342 0.0000 -0.0000 1.6315 -61.2312 24.0803 1.3795 12.0885 178.7259 -2.9760 11.1897 0.8193 -2.3385 3.5201 0.8550 13.6492 2.0326 1.7754 -1.6319 -1.6907 0.9154 -17.8530 -4.9933 -10.3974 5.2013 -6.0563 -10.6858 0.1974 -7.7315 10.3175 15.3049 -18.5071 75.7654 0.0000 0.0000 8.9191 -0.7368 -6.3623 0.0798 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.2085 1.4990 -18.1157 3.5064 18.8136 -83.4855 -0.0000 0.0000 2.9276 10.3839 1.8278 -9.7441 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -34.0444 14.1404 2.0472 25.2684 0.0000 0.0000 11.0496 -7.3370 9.7680 -1.5053 0.0000 -0.0000 5.4870 17.8932 4.5754 1.3972 0.0000 0.0000 -9.5655 -5.7429 -0.1758 -3.9705 0.0000 -0.0000 1.6853 -60.6381 24.0142 1.1359 12.1510 178.9762 -3.7513 10.9302 1.2074 -2.7041 3.3711 0.8603 14.4333 2.5086 1.4155 -1.4078 -1.3206 0.6234 -17.0945 -4.1166 -10.0354 6.0599 -5.3911 -10.8993 -0.1872 -8.4906 9.8999 13.1545 -20.0448 74.8091 0.0000 0.0000 10.3474 -0.7429 -6.1620 0.3082 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.2668 2.3349 -18.0561 6.5964 21.3762 -83.9404 -0.0000 0.0000 5.6409 13.9161 3.9493 -10.5721 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -32.2846 13.5116 -2.8604 12.9831 0.0000 0.0000 19.1924 -8.9851 16.7136 -1.5719 0.0000 -0.0000 6.7804 17.7835 4.1819 1.7789 0.0000 0.0000 -11.5111 -5.8339 -0.3986 -4.1065 0.0000 -0.0000 1.7705 -59.9663 23.9223 0.9687 12.2361 179.1465 -4.4264 10.9471 1.6355 -2.9607 3.0237 0.8274 14.8213 2.9182 1.1014 -1.1968 -0.9427 0.4159 -16.3928 -3.2691 -9.5597 6.9160 -4.6004 -10.7287 -0.6691 -9.0919 9.3167 11.4177 -21.9058 73.9546 0.0000 0.0000 11.7085 -0.1008 -6.8617 0.4310 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -5.1941 3.2296 -16.9043 9.7570 18.3343 -85.2567 -0.0000 0.0000 6.6934 13.4203 4.7407 -9.6563 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -30.7926 12.0599 -5.3728 4.3113 0.0000 0.0000 19.8511 -10.3876 20.0036 -2.0416 0.0000 -0.0000 8.1153 17.5720 4.2915 2.5644 0.0000 0.0000 -13.8033 -5.5185 -1.0839 -4.2141 0.0000 -0.0000 1.8690 -59.2431 23.8081 0.8838 12.2600 179.1108 -5.0159 10.8855 1.9577 -3.1760 2.7613 0.8089 15.1580 3.2139 0.9972 -1.0189 -0.6356 0.3033 -15.9938 -2.3942 -8.8406 7.5670 -3.5535 -10.1177 -1.1817 -9.4950 8.8147 9.6328 -23.4613 72.9983 0.0000 0.0000 13.0737 0.8131 -7.9408 0.3102 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.1035 3.9581 -15.9588 12.3401 13.7316 -86.0789 -0.0000 0.0000 7.0601 11.1759 5.5072 -8.7134 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -30.4473 10.3916 -4.8674 1.2331 0.0000 0.0000 12.2620 -10.0488 17.7365 -1.9077 0.0000 -0.0000 9.3647 17.2285 4.8314 3.8078 0.0000 0.0000 -16.2552 -4.4082 -1.9356 -4.1445 0.0000 -0.0000 1.9732 -58.4625 23.6774 1.0762 11.9916 179.1216 -5.2967 10.7091 2.0726 -3.2583 2.6288 0.7739 15.4274 3.0125 0.8287 -0.9402 -0.4149 0.1925 -15.8597 -1.3760 -7.7539 8.0283 -2.3591 -9.1380 -1.6487 -9.6300 8.5920 7.8095 -24.6246 71.9667 0.0000 0.0000 14.5452 1.9405 -8.7664 0.0440 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -3.6895 4.2571 -15.7775 14.1010 12.6843 -86.0089 -0.0000 0.0000 7.6391 11.3209 6.9497 -8.5218 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -30.4867 8.9055 -4.9341 2.3981 0.0000 0.0000 4.8513 -7.2348 13.8344 -1.1809 0.0000 -0.0000 10.9472 16.5383 5.2561 5.2971 0.0000 0.0000 -18.8360 -3.1602 -2.6526 -4.2184 0.0000 -0.0000 2.0859 -57.6327 23.5345 0.7492 11.1428 -179.9932 -5.6939 10.2681 2.0663 -3.4548 2.6203 0.7171 15.6428 2.1582 0.0283 -0.9592 -0.2768 -0.0546 -16.1413 -0.3119 -6.4778 8.2188 -1.2423 -7.9523 -2.4197 -9.5398 8.4545 6.5270 -25.5608 71.0303 0.0000 0.0000 15.8005 2.7160 -9.2625 -0.0167 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.5636 4.2767 -15.8296 15.0322 13.9223 -85.5440 -0.0000 0.0000 8.0241 13.0952 8.3891 -8.6861 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -30.3120 7.8719 -5.2944 4.6410 0.0000 0.0000 4.8314 -5.4020 10.8704 -1.5880 0.0000 -0.0000 12.0743 15.0542 5.4485 7.1621 0.0000 0.0000 -21.5941 -2.4961 -3.5988 -4.5178 0.0000 -0.0000 2.2216 -56.7783 23.3753 -0.8248 9.5296 -178.0639 -6.7521 9.0465 2.2259 -4.1990 2.7748 0.7028 16.2492 1.1966 -1.3773 -1.0832 -0.2396 -0.4235 -17.2741 0.5042 -5.4871 7.8445 -0.3521 -6.8117 -3.6590 -9.8481 7.9204 5.4443 -25.1077 70.3495 0.0000 0.0000 16.1734 2.1193 -10.5837 0.0841 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.3822 4.7328 -15.7410 15.0630 13.1144 -85.0343 -0.0000 0.0000 7.6775 13.0032 9.4152 -8.8394 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -29.9737 6.7345 -5.4140 5.3908 0.0000 0.0000 11.3198 -4.3447 10.0846 -2.0901 0.0000 -0.0000 11.7265 12.4493 6.0975 9.6285 0.0000 0.0000 -24.5381 -1.7065 -5.3317 -4.4865 0.0000 -0.0000 2.4216 -55.8988 23.2237 -3.0251 6.5712 -176.5227 -8.3590 6.5254 2.6704 -5.6524 2.8240 0.7433 17.9318 0.3765 -2.4553 -1.5629 -0.2888 -0.6881 -19.4200 0.8745 -4.8454 6.8490 0.2158 -5.8694 -5.0206 -11.2525 6.9951 3.3874 -21.8071 69.9121 0.0000 0.0000 15.7335 0.8559 -13.6394 -0.2373 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.1992 6.6930 -15.3034 13.7645 9.3240 -84.4062 -0.0000 0.0000 6.8093 10.3478 10.4591 -8.9741 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -29.3460 3.6254 -4.7095 3.9944 0.0000 0.0000 18.0714 0.0176 9.5793 -1.6211 0.0000 -0.0000 10.3428 8.2865 7.8970 12.4646 0.0000 0.0000 -27.5480 0.2728 -7.3188 -3.9535 0.0000 -0.0000 2.7147 -54.9215 23.1573 -3.2153 1.5182 -177.0816 -8.4668 3.1549 2.8767 -6.7422 1.9622 0.5414 19.6067 -1.6495 -2.2145 -2.5852 -0.2545 -0.5622 -21.5965 1.0196 -3.8756 5.5937 0.2451 -4.9842 -5.7069 -12.5991 6.5825 -0.0001 -17.1212 69.5600 0.0000 0.0000 15.7549 1.4149 -16.5411 -0.8859 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -2.9061 9.8670 -14.1334 11.1231 5.8900 -83.4985 -0.0000 0.0000 5.6321 6.8198 10.9693 -8.7098 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -25.9678 -2.8796 -3.0554 0.7385 0.0000 0.0000 21.0500 5.1274 7.2664 -0.6027 0.0000 -0.0000 11.2873 2.0238 10.6745 14.6452 0.0000 0.0000 -29.8010 2.6820 -8.1185 -4.1059 0.0000 -0.0000 3.0173 -53.9428 23.2155 -2.0793 -4.0060 -179.2587 -6.7154 1.3174 2.4286 -5.7745 0.4569 0.0393 17.9388 -6.1808 -0.8754 -3.4723 -0.1702 0.0401 -22.3469 1.0023 -2.2154 4.2383 -0.4869 -3.8153 -5.2703 -11.4228 7.0985 -3.6007 -15.4603 69.3221 0.0000 0.0000 17.3518 4.9324 -15.0563 -1.0729 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -2.3888 11.5994 -12.2372 8.0435 6.3319 -82.0104 -0.0000 0.0000 4.1935 3.5073 9.6349 -7.7780 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -21.2694 -10.1442 -2.3432 -2.1470 0.0000 -0.0000 20.4709 5.7430 6.2113 0.4001 0.0000 0.0000 13.6257 -4.1367 13.2210 17.2587 0.0000 0.0000 -30.0094 3.1232 -6.9558 -6.2278 0.0000 -0.0000 3.2116 -53.1851 23.3764 -2.8766 -6.9596 178.4015 -5.1991 1.0136 1.6135 -4.1267 -0.7330 -0.2798 13.8830 -8.5851 0.0048 -3.6203 -1.0050 0.7378 -22.1391 -0.8621 -1.2810 2.6328 -1.5750 -2.1962 -4.5502 -8.7112 7.5446 -6.7133 -18.6017 68.9335 0.0000 0.0000 20.6379 8.9807 -8.4373 -1.2357 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -2.1404 8.8397 -10.9556 5.2064 9.6038 -79.1410 -0.0000 0.0000 2.6949 0.9787 7.1609 -6.8673 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -19.8777 -14.0895 -4.1636 -2.2113 0.0000 -0.0000 18.0739 2.5315 9.2290 0.6616 0.0000 0.0000 11.4343 -7.4451 14.1869 23.8735 0.0000 0.0000 -27.3516 1.1995 -4.7147 -9.4331 0.0000 -0.0000 3.3150 -52.5733 23.5636 -4.3630 -7.6907 177.5908 -4.2749 0.6935 0.8149 -3.0743 -1.1107 -0.3424 10.6899 -7.9829 -0.3293 -3.3991 -2.1988 1.1118 -21.9502 -4.5197 -1.7314 0.9842 -2.7144 -0.7441 -4.3908 -6.1976 7.4793 -9.6988 -23.9805 67.8010 0.0000 0.0000 24.8432 11.4856 -1.1743 -1.5657 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.4195 3.3958 -11.2390 2.3149 10.6517 -74.8427 -0.0000 0.0000 1.2680 0.1231 5.6752 -6.6517 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -20.0352 -15.0084 -7.2572 -1.2138 0.0000 -0.0000 16.1849 -0.1715 13.5287 0.3867 0.0000 0.0000 5.3317 -9.3294 14.2594 34.5349 0.0000 0.0000 -22.2744 -0.1738 -2.7607 -11.1799 0.0000 -0.0000 3.4134 -51.9833 23.7026 -5.1397 -8.6080 178.3871 -3.4365 -0.3899 0.3481 -2.4869 -1.1384 -0.3550 8.9584 -7.2497 -1.2481 -3.3193 -2.8658 1.1496 -21.7267 -7.8396 -2.6872 -0.0124 -3.7309 -0.2952 -4.5662 -4.7012 7.1146 -12.9243 -27.1758 66.3168 0.0000 0.0000 28.5530 13.0983 3.3545 -1.8687 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -2.7703 0.0273 -11.9463 -0.9048 7.2710 -70.8487 -0.0000 -0.0000 -0.2353 1.2811 4.3508 -6.9294 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -19.4802 -15.7485 -9.4642 -0.8692 0.0000 -0.0000 14.5723 -1.2618 15.4688 0.0891 0.0000 0.0000 -1.5349 -12.3525 14.5835 46.4435 0.0000 0.0000 -17.5553 -0.2195 -1.1622 -10.5473 0.0000 -0.0000 3.5138 -51.3584 23.7967 -5.0091 -10.4300 179.2931 -2.5724 -2.1023 0.1892 -2.0562 -1.4285 -0.4112 8.1863 -7.4082 -1.5673 -3.4908 -3.1798 1.1914 -21.0115 -9.4014 -3.3641 0.1966 -4.3300 -0.8754 -4.8725 -4.0726 6.7116 -15.7818 -27.0080 65.1639 0.0000 0.0000 30.8466 14.5519 5.6275 -1.9044 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -2.8130 -0.1266 -11.7736 -4.8337 4.2914 -68.7432 -0.0000 -0.0000 -1.9609 2.2166 0.7413 -6.6290 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -17.5269 -17.4536 -10.7127 -1.4447 0.0000 -0.0000 12.9297 -2.9154 15.9249 -0.2085 0.0000 -0.0000 -7.1090 -16.6491 15.3289 56.5184 0.0000 0.0000 -15.7268 -0.6281 0.5053 -10.1685 0.0000 -0.0000 3.5725 -50.7153 23.8909 -4.5071 -11.9238 179.4013 -2.0930 -3.3820 0.1560 -1.7683 -1.8376 -0.4599 8.0549 -8.1740 -0.9440 -3.5489 -3.4802 1.4881 -19.7900 -9.4984 -3.6474 1.3830 -4.3358 -1.8456 -5.3905 -3.4638 6.3110 -17.5023 -25.8881 64.3922 0.0000 0.0000 31.7229 15.2591 7.4402 -1.2928 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -2.9418 0.4452 -10.7936 -9.0513 6.3566 -68.1996 -0.0000 -0.0000 -3.7917 -0.0244 -4.1006 -5.9597 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -14.8585 -18.9127 -12.1847 -2.1528 0.0000 -0.0000 11.6495 -5.9035 17.7308 -0.6543 0.0000 -0.0000 -11.2144 -20.4498 16.5145 63.0560 0.0000 0.0000 -16.4271 -1.9444 1.4885 -11.0054 0.0000 -0.0000 3.5876 -50.0882 23.9997 -3.8355 -12.4210 179.3436 -1.9843 -4.0665 0.1272 -1.6700 -1.8994 -0.4445 8.3372 -8.7323 -0.2178 -3.2333 -3.8563 1.9052 -18.4440 -9.3934 -3.8673 2.7850 -3.8276 -2.6274 -6.0575 -2.7778 5.7828 -17.9775 -25.7378 63.8946 0.0000 0.0000 31.5180 14.7807 9.4411 -0.4305 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -3.5495 -0.1426 -9.9931 -12.0228 10.5584 -67.7676 -0.0000 -0.0000 -5.2764 -4.2297 -7.3844 -6.3175 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -12.3133 -19.3355 -14.7162 -2.1639 0.0000 -0.0000 10.6256 -8.1474 21.1224 -1.0435 0.0000 -0.0000 -14.5930 -22.7713 17.2650 66.1449 0.0000 0.0000 -17.9463 -2.9657 1.2349 -11.2971 0.0000 -0.0000 3.5771 -49.4885 24.1093 -2.9085 -12.3029 179.9947 -1.9061 -4.5853 0.0413 -1.6291 -1.5982 -0.3969 8.6960 -8.8595 -0.1118 -2.7755 -4.1170 2.1414 -17.2137 -9.6178 -4.0814 3.8201 -3.2313 -3.0767 -6.5133 -2.4962 5.2684 -17.6008 -25.9135 63.7607 0.0000 0.0000 30.5779 13.7404 10.6715 0.0493 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.3207 -1.0880 -9.7437 -13.2513 10.9650 -67.4640 -0.0000 -0.0000 -6.0028 -5.9416 -7.8121 -6.9532 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -10.1098 -19.0750 -17.4404 -1.4897 0.0000 -0.0000 9.0671 -8.3605 23.7994 -1.2300 0.0000 -0.0000 -17.9376 -23.7517 16.5782 66.6341 0.0000 0.0000 -19.2272 -2.4216 0.9734 -10.2229 0.0000 -0.0000 3.5431 -48.9185 24.2028 -1.9263 -12.0071 -178.9420 -1.7013 -5.0551 -0.0909 -1.5256 -1.3279 -0.3714 8.8937 -8.8472 -0.3545 -2.4527 -4.1296 2.1421 -16.1319 -9.6593 -4.0835 4.2908 -3.0682 -3.3459 -6.6119 -2.3146 4.9665 -16.5330 -25.4009 63.9559 0.0000 0.0000 29.1794 12.7388 10.3726 0.1879 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -4.8509 -1.5187 -9.4171 -13.5029 7.7579 -67.8484 -0.0000 -0.0000 -6.3597 -3.8960 -6.8065 -7.2543 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.1302 -18.5973 -18.8586 -0.6072 0.0000 -0.0000 7.0153 -7.8305 24.6226 -1.2853 0.0000 -0.0000 -21.2577 -23.8981 15.1798 65.0382 0.0000 0.0000 -19.9808 -1.1715 2.1703 -8.9589 0.0000 -0.0000 3.4893 -48.3876 24.2732 -1.2610 -11.6544 -178.3475 -1.4999 -5.3926 -0.1737 -1.4121 -1.3214 -0.3774 8.9978 -8.7853 -0.2889 -2.2557 -3.9844 2.1150 -15.3348 -9.2579 -3.9509 4.1634 -3.5084 -3.6823 -6.4952 -1.7920 4.9038 -14.8743 -24.0394 64.2716 0.0000 0.0000 27.3140 11.4677 8.9331 0.4859 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -5.2968 -1.8816 -8.6177 -13.7529 5.5866 -68.8516 -0.0000 -0.0000 -6.6718 -1.5457 -6.1495 -7.5098 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -6.3577 -18.0671 -18.8193 0.0630 0.0000 0.0000 5.2897 -7.8666 24.6359 -1.2806 0.0000 -0.0000 -24.2843 -23.7228 14.5564 61.5062 0.0000 0.0000 -19.9968 -1.2825 4.2490 -8.0504 0.0000 -0.0000 3.4319 -47.8926 24.3225 -0.9060 -11.2703 -178.3072 -1.3314 -5.5973 -0.1936 -1.3179 -1.4127 -0.3742 9.1066 -8.5744 0.2027 -2.1061 -3.8837 2.1934 -14.9395 -8.8919 -4.0540 3.5675 -4.3968 -4.3442 -6.2725 -1.1821 5.0171 -12.9046 -22.2377 64.5334 0.0000 0.0000 24.8059 9.4629 6.9542 0.8813 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -5.8701 -2.4920 -7.7955 -14.2727 6.1461 -70.1012 -0.0000 -0.0000 -6.8904 -1.9783 -5.6427 -7.8584 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -4.6859 -17.5966 -18.2098 0.2919 0.0000 0.0000 3.9354 -8.0254 24.6546 -1.1635 0.0000 -0.0000 -26.8636 -23.3217 14.6137 56.1969 0.0000 0.0000 -19.2464 -2.4232 5.1033 -7.3097 0.0000 -0.0000 3.3727 -47.4181 24.3567 -0.7009 -10.8736 -178.3562 -1.1452 -5.6691 -0.2095 -1.1873 -1.4311 -0.3398 9.1615 -8.2815 0.8014 -2.0374 -3.9128 2.3402 -14.8993 -8.9678 -4.6106 2.8242 -5.4822 -5.3866 -6.1360 -0.6096 5.2259 -10.5920 -20.9961 64.6298 0.0000 0.0000 21.7104 6.8357 4.4568 0.8753 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.4629 -3.0137 -7.4491 -14.8966 7.4641 -71.1207 -0.0000 -0.0000 -7.2942 -3.3567 -5.0454 -8.1614 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -3.1080 -17.2178 -17.5758 0.2391 0.0000 0.0000 2.5091 -7.5507 24.4977 -0.8937 0.0000 -0.0000 -28.9365 -22.2531 13.8975 49.2834 0.0000 0.0000 -18.2239 -2.0471 3.6498 -8.0937 0.0000 -0.0000 3.2922 -46.9524 24.3804 -0.6974 -10.5166 -178.5179 -0.9415 -5.6121 -0.2304 -1.0717 -1.4165 -0.3085 9.1449 -8.1681 1.4208 -2.0639 -4.0371 2.5474 -15.0961 -9.2345 -5.4008 2.2027 -6.4967 -6.5604 -6.1324 0.1967 5.4526 -7.7026 -20.6153 64.8746 0.0000 0.0000 17.8753 3.5854 1.2926 0.6225 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.8040 -3.2106 -7.4401 -15.5235 7.7108 -71.7667 -0.0000 -0.0000 -8.1138 -3.1721 -4.5593 -8.3410 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -1.8322 -16.8138 -16.6817 0.3463 0.0000 0.0000 0.9980 -6.8647 24.1032 -0.5535 0.0000 -0.0000 -30.3849 -20.3530 11.7069 40.9295 0.0000 0.0000 -16.8680 0.2140 0.8641 -11.1028 0.0000 -0.0000 3.1824 -46.4857 24.3898 -0.9755 -10.2928 -179.0955 -0.8181 -5.5446 -0.2704 -0.9964 -1.3967 -0.2796 9.1300 -8.3542 2.1738 -2.1059 -4.2353 2.8616 -15.4144 -9.3137 -6.0604 1.8203 -7.2162 -7.5115 -6.3647 1.3143 5.7395 -4.1375 -20.8397 65.4776 0.0000 0.0000 13.2674 0.2601 -2.7870 0.4589 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -7.0917 -3.4091 -7.5168 -15.8853 7.0520 -72.0865 -0.0000 -0.0000 -8.9377 -2.0949 -4.1534 -8.5329 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.9388 -16.3466 -15.3862 0.8239 0.0000 0.0000 -0.4636 -6.6149 23.8522 -0.1929 0.0000 -0.0000 -31.2315 -18.1398 8.7352 31.7743 0.0000 0.0000 -15.0568 1.7207 -1.7947 -12.7517 0.0000 -0.0000 3.0547 -45.9877 24.3829 -1.2080 -10.1246 -179.8926 -0.6620 -5.5329 -0.3344 -0.9149 -1.2445 -0.2356 9.1448 -8.6472 2.9437 -2.1259 -4.4917 3.2033 -15.6672 -9.2421 -6.4646 1.7487 -7.6184 -8.0952 -6.5658 2.0217 6.1528 -0.4559 -21.1234 66.1647 0.0000 0.0000 8.6422 -1.3516 -7.6297 0.0505 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -7.5837 -3.8232 -7.7491 -15.9362 6.1982 -72.2351 -0.0000 -0.0000 -9.1224 -1.6888 -3.4924 -8.6744 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.1152 -15.8433 -14.1978 1.3240 0.0000 0.0000 -2.0410 -6.4975 23.9787 0.1492 0.0000 0.0000 -31.4361 -16.0616 6.1480 22.8280 0.0000 0.0000 -13.1788 2.1601 -3.7467 -11.2065 0.0000 -0.0000 2.9242 -45.4327 24.3610 -1.2906 -9.9820 179.3900 -0.4950 -5.5897 -0.4150 -0.8112 -0.9600 -0.1877 9.1060 -8.8674 3.4910 -2.1278 -4.6985 3.4385 -15.7037 -9.0919 -6.6189 1.9937 -7.8797 -8.3985 -6.3310 1.9667 6.6634 2.8967 -21.3288 66.5038 0.0000 0.0000 5.3066 0.0737 -11.8207 -0.6527 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -8.2083 -4.3182 -8.0812 -16.0063 5.7825 -72.4008 -0.0000 -0.0000 -8.6750 -1.6217 -2.5467 -8.5167 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 1.5616 -15.3973 -13.5129 1.5588 0.0000 0.0000 -3.7674 -6.0251 24.3478 0.3242 0.0000 0.0000 -31.3236 -14.2407 4.6420 15.0340 0.0000 0.0000 -10.7002 3.5977 -4.7588 -9.4824 0.0000 -0.0000 2.7953 -44.8298 24.3238 -1.5733 -9.9376 178.5120 -0.4706 -5.6685 -0.5154 -0.7809 -0.7877 -0.1731 8.9979 -9.0157 3.8759 -2.1093 -4.7118 3.5150 -15.5827 -8.6994 -6.4219 2.3707 -8.0995 -8.5017 -5.5803 1.4536 7.3793 5.8881 -21.5263 66.4466 0.0000 0.0000 3.6682 3.1720 -14.3641 -0.9852 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -8.7738 -4.6662 -8.0977 -16.2770 5.8231 -72.6974 -0.0000 -0.0000 -8.0899 -1.2361 -1.7602 -8.1871 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 2.8872 -15.0219 -12.9534 1.8358 0.0000 0.0000 -5.4283 -5.4727 24.8240 0.2473 0.0000 0.0000 -31.4917 -12.7269 3.9988 9.0819 0.0000 0.0000 -6.7919 5.7118 -4.2651 -9.4201 0.0000 -0.0000 2.6713 -44.1893 24.2661 -2.1964 -9.8852 177.2465 -0.6038 -5.5851 -0.6557 -0.8533 -0.7859 -0.1794 8.8963 -9.1400 4.2104 -2.1044 -4.5456 3.4894 -15.4835 -8.0005 -5.8950 2.6639 -8.2127 -8.4366 -4.5813 0.5226 8.3972 8.3160 -21.9045 66.1062 0.0000 0.0000 2.9395 5.2412 -15.8068 -0.7529 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -9.1729 -4.6887 -7.6699 -16.5677 5.4910 -73.1511 -0.0000 -0.0000 -7.5371 -1.3431 -1.3441 -8.0700 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 3.8217 -14.5390 -12.0052 2.4661 0.0000 0.0000 -7.1936 -5.1210 25.2955 0.1327 0.0000 0.0000 -32.1210 -11.5699 3.7764 5.4071 0.0000 0.0000 -2.1517 6.9519 -2.3815 -9.6013 0.0000 -0.0000 2.5645 -43.4726 24.1829 -2.7417 -9.6132 175.8697 -0.8032 -5.2657 -0.7820 -0.9511 -0.7130 -0.1602 8.8651 -9.0460 4.4017 -2.1541 -4.3463 3.3912 -15.4760 -7.2573 -5.3955 2.8570 -8.1851 -8.2949 -3.5847 -0.8233 9.3297 10.2126 -22.7148 65.7594 0.0000 0.0000 2.4801 5.0888 -16.6301 -0.4463 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -9.3359 -4.4740 -7.2848 -16.7635 4.7290 -73.6706 -0.0000 -0.0000 -6.9053 -2.3936 -1.2640 -8.0423 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 5.0007 -13.8181 -10.8186 3.1749 0.0000 0.0000 -9.4878 -4.5891 25.6599 0.2715 0.0000 0.0000 -32.5805 -10.7413 4.0743 4.1973 0.0000 0.0000 1.3312 7.4850 -0.7795 -9.3473 0.0000 -0.0000 2.4870 -42.6301 24.0685 -3.0566 -9.3031 174.3093 -1.1862 -4.9868 -0.8320 -1.0821 -0.5740 -0.1208 8.8796 -8.5243 4.5449 -2.1634 -4.1232 3.2383 -15.5028 -6.6669 -5.0568 2.9455 -8.0803 -8.1802 -2.7044 -1.7512 9.7103 12.4447 -23.8737 66.1394 0.0000 0.0000 2.4882 3.6148 -16.4242 -0.4882 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -9.3227 -4.3343 -7.1270 -16.6528 4.5616 -74.1478 -0.0000 -0.0000 -6.4081 -2.8629 -1.7515 -7.7662 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 6.7614 -13.0164 -9.8257 3.8480 0.0000 0.0000 -12.1065 -3.9141 26.2872 0.6859 0.0000 0.0000 -31.8406 -10.4776 4.6821 4.3731 0.0000 0.0000 3.1997 7.2815 -0.7788 -9.8091 0.0000 -0.0000 2.4234 -41.6854 23.9153 -3.8045 -9.0710 171.9916 -2.0237 -4.7381 -0.9663 -1.4814 -0.6129 -0.1116 8.8745 -7.9313 4.9082 -2.0581 -3.7146 3.0612 -15.5765 -6.1122 -4.4520 2.7363 -7.9476 -7.9693 -2.0740 -1.8280 9.6116 15.6464 -24.3347 68.0884 0.0000 0.0000 2.8971 2.3762 -15.6296 -0.6956 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -9.3117 -3.9035 -6.4656 -15.5019 3.7665 -74.8222 -0.0000 -0.0000 -6.3389 -1.2297 -3.0731 -7.5934 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 7.9568 -11.9986 -8.9046 5.3562 0.0000 0.0000 -14.7339 -4.0598 27.5696 1.2042 0.0000 0.0000 -29.7571 -10.7436 4.9393 3.7384 0.0000 0.0000 5.7744 5.4642 -1.5350 -11.0246 0.0000 -0.0000 2.3106 -40.6777 23.7495 -4.8109 -7.4350 169.4394 -3.2034 -3.0143 -1.3052 -2.2781 -0.5495 -0.0892 8.9535 -7.8284 5.0027 -1.9855 -3.1387 2.7719 -15.7639 -5.6150 -3.4159 2.2233 -7.7704 -7.4177 -1.8589 -2.4677 9.1604 18.9664 -22.7784 71.5020 0.0000 0.0000 2.8738 2.1110 -15.6159 -0.8105 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -9.1491 -1.8723 -4.7639 -12.9213 -1.3257 -76.1687 -0.0000 -0.0000 -6.4492 2.0897 -5.5346 -7.8907 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 7.8468 -9.1061 -8.0236 8.5412 0.0000 0.0000 -17.9811 -5.3168 28.9911 1.5952 0.0000 0.0000 -26.7594 -9.4608 4.1900 1.2851 0.0000 0.0000 10.5558 2.3439 -0.6050 -10.9339 0.0000 -0.0000 2.0879 -39.5491 23.6503 -3.9449 -2.5271 168.4015 -4.0091 1.4176 -1.4567 -3.1182 0.4882 0.1001 9.2908 -7.4800 3.9088 -2.0524 -2.6051 2.2028 -15.7429 -5.6485 -2.8106 1.9379 -7.4034 -6.6292 -2.0950 -4.6308 7.9947 21.5050 -20.3102 75.3015 0.0000 0.0000 2.3423 2.5647 -16.0131 -0.8956 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.2585 1.6666 -3.1519 -9.7000 -9.7787 -77.6539 -0.0000 -0.0000 -6.3112 6.0358 -9.6415 -7.9280 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 8.2335 -2.2691 -8.2959 13.1146 0.0000 0.0000 -21.9193 -6.7379 29.9141 1.2124 0.0000 0.0000 -22.2718 -3.8026 2.7053 -2.0326 0.0000 -0.0000 15.2573 -0.5749 2.5537 -8.4696 0.0000 -0.0000 1.7801 -38.3156 23.6920 -0.9275 4.0493 168.7854 -4.2447 5.3598 -1.0084 -3.4006 2.2379 0.4713 9.5470 -4.1255 2.2593 -2.0193 -2.1733 1.4220 -14.9838 -6.4233 -3.5185 2.3542 -6.5731 -6.0990 -2.7192 -6.0290 5.9939 24.0050 -20.4154 78.9847 0.0000 0.0000 2.2594 2.8590 -14.8923 -0.9740 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.2732 3.7151 -3.5048 -5.8717 -13.9343 -78.2763 -0.0000 -0.0000 -5.4406 9.6317 -13.9684 -7.2413 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 9.7435 6.9394 -9.9133 19.4097 0.0000 0.0000 -23.6834 -7.7832 30.6553 -0.6698 0.0000 -0.0000 -17.0951 4.6174 1.2630 -3.3823 0.0000 -0.0000 15.6221 -2.3452 5.6440 -5.6402 0.0000 -0.0000 1.5039 -37.2090 23.8703 1.2570 7.7579 168.7112 -4.5761 5.4664 -0.4587 -3.3048 2.5685 0.6355 9.3640 1.0508 2.0331 -1.6109 -1.2108 0.7592 -13.9463 -6.3442 -4.5387 3.0869 -5.4037 -6.0037 -3.5494 -3.4733 4.3498 26.9669 -24.0010 82.6182 0.0000 0.0000 3.0602 1.8876 -13.2365 -0.7404 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.0985 3.1267 -5.5329 -0.7767 -10.1721 -78.2750 -0.0000 -0.0000 -3.2097 11.2387 -14.8944 -7.6885 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 7.9438 13.1735 -8.2096 29.4967 0.0000 0.0000 -19.3460 -8.9699 30.5732 -3.7200 0.0000 -0.0000 -13.6891 9.8720 1.1332 -1.8342 0.0000 -0.0000 11.6587 -2.9407 6.5724 -4.8138 0.0000 -0.0000 1.3019 -36.3221 24.0559 2.5104 8.0935 166.8422 -4.3254 3.7324 -0.1598 -2.9789 1.6249 0.5211 8.6521 3.9811 3.3972 -1.1285 0.2171 0.4332 -13.1774 -4.1593 -4.1390 3.3500 -4.1235 -5.6487 -4.6363 2.2947 4.4804 28.9493 -28.0998 85.6576 0.0000 0.0000 4.3055 -0.4215 -14.2618 -0.2867 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.7830 1.7039 -7.5607 5.0197 -3.8624 -78.2698 -0.0000 0.0000 0.6242 10.7047 -9.3240 -9.8619 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 1.1668 15.2286 -1.2981 43.1947 0.0000 0.0000 -8.4398 -12.5363 29.7681 -5.3363 0.0000 -0.0000 -10.9452 11.1233 3.7285 -0.5288 0.0000 -0.0000 7.8897 -3.7335 5.3446 -5.3824 0.0000 -0.0000 1.1212 -35.5910 24.1231 3.6855 8.6270 164.2401 -3.5887 3.8300 0.0569 -2.5632 0.9696 0.4154 7.8854 4.6512 4.3960 -0.9619 1.1052 0.2287 -12.6516 -1.4889 -2.4690 3.0233 -2.7831 -4.2572 -6.2656 6.6082 5.5588 28.0422 -29.2413 87.1052 0.0000 0.0000 5.6078 -2.2039 -17.0877 -0.0998 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -2.2737 0.3293 -8.8231 10.6428 -0.9197 -78.3664 -0.0000 0.0000 4.7939 11.9520 1.4311 -10.8335 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.5666 16.1671 6.3236 56.4424 0.0000 0.0000 2.1522 -16.9954 28.4187 -4.7671 0.0000 -0.0000 -8.2839 12.5908 7.1284 -0.7663 0.0000 -0.0000 6.0711 -5.3269 4.0275 -5.2656 0.0000 -0.0000 0.9819 -34.8873 24.1125 5.3140 10.1318 163.3673 -2.9684 5.8668 0.1615 -2.2650 1.3499 0.4091 7.9859 4.5221 3.3976 -0.9388 1.2696 -0.1756 -12.2798 -0.4623 -0.7811 2.8065 -1.7016 -2.2385 -7.6976 6.6712 5.8401 24.2962 -27.4449 86.8649 0.0000 0.0000 7.5773 -1.5374 -16.4021 -0.0178 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.0621 -0.7569 -9.3475 15.1314 -0.9695 -78.3235 -0.0000 0.0000 7.2929 15.2308 10.8480 -10.7962 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -14.4077 17.4422 10.8685 66.2275 0.0000 0.0000 4.0711 -18.2000 23.6335 -4.9555 0.0000 -0.0000 -4.9346 15.4569 8.0314 -2.0098 0.0000 -0.0000 4.8428 -6.6610 3.5125 -4.6010 0.0000 -0.0000 0.9188 -34.2128 24.1107 6.2549 11.1905 164.9176 -3.0671 7.6318 0.2409 -2.2740 2.1911 0.4398 9.0425 4.4425 1.0373 -0.7594 1.2434 -0.8553 -11.9580 -1.1837 0.1710 3.2992 -1.3913 -0.8322 -8.3488 4.7155 5.2769 19.7427 -27.4227 85.1816 0.0000 0.0000 11.2396 0.9203 -9.7969 -0.1580 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -1.5143 -0.8526 -9.1689 16.8831 -0.1508 -78.3113 -0.0000 0.0000 7.8761 16.6635 13.7586 -10.1476 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -19.1813 18.1381 11.4190 71.6120 0.0000 0.0000 -1.5974 -14.1144 14.6327 -5.3504 0.0000 -0.0000 -1.8428 17.5390 6.7953 -2.7175 0.0000 -0.0000 3.1155 -6.5702 2.5624 -5.0830 0.0000 -0.0000 0.9227 -33.6008 24.1566 6.3075 10.9012 167.5283 -3.3597 8.1672 0.2595 -2.3860 2.5229 0.4164 10.1437 4.5757 -0.7821 -0.4181 1.4204 -1.4956 -11.5553 -2.3725 0.3038 4.1618 -1.9692 -0.6975 -8.8044 4.1919 4.8820 15.6802 -32.5324 81.4613 0.0000 0.0000 16.4284 1.8105 -2.0982 -0.3350 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.7408 0.1194 -8.7354 16.2418 3.0555 -78.6396 -0.0000 0.0000 7.2144 14.8807 10.3375 -9.2627 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -22.6175 17.3807 9.7215 72.1616 0.0000 0.0000 -6.9550 -7.0109 5.4993 -4.0668 0.0000 -0.0000 0.2767 17.6560 6.4067 -2.1779 0.0000 -0.0000 1.1805 -5.5898 -0.1107 -6.5321 0.0000 -0.0000 0.9676 -33.0556 24.2389 5.9881 9.7205 169.8972 -3.3976 8.0804 0.2367 -2.3837 2.3091 0.3427 10.6664 4.6450 -1.3783 -0.0851 1.5919 -1.7666 -11.0485 -3.1009 -0.1347 4.6172 -2.8812 -1.4307 -9.1529 4.9464 4.6778 10.9297 -37.5511 76.1346 0.0000 0.0000 20.7923 -0.1673 2.7416 0.2967 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.2347 1.3328 -8.5979 15.2219 6.9051 -79.3902 -0.0000 0.0000 5.9995 11.4287 5.4147 -9.6410 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -25.3423 15.6037 8.0137 68.5021 0.0000 0.0000 -9.0917 -2.0169 -0.5285 -2.2237 0.0000 -0.0000 1.4099 16.5039 7.7847 -0.7599 0.0000 -0.0000 -0.7342 -5.2586 -3.8991 -7.0588 0.0000 -0.0000 1.0331 -32.5584 24.3262 5.4858 8.4645 171.9107 -3.3288 8.0345 0.2228 -2.3272 2.1656 0.3134 10.8807 4.3536 -1.4489 0.1652 1.4934 -1.7018 -10.6111 -3.2922 -0.8798 4.4863 -3.2889 -2.3573 -8.9264 5.0042 4.0912 5.1828 -36.7301 71.6335 0.0000 0.0000 22.4669 -1.5688 5.7593 0.5130 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0023 1.7390 -8.7837 14.6795 9.8140 -80.4749 -0.0000 0.0000 4.8873 9.0258 2.6310 -10.1870 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -27.3722 13.9338 6.5003 61.3751 0.0000 0.0000 -9.7165 -0.1733 -3.0099 -1.1861 0.0000 -0.0000 1.9632 15.0544 8.8361 0.8238 0.0000 0.0000 -2.8558 -5.8441 -6.8397 -6.1470 0.0000 -0.0000 1.0892 -32.0805 24.3842 4.9547 7.6112 173.7171 -3.2482 8.1544 0.1682 -2.2381 2.2369 0.3202 11.0685 3.8487 -1.5792 0.3401 1.3268 -1.5700 -10.4423 -2.9146 -1.6846 4.1352 -2.8492 -3.2420 -8.4199 4.4913 3.3247 0.0162 -32.1313 69.2650 0.0000 0.0000 22.3939 -0.4864 8.1974 -0.1706 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0489 1.0682 -9.0744 14.4448 11.6047 -81.3948 -0.0000 0.0000 4.1718 9.0208 1.6442 -9.8287 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -28.5987 13.2077 4.5616 51.6205 0.0000 0.0000 -8.6611 -0.5889 -2.3727 -0.5418 0.0000 -0.0000 2.5188 13.9718 8.3810 1.9887 0.0000 0.0000 -4.6832 -5.9656 -8.2482 -5.3681 0.0000 -0.0000 1.1056 -31.6010 24.3996 4.6830 7.2701 174.9610 -2.9274 8.1993 0.0970 -2.0678 2.2471 0.3015 11.1408 3.5556 -1.6731 0.3671 1.4344 -1.5606 -10.4583 -1.7985 -2.2835 3.8011 -1.8304 -4.1104 -8.1153 4.3104 2.8635 -4.1247 -28.6950 67.8629 0.0000 0.0000 22.3660 0.3342 9.9841 -0.5711 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0710 0.1840 -9.0836 14.4039 11.9911 -81.9522 -0.0000 0.0000 4.1899 10.4334 1.7169 -9.1514 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -29.1313 13.3602 1.9200 40.4009 0.0000 0.0000 -4.2720 -2.4566 0.9933 0.2280 0.0000 0.0000 3.5345 13.5552 7.2672 2.4694 0.0000 0.0000 -5.7518 -5.1489 -8.6592 -5.6057 0.0000 -0.0000 1.0808 -31.1100 24.3810 4.5844 7.3623 175.3203 -2.4633 8.0276 0.0882 -1.8643 2.0809 0.2619 10.9773 3.6908 -1.4483 0.2299 1.8348 -1.6248 -10.4223 -0.0457 -2.5259 3.4823 -0.6989 -4.8257 -8.1297 4.3236 2.7506 -7.4965 -28.0901 66.4382 0.0000 0.0000 23.2546 -0.7677 10.6879 -0.2105 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.3206 -0.1553 -8.6209 14.7303 11.1857 -82.4486 -0.0000 0.0000 5.1690 11.6534 2.2980 -8.5782 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -29.2379 13.7129 -1.9269 28.4668 0.0000 0.0000 3.9555 -3.6080 6.7631 0.2448 0.0000 0.0000 4.8509 13.7824 6.3509 2.3995 0.0000 0.0000 -6.6937 -4.7273 -8.4543 -5.7244 0.0000 -0.0000 1.0460 -30.5802 24.3333 4.6921 7.8786 175.1192 -2.0166 8.0648 0.1086 -1.6010 1.7746 0.2229 10.5940 4.0964 -0.9386 0.0765 2.3165 -1.6720 -10.1743 1.8621 -2.4168 3.2455 0.1805 -5.0966 -8.3350 4.4227 2.8468 -10.0880 -28.8414 64.8862 0.0000 0.0000 24.8776 -1.8223 10.3528 0.1495 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.5737 -0.4053 -7.9543 15.4159 10.6643 -82.9768 -0.0000 0.0000 6.5841 12.2686 2.8605 -7.8314 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -28.9319 13.6729 -7.4503 16.9182 0.0000 0.0000 13.1510 -2.2806 13.6790 -1.3915 0.0000 -0.0000 6.4401 14.5548 5.6005 2.1910 0.0000 0.0000 -8.2619 -5.4018 -8.0297 -4.4673 0.0000 -0.0000 1.0319 -30.0233 24.2632 4.8847 8.6807 174.9544 -1.7227 8.5721 0.1523 -1.3253 1.4123 0.1920 10.2643 4.5461 -0.4835 0.0320 2.7490 -1.7198 -9.9174 3.2546 -2.0420 3.2027 0.6885 -4.8322 -8.6414 4.8162 3.0586 -11.8175 -29.4727 63.3175 0.0000 0.0000 26.6731 -1.0494 9.6036 0.1053 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.7281 -1.0171 -7.4779 16.0934 11.0674 -83.2073 -0.0000 0.0000 7.5956 12.5448 3.3407 -7.0004 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -29.2006 12.9396 -12.0080 8.4464 0.0000 0.0000 17.8793 -0.8823 18.1380 -3.7180 0.0000 -0.0000 7.8595 15.4870 5.5307 2.6642 0.0000 0.0000 -10.3839 -5.5511 -8.5724 -2.4255 0.0000 -0.0000 1.0453 -29.4828 24.2012 4.8830 9.0521 175.2044 -1.5122 8.7885 0.1614 -1.1568 1.1287 0.1660 10.2061 4.9838 -0.2801 0.0248 3.0923 -1.8105 -9.8826 3.8347 -1.5474 3.3683 0.9004 -4.2498 -8.8947 5.1868 3.2527 -12.9099 -29.3901 61.9759 0.0000 0.0000 28.0111 0.2165 8.7855 0.1861 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.8117 -1.3774 -7.3002 16.4783 11.5624 -82.9676 -0.0000 0.0000 7.9827 12.6457 4.0311 -6.5741 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -30.3634 11.6578 -13.3437 4.0078 0.0000 0.0000 16.2441 -2.1788 17.6794 -4.8568 0.0000 -0.0000 8.5960 15.6904 6.7049 4.2289 0.0000 0.0000 -12.5323 -3.9386 -10.5958 -1.4319 0.0000 -0.0000 1.0812 -28.9422 24.1571 4.6717 8.6639 176.0131 -1.2726 8.4771 0.0151 -1.0021 0.9583 0.1402 10.1208 5.1425 -0.2742 -0.0166 3.2483 -1.8776 -9.8026 3.9482 -1.1050 3.7935 1.0351 -3.6440 -8.9926 5.5603 3.3324 -13.5166 -29.1399 60.9303 0.0000 0.0000 28.5778 0.2027 7.7710 0.6796 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.7702 -1.2664 -7.3141 16.7927 12.0693 -82.7065 -0.0000 0.0000 8.0974 12.5453 4.6342 -6.4831 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -31.8260 10.1492 -13.9787 2.8186 0.0000 0.0000 11.4341 -3.8659 14.1406 -3.8814 0.0000 -0.0000 9.0699 14.9199 7.8889 6.0670 0.0000 0.0000 -14.2375 -2.2227 -12.5895 -2.5467 0.0000 -0.0000 1.1294 -28.3795 24.1351 4.1674 7.7215 177.3602 -1.1634 7.8010 -0.2383 -0.9324 0.9416 0.1209 9.9858 4.8754 -0.4654 -0.0342 3.2039 -1.8867 -9.6568 4.0839 -0.8294 4.4030 1.4159 -3.1614 -8.9175 5.7166 3.2043 -13.8036 -28.7922 60.4230 0.0000 0.0000 28.3551 -0.7146 6.5138 1.2244 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.4802 -1.1193 -7.4116 17.2280 12.8129 -82.7966 -0.0000 0.0000 8.0830 11.8915 4.5767 -6.3045 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -33.3294 8.6583 -16.0316 3.9827 0.0000 0.0000 8.6047 -4.1937 9.7466 -2.3253 0.0000 -0.0000 9.5169 13.5191 8.2571 7.4426 0.0000 0.0000 -15.5130 -2.0580 -13.6748 -4.6741 0.0000 -0.0000 1.1790 -27.7984 24.1276 3.2115 6.7468 179.0896 -1.4325 7.0262 -0.3793 -1.0987 1.0640 0.1207 10.0868 4.4123 -0.9348 0.0021 3.0922 -1.9052 -9.7428 4.5638 -0.7312 5.0424 2.3049 -2.8304 -8.7906 5.3025 2.8945 -13.8995 -28.0674 60.5431 0.0000 0.0000 27.6410 -1.3031 5.3142 1.4599 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0583 -1.2585 -7.6589 17.7444 13.6335 -83.0638 -0.0000 0.0000 7.8682 10.5670 4.1811 -6.0785 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -34.6416 7.4415 -19.1254 5.9159 0.0000 0.0000 9.8585 -4.0924 5.0775 -2.0592 0.0000 -0.0000 9.5910 11.9758 8.3460 8.5847 0.0000 0.0000 -16.5093 -2.5055 -14.6985 -6.1793 0.0000 -0.0000 1.2250 -27.1904 24.1116 1.9267 5.9947 -179.2488 -2.0306 6.2917 -0.3009 -1.4280 1.1284 0.1147 10.3536 4.0083 -1.4512 -0.0068 3.0902 -1.9618 -10.0573 5.6904 -0.6295 5.6856 3.7484 -2.6298 -8.7446 4.3959 2.6587 -13.7835 -27.1580 60.8903 0.0000 0.0000 26.9787 -1.3186 4.2679 1.3702 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.1116 -1.4071 -8.1402 18.3310 14.9251 -83.2144 -0.0000 0.0000 7.7680 9.7508 4.3295 -6.1141 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -35.4311 6.3255 -21.7479 7.3978 0.0000 0.0000 12.7309 -4.2160 1.1130 -2.8090 0.0000 -0.0000 9.3536 10.5731 8.6408 9.7398 0.0000 0.0000 -17.4525 -1.9277 -16.2136 -6.8275 0.0000 -0.0000 1.2633 -26.5239 24.0688 0.6237 5.2163 -178.0091 -2.7617 5.4018 -0.2300 -1.7439 0.9303 0.0743 10.4911 3.6719 -1.6499 -0.1170 3.2795 -2.0337 -10.4072 7.7923 -0.2404 6.3463 5.5903 -2.4491 -8.7496 3.3753 2.7764 -13.3909 -26.2546 61.0612 0.0000 0.0000 26.7744 -1.1803 3.0966 1.1876 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.1096 -1.3217 -8.7221 19.0002 17.5614 -83.2390 -0.0000 0.0000 8.1579 10.8544 4.9839 -6.3779 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -35.2956 4.9141 -22.3463 8.6909 0.0000 0.0000 13.9837 -4.3573 -0.4096 -3.1325 0.0000 -0.0000 9.3331 9.2065 9.1892 10.7103 0.0000 0.0000 -18.5373 -0.6022 -17.8414 -7.6189 0.0000 -0.0000 1.2845 -25.7910 23.9912 -0.7462 4.4556 -176.7649 -3.6610 4.3057 -0.2264 -2.1571 0.6601 0.0183 10.6729 3.3481 -1.8400 -0.2027 3.6079 -2.1707 -11.0264 10.8182 0.4384 6.7635 7.6996 -2.1708 -8.7694 2.0860 3.1543 -12.8503 -24.6056 61.1332 0.0000 0.0000 26.8735 -1.1801 1.2757 1.2717 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.3662 -1.2368 -9.1830 19.5716 20.4312 -83.2634 -0.0000 0.0000 8.7074 12.6973 5.3686 -6.6098 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -33.9278 3.5031 -20.8578 9.8632 0.0000 0.0000 13.6541 -4.0069 1.2034 -2.1483 0.0000 -0.0000 9.4119 7.8826 9.8560 11.6545 0.0000 0.0000 -19.5671 0.5499 -19.4662 -8.8212 0.0000 -0.0000 1.2962 -25.0162 23.8828 -2.6531 3.7600 -174.7725 -5.1162 2.8570 0.1015 -3.0471 0.5935 -0.0056 11.6009 3.2893 -2.6254 -0.2004 3.9565 -2.4871 -12.3671 14.3602 1.0691 6.5907 9.9845 -1.8815 -8.9121 -0.2416 3.2975 -12.5113 -21.1179 61.3779 0.0000 0.0000 26.6688 -1.4323 -1.7557 1.7946 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.3758 -0.7662 -9.4843 19.8309 20.2579 -83.2478 -0.0000 0.0000 8.7184 12.2742 5.6341 -6.6575 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -31.3975 2.2932 -19.1193 9.2421 0.0000 0.0000 13.5756 -1.4172 4.5731 -0.2136 0.0000 -0.0000 8.6451 6.3891 10.5597 13.3218 0.0000 0.0000 -20.4817 1.7736 -21.6673 -9.4683 0.0000 -0.0000 1.3434 -24.1771 23.7807 -4.4889 1.6968 -172.4938 -6.8671 -0.1704 0.6287 -4.4126 0.1596 -0.0684 13.4583 3.9201 -3.4110 -0.3189 4.2979 -2.8657 -14.2447 18.0579 1.5779 6.0131 12.1432 -1.7739 -9.3856 -3.3654 3.0600 -12.4802 -16.6633 61.4132 0.0000 0.0000 25.9779 -1.7670 -6.0175 2.4082 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.2354 1.4477 -9.5857 19.6972 16.0444 -83.0487 -0.0000 0.0000 8.2756 9.3987 6.2699 -6.5996 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -27.3456 -0.6001 -18.7369 4.7703 0.0000 0.0000 14.3378 4.2698 6.7484 0.9957 0.0000 0.0000 7.2352 3.1044 11.8281 16.2239 0.0000 0.0000 -21.9844 3.2958 -24.6714 -9.2475 0.0000 -0.0000 1.4295 -23.2243 23.7243 -4.3659 -2.4281 -171.6645 -7.3819 -4.5384 0.5750 -5.1429 -2.0730 -0.5118 14.5822 4.8954 -2.6994 -0.7460 4.8327 -2.9464 -15.7577 21.1809 2.5393 5.5111 13.6872 -1.7461 -10.2264 -4.7297 3.2881 -12.2208 -14.9245 60.1986 0.0000 0.0000 25.3742 -1.7998 -9.9652 2.3775 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0392 4.9564 -9.2141 19.4893 11.7475 -82.9215 -0.0000 0.0000 7.8453 6.8695 6.3806 -6.3575 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -21.4583 -6.4469 -17.4290 -2.3018 0.0000 -0.0000 15.8110 8.9002 5.3961 0.7533 0.0000 0.0000 6.8855 -2.7070 14.1518 20.7681 0.0000 0.0000 -23.9604 4.0957 -27.3534 -9.9041 0.0000 -0.0000 1.5048 -22.3365 23.7563 -3.5566 -6.5036 -173.2674 -6.5616 -7.5340 0.3087 -4.5717 -4.9193 -1.0635 13.6919 4.1557 -0.5550 -1.2617 5.5035 -2.6243 -17.0407 22.5192 4.4871 4.9274 13.9497 -1.3917 -10.7444 -3.4785 4.9373 -12.0409 -16.6456 58.0003 0.0000 0.0000 25.0861 -2.0137 -11.1932 1.5448 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.5505 7.4194 -8.0169 19.2804 10.5547 -83.1921 -0.0000 0.0000 7.4200 5.5258 4.7643 -5.8703 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -17.8813 -11.8716 -13.6454 -4.8143 0.0000 -0.0000 15.6158 9.4116 2.2234 -0.0265 0.0000 -0.0000 5.3373 -8.4814 16.1400 28.8987 0.0000 0.0000 -23.4860 3.3362 -27.8658 -12.9308 0.0000 -0.0000 1.5725 -21.6095 23.8789 -2.8774 -8.6130 -175.2103 -5.0255 -8.1247 0.2746 -3.4469 -5.5132 -1.0918 12.2912 1.6485 0.6613 -1.5120 5.3452 -2.1480 -18.1017 20.6097 6.3291 4.0374 12.6476 -0.5690 -10.3670 -1.5801 7.2899 -12.5235 -19.3574 56.1786 0.0000 0.0000 24.8138 -3.0918 -9.0126 0.5815 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 1.2825 6.2709 -6.6441 19.1789 11.5724 -83.7149 -0.0000 0.0000 6.5854 3.3330 2.1403 -5.3064 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -16.8243 -14.6067 -13.9105 -2.1019 0.0000 -0.0000 12.4332 8.7227 3.6829 -0.3729 0.0000 -0.0000 0.4749 -12.5038 15.0813 41.3115 0.0000 0.0000 -16.7126 3.2238 -26.2118 -15.9859 0.0000 -0.0000 1.6443 -20.9509 24.0033 -1.7263 -8.9942 -174.8585 -3.4601 -7.3086 0.1914 -2.6177 -4.1947 -0.8416 11.4598 -0.3071 -0.1465 -1.4678 4.1639 -1.7802 -17.7633 15.5026 6.1662 3.4100 10.1425 0.2323 -9.1963 -0.5374 8.3199 -12.9803 -21.4885 55.8341 0.0000 0.0000 24.1079 -4.7803 -5.2617 -0.0974 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 1.8999 2.4776 -6.2080 19.3170 12.2393 -83.9292 -0.0000 0.0000 5.4215 0.2926 0.7145 -5.1088 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -14.7998 -15.1668 -16.9914 -0.1280 0.0000 -0.0000 9.2394 8.7498 6.9221 -0.1750 0.0000 -0.0000 -6.7104 -14.8358 10.7302 54.6964 0.0000 0.0000 -5.3607 5.7081 -23.9894 -14.0421 0.0000 -0.0000 1.7160 -20.2956 24.0981 -0.2833 -9.1861 -173.2303 -2.2368 -6.6111 0.0707 -2.1480 -2.9029 -0.6211 11.1261 -1.0113 -1.2944 -1.3750 2.7809 -1.4477 -16.1451 9.3482 4.0752 3.8174 6.8766 0.2405 -7.9823 -0.1397 7.2151 -12.3222 -23.1169 57.1750 0.0000 0.0000 22.6737 -6.0215 -2.7619 -0.6233 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 1.8302 0.5065 -6.7321 19.2663 11.3900 -83.3847 -0.0000 0.0000 4.5435 -0.7142 1.2194 -5.4837 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -11.1169 -15.8204 -17.4047 -1.2571 0.0000 -0.0000 7.6474 8.8590 6.7888 0.2564 0.0000 0.0000 -13.8967 -16.3009 5.8288 65.3591 0.0000 0.0000 2.1486 8.0735 -21.7784 -11.2641 0.0000 -0.0000 1.7306 -19.6657 24.1753 0.8098 -9.4545 -172.9959 -1.4694 -6.5483 0.0267 -1.8616 -2.4922 -0.4818 11.1404 -0.6041 -1.0261 -1.3244 1.7929 -0.9928 -14.3914 4.0308 1.5684 4.9328 3.4298 -0.6863 -7.3650 0.7277 5.4202 -10.6238 -24.7611 59.2591 0.0000 0.0000 20.5143 -6.0806 -3.1968 -0.9252 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 1.2990 1.7826 -7.3496 18.5817 10.6473 -82.2392 -0.0000 0.0000 4.0404 0.5671 1.9096 -6.2397 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.5612 -16.6217 -14.1201 -2.7052 0.0000 -0.0000 6.6844 8.1098 4.2382 0.8873 0.0000 0.0000 -19.5929 -17.2683 3.2598 72.0551 0.0000 0.0000 1.7166 7.6859 -18.1220 -12.0090 0.0000 -0.0000 1.6900 -19.0962 24.2303 1.3136 -9.6711 -174.6052 -1.1939 -7.0206 0.0766 -1.7013 -2.6628 -0.4071 11.5481 0.3276 0.3207 -1.1169 1.3215 -0.4947 -13.3090 0.3920 -0.2539 5.6811 0.6468 -1.8628 -7.1500 2.3426 4.5782 -8.9731 -25.9488 61.2137 0.0000 0.0000 18.1058 -5.1181 -5.8686 -0.6828 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.9746 3.5709 -7.5372 17.2125 11.7769 -80.8570 -0.0000 0.0000 3.3318 0.4791 1.3223 -6.9486 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -5.3367 -17.0605 -10.9878 -2.2642 0.0000 -0.0000 5.0356 7.3357 3.3995 1.4637 0.0000 0.0000 -23.8788 -18.1717 3.2308 74.7482 0.0000 0.0000 -2.5488 4.1971 -12.5648 -12.6363 0.0000 -0.0000 1.6310 -18.5607 24.2596 1.7141 -9.7034 -176.2641 -1.1200 -7.6263 0.1263 -1.6086 -2.8104 -0.3666 12.2672 1.0242 1.3760 -0.6972 1.1590 -0.1600 -12.9246 -1.4076 -1.2300 5.6878 -0.8262 -2.6484 -6.8491 3.7535 4.7029 -7.9375 -25.7046 62.7555 0.0000 0.0000 16.5985 -3.8286 -8.2583 -0.0164 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.9288 3.6858 -7.5775 15.8306 14.3240 -79.5888 -0.0000 0.0000 2.4169 -2.7282 0.1200 -7.5155 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -3.4883 -17.2156 -10.5413 -1.4039 0.0000 -0.0000 3.1500 7.7749 5.0930 1.4539 0.0000 0.0000 -27.3442 -18.6785 3.4607 73.8666 0.0000 0.0000 -4.9195 0.3477 -6.4657 -11.1523 0.0000 -0.0000 1.5618 -18.0285 24.2862 2.2009 -9.5701 -176.9059 -0.9899 -8.0284 0.0981 -1.5615 -2.8524 -0.3555 12.9277 1.1902 1.7255 -0.3299 1.1400 -0.0307 -12.8538 -1.6781 -1.6094 5.5051 -1.0973 -3.0167 -6.3671 4.0001 4.9768 -7.2118 -24.2116 63.7470 0.0000 0.0000 16.7660 -3.1480 -8.4819 0.4242 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.8224 2.9600 -7.7325 15.2178 16.3021 -78.8129 -0.0000 0.0000 1.9752 -6.0650 -0.5502 -8.0422 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -1.2885 -17.1709 -10.8059 -1.6283 0.0000 -0.0000 1.7464 8.9518 6.3539 0.8044 0.0000 0.0000 -30.0639 -18.3619 2.8508 69.7209 0.0000 0.0000 -5.1934 -1.7247 -0.9084 -9.7366 0.0000 -0.0000 1.4700 -17.5131 24.3231 2.2378 -9.2640 -177.0822 -0.9903 -8.1565 0.0421 -1.5557 -2.8962 -0.3692 13.2213 1.0551 1.8096 -0.1971 1.1929 -0.0024 -12.8511 -0.9931 -1.5972 5.6558 -0.7367 -3.2178 -6.0568 3.4275 5.1894 -6.5093 -23.3139 64.0924 0.0000 0.0000 17.7892 -3.4243 -7.3556 0.4498 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.6053 2.6978 -7.8722 15.3672 16.6257 -78.6982 -0.0000 0.0000 2.1714 -6.5023 -0.6513 -8.4044 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.3254 -16.7606 -9.6755 -1.9545 0.0000 -0.0000 0.6455 9.6111 5.6324 0.0836 0.0000 0.0000 -31.9000 -17.4973 2.3853 62.3972 0.0000 0.0000 -5.1236 -2.8182 2.9619 -9.0992 0.0000 -0.0000 1.3669 -17.0041 24.3575 2.0014 -8.8474 -177.2557 -1.0066 -8.1771 0.0067 -1.5402 -2.8760 -0.3775 13.2170 0.9140 1.8428 -0.1733 1.2791 -0.0264 -12.8672 -0.0911 -1.4227 5.9517 -0.2031 -3.3717 -6.0761 3.0795 5.5113 -5.8984 -24.1819 64.0560 0.0000 0.0000 18.1711 -4.2100 -6.8442 0.4790 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.4386 2.5597 -7.9072 15.8196 15.8985 -79.0112 -0.0000 0.0000 2.5588 -4.7839 -0.6936 -8.5907 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 1.2469 -16.0637 -8.4737 -1.3599 0.0000 -0.0000 -0.8667 9.5340 4.8920 -0.1725 0.0000 -0.0000 -32.4627 -16.7410 2.9588 52.5227 0.0000 0.0000 -4.5669 -3.5244 3.3017 -8.3190 0.0000 -0.0000 1.2781 -16.4809 24.3698 1.7539 -8.6496 -177.2132 -1.1012 -8.3480 -0.0798 -1.5685 -2.7735 -0.3897 13.2572 0.8233 1.7120 -0.0970 1.3888 -0.1026 -12.9494 0.5056 -1.3316 5.9310 0.2247 -3.5310 -6.1421 3.1435 5.8661 -5.4500 -25.4212 64.0729 0.0000 0.0000 17.5248 -4.8229 -7.3482 0.5580 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.2513 2.0916 -7.9955 16.2439 15.0004 -79.3382 -0.0000 0.0000 2.8588 -3.1054 -0.5769 -8.6721 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 1.8947 -15.6000 -8.8193 -0.1822 0.0000 -0.0000 -2.9006 9.2976 5.5481 -0.0108 0.0000 -0.0000 -32.1820 -16.3151 4.4715 41.3445 0.0000 0.0000 -2.9683 -3.4158 -0.7502 -7.5787 0.0000 -0.0000 1.1932 -15.9298 24.3613 1.5113 -8.7348 -176.8478 -1.3316 -8.6717 -0.2761 -1.6731 -2.6395 -0.4120 13.4377 0.7216 1.4412 -0.0068 1.5006 -0.2122 -13.1038 0.7327 -1.4109 5.6569 0.3348 -3.7748 -6.0150 3.1186 6.0802 -4.8549 -25.0280 64.2271 0.0000 0.0000 16.7494 -5.0699 -7.9619 0.4406 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0250 1.8878 -8.1373 16.4967 13.9930 -79.5132 -0.0000 0.0000 3.1053 -1.8899 -0.1864 -8.7026 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 2.4929 -15.4420 -9.7035 1.0401 0.0000 0.0000 -5.0487 9.2222 6.3314 0.1486 0.0000 0.0000 -31.4911 -15.7725 6.6704 29.6800 0.0000 0.0000 -0.0705 -1.4543 -7.5609 -7.4896 0.0000 -0.0000 1.0798 -15.3379 24.3350 1.2308 -8.7939 -176.4892 -1.5827 -9.0273 -0.5026 -1.7597 -2.3640 -0.4122 13.4716 0.6451 1.2124 0.0079 1.5405 -0.2981 -13.2170 0.6486 -1.6128 5.5852 0.0973 -4.1203 -5.7078 2.9466 6.1351 -3.9957 -23.3994 64.2867 0.0000 0.0000 16.3867 -5.2955 -8.1088 0.1679 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0096 2.2405 -8.1749 16.6159 12.8003 -79.6683 -0.0000 0.0000 3.2668 -0.7245 -0.0632 -8.6262 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 3.0711 -15.1895 -9.6614 2.3877 0.0000 0.0000 -7.1874 9.2627 6.0381 0.0362 0.0000 0.0000 -30.4044 -14.6147 9.0092 18.2202 0.0000 0.0000 4.3887 3.4995 -13.7847 -8.0093 0.0000 -0.0000 0.9310 -14.6933 24.2887 1.0248 -8.6296 -176.3664 -1.6896 -9.2790 -0.6704 -1.7433 -1.9276 -0.3768 13.2099 0.6213 1.0968 -0.0464 1.4761 -0.3225 -13.2684 0.2596 -1.8855 5.8520 -0.3193 -4.4348 -5.4330 3.0274 6.1001 -3.1909 -22.6277 64.2178 0.0000 0.0000 15.9309 -5.7025 -8.1739 -0.0591 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 0.2054 2.6094 -8.1815 16.7861 12.0164 -79.8128 -0.0000 0.0000 3.2996 0.1717 -0.3034 -8.4736 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 3.8489 -14.6308 -9.2286 3.9047 0.0000 0.0000 -9.4126 9.2069 5.5188 -0.1859 0.0000 -0.0000 -29.2797 -12.8289 8.8557 8.8348 0.0000 0.0000 8.2345 9.6869 -15.5205 -8.5631 0.0000 -0.0000 0.7762 -14.0248 24.2361 0.6817 -8.2852 -176.3628 -1.8170 -9.0197 -0.7739 -1.7707 -1.6848 -0.3593 13.0131 0.5219 0.9824 -0.1684 1.3535 -0.3100 -13.5961 -0.3610 -2.1529 6.1163 -0.7868 -4.5774 -5.3838 3.0133 6.0410 -2.7566 -22.7850 64.2266 0.0000 0.0000 15.0130 -6.2475 -8.6515 -0.2372 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 0.2460 2.8957 -8.3760 17.0059 11.8574 -79.6575 -0.0000 0.0000 3.3548 0.6871 -0.1902 -8.4537 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 4.5874 -13.8428 -9.3663 5.3821 0.0000 0.0000 -11.6072 8.8458 5.6875 -0.2207 0.0000 -0.0000 -29.2530 -10.9626 6.2369 3.7684 0.0000 0.0000 7.9844 12.1782 -12.1788 -9.0839 0.0000 -0.0000 0.6198 -13.3419 24.1764 0.1763 -7.9469 -176.3948 -1.9730 -8.3872 -0.8936 -1.8888 -1.7020 -0.3678 12.9467 0.3065 0.8639 -0.3621 1.1893 -0.2741 -14.1800 -1.0254 -2.3450 6.1601 -1.4236 -4.5794 -5.4361 2.5204 6.0752 -2.6419 -22.5129 64.1730 0.0000 0.0000 14.2179 -6.6172 -9.1964 -0.4826 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.1986 3.2805 -8.6878 17.1498 11.6525 -79.2635 -0.0000 0.0000 3.5716 1.0983 0.2955 -8.5571 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 5.3539 -13.0482 -9.4551 6.5023 0.0000 0.0000 -13.5971 8.2589 5.9232 -0.2032 0.0000 -0.0000 -30.6456 -9.1556 6.4883 3.5496 0.0000 0.0000 5.3879 9.2153 -8.2625 -9.6690 0.0000 -0.0000 0.4388 -12.5846 24.0965 -0.3141 -7.3978 -177.0920 -2.2630 -7.7602 -0.9386 -1.9784 -1.6476 -0.3347 12.8108 0.3420 1.1070 -0.4954 0.9678 -0.1416 -14.4824 -1.7939 -2.5584 6.1389 -2.5401 -4.5795 -5.2142 1.9741 6.1793 -2.5581 -21.9134 63.8458 0.0000 0.0000 14.1347 -6.5910 -9.0141 -0.6936 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.3359 3.6031 -8.8546 17.4189 10.9276 -79.0208 -0.0000 0.0000 3.8515 1.3954 0.4492 -8.5149 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 6.5818 -11.9565 -8.4187 7.2975 0.0000 0.0000 -15.4922 7.5585 5.6592 -0.5059 0.0000 -0.0000 -31.4006 -7.5012 9.5278 4.9918 0.0000 0.0000 3.8212 6.4544 -3.7859 -9.8171 0.0000 -0.0000 0.2256 -11.7246 24.0017 -1.0823 -6.3354 -179.1475 -3.0845 -7.0720 -1.0172 -2.3309 -1.5055 -0.2397 12.8197 1.0079 2.1557 -0.4433 0.7896 0.1731 -14.4550 -3.1670 -2.8951 6.2441 -4.3411 -4.5592 -4.6970 1.6962 6.1969 -2.2337 -21.9974 63.5696 0.0000 0.0000 14.3996 -6.5655 -8.1603 -0.6843 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.1309 4.1037 -8.8170 18.0826 10.3310 -78.7137 -0.0000 0.0000 4.1795 1.8241 0.8159 -8.3683 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 7.6679 -9.9727 -7.1429 8.5318 0.0000 0.0000 -17.6563 6.3895 6.1506 -0.8098 0.0000 -0.0000 -29.5609 -5.9032 11.9749 3.8184 0.0000 0.0000 4.5883 8.1056 1.0246 -10.0211 0.0000 -0.0000 0.0074 -10.7659 23.8885 -2.0545 -5.0688 177.6185 -4.4516 -6.0555 -1.1982 -3.0366 -1.5955 -0.1710 13.1654 1.9835 3.7156 -0.2899 0.6852 0.5886 -14.5009 -5.6083 -3.1973 6.4195 -6.6148 -4.3476 -4.1737 1.0470 6.0413 -1.4779 -21.9775 64.1115 0.0000 0.0000 14.2621 -7.1229 -7.8291 -0.4881 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -1.0535 5.3538 -8.7016 18.7697 10.8499 -77.6307 -0.0000 0.0000 4.8446 3.5446 2.6960 -8.4603 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 8.0971 -7.2712 -6.7174 10.9232 0.0000 0.0000 -20.2965 4.5413 8.4558 -0.4453 0.0000 -0.0000 -25.3643 -4.1662 8.8120 -0.8471 0.0000 -0.0000 7.4885 9.6613 6.6197 -11.0014 0.0000 -0.0000 -0.1813 -9.7237 23.7728 -2.0095 -3.5056 174.7184 -5.3981 -3.6653 -1.1924 -3.7320 -1.8059 -0.1723 13.8507 2.3430 4.4486 -0.2746 0.3230 0.8721 -14.6420 -8.9359 -3.3823 6.3726 -8.6056 -3.9331 -3.8054 -1.1815 5.6332 -0.5232 -19.9759 65.6690 0.0000 0.0000 13.7218 -7.6867 -8.6582 -0.3686 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.5125 7.2982 -8.6385 18.4430 11.5681 -75.6538 -0.0000 0.0000 5.9628 6.9256 5.2665 -8.7361 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 8.9790 -4.0466 -6.4674 14.2576 0.0000 0.0000 -22.8758 2.8229 10.7608 -0.1295 0.0000 -0.0000 -20.2041 -2.0829 2.8545 -5.9270 0.0000 -0.0000 12.9601 5.1411 10.4092 -11.1758 0.0000 -0.0000 -0.3966 -8.6791 23.7384 -0.7688 -0.8250 173.7925 -5.6995 0.1932 -1.0698 -4.2920 -0.8583 0.0013 14.7889 1.5772 3.5481 -0.4429 -0.5156 0.8887 -14.3678 -11.7475 -3.6883 5.9484 -9.5847 -3.5266 -3.5179 -4.5301 4.9211 0.1925 -17.2229 67.2673 0.0000 0.0000 13.5550 -7.1915 -9.3174 -0.3712 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -2.9903 9.0287 -8.7609 17.1457 10.8702 -73.6650 -0.0000 0.0000 6.8327 9.7773 5.8473 -8.5828 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 10.0763 0.1539 -5.9780 18.7799 0.0000 0.0000 -24.1574 1.7968 10.7655 -1.8249 0.0000 -0.0000 -16.7825 1.9133 1.9100 -6.6384 0.0000 -0.0000 17.0267 -2.7909 9.1027 -9.0716 0.0000 -0.0000 -0.6533 -7.7095 23.8692 0.4804 2.3491 174.0714 -5.8755 3.1287 -0.8259 -4.5634 1.0850 0.4014 15.0946 1.1481 2.1059 -0.4700 -1.3567 0.7508 -13.3956 -12.6634 -4.4223 5.5835 -9.5128 -3.4617 -3.3004 -6.2587 3.9037 1.3204 -18.2489 67.8975 0.0000 0.0000 14.0145 -6.3497 -8.2660 -0.3004 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -2.6151 8.9895 -9.1284 16.3695 10.3143 -72.6597 -0.0000 0.0000 6.7631 9.8936 3.8839 -7.7851 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 9.2763 4.5153 -4.6288 25.9251 0.0000 0.0000 -22.2119 0.3405 8.8646 -5.8207 0.0000 -0.0000 -15.1208 6.3216 3.5793 -3.8390 0.0000 -0.0000 15.6938 -5.5760 7.5159 -7.4606 0.0000 -0.0000 -0.8942 -6.8827 24.1109 0.6989 3.9449 173.4740 -6.1085 3.1482 -0.4565 -4.4192 1.9825 0.6083 13.9331 2.1807 1.7743 -0.2371 -1.2532 0.6489 -12.4607 -11.6671 -5.1817 5.8274 -8.7128 -4.0177 -3.0264 -4.6733 3.3415 3.1263 -23.6476 67.1887 0.0000 0.0000 14.2637 -7.0841 -6.9948 -0.0115 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.6629 7.0642 -9.5230 16.5868 12.2756 -72.6833 -0.0000 0.0000 6.0248 8.0844 2.3320 -7.4307 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 4.1948 7.0605 -1.3432 37.0883 0.0000 0.0000 -16.1163 -2.6979 7.3272 -8.9740 0.0000 -0.0000 -13.5495 8.2448 4.7891 -2.2471 0.0000 -0.0000 11.9218 -2.6541 7.3514 -8.0806 0.0000 -0.0000 -1.1160 -6.2253 24.2905 0.4150 4.5002 171.6443 -5.7917 2.3411 -0.1206 -3.8777 1.6044 0.5272 11.8470 3.3484 2.6608 -0.1308 -0.4358 0.6503 -12.3586 -9.4481 -5.2671 6.3578 -7.6019 -4.8378 -2.5873 -1.4282 3.9555 4.1743 -28.1698 65.6576 0.0000 0.0000 13.5191 -8.7329 -8.0474 0.0470 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.4173 4.7858 -9.9019 16.6672 15.3437 -73.0338 -0.0000 0.0000 5.2432 6.7956 3.2165 -7.7609 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.3115 8.1590 2.6776 50.6712 0.0000 0.0000 -7.6940 -5.8141 7.1127 -7.9158 0.0000 -0.0000 -11.9460 8.9392 5.9934 -2.4426 0.0000 -0.0000 9.0117 -0.7397 7.1706 -9.0973 0.0000 -0.0000 -1.3191 -5.6657 24.3244 0.9284 5.7699 170.4772 -4.6811 3.4935 -0.0395 -3.2357 1.3993 0.4588 10.4868 3.5984 3.1216 -0.3610 -0.0138 0.6081 -12.9104 -7.3690 -4.9309 6.2990 -6.5800 -5.2118 -2.3591 0.1268 4.6582 3.7998 -28.1296 64.4367 0.0000 0.0000 12.4132 -8.1739 -10.3207 -0.4202 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.7672 3.4079 -10.3201 15.3695 15.6961 -73.2780 -0.0000 0.0000 4.7193 7.1929 4.2699 -7.7584 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -12.3192 9.7970 4.9448 62.7595 0.0000 0.0000 -2.0413 -6.6859 5.8840 -5.3113 0.0000 -0.0000 -10.3949 10.9478 9.8344 -2.3446 0.0000 -0.0000 7.2721 -2.0293 3.8980 -8.9621 0.0000 -0.0000 -1.4629 -5.1145 24.2936 2.0807 7.6025 171.4577 -3.6529 6.1691 -0.1208 -2.8724 2.0733 0.5023 10.6366 3.2301 1.8810 -0.7058 -0.2974 0.3625 -13.2119 -6.5004 -4.8833 5.7279 -6.1783 -4.9164 -2.2650 -1.1237 4.2540 2.6062 -25.8109 63.9323 0.0000 0.0000 12.1629 -5.3786 -10.1458 -0.8496 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.0793 3.2995 -10.7548 12.9080 12.9204 -73.2200 -0.0000 0.0000 4.2039 7.7633 2.6251 -7.1993 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -17.8494 12.5447 4.2673 70.7996 0.0000 0.0000 -2.4431 -4.9240 1.6639 -3.9998 0.0000 -0.0000 -8.3547 13.8510 14.0610 -1.8738 0.0000 -0.0000 5.3251 -2.9076 -1.1734 -8.1367 0.0000 -0.0000 -1.5255 -4.5566 24.3062 2.6971 8.7660 174.1149 -3.3603 8.3467 -0.1765 -2.8017 3.1558 0.5868 11.4596 2.7885 -0.4832 -0.8796 -0.7310 -0.1421 -12.9110 -6.7078 -5.1446 5.7279 -6.7787 -4.1858 -2.1840 -2.8874 3.1336 1.6584 -25.7041 63.5038 0.0000 0.0000 12.8298 -4.5649 -6.9669 -1.2164 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -2.1108 3.8684 -11.1548 10.6577 11.0642 -72.6657 -0.0000 0.0000 3.3117 6.6275 -1.3293 -6.8439 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -21.5990 15.0432 1.3577 73.7944 0.0000 0.0000 -5.9618 -1.0647 -3.6836 -3.3579 0.0000 -0.0000 -5.8852 15.7174 14.9337 -1.9198 0.0000 -0.0000 3.3580 -1.0379 -4.8260 -7.8355 0.0000 -0.0000 -1.5282 -4.0336 24.3830 2.5529 8.8396 176.8655 -3.5206 9.4144 -0.2179 -2.8012 3.8117 0.6133 11.9344 2.6021 -2.6204 -0.8136 -0.7939 -0.7100 -12.5333 -7.2122 -5.1107 6.5653 -8.0552 -3.2976 -2.2417 -3.2900 2.4003 1.3379 -27.8181 62.4736 0.0000 0.0000 13.2763 -7.4501 -5.0323 -1.0801 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.7058 4.2685 -11.4251 9.5638 12.3074 -71.7219 -0.0000 0.0000 2.1805 4.1574 -4.7734 -7.7525 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -24.9356 16.0619 -1.2331 72.3845 0.0000 0.0000 -7.9895 2.2613 -6.5923 -3.0621 0.0000 -0.0000 -3.9037 15.9630 13.7018 -2.1469 0.0000 -0.0000 1.9884 1.9627 -6.8277 -7.8446 0.0000 -0.0000 -1.4952 -3.5682 24.4889 2.3975 8.3686 178.6757 -3.5050 9.9951 -0.2456 -2.7329 3.9181 0.5829 12.0954 2.5622 -3.7917 -0.6607 -0.5770 -1.0931 -12.5511 -7.2532 -4.5251 7.2934 -9.1404 -2.3919 -2.4898 -3.1316 2.3616 0.9144 -28.3320 61.0350 0.0000 0.0000 12.7688 -9.9358 -7.1171 -0.9109 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -1.6287 4.3571 -11.5313 9.5943 13.9890 -71.0110 -0.0000 0.0000 1.6591 2.9279 -5.8156 -8.8953 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -28.0086 15.7630 -1.8539 67.6741 0.0000 0.0000 -7.5098 3.0271 -5.8013 -2.9403 0.0000 -0.0000 -2.5430 15.3636 13.7455 -1.9223 0.0000 -0.0000 1.1489 4.6227 -8.8265 -7.4064 0.0000 -0.0000 -1.4338 -3.1564 24.5901 2.2235 7.6986 179.8917 -3.4898 10.3156 -0.2109 -2.7044 3.8561 0.5593 12.4765 2.4855 -4.1872 -0.5718 -0.3557 -1.2751 -12.8355 -6.4734 -3.7399 7.2029 -9.3154 -1.6131 -2.8301 -3.4938 2.5604 -0.0890 -26.0116 59.4240 0.0000 0.0000 12.1164 -8.6521 -11.0062 -0.7790 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.4165 4.3821 -11.4756 10.4871 13.7178 -71.0249 -0.0000 0.0000 2.2582 4.0084 -4.9636 -8.7500 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -30.4698 14.9953 -1.5474 60.0070 0.0000 0.0000 -5.7032 2.0881 -2.5142 -2.4823 0.0000 -0.0000 -1.6807 14.3755 15.3109 -1.3166 0.0000 -0.0000 0.4851 7.0441 -11.3818 -6.9450 0.0000 -0.0000 -1.3541 -2.7680 24.6727 1.8662 6.7555 -178.6929 -3.5830 10.1161 -0.2259 -2.7218 3.7309 0.5292 13.0053 2.4277 -4.3382 -0.5539 -0.0122 -1.4230 -13.1385 -4.9340 -3.0773 6.6515 -8.5821 -1.2017 -3.0283 -3.9580 2.7790 -1.5581 -23.2722 57.3810 0.0000 0.0000 12.3185 -5.9525 -12.8854 -0.3691 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.1950 4.2067 -11.2043 11.9691 12.8897 -71.3956 -0.0000 0.0000 3.6329 5.3897 -3.2483 -7.8702 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -31.7502 14.4747 -2.3074 49.5513 0.0000 0.0000 -3.9683 1.1733 1.4503 -1.9207 0.0000 -0.0000 -1.0147 13.0539 16.1062 -0.8353 0.0000 -0.0000 -0.2006 8.8764 -13.5766 -6.9966 0.0000 -0.0000 -1.2823 -2.3839 24.7230 1.4546 5.9760 -177.0159 -3.5500 9.6904 -0.3230 -2.6542 3.4360 0.4653 13.2679 2.6077 -4.3712 -0.5468 0.6096 -1.6260 -13.4973 -2.9250 -2.5994 6.2132 -7.5331 -1.3071 -3.0296 -3.9588 3.1549 -3.3754 -21.8409 54.7105 0.0000 0.0000 13.1428 -5.6539 -12.1492 -0.3933 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.1476 3.7699 -10.7811 13.5228 13.3378 -71.5569 -0.0000 0.0000 5.2353 5.3560 -1.4605 -7.2280 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -32.0030 14.5342 -4.3153 37.4953 0.0000 0.0000 -3.2645 1.0092 4.6811 -1.8436 0.0000 -0.0000 -0.3695 12.0439 15.3933 -0.6276 0.0000 -0.0000 -0.8922 9.2031 -14.7315 -6.8701 0.0000 -0.0000 -1.2245 -2.0031 24.7313 1.1003 5.8714 -175.6447 -3.3621 9.5738 -0.3255 -2.4749 3.0091 0.4014 13.3149 3.1700 -4.0256 -0.5586 1.3124 -1.7792 -13.9399 -0.8843 -2.2959 5.9156 -6.6736 -1.8296 -3.0413 -3.9127 3.7166 -5.5302 -21.0408 51.5718 0.0000 0.0000 13.9817 -7.3577 -10.6065 -0.6676 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -1.0908 3.6365 -10.2993 14.7418 13.8847 -71.4409 -0.0000 0.0000 6.6538 4.7372 -0.1202 -6.8819 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -32.2487 14.9090 -6.3017 25.7345 0.0000 0.0000 -3.2882 1.4561 5.8736 -2.0076 0.0000 -0.0000 0.3770 11.9036 14.0585 -0.6759 0.0000 -0.0000 -1.6181 8.0645 -14.8153 -6.1930 0.0000 -0.0000 -1.1623 -1.6069 24.7092 1.0980 6.2516 -174.8192 -2.9143 9.7830 -0.2328 -2.1881 2.5296 0.3617 13.3541 4.0258 -3.2138 -0.6382 1.8733 -1.8236 -14.2509 0.6946 -2.0999 5.6609 -6.0488 -2.4960 -3.0839 -4.1333 4.2356 -7.7547 -20.1748 48.5589 0.0000 0.0000 14.7572 -8.2497 -9.1684 -0.7390 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.8825 4.1495 -9.7232 15.7691 12.8203 -71.2105 -0.0000 0.0000 7.5235 4.6315 0.6876 -6.5428 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -32.9988 15.1546 -7.9250 16.0795 0.0000 0.0000 -2.9056 1.8646 4.7500 -1.9895 0.0000 -0.0000 1.7867 12.2809 12.5377 -1.1926 0.0000 -0.0000 -2.4739 6.4835 -14.2210 -6.3266 0.0000 -0.0000 -1.0873 -1.1863 24.6803 1.4076 6.6318 -174.0988 -2.2608 10.0250 -0.2169 -1.7643 2.0852 0.3220 13.3433 4.8618 -2.3889 -0.7580 2.3130 -1.8226 -14.3436 1.5924 -1.9139 5.5743 -5.5298 -2.9753 -3.0195 -4.2080 4.5505 -9.5657 -19.7315 46.2776 0.0000 0.0000 15.5879 -7.7690 -7.9308 -0.6972 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.5139 4.8521 -9.0829 16.6716 10.7662 -70.8157 -0.0000 0.0000 7.8102 4.5654 1.1378 -6.0815 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -34.4058 15.2391 -10.2660 9.9860 0.0000 0.0000 -2.1528 1.5146 3.0502 -1.7971 0.0000 -0.0000 3.8093 12.5198 10.6611 -2.0934 0.0000 -0.0000 -3.3265 5.3579 -13.4657 -8.1653 0.0000 -0.0000 -1.0108 -0.7573 24.6649 1.7091 6.8561 -173.0757 -1.5281 10.1254 -0.3110 -1.2858 1.8282 0.2870 13.2281 5.4049 -1.9911 -0.8347 2.6537 -1.8580 -14.3878 2.1016 -1.7039 5.6701 -5.1288 -3.1349 -2.8516 -3.9453 4.6923 -10.6641 -19.7369 45.0426 0.0000 0.0000 16.2037 -7.4977 -7.4973 -0.6127 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.1421 5.1660 -8.5705 17.2860 9.5810 -70.2872 -0.0000 0.0000 7.9353 4.0105 1.4114 -5.5950 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -36.3184 15.4201 -13.8216 7.4724 0.0000 0.0000 -1.7348 0.8676 2.6024 -1.4648 0.0000 -0.0000 5.7734 12.4283 8.8343 -2.8744 0.0000 -0.0000 -3.9307 5.0398 -13.0574 -9.9909 0.0000 -0.0000 -0.9342 -0.3175 24.6637 1.8646 6.9021 -171.8918 -0.8436 10.0892 -0.4114 -0.9120 1.7441 0.2657 13.1173 5.5634 -1.8477 -0.8650 2.8684 -1.8996 -14.4106 2.5734 -1.5032 5.7843 -4.8199 -3.1659 -2.8034 -3.6686 4.8232 -11.1124 -19.5859 44.5292 0.0000 0.0000 16.4326 -7.8771 -8.3208 -0.3380 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0310 5.0797 -8.2640 17.6765 9.8083 -70.0083 -0.0000 0.0000 8.2142 3.6547 1.7179 -5.3466 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -38.3057 15.5685 -16.7054 7.2669 0.0000 0.0000 -1.3497 1.0058 2.4569 -1.1507 0.0000 -0.0000 7.3666 12.0268 7.6172 -3.2297 0.0000 -0.0000 -4.5434 5.3465 -13.1657 -9.3651 0.0000 -0.0000 -0.8417 0.1618 24.6704 2.1277 6.4755 -170.9146 -0.1866 9.7793 -0.4926 -0.5648 1.5688 0.2298 12.9496 5.4466 -1.5268 -0.9043 2.9693 -1.8399 -14.3279 3.0811 -1.3238 5.8723 -4.4789 -3.2843 -2.9376 -3.4991 5.0635 -11.2451 -19.3208 44.0709 0.0000 0.0000 16.6139 -8.0711 -9.5787 0.0925 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0110 4.9068 -8.0303 18.0848 10.6612 -70.2227 -0.0000 0.0000 8.4155 4.0461 2.0963 -5.5236 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -39.6793 15.0675 -17.6256 8.2721 0.0000 0.0000 -0.5984 1.8449 1.2165 -1.0492 0.0000 -0.0000 8.9257 11.0162 6.8221 -3.2856 0.0000 -0.0000 -5.6434 5.6777 -13.4187 -7.0746 0.0000 -0.0000 -0.7355 0.6696 24.6788 2.1619 5.6881 -170.1202 0.2709 9.2596 -0.5966 -0.3063 1.2997 0.1887 12.6924 5.2585 -1.0095 -0.9874 3.0152 -1.7034 -14.3064 3.5091 -1.1845 5.9130 -4.0937 -3.4666 -3.0488 -3.3588 5.3843 -11.3830 -19.4200 43.4373 0.0000 0.0000 17.0496 -7.9723 -10.1103 0.4114 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0379 4.7423 -7.8157 18.4503 11.3724 -70.7101 -0.0000 0.0000 8.1930 4.3082 2.3564 -5.9304 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -40.3195 13.9721 -17.8875 9.7180 0.0000 0.0000 0.4120 2.3263 -0.0690 -1.1688 0.0000 -0.0000 9.9632 9.6136 6.4474 -2.8687 0.0000 -0.0000 -7.1128 5.7168 -13.8498 -5.7906 0.0000 -0.0000 -0.6281 1.1770 24.6795 1.3955 5.0359 -169.4729 0.2977 8.7702 -0.5677 -0.3399 1.1861 0.1915 12.5073 5.2489 -0.5409 -1.1300 3.0071 -1.5641 -14.6399 3.7691 -1.1600 5.7638 -3.7815 -3.6298 -2.9928 -3.5913 5.6632 -11.6184 -19.5103 42.9755 0.0000 0.0000 17.4889 -8.0501 -9.9934 0.5577 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0486 4.6920 -7.7368 18.5247 11.5623 -71.1431 -0.0000 0.0000 7.6876 3.5679 2.4708 -6.1625 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -40.4861 12.6483 -18.7826 10.5553 0.0000 0.0000 1.8707 2.1241 -0.2195 -1.3650 0.0000 -0.0000 9.8247 8.4875 6.9752 -1.8444 0.0000 -0.0000 -8.4941 5.8737 -14.8236 -6.0470 0.0000 -0.0000 -0.5119 1.7117 24.6549 -0.0872 4.4598 -169.2682 -0.2452 8.3719 -0.2776 -0.6524 1.1228 0.2218 12.5278 5.4307 -0.0075 -1.3530 2.9342 -1.3976 -15.3553 3.9060 -1.2435 5.4620 -3.5919 -3.7998 -2.8541 -4.5021 5.9155 -11.8020 -18.9313 42.8960 0.0000 0.0000 17.6652 -8.1071 -9.8956 0.7517 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0098 5.0895 -7.8324 18.3798 11.2865 -71.4131 -0.0000 0.0000 7.3244 2.5240 2.6063 -6.1103 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -40.2301 10.7342 -19.9796 10.1407 0.0000 0.0000 4.1701 1.3025 0.0011 -1.4822 0.0000 -0.0000 8.9419 7.5765 8.2544 -0.6640 0.0000 -0.0000 -10.0129 6.4175 -16.0031 -6.3652 0.0000 -0.0000 -0.3895 2.3395 24.5919 -1.5083 3.5933 -169.4398 -1.0402 7.8914 0.0479 -1.0295 0.8923 0.2288 12.6651 5.5010 0.6436 -1.6083 2.8328 -1.1651 -16.2751 4.0179 -1.2782 5.2552 -3.4725 -3.9800 -2.7458 -5.5875 6.2830 -11.7727 -18.1615 42.9516 0.0000 0.0000 17.7693 -7.8190 -9.8460 1.0327 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.1748 5.8737 -8.0516 18.1946 11.0657 -71.4793 -0.0000 0.0000 7.1839 2.2193 2.7616 -5.9933 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -38.8182 8.0759 -20.4224 9.1570 0.0000 0.0000 6.5169 -0.5461 -0.0888 -1.5772 0.0000 -0.0000 8.4892 6.3448 9.4969 0.2342 0.0000 0.0000 -12.0982 7.0176 -16.8986 -5.9658 0.0000 -0.0000 -0.3035 3.0620 24.4843 -3.0286 2.9289 -169.0090 -2.0536 7.4053 0.3342 -1.5533 0.7872 0.2349 13.0228 5.4999 0.7745 -1.7767 2.7372 -1.0850 -17.4027 4.0968 -1.3132 5.0760 -3.4028 -4.0797 -2.6363 -6.6091 6.6487 -11.4765 -17.5612 43.1194 0.0000 0.0000 17.8306 -7.7803 -9.8735 1.1889 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.2256 6.5120 -8.5324 17.9554 10.9052 -71.2067 -0.0000 0.0000 6.9517 2.3097 2.8383 -5.9816 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -35.9787 6.0694 -19.4017 8.5362 0.0000 0.0000 8.1234 -2.6522 0.7926 -1.9503 0.0000 -0.0000 8.1042 5.2647 10.4679 1.4113 0.0000 0.0000 -14.3085 7.5979 -18.1364 -5.6141 0.0000 -0.0000 -0.2736 3.8630 24.3295 -5.2305 2.7803 -167.3061 -3.6388 6.6220 0.9066 -2.5993 1.0004 0.2954 14.1118 6.1281 -0.0895 -1.8649 2.6622 -1.3283 -18.8266 4.1264 -1.6049 4.7003 -3.3269 -4.1600 -2.5900 -8.4670 6.7189 -10.8179 -15.9097 43.6353 0.0000 0.0000 17.3852 -8.4618 -10.7406 1.1523 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.2047 7.2421 -9.2817 17.7251 9.6146 -70.6624 -0.0000 0.0000 6.4368 1.8191 3.2797 -6.1044 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -32.0128 5.3246 -17.4933 7.2380 0.0000 0.0000 9.9993 -2.1254 3.5867 -2.3126 0.0000 -0.0000 6.8473 4.6389 11.3502 3.5305 0.0000 0.0000 -16.2905 8.6266 -20.4023 -5.7704 0.0000 -0.0000 -0.2372 4.8140 24.1496 -6.7117 1.1770 -165.7118 -5.4738 3.7318 1.6041 -4.0634 0.5524 0.2748 16.0907 7.8954 -0.7583 -2.0750 2.6883 -1.6155 -20.2465 4.3614 -1.9469 4.4431 -3.0751 -4.3763 -2.8789 -11.3940 6.6866 -9.7003 -12.6788 44.0916 0.0000 0.0000 16.3498 -8.9802 -12.4814 1.0124 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.6048 9.1121 -9.7820 17.6727 7.1077 -70.0507 -0.0000 0.0000 5.7745 0.8750 4.6165 -6.4006 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -26.6653 2.7282 -15.6902 3.4592 0.0000 0.0000 12.4142 2.3628 5.9492 -1.5559 0.0000 -0.0000 6.1175 2.1662 12.5994 6.1067 0.0000 0.0000 -18.9774 10.1139 -22.9199 -5.9216 0.0000 -0.0000 -0.1259 5.9806 24.0064 -4.5999 -3.6826 -166.4000 -5.7831 -1.5432 1.5834 -4.6920 -1.9507 -0.2132 17.2647 8.9382 0.4546 -2.4573 3.0577 -1.3890 -20.9436 5.3396 -1.3999 4.7451 -2.6384 -4.4823 -3.4535 -12.7295 7.1727 -8.2736 -11.0203 44.0081 0.0000 0.0000 15.3062 -8.4027 -13.0370 0.7562 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -1.3239 11.6928 -9.4265 17.5341 6.2855 -69.6109 -0.0000 0.0000 5.3593 0.1343 6.2325 -6.7288 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -19.4048 -4.7351 -13.8204 -1.6507 0.0000 -0.0000 14.1613 6.8420 5.9060 -0.2725 0.0000 -0.0000 8.7732 -4.5679 15.6049 8.9189 0.0000 0.0000 -22.7228 11.4651 -24.5811 -6.0129 0.0000 -0.0000 0.0486 7.0632 23.9771 -2.3562 -9.3930 -169.3105 -5.2322 -5.1631 1.1262 -4.2186 -4.3401 -0.6749 16.0620 5.9345 2.9144 -2.7112 3.4904 -0.5839 -20.9726 6.7410 0.3790 5.0144 -2.3814 -3.8455 -3.6100 -10.5350 8.3405 -7.2177 -13.7852 44.3013 0.0000 0.0000 14.6259 -7.8132 -10.5407 0.2179 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.4096 12.6176 -8.4312 16.6624 8.8532 -69.3739 -0.0000 0.0000 5.4896 -0.5783 6.8056 -6.7177 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -16.1338 -12.6457 -12.7805 -1.2922 0.0000 -0.0000 12.4545 7.8737 6.2330 0.1363 0.0000 0.0000 10.0941 -12.2945 19.7763 15.5268 0.0000 0.0000 -25.2731 11.5119 -24.8805 -7.1664 0.0000 -0.0000 0.1473 7.9425 24.0752 -1.5941 -11.4819 -171.7289 -4.2045 -5.5460 0.7863 -3.2053 -3.9793 -0.5168 13.6137 1.9806 4.0093 -2.5809 2.8143 0.1789 -20.4691 6.5383 1.7837 4.4060 -2.5487 -2.3215 -2.9053 -6.7760 9.3176 -6.7204 -19.5813 45.7473 0.0000 0.0000 14.3192 -8.7490 -6.4674 -0.1530 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.4294 9.0945 -7.9751 15.5152 12.5032 -69.2828 -0.0000 0.0000 5.7331 -1.7014 6.3415 -6.2500 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.9646 -15.4246 -14.7318 3.7767 0.0000 0.0000 7.7218 7.1388 9.2216 -0.1817 0.0000 -0.0000 6.5867 -16.1542 17.4717 27.9011 0.0000 0.0000 -23.6514 9.7861 -21.0850 -9.8097 0.0000 -0.0000 0.1553 8.7580 24.1897 -0.4564 -10.6833 -171.4125 -2.7288 -4.5685 0.4534 -2.3003 -2.4998 -0.2481 11.5769 0.0914 3.2362 -2.3091 1.5812 0.5002 -19.3426 4.5277 1.5805 3.4232 -3.3039 -0.9392 -1.7154 -4.0982 9.2013 -5.8819 -23.9693 48.2194 0.0000 0.0000 14.1632 -10.3109 -4.5001 0.0734 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 0.1649 3.2758 -8.3759 14.9689 13.2415 -69.1779 -0.0000 0.0000 5.4016 -2.4104 6.2236 -5.8726 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -13.8636 -14.8160 -15.4850 6.7684 0.0000 0.0000 4.0562 6.9719 10.2997 -0.4431 0.0000 -0.0000 -0.3766 -16.7264 10.5200 43.5581 0.0000 0.0000 -16.9529 9.9087 -16.5110 -11.7411 0.0000 -0.0000 0.1731 9.5752 24.2387 1.2823 -10.8647 -170.2967 -1.4519 -4.9697 0.3137 -1.7441 -1.9528 -0.1534 10.5335 -0.4998 2.6654 -2.1714 0.8129 0.6906 -17.9146 2.3927 0.3747 3.3898 -4.4142 -0.8206 -0.7938 -3.2511 8.3535 -4.3570 -24.3637 50.7522 0.0000 0.0000 14.0888 -10.1374 -5.8020 0.5071 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.6373 0.3639 -8.8334 13.8301 10.6609 -68.8367 -0.0000 0.0000 4.4800 -1.4768 6.0247 -6.0527 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -9.8456 -15.8319 -14.1242 6.2898 0.0000 0.0000 2.2895 7.7978 8.8154 -0.2680 0.0000 -0.0000 -7.7663 -18.2454 5.4045 57.8207 0.0000 0.0000 -9.8183 10.6904 -15.3678 -11.8458 0.0000 -0.0000 0.1855 10.3844 24.2331 2.9958 -12.4155 -170.7827 -0.8104 -6.5654 0.3061 -1.4655 -2.6289 -0.1903 10.3412 -0.6589 3.7968 -2.1085 0.5127 1.1351 -16.5032 1.0719 -0.8668 4.5941 -5.3422 -1.8074 -0.5681 -3.2389 7.8184 -3.0283 -22.7325 51.9798 0.0000 0.0000 14.2846 -8.0231 -7.9517 1.0392 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.9977 1.3454 -8.8381 10.5842 8.8582 -68.3166 -0.0000 0.0000 3.1050 0.0871 3.9270 -6.1773 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -5.5051 -18.4137 -12.0657 4.8424 0.0000 0.0000 0.9968 8.2305 7.9336 -0.0142 0.0000 -0.0000 -13.8975 -21.3465 3.5861 67.9186 0.0000 0.0000 -7.4391 8.8654 -15.9865 -12.0030 0.0000 -0.0000 0.1342 11.1394 24.2221 3.7518 -13.3154 -172.7580 -0.9799 -7.6426 0.3113 -1.4273 -3.3713 -0.2185 10.6365 -0.6663 5.8141 -1.8990 0.2428 1.7856 -15.2181 0.2977 -1.8370 5.9405 -5.8020 -2.9694 -0.6473 -3.2252 7.6771 -2.3939 -21.8379 52.2803 0.0000 0.0000 14.6482 -6.6020 -8.2937 1.2099 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.9151 3.0342 -8.5830 6.0870 10.1828 -67.7889 -0.0000 0.0000 1.2132 -0.2120 -0.2651 -6.0008 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -2.4519 -19.6296 -10.9349 5.0862 0.0000 0.0000 -1.1988 7.8782 9.4466 -0.0627 0.0000 -0.0000 -18.9593 -23.3524 3.9099 73.1465 0.0000 0.0000 -9.6080 5.2422 -14.8715 -12.3647 0.0000 -0.0000 0.0031 11.8592 24.2366 4.1280 -12.6453 -174.5559 -1.3695 -7.8313 0.2776 -1.4566 -3.3796 -0.1541 11.0204 -0.5218 7.3198 -1.5182 -0.1709 2.3467 -14.0715 -0.3188 -2.6003 6.4872 -5.9209 -3.8182 -0.4762 -3.2789 7.4018 -2.0925 -21.8483 52.7888 0.0000 0.0000 15.0219 -7.5918 -6.5995 0.7860 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.4051 3.2636 -8.4101 2.5508 12.3587 -67.2094 -0.0000 -0.0000 -0.8087 -2.5525 -4.4097 -6.3099 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.3809 -18.7079 -9.8964 6.9345 0.0000 0.0000 -3.8391 7.4483 10.8499 -0.3240 0.0000 -0.0000 -22.8060 -22.6861 4.5827 73.5482 0.0000 0.0000 -12.2493 1.5456 -10.6742 -11.7821 0.0000 -0.0000 -0.1751 12.5552 24.2678 4.6894 -11.4279 -175.6843 -1.4160 -7.7633 0.2212 -1.4259 -3.1606 -0.0847 11.1874 -0.4302 8.1457 -1.1660 -0.4526 2.6815 -13.1494 -0.6707 -3.0988 6.4354 -6.0729 -4.4019 -0.1617 -3.4115 7.0946 -1.6492 -22.1126 53.5920 0.0000 0.0000 15.3989 -9.3368 -4.6058 0.4178 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -4.0559 2.7032 -8.3089 1.0376 12.5759 -66.7928 -0.0000 -0.0000 -2.0651 -4.3881 -5.8455 -6.8739 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 1.1688 -17.1346 -7.4112 9.5147 0.0000 0.0000 -6.2578 7.0910 9.7935 -0.5480 0.0000 -0.0000 -25.4802 -20.6183 4.7973 69.8446 0.0000 0.0000 -13.0363 -1.4581 -5.0026 -9.7904 0.0000 -0.0000 -0.3732 13.1972 24.2849 4.9099 -10.4332 -176.6964 -1.3687 -7.6575 0.1873 -1.4140 -3.1817 -0.0813 11.1620 -0.5751 8.6269 -0.9809 -0.5147 2.8506 -12.6445 -0.7224 -3.2654 6.3422 -6.4062 -4.7826 -0.1609 -3.2953 7.1883 -1.2357 -23.1337 54.2632 0.0000 0.0000 15.4077 -9.4048 -4.1022 0.4771 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -4.9140 2.3216 -8.1200 0.7417 11.1545 -66.6394 -0.0000 -0.0000 -2.1733 -3.7997 -4.3614 -6.8842 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 1.7796 -15.7227 -4.6698 12.5486 0.0000 0.0000 -8.6359 6.4936 7.9836 -0.6538 0.0000 -0.0000 -27.4703 -18.5289 4.8920 62.7366 0.0000 0.0000 -13.0049 -3.4440 -0.2526 -7.8509 0.0000 -0.0000 -0.5737 13.8076 24.2727 4.7643 -9.5775 -177.5583 -1.4694 -7.4170 0.1836 -1.4195 -3.1384 -0.0849 11.0904 -0.9337 8.7589 -0.9149 -0.6299 2.9513 -12.5192 -0.9155 -3.3267 6.2758 -6.7434 -4.9697 -0.5039 -2.8940 7.5750 -1.2622 -25.4333 54.7529 0.0000 0.0000 14.5861 -7.6344 -5.2331 0.7927 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -5.5386 1.8902 -7.9636 0.5959 10.0019 -66.6175 -0.0000 -0.0000 -1.5098 -1.6786 -1.9052 -6.4191 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 2.0997 -14.3265 -3.3116 15.1878 0.0000 0.0000 -10.8469 5.7705 7.5193 -0.7794 0.0000 -0.0000 -28.4260 -16.6849 5.2855 52.4401 0.0000 0.0000 -12.8623 -4.2403 1.7733 -7.6888 0.0000 -0.0000 -0.7457 14.4313 24.2429 4.6751 -9.0797 -178.0646 -1.6458 -7.2539 0.1509 -1.4593 -2.8950 -0.0804 11.1295 -1.4151 8.6445 -0.8797 -0.9652 3.0673 -12.6019 -1.5291 -3.5775 6.1122 -6.9924 -5.0942 -0.7752 -2.7222 7.8013 -1.6081 -27.8238 55.2754 0.0000 0.0000 13.1892 -5.7090 -6.7618 1.0406 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.8843 1.3386 -8.0497 0.5107 9.7405 -66.5668 -0.0000 -0.0000 -0.7707 -0.1822 -0.0543 -5.9646 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 2.9970 -13.3341 -2.7999 16.7499 0.0000 0.0000 -12.3651 5.1790 7.7356 -1.1134 0.0000 -0.0000 -28.0265 -15.5127 6.3701 39.5549 0.0000 0.0000 -10.5876 -3.5914 -0.1444 -8.6688 0.0000 -0.0000 -0.8901 15.0416 24.2139 4.1440 -9.0192 -178.4578 -2.2133 -7.0935 -0.1035 -1.7504 -2.6637 -0.0826 11.5115 -2.1587 8.5242 -0.8812 -1.3352 3.2096 -13.0115 -2.3126 -3.9293 5.9776 -7.3004 -5.2855 -0.8915 -3.3129 7.8997 -1.5869 -28.5256 55.8958 0.0000 0.0000 12.0926 -4.8717 -7.6516 1.0168 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.2401 1.5957 -8.1273 0.6674 9.3732 -66.3731 -0.0000 -0.0000 -0.4478 -0.0870 1.1117 -5.8319 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 3.6995 -12.8839 -2.3010 17.5244 0.0000 0.0000 -13.3151 4.7295 7.6587 -1.6221 0.0000 -0.0000 -27.3388 -14.8876 8.8035 25.2236 0.0000 0.0000 -3.7342 -1.0940 -5.6954 -9.8005 0.0000 -0.0000 -1.0468 15.6401 24.1721 3.1382 -9.1694 -178.7505 -3.0311 -7.0340 -0.5931 -2.2089 -2.3105 -0.0874 11.9804 -3.1658 8.2642 -0.9621 -1.5660 3.2607 -13.6286 -3.0030 -4.1726 6.1135 -7.7342 -5.5652 -1.0156 -4.3274 8.1751 -0.9008 -27.7654 56.4694 0.0000 0.0000 11.6106 -4.9542 -7.9693 0.9140 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -6.5707 2.7087 -7.9260 0.9396 8.5361 -66.0247 -0.0000 -0.0000 -0.4252 -0.5626 2.0840 -5.9234 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 4.2056 -12.5402 -2.4213 17.5873 0.0000 0.0000 -14.3858 4.5679 8.1184 -1.8829 0.0000 -0.0000 -26.9187 -13.7478 9.6885 11.0019 0.0000 0.0000 6.0561 4.0439 -10.3573 -10.9914 0.0000 -0.0000 -1.1953 16.2997 24.1028 2.8389 -9.4579 -178.7136 -3.2667 -7.1986 -0.8289 -2.2331 -1.7581 -0.0861 11.9288 -4.0566 7.6249 -1.1069 -1.7538 3.1655 -14.0609 -3.6304 -4.5114 6.4231 -8.1552 -5.9792 -1.1607 -5.0485 8.4555 0.0430 -27.1754 56.8703 0.0000 0.0000 11.2912 -5.3226 -8.0770 0.9048 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -6.6415 3.4837 -7.7910 1.2472 7.8560 -65.8004 -0.0000 -0.0000 -0.1800 -0.5361 2.8413 -5.9414 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 6.1832 -12.2858 -3.3592 16.5050 0.0000 0.0000 -15.5612 4.7341 9.6555 -1.6235 0.0000 -0.0000 -26.8042 -12.9092 3.1829 1.4552 0.0000 0.0000 10.1566 10.8363 -7.6737 -11.7064 0.0000 -0.0000 -1.3053 16.9465 24.0393 2.6553 -9.6251 -178.6631 -3.1797 -6.9901 -0.8507 -2.1322 -1.5446 -0.0816 11.8088 -4.5172 7.1431 -1.3298 -1.9136 3.0868 -14.6172 -4.0413 -5.0609 6.4391 -8.4379 -6.5841 -1.2733 -5.5545 8.6396 0.5043 -26.7863 56.9369 0.0000 0.0000 10.8659 -5.7144 -8.0117 0.8305 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -6.6355 4.0202 -7.9070 1.6697 7.1722 -66.1525 -0.0000 0.0000 0.5261 0.1501 3.1786 -5.9006 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 8.1848 -12.0146 -4.2331 15.4971 0.0000 0.0000 -16.3510 4.7954 11.2019 -1.2553 0.0000 -0.0000 -28.7446 -12.8027 0.3284 0.2475 0.0000 0.0000 6.0279 12.3778 -7.5395 -11.0349 0.0000 -0.0000 -1.4154 17.5876 23.9961 2.3150 -9.6957 -179.7911 -3.0018 -6.8748 -0.7827 -2.0056 -1.7571 -0.0789 11.8175 -4.2942 7.6267 -1.5188 -1.9135 3.2089 -15.1602 -4.1057 -5.5835 6.1682 -8.5649 -7.2167 -1.1786 -5.6385 8.8355 0.4459 -26.6532 56.7671 0.0000 0.0000 10.4738 -5.8864 -7.5836 0.5867 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -6.6804 4.3242 -8.1211 2.3965 7.0172 -66.8489 -0.0000 0.0000 1.3107 0.7856 3.3084 -5.9705 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 9.4380 -11.4733 -3.6690 15.7480 0.0000 0.0000 -16.7778 4.4985 12.0921 -1.6166 0.0000 -0.0000 -31.2755 -13.1315 1.7846 3.9070 0.0000 0.0000 1.1653 8.3410 -9.1806 -10.1902 0.0000 -0.0000 -1.5607 18.2835 23.9715 1.8465 -9.2879 177.8400 -2.9481 -6.7430 -0.6188 -1.9019 -2.0672 -0.0613 11.8260 -3.4558 8.5938 -1.5935 -1.7651 3.3632 -15.3814 -4.1837 -5.7758 6.0177 -8.6018 -7.5408 -0.8897 -5.6331 9.1470 0.5438 -26.6866 56.8948 0.0000 0.0000 10.2959 -5.8820 -6.8890 0.2923 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -6.7377 4.3971 -8.2220 3.3630 7.5231 -67.1630 -0.0000 0.0000 1.9028 0.8356 3.8922 -6.0955 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 10.0794 -10.0567 -2.3203 17.2753 0.0000 0.0000 -17.1456 4.0124 13.0844 -3.2012 0.0000 -0.0000 -32.5671 -13.5743 3.2242 7.6386 0.0000 0.0000 1.8919 4.2532 -8.1419 -12.5061 0.0000 -0.0000 -1.7406 19.0767 23.9553 1.2137 -8.3137 175.4393 -3.3377 -6.4375 -0.4558 -2.0276 -2.1209 -0.0240 11.7528 -2.3365 9.0163 -1.5293 -1.5805 3.2870 -15.2345 -4.5453 -5.6644 6.2503 -8.6400 -7.4834 -0.5479 -5.8208 9.3429 1.6300 -26.4112 57.7880 0.0000 0.0000 10.5893 -6.3887 -6.1451 0.0602 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -6.7537 4.4003 -8.2088 4.4033 8.2408 -66.8838 -0.0000 0.0000 2.5776 0.7561 5.0939 -6.0618 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 10.1640 -7.8449 -1.5187 19.6053 0.0000 0.0000 -17.2697 3.4508 14.5280 -5.4976 0.0000 -0.0000 -32.6021 -13.4922 4.4266 10.3314 0.0000 0.0000 6.2495 4.7706 -7.0663 -16.0460 0.0000 -0.0000 -1.9286 19.9919 23.9143 0.5529 -7.4557 173.3659 -4.1201 -6.2945 -0.3754 -2.4055 -2.1172 -0.0028 11.6469 -1.2619 8.9960 -1.2762 -1.3457 3.0822 -14.9094 -4.8932 -5.4916 6.6400 -8.6739 -7.3176 -0.1467 -5.7408 9.1904 3.6699 -25.3716 59.2192 0.0000 0.0000 11.4652 -7.8676 -5.6384 -0.0204 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.7707 4.3006 -8.0558 5.5569 8.9812 -66.6223 -0.0000 0.0000 3.5365 1.2216 6.2931 -5.8836 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 10.0365 -5.7515 -0.4278 22.3926 0.0000 0.0000 -16.6662 2.4997 15.3668 -7.9502 0.0000 -0.0000 -31.0739 -13.2696 5.4675 12.2341 0.0000 0.0000 8.3200 7.2584 -8.9857 -18.0106 0.0000 -0.0000 -2.1495 20.9805 23.8139 -0.3478 -6.2258 171.2766 -5.3427 -5.6224 -0.4672 -3.1392 -2.4151 -0.0384 12.0227 -0.3250 9.1516 -0.9844 -0.9770 2.9105 -14.9510 -4.9278 -5.2674 6.6603 -8.5926 -7.2692 0.1266 -5.7451 9.0658 5.3063 -23.2521 60.3527 0.0000 0.0000 12.2128 -9.4103 -6.0018 0.1213 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.9381 4.6421 -7.5625 6.7854 8.7458 -66.7958 -0.0000 0.0000 4.4092 2.0853 7.2579 -5.7931 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 9.4034 -3.2085 1.1730 25.6632 0.0000 0.0000 -16.0010 0.9443 15.7574 -10.8525 0.0000 -0.0000 -28.3985 -12.1629 5.6751 12.9893 0.0000 0.0000 7.9979 7.3789 -11.8294 -17.1689 0.0000 -0.0000 -2.4825 22.0237 23.6773 -0.7197 -2.6244 169.6948 -6.6131 -2.8760 -0.5488 -4.1914 -2.8098 -0.0877 13.2237 1.0499 9.2206 -0.9733 -0.4960 2.6221 -15.5610 -4.9469 -4.9623 6.3034 -8.2939 -7.3042 -0.2027 -7.0837 9.4488 5.3380 -20.8994 60.5309 0.0000 0.0000 11.7742 -9.3979 -7.6473 0.1430 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -7.2318 6.1637 -6.9724 7.7933 6.2821 -66.9187 -0.0000 0.0000 4.7735 3.0180 8.1500 -5.9197 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 8.7660 2.4953 0.5221 29.3011 0.0000 0.0000 -16.2497 -0.7372 18.2603 -14.5362 0.0000 -0.0000 -25.5488 -7.6392 4.1085 13.1598 0.0000 0.0000 7.1702 5.3184 -10.7759 -12.6048 0.0000 -0.0000 -2.9582 23.1391 23.5906 0.2614 3.7630 168.7815 -7.3022 0.9684 -0.3434 -5.0728 -2.6808 0.0057 14.3471 4.2516 9.1236 -1.3385 -0.0101 2.1281 -16.0450 -5.2250 -4.8253 6.2748 -7.8414 -7.3321 -1.1130 -9.4833 10.0566 3.8479 -20.4112 59.9571 0.0000 0.0000 9.9545 -7.2675 -9.5164 -0.3844 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -7.2028 8.3941 -7.0482 8.3783 2.9536 -66.5213 -0.0000 0.0000 4.7079 3.9128 8.0866 -6.1051 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 8.1988 12.4726 -3.0301 34.2600 0.0000 0.0000 -15.4514 -2.7737 23.7046 -18.1181 0.0000 -0.0000 -23.1215 0.6577 1.9445 13.9437 0.0000 0.0000 5.8289 3.5142 -5.4904 -7.8108 0.0000 -0.0000 -3.4606 24.2583 23.6373 1.9373 9.9949 166.7444 -7.1644 2.5789 0.1118 -5.0214 -2.4750 0.2037 13.5964 9.7092 10.1923 -1.6851 0.6741 1.7268 -15.7726 -5.3086 -4.9131 6.8938 -7.3930 -7.3375 -1.8204 -10.6115 10.2293 1.8246 -22.2488 59.3390 0.0000 0.0000 8.0080 -4.7256 -9.5350 -1.3713 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.5269 9.7569 -7.7244 8.6897 2.7949 -66.3296 -0.0000 0.0000 4.6892 3.9719 5.6685 -5.9726 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 5.0880 22.8795 -2.7951 42.0243 0.0000 0.0000 -8.7191 -6.0283 28.4920 -19.5797 0.0000 -0.0000 -20.2982 8.5695 2.2839 13.7340 0.0000 0.0000 3.4835 2.1789 -0.7936 -5.9565 0.0000 -0.0000 -3.8373 25.2937 23.7928 4.2338 13.5438 162.5041 -5.8693 2.1816 0.6016 -3.8613 -2.4710 0.3725 11.0750 13.7781 12.8949 -1.7400 1.9083 1.7435 -15.2078 -4.0981 -4.5687 7.4977 -7.0627 -7.1876 -1.9115 -8.3041 10.1232 0.4431 -24.2379 59.3243 0.0000 0.0000 7.6977 -4.1080 -7.8507 -2.2365 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.5376 9.8387 -7.9127 8.8584 7.5032 -66.9451 -0.0000 0.0000 4.9951 2.2362 1.7288 -5.6697 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -1.9776 28.7004 6.4274 51.3065 0.0000 0.0000 4.8583 -11.7947 30.0537 -15.2100 0.0000 -0.0000 -14.9544 13.4658 3.8403 9.5640 0.0000 0.0000 2.0699 0.9572 1.9687 -6.6582 0.0000 -0.0000 -4.0095 26.1808 23.9176 6.7930 14.1894 158.6503 -3.6848 2.0967 0.9017 -2.4508 -2.1206 0.4751 9.0755 14.0776 14.6085 -1.7641 3.1410 1.7878 -15.0620 -1.9881 -3.5502 7.3601 -6.6222 -6.6675 -1.7662 -4.1668 10.1632 -0.5484 -23.9333 59.9853 0.0000 0.0000 9.4235 -5.4479 -6.2103 -2.2675 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.6637 9.1029 -7.6017 9.1464 13.8042 -67.5884 -0.0000 0.0000 5.6264 0.3266 -0.9808 -5.3020 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -8.6009 28.1213 18.0660 59.5672 0.0000 0.0000 15.5322 -18.0656 29.4651 -8.1518 0.0000 -0.0000 -8.0022 15.9037 2.1002 3.5016 0.0000 0.0000 2.6306 0.2607 5.5539 -7.3839 0.0000 -0.0000 -4.0358 26.8685 23.9703 8.1024 14.0358 158.8146 -2.0664 3.3094 0.8818 -1.7741 -1.4002 0.4780 8.9424 12.8480 12.9606 -1.9382 3.5975 1.3086 -15.5554 -0.6574 -2.5866 6.6196 -5.7906 -5.8928 -2.0740 -2.2643 10.2271 -2.6283 -21.2637 60.3936 0.0000 0.0000 12.1795 -6.7228 -4.6743 -1.5357 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -3.8056 8.3534 -7.8055 9.6902 16.6079 -67.8496 -0.0000 0.0000 6.5628 0.9602 -1.0952 -4.2096 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -12.5628 24.8446 23.7007 66.4582 0.0000 0.0000 14.0372 -19.8090 26.2179 -5.3140 0.0000 -0.0000 -3.9378 17.0568 1.3704 1.5307 0.0000 0.0000 2.5383 -0.5198 5.2044 -6.9477 0.0000 -0.0000 -3.9841 27.4094 24.0020 7.5337 14.0966 162.3547 -1.8900 4.9875 0.6694 -1.9571 -0.5617 0.4651 10.1759 11.5032 9.3843 -2.0288 3.4522 0.5448 -16.1100 -0.2890 -2.2221 6.1124 -4.7031 -5.2880 -3.0369 -2.8578 10.0689 -5.9715 -19.4527 59.8780 0.0000 0.0000 14.9399 -6.7916 -2.5962 -0.9706 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.6703 8.0790 -8.6910 10.8892 15.5831 -68.3409 -0.0000 0.0000 7.2206 3.4570 -0.1107 -2.9560 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -15.9494 21.5132 23.5913 70.9270 0.0000 0.0000 3.6170 -16.8724 19.3150 -6.0049 0.0000 -0.0000 -4.1964 17.3639 3.5387 4.9634 0.0000 0.0000 -0.1725 -1.7085 0.1067 -6.4004 0.0000 -0.0000 -3.8525 27.9379 24.0527 6.4075 13.1270 165.1268 -2.4355 5.5168 0.6445 -2.2761 -0.2017 0.4425 11.4102 10.5945 7.1525 -1.8208 3.2704 0.1215 -16.1094 -0.1018 -2.2840 6.3249 -3.7445 -5.0954 -4.2437 -3.1685 9.6165 -9.4299 -20.4760 58.5370 0.0000 0.0000 17.3663 -6.3070 -0.3360 -1.0913 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.4204 7.9018 -9.4000 12.8697 15.0666 -69.5893 -0.0000 0.0000 7.0349 4.3939 -0.0007 -2.3819 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -19.4419 17.0530 22.7161 71.7845 0.0000 0.0000 -6.2586 -12.8207 10.2310 -6.4090 0.0000 -0.0000 -4.6634 16.1835 4.1163 8.2495 0.0000 0.0000 -3.2574 -2.7418 -2.9997 -6.2102 0.0000 -0.0000 -3.7168 28.5002 24.1194 6.0903 11.8272 165.2529 -2.7112 5.2869 0.7794 -2.3083 -0.4094 0.4038 11.9212 10.5351 7.1046 -1.5008 3.3898 0.1031 -15.7490 0.0928 -2.3023 6.9703 -3.2660 -5.0968 -5.0499 -2.3993 9.2041 -12.2004 -22.0005 57.0885 0.0000 0.0000 19.2140 -6.1692 1.0032 -1.4107 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.6476 7.8140 -9.4060 15.0683 17.7414 -71.1732 -0.0000 0.0000 6.4720 2.8301 0.0486 -2.5336 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -22.7630 12.5035 23.2690 69.2241 0.0000 0.0000 -12.1821 -9.1765 1.9752 -4.6110 0.0000 -0.0000 -3.2672 14.9375 3.5429 8.7886 0.0000 0.0000 -4.9772 -3.3481 -3.0728 -5.9462 0.0000 -0.0000 -3.6131 29.0464 24.1543 6.3754 11.0757 164.4277 -2.4217 5.2771 0.8621 -2.1022 -0.7000 0.3643 11.8983 10.9904 7.6049 -1.3576 3.6366 0.1083 -15.4146 -0.0848 -2.1086 7.6048 -3.2341 -4.9462 -5.2778 -1.6629 9.0557 -14.0739 -21.6290 56.4544 0.0000 0.0000 20.2705 -6.2543 0.9496 -1.4215 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.4040 8.0137 -9.1352 16.9576 22.0564 -72.2795 -0.0000 0.0000 6.5384 2.0303 1.2640 -2.7986 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -25.6974 9.7490 23.2108 63.9476 0.0000 0.0000 -15.6185 -5.8340 -2.8213 -2.4538 0.0000 -0.0000 -1.5718 14.4591 3.1661 9.0966 0.0000 0.0000 -6.4968 -3.6878 -2.2499 -5.5969 0.0000 -0.0000 -3.5266 29.5591 24.1371 6.6812 10.8549 164.0853 -1.9983 5.6700 0.7995 -1.8654 -0.7409 0.3535 11.8097 11.4138 7.6303 -1.3645 3.7731 -0.0071 -15.1538 -0.5738 -1.8222 8.0136 -3.2809 -4.6127 -5.2258 -1.2443 8.9822 -15.4013 -20.3770 56.6658 0.0000 0.0000 20.7910 -5.7536 0.1486 -1.1907 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0802 8.5487 -9.0307 18.5108 24.8403 -72.9338 -0.0000 0.0000 7.4076 3.9949 2.6597 -2.6650 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -28.5772 9.1005 20.9451 56.8756 0.0000 0.0000 -16.8230 -4.1369 -3.0432 -2.1455 0.0000 -0.0000 -0.6784 14.4689 3.3273 10.6937 0.0000 0.0000 -8.7706 -3.9820 -2.1866 -5.4785 0.0000 -0.0000 -3.4342 30.0889 24.1008 7.2269 10.6949 163.6477 -1.6149 6.0757 0.7116 -1.6167 -0.6929 0.3588 11.8247 11.6624 7.6642 -1.3051 3.8750 -0.0833 -14.8437 -0.8552 -1.5248 8.1734 -3.0728 -4.2910 -5.1714 -0.6196 8.7651 -16.4330 -20.3099 57.2630 0.0000 0.0000 21.2674 -4.7476 -0.5411 -1.0459 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.6522 9.1105 -8.8595 20.3256 25.3796 -73.7103 -0.0000 0.0000 8.2354 6.1172 2.8544 -2.4076 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -30.9053 9.2876 17.1893 48.6721 0.0000 0.0000 -14.5122 -3.8947 0.6765 -3.5008 0.0000 -0.0000 0.8679 14.6416 3.3039 11.5580 0.0000 0.0000 -10.6907 -4.2763 -2.1118 -5.3969 0.0000 -0.0000 -3.3260 30.6682 24.0780 8.2600 10.4029 162.7288 -1.1377 6.3585 0.6810 -1.2801 -0.7545 0.3392 11.8267 11.8246 8.0091 -1.1438 4.0780 -0.0764 -14.4579 -0.5922 -1.1678 8.1740 -2.6095 -4.0893 -5.1638 0.0684 8.5085 -17.0145 -21.4441 57.9340 0.0000 0.0000 22.0619 -3.9992 -0.9311 -0.9808 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 1.4561 9.5357 -8.2587 22.4407 25.5970 -74.5503 -0.0000 0.0000 8.5249 5.7403 2.1214 -2.2096 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -31.9017 9.4377 12.6842 39.4430 0.0000 0.0000 -8.0191 -3.3276 7.2910 -5.3658 0.0000 -0.0000 4.0045 14.9612 2.6878 10.4216 0.0000 0.0000 -11.4745 -4.5035 -1.3211 -5.1363 0.0000 -0.0000 -3.1995 31.2664 24.0546 9.1804 10.2206 162.2719 -0.6966 6.6910 0.6740 -0.9297 -0.8854 0.2984 11.7010 11.9242 8.1505 -1.0097 4.3570 -0.1507 -14.0394 0.1029 -0.7613 8.2071 -2.0717 -4.0044 -5.1393 0.3080 8.3991 -17.1152 -22.6471 58.3456 0.0000 0.0000 23.3284 -3.6516 -1.3982 -0.7390 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 1.9098 9.7730 -7.4020 24.3825 27.0556 -75.1519 -0.0000 0.0000 8.6393 4.1254 1.8109 -2.1408 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -32.0393 9.6019 7.2886 29.7448 0.0000 0.0000 1.6974 -1.5454 15.4109 -7.4154 0.0000 -0.0000 7.4194 15.3062 1.6189 8.7016 0.0000 0.0000 -11.8873 -4.6545 -0.5338 -4.9860 0.0000 -0.0000 -3.0565 31.8415 24.0074 9.3812 10.4311 162.9122 -0.5607 7.1117 0.6773 -0.7032 -0.9919 0.2637 11.5394 12.0835 7.8916 -0.9522 4.6371 -0.3417 -13.7119 0.9893 -0.4755 8.3934 -1.5419 -4.0716 -5.0582 0.1043 8.3583 -17.0788 -23.4003 58.1525 0.0000 0.0000 25.0051 -3.3153 -2.3775 -0.3795 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 1.9713 9.8437 -6.8682 26.0167 28.9166 -75.5457 -0.0000 0.0000 8.9464 3.8679 2.3941 -2.1014 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -32.4394 9.7494 1.7366 20.7388 0.0000 0.0000 11.0689 2.0092 22.4739 -9.3608 0.0000 -0.0000 9.7357 15.5141 0.7110 7.8136 0.0000 0.0000 -12.7480 -4.7210 -0.8226 -5.0212 0.0000 -0.0000 -2.8944 32.3943 23.9393 9.1333 10.7694 164.0395 -0.5522 7.3287 0.7416 -0.5779 -1.1522 0.2397 11.4660 12.4993 7.6989 -0.9291 4.9446 -0.5153 -13.5906 1.9195 -0.3717 8.7072 -0.9962 -4.3103 -4.8786 -0.1940 8.3094 -17.2278 -23.6751 57.3321 0.0000 0.0000 26.7736 -2.7965 -3.9677 -0.1159 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 1.8654 9.9663 -6.8255 27.4461 29.6187 -75.9537 -0.0000 0.0000 9.3411 4.9591 3.1484 -2.1025 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -33.2197 9.4168 -1.6993 13.4481 0.0000 0.0000 15.0249 5.7231 25.7829 -10.6107 0.0000 -0.0000 11.4007 15.4825 0.0296 7.3513 0.0000 0.0000 -13.7973 -4.6116 -1.7305 -4.8849 0.0000 -0.0000 -2.7196 32.9583 23.8634 8.9623 11.0001 164.9500 -0.4300 7.2714 0.8268 -0.3719 -1.4119 0.2115 11.3776 13.0920 7.9330 -0.9213 5.3095 -0.6084 -13.6474 2.8647 -0.2606 9.0715 -0.4958 -4.5757 -4.5661 -0.4267 8.3724 -17.5219 -23.5641 56.2254 0.0000 0.0000 28.2160 -2.1149 -5.8212 0.1373 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 1.7502 10.4337 -6.8365 28.4969 29.4696 -76.3321 -0.0000 0.0000 9.6357 5.7136 3.2668 -2.1657 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -33.8380 8.7026 -2.1983 8.4550 0.0000 0.0000 12.3765 7.0259 24.1677 -10.3425 0.0000 -0.0000 13.3049 15.3318 -0.8721 6.6001 0.0000 0.0000 -14.5678 -4.3372 -2.1882 -4.7873 0.0000 -0.0000 -2.5381 33.5487 23.7871 8.7826 11.2223 165.7634 -0.2574 7.1060 0.8870 -0.1274 -1.7070 0.1875 11.1687 13.7295 8.3455 -0.9527 5.6506 -0.6510 -13.7492 3.7212 -0.0432 9.3699 -0.1121 -4.6940 -4.1792 -0.7456 8.5108 -17.6956 -23.3989 55.2433 0.0000 0.0000 29.1208 -1.4976 -7.3936 0.4857 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 1.7504 11.1358 -6.5452 28.9385 29.7696 -76.6113 -0.0000 0.0000 9.8447 5.2108 2.6454 -2.1724 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -34.1265 8.0439 -2.4099 5.5329 0.0000 0.0000 7.2404 6.8745 18.9466 -8.4862 0.0000 -0.0000 15.2745 15.1285 -1.7767 5.7980 0.0000 0.0000 -15.2139 -3.9806 -2.4786 -5.3122 0.0000 -0.0000 -2.3584 34.1372 23.7108 8.0376 11.7038 166.9433 -0.3365 6.9447 1.0030 -0.0702 -1.9261 0.1924 10.9685 14.4240 8.5632 -1.0372 5.8786 -0.7207 -13.8739 4.3964 0.1177 9.4394 0.2523 -4.7227 -3.8047 -1.4073 8.4934 -17.6600 -23.2539 54.5513 0.0000 0.0000 29.6623 -1.3344 -8.3128 0.6609 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 1.8211 11.6512 -6.2051 29.0653 30.7593 -76.8120 -0.0000 0.0000 9.9025 3.7402 1.5025 -2.1446 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -34.4802 7.8429 -4.0336 3.7559 0.0000 0.0000 4.6194 6.6783 13.2310 -6.7886 0.0000 -0.0000 16.4032 14.9093 -2.2292 5.4795 0.0000 0.0000 -15.9950 -3.5961 -3.3796 -5.9364 0.0000 -0.0000 -2.1866 34.7168 23.6382 6.7429 12.2667 168.5563 -0.6282 6.6086 1.1966 -0.1517 -2.1842 0.1866 10.9081 15.2606 8.5724 -1.1867 6.0097 -0.8041 -14.1312 5.0429 0.1125 9.2688 0.7474 -4.8347 -3.5486 -2.4410 8.3495 -17.5772 -23.1016 53.7359 0.0000 0.0000 30.4341 -1.1848 -8.5592 0.4884 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 1.7939 12.0538 -6.1221 29.2219 31.8953 -76.8200 -0.0000 0.0000 9.7457 2.1013 0.0030 -2.2545 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -34.7001 8.3201 -5.8106 2.6751 0.0000 0.0000 5.4534 6.1175 9.6352 -6.2456 0.0000 -0.0000 16.6980 14.5229 -2.1817 5.6535 0.0000 0.0000 -16.8169 -3.0143 -4.9423 -5.5050 0.0000 -0.0000 -2.0307 35.3062 23.5740 5.0478 12.6041 170.1866 -1.0236 5.7828 1.3833 -0.3171 -2.6375 0.1373 10.8982 16.3097 8.7172 -1.4327 6.1842 -0.8533 -14.7086 5.8281 0.0779 9.0175 1.3095 -5.0265 -3.1609 -4.0730 8.3639 -17.8685 -22.7822 52.3909 0.0000 0.0000 31.8588 -0.4078 -8.3389 0.3571 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 1.5765 12.9991 -5.9733 29.1908 33.2364 -76.4020 -0.0000 0.0000 9.4927 1.1820 -1.6259 -2.4444 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -34.5927 9.4060 -6.2718 3.1390 0.0000 0.0000 6.9746 4.8754 9.7000 -5.8825 0.0000 -0.0000 16.4083 13.8724 -1.7803 6.1827 0.0000 0.0000 -17.4297 -2.0074 -6.6282 -4.2638 0.0000 -0.0000 -1.8829 35.9339 23.5033 2.7308 12.7758 171.6276 -1.7346 4.4035 1.5688 -0.6784 -3.2908 0.0602 10.7124 17.8438 9.2164 -1.7392 6.3718 -0.8471 -15.6406 6.5311 0.0429 8.7447 1.7333 -5.1917 -2.4321 -6.3190 8.4473 -18.4523 -22.6179 50.5751 0.0000 0.0000 33.7781 -0.1085 -7.6240 0.5999 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 1.3245 14.3413 -5.3754 28.8644 35.3404 -75.7425 -0.0000 0.0000 9.2852 0.9833 -2.9960 -2.3893 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -34.3115 10.8027 -5.1822 5.2669 0.0000 0.0000 8.2134 2.9015 11.9131 -4.7835 0.0000 -0.0000 15.4515 13.0726 -1.0724 6.9285 0.0000 0.0000 -17.8391 -0.6989 -8.2743 -4.3567 0.0000 -0.0000 -1.7129 36.6067 23.4095 -0.4148 12.8300 173.2307 -2.9655 2.5428 1.9238 -1.4304 -4.1324 -0.0507 10.5718 20.3021 9.7123 -2.0676 6.2870 -0.8522 -16.9502 6.6413 -0.2357 8.2973 2.0123 -5.3139 -1.5508 -9.1929 8.0934 -18.1842 -22.2549 49.2061 0.0000 0.0000 35.2869 -2.3828 -5.5012 1.3630 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 1.0431 15.2840 -4.8641 28.5747 37.7201 -74.7735 -0.0000 0.0000 9.1435 0.4349 -3.7064 -1.9955 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -33.8030 11.9131 -3.9990 6.5647 0.0000 0.0000 11.6387 1.1338 13.1676 -3.3203 0.0000 -0.0000 13.7386 12.0390 -0.1242 7.7815 0.0000 0.0000 -18.3258 0.4177 -10.1392 -6.8176 0.0000 -0.0000 -1.4810 37.2990 23.3426 -4.0828 11.7350 174.9053 -4.4287 -0.5767 2.5067 -2.5528 -5.8677 -0.3590 10.9147 24.6490 9.7720 -2.5642 5.7041 -0.9526 -18.9783 5.8219 -0.8449 7.6815 2.3105 -5.3118 -0.8543 -13.5041 7.4378 -15.6494 -20.0911 49.1965 0.0000 0.0000 35.4713 -6.4983 -0.5964 3.2746 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.3764 16.3636 -5.2877 27.9060 38.3380 -72.1106 -0.0000 0.0000 9.0999 -0.4524 -3.3914 -1.5320 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -32.7017 11.2332 -4.5874 4.3949 0.0000 0.0000 17.6394 1.0569 12.1968 -1.6997 0.0000 -0.0000 11.3543 9.7337 1.4982 9.0282 0.0000 0.0000 -18.9639 1.1785 -12.3478 -9.3227 0.0000 -0.0000 -1.1688 38.0239 23.3627 -7.0780 8.7608 175.3980 -5.1692 -4.5324 2.9332 -3.2247 -9.9094 -1.1875 10.4554 30.7044 10.2268 -3.3477 4.8006 -1.0098 -21.5450 4.4709 -1.2628 7.2296 2.5224 -4.9889 -0.1907 -18.7562 7.6476 -10.5152 -16.4113 49.5608 0.0000 0.0000 34.2249 -8.8607 7.2230 6.2274 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.5843 18.6276 -6.3749 26.3423 36.5226 -67.0092 -0.0000 0.0000 8.9819 0.0897 -2.2864 -1.0413 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -30.6108 7.6335 -5.2599 -0.5648 0.0000 -0.0000 22.5727 1.9861 9.3226 -0.3128 0.0000 -0.0000 9.3334 5.6036 4.1752 10.8845 0.0000 0.0000 -19.1291 1.9271 -14.4020 -10.6661 0.0000 -0.0000 -0.8368 38.7428 23.4589 -9.1517 5.5651 173.6474 -4.7818 -6.7061 2.9261 -2.8071 -14.4970 -2.0414 7.6621 33.4742 12.4955 -4.2189 4.4934 -0.7057 -24.0947 3.8513 -0.6484 6.6562 2.1290 -4.3347 1.2079 -22.2550 9.5251 -3.8071 -14.1242 49.0900 0.0000 0.0000 31.4719 -8.1108 15.4457 7.9046 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.7823 21.6963 -7.1394 24.0816 34.0682 -61.4563 -0.0000 0.0000 8.5905 2.2937 -1.4157 -0.5278 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -29.4642 2.8077 -4.3989 -3.1876 0.0000 -0.0000 22.8151 2.7782 7.5536 0.2747 0.0000 0.0000 7.9172 1.5260 7.6178 13.3841 0.0000 0.0000 -18.0565 2.5749 -15.5035 -12.1728 0.0000 -0.0000 -0.5526 39.3614 23.5894 -10.9836 4.0850 170.4386 -4.2350 -6.3837 2.6014 -2.4269 -13.5132 -1.6507 6.4846 26.7843 14.2445 -4.9709 5.1028 0.0853 -26.9818 4.6002 1.3865 4.9125 0.9215 -3.5986 3.3227 -21.4066 12.6078 2.8488 -15.5150 48.5858 0.0000 0.0000 26.7095 -6.5925 19.1313 6.4022 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.3978 23.3632 -7.3792 21.7249 33.6120 -58.4902 -0.0000 0.0000 8.0819 3.1675 -1.6029 -0.4676 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -30.5345 -0.8371 -4.0789 -1.2602 0.0000 -0.0000 19.6459 3.3280 9.3365 0.2152 0.0000 0.0000 5.9458 -0.6700 10.9272 16.8575 0.0000 0.0000 -15.8527 2.6701 -15.6098 -15.1090 0.0000 -0.0000 -0.2817 39.9226 23.7290 -11.5997 3.4681 168.3228 -3.5156 -4.9957 1.9893 -2.3232 -7.9760 -0.5795 7.8557 15.3547 13.8233 -5.2165 4.8292 1.0427 -29.8288 5.1516 3.7000 1.7525 -0.5892 -2.9400 5.1365 -15.9496 15.5701 8.5405 -20.7069 49.3337 0.0000 0.0000 20.0788 -7.3517 14.8297 3.3208 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 2.4309 20.5888 -7.9772 20.6460 36.9445 -59.0776 -0.0000 0.0000 7.3383 -0.0559 -2.3107 -1.5945 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -30.4611 -2.8387 -3.8437 0.9437 0.0000 0.0000 17.1955 3.3441 10.6331 -0.0183 0.0000 -0.0000 3.9718 -2.3367 13.0520 21.8303 0.0000 0.0000 -12.9647 2.5775 -16.0771 -17.8563 0.0000 -0.0000 0.0284 40.4558 23.8681 -11.2420 2.0010 168.8711 -2.3530 -3.8730 1.4132 -1.9907 -4.6801 -0.0713 9.3785 8.4105 12.3354 -4.9312 3.0639 1.6339 -32.1833 3.5422 3.7921 -1.3713 -2.1783 -2.3127 6.2721 -10.5610 17.4947 13.4523 -25.6318 50.5704 0.0000 0.0000 13.3944 -8.8209 5.2082 0.9669 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 4.0501 14.5434 -9.9641 20.5256 40.7387 -60.3090 -0.0000 0.0000 5.7820 -4.8689 -1.2098 -3.5001 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -28.3494 -4.3202 -3.7605 1.2564 0.0000 0.0000 15.8067 3.4326 9.2912 -0.0399 0.0000 -0.0000 1.1904 -5.7397 13.4391 29.6031 0.0000 0.0000 -9.3276 3.3525 -17.7909 -17.4660 0.0000 -0.0000 0.3663 40.9476 23.9653 -11.2242 -0.5269 171.4942 -1.5435 -3.4019 1.0037 -1.7652 -3.6665 -0.0081 10.8112 4.4367 10.5590 -4.5804 1.0611 1.9878 -33.6946 0.3890 1.3121 -2.8520 -4.2471 -2.1725 7.1518 -8.3376 18.1272 18.3641 -27.0961 50.9967 0.0000 0.0000 8.7642 -5.6514 -4.5997 -0.4661 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 4.6656 10.6730 -12.5138 19.8558 39.8223 -60.0507 -0.0000 0.0000 4.2586 -5.9712 2.2915 -4.6530 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -25.9961 -6.1705 -4.2065 0.3734 0.0000 0.0000 14.3561 3.5864 6.5096 0.0092 0.0000 0.0000 -3.9808 -10.9778 11.8730 39.9070 0.0000 0.0000 -4.9022 5.4364 -19.4478 -13.8807 0.0000 -0.0000 0.6827 41.4098 24.0071 -11.8647 -3.1868 174.3346 -1.5429 -3.3933 0.7451 -1.7768 -3.3677 -0.0342 11.8509 1.5470 9.3768 -4.3979 -0.7467 2.4114 -33.4296 -3.4555 -2.8823 -2.7277 -6.5759 -2.7552 7.9510 -8.9349 17.4369 22.9569 -25.9862 50.5737 0.0000 0.0000 6.5181 1.2107 -12.1084 -0.5439 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 4.6387 9.7597 -14.3485 18.8705 35.0290 -59.4097 -0.0000 0.0000 3.6319 -2.1293 6.0148 -5.1226 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -24.2970 -8.2572 -4.7653 -1.0200 0.0000 -0.0000 13.1001 3.6086 3.8517 -0.1369 0.0000 -0.0000 -10.7752 -16.0886 9.4873 49.7937 0.0000 0.0000 -1.6420 7.8659 -18.8941 -11.3904 0.0000 -0.0000 0.9028 41.8922 24.0515 -11.7965 -4.7734 176.0246 -1.5055 -3.2795 0.6832 -1.7703 -2.8922 0.0230 12.6807 -0.6116 9.0016 -4.1603 -2.4530 3.0297 -31.2616 -7.2532 -7.2187 -1.8590 -8.3819 -3.5341 8.3078 -10.7407 15.5138 26.2281 -24.3523 50.2131 0.0000 0.0000 5.6063 5.8009 -15.3488 -0.4174 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 3.9793 9.1485 -15.1961 18.0100 30.8070 -59.0896 -0.0000 0.0000 3.4504 2.0556 7.4658 -5.4313 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -22.1300 -9.6381 -4.8682 -2.3383 0.0000 -0.0000 12.2244 3.6674 2.1456 -0.3920 0.0000 -0.0000 -15.8436 -19.0957 8.3089 56.3509 0.0000 0.0000 -2.2224 8.9429 -15.0109 -11.4383 0.0000 -0.0000 0.9781 42.4018 24.1469 -10.4041 -5.0134 176.6939 -0.8043 -2.9994 0.6905 -1.4926 -2.1819 0.1415 13.3520 -2.2347 8.8709 -3.6158 -3.9932 3.6676 -27.8981 -10.2080 -9.8877 -0.4004 -9.0251 -3.8787 7.9259 -12.3119 12.9289 27.6092 -23.6075 50.6672 0.0000 0.0000 5.1718 5.8118 -14.0186 -1.1577 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 2.8573 7.4535 -15.3672 16.7101 29.2367 -58.2562 -0.0000 0.0000 3.1857 1.8046 6.4929 -5.3734 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -19.3086 -9.7802 -4.5847 -2.4325 0.0000 -0.0000 10.8671 3.8823 1.3563 -0.5556 0.0000 -0.0000 -17.7710 -19.7729 8.9976 58.6339 0.0000 0.0000 -5.6563 7.6918 -9.3771 -12.2447 0.0000 -0.0000 0.9286 42.8970 24.2809 -8.6737 -4.2842 177.1748 0.1317 -2.6997 0.6380 -1.0862 -1.6059 0.1951 13.7351 -3.4181 8.3966 -2.8583 -5.0207 4.0272 -24.2806 -11.8001 -10.3227 1.6808 -8.6135 -3.8016 7.1838 -13.2881 10.6229 27.1495 -24.0913 51.5996 0.0000 0.0000 5.3266 3.0587 -10.2932 -1.6053 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 1.7618 5.6107 -15.0375 14.5250 28.3225 -56.2680 -0.0000 0.0000 2.6874 -1.5906 5.1596 -5.1512 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -17.0168 -8.7079 -4.1161 -0.9173 0.0000 -0.0000 8.6381 4.0855 0.8188 -0.6556 0.0000 -0.0000 -18.4201 -18.6591 10.1488 57.3500 0.0000 0.0000 -8.5796 5.5189 -5.0124 -12.5194 0.0000 -0.0000 0.8333 43.3611 24.4120 -7.3474 -3.0971 178.0622 0.8088 -2.4723 0.5203 -0.7796 -1.2357 0.1911 14.0873 -4.2222 7.6404 -2.1903 -5.4085 4.0489 -21.2482 -12.1008 -9.6104 3.7215 -8.0055 -3.7584 6.5338 -13.8004 9.1474 25.4636 -25.6452 52.1713 0.0000 0.0000 6.5858 -1.1202 -6.3144 -1.2002 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.9448 4.5151 -14.3211 11.7828 25.7744 -54.0170 -0.0000 0.0000 2.0367 -3.3745 4.5725 -4.8763 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.2256 -6.9880 -3.5967 0.6678 0.0000 0.0000 6.5053 4.2318 -0.0336 -0.7881 0.0000 -0.0000 -19.4201 -16.6241 10.5585 53.7506 0.0000 0.0000 -9.7009 4.2492 -3.5425 -11.6164 0.0000 -0.0000 0.7620 43.8090 24.5183 -6.1663 -2.0684 179.3099 1.3672 -2.4323 0.4110 -0.5266 -1.0231 0.1747 14.6957 -4.6703 7.0868 -1.7567 -5.4322 3.9680 -19.2160 -11.8173 -9.1175 5.0038 -7.9686 -4.2306 6.0250 -13.8365 8.5204 23.2655 -27.9603 51.8595 0.0000 0.0000 8.9404 -6.2552 -2.4659 -0.4008 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.2567 3.8713 -13.5876 8.9972 21.9662 -52.5867 -0.0000 0.0000 1.3050 -2.3739 3.6587 -4.6598 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -12.9458 -5.4908 -3.3976 0.9296 0.0000 0.0000 5.1425 4.4837 -1.0185 -0.8533 0.0000 -0.0000 -20.4586 -14.7834 10.6104 48.4461 0.0000 0.0000 -9.5484 3.9118 -4.5248 -9.5968 0.0000 -0.0000 0.7322 44.2266 24.5824 -5.2332 -1.7660 -179.3640 1.9751 -2.7405 0.3611 -0.2646 -0.9538 0.1513 15.1234 -4.9356 6.9211 -1.4932 -5.4660 3.9971 -17.9273 -11.8379 -9.4551 5.4561 -8.5394 -5.4180 5.6198 -13.2521 8.4080 20.9837 -30.7739 50.9962 0.0000 0.0000 11.5811 -10.1696 1.5352 0.4144 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.3988 3.1172 -13.2235 6.2651 18.6773 -51.9595 -0.0000 0.0000 0.5411 -1.5310 1.4884 -4.4904 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -10.5916 -4.9013 -3.8430 0.3737 0.0000 0.0000 4.1423 4.7611 -1.6684 -0.7715 0.0000 -0.0000 -21.5329 -13.9612 11.1242 41.8713 0.0000 0.0000 -8.7380 3.9846 -6.8290 -7.5380 0.0000 -0.0000 0.7380 44.5820 24.5875 -5.2265 -2.5014 -178.0802 2.3796 -3.4522 0.3831 -0.0935 -1.0246 0.1153 14.7774 -5.2779 6.8809 -1.2671 -5.6800 4.1466 -16.9195 -12.7558 -10.5063 5.4128 -9.3253 -7.0230 5.3991 -12.2589 8.3655 18.8541 -33.5801 50.4799 0.0000 0.0000 13.6003 -10.9948 5.3296 0.8511 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.9756 2.1835 -13.1989 3.6295 16.6956 -51.6454 -0.0000 -0.0000 -0.3143 -2.8393 -1.0812 -4.3504 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -9.4748 -5.4858 -5.0674 0.0459 0.0000 0.0000 3.1064 4.8898 -1.6986 -0.7045 0.0000 -0.0000 -23.6940 -14.2198 12.1310 34.6705 0.0000 0.0000 -7.0489 4.3221 -9.9532 -6.6082 0.0000 -0.0000 0.7718 44.9025 24.5441 -6.0034 -4.0190 -176.9671 2.4271 -4.3220 0.4580 -0.0788 -1.1003 0.0712 14.0277 -5.7947 6.7375 -1.0262 -6.1203 4.3607 -16.0747 -14.5536 -11.8393 5.2834 -10.0528 -8.4010 5.2738 -11.5734 8.0638 16.9646 -35.5879 50.7620 0.0000 0.0000 14.7751 -9.8860 7.9260 0.6424 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.4916 1.1960 -13.4164 1.3447 15.5961 -51.2012 -0.0000 -0.0000 -1.4629 -4.9788 -2.9198 -4.4935 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -9.4265 -6.9337 -6.7225 -0.0622 0.0000 -0.0000 2.1703 4.9320 -1.3116 -0.7745 0.0000 -0.0000 -26.8706 -14.8708 12.9874 27.0028 0.0000 0.0000 -3.2016 5.3837 -13.4341 -8.1466 0.0000 -0.0000 0.8140 45.2827 24.4821 -6.1796 -5.7265 -176.1964 2.7459 -5.1253 0.5581 0.0270 -0.9397 0.0574 13.5242 -6.4117 6.4939 -0.7803 -6.7875 4.6274 -15.4575 -16.6880 -13.0860 5.4763 -10.6806 -9.0549 5.1035 -11.8151 7.4176 15.2403 -36.4508 51.4983 0.0000 0.0000 15.5752 -9.1996 8.9104 0.1045 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.9696 -0.0029 -14.0134 -0.1886 14.9466 -50.3856 -0.0000 -0.0000 -2.8256 -6.0937 -4.0047 -5.0376 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -8.5389 -8.7349 -7.7940 -0.4644 0.0000 -0.0000 1.2971 5.0712 -1.1431 -0.7963 0.0000 -0.0000 -29.0947 -15.3539 13.2446 18.9890 0.0000 0.0000 3.0208 7.7477 -15.8052 -12.5786 0.0000 -0.0000 0.8419 45.7477 24.4172 -5.6577 -7.3126 -175.8547 3.3618 -5.8774 0.6807 0.3052 -0.5762 0.0636 13.2744 -6.9255 6.2575 -0.5294 -7.5250 4.9009 -15.0294 -18.5521 -14.0565 6.0775 -11.2398 -9.0297 4.9627 -12.7054 6.6461 13.6533 -37.1165 52.1203 0.0000 0.0000 16.6096 -9.2903 9.3424 -0.1624 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -2.3193 -1.4479 -14.9455 -0.7007 14.5294 -49.5236 -0.0000 -0.0000 -3.8161 -6.1865 -4.6946 -5.7161 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.7842 -10.5391 -7.8688 -0.7408 0.0000 -0.0000 0.0807 5.3563 -1.3202 -0.6119 0.0000 -0.0000 -30.3247 -15.7108 12.9840 12.3360 0.0000 0.0000 8.4118 10.6185 -15.4842 -16.3526 0.0000 -0.0000 0.8414 46.2446 24.3659 -5.5346 -8.4354 -176.0729 3.7444 -6.1766 0.7320 0.4309 -0.3073 0.0781 13.1515 -7.2254 6.1977 -0.2735 -8.0770 5.1339 -14.7449 -19.8321 -14.6358 6.6535 -11.6684 -8.7400 5.0066 -13.3199 6.1031 12.3898 -38.8238 52.4066 0.0000 0.0000 17.9664 -9.2086 10.0830 0.3227 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -2.5447 -2.5237 -15.7836 -0.3186 14.1207 -49.3253 -0.0000 -0.0000 -3.9572 -5.9931 -4.7814 -5.9404 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -5.6591 -11.7972 -7.7852 -0.2195 0.0000 -0.0000 -1.5708 5.5591 -1.0519 -0.4650 0.0000 -0.0000 -31.8965 -15.6860 13.6645 8.4034 0.0000 0.0000 9.8509 11.7874 -12.9874 -15.7448 0.0000 -0.0000 0.8150 46.7721 24.3241 -5.9842 -9.1054 -177.0266 3.7477 -6.0509 0.6842 0.3612 -0.2213 0.1047 13.2243 -7.1936 6.4540 -0.0506 -8.2983 5.3046 -14.5126 -20.6155 -14.8307 6.8882 -11.8313 -8.5041 5.1809 -13.4238 5.9889 11.7756 -41.3110 52.3989 0.0000 0.0000 19.1536 -8.8429 10.3299 1.2047 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -2.6909 -2.8794 -16.2841 0.4303 14.0603 -49.9214 -0.0000 -0.0000 -3.4868 -5.7270 -4.0686 -5.5485 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -5.2102 -12.4976 -7.9094 0.8822 0.0000 0.0000 -3.3933 5.4538 -0.0050 -0.5610 0.0000 -0.0000 -33.7495 -15.3379 16.1548 6.6305 0.0000 0.0000 8.3134 10.6483 -9.8461 -12.3669 0.0000 -0.0000 0.7714 47.3909 24.2701 -6.0634 -9.6390 -178.4130 3.8564 -5.9501 0.6460 0.4051 -0.1199 0.1435 13.4175 -6.8273 6.7704 0.0813 -8.3097 5.3417 -14.2135 -21.0016 -14.8264 7.0621 -11.7695 -8.4013 5.4246 -13.7038 6.1624 12.0618 -43.0109 52.4915 0.0000 0.0000 19.5399 -8.5270 9.3482 1.5679 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -2.6263 -2.7882 -16.6166 1.0988 15.0341 -50.7060 -0.0000 -0.0000 -3.0423 -5.5202 -3.2556 -5.0232 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -4.1042 -13.0268 -7.7461 2.0701 0.0000 0.0000 -5.4331 5.2056 1.2386 -0.5766 0.0000 -0.0000 -34.7110 -15.2293 19.0262 6.1881 0.0000 0.0000 6.4605 10.1921 -6.5440 -10.5641 0.0000 -0.0000 0.7211 48.1023 24.1804 -5.9710 -10.4941 -179.7940 4.0076 -6.1919 0.6841 0.4952 0.0508 0.1659 13.3798 -6.3888 6.7483 0.1679 -8.2121 5.2035 -13.8411 -20.9129 -14.8297 7.5935 -11.6451 -8.4062 5.8842 -14.2458 6.2841 13.5112 -43.4133 53.3945 0.0000 0.0000 18.8517 -8.0655 7.9400 1.5547 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -2.1663 -2.5648 -16.8288 1.7898 17.1525 -51.3910 -0.0000 -0.0000 -2.8544 -5.6764 -3.0225 -4.8758 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -2.6967 -13.7929 -6.9167 3.5626 0.0000 0.0000 -7.9052 5.1192 1.9335 -0.2645 0.0000 -0.0000 -34.7860 -15.6552 20.8884 6.5065 0.0000 0.0000 5.4759 11.5151 -4.0841 -11.2305 0.0000 -0.0000 0.6623 48.8662 24.0519 -6.9874 -11.6034 178.3928 3.2580 -6.4408 0.6303 0.2038 0.0977 0.1683 13.3718 -6.0832 6.5976 0.3019 -7.9704 5.0127 -13.5761 -20.3927 -14.6600 8.4112 -11.3739 -8.4134 6.5556 -14.5623 6.3677 16.0491 -42.8762 55.0876 0.0000 0.0000 17.2307 -7.2173 6.5792 2.0076 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -1.4010 -1.7014 -16.5841 2.9434 19.5517 -52.3047 -0.0000 -0.0000 -2.6566 -5.9658 -3.0803 -5.0267 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.4252 -14.7354 -5.3199 5.5329 0.0000 0.0000 -10.5242 4.9514 2.0907 -0.0671 0.0000 -0.0000 -34.5289 -16.1258 21.1825 6.1228 0.0000 0.0000 6.1557 10.8708 -3.5112 -11.5872 0.0000 -0.0000 0.5518 49.7545 23.9396 -7.9236 -11.3977 175.8536 1.9633 -5.1792 0.0977 -0.4286 0.1586 0.2192 14.5550 -5.8135 6.7170 0.4099 -7.6603 4.8010 -13.5913 -19.9658 -13.8767 9.0974 -10.6681 -8.2809 6.9379 -15.7712 7.1566 18.2683 -40.5965 55.3873 0.0000 0.0000 15.2045 -6.0418 4.0301 2.4332 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.5532 0.8422 -15.5952 4.6182 21.2246 -53.3310 -0.0000 -0.0000 -2.3642 -5.9581 -3.1999 -5.0005 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.3300 -14.1373 -3.5529 6.8861 0.0000 0.0000 -12.8759 3.8876 2.9432 -0.3350 0.0000 -0.0000 -31.6804 -14.9292 18.7498 3.0847 0.0000 0.0000 9.2733 5.7294 -2.2423 -10.4293 0.0000 -0.0000 0.3433 50.9359 23.8997 -4.8977 -8.3544 173.9495 2.2368 -1.2327 -0.6200 -0.5170 0.8893 0.3674 17.1535 -5.1781 6.4117 0.3368 -7.5408 4.3006 -13.3389 -20.0330 -12.7651 9.5884 -9.6112 -8.2759 6.7721 -19.3307 8.7539 18.8749 -36.6194 52.5981 0.0000 0.0000 13.2789 -4.6101 0.1526 1.5912 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.4239 4.4052 -14.3239 6.3859 22.9007 -53.4651 -0.0000 -0.0000 -2.4823 -6.2260 -3.9620 -4.9315 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 5.0021 -9.7225 -2.6759 6.4779 0.0000 0.0000 -15.0658 1.7875 4.9059 -0.5875 0.0000 -0.0000 -22.3167 -10.3743 13.0002 -3.2340 0.0000 -0.0000 14.6484 -0.5467 3.3417 -8.2055 0.0000 -0.0000 0.0494 52.2065 23.9145 -0.1713 -3.7209 173.7147 3.3922 3.0895 -0.8108 0.1455 2.5455 0.5312 18.7699 -3.9458 4.5650 0.2235 -7.5450 3.2801 -11.7800 -19.8892 -12.3453 10.2587 -8.4954 -9.1005 6.3342 -23.2515 9.3993 18.3685 -34.3028 49.1027 0.0000 0.0000 11.4229 -3.3163 -2.1773 -0.7605 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 1.6918 6.4822 -13.5369 8.3497 26.6758 -52.6054 -0.0000 -0.0000 -3.2500 -7.2670 -5.5701 -5.5634 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 12.2512 -3.1434 -3.8542 6.8529 0.0000 0.0000 -17.1352 -0.1709 6.2894 -0.7030 0.0000 -0.0000 -12.2002 -4.0961 7.3210 -8.4998 0.0000 -0.0000 18.6474 -3.0608 9.3399 -5.9499 0.0000 -0.0000 -0.3148 53.1315 24.0199 0.3189 -0.2127 175.3741 3.2841 4.9295 -0.9006 0.3024 3.9349 0.5253 18.3686 -3.0901 1.3631 0.3762 -6.9701 1.9809 -9.4018 -18.2228 -12.5846 11.3554 -6.8496 -10.8144 5.3132 -23.8213 7.9788 17.1684 -36.3285 47.1852 0.0000 0.0000 9.8718 -3.2307 -1.1271 -3.3270 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 2.8933 7.5636 -12.8728 11.3631 31.2251 -52.4853 -0.0000 -0.0000 -3.7289 -7.8494 -6.4266 -6.6554 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 11.7193 1.4703 -5.6813 12.5057 0.0000 0.0000 -18.2202 -0.8248 5.7418 -1.6349 0.0000 -0.0000 -9.8065 0.5228 2.7346 -8.6298 0.0000 -0.0000 17.3544 -2.0146 13.1289 -5.4266 0.0000 -0.0000 -0.6688 53.7586 24.1814 -2.2038 0.5878 176.3889 2.3570 4.2583 -0.9030 -0.1128 3.9441 0.3775 16.7983 -2.8045 -1.2025 0.8587 -5.4973 1.0002 -6.4936 -14.1167 -12.1171 13.0013 -4.2728 -12.1641 3.5925 -19.6184 5.3853 15.7022 -41.7899 45.9511 0.0000 0.0000 9.5453 -5.1681 -0.4654 -4.0285 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 3.7029 8.6694 -11.5352 16.2345 34.6100 -54.7031 -0.0000 -0.0000 -2.7837 -6.4458 -4.8467 -6.8174 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 4.0744 3.2093 -4.1117 24.1427 0.0000 0.0000 -16.6653 -1.1471 3.5276 -4.0539 0.0000 -0.0000 -12.0484 2.2225 2.2504 -5.9944 0.0000 -0.0000 13.5243 -1.9121 13.2908 -5.7576 0.0000 -0.0000 -0.9944 54.3657 24.2920 -3.8899 1.1786 173.9270 1.5718 3.7587 -0.7670 -0.5666 3.2139 0.2863 15.5641 -2.0740 -1.4546 1.3438 -3.8052 0.5763 -3.1527 -7.9983 -9.8516 14.4986 -1.2601 -11.5624 1.8828 -14.5576 3.5952 12.5058 -44.9093 42.5587 0.0000 0.0000 10.9747 -7.6087 -4.3120 -3.4213 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 3.8970 9.7358 -9.3796 22.2311 36.5469 -58.3252 -0.0000 -0.0000 -0.3546 -3.4237 -0.7681 -6.0986 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -5.5068 4.6987 0.7573 38.7407 0.0000 0.0000 -11.9651 -2.8626 2.9337 -6.7049 0.0000 -0.0000 -13.3018 3.1870 5.9683 -3.6600 0.0000 -0.0000 10.6551 -4.0600 11.9761 -5.5455 0.0000 -0.0000 -1.3127 55.1235 24.3076 -2.5392 3.7245 169.4656 1.6673 5.0500 -0.7457 -0.6078 3.0719 0.3493 15.4303 -0.5419 -0.3408 1.5965 -2.4907 0.3134 -0.2393 -1.4760 -6.3184 15.0735 0.7813 -8.7825 1.2593 -13.1187 3.0444 6.3121 -41.6055 37.2540 0.0000 0.0000 13.8262 -7.7969 -8.7880 -2.7699 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 3.5249 10.2810 -7.1911 27.0272 38.2659 -60.6031 -0.0000 0.0000 2.4923 0.6141 4.5840 -5.6366 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -12.6907 7.5935 7.2982 52.2823 0.0000 0.0000 -6.4623 -4.4422 4.8113 -6.8687 0.0000 -0.0000 -10.7792 6.1141 9.2270 -3.0465 0.0000 -0.0000 8.9331 -5.8356 13.3332 -4.9140 0.0000 -0.0000 -1.5770 55.9203 24.2576 -0.2795 6.8309 166.4599 1.8137 6.8499 -0.8229 -0.5421 3.5722 0.4550 15.7535 1.1781 0.0518 1.6829 -1.4762 -0.2189 1.1862 3.6150 -2.8056 15.3164 1.0154 -5.3236 2.0702 -14.3152 2.9672 -1.4270 -35.0387 32.4593 0.0000 0.0000 17.5771 -6.3187 -7.6945 -1.8326 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.0973 10.5635 -5.6139 28.7377 40.0473 -59.8368 -0.0000 0.0000 4.4155 4.5267 8.4993 -5.6166 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -18.0866 10.4780 12.6618 62.6648 0.0000 0.0000 -3.7754 -4.5064 6.6121 -4.2518 0.0000 -0.0000 -7.0663 10.3146 10.2690 -3.7708 0.0000 -0.0000 7.2698 -6.0858 15.4767 -4.6205 0.0000 -0.0000 -1.7364 56.5993 24.2157 0.1712 8.6489 166.4587 1.4761 7.6836 -0.9053 -0.6672 3.7744 0.4499 15.7812 2.4258 -0.8050 1.7164 -0.4977 -1.0106 1.1923 6.2538 -0.3314 15.7020 0.5805 -2.7607 3.2614 -14.7852 2.7299 -9.0723 -29.8592 28.4144 0.0000 0.0000 21.0667 -6.4505 -1.2280 -1.4499 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.0684 11.6967 -4.3748 27.3300 40.1340 -56.3403 -0.0000 0.0000 4.5013 5.4995 8.2046 -5.2631 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -23.2000 11.5655 14.6377 69.1328 0.0000 0.0000 -4.6825 -3.9722 5.9067 -2.0573 0.0000 -0.0000 -5.0169 13.1263 10.6967 -4.4611 0.0000 -0.0000 5.4220 -6.2592 14.8849 -4.7158 0.0000 -0.0000 -1.7697 57.1894 24.2372 -0.5242 8.6957 168.2481 1.1848 7.6464 -0.9876 -0.8007 3.4157 0.3422 15.5205 3.0182 -2.0087 1.7182 0.3808 -1.7307 0.9438 7.0844 0.7419 15.6503 0.7907 -1.6165 3.5052 -13.6687 2.3680 -15.5271 -26.2945 24.2212 0.0000 0.0000 23.1936 -8.1645 4.9391 -2.3083 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 3.4621 13.9124 -2.9761 24.0572 38.4065 -51.7117 -0.0000 0.0000 2.7079 2.6270 3.5514 -4.7980 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -27.1936 10.8114 13.8249 71.2804 0.0000 0.0000 -7.0171 -3.2723 2.6096 -2.2265 0.0000 -0.0000 -4.2492 13.6966 11.8536 -3.9732 0.0000 -0.0000 3.5408 -6.8559 11.6497 -4.7723 0.0000 -0.0000 -1.7068 57.7709 24.3052 -0.9211 7.9039 170.1321 1.2099 7.5369 -1.0498 -0.7899 3.0290 0.2322 15.1638 3.1958 -2.8162 1.7254 0.8777 -2.1756 1.1892 7.3252 0.7984 15.0835 1.7184 -1.7529 2.5120 -12.0985 2.3146 -20.2832 -22.4216 20.1388 0.0000 0.0000 23.9584 -8.8204 7.2745 -4.2988 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 3.8105 15.8349 -1.1992 19.9186 37.5161 -47.3374 -0.0000 0.0000 0.0515 -2.6138 -2.8545 -5.6986 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -29.5726 9.2572 12.3968 69.5721 0.0000 0.0000 -8.4402 -1.9997 -1.3692 -3.2181 0.0000 -0.0000 -3.5646 13.0190 13.0038 -2.3540 0.0000 -0.0000 1.3941 -7.0579 8.5128 -4.6310 0.0000 -0.0000 -1.6057 58.3398 24.3650 -1.1878 7.1763 171.7241 1.2081 7.6908 -1.0908 -0.7761 2.8939 0.1725 14.7693 3.1199 -3.3212 1.7765 1.0032 -2.4630 1.6432 7.7230 0.4537 14.7737 2.8289 -2.5905 0.9590 -10.5276 2.4533 -23.6911 -18.1612 17.0942 0.0000 0.0000 24.4153 -7.9884 6.5601 -5.9732 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 3.5534 16.3061 0.8640 15.4251 39.0379 -43.4425 -0.0000 -0.0000 -2.2181 -7.8674 -7.8728 -7.8609 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -31.4943 7.7860 11.4598 65.1772 0.0000 0.0000 -7.9565 -0.5905 -4.0999 -3.4354 0.0000 -0.0000 -2.8858 12.1347 13.7758 -0.5666 0.0000 -0.0000 -0.9569 -6.6806 6.2208 -4.2785 0.0000 -0.0000 -1.4968 58.8780 24.3956 -1.7045 6.5427 173.1657 0.9746 7.8933 -1.0893 -0.8615 2.7356 0.1171 14.4955 2.8823 -3.8227 1.8283 1.0967 -2.7660 1.7858 8.5460 0.2387 15.0499 3.8627 -3.2115 -0.6454 -8.7873 2.3790 -26.4158 -14.6313 15.4077 0.0000 0.0000 25.4806 -7.0349 5.5990 -6.2633 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 2.7881 16.0870 2.7398 11.3976 40.4880 -39.9998 -0.0000 -0.0000 -3.4202 -10.1970 -10.3130 -8.4661 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -33.5211 6.7836 10.5887 58.6600 0.0000 0.0000 -5.6404 0.1874 -4.6834 -3.1386 0.0000 -0.0000 -2.3318 11.2611 14.5426 0.6910 0.0000 0.0000 -3.1261 -6.2945 3.9395 -3.7329 0.0000 -0.0000 -1.3876 59.4105 24.4037 -2.1627 5.9987 174.3870 0.6271 7.9788 -1.0522 -0.9754 2.3728 0.0352 14.4631 2.7457 -4.2930 1.8474 1.4236 -3.1164 1.6978 9.7594 0.5183 15.4066 4.8405 -2.9870 -2.0656 -7.3397 2.1227 -29.0903 -12.0247 14.9061 0.0000 0.0000 27.2951 -6.2727 5.6860 -5.7140 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 2.0149 16.1186 4.0509 9.6737 39.0647 -38.3470 -0.0000 -0.0000 -3.3469 -8.9936 -10.9358 -6.5517 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -34.9434 6.5075 9.2197 49.9809 0.0000 0.0000 -1.6384 0.2681 -2.9428 -2.7703 0.0000 -0.0000 -1.7361 10.4325 15.2216 1.7479 0.0000 0.0000 -5.0477 -5.9392 1.8543 -3.3469 0.0000 -0.0000 -1.2900 59.9613 24.3861 -2.4288 5.8490 175.3766 0.2096 7.9641 -1.0073 -1.1040 2.0008 -0.0374 14.5510 2.9172 -4.5841 1.9110 1.9745 -3.4273 1.6890 11.1415 1.2067 15.3823 5.7548 -2.0897 -3.1575 -6.6265 1.9215 -31.9036 -9.8272 15.0110 0.0000 0.0000 29.9237 -4.4208 6.5067 -5.0699 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 1.5877 15.9237 4.7683 10.6416 35.8661 -38.8398 -0.0000 -0.0000 -2.4560 -6.4288 -11.0033 -4.5859 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -35.5536 7.0548 7.1359 39.7098 0.0000 0.0000 3.7983 -0.3004 0.6185 -2.3648 0.0000 -0.0000 -1.1007 9.9369 15.6340 3.0617 0.0000 0.0000 -6.9527 -5.2965 0.4244 -3.4389 0.0000 -0.0000 -1.2100 60.5265 24.3427 -2.7703 6.0493 176.2228 -0.3167 7.7839 -0.8835 -1.3193 1.7096 -0.0736 14.6921 3.3310 -4.6485 2.0097 2.5713 -3.6350 1.6297 12.5193 1.8555 15.0969 6.6976 -1.1912 -3.9134 -6.4196 1.8939 -34.5202 -7.6252 15.0410 0.0000 0.0000 33.5576 -1.3186 7.9889 -4.4543 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 1.3778 15.1807 5.0718 12.0225 33.6389 -39.7743 -0.0000 -0.0000 -1.6267 -4.8540 -11.3102 -3.9047 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -35.9728 7.9297 4.0581 29.0748 0.0000 0.0000 9.6024 -1.7677 4.9276 -2.0913 0.0000 -0.0000 -0.3999 9.8258 15.7660 4.1547 0.0000 0.0000 -8.7335 -4.5469 -0.5626 -3.6376 0.0000 -0.0000 -1.1384 61.1222 24.2871 -3.0230 6.3296 177.0337 -0.7245 7.4916 -0.6839 -1.4551 1.3350 -0.1119 14.8157 3.8031 -4.4998 2.0265 3.0844 -3.7582 1.2767 13.8942 2.1276 14.9138 7.8980 -0.8388 -4.3465 -6.2505 1.9612 -36.8443 -5.8111 14.6870 0.0000 0.0000 38.1384 1.6943 10.2833 -3.8096 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 1.0664 14.6301 5.2579 12.0155 33.1846 -39.9011 -0.0000 -0.0000 -1.3097 -4.1987 -11.3607 -3.0851 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -36.1902 8.5782 -0.1415 19.3121 0.0000 0.0000 13.8404 -4.0577 9.1144 -2.0042 0.0000 -0.0000 0.9723 9.9621 15.1602 4.2058 0.0000 0.0000 -9.9940 -3.9801 -1.0900 -3.4998 0.0000 -0.0000 -1.0643 61.7722 24.2273 -2.9453 6.7531 178.1552 -0.7982 7.3493 -0.5602 -1.3361 0.8974 -0.1782 14.7003 4.1866 -4.3271 1.9236 3.4819 -3.8504 0.8420 15.2907 1.9887 14.9270 9.3164 -1.2127 -4.4086 -6.0084 1.8993 -39.1287 -5.3036 13.9253 -0.0000 0.0000 43.5772 4.5807 12.7454 -3.3502 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.6606 14.6119 5.5342 11.0888 33.7521 -39.4364 -0.0000 -0.0000 -1.5328 -4.4212 -11.1837 -1.5322 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -36.1852 9.1277 -4.7070 11.9207 0.0000 0.0000 15.0403 -6.3492 12.2177 -1.7215 0.0000 -0.0000 3.2720 10.3115 13.5127 3.2990 0.0000 0.0000 -10.5877 -3.3608 -1.0483 -3.2656 0.0000 -0.0000 -0.9797 62.4416 24.1695 -3.2369 7.3524 179.9732 -0.9672 7.2434 -0.5031 -1.2639 0.7410 -0.2074 14.4569 4.3812 -4.4255 1.7927 3.7315 -3.9815 0.4868 16.6116 1.5138 14.8395 10.5551 -2.0738 -4.3451 -6.0942 1.6680 -41.1586 -6.0451 12.7382 -0.0000 0.0001 49.7247 8.0578 14.4884 -2.7708 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.3162 14.8406 5.8111 10.4956 34.5070 -39.2125 -0.0000 -0.0000 -2.1646 -5.9290 -11.4674 -1.2356 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -36.6952 9.8570 -8.9586 7.1640 0.0000 0.0000 13.9530 -7.2238 12.7676 -1.4601 0.0000 -0.0000 5.2417 10.6078 11.5930 2.4844 0.0000 0.0000 -10.8180 -2.4113 -1.1108 -3.2222 0.0000 -0.0000 -0.8775 63.1173 24.1120 -4.0839 7.9880 -177.7537 -1.4011 7.1439 -0.3170 -1.3975 0.7773 -0.2091 14.3135 4.4036 -4.7444 1.6892 3.7931 -4.0953 0.0764 17.7598 0.8812 14.4211 11.4486 -2.9553 -4.3468 -6.6305 1.5477 -42.2765 -7.0941 11.3230 -0.0000 0.0001 55.5611 10.6989 15.8479 -0.9372 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.1527 15.3836 5.8358 10.5488 34.9243 -39.4210 -0.0000 -0.0000 -3.0831 -6.9015 -11.7993 -2.9402 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -37.4197 10.4475 -12.8262 3.7134 0.0000 0.0000 11.9921 -5.8901 9.8554 -1.5939 0.0000 -0.0000 6.4527 10.6887 10.1413 2.1966 0.0000 0.0000 -11.0586 -1.3025 -1.8421 -3.1445 0.0000 -0.0000 -0.7637 63.8497 24.0476 -4.6459 8.4608 -175.6139 -1.6844 7.0764 -0.0797 -1.4789 0.6357 -0.2341 14.2096 4.2004 -4.8515 1.5751 3.7585 -4.0699 -0.4339 18.7771 0.4205 13.8585 12.2682 -3.5960 -4.0927 -7.3513 1.7860 -42.2382 -8.0715 10.2547 -0.0000 0.0001 59.5175 10.9009 17.9874 2.2480 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.2283 16.4279 5.6600 11.2245 34.9357 -40.0857 -0.0000 -0.0000 -3.9664 -6.3577 -11.8198 -4.6255 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -37.1621 10.6001 -16.0106 1.3452 0.0000 0.0000 9.3080 -3.2622 4.6614 -1.4354 0.0000 -0.0000 7.8001 10.4262 9.2322 2.4340 0.0000 0.0000 -11.6304 -0.1359 -3.1068 -3.0685 0.0000 -0.0000 -0.6645 64.6515 23.9663 -5.0370 8.7469 -173.1944 -2.0288 6.7994 -0.0358 -1.5685 0.4491 -0.2708 14.1313 3.7352 -4.8107 1.4498 3.6923 -3.9441 -0.9363 19.7358 0.2172 13.3888 13.0287 -4.0495 -3.5120 -8.1347 2.1653 -41.2247 -9.4045 9.7259 -0.0000 0.0001 60.9693 10.1181 20.7190 5.5240 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.4120 17.2941 5.5105 13.3045 35.0637 -41.8131 -0.0000 -0.0000 -4.1870 -5.6525 -11.7574 -5.2962 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -35.6516 11.3050 -18.8153 1.0361 0.0000 0.0000 6.5866 -1.1095 0.9244 -0.9892 0.0000 -0.0000 8.6747 9.6692 9.2766 4.2220 0.0000 0.0000 -12.8313 1.4623 -5.4336 -3.5322 0.0000 -0.0000 -0.5714 65.5018 23.8239 -6.1396 8.7274 -169.3844 -3.0107 6.1219 -0.0188 -2.1297 0.6019 -0.2564 14.3152 2.9662 -5.2504 1.3409 3.4357 -3.8633 -1.5943 20.4926 -0.0469 12.9122 13.3234 -4.4524 -3.2245 -9.1885 2.3426 -39.5453 -10.7581 9.2990 -0.0000 0.0001 60.2664 10.8503 22.0889 7.6965 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.5074 17.4854 5.1744 17.1771 35.0774 -44.7398 -0.0000 -0.0000 -3.4526 -5.1061 -10.3646 -5.6034 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -33.0920 13.2405 -21.6510 1.9617 0.0000 0.0000 6.6574 -0.0229 0.1356 -1.2607 0.0000 -0.0000 7.8104 8.0328 10.5920 8.4019 0.0000 0.0000 -14.8186 3.6484 -9.8602 -4.2901 0.0000 -0.0000 -0.4342 66.3965 23.5953 -7.6731 7.3302 -165.0628 -4.6977 4.1108 0.3987 -3.3803 0.8777 -0.1937 15.2825 2.0581 -5.7282 1.0746 2.9791 -3.7340 -3.2427 20.9591 -0.4162 12.1884 13.0810 -4.8891 -3.6185 -11.1792 2.6648 -37.6476 -10.2466 9.1266 -0.0000 0.0001 57.0982 12.2136 21.2574 8.4990 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0333 18.5371 4.1414 21.0097 33.3385 -46.7688 -0.0000 -0.0000 -2.3555 -3.7625 -5.3922 -5.9805 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -29.8295 13.9370 -24.2614 1.6501 0.0000 0.0000 11.3448 1.3066 0.0693 -1.4754 0.0000 -0.0000 5.6906 4.5603 11.8316 13.8305 0.0000 0.0000 -17.7572 5.7657 -14.6586 -4.5067 0.0000 -0.0000 -0.2386 67.3676 23.3913 -7.3437 3.2847 -163.4882 -6.1000 -0.9581 0.9036 -5.0117 -0.0606 -0.2725 17.6212 1.6132 -4.3454 0.4023 2.8431 -3.1851 -6.6253 21.4863 -0.2187 11.3311 12.7134 -5.4099 -4.2835 -14.0428 4.0531 -35.6370 -7.3055 10.0147 -0.0000 0.0001 49.9282 10.1485 20.4993 7.9835 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.5329 21.9810 2.6475 22.7241 29.7545 -45.7305 -0.0000 -0.0000 -1.5255 -1.9022 2.6787 -6.2097 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -25.4468 9.3450 -26.3434 -1.7256 0.0000 -0.0000 17.7106 3.4036 -0.6936 -0.5305 0.0000 -0.0000 4.9431 -1.7524 12.8058 18.5510 0.0000 0.0000 -21.0517 7.4118 -17.0530 -5.0317 0.0000 -0.0000 -0.0454 68.3520 23.3485 -5.1148 -1.7519 -165.6822 -6.1871 -6.6489 0.8207 -5.6761 -3.8437 -0.9737 19.3551 1.9064 -0.4167 -0.3777 3.6016 -2.1070 -10.4195 21.6797 0.9273 10.6145 12.2872 -5.9697 -4.3845 -15.6828 6.8060 -33.4420 -5.5913 11.4631 -0.0000 0.0000 38.7770 4.4455 20.3891 4.0102 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -3.4214 24.8941 1.8017 23.0480 28.0442 -43.8985 -0.0000 -0.0000 -0.3302 -0.6470 9.6417 -5.7248 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -20.7571 1.1841 -27.3403 -5.9487 0.0000 -0.0000 20.5507 5.3775 -0.3950 0.6033 0.0000 0.0000 6.1884 -8.9369 15.0378 23.0664 0.0000 0.0000 -21.8339 8.4464 -17.2051 -8.1040 0.0000 -0.0000 0.0678 69.0905 23.5066 -4.9670 -3.9461 -169.1877 -5.7686 -9.1207 0.5923 -5.0192 -7.0618 -1.4532 18.2394 1.8559 3.9651 -0.7760 4.3360 -0.8864 -12.7596 19.9583 1.9722 9.5982 10.8895 -6.4579 -3.8938 -15.6224 10.1229 -31.7100 -8.0117 12.6722 0.0000 0.0000 26.9667 -0.5501 16.9531 -4.5705 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.1280 23.6460 1.5030 22.7681 30.0349 -43.7793 -0.0000 0.0000 1.6651 0.4287 12.5267 -4.7459 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -19.7386 -2.9573 -27.6926 -5.7291 0.0000 -0.0000 17.8652 5.9518 2.4985 1.1049 0.0000 0.0000 3.8702 -12.4523 16.1648 30.6443 0.0000 0.0000 -17.1627 8.8127 -16.0935 -13.4960 0.0000 -0.0000 0.1528 69.6724 23.7646 -5.2223 -2.8845 -170.1118 -4.5905 -8.8974 0.3880 -3.5043 -6.3721 -1.0611 15.1210 0.8100 5.9080 -0.9675 3.6444 -0.0442 -13.4864 14.2617 1.4070 8.0695 7.6385 -7.0902 -2.7860 -14.9795 12.6971 -28.8389 -13.3585 13.3881 0.0000 0.0000 18.3801 -3.2243 7.5713 -10.2990 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -3.2810 18.3076 0.3328 22.0497 32.3391 -44.2669 -0.0000 0.0000 3.0197 2.2950 12.9496 -4.4029 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -18.9484 -2.2669 -28.9027 -3.8359 0.0000 -0.0000 14.4101 4.4959 5.5894 0.9022 0.0000 0.0000 -1.9734 -13.3243 13.9156 41.1781 0.0000 0.0000 -7.9113 9.9038 -15.7735 -16.2526 0.0000 -0.0000 0.3119 70.2051 23.9782 -4.4639 -1.5971 -168.1176 -2.7067 -8.0382 0.2711 -2.2372 -4.2604 -0.5869 12.3103 0.1535 5.3904 -1.3774 1.8379 0.3772 -14.1088 4.9718 -1.1684 6.0191 2.3789 -8.1891 -0.4678 -13.9292 13.6554 -20.1892 -18.1053 16.6902 0.0000 0.0000 14.7824 -2.7728 -5.2488 -8.4038 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -1.9045 13.2295 -2.0936 19.6834 29.7623 -42.8035 -0.0000 0.0000 2.5775 3.8510 12.7789 -4.9060 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -16.7192 -0.9204 -29.9006 -2.8575 0.0000 -0.0000 12.6836 2.7255 5.5650 0.3742 0.0000 0.0000 -8.8903 -14.5184 9.6298 51.7659 0.0000 0.0000 -0.0465 11.2778 -17.4212 -14.3130 0.0000 -0.0000 0.5090 70.6952 24.1072 -3.3103 -1.4116 -166.3583 -0.8845 -7.5987 0.3220 -1.4465 -2.9582 -0.3321 11.0750 0.0100 5.0747 -1.8844 -0.1126 0.8801 -15.7248 -4.7952 -5.1284 3.2400 -3.2168 -9.6701 3.0132 -12.2276 13.5559 -8.3307 -18.6582 24.5859 0.0000 0.0000 14.4555 0.3715 -13.2659 -0.9176 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.7762 11.7084 -5.0320 14.9547 22.4491 -39.2950 -0.0000 0.0000 1.1247 2.7762 9.9560 -4.9016 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -14.4471 -1.1863 -29.4645 -2.3458 0.0000 -0.0000 11.1630 2.2671 3.6309 -0.1304 0.0000 -0.0000 -15.2760 -16.6880 6.2900 59.8764 0.0000 0.0000 2.4573 12.1839 -19.6830 -12.3046 0.0000 -0.0000 0.6513 71.1455 24.1714 -2.4792 -1.6280 -166.7813 0.1666 -7.2567 0.4654 -0.9651 -2.6184 -0.1939 11.0565 -0.3886 6.1694 -2.1718 -1.6288 1.7591 -17.4218 -12.1813 -9.0185 0.6376 -6.4108 -11.0174 5.8376 -10.1212 13.0546 -2.0849 -17.2971 33.3710 0.0000 0.0000 13.9737 1.2103 -15.9779 3.0430 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.7054 11.2116 -7.4949 9.1740 16.8685 -36.3006 -0.0000 0.0000 0.1402 -1.1644 3.1310 -4.1323 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -12.7286 -2.3471 -28.0312 -2.1133 0.0000 -0.0000 9.5027 3.0641 2.8410 -0.4765 0.0000 -0.0000 -20.1713 -18.9889 5.6877 64.1211 0.0000 0.0000 1.6048 12.7143 -20.3131 -11.4937 0.0000 -0.0000 0.7126 71.5685 24.1994 -1.9217 -1.6247 -168.4760 0.5416 -6.9693 0.5894 -0.6437 -2.6905 -0.1336 11.4739 -1.4422 7.5920 -2.1719 -2.4948 2.6318 -17.6548 -15.2848 -10.9628 -0.2058 -6.7932 -12.1786 6.3593 -8.7749 13.1224 -1.6529 -17.8367 40.4126 0.0000 0.0000 12.8564 1.8826 -16.4459 1.8810 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -1.8604 9.1777 -8.6142 3.8310 15.6140 -35.1695 -0.0000 -0.0000 -0.0128 -5.4806 -3.5477 -4.8200 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -10.9000 -3.4107 -26.3891 -2.6926 0.0000 -0.0000 8.6700 3.9993 3.2622 -0.7267 0.0000 -0.0000 -23.5396 -20.3117 6.4295 64.3997 0.0000 0.0000 0.7585 12.9587 -18.4927 -10.7362 0.0000 -0.0000 0.7209 71.9611 24.2275 -1.4066 -1.4351 -169.9302 0.7702 -7.1207 0.6262 -0.4109 -2.9716 -0.1584 11.8703 -2.5727 8.3775 -2.0641 -2.6679 3.0275 -16.6509 -14.4731 -10.8253 0.8110 -5.8111 -13.3491 5.7691 -9.4189 14.3283 -3.0128 -18.7797 44.9197 0.0000 0.0000 13.4701 4.0124 -11.2468 0.4618 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -3.6757 6.5989 -8.8799 0.6467 14.8460 -35.2233 -0.0000 -0.0000 -0.3272 -7.6746 -5.6100 -7.0794 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -8.8932 -4.0615 -24.4100 -3.7824 0.0000 -0.0000 8.5393 4.4329 2.9630 -0.9710 0.0000 -0.0000 -25.8326 -20.0233 6.2607 61.0272 0.0000 0.0000 0.3028 13.9025 -14.9484 -9.7989 0.0000 -0.0000 0.6856 72.3050 24.2853 -1.3267 -0.9985 -170.9925 0.8972 -7.5291 0.5881 -0.3012 -3.3736 -0.2187 12.1653 -3.0274 8.7708 -1.9304 -2.3597 3.0230 -15.8951 -12.1364 -10.0246 2.0846 -4.8103 -14.2846 5.8113 -10.8319 15.8919 -4.4301 -18.7302 47.4602 0.0000 0.0000 16.4398 3.7200 -2.2770 1.4936 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.3743 5.0697 -8.9963 -0.4086 11.6996 -36.3001 -0.0000 -0.0000 -1.6052 -7.7292 -5.0304 -9.4842 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -7.7010 -3.9370 -22.2283 -4.1491 0.0000 -0.0000 7.9481 4.4368 2.0041 -1.2316 0.0000 -0.0000 -27.2270 -18.2074 5.2322 54.1804 0.0000 0.0000 -1.0657 15.5135 -10.6130 -8.9735 0.0000 -0.0000 0.6109 72.6102 24.3633 -1.8615 -0.2472 -172.1267 0.8724 -7.6316 0.5752 -0.2871 -3.6329 -0.2548 12.2631 -2.9521 9.1160 -1.8053 -1.9937 2.9732 -15.7685 -10.2959 -9.5017 2.4077 -4.1684 -14.7293 6.4222 -11.0820 16.5988 -6.4119 -20.0523 49.1286 0.0000 0.0000 20.2775 -1.1419 4.2046 3.9956 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.2751 4.1258 -9.0805 -1.5979 8.2162 -38.4032 -0.0000 -0.0000 -3.3788 -7.9110 -6.0543 -10.9060 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -7.7581 -3.0066 -20.4798 -3.2005 0.0000 -0.0000 6.6239 4.2230 1.6658 -1.4340 0.0000 -0.0000 -27.8556 -15.7259 4.5938 44.6480 0.0000 0.0000 -2.4468 15.6138 -7.4461 -7.8935 0.0000 -0.0000 0.5291 72.9097 24.4260 -2.5166 0.3745 -173.2393 0.9684 -7.4147 0.5851 -0.2330 -3.5401 -0.2489 11.9396 -3.0367 9.1331 -1.8413 -1.8706 2.9893 -15.7379 -9.2705 -9.2469 2.2847 -3.9323 -14.6069 6.4958 -10.2848 16.2261 -8.4053 -23.7919 50.4602 0.0000 0.0000 23.6019 -5.2208 5.5264 5.4018 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.3286 2.8023 -9.1683 -4.0074 7.0206 -41.1502 -0.0000 -0.0000 -4.6650 -9.3424 -8.5534 -11.2236 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.3150 -2.0674 -19.3485 -1.6272 0.0000 -0.0000 5.2891 3.9428 1.8325 -1.5290 0.0000 -0.0000 -28.1654 -13.6298 4.4352 34.1743 0.0000 0.0000 -1.6893 14.3351 -8.2264 -8.0016 0.0000 -0.0000 0.4594 73.2335 24.4575 -2.7498 0.3891 -174.2445 1.3457 -7.3500 0.5797 -0.0876 -3.1655 -0.2375 11.3526 -3.4405 8.5844 -2.0432 -1.9764 2.9561 -15.4915 -8.8436 -8.9985 2.6244 -4.2753 -14.0244 5.7587 -9.5719 15.5754 -9.3661 -27.4511 51.6066 0.0000 0.0000 25.6439 -4.4844 3.4538 4.3645 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -6.1212 1.4437 -9.3901 -6.3430 7.3810 -43.9963 -0.0000 -0.0000 -5.0906 -10.2462 -10.1565 -11.2314 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -8.4146 -1.8715 -18.5267 -0.2715 0.0000 -0.0000 4.0829 3.7268 1.9185 -1.5640 0.0000 -0.0000 -28.2133 -12.4147 4.1391 24.2440 0.0000 0.0000 1.2101 14.7822 -13.0224 -11.2793 0.0000 -0.0000 0.3858 73.6077 24.4605 -2.3846 -0.2194 -175.5187 1.7915 -7.7203 0.5718 0.0967 -2.7227 -0.2416 10.9629 -3.7795 7.7267 -2.1282 -2.1693 2.8460 -14.9383 -9.1195 -8.7974 3.4658 -4.9945 -13.2237 4.9896 -8.9922 15.0260 -9.1009 -28.9202 53.0153 0.0000 0.0000 26.1074 -1.8467 1.5551 3.2351 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -6.1060 0.5960 -9.7854 -7.4132 7.6130 -46.9845 -0.0000 -0.0000 -4.8705 -9.7655 -9.8936 -11.1443 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -7.4687 -2.5055 -17.7068 0.3210 0.0000 0.0000 2.8300 3.4795 2.2258 -1.6020 0.0000 -0.0000 -27.9388 -12.0369 3.3529 16.0769 0.0000 0.0000 4.8993 17.6560 -18.3957 -15.0226 0.0000 -0.0000 0.2843 74.0179 24.4506 -1.8465 -0.8845 -177.3520 1.9321 -8.0219 0.5565 0.1880 -2.3663 -0.2632 11.0976 -3.9290 6.8676 -1.9299 -2.3406 2.7304 -14.1045 -9.9104 -8.6533 4.3818 -5.5422 -12.3757 4.4607 -8.1036 14.4591 -8.1570 -29.0058 54.4054 0.0000 0.0000 25.5420 -1.1040 1.5793 3.0156 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.2834 0.2090 -10.1358 -7.3709 7.7694 -50.2973 -0.0000 -0.0000 -4.4916 -8.8780 -8.9055 -10.8057 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.8673 -3.2398 -16.7203 0.1524 0.0000 0.0000 1.8222 3.0452 3.0831 -1.5936 0.0000 -0.0000 -28.0170 -11.9064 2.3622 11.0273 0.0000 0.0000 7.1002 19.9815 -20.6393 -15.3072 0.0000 -0.0000 0.1602 74.4370 24.4383 -1.3557 -1.4040 -179.6835 1.9895 -7.9412 0.4981 0.2145 -2.1696 -0.2873 11.4983 -4.0788 6.0663 -1.6265 -2.4621 2.5878 -13.0611 -10.5759 -8.2816 5.2839 -5.7283 -11.4652 3.9623 -7.3806 13.9541 -7.2803 -29.0479 55.0255 0.0000 0.0000 24.6971 -1.5575 2.4064 2.7973 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -6.3536 0.0399 -10.2212 -6.7132 8.5149 -53.5489 -0.0000 -0.0000 -4.3628 -8.2613 -8.0058 -10.5293 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.1948 -3.7340 -15.5575 -0.2438 0.0000 -0.0000 1.2042 2.5055 4.1812 -1.4569 0.0000 -0.0000 -28.8020 -11.8552 1.9883 9.3726 0.0000 0.0000 7.0694 20.3138 -19.7876 -14.0770 0.0000 -0.0000 0.0254 74.8792 24.4198 -0.7643 -2.1335 177.4425 2.3109 -7.8201 0.4345 0.3356 -2.1121 -0.3196 11.8289 -4.2807 5.3382 -1.3627 -2.5667 2.4173 -11.9196 -10.7374 -7.5087 6.2558 -5.8404 -10.3528 3.4076 -7.2311 13.5718 -6.8625 -29.5936 54.5278 0.0000 0.0000 23.8786 -1.6326 2.6902 2.4322 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.1003 0.0366 -10.0678 -5.3975 9.3446 -56.2488 -0.0000 -0.0000 -4.4935 -7.5077 -6.7091 -10.7544 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -2.5335 -4.2742 -14.1142 -0.2828 0.0000 -0.0000 0.4597 1.9614 5.3559 -1.2353 0.0000 -0.0000 -29.6378 -12.2638 1.8295 9.9470 0.0000 0.0000 6.2026 20.1946 -18.2152 -13.6172 0.0000 -0.0000 -0.1216 75.3720 24.3938 -0.1510 -3.1949 173.9694 2.6891 -7.8046 0.3607 0.4710 -2.0644 -0.3559 12.2650 -4.5314 4.6712 -1.0401 -2.6442 2.2620 -10.8463 -10.6582 -6.4885 7.1690 -6.0600 -8.9379 2.8770 -7.2439 13.1273 -6.7171 -30.5324 53.2730 0.0000 0.0000 22.9051 -2.6074 2.4694 2.2094 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.7144 0.2205 -9.8340 -3.2962 9.3824 -58.3254 -0.0000 -0.0000 -4.5005 -6.3795 -4.9168 -11.2020 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.8436 -4.8814 -12.4564 0.1305 0.0000 0.0000 -0.6391 1.2268 6.9887 -1.0426 0.0000 -0.0000 -29.7738 -13.1835 0.7232 11.1416 0.0000 0.0000 5.5999 20.8739 -18.4214 -13.5316 0.0000 -0.0000 -0.2822 75.9187 24.3604 0.0907 -4.4009 170.1016 2.6475 -7.7281 0.2599 0.4616 -1.9472 -0.3947 12.9769 -4.8566 3.9077 -0.6263 -2.6829 2.0903 -9.8415 -10.7013 -5.3921 7.9686 -6.2190 -7.3246 2.4982 -7.2387 12.6121 -6.5604 -31.1822 51.6542 0.0000 0.0000 21.5558 -5.2556 2.1496 1.6489 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -5.4324 0.5154 -9.6175 -0.8085 9.0688 -59.8564 -0.0000 -0.0000 -4.0047 -5.1655 -3.2383 -11.2757 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.6039 -5.3723 -10.8429 0.7393 0.0000 0.0000 -1.6735 0.2271 9.1689 -0.8826 0.0000 -0.0000 -29.2790 -14.2307 -2.4001 11.9324 0.0000 0.0000 5.4000 21.5433 -21.5299 -13.0316 0.0000 -0.0000 -0.4414 76.5355 24.3115 0.1045 -5.7543 166.0585 2.4447 -7.6063 0.1819 0.4268 -1.7100 -0.4287 13.5747 -5.2769 3.0219 -0.2556 -2.7496 1.8868 -8.7226 -10.8403 -4.3086 8.8530 -6.1777 -5.7668 2.3773 -7.5451 12.1926 -6.4971 -30.9804 49.3215 0.0000 0.0000 20.1221 -7.3896 1.8058 0.6474 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -5.1263 0.7615 -9.4881 1.4238 9.8176 -60.8471 -0.0000 -0.0000 -3.0009 -3.7884 -1.7362 -10.8168 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 2.1159 -5.8116 -9.1509 1.2695 0.0000 0.0000 -2.5776 -0.7486 11.4015 -0.6998 0.0000 -0.0000 -27.9160 -15.2232 -8.2496 12.0073 0.0000 0.0000 5.1359 21.6998 -26.2530 -12.3273 0.0000 -0.0000 -0.5782 77.2349 24.2278 -0.0704 -7.5107 161.7040 2.3142 -7.6432 0.1145 0.4575 -1.4112 -0.4506 13.8159 -5.7672 2.3482 0.0542 -2.8999 1.7600 -7.5311 -10.8583 -3.3285 9.8037 -6.1092 -4.4394 2.5008 -8.0209 11.8895 -6.8211 -30.1020 45.6319 0.0000 0.0000 19.1749 -7.6258 1.6363 0.0363 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -4.7889 0.9632 -9.5542 3.3217 12.0229 -61.3508 -0.0000 -0.0000 -1.7569 -2.1278 -0.2598 -10.1056 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 3.9276 -6.4393 -6.7797 1.6765 0.0000 0.0000 -3.8103 -1.5369 13.3619 -0.5275 0.0000 -0.0000 -25.2418 -16.5265 -15.0993 11.4326 0.0000 0.0000 5.0716 21.8137 -30.7588 -11.2014 0.0000 -0.0000 -0.6879 77.9867 24.1114 -0.7840 -9.5196 156.9779 1.9616 -7.4692 -0.0932 0.2747 -1.3029 -0.4670 14.2724 -6.4598 1.9990 0.3697 -3.0548 1.7543 -6.6918 -10.7770 -2.5301 10.4825 -6.2150 -3.2867 2.6237 -8.5834 11.6392 -7.5105 -28.5139 40.8568 0.0000 0.0000 18.6113 -7.6744 1.6488 -0.1745 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -4.7369 1.5960 -9.7586 5.3153 14.0008 -61.4754 -0.0000 -0.0000 -0.5357 -0.7963 1.1311 -9.4895 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 5.7270 -7.1784 -3.6686 1.8521 0.0000 0.0000 -5.1700 -2.4278 15.1897 -0.4210 0.0000 -0.0000 -21.5115 -18.2218 -20.1220 10.4927 0.0000 0.0000 5.6562 21.7195 -33.3773 -9.5249 0.0000 -0.0000 -0.7918 78.7185 24.0046 -2.2991 -10.8349 152.3960 0.9821 -5.9718 -0.4139 -0.3812 -1.3468 -0.4814 15.4369 -7.8572 1.3707 0.5031 -3.2477 1.6911 -6.5641 -10.7647 -1.9394 10.8766 -6.3593 -2.3312 2.2728 -10.2862 11.4020 -8.2251 -25.3964 36.0337 0.0000 0.0000 17.8310 -8.8182 1.0706 -0.8640 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -5.0286 3.4217 -9.6949 7.5782 13.7219 -61.3254 -0.0000 0.0000 0.5250 -0.0155 2.4138 -9.0617 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 6.6414 -7.4392 -0.5623 1.8126 0.0000 0.0000 -5.9524 -3.6371 16.6485 -0.3922 0.0000 -0.0000 -18.5771 -19.3629 -22.4058 10.5257 0.0000 0.0000 5.3123 20.6675 -32.8112 -8.0861 0.0000 -0.0000 -0.9417 79.3747 23.9528 -4.1624 -10.2463 148.6254 -0.2684 -2.4495 -0.6970 -1.3090 -0.6944 -0.4007 16.5410 -10.3545 0.0449 0.1137 -3.8132 1.4804 -7.0246 -10.5588 -1.7748 11.4420 -6.3405 -1.9921 0.9690 -13.4871 10.7629 -9.0189 -21.3131 31.4858 0.0000 0.0000 17.0399 -10.1394 -0.0776 -2.1139 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -5.3228 6.4474 -9.1429 9.8272 11.5320 -60.9585 -0.0000 0.0000 1.2910 1.1088 3.4271 -8.6681 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 5.7865 -6.2383 1.6301 2.2185 0.0000 0.0000 -6.4898 -5.0474 17.6152 -0.4903 0.0000 -0.0000 -18.5811 -18.4438 -22.9739 13.4107 0.0000 0.0000 1.9907 18.1845 -29.4228 -6.7974 0.0000 -0.0000 -1.1882 79.9448 23.9459 -5.7208 -7.7702 144.9831 -0.8561 1.2811 -0.8855 -1.7605 1.2252 -0.1115 15.8945 -12.3055 -1.2685 -0.6514 -4.8405 1.3845 -7.7111 -9.6314 -2.5252 12.1783 -6.3483 -2.6635 -1.0226 -15.9225 9.0381 -10.5562 -19.1766 26.7279 0.0000 0.0000 17.0432 -11.0453 0.0211 -3.3633 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -5.2609 9.1078 -8.6866 11.6093 9.9127 -60.5825 -0.0000 0.0000 1.7105 2.7754 3.8601 -8.3005 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 2.8108 -3.3084 3.0466 4.2739 0.0000 0.0000 -7.6733 -6.7835 19.2891 -0.7163 0.0000 -0.0000 -20.7400 -15.7236 -22.3001 18.0538 0.0000 0.0000 -2.8459 14.9356 -25.1333 -5.4815 0.0000 -0.0000 -1.5357 80.4428 23.9678 -6.1452 -4.4125 139.5885 -0.5223 3.5807 -0.7938 -1.4743 2.5049 0.1453 13.9119 -10.6910 -1.2294 -1.2955 -5.3429 1.5615 -8.7949 -8.0780 -4.2186 12.1915 -6.6306 -4.0504 -2.1721 -15.5618 6.8891 -12.9901 -20.1189 21.8190 0.0000 0.0000 17.3785 -11.8716 2.0664 -4.5436 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -4.9698 9.8594 -9.1044 12.3879 9.9291 -60.1828 -0.0000 0.0000 1.8712 3.6830 3.8227 -8.0935 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -1.5803 0.8261 5.1255 8.0855 0.0000 0.0000 -8.5313 -9.3784 22.5304 -0.7833 0.0000 -0.0000 -21.5048 -12.9158 -18.9322 20.5988 0.0000 0.0000 -5.9058 12.4156 -21.6087 -5.1010 0.0000 -0.0000 -1.9435 80.8764 24.0150 -5.5957 -1.2373 131.9837 -0.0216 4.6589 -0.5450 -1.1381 1.9654 0.2453 12.5645 -6.3021 0.5444 -1.7019 -4.3385 1.7531 -10.4285 -5.9450 -5.7703 10.9428 -7.0588 -5.3174 -1.5166 -12.9959 5.8957 -14.5410 -21.8901 18.2385 0.0000 0.0000 16.5695 -12.0248 3.5513 -5.9340 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -4.7158 9.4664 -9.9547 11.8191 9.8990 -59.3956 -0.0000 0.0000 1.9211 3.1373 3.6216 -7.8264 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -6.5739 4.7083 7.1902 11.7186 0.0000 0.0000 -6.8928 -12.6301 26.3787 -0.4363 0.0000 -0.0000 -20.1333 -10.8301 -13.8414 20.1474 0.0000 0.0000 -7.0996 10.4712 -17.9140 -5.4489 0.0000 -0.0000 -2.3276 81.2470 24.0924 -5.2197 1.0964 124.1095 0.1425 4.9061 -0.3755 -1.0903 0.7698 0.2527 12.1846 -2.0559 2.2419 -2.0680 -2.4899 1.5191 -12.3174 -3.7103 -6.0476 9.1118 -7.2154 -5.9126 -0.2531 -11.1188 6.2037 -13.3311 -21.2645 17.6267 0.0000 0.0000 14.8280 -11.2253 1.7855 -6.6999 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.4760 9.7156 -9.9581 10.3969 8.2180 -58.4521 -0.0000 0.0000 2.1059 2.6409 2.8013 -6.9332 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -10.8621 6.9374 6.8569 12.7647 0.0000 0.0000 -3.4740 -15.2546 27.6026 -0.1178 0.0000 -0.0000 -18.5001 -9.6927 -9.4530 18.4590 0.0000 0.0000 -7.6787 8.3844 -13.5242 -5.6600 0.0000 -0.0000 -2.6209 81.5382 24.2051 -6.1437 2.9319 118.2337 -0.4762 4.8700 -0.3274 -1.4722 0.0033 0.1847 12.5067 0.3198 2.1637 -2.5297 -1.2605 0.8708 -14.3081 -2.3266 -5.2467 7.8404 -6.8834 -5.8257 0.0794 -11.8681 6.9417 -11.4507 -17.5130 18.2369 0.0000 0.0000 14.1543 -10.0029 -1.1560 -5.3425 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -4.3576 11.0594 -8.9945 9.0688 5.7892 -57.9869 -0.0000 0.0000 2.4851 3.4598 1.0123 -5.6235 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -13.3787 7.1224 3.1461 10.1251 0.0000 0.0000 -1.7968 -15.8177 23.7400 -0.2567 0.0000 -0.0000 -18.3210 -10.0294 -5.9419 16.8832 0.0000 0.0000 -7.7718 6.7898 -10.7085 -5.6568 0.0000 -0.0000 -2.8037 81.7721 24.3375 -7.6261 4.4844 114.3007 -1.5984 5.6530 -0.3199 -2.1212 -0.0394 0.1184 13.3022 0.3536 0.8053 -2.8860 -1.2372 0.2712 -16.1447 -1.8865 -4.3326 7.5291 -6.3239 -5.4184 -0.6700 -13.6382 7.4832 -12.2069 -13.5246 17.5601 0.0000 0.0000 15.4834 -9.5213 -1.7771 -2.7287 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -4.5026 12.4476 -8.1418 8.3065 4.9461 -58.0590 -0.0000 0.0000 2.6947 4.0001 -0.8293 -5.1844 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -13.8806 6.1423 -1.3289 4.9881 0.0000 0.0000 -2.6902 -13.1952 16.9126 -0.4107 0.0000 -0.0000 -18.2203 -11.2520 -2.0460 14.4906 0.0000 0.0000 -6.8708 6.3884 -10.4809 -5.7725 0.0000 -0.0000 -2.9265 82.0110 24.4661 -8.2181 5.5197 110.3190 -2.4446 7.3355 -0.1951 -2.5884 0.2964 0.1194 14.1079 -0.7211 -0.2488 -2.9953 -1.7023 0.0289 -17.5289 -1.8514 -3.9750 7.5783 -5.8712 -5.1702 -1.5964 -14.2368 7.7617 -15.3907 -11.3046 15.9808 0.0000 0.0000 18.0126 -11.0583 -0.4811 -0.6541 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -4.6824 13.0577 -8.1617 7.8976 6.1046 -58.2570 -0.0000 0.0000 2.3805 2.0770 -1.3940 -6.3434 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -13.8342 5.7725 -2.4743 1.4043 0.0000 0.0000 -3.6421 -9.3675 11.6170 -0.3962 0.0000 -0.0000 -15.9271 -11.8401 1.9458 9.9697 0.0000 0.0000 -5.0019 6.4203 -9.9324 -5.8775 0.0000 -0.0000 -3.0377 82.2786 24.5727 -7.9921 5.6990 105.2632 -2.5550 8.4117 0.1236 -2.6618 0.5327 0.1451 14.5792 -1.0626 -0.5702 -3.0195 -1.8887 -0.0261 -18.3767 -1.9430 -4.1666 7.3823 -5.3989 -5.3436 -1.9345 -14.0913 7.8814 -18.2426 -9.4688 15.3632 0.0000 0.0000 20.4145 -13.6743 0.8801 0.4492 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -4.6268 13.0647 -8.6451 7.4786 7.6501 -58.6852 -0.0000 0.0000 1.8208 -1.3168 -0.8382 -7.9306 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -14.4660 6.5445 -1.9008 2.1127 0.0000 0.0000 -3.1637 -7.1831 11.7331 -0.2502 0.0000 -0.0000 -11.4166 -11.6222 4.2656 3.9346 0.0000 0.0000 -2.9332 5.9815 -6.2369 -5.7689 0.0000 -0.0000 -3.1633 82.5475 24.6233 -7.5201 5.6380 100.1735 -2.2096 8.6192 0.3465 -2.4396 0.8448 0.1720 14.3925 -0.6663 -0.9619 -3.0767 -1.8182 -0.2131 -18.6001 -1.9308 -4.3834 7.0349 -4.4576 -5.7653 -1.9081 -14.2052 7.8437 -19.4361 -6.8706 16.3727 0.0000 0.0000 22.2332 -15.2219 1.5663 1.0675 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.3258 12.7897 -8.9444 7.0180 8.7355 -59.8334 -0.0000 0.0000 1.6398 -3.1816 -0.7837 -8.7143 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -16.2054 8.2347 -1.6140 5.9873 0.0000 0.0000 -1.5354 -6.0980 14.9423 0.0422 0.0000 0.0000 -7.5197 -10.9903 5.5930 -0.6676 0.0000 -0.0000 -1.4966 5.1217 -1.6950 -5.5554 0.0000 -0.0000 -3.2861 82.8109 24.6284 -6.7054 5.6030 96.0019 -1.7508 8.8611 0.2877 -2.1676 1.3338 0.1842 13.9839 -0.4359 -1.8328 -3.0915 -1.6781 -0.5763 -18.3842 -1.3519 -4.0933 6.8489 -2.8628 -5.8209 -2.2367 -14.4258 7.7112 -20.1834 -4.3345 17.8519 0.0000 0.0000 23.8823 -15.1195 1.7145 1.7506 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.0431 12.4225 -9.1869 6.6868 9.5876 -61.5638 -0.0000 0.0000 1.9077 -2.6512 -1.6969 -8.9686 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -18.1103 10.6847 -1.2366 10.3779 0.0000 0.0000 0.0303 -4.1476 16.0072 -0.0252 0.0000 -0.0000 -5.6053 -9.8452 8.0076 -2.2108 0.0000 -0.0000 -1.0699 4.4192 0.2998 -5.3945 0.0000 -0.0000 -3.3747 83.0515 24.6296 -5.9507 5.4634 92.1949 -1.5698 9.1271 0.1665 -2.0557 1.5309 0.1544 13.9798 -0.4777 -2.6987 -3.0084 -1.3266 -0.9336 -18.0072 0.1517 -3.1070 6.8750 -0.9093 -4.9968 -3.0134 -14.2952 7.6636 -21.7069 -2.9856 18.8162 0.0000 0.0000 25.7416 -14.5436 1.6614 2.4069 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -3.9230 11.9109 -9.5850 6.6573 10.5354 -63.4763 -0.0000 0.0000 2.1488 -1.4758 -2.5992 -9.2732 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -19.6164 12.8103 -0.3376 14.0511 0.0000 0.0000 1.1705 -1.1011 13.3333 -0.5896 0.0000 -0.0000 -4.9014 -8.8111 11.7602 -1.5753 0.0000 -0.0000 -1.5727 3.8266 0.2880 -5.1213 0.0000 -0.0000 -3.4086 83.2567 24.6458 -5.5180 5.1798 87.8056 -1.6798 9.0881 0.1934 -2.0888 1.2084 0.0716 14.2160 -0.3926 -3.1159 -2.9075 -0.6936 -1.1731 -17.5607 2.4815 -1.5509 7.1294 0.9126 -3.4678 -3.6242 -13.9157 7.8741 -23.6320 -2.4839 19.4803 0.0000 0.0000 27.7232 -14.5349 1.5456 2.8646 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.9101 11.2864 -9.7399 7.1416 11.4852 -65.6255 -0.0000 0.0000 2.0935 -0.9613 -2.7803 -9.4566 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -20.6613 14.0342 0.5387 16.5812 0.0000 0.0000 2.8669 1.3164 8.8202 -0.9795 0.0000 -0.0000 -4.2665 -8.3111 15.4950 -0.2063 0.0000 -0.0000 -2.7119 3.0681 0.8841 -4.7981 0.0000 -0.0000 -3.3935 83.4192 24.6629 -5.3267 4.9428 82.8159 -1.8833 8.7421 0.2901 -2.1400 0.7144 -0.0198 14.2017 -0.0875 -3.2588 -2.8957 -0.0123 -1.3836 -17.1204 4.8732 0.2367 7.6379 2.4048 -1.8234 -3.8676 -13.6104 8.3020 -24.9881 -2.0705 20.3750 0.0000 0.0000 29.6064 -14.6713 1.4936 3.4127 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.9470 10.7499 -9.3354 8.2005 11.9361 -68.1356 -0.0000 0.0000 1.9541 -0.5368 -2.3054 -9.0812 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -21.1779 14.7489 -0.0464 17.4909 0.0000 0.0000 4.9478 1.6569 5.3802 -1.0085 0.0000 -0.0000 -3.5228 -8.1894 18.4122 1.2817 0.0000 0.0000 -4.0875 2.3246 2.9241 -4.7942 0.0000 -0.0000 -3.3436 83.5248 24.6638 -5.2834 4.6278 77.8305 -1.8438 8.3551 0.3612 -2.1248 0.4096 -0.0809 13.8911 0.2560 -3.4855 -2.9718 0.4076 -1.5994 -16.7686 6.5609 1.8163 8.0877 3.7664 -0.3645 -4.2931 -13.3833 8.5243 -25.5503 -1.8381 21.5541 0.0000 0.0000 31.4279 -13.8876 1.5792 4.2572 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -3.9274 10.3492 -8.8297 9.3842 11.7653 -70.6288 -0.0000 0.0000 1.9534 0.4702 -1.4356 -8.3291 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -20.8023 15.2991 -2.6056 16.9036 0.0000 0.0000 6.0718 1.2861 4.7663 -1.3492 0.0000 -0.0000 -2.6335 -8.2565 21.2194 2.8089 0.0000 0.0000 -5.4335 1.8205 5.0690 -4.9788 0.0000 -0.0000 -3.2872 83.5848 24.6432 -5.0413 4.4294 73.0706 -1.8789 8.2444 0.4640 -2.1590 0.2631 -0.1158 13.7253 0.5753 -3.8377 -3.0758 0.5815 -1.7792 -16.6711 7.6512 3.0379 8.0563 5.2371 1.0034 -5.2929 -13.2552 8.2646 -25.8503 -1.8508 22.8065 0.0000 0.0000 33.4720 -12.0684 1.7302 5.1959 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.8492 9.9439 -8.7366 10.2316 11.6538 -72.6334 -0.0000 0.0000 2.0880 1.5298 -0.5841 -7.6624 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -20.2158 15.7981 -5.6662 15.9171 0.0000 0.0000 5.8598 1.8806 6.3068 -2.3097 0.0000 -0.0000 -1.9812 -8.1820 24.3866 4.3908 0.0000 0.0000 -6.7582 1.3645 6.6428 -4.8455 0.0000 -0.0000 -3.2238 83.6397 24.6073 -4.3463 4.3521 68.3007 -2.1328 8.2015 0.5885 -2.3531 0.1831 -0.1316 13.9155 0.9229 -4.1297 -3.2075 0.7753 -1.9092 -17.0689 8.9598 4.1846 7.6130 6.7537 2.3873 -6.4845 -13.2517 7.8474 -26.4943 -1.6283 23.9099 0.0000 0.0000 36.0587 -10.0749 1.8906 6.0017 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.8486 9.5246 -8.9349 10.8320 12.1748 -74.1114 -0.0000 0.0000 2.4208 1.8292 -0.1967 -7.0350 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -19.9888 16.2857 -7.8630 15.2891 0.0000 0.0000 5.4075 2.6030 7.6899 -3.1361 0.0000 -0.0000 -1.4667 -7.5770 27.2549 5.5736 0.0000 0.0000 -7.9298 0.7911 8.5432 -4.4796 0.0000 -0.0000 -3.1450 83.7153 24.5587 -3.1747 4.3013 63.3298 -2.4530 7.8693 0.6390 -2.5776 0.0819 -0.1477 14.1441 1.5252 -4.3095 -3.4487 1.1768 -2.0530 -18.0536 10.7397 5.5617 7.1215 8.0984 3.7320 -7.3761 -13.2614 7.7354 -27.6636 -1.0124 24.6675 -0.0000 0.0000 39.2831 -8.5018 2.2108 6.6941 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -3.9605 9.0930 -9.0622 11.4466 12.9515 -75.2543 -0.0000 0.0000 3.1485 1.5633 -0.1625 -6.1647 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -20.3116 16.7573 -10.0387 15.1300 0.0000 0.0000 5.9223 2.1110 7.4558 -3.1290 0.0000 -0.0000 -0.9890 -6.2777 29.3617 6.0884 0.0000 0.0000 -8.7540 0.2792 11.3538 -4.3344 0.0000 -0.0000 -3.0566 83.7930 24.4960 -1.7796 4.0590 58.2432 -2.4416 7.2151 0.5508 -2.5976 -0.1542 -0.2047 13.9521 2.5506 -4.4237 -3.8334 1.7675 -2.2789 -19.4014 12.4341 7.1120 6.6167 9.2400 4.9970 -8.0056 -13.0898 7.8292 -29.1171 -0.5345 25.1156 -0.0000 0.0000 42.9131 -7.2026 2.8757 7.3892 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.9407 8.5174 -9.0676 11.9560 13.2333 -76.1119 -0.0000 0.0000 4.2023 1.5477 0.1983 -5.1547 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -20.9724 16.9917 -13.3928 15.4252 0.0000 0.0000 6.7831 1.1158 5.5342 -2.5278 0.0000 -0.0000 -0.6827 -4.6731 30.9841 6.6446 0.0000 0.0000 -9.5456 0.0043 14.6311 -4.3064 0.0000 -0.0000 -2.9742 83.8492 24.4185 -0.2761 3.7306 53.1565 -2.1993 6.4009 0.3721 -2.4433 -0.4578 -0.2719 13.3479 3.7406 -4.5870 -4.2605 2.4329 -2.5264 -20.8953 13.7010 8.5905 5.8273 10.2926 6.2046 -8.4533 -12.7866 7.8324 -30.7526 -0.3641 25.6264 -0.0000 0.0000 46.5447 -6.0071 3.8741 8.1900 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.6911 7.7320 -9.0860 12.1585 13.0435 -76.5170 -0.0000 0.0000 5.0713 2.0522 1.1280 -4.3837 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -21.9844 16.7723 -17.2295 16.0600 0.0000 0.0000 6.6976 1.0662 2.0928 -2.0054 0.0000 -0.0000 -1.0897 -3.3152 32.8071 8.2730 0.0000 0.0000 -10.8309 -0.1843 17.5847 -4.0338 0.0000 -0.0000 -2.8945 83.8614 24.3347 1.0771 3.6041 48.1368 -2.0362 5.4214 0.1848 -2.2981 -0.7702 -0.3420 12.6775 4.4800 -4.8800 -4.5648 3.0830 -2.7555 -22.5831 14.7525 9.9368 4.6405 11.2359 7.2943 -8.4899 -12.3910 7.9505 -32.7860 -0.2694 26.3261 -0.0000 0.0001 49.9648 -5.1153 5.0885 9.0891 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.4461 6.8819 -9.0863 12.1523 13.1700 -76.3282 -0.0000 0.0000 5.3561 2.6133 1.8846 -3.9379 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -23.0195 15.6447 -20.3886 16.3088 0.0000 0.0000 5.9771 1.3035 -2.3997 -1.7868 0.0000 -0.0000 -2.1875 -2.7269 34.7729 10.9747 0.0000 0.0000 -12.5432 -0.3676 20.2420 -3.6834 0.0000 -0.0000 -2.8033 83.8059 24.2499 2.0938 3.6305 43.2759 -1.9245 4.4370 0.0502 -2.1554 -1.0101 -0.4241 12.0876 4.3653 -5.3496 -4.7251 3.6305 -2.9803 -24.4552 15.5967 11.0934 3.2063 11.9054 8.1044 -8.1494 -11.7278 8.3802 -35.1031 -0.5121 26.9142 -0.0000 0.0001 53.1564 -4.6519 6.3152 9.8545 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.2718 6.0866 -9.0640 12.0476 14.1581 -75.6746 -0.0000 0.0000 5.3445 2.5656 1.7966 -3.6405 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -23.5736 13.4407 -22.8250 15.8251 0.0000 0.0000 5.2894 0.5489 -5.9192 -1.5748 0.0000 -0.0000 -3.2363 -2.8154 36.0007 13.9023 0.0000 0.0000 -14.2424 -0.2708 23.0538 -3.4752 0.0000 -0.0000 -2.7058 83.6644 24.1583 2.9008 3.5311 38.7569 -1.6835 3.6787 -0.0453 -1.9211 -1.0767 -0.4844 11.5168 3.7480 -5.9902 -4.8858 3.9538 -3.1802 -26.2622 15.8901 11.8199 1.7413 12.2486 8.4896 -7.9900 -10.8639 8.6978 -37.0684 -1.6167 27.2552 -0.0000 0.0001 56.0243 -4.3028 7.2285 10.2714 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -2.9680 5.3488 -9.2399 11.7819 15.7483 -74.8367 -0.0000 0.0000 5.5696 2.1243 1.3037 -3.5832 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -23.5920 10.4478 -24.2183 15.0040 0.0000 0.0000 4.7728 -0.1264 -6.6657 -1.3744 0.0000 -0.0000 -3.8132 -3.1731 36.0661 16.7483 0.0000 0.0000 -15.9479 0.4866 25.4301 -3.1519 0.0000 -0.0000 -2.6157 83.4375 24.0609 3.6577 3.3544 34.5722 -1.3685 2.8564 -0.0650 -1.7301 -1.0215 -0.5220 11.1263 3.2342 -6.6256 -5.1663 4.0716 -3.3259 -27.9937 15.8015 12.1313 0.3403 12.3566 8.4603 -8.2551 -10.2643 8.7027 -38.4875 -3.2428 27.6225 -0.0000 0.0001 58.4046 -3.7309 7.6977 10.4594 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -2.5334 4.9299 -9.7916 11.4258 16.9457 -73.8337 -0.0000 0.0000 5.9104 2.0236 1.3110 -3.9332 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -23.4441 7.0717 -23.2657 14.1056 0.0000 0.0000 4.6444 1.1314 -5.6426 -1.2694 0.0000 -0.0000 -4.0191 -3.7598 35.1543 19.6297 0.0000 0.0000 -17.7615 2.0674 26.5104 -2.8455 0.0000 -0.0000 -2.5317 83.1441 23.9819 4.4208 3.5052 30.3996 -1.2609 1.5478 0.0155 -1.7557 -1.1613 -0.5680 11.1304 2.8287 -7.0081 -5.4977 4.2670 -3.4245 -30.0398 15.8768 12.5780 -1.1270 12.1904 8.2718 -8.5454 -10.0128 9.1209 -39.9145 -4.7663 27.9679 -0.0000 0.0001 60.4164 -3.1055 8.0547 10.6695 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -2.1927 5.1105 -10.4629 11.3294 16.7874 -72.6040 -0.0000 0.0000 5.8130 1.9926 1.8478 -4.3908 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -23.7038 3.9083 -19.5790 13.5549 0.0000 0.0000 4.6584 3.3439 -5.1370 -0.9723 0.0000 -0.0000 -4.0912 -4.8533 33.5722 22.5121 0.0000 0.0000 -19.2140 4.5567 26.4241 -3.3663 0.0000 -0.0000 -2.4404 82.7906 23.9464 5.0786 3.8598 25.8822 -1.2658 0.0221 0.1636 -1.8039 -1.6526 -0.6678 11.2513 2.2705 -6.9564 -5.7522 4.6777 -3.4320 -32.2250 15.9141 13.4725 -2.9725 11.4335 8.3422 -8.3615 -9.4361 10.4963 -41.6242 -6.7114 27.7738 -0.0000 0.0001 62.1669 -3.0157 8.7012 10.8942 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.8896 5.4748 -10.9474 11.7054 15.4940 -71.3936 -0.0000 0.0000 5.2758 1.1106 2.2418 -4.4218 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -24.5002 1.6650 -15.3427 14.2344 0.0000 0.0000 4.1126 3.8205 -4.9629 -0.5921 0.0000 -0.0000 -3.8628 -6.3695 31.4224 25.4365 0.0000 0.0000 -19.5342 7.8292 25.6973 -4.8848 0.0000 -0.0000 -2.3429 82.3544 23.9473 5.4735 3.5585 21.0416 -1.0052 -0.9046 0.2317 -1.5277 -2.0278 -0.7075 10.9392 1.8874 -6.3987 -5.8694 4.9282 -3.2751 -33.4739 14.8090 14.1551 -5.2838 9.8693 8.9649 -7.6489 -8.0725 12.1093 -42.9075 -10.0549 26.9240 -0.0000 0.0001 63.1238 -3.7571 9.6083 10.9555 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.4238 5.1369 -11.4072 12.3167 14.6050 -70.6242 -0.0000 0.0000 4.9500 -0.1097 2.5705 -4.1603 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -25.2563 0.6809 -12.8957 16.4013 0.0000 0.0000 2.5625 2.7215 -3.1420 -0.3563 0.0000 -0.0000 -2.9154 -7.6565 28.8276 28.5727 0.0000 0.0000 -17.9541 11.0951 23.3842 -6.6941 0.0000 -0.0000 -2.2684 81.8244 23.9568 5.5922 2.2438 16.1504 -0.5558 -0.9144 0.2231 -1.1442 -1.7983 -0.5978 10.3025 2.2160 -5.4331 -5.8826 4.6435 -2.9345 -33.2079 11.9567 13.8281 -7.5374 7.6841 9.9776 -6.5334 -6.4933 13.0572 -42.9516 -14.2596 26.3089 -0.0000 0.0001 62.2761 -4.8262 10.4349 10.7521 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.0743 4.0563 -12.1355 12.7032 15.2203 -70.2453 -0.0000 0.0000 5.0479 0.1351 3.6534 -4.3628 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -25.5258 0.3676 -10.7257 19.3284 0.0000 0.0000 0.3133 2.4555 -0.6171 -0.2402 0.0000 -0.0000 -1.2531 -8.4466 26.0696 31.6638 0.0000 0.0000 -14.0444 13.2573 17.5682 -8.4272 0.0000 -0.0000 -2.2518 81.2290 23.9554 5.4424 0.7854 11.5539 -0.3554 -0.5883 0.2612 -1.0332 -1.1974 -0.4129 9.8381 3.0521 -4.3357 -5.7926 3.9816 -2.5237 -32.0472 8.0357 12.5504 -9.0875 5.3254 10.8316 -5.1385 -5.2302 13.5327 -41.6159 -17.8016 26.8056 -0.0000 0.0001 59.2042 -5.3512 10.9403 10.2222 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.2151 3.1452 -13.0492 12.4063 16.7054 -69.6514 -0.0000 0.0000 5.0852 1.9182 5.2334 -5.2395 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -25.2748 -0.5146 -6.5496 22.0096 0.0000 0.0000 -2.1581 3.5046 -0.0198 -0.1122 0.0000 -0.0000 0.6668 -9.5187 22.9561 34.1830 0.0000 0.0000 -8.4875 14.1821 8.1520 -10.6649 0.0000 -0.0000 -2.2937 80.6242 23.9363 4.9859 -0.0135 7.6645 -0.4679 -0.4605 0.3558 -1.1738 -0.7230 -0.2556 9.7841 3.7731 -3.4632 -5.5321 3.3285 -2.1939 -30.8091 4.2546 10.8903 -9.7716 3.1536 11.1119 -3.8205 -3.9959 14.1614 -39.3408 -20.2362 28.2055 -0.0000 0.0001 54.5716 -5.2776 11.1937 9.4535 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -1.6827 2.7381 -13.7828 11.1262 17.9343 -68.6039 -0.0000 0.0000 4.7414 2.9412 5.7909 -5.9523 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -24.5733 -2.0965 -1.7133 24.2351 0.0000 0.0000 -4.4365 4.4291 -1.0503 0.1016 0.0000 0.0000 2.2644 -11.3619 18.5036 36.1013 0.0000 0.0000 -2.1620 15.0724 -3.0578 -13.4326 0.0000 -0.0000 -2.3683 80.0618 23.9059 4.2836 -0.2779 4.7703 -0.6378 -0.3965 0.4040 -1.3419 -0.4833 -0.1693 10.0520 4.0093 -2.8304 -5.1320 2.8306 -1.9532 -29.7937 1.5670 9.3664 -9.7967 1.4107 10.7990 -2.8172 -2.6656 14.8497 -36.7000 -22.0449 30.1235 -0.0000 0.0001 49.3513 -5.3955 11.3351 8.6207 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -2.0769 2.2770 -14.3309 8.9548 18.7483 -67.4378 -0.0000 0.0000 4.0467 2.0918 4.5077 -5.7987 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -23.5219 -3.4617 1.1296 26.1327 0.0000 0.0000 -6.4871 4.6078 -1.3826 0.2685 0.0000 0.0000 2.8628 -13.4980 12.2508 37.9201 0.0000 0.0000 4.2788 16.2354 -14.2595 -14.3638 0.0000 -0.0000 -2.4510 79.5682 23.8779 3.6061 -0.4581 2.7637 -0.7612 -0.2286 0.3908 -1.4648 -0.2665 -0.0876 10.3856 3.8871 -2.0660 -4.7179 2.3720 -1.6420 -28.9680 0.4237 8.2771 -9.4805 0.5318 10.1117 -1.8571 -1.8049 15.1755 -34.1205 -23.0251 32.3611 -0.0000 0.0000 44.4140 -6.1272 11.2969 7.7604 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.3647 1.2562 -15.0870 6.5785 19.5246 -66.5657 -0.0000 0.0000 3.0716 1.1223 2.3370 -5.3664 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -22.3307 -4.2029 1.9377 27.5575 0.0000 0.0000 -8.2971 4.8119 -0.4546 0.3328 0.0000 0.0000 1.9858 -15.3407 5.4632 40.1242 0.0000 0.0000 8.3772 16.5546 -22.5715 -12.2967 0.0000 -0.0000 -2.5282 79.1295 23.8701 2.9605 -0.4873 1.2766 -0.8199 -0.2722 0.3909 -1.5487 -0.1232 0.0098 10.6977 3.6738 -0.8611 -4.3386 1.9913 -1.1696 -28.3581 0.8042 7.7624 -9.0744 0.7248 9.2311 -0.7486 -1.6795 15.3422 -31.7514 -22.7174 34.0696 -0.0000 0.0000 40.6625 -7.0151 11.0622 6.8298 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -2.9168 -0.3389 -16.1388 5.0023 20.1333 -66.3286 -0.0000 0.0000 2.0235 1.4356 0.8663 -5.4315 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -20.7935 -4.8737 2.5215 28.0724 0.0000 0.0000 -9.6307 5.4047 0.3454 0.3517 0.0000 0.0000 0.0191 -17.0557 -0.2822 42.6408 0.0000 0.0000 7.9270 16.0220 -24.6133 -10.6406 0.0000 -0.0000 -2.5872 78.7233 23.8929 2.1989 -0.1373 0.0693 -0.8187 -0.7777 0.4056 -1.5753 -0.2500 0.0803 11.0563 3.4525 0.6225 -3.9465 1.8258 -0.6360 -27.9951 2.3078 7.8323 -8.6346 1.3619 8.2144 0.1370 -1.6875 15.9431 -29.3436 -21.8962 34.3412 -0.0000 0.0000 38.3735 -7.5918 10.7539 5.8784 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.9825 -2.1347 -17.1862 4.6553 20.1660 -66.7585 -0.0000 0.0000 1.3566 2.4144 0.6629 -5.8385 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -18.6486 -5.7677 3.4668 27.4846 0.0000 0.0000 -10.3465 5.8914 0.5072 0.3399 0.0000 0.0000 -2.4157 -18.9433 -4.4527 44.6888 0.0000 0.0000 4.3758 14.6212 -20.2973 -11.0621 0.0000 -0.0000 -2.6152 78.3419 23.9375 1.2748 0.3525 -0.9263 -0.6877 -1.4872 0.3997 -1.5118 -0.5629 0.0998 11.3678 3.2495 2.0020 -3.5519 1.8368 -0.1925 -27.7113 4.0703 8.2066 -8.0854 1.5817 7.2147 0.5662 -1.4419 17.0941 -26.5466 -21.7521 33.7683 0.0000 0.0000 36.4720 -8.1903 10.2758 5.0762 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -5.3852 -3.8089 -18.0478 5.0271 19.9183 -67.4305 -0.0000 0.0000 1.3936 3.0817 1.4125 -5.9450 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -16.0267 -6.4530 4.0483 26.2011 0.0000 0.0000 -10.7146 6.0523 0.8833 0.2870 0.0000 0.0000 -5.0190 -20.7713 -7.0759 45.3808 0.0000 0.0000 0.8946 12.0003 -13.3524 -11.0153 0.0000 -0.0000 -2.6074 77.9913 23.9784 0.4264 0.6076 -1.8499 -0.4577 -2.0889 0.3917 -1.3873 -0.7711 0.1166 11.4444 3.1433 3.1334 -3.2695 1.8360 0.1606 -27.2893 5.1752 8.4604 -7.4495 1.2991 6.5180 0.8190 -1.2293 18.3096 -23.3594 -22.4612 33.9060 0.0000 0.0000 33.5142 -9.2436 9.3892 4.4983 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.7527 -5.2260 -18.7798 5.3249 20.0446 -67.8778 -0.0000 0.0000 1.8705 3.3679 2.6197 -5.6874 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -13.6185 -6.6512 4.1516 25.0674 0.0000 0.0000 -11.1938 6.1550 1.8131 0.2726 0.0000 0.0000 -7.7532 -22.2410 -8.1041 44.2620 0.0000 0.0000 -1.0339 9.0904 -7.7505 -9.8214 0.0000 -0.0000 -2.5653 77.6656 23.9978 -0.2962 0.6310 -2.8533 -0.1238 -2.5979 0.4139 -1.2403 -0.7879 0.1657 11.3191 3.1586 4.1697 -3.1290 1.7104 0.4887 -26.7069 5.3796 8.4702 -6.8708 0.9905 6.2230 1.2584 -1.2135 19.0914 -19.9479 -23.3063 35.5749 0.0000 0.0000 29.1563 -10.5883 8.2445 3.9586 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -7.8753 -6.3810 -19.3537 5.2216 20.5009 -68.0675 -0.0000 0.0000 2.1192 3.5987 3.5946 -5.5474 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -11.7768 -6.5996 4.6182 24.6536 0.0000 0.0000 -11.9523 6.2277 2.5246 0.3554 0.0000 0.0000 -10.2167 -23.4063 -7.4154 41.1322 0.0000 0.0000 -1.7708 7.2589 -5.0097 -9.5494 0.0000 -0.0000 -2.4878 77.3556 23.9974 -0.9595 0.5348 -3.7777 0.2073 -3.0553 0.4548 -1.1042 -0.7265 0.2246 11.2779 3.1934 5.1611 -3.0107 1.5221 0.8247 -26.1234 5.0373 8.3065 -6.4067 0.8634 6.1447 1.6867 -1.1167 19.3150 -16.3296 -24.0065 38.2018 0.0000 0.0000 24.2941 -11.8590 7.1617 3.1703 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -8.7814 -7.4381 -19.7121 4.8165 20.7874 -68.2727 -0.0000 0.0000 1.7586 3.6292 3.8206 -5.7431 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -10.4071 -6.4099 5.6249 24.9284 0.0000 0.0000 -12.8779 6.0678 2.6037 0.4170 0.0000 0.0000 -12.1802 -24.2246 -5.3190 35.9771 0.0000 0.0000 -1.3754 7.2389 -5.1997 -10.1366 0.0000 -0.0000 -2.3736 77.0502 23.9879 -1.6630 0.3463 -4.2482 0.4705 -3.4225 0.4653 -0.9784 -0.6265 0.2589 11.4405 3.1250 5.9917 -2.8141 1.2877 1.1535 -25.5664 4.5780 7.9294 -5.9821 0.6826 6.0489 1.7997 -0.7723 19.1543 -12.6361 -24.8696 40.7161 0.0000 0.0000 20.0952 -12.8886 6.1383 1.9452 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.6375 -8.4597 -20.0276 4.2293 21.0178 -68.5260 -0.0000 0.0000 0.9175 3.2980 3.4425 -6.0348 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.1496 -5.9544 6.3532 25.4646 0.0000 0.0000 -13.9015 5.7530 2.5048 0.3488 0.0000 0.0000 -13.6561 -24.4284 -2.2969 28.9936 0.0000 0.0000 0.9622 8.7744 -8.2353 -9.9640 0.0000 -0.0000 -2.2240 76.7359 23.9725 -2.3686 0.1494 -4.1374 0.6904 -3.7796 0.3950 -0.8864 -0.3835 0.2908 11.6390 2.8533 6.5443 -2.5933 0.9842 1.4362 -24.8771 4.0216 7.3287 -5.5440 0.3358 5.8265 1.7231 -0.4972 18.8831 -9.0730 -25.9055 42.6058 0.0000 0.0000 17.2177 -13.5001 5.0280 0.5225 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -10.4625 -9.3969 -20.3597 3.5404 21.5645 -68.7909 -0.0000 0.0000 0.0373 2.8038 3.0860 -6.2173 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -7.8384 -5.3034 6.4667 25.9664 0.0000 0.0000 -15.0520 5.5018 2.4632 0.2884 0.0000 0.0000 -14.7880 -23.7939 1.2394 20.8400 0.0000 0.0000 5.6943 10.9047 -13.3239 -9.1992 0.0000 -0.0000 -2.0435 76.4046 23.9491 -2.9726 0.0652 -3.6792 0.8773 -4.1735 0.2495 -0.8066 -0.0049 0.3069 11.6675 2.3761 6.8037 -2.4274 0.5844 1.6489 -23.9706 3.2134 6.6279 -5.1442 -0.0739 5.5656 1.9318 -0.7224 18.5849 -5.5888 -26.2579 44.3834 0.0000 0.0000 15.5025 -13.6783 4.0129 -0.4453 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -11.2467 -10.2109 -20.5364 3.0328 22.1879 -69.1151 -0.0000 -0.0000 -0.5814 2.4311 3.1815 -6.2748 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -6.5109 -4.6958 6.4187 26.3642 0.0000 0.0000 -16.2905 5.3116 2.2687 0.4322 0.0000 0.0000 -15.8485 -22.1986 3.7918 12.7360 0.0000 0.0000 11.2737 12.8923 -17.3296 -9.5173 0.0000 -0.0000 -1.8498 76.0491 23.9204 -3.6378 0.2486 -3.1814 1.1179 -4.5367 0.1032 -0.6887 0.3772 0.3139 11.6046 1.6453 6.8186 -2.2916 0.0825 1.8455 -22.9519 2.2143 5.8807 -4.8197 -0.3924 5.3939 2.4598 -1.3894 18.1191 -2.2705 -25.6832 46.4639 0.0000 0.0000 14.4705 -13.5767 3.3266 -0.6470 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -12.0185 -11.0463 -20.6412 2.8571 22.4213 -69.3876 -0.0000 -0.0000 -0.9381 2.2098 3.6100 -6.2199 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -4.8497 -4.3419 6.4734 26.3955 0.0000 0.0000 -17.4312 5.1234 1.9167 0.6804 0.0000 0.0000 -16.9086 -20.0642 2.4262 6.0540 0.0000 0.0000 14.4715 14.9709 -15.6484 -11.4389 0.0000 -0.0000 -1.6765 75.6648 23.8937 -4.6882 0.9608 -2.8521 1.6167 -4.8462 0.0557 -0.4386 0.6000 0.3033 11.5828 0.6102 6.7758 -2.1348 -0.5804 2.1549 -22.0024 1.3027 4.9756 -4.5625 -0.4871 5.3118 2.9941 -2.1845 17.3098 0.2251 -25.0902 48.4989 0.0000 0.0000 13.8974 -13.3077 2.8299 -0.5081 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -12.8451 -12.1116 -21.1598 2.8247 22.5382 -69.2172 -0.0000 -0.0000 -1.2276 1.9618 4.0225 -6.0820 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -2.2855 -4.5094 6.5182 25.5902 0.0000 0.0000 -18.2061 4.9648 1.6757 0.7644 0.0000 0.0000 -17.9363 -18.4793 -1.4344 2.2678 0.0000 0.0000 13.9814 15.9249 -9.5512 -13.3800 0.0000 -0.0000 -1.5271 75.2769 23.8699 -5.7654 2.1804 -2.8423 2.2207 -5.0803 0.0106 -0.1616 0.6363 0.2882 11.6475 -0.6554 6.8266 -2.0001 -1.4049 2.6107 -21.3143 0.5459 3.9887 -4.4419 -0.3685 5.2742 3.3834 -3.1459 16.3439 1.4738 -25.0769 50.0525 0.0000 0.0000 13.8845 -12.7499 2.2922 -0.5408 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -13.6129 -13.3075 -22.0710 2.7461 22.7020 -68.5593 -0.0000 -0.0000 -1.4519 1.3486 4.3488 -5.9330 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.6772 -5.1186 6.4129 24.0355 0.0000 0.0000 -18.5767 4.7249 1.9612 0.7194 0.0000 0.0000 -19.4837 -17.6687 -2.0598 2.2036 0.0000 0.0000 12.2270 14.3847 -6.3142 -13.9524 0.0000 -0.0000 -1.3979 74.8868 23.8427 -6.5218 3.8012 -3.2415 2.7481 -5.2058 -0.1012 0.0266 0.5454 0.2742 11.7743 -2.0646 6.8474 -1.9168 -2.3036 3.0626 -20.9011 -0.3113 3.1498 -4.5260 -0.2816 5.3183 3.7348 -4.4614 15.5680 1.9821 -25.2357 51.3847 0.0000 0.0000 14.3483 -11.7844 1.7730 -0.7219 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -14.1933 -14.3910 -22.8501 2.7920 22.4317 -67.7797 -0.0000 -0.0000 -1.4248 0.3450 4.8456 -5.7724 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.5725 -6.0345 6.3257 21.9702 0.0000 0.0000 -18.6501 4.3401 2.8354 0.8205 0.0000 0.0000 -21.2099 -17.7081 0.9728 4.4549 0.0000 0.0000 11.0034 12.1193 -7.4021 -13.4083 0.0000 -0.0000 -1.2735 74.4794 23.8091 -6.8508 5.4474 -3.8582 2.9774 -5.0591 -0.2115 0.0917 0.3770 0.2447 12.0500 -3.4716 6.5755 -1.8272 -3.1641 3.3790 -20.7786 -1.3759 2.4262 -4.6825 -0.4018 5.4232 3.9494 -5.9951 15.0608 2.4804 -25.3137 52.8032 0.0000 0.0000 14.9089 -10.4427 1.2078 -0.8554 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -14.6603 -15.1887 -23.4106 3.0796 21.4581 -67.0636 -0.0000 -0.0000 -1.1906 -0.5170 5.5378 -5.4860 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 6.2342 -6.8877 6.2882 19.6201 0.0000 0.0000 -18.5975 3.8870 3.9503 1.0148 0.0000 0.0000 -22.7236 -18.2085 3.8016 7.4581 0.0000 0.0000 10.5139 10.8768 -8.6358 -13.0362 0.0000 -0.0000 -1.1225 74.0427 23.7704 -6.8547 6.6969 -4.4910 2.8589 -4.6534 -0.2598 0.0569 0.2358 0.2126 12.5442 -4.7091 6.0895 -1.6890 -3.8981 3.6072 -21.0633 -2.3500 1.5862 -4.6172 -0.5257 5.4125 3.8385 -7.2015 14.6481 3.0988 -25.7067 54.0033 0.0000 0.0000 15.3229 -8.9173 0.3061 -1.0120 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -15.1517 -15.7077 -24.1206 3.3439 20.4929 -66.4003 -0.0000 -0.0000 -1.0775 -0.7797 5.9715 -5.0784 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 8.5557 -7.2741 6.3244 17.3993 0.0000 0.0000 -18.5808 3.3497 4.8378 0.9275 0.0000 0.0000 -24.0824 -18.3252 4.5076 11.4428 0.0000 0.0000 10.3817 10.6539 -7.5981 -13.0920 0.0000 -0.0000 -0.9224 73.5714 23.7173 -6.5150 7.4955 -5.4156 2.5170 -4.1807 -0.2638 -0.0608 0.1032 0.1904 13.0865 -5.6303 5.8073 -1.5849 -4.4550 3.8164 -21.6885 -2.9895 0.7434 -4.1842 -0.4148 5.2138 3.6714 -7.8150 14.3190 3.7858 -26.0009 54.7660 0.0000 0.0000 15.6433 -7.5281 -0.8545 -1.2748 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.5557 -16.0460 -24.8403 3.4607 20.0970 -66.1345 -0.0000 -0.0000 -1.1981 -0.6894 5.7662 -4.7999 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 10.1530 -7.1347 6.9084 16.0349 0.0000 0.0000 -18.8484 2.6961 5.3233 0.5630 0.0000 0.0000 -24.9454 -17.8449 4.2613 16.5016 0.0000 0.0000 9.7601 10.1957 -5.4034 -12.4852 0.0000 -0.0000 -0.6684 73.0752 23.6363 -5.5705 7.8317 -6.8557 2.0095 -3.4973 -0.3383 -0.3563 -0.0523 0.1767 13.4413 -6.3704 5.7506 -1.6275 -4.8303 3.9210 -22.3654 -3.4358 0.3807 -3.5788 -0.2421 5.0479 3.8061 -8.3980 14.2909 4.7625 -24.8575 55.4874 0.0000 0.0000 15.7958 -6.4053 -1.8567 -1.3708 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -15.6960 -16.0302 -24.9198 3.8100 19.5892 -66.6905 -0.0000 -0.0000 -1.2523 -0.6615 5.2205 -4.8906 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 10.4814 -6.4782 8.0872 16.0270 0.0000 0.0000 -19.7377 2.0802 5.6311 0.3734 0.0000 0.0000 -24.8649 -16.7986 4.0729 20.9529 0.0000 0.0000 7.6795 8.4876 -3.4936 -11.3113 0.0000 -0.0000 -0.3639 72.5770 23.5400 -3.9173 7.3718 -8.2778 1.1736 -2.0905 -0.5364 -0.8813 -0.1175 0.1466 13.6554 -7.2662 5.4257 -1.8131 -5.1194 3.8090 -23.0227 -3.7861 0.6358 -3.1748 -0.2250 5.1010 3.9742 -9.6536 14.6393 5.7201 -22.3875 56.1570 0.0000 0.0000 15.5703 -5.2485 -2.7927 -1.1396 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -15.5814 -15.3564 -24.3031 4.4420 18.2134 -67.8240 -0.0000 -0.0000 -0.9793 -0.6797 4.7938 -5.2618 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 9.4034 -5.0960 8.9000 17.1162 0.0000 0.0000 -21.2029 1.5025 5.8997 0.4129 0.0000 0.0000 -24.7451 -14.6218 2.1843 23.7471 0.0000 0.0000 3.6449 6.3834 -0.6094 -10.6715 0.0000 -0.0000 -0.0265 72.0747 23.4696 -2.2447 6.2957 -8.9159 0.2800 -0.2722 -0.7628 -1.4246 0.1419 0.1266 13.8902 -8.3549 4.6278 -2.0267 -5.3929 3.5757 -23.8721 -3.7811 0.9726 -3.1999 -0.1544 5.1853 3.6543 -11.1649 15.0787 5.7121 -21.0078 56.0418 0.0000 0.0000 15.1673 -3.6926 -3.9898 -0.9416 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -15.3262 -14.3952 -23.8353 4.6854 16.8581 -68.8725 -0.0000 -0.0000 -0.6169 -0.7064 4.2744 -5.5332 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 7.9848 -3.1704 8.9068 18.4864 0.0000 0.0000 -22.3832 0.5808 5.8664 0.1347 0.0000 0.0000 -25.6263 -11.3392 -2.7227 26.1138 0.0000 0.0000 -1.0827 5.2932 4.7142 -9.9464 0.0000 -0.0000 0.3029 71.5471 23.4543 -1.3239 5.6181 -9.0489 -0.1056 0.7192 -0.8598 -1.6386 0.5257 0.1503 14.0710 -8.9576 3.8949 -2.1957 -5.5508 3.4012 -24.9438 -3.3286 0.8906 -3.5200 0.2148 4.9803 3.1749 -11.8999 15.2898 4.5014 -21.6010 54.9809 0.0000 0.0000 15.2189 -2.3240 -4.6897 -1.1391 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -14.9355 -14.0698 -24.0578 4.2366 16.9856 -69.7885 -0.0000 -0.0000 -0.5210 -1.0164 3.1893 -5.5037 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 7.4132 -1.6640 9.2941 19.7538 0.0000 0.0000 -22.3271 -0.7163 5.3137 -0.7305 0.0000 -0.0000 -26.8803 -8.7147 -6.7386 29.2655 0.0000 0.0000 -4.6211 5.0788 9.2692 -8.6758 0.0000 -0.0000 0.6085 70.9877 23.4944 -1.0757 5.5495 -9.6145 -0.0152 0.7124 -0.7769 -1.5506 0.6412 0.1603 14.0648 -8.6818 3.6955 -2.3249 -5.4198 3.2749 -25.8643 -2.7100 0.6146 -3.6965 0.6117 4.5035 3.2308 -11.5861 15.3381 3.4107 -22.1394 53.8018 0.0000 0.0000 16.2000 -2.1734 -3.7227 -1.5422 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -14.3219 -14.3514 -24.4251 3.8331 18.1288 -71.0087 -0.0000 -0.0000 -0.6203 -1.6040 1.8171 -5.4756 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 7.4297 -0.7907 10.7061 21.2802 0.0000 0.0000 -21.1490 -1.6471 4.7201 -1.8178 0.0000 -0.0000 -27.1070 -7.9229 -6.0527 31.9757 0.0000 0.0000 -6.5527 4.4821 9.7192 -7.6115 0.0000 -0.0000 0.9113 70.4205 23.5734 -0.8447 5.2297 -10.7878 0.0154 0.7549 -0.6739 -1.5389 0.5673 0.1562 13.8555 -7.9721 3.6719 -2.4251 -5.0498 3.0885 -26.2026 -2.1230 0.6276 -3.4209 0.7176 4.0824 3.8199 -10.9794 15.5047 3.3381 -21.3809 53.2897 0.0000 0.0000 17.7073 -2.9852 -1.8206 -1.6349 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -13.4810 -14.2093 -24.3833 4.2128 18.7916 -72.3223 -0.0000 -0.0000 -0.6655 -1.7628 0.9291 -5.7616 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 6.7727 0.3365 11.9037 23.6908 0.0000 0.0000 -19.7089 -1.6111 4.7518 -2.7228 0.0000 -0.0000 -26.0063 -7.7269 -2.5057 32.7206 0.0000 0.0000 -7.9730 3.0286 7.9002 -7.3691 0.0000 -0.0000 1.2226 69.8878 23.6813 -0.2262 4.0798 -12.0716 -0.4581 1.4703 -0.6126 -1.7763 0.6431 0.1684 13.6266 -7.3588 3.3665 -2.4736 -4.6287 2.8519 -26.0574 -1.4238 0.9268 -2.8394 0.7852 3.9153 4.1258 -10.7028 15.8598 3.3325 -20.8207 53.0475 0.0000 0.0000 19.1316 -3.3434 -1.1969 -1.3921 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -12.5020 -13.1766 -24.1172 5.0350 18.5670 -73.0688 -0.0000 -0.0000 -0.5612 -1.1962 0.7216 -6.1796 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 4.3608 2.1846 12.2218 27.7813 0.0000 0.0000 -18.1272 -1.5283 5.5308 -3.3214 0.0000 -0.0000 -24.5200 -6.5274 0.4686 31.5731 0.0000 0.0000 -9.2203 1.6426 6.9621 -7.5447 0.0000 -0.0000 1.5105 69.4252 23.8034 0.6355 2.5829 -13.2679 -1.2096 2.4417 -0.5278 -2.1152 0.9204 0.2126 13.4831 -6.8510 2.9555 -2.4762 -4.2521 2.6640 -25.8344 -0.4702 1.2182 -2.3325 1.1503 3.8795 3.7196 -10.4913 16.1366 2.5352 -21.6165 52.6359 0.0000 0.0000 20.4808 -2.4889 -2.5194 -1.2157 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -11.6014 -11.9540 -23.9937 5.6619 18.0795 -73.1630 -0.0000 -0.0000 -0.2962 -0.5703 0.7374 -6.3292 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.1066 3.8950 12.8893 34.0739 0.0000 0.0000 -15.5669 -2.4615 6.6586 -3.3621 0.0000 -0.0000 -23.4255 -4.7146 2.0316 29.8387 0.0000 0.0000 -9.6977 0.7917 7.4417 -7.5735 0.0000 -0.0000 1.7428 69.0322 23.9039 1.3178 1.2207 -14.5834 -1.7214 3.3527 -0.4014 -2.3226 1.1609 0.2743 13.2766 -6.1262 2.7619 -2.5052 -3.8600 2.5310 -25.6328 0.4867 1.4428 -2.0670 1.6584 3.8178 3.0309 -9.9440 16.0807 1.4200 -22.5558 52.4769 0.0000 0.0000 22.0778 -0.8060 -4.0576 -1.2383 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -10.9190 -11.3178 -23.9349 6.0073 17.5705 -73.0672 -0.0000 0.0000 0.1442 -0.4487 0.6118 -6.1760 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.9484 4.7494 14.1529 41.6846 0.0000 0.0000 -12.4030 -2.9190 7.0143 -2.9817 0.0000 -0.0000 -22.4612 -3.2445 3.8956 28.3431 0.0000 0.0000 -9.6633 0.0257 7.5972 -7.5788 0.0000 -0.0000 1.9134 68.6677 23.9687 1.3956 0.1352 -15.9397 -1.7610 4.2512 -0.3091 -2.3148 1.2708 0.3194 12.9839 -5.2121 2.7389 -2.5776 -3.3896 2.3653 -25.2914 1.2293 1.7459 -1.9315 2.0319 3.7212 2.4225 -9.1182 15.7650 0.4307 -22.7695 52.7674 0.0000 0.0000 24.0801 1.3319 -4.1850 -1.2032 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -10.3419 -11.0002 -23.6445 6.0625 17.0875 -72.8662 -0.0000 0.0000 0.3564 -0.4209 0.1686 -6.0689 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -9.1053 5.0003 14.5377 48.3279 0.0000 0.0000 -10.9917 -0.4469 3.8376 -3.2223 0.0000 -0.0000 -20.9128 -2.1352 6.4125 26.8469 0.0000 0.0000 -9.9614 -0.8279 6.9507 -7.7307 0.0000 -0.0000 2.0259 68.3133 24.0241 1.0689 -0.3647 -17.1016 -1.6662 4.8697 -0.2429 -2.2229 1.2557 0.3323 12.9107 -4.3954 2.7874 -2.5961 -2.9048 2.2060 -24.8597 1.9141 2.0954 -1.8379 2.3529 3.5848 1.7215 -8.1713 15.4635 -1.2281 -23.5751 52.4432 0.0000 0.0000 26.8000 3.8704 -3.1778 -1.0928 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -9.5637 -10.2964 -23.0196 5.2702 17.4913 -72.3102 -0.0000 -0.0000 -0.5014 0.3172 -1.0360 -6.1662 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -11.8151 4.8465 13.1669 51.9816 0.0000 0.0000 -11.7909 4.5500 -4.3062 -3.4777 0.0000 -0.0000 -18.9440 -1.3705 8.1409 25.2973 0.0000 0.0000 -10.6614 -1.3731 6.7260 -7.7926 0.0000 -0.0000 2.0927 67.9828 24.0928 0.6971 -0.1020 -18.1307 -1.6152 4.9598 -0.1540 -2.1496 1.1184 0.3250 13.1421 -3.8280 3.0845 -2.4883 -2.5031 2.1844 -24.5042 2.6685 2.3167 -1.8017 2.7624 3.3667 0.8269 -6.9717 15.2043 -4.2819 -26.1332 50.5199 0.0000 0.0000 30.8685 6.5258 -1.8614 -0.9991 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -8.3901 -9.2106 -22.0692 3.1559 19.8722 -71.4760 -0.0000 -0.0000 -3.0598 2.2007 -3.2650 -6.2007 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -13.6038 4.2608 10.6302 51.9990 0.0000 0.0000 -12.9086 9.4471 -13.5987 -2.0893 0.0000 -0.0000 -17.0194 -1.2347 8.8682 24.0884 0.0000 0.0000 -11.2358 -1.6054 7.1788 -7.7167 0.0000 -0.0000 2.1377 67.6980 24.1606 0.5823 0.5039 -19.1202 -1.6216 4.8383 -0.0732 -2.1062 0.9094 0.3206 13.4004 -3.4815 3.5953 -2.3499 -2.2781 2.3110 -24.2260 3.2816 2.3829 -1.8051 3.1115 3.1761 -0.0257 -5.6095 14.7846 -8.2545 -29.3877 47.4597 0.0000 0.0000 36.4522 9.0194 -0.2433 -0.8750 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -7.0366 -8.1993 -20.7746 0.2983 23.9961 -70.6072 -0.0000 -0.0000 -7.2545 5.1406 -5.9883 -5.8835 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -15.2883 3.5565 7.9811 49.6592 0.0000 0.0000 -14.2318 11.3335 -17.5631 -0.0175 0.0000 -0.0000 -15.5260 -1.6116 9.7378 23.3424 0.0000 0.0000 -11.5980 -1.8812 7.2475 -7.8166 0.0000 -0.0000 2.1770 67.4458 24.2088 0.4991 0.9141 -19.7588 -1.4700 5.0669 -0.0715 -2.0382 0.7815 0.3226 13.4753 -3.3994 3.9619 -2.3129 -2.2306 2.4175 -23.8701 3.5401 2.3768 -1.7650 3.2600 3.1539 -0.5025 -4.7150 14.0039 -12.2947 -31.8769 44.7908 -0.0000 0.0000 42.6890 11.6097 1.6495 -0.7858 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -5.6791 -7.3435 -19.2173 -2.4047 28.0182 -69.8708 -0.0000 -0.0000 -12.2537 8.3364 -8.6618 -5.3488 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -16.7688 3.2739 5.4966 46.2393 0.0000 0.0000 -15.7216 9.5375 -14.8464 0.7739 0.0000 0.0000 -14.2433 -1.8210 10.8067 22.6678 0.0000 0.0000 -12.0542 -2.1946 6.7624 -8.0966 0.0000 -0.0000 2.2165 67.2019 24.2375 0.1942 0.9013 -19.7816 -1.1804 5.7404 -0.1208 -1.9329 0.8274 0.3314 13.5021 -3.5301 3.9833 -2.3603 -2.2765 2.4658 -23.3659 3.6098 2.2745 -1.6391 3.3534 3.2191 -0.8082 -4.4482 13.0136 -16.2927 -34.0872 42.6954 -0.0000 0.0000 48.9174 14.9109 3.0625 -0.9936 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -4.5254 -6.5890 -17.8183 -4.6850 31.2135 -69.1218 -0.0000 -0.0000 -17.3235 11.1090 -11.3460 -4.8528 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -17.8123 3.5926 3.2065 41.9974 0.0000 0.0000 -15.8008 6.4780 -9.7710 0.3726 0.0000 0.0000 -12.9453 -1.3480 11.1464 21.8008 0.0000 0.0000 -12.5489 -2.3559 6.6235 -8.2174 0.0000 -0.0000 2.2529 66.9643 24.2568 -0.2173 0.6311 -19.4232 -0.9673 6.4255 -0.1567 -1.8290 0.9411 0.3487 13.6501 -3.6220 3.9401 -2.3603 -2.2913 2.5115 -22.8353 3.7679 2.0596 -1.4565 3.5638 3.1472 -1.3340 -4.1857 12.1590 -20.4350 -36.8630 40.1056 -0.0000 0.0001 55.1859 18.8038 3.7263 -1.4584 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -3.8209 -6.1838 -16.8220 -6.5573 34.4270 -68.2516 -0.0000 -0.0000 -22.2455 13.4663 -13.8732 -4.3658 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -18.5445 4.0312 1.3675 36.9505 0.0000 0.0000 -14.5769 4.9234 -6.3005 -0.1688 0.0000 -0.0000 -11.6604 -0.4479 10.7853 20.8219 0.0000 0.0000 -12.7919 -2.5202 6.8994 -8.1169 0.0000 -0.0000 2.2778 66.7422 24.2738 -0.5369 0.3486 -18.9264 -0.8780 6.8203 -0.1557 -1.7679 1.0024 0.3601 13.8931 -3.5354 3.9747 -2.2576 -2.2052 2.5396 -22.4050 3.9853 1.8331 -1.2849 3.8375 2.9053 -2.1489 -3.4901 11.5779 -24.3755 -39.8229 36.8016 -0.0000 0.0001 61.3185 22.1847 4.4497 -1.7439 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -3.6522 -6.3359 -16.0019 -7.8417 38.0472 -67.4667 -0.0000 -0.0000 -26.9264 15.7825 -15.7919 -3.7386 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -19.2110 4.1184 0.2501 31.4518 0.0000 0.0000 -13.0126 4.7081 -4.9145 -0.3629 0.0000 -0.0000 -10.4052 0.3756 10.5924 19.7538 0.0000 0.0000 -12.7877 -2.9262 6.6950 -7.9777 0.0000 -0.0000 2.2820 66.5283 24.2937 -0.7838 0.1669 -18.0065 -0.7933 7.0284 -0.1517 -1.7154 1.0399 0.3486 14.1460 -3.4534 3.7896 -2.1133 -2.0627 2.4433 -22.0360 4.1179 1.6790 -1.1621 4.0467 2.6155 -2.9383 -2.7357 11.0752 -27.4448 -42.0587 34.0457 -0.0000 0.0001 66.4802 23.9691 5.8765 -1.4974 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -3.6999 -6.7197 -15.1418 -8.5834 41.0581 -67.0213 -0.0000 -0.0000 -31.1227 18.0046 -17.2055 -3.0822 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -19.8050 3.9512 -0.6355 26.0203 0.0000 0.0000 -11.3411 4.3450 -4.1403 -0.3981 0.0000 -0.0000 -9.0873 0.9709 10.6514 18.5107 0.0000 0.0000 -12.7346 -3.4113 5.6719 -7.7624 0.0000 -0.0000 2.2633 66.3032 24.3185 -1.1441 0.0355 -16.4005 -0.6127 7.2873 -0.1609 -1.6426 1.1194 0.3249 14.4226 -3.5990 3.1952 -1.9741 -1.9304 2.2440 -21.6206 4.2123 1.5346 -1.0218 4.2062 2.3132 -3.5030 -2.3657 10.5446 -29.4433 -43.2449 32.5537 -0.0000 0.0001 70.2111 24.4471 7.5779 -0.8543 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -3.7105 -6.9707 -14.3738 -9.0582 42.9244 -66.8537 -0.0000 -0.0000 -34.7490 19.7652 -18.5497 -2.6424 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -20.2291 3.9109 -2.0779 21.2379 0.0000 0.0000 -9.6516 3.4388 -2.8352 -0.7168 0.0000 -0.0000 -7.5607 1.5122 10.3177 17.0859 0.0000 0.0000 -12.6279 -3.6277 4.4016 -7.3836 0.0000 -0.0000 2.2264 66.0663 24.3424 -1.6052 -0.1297 -14.4964 -0.3916 7.6418 -0.1762 -1.5701 1.1621 0.2823 14.7208 -3.8755 2.5885 -1.8451 -1.8099 2.0310 -21.1366 4.3694 1.3502 -0.7700 4.4169 1.9704 -3.8528 -2.2867 10.2101 -30.7934 -43.4407 31.6922 -0.0000 0.0001 72.7560 24.9840 8.8765 -0.3293 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.6800 -7.1020 -13.7880 -9.3958 44.2104 -66.8778 -0.0000 -0.0000 -37.8979 20.8591 -19.7094 -2.4683 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -20.7487 4.0350 -3.7870 17.6661 0.0000 0.0000 -8.2359 2.5418 -0.9093 -1.2769 0.0000 -0.0000 -5.9204 2.0681 9.4293 15.6568 0.0000 0.0000 -12.4319 -3.5597 3.4212 -7.0737 0.0000 -0.0000 2.1784 65.8330 24.3544 -2.0184 -0.4039 -12.8784 -0.1866 8.0020 -0.1763 -1.4618 1.1585 0.2525 14.8686 -4.0754 2.2651 -1.7418 -1.7020 1.9295 -20.6151 4.5513 1.1850 -0.4317 4.7230 1.6282 -4.0952 -2.1509 10.2010 -31.6344 -42.9593 30.9483 -0.0000 0.0001 74.2474 26.1122 9.6618 -0.2086 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -3.7126 -7.3080 -13.2873 -9.5173 45.4445 -67.1209 -0.0000 -0.0000 -40.5651 21.5689 -20.2152 -2.3627 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -21.7301 4.1702 -4.5257 15.5879 0.0000 0.0000 -7.2931 2.0914 0.9678 -1.5843 0.0000 -0.0000 -4.3905 2.6197 8.4720 14.3882 0.0000 0.0000 -12.3272 -3.4312 2.7358 -7.0379 0.0000 -0.0000 2.1183 65.6017 24.3541 -2.4279 -0.7566 -11.5081 0.1460 8.2850 -0.1943 -1.2895 1.1665 0.2357 14.7741 -4.1261 2.1412 -1.7051 -1.6037 1.8761 -20.0515 4.6734 1.0598 -0.1447 5.0849 1.3434 -4.1483 -2.0677 10.2891 -31.7014 -42.1270 30.8900 -0.0000 0.0001 74.2757 26.8380 10.1093 -0.2303 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.8167 -7.6279 -12.8399 -9.4819 46.3454 -67.5210 -0.0000 -0.0000 -42.6123 22.4337 -20.0736 -2.0398 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -22.9064 4.2881 -4.0444 14.6242 0.0000 0.0000 -6.6103 2.1203 2.0873 -1.5369 0.0000 -0.0000 -2.9345 3.1225 7.7253 13.3101 0.0000 0.0000 -12.4335 -3.2769 2.0683 -7.0810 0.0000 -0.0000 2.0464 65.3578 24.3499 -2.8179 -1.2299 -10.0426 0.5359 8.5189 -0.2202 -1.0928 1.2268 0.2272 14.5761 -4.1297 2.0090 -1.7291 -1.5140 1.7987 -19.4873 4.8809 0.9545 0.0189 5.4581 1.0227 -3.8972 -2.3277 10.2900 -31.1240 -41.1280 31.7855 -0.0000 0.0001 72.8056 26.3501 10.1694 -0.0309 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -3.8931 -7.8020 -12.4578 -9.4352 46.4915 -68.0586 -0.0000 -0.0000 -44.0722 23.7364 -19.5408 -1.3405 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -23.9865 4.5528 -3.2575 14.2441 0.0000 0.0000 -5.9657 2.1916 2.3209 -1.5169 0.0000 -0.0000 -1.4728 3.6301 7.0521 12.2283 0.0000 0.0000 -12.5218 -2.9663 1.2526 -6.9964 0.0000 -0.0000 1.9623 65.0849 24.3478 -3.1899 -1.7609 -8.4694 0.8847 8.6822 -0.2109 -0.9215 1.2626 0.2117 14.4615 -4.1770 1.9103 -1.7602 -1.3922 1.7234 -19.0640 5.3790 0.8989 0.1285 5.8381 0.5697 -3.5159 -2.7808 10.4013 -30.5248 -40.1809 32.5378 -0.0000 0.0001 70.9509 25.3565 9.6264 0.2857 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.9496 -7.7702 -12.0187 -9.2911 46.3344 -68.7402 -0.0000 -0.0000 -45.4687 25.3240 -18.4409 -0.3781 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -24.7866 4.9430 -2.8620 14.1118 0.0000 0.0000 -5.4497 1.8347 2.1679 -1.6798 0.0000 -0.0000 0.2048 4.1172 6.2326 10.8508 0.0000 0.0000 -12.4331 -2.4716 0.4161 -6.9507 0.0000 -0.0000 1.8642 64.7864 24.3386 -3.3899 -2.2944 -6.9205 1.0884 8.7649 -0.1853 -0.7838 1.2205 0.1901 14.4243 -4.2567 1.9640 -1.7644 -1.2548 1.7052 -18.9210 6.1111 0.9044 0.2549 6.2593 0.0348 -3.2102 -3.0882 10.6969 -30.2508 -39.5546 32.2251 -0.0000 0.0001 69.9893 24.9108 8.6804 0.3544 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.1319 -7.8416 -11.5322 -8.9560 46.6124 -69.3039 -0.0000 -0.0000 -47.4342 26.8155 -16.7225 0.4205 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -25.4027 5.3393 -2.8888 14.0679 0.0000 0.0000 -5.1556 1.2658 2.1926 -1.7615 0.0000 -0.0000 1.8641 4.5104 5.1426 9.3694 0.0000 0.0000 -12.4403 -1.9513 -0.1669 -7.0897 0.0000 -0.0000 1.7467 64.4742 24.3146 -3.3014 -2.8440 -5.2706 1.1801 8.7982 -0.1542 -0.6964 1.1993 0.1816 14.4182 -4.3677 2.0653 -1.7823 -1.1682 1.7238 -19.0666 6.8318 0.8872 0.3458 6.7298 -0.4765 -2.9938 -3.3235 10.9081 -30.1311 -39.2862 31.2340 -0.0000 0.0001 70.1469 24.7889 7.8449 0.2016 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -4.3493 -8.0459 -11.2365 -8.7363 46.9265 -69.4917 -0.0000 -0.0000 -49.9126 27.8610 -15.3067 0.6637 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -25.8381 5.7568 -3.1530 13.9176 0.0000 0.0000 -4.8049 0.9859 2.3037 -1.5868 0.0000 -0.0000 3.0607 4.7509 3.9590 8.3567 0.0000 0.0000 -12.7957 -1.4962 -0.6826 -7.2154 0.0000 -0.0000 1.6063 64.1498 24.2841 -2.9174 -3.3949 -3.4763 1.1831 8.7553 -0.0686 -0.7131 1.2588 0.1903 14.5207 -4.5189 2.1059 -1.8584 -1.1359 1.7260 -19.4287 7.4745 0.8711 0.3076 7.1993 -0.9333 -2.7008 -3.8829 10.9525 -30.0200 -39.0167 30.3996 -0.0000 0.0001 70.9155 24.2215 7.3567 0.1619 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -4.4574 -8.0207 -11.2135 -8.8561 46.6084 -69.3148 -0.0000 -0.0000 -52.4502 28.3953 -15.0212 0.3901 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -26.1368 6.1794 -3.3248 13.7356 0.0000 0.0000 -3.9049 0.6589 1.9986 -1.3281 0.0000 -0.0000 3.7100 4.8067 2.9889 7.9167 0.0000 0.0000 -13.3095 -0.9690 -1.5226 -7.1841 0.0000 -0.0000 1.4433 63.7951 24.2536 -2.3355 -3.8113 -1.8598 1.0504 8.5403 0.0634 -0.8175 1.2886 0.1987 14.7478 -4.7124 2.2045 -1.9600 -1.0817 1.7215 -19.9499 8.1647 1.0581 0.1286 7.5846 -1.2998 -2.3113 -4.6667 11.1652 -30.0715 -38.6487 29.6331 -0.0000 0.0001 72.1275 23.4785 6.8481 0.3343 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -4.3953 -7.6123 -11.1426 -9.1380 45.9886 -69.0018 -0.0000 -0.0000 -54.9189 28.5477 -15.1595 0.0117 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -26.4537 6.3850 -3.0707 14.0110 0.0000 0.0000 -2.1109 -0.4323 1.3989 -1.2111 0.0000 -0.0000 4.2142 4.6320 2.2477 7.5359 0.0000 0.0000 -13.8379 -0.2321 -2.4794 -7.1824 0.0000 -0.0000 1.2622 63.3883 24.2084 -1.6172 -4.1689 -0.5309 0.7381 8.2298 0.1751 -0.9060 1.2140 0.1878 14.9363 -4.8272 2.4039 -2.0195 -0.9828 1.7218 -20.6311 8.7501 1.4504 -0.1551 7.8104 -1.5058 -1.9517 -5.2354 11.6570 -30.4095 -38.4824 28.4974 -0.0000 0.0001 73.8656 23.4273 5.7198 0.4526 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -4.5273 -7.4501 -10.9870 -9.2349 46.1886 -68.3470 -0.0000 -0.0000 -57.6556 28.6604 -14.3058 -0.1779 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -26.7385 6.4393 -2.5036 14.9332 0.0000 0.0000 0.6189 -1.7813 1.3300 -1.2302 0.0000 -0.0000 4.8242 4.3735 1.5101 6.9604 0.0000 0.0000 -14.5882 0.5931 -3.1035 -7.2985 0.0000 -0.0000 1.0621 62.9201 24.1371 -0.7780 -4.7096 0.9045 0.3554 7.9638 0.3050 -1.0481 1.2303 0.1955 15.1080 -4.7973 2.4659 -2.0650 -0.9238 1.6800 -21.5157 8.9343 1.7328 -0.5913 7.8360 -1.5679 -1.5735 -5.6815 12.0310 -30.8501 -38.3420 27.4942 -0.0000 0.0001 75.7647 24.0832 3.8168 0.3026 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.8514 -7.5562 -10.9831 -9.3320 46.5445 -67.5332 -0.0000 -0.0000 -60.2966 28.8344 -12.5490 -0.3588 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -26.4896 6.6852 -1.8549 15.7819 0.0000 0.0000 3.8411 -2.0155 1.7843 -1.2161 0.0000 -0.0000 5.4742 4.2210 0.6541 6.3910 0.0000 0.0000 -15.5017 1.3456 -3.5799 -7.3498 0.0000 -0.0000 0.8329 62.3956 24.0543 0.3333 -5.2581 2.4155 -0.2005 7.5030 0.6236 -1.4107 1.4961 0.2575 15.5313 -4.7339 2.3940 -2.2044 -0.9444 1.5947 -22.6491 8.8881 1.8562 -1.3075 7.7167 -1.5841 -1.1012 -6.4533 12.1547 -30.9890 -37.4816 27.4283 -0.0000 0.0001 77.2939 24.7631 1.5539 -0.0266 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -4.9545 -6.7997 -11.0054 -9.6686 45.0894 -67.3538 -0.0000 -0.0001 -62.0099 28.8184 -10.9843 -0.8391 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -25.8680 6.8372 -0.6572 16.2072 0.0000 0.0000 6.1570 -1.2396 1.4127 -1.0049 0.0000 -0.0000 5.9919 3.9564 -0.1917 5.7822 0.0000 0.0000 -16.2065 2.1745 -4.1777 -7.3600 0.0000 -0.0000 0.5554 61.8208 23.9815 1.4984 -4.8771 3.0287 -0.7955 6.1737 1.0683 -1.9253 1.5987 0.3162 16.1079 -4.7464 2.7666 -2.4721 -0.9278 1.6258 -23.9502 9.0426 2.2578 -2.3612 7.5197 -1.5418 -0.8032 -7.2066 12.5710 -30.6290 -35.9462 27.7200 -0.0000 0.0001 78.5818 25.2377 -0.5893 -0.3934 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.5475 -4.6572 -10.5725 -10.2563 41.5599 -68.0120 -0.0000 -0.0001 -62.6625 28.3034 -9.6832 -1.6859 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -25.6670 5.5782 1.4916 17.1777 0.0000 0.0000 6.1049 -0.8001 -0.5101 -0.5549 0.0000 -0.0000 6.5391 2.7136 -0.5772 5.1585 0.0000 0.0000 -17.1077 3.3444 -4.3519 -7.6339 0.0000 -0.0000 0.2269 61.2409 23.9133 2.4884 -3.2481 2.2831 -1.0240 4.1763 1.2767 -2.1474 0.9108 0.2487 16.0759 -4.6719 3.9404 -2.7591 -0.8787 1.8961 -25.2039 9.0082 2.9972 -3.6615 7.0649 -1.3197 -0.8490 -6.9404 13.6334 -30.2297 -35.1453 26.8805 -0.0000 0.0001 80.2493 25.8387 -2.4154 -0.8179 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.0852 -2.8609 -9.9132 -10.9962 38.4759 -68.3295 -0.0000 -0.0001 -62.9173 27.7107 -8.2429 -2.8300 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -26.5799 2.5290 3.3959 19.7941 0.0000 0.0000 3.7082 -0.8640 -2.5298 0.0636 0.0000 0.0000 6.4188 0.2266 0.5303 6.3233 0.0000 0.0000 -19.2757 4.8405 -4.2517 -8.1384 0.0000 -0.0000 -0.1292 60.7184 23.8497 3.2068 -1.3261 1.5997 -0.6296 2.5832 0.9936 -1.8007 -0.2057 0.1021 15.1635 -4.2503 5.2019 -2.9216 -1.1683 2.2846 -26.2006 7.4529 3.1068 -5.1181 5.9277 -0.9032 -0.7461 -5.5221 14.8400 -30.8731 -36.1967 24.3655 -0.0000 0.0001 82.5217 26.6930 -3.8235 -1.3411 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.8703 -3.4159 -10.0888 -12.1217 37.4261 -67.4494 -0.0000 -0.0001 -62.7660 27.6913 -8.1533 -4.2720 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -27.7556 -0.6498 3.3426 23.0012 0.0000 0.0000 0.6807 -0.4361 -3.2423 0.6693 0.0000 0.0000 4.3488 -2.7841 2.3961 11.7050 0.0000 0.0000 -22.2449 6.1765 -4.7868 -8.4058 0.0000 -0.0000 -0.4889 60.2580 23.8200 3.3890 0.2088 2.5257 0.1660 1.6121 0.5220 -1.2888 -0.6489 0.0707 14.2225 -3.7558 5.5633 -2.8963 -1.9753 2.5569 -26.8124 3.8176 1.5918 -6.7424 3.7708 -0.3844 0.1167 -3.8210 15.3731 -33.1566 -38.6671 20.8877 -0.0000 0.0001 84.9858 27.6048 -4.6842 -1.8317 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -3.7349 -5.9395 -11.8407 -13.9084 37.0842 -65.8078 -0.0000 -0.0001 -61.5743 27.7142 -11.3682 -5.9455 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -27.6570 -2.6933 1.6398 24.8303 0.0000 0.0000 -1.5919 0.6767 -3.4070 1.0792 0.0000 0.0000 0.4752 -5.6438 1.8381 20.5223 0.0000 0.0000 -23.6578 6.3966 -5.2999 -8.3881 0.0000 -0.0000 -0.8178 59.8304 23.8615 3.2786 1.1901 4.5893 0.6930 1.1987 0.2407 -1.0413 -0.4280 0.1225 13.9223 -3.5555 5.2199 -2.6758 -3.0638 2.7810 -27.0424 -0.6769 -1.2290 -8.4135 0.7833 0.1455 1.3884 -2.4799 14.9453 -35.9270 -41.6894 17.5459 -0.0000 0.0001 87.1570 28.5744 -5.4322 -2.2041 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -3.5110 -8.1565 -14.4508 -15.5565 35.7402 -64.7522 -0.0000 -0.0000 -59.2850 26.6557 -16.6515 -7.6147 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -26.2733 -3.7002 -0.4965 24.7200 0.0000 0.0000 -2.9858 1.5897 -3.5946 1.2678 0.0000 0.0000 -4.1116 -7.6049 -0.4896 29.5442 0.0000 0.0000 -22.5934 5.0403 -5.6156 -7.7069 0.0000 -0.0000 -1.0796 59.3977 23.9766 3.0172 1.6641 5.9290 0.8524 1.1309 0.1724 -1.0101 -0.1826 0.1939 14.0703 -3.5470 5.2161 -2.3092 -4.0663 3.1252 -26.8355 -4.6009 -4.0827 -9.5952 -2.2288 0.5193 2.1391 -1.6584 14.1595 -37.4253 -44.5992 15.2233 -0.0000 0.0001 88.7904 29.7540 -7.1532 -2.7972 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.3422 -8.9338 -16.3870 -15.8140 33.8410 -65.0893 -0.0000 -0.0000 -56.4251 24.9587 -20.4346 -9.1037 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -24.1138 -4.2685 -2.4572 23.3170 0.0000 0.0000 -3.8410 1.7048 -2.9701 1.2955 0.0000 0.0000 -7.7472 -8.6328 -1.8542 36.1703 0.0000 0.0000 -21.1014 2.4969 -4.5684 -6.2282 0.0000 -0.0000 -1.2586 58.9668 24.1102 2.8807 1.6027 5.6835 0.7056 1.1595 0.1786 -1.0238 -0.1625 0.2554 14.2076 -3.3777 5.9361 -1.9206 -4.7502 3.5864 -26.0672 -7.3975 -6.0967 -9.7122 -4.5960 0.4183 2.1999 -1.1233 13.6123 -37.1176 -46.9507 14.6073 -0.0000 0.0001 89.5617 31.2144 -10.2523 -3.9580 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -3.3405 -8.5803 -17.0598 -14.8566 31.7040 -66.5194 -0.0000 -0.0000 -52.8389 24.1752 -21.1690 -9.9719 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -22.0511 -4.4170 -4.4540 21.8462 0.0000 0.0000 -4.4936 1.2657 -0.6326 1.3007 0.0000 0.0000 -10.0999 -8.9686 -1.4272 39.9294 0.0000 0.0000 -20.6824 0.0061 -1.2711 -6.0682 0.0000 -0.0000 -1.3783 58.5500 24.2122 2.6703 1.1383 4.6854 0.6501 1.0580 0.2134 -0.9938 -0.1947 0.3049 14.1372 -2.9613 6.7712 -1.6181 -5.1020 3.9249 -24.7615 -9.3761 -7.3236 -8.7417 -6.2139 -0.1348 2.2551 -0.8188 13.3473 -35.2296 -48.2329 16.5388 -0.0000 0.0001 88.7193 32.7409 -13.2483 -5.2825 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -3.4539 -7.9046 -17.0825 -13.7472 28.5788 -68.2292 -0.0000 -0.0000 -48.0483 24.8633 -19.7389 -9.4699 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -20.2045 -4.1462 -6.4343 20.9766 0.0000 0.0000 -5.2227 0.7265 2.5101 1.4391 0.0000 0.0000 -11.5810 -8.9557 -0.0505 41.4123 0.0000 0.0000 -20.7851 -1.6793 2.2455 -7.3317 0.0000 -0.0000 -1.4738 58.1517 24.2785 2.3113 0.6681 3.9330 0.7332 0.7825 0.2519 -0.9678 -0.1373 0.3353 13.9942 -2.6397 7.0831 -1.3846 -5.2542 4.0169 -23.1137 -10.9445 -8.0151 -7.1653 -7.2104 -0.6536 2.5667 -0.7938 13.0845 -31.6292 -48.0777 21.5079 -0.0000 0.0001 85.3005 33.7199 -13.6565 -5.8725 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.7745 -7.4015 -17.1700 -12.7547 24.5321 -69.4903 -0.0000 -0.0000 -42.3545 25.8380 -16.5877 -7.5240 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -18.5175 -3.8624 -7.8615 20.5841 0.0000 0.0000 -6.1028 0.2809 4.7900 1.6682 0.0000 0.0000 -12.8097 -9.0768 1.3412 41.2575 0.0000 0.0000 -20.6730 -2.1145 2.9986 -8.0498 0.0000 -0.0000 -1.5604 57.7688 24.3257 1.9501 0.4652 3.5316 0.7578 0.4630 0.2537 -0.9855 -0.0597 0.3327 13.9151 -2.6913 6.8731 -1.1290 -5.3566 3.9833 -21.3700 -12.1550 -8.2586 -5.4290 -7.6962 -0.8109 2.7136 -0.9250 12.6166 -26.6753 -46.6008 28.5880 -0.0000 0.0001 79.0370 33.2505 -10.8754 -5.5491 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -4.3535 -7.0945 -17.4605 -11.4050 20.5960 -70.4156 -0.0000 -0.0000 -35.8089 25.2179 -12.2868 -5.4772 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -17.0194 -3.8913 -8.6650 20.3584 0.0000 0.0000 -6.9753 0.0988 5.9605 1.8000 0.0000 0.0000 -14.0024 -9.5825 2.6170 39.7288 0.0000 0.0000 -20.1864 -1.2920 0.6226 -7.8907 0.0000 -0.0000 -1.6387 57.3993 24.3560 1.6396 0.4374 3.2740 0.7135 0.2166 0.2197 -1.0005 0.0008 0.3101 13.8954 -2.9501 6.4577 -0.8352 -5.4767 3.9559 -19.8393 -13.0819 -8.3550 -3.7484 -7.9198 -0.8312 2.3748 -0.9746 12.0412 -21.9473 -44.5665 35.5127 -0.0000 0.0001 71.0751 31.3731 -7.2662 -4.9669 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -5.1303 -6.9810 -18.0370 -9.4140 17.0464 -71.7440 -0.0000 -0.0000 -27.3624 21.8734 -9.2523 -4.8026 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -15.6601 -4.0903 -9.3076 20.2154 0.0000 0.0000 -7.7892 0.3342 6.8358 1.7832 0.0000 0.0000 -15.1606 -10.2393 3.8762 37.0885 0.0000 0.0000 -19.3457 0.0333 -2.7501 -7.5073 0.0000 -0.0000 -1.7074 57.0450 24.3649 1.3097 0.3432 3.1017 0.7495 0.0643 0.1876 -0.9766 0.1155 0.2984 13.9067 -3.0615 6.0450 -0.5603 -5.6136 3.9400 -18.7101 -13.9820 -8.7332 -2.3022 -8.2792 -1.0642 1.8244 -0.7770 11.6375 -18.8181 -42.8745 40.5523 -0.0000 0.0001 63.3356 29.5097 -5.3243 -4.9067 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.1793 -7.2442 -19.1623 -6.6751 13.5428 -73.5842 -0.0000 -0.0000 -17.0837 15.7715 -7.9534 -5.4950 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -14.3841 -4.1814 -9.9068 20.2780 0.0000 0.0000 -8.7301 0.8504 7.7153 1.7519 0.0000 0.0000 -16.3887 -10.6347 5.0460 33.7967 0.0000 0.0000 -18.2170 1.4253 -5.1724 -7.7603 0.0000 -0.0000 -1.7628 56.7055 24.3605 1.0436 0.1231 2.7561 0.8426 0.0037 0.1791 -0.9506 0.2703 0.3122 13.9406 -2.9671 5.7801 -0.3376 -5.7255 3.9227 -17.8700 -14.9379 -9.4002 -1.2437 -8.8770 -1.4805 1.4425 -0.3556 11.5368 -17.0673 -41.5049 43.8332 -0.0000 0.0001 57.0924 28.5742 -5.4756 -5.5835 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -7.7777 -8.0838 -20.6290 -3.1451 11.7647 -75.0463 -0.0000 -0.0000 -7.7706 9.5015 -5.6741 -6.0841 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -13.3601 -4.1585 -10.0711 20.6345 0.0000 0.0000 -9.8229 1.3366 8.3557 1.7756 0.0000 0.0000 -17.8155 -10.6613 6.2348 30.1749 0.0000 0.0000 -16.7415 3.1662 -6.0515 -9.9485 0.0000 -0.0000 -1.8045 56.3643 24.3551 0.9137 -0.0156 1.8876 0.9093 -0.0500 0.1780 -0.9470 0.3636 0.3267 13.9549 -2.8607 5.7626 -0.1521 -5.7859 3.9488 -17.1124 -15.8108 -9.9354 -0.5086 -9.4059 -1.8313 1.2511 0.0628 11.5982 -15.4243 -39.5220 46.7157 -0.0000 0.0001 52.2818 27.8782 -6.6185 -6.3897 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -9.3920 -9.1325 -21.5162 0.4136 12.6337 -75.9034 -0.0000 -0.0000 -1.7737 6.3478 -1.4491 -5.9047 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -12.5258 -4.2661 -9.7386 21.0118 0.0000 0.0000 -10.8114 1.6496 8.9058 1.7719 0.0000 0.0000 -19.2876 -10.6263 7.6597 26.4434 0.0000 0.0000 -15.2158 4.7764 -5.5872 -13.6086 0.0000 -0.0000 -1.8419 55.9986 24.3489 0.8591 0.1629 0.6632 0.9087 -0.2840 0.1789 -0.9256 0.3980 0.3312 13.9315 -2.8324 5.8942 -0.0047 -5.8312 4.0055 -16.4224 -16.5404 -10.1360 0.1087 -9.6574 -2.0084 1.2487 0.1425 11.5673 -13.3935 -36.2075 50.0759 -0.0000 0.0000 48.0868 26.6171 -7.3082 -6.6977 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -10.3234 -9.8957 -21.5675 3.4142 14.1594 -76.3378 -0.0000 0.0000 0.8837 6.2649 3.4512 -5.8570 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -11.4965 -4.6951 -9.3781 20.9621 0.0000 0.0000 -11.5838 1.8121 9.7430 1.7188 0.0000 0.0000 -20.7601 -10.8390 9.1402 23.1981 0.0000 0.0000 -14.4335 4.9747 -4.3519 -14.6071 0.0000 -0.0000 -1.8835 55.5917 24.3411 0.5932 0.6159 -0.4339 1.0388 -0.7468 0.1999 -0.8384 0.4474 0.3275 13.8802 -2.7697 5.9847 0.0966 -5.8829 4.0259 -15.9039 -17.2112 -10.1741 0.6776 -9.7513 -2.1301 1.2854 -0.0093 11.4186 -11.5214 -32.5888 53.2557 -0.0000 0.0000 44.1509 25.2378 -6.9430 -6.6379 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -10.4332 -10.1375 -21.3088 5.6309 15.0087 -76.3753 -0.0000 0.0000 1.4820 7.1302 7.1852 -6.2760 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -9.8111 -5.3500 -9.2822 20.3367 0.0000 0.0000 -12.2814 1.8235 10.8050 1.7064 0.0000 0.0000 -22.1660 -11.2307 10.3324 20.9510 0.0000 0.0000 -14.5417 3.9598 -3.4120 -12.2325 0.0000 -0.0000 -1.9258 55.1572 24.3327 0.2644 1.1021 -1.3587 1.2319 -1.2248 0.2385 -0.7193 0.4868 0.3322 13.8060 -2.5958 6.0638 0.1377 -5.9025 4.0082 -15.6019 -17.7894 -10.2395 1.1196 -9.8236 -2.3220 1.1539 -0.0059 11.2989 -10.1587 -30.2537 55.5150 -0.0000 0.0000 40.6514 24.3324 -6.0522 -6.7937 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -9.9783 -9.8220 -20.9508 7.0710 15.5202 -76.3256 -0.0000 0.0000 1.5255 7.2523 8.6655 -6.5253 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -7.9048 -5.9901 -9.2007 19.5602 0.0000 0.0000 -12.9649 1.7325 11.6913 1.7148 0.0000 0.0000 -23.7657 -11.5717 11.2156 19.6224 0.0000 0.0000 -14.6257 3.3365 -3.6130 -10.6729 0.0000 -0.0000 -1.9599 54.7076 24.3204 0.0550 1.4265 -2.3754 1.4183 -1.4732 0.2712 -0.6286 0.4527 0.3364 13.7247 -2.3506 6.2666 0.1245 -5.8348 4.0132 -15.5088 -18.1539 -10.3502 1.4161 -9.8637 -2.6261 0.7422 0.2841 11.3411 -9.1295 -29.2869 56.8724 0.0000 0.0000 37.7330 23.6854 -5.3954 -7.2097 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.3922 -9.2337 -20.4287 8.1090 16.0792 -76.4693 -0.0000 0.0000 1.6534 6.5969 8.3093 -6.3634 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -6.2511 -6.4070 -8.9585 19.0848 0.0000 0.0000 -13.6689 1.7156 12.3877 1.6322 0.0000 0.0000 -25.5824 -11.6770 11.9137 18.7068 0.0000 0.0000 -13.9812 3.5108 -4.3270 -11.1471 0.0000 -0.0000 -1.9866 54.2334 24.2919 -0.0931 1.6165 -3.4108 1.5653 -1.5433 0.2957 -0.5477 0.4364 0.3491 13.6697 -2.0606 6.5040 0.0919 -5.7208 4.0180 -15.5843 -18.3055 -10.5292 1.6516 -9.9220 -3.0136 0.2850 0.7120 11.5325 -8.3203 -28.4984 57.7597 0.0000 0.0000 35.3342 23.0345 -5.1660 -7.4030 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -8.8806 -8.7464 -19.9504 8.9220 16.4744 -76.6204 -0.0000 0.0000 1.7152 6.1513 7.3761 -6.2442 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -4.7477 -6.6054 -8.6903 18.9491 0.0000 0.0000 -14.6026 1.8083 13.1707 1.4945 0.0000 0.0000 -27.3344 -11.4539 12.5159 17.8618 0.0000 0.0000 -13.2428 3.6241 -4.2361 -10.8392 0.0000 -0.0000 -2.0126 53.7225 24.2447 -0.2432 1.7868 -4.2597 1.6548 -1.5932 0.3341 -0.4780 0.5020 0.3698 13.6270 -1.6834 6.6376 0.0772 -5.6154 3.9751 -15.7525 -18.3618 -10.8288 1.8807 -10.0754 -3.4117 0.0242 1.1981 11.7313 -7.7305 -27.5402 58.4235 0.0000 0.0000 33.5271 22.7118 -5.1750 -7.2166 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -8.3833 -8.4434 -19.7543 9.4277 16.6405 -76.5328 -0.0000 0.0000 1.5779 6.3309 6.7561 -6.3988 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -3.1688 -6.7170 -8.4250 18.9422 0.0000 0.0000 -15.8026 1.6955 14.0712 1.4465 0.0000 0.0000 -28.6885 -10.8742 13.3744 16.8277 0.0000 0.0000 -13.1555 3.4205 -3.2545 -9.0274 0.0000 -0.0000 -2.0399 53.1924 24.1879 0.0011 2.0397 -5.1217 1.5237 -1.6643 0.3830 -0.4959 0.5410 0.3897 13.4880 -1.2843 6.7739 0.0373 -5.4726 3.9140 -15.9692 -18.3430 -11.1152 2.0806 -10.2537 -3.7752 0.0588 1.5259 11.7953 -7.4070 -26.7631 59.0330 0.0000 0.0000 32.4132 22.3257 -5.3509 -7.0684 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -7.8762 -8.0517 -19.6161 9.7845 16.7653 -76.3818 -0.0000 0.0000 1.4225 6.4857 6.5470 -6.5766 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.9428 -6.8893 -8.0297 18.9664 0.0000 0.0000 -16.9038 1.1237 14.9249 1.4594 0.0000 0.0000 -29.9037 -10.1171 14.7601 15.3282 0.0000 0.0000 -13.0663 3.2884 -2.3422 -8.0750 0.0000 -0.0000 -2.0648 52.6514 24.1232 0.8491 2.3453 -6.1530 1.1528 -1.6915 0.3883 -0.6485 0.4856 0.4030 13.2253 -0.9252 7.0094 -0.1145 -5.2699 3.8511 -16.2779 -18.2165 -11.2259 2.2009 -10.4777 -4.1425 0.1502 1.4923 11.8136 -7.2705 -26.4020 59.5157 0.0000 0.0000 32.0038 21.0215 -5.8100 -7.2483 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -7.4632 -7.3782 -19.2157 10.2636 16.8146 -76.4283 -0.0000 0.0000 1.4165 6.0641 6.5988 -6.4775 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -1.2262 -7.1139 -7.6474 18.8322 0.0000 0.0000 -17.7617 0.4598 15.7524 1.3706 0.0000 0.0000 -31.3860 -9.2558 16.0266 13.5715 0.0000 0.0000 -12.1884 3.0338 -1.5151 -8.2507 0.0000 -0.0000 -2.0831 52.0560 24.0445 1.7532 2.4670 -6.9875 0.7343 -1.6110 0.3518 -0.7980 0.5244 0.4294 12.9292 -0.4934 7.1344 -0.3364 -5.0310 3.7088 -16.6887 -18.1804 -11.3460 2.1921 -11.0832 -4.5778 0.2899 1.1858 11.9389 -7.2863 -26.0614 59.7257 0.0000 0.0000 32.0131 19.3396 -6.1894 -7.4350 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.0664 -6.5814 -18.6624 10.7061 16.6153 -76.6133 -0.0000 0.0000 1.4994 5.6374 6.7011 -6.2057 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.2002 -7.1382 -7.5332 18.2224 0.0000 0.0000 -18.7843 0.3184 16.5853 1.1467 0.0000 0.0000 -32.6825 -7.8910 16.3405 12.3037 0.0000 0.0000 -11.2547 1.6970 -0.1276 -7.7056 0.0000 -0.0000 -2.0892 51.3453 23.9562 2.1049 2.1580 -7.6034 0.3647 -1.3390 0.3173 -0.9230 0.6916 0.4772 12.7720 0.3029 7.1783 -0.4755 -4.7349 3.4834 -17.0578 -18.4987 -11.7137 2.0608 -12.2273 -5.0845 0.6288 1.1608 12.1422 -7.1616 -25.6016 59.8550 0.0000 0.0000 31.8302 18.8614 -5.8451 -7.1604 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.4878 -5.6327 -18.1250 10.9167 16.3188 -76.7760 -0.0000 0.0000 1.5043 5.9238 6.5350 -6.0914 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 1.7942 -6.6212 -7.3984 17.2601 0.0000 0.0000 -20.1345 0.4409 17.3057 0.8888 0.0000 0.0000 -32.3635 -5.6518 16.1552 11.3907 0.0000 0.0000 -10.6782 -0.9203 0.8347 -7.3661 0.0000 -0.0000 -2.0910 50.5296 23.8529 2.6122 1.6955 -8.9956 -0.4997 -1.0714 0.2712 -1.2645 0.6927 0.5347 12.6973 1.4683 7.7025 -0.4683 -4.2977 3.3600 -17.2780 -19.1148 -12.0423 1.9908 -13.4147 -5.5461 0.9620 1.6024 12.3447 -6.2807 -25.0755 60.5234 0.0000 0.0000 30.8741 19.0915 -5.2034 -6.5314 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.8424 -4.1050 -17.2835 11.3538 16.1107 -76.9549 -0.0000 0.0000 1.4528 6.1372 6.0671 -6.2030 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.5261 -5.7586 -6.5235 16.8957 0.0000 0.0000 -21.3694 -0.2761 17.9938 0.6748 0.0000 0.0000 -30.2631 -3.3355 15.8816 9.5154 0.0000 0.0000 -8.3275 -3.3587 -0.0850 -9.5539 0.0000 -0.0000 -2.0944 49.6541 23.7263 3.7124 0.9010 -11.6682 -1.9679 -0.3681 0.1306 -1.9355 0.4025 0.5780 12.6201 2.7173 8.8687 -0.4982 -3.7957 3.4041 -17.5445 -19.8566 -11.8795 2.1394 -14.0271 -5.7868 1.0710 1.3641 12.7014 -4.7587 -23.5242 62.0176 0.0000 0.0000 29.2477 17.7663 -5.7176 -5.7988 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -5.4692 -1.8245 -15.8504 12.4530 15.4934 -76.9924 -0.0000 0.0000 1.5575 5.1228 5.8426 -6.2449 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 3.9125 -4.2112 -5.3435 18.0533 0.0000 0.0000 -22.5848 -2.0733 19.4958 0.3733 0.0000 0.0000 -27.4470 -1.4189 14.3137 5.9548 0.0000 0.0000 -1.5528 -4.3397 -1.3706 -12.0352 0.0000 -0.0000 -2.0890 48.7368 23.6073 4.2070 -1.3601 -14.3898 -3.2604 1.9932 -0.0152 -2.6688 0.3177 0.6443 12.7067 3.9944 9.8236 -0.7404 -3.4518 3.3651 -18.1863 -20.7997 -11.5351 2.2487 -14.1384 -5.8178 1.2891 -0.7360 13.2675 -3.8164 -20.4261 63.5909 0.0000 0.0000 27.9779 15.2716 -7.5141 -5.0629 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -5.2670 0.5932 -14.3917 13.6121 13.7405 -76.3849 -0.0000 0.0000 1.9234 3.8885 6.0452 -5.9487 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 3.6074 -0.6746 -5.2372 21.0190 0.0000 0.0000 -24.3006 -3.5560 22.1340 -0.4219 0.0000 -0.0000 -24.5814 1.2262 10.5396 1.9488 0.0000 0.0000 7.9167 -4.0427 -0.1313 -10.4627 0.0000 -0.0000 -2.0667 47.8042 23.5773 3.2272 -5.0277 -15.9047 -3.8230 5.4419 -0.0186 -3.1209 0.9774 0.8216 12.9887 5.7897 10.0044 -1.1105 -3.2354 3.0244 -19.0382 -21.7248 -11.7239 1.8450 -14.2486 -5.9881 2.1575 -3.7795 13.6917 -4.2905 -17.8024 64.4683 0.0000 0.0000 27.8231 14.4251 -8.5052 -4.3695 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -4.6939 2.4918 -13.7932 14.0224 11.4004 -74.9685 -0.0000 0.0000 2.3526 4.3935 5.8215 -5.4623 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 3.1146 4.7582 -5.9030 25.9553 0.0000 0.0000 -25.3961 -3.7867 24.4611 -2.1150 0.0000 -0.0000 -21.9713 5.1672 6.8428 -0.0461 0.0000 -0.0000 13.5117 -3.1445 2.8381 -7.3569 0.0000 -0.0000 -2.0463 46.9256 23.7033 1.9268 -7.6951 -16.8999 -3.8802 6.9529 0.0720 -3.1940 1.6892 1.0275 13.0452 8.3978 10.2566 -1.3566 -2.6280 2.5992 -19.4659 -21.5185 -12.2050 1.0691 -14.2276 -6.7173 3.0749 -5.4166 13.5110 -5.3433 -19.2176 64.6412 0.0000 0.0000 28.3411 15.0095 -7.8860 -3.7357 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.6249 4.1740 -13.8477 13.8801 10.1265 -73.4693 -0.0000 0.0000 2.7332 5.8026 4.3253 -5.0160 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 1.3353 9.0561 -4.7331 32.9175 0.0000 0.0000 -22.2950 -4.6519 24.7918 -4.2628 0.0000 -0.0000 -19.6980 8.2779 6.4296 0.3522 0.0000 0.0000 12.3086 -2.7796 4.2882 -6.5511 0.0000 -0.0000 -2.0663 46.1523 23.9409 1.4892 -7.3671 -18.6351 -3.6870 5.3047 0.2180 -3.0421 1.2476 1.0351 12.5453 10.7734 11.5198 -1.4149 -1.3375 2.4327 -19.0205 -18.8250 -11.7099 0.8631 -13.2974 -7.8844 2.8048 -4.6989 12.9551 -6.0607 -25.6382 63.8346 0.0000 0.0000 28.9927 13.0797 -7.9588 -2.9519 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -2.5705 6.2399 -13.4786 13.9244 10.9670 -72.7617 -0.0000 0.0000 3.2526 5.2471 2.1489 -4.6726 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.3685 9.4989 -0.4954 40.7828 0.0000 0.0000 -13.5050 -9.7298 23.1553 -4.3202 0.0000 -0.0000 -17.1535 8.2187 8.9104 0.6992 0.0000 0.0000 8.5676 -3.1911 3.2648 -7.8236 0.0000 -0.0000 -2.1112 45.4792 24.1720 1.7554 -5.4952 -20.6273 -3.3643 2.9822 0.4031 -2.7973 0.0003 0.8757 11.8247 11.5606 13.1543 -1.4253 0.1284 2.5232 -17.9528 -13.6434 -9.7614 1.7954 -11.0677 -8.7851 1.2175 -3.1572 12.8010 -7.4734 -33.9527 61.1501 0.0000 0.0000 30.3333 7.0032 -10.3515 -2.2389 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.8915 8.0156 -12.4221 14.5543 13.2870 -73.0916 -0.0000 0.0000 4.1212 2.8532 1.0686 -4.4304 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -6.2789 7.7877 3.5811 47.0238 0.0000 0.0000 -4.9411 -17.3728 21.1132 -1.1194 0.0000 -0.0000 -14.7571 6.4442 11.2290 0.4534 0.0000 0.0000 6.2768 -3.5040 1.8526 -9.0272 0.0000 -0.0000 -2.1590 44.8512 24.3308 1.7387 -4.0535 -21.1515 -2.9761 2.0827 0.4988 -2.5527 -0.8248 0.7258 11.6408 10.7957 13.8072 -1.4303 1.1224 2.5509 -16.7931 -7.6474 -7.2216 3.1379 -8.1047 -9.0049 -0.4601 -2.7480 12.9387 -10.8673 -40.0215 56.9106 0.0000 0.0000 33.0051 0.3753 -12.5068 -1.9462 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -1.5135 8.2483 -11.5227 15.8265 15.3375 -74.2183 -0.0000 0.0000 5.2538 2.0599 2.0993 -3.9697 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -8.4249 7.0563 3.8784 50.3230 0.0000 0.0000 -4.1696 -20.4520 17.4329 -0.0161 0.0000 -0.0000 -12.8274 5.3992 12.4907 0.8763 0.0000 0.0000 4.7314 -3.5878 0.4230 -9.2417 0.0000 -0.0000 -2.1983 44.2293 24.4191 1.2873 -3.4568 -19.8581 -2.7595 2.2862 0.4931 -2.4583 -0.9275 0.6566 12.0236 9.6255 13.2840 -1.3141 1.6404 2.3824 -15.6191 -2.5693 -5.0288 4.0457 -5.4475 -8.7398 -1.8178 -3.0897 12.8156 -15.0410 -43.7288 52.4091 0.0000 0.0000 36.7437 -3.2839 -11.2445 -0.9646 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.4538 7.1022 -11.2105 17.6625 16.0920 -75.7654 -0.0000 0.0000 6.2352 4.1727 4.6204 -3.5873 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -9.0115 8.0546 0.2001 50.5111 0.0000 0.0000 -10.1862 -17.0352 10.8634 -1.8532 0.0000 -0.0000 -11.0271 5.6197 13.4821 1.7560 0.0000 0.0000 2.5559 -3.7020 -1.8141 -9.2744 0.0000 -0.0000 -2.2180 43.6084 24.4690 0.8912 -3.2237 -18.1124 -2.8996 2.4995 0.5252 -2.5027 -0.9855 0.5969 12.5146 9.0508 12.5595 -1.0445 2.0780 2.1430 -14.4340 0.9221 -3.4721 4.6895 -3.6751 -8.2186 -3.1705 -3.1169 12.4329 -18.9105 -46.7144 48.0964 -0.0000 0.0000 40.1712 -6.0775 -7.7729 0.3449 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.6793 6.3089 -10.8652 19.4852 15.6423 -77.3442 -0.0000 0.0000 6.7513 6.7933 7.0222 -3.7020 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -9.3068 9.7127 -4.9925 47.8276 0.0000 0.0000 -15.9165 -11.2354 3.7557 -2.1512 0.0000 -0.0000 -8.9437 6.3278 14.0188 1.8022 0.0000 0.0000 0.5974 -3.9250 -4.0519 -9.4754 0.0000 -0.0000 -2.2207 42.9885 24.5057 0.2981 -2.8822 -16.9293 -3.0063 2.3849 0.6347 -2.5433 -1.3545 0.4912 13.0411 9.1954 12.2744 -0.7447 2.5456 1.9615 -13.5142 2.9430 -2.3535 5.5668 -2.7071 -7.5522 -4.4518 -2.8581 12.1845 -22.6513 -48.7804 44.1029 -0.0000 0.0000 42.1197 -10.7258 -5.0013 0.9555 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -1.8739 6.7916 -10.0332 20.5182 14.8519 -78.6343 -0.0000 0.0000 6.7787 6.8903 7.8343 -3.8381 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -9.5986 11.1828 -9.2769 43.2492 0.0000 0.0000 -18.2572 -7.6740 -1.4843 -0.6559 0.0000 -0.0000 -6.3612 6.9340 12.9728 1.1613 0.0000 0.0000 -0.4403 -4.2679 -4.4867 -9.4768 0.0000 -0.0000 -2.2108 42.3899 24.5221 -0.6787 -2.5811 -16.1298 -2.8681 2.3208 0.7494 -2.4997 -1.6735 0.3965 13.6467 9.5176 12.2592 -0.5083 2.8518 1.8686 -12.9519 3.7789 -1.5116 6.6578 -2.2341 -6.8853 -5.2378 -2.6942 12.1798 -26.0708 -49.1077 41.2449 -0.0000 0.0000 42.5854 -15.6302 -3.3915 0.8387 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.7849 7.5957 -9.1852 20.6954 14.5921 -79.5293 -0.0000 0.0000 6.4063 4.9321 6.7058 -3.8801 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -9.8114 12.3539 -11.9188 37.7533 0.0000 0.0000 -18.2462 -6.2834 -3.8864 0.2946 0.0000 0.0000 -3.8418 7.4951 11.0084 1.1871 0.0000 0.0000 -1.5471 -4.8419 -3.5434 -9.2019 0.0000 -0.0000 -2.1837 41.8369 24.5119 -1.5906 -2.4769 -15.3968 -2.7087 2.4284 0.8025 -2.4170 -1.6801 0.3746 14.1070 9.5671 12.2628 -0.3288 2.9096 1.8800 -12.4897 3.8766 -0.9594 7.5770 -2.1042 -6.2513 -5.4327 -2.4961 12.1019 -28.3423 -48.3764 40.0934 -0.0000 0.0000 42.3314 -17.4870 -1.9397 0.4986 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.4571 7.8605 -8.8030 20.6688 14.7254 -80.1180 -0.0000 0.0000 5.9695 3.2907 4.5209 -4.2734 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -10.5439 13.1827 -13.0119 32.0912 0.0000 0.0000 -16.4471 -5.2798 -3.6920 0.2676 0.0000 0.0000 -1.9055 8.1062 10.0452 2.0281 0.0000 0.0000 -3.3605 -5.6046 -3.3475 -8.8724 0.0000 -0.0000 -2.1447 41.3251 24.4985 -2.1794 -2.2321 -14.7973 -2.5961 2.4537 0.8306 -2.3466 -1.6397 0.3690 14.3316 9.2719 12.2387 -0.2120 2.8660 1.9520 -12.0319 3.6785 -0.6308 8.1763 -2.2155 -5.5563 -5.3499 -2.2658 11.7850 -29.0701 -47.6514 40.4002 -0.0000 0.0000 41.8570 -15.6417 -0.5402 0.0749 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -1.1945 7.8477 -8.6866 20.9672 14.5978 -80.5405 -0.0000 0.0000 5.8911 2.8253 2.6355 -4.7957 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -12.0432 13.3823 -13.0363 26.6583 0.0000 0.0000 -12.8646 -4.3441 -1.8363 0.0416 0.0000 0.0000 -0.2281 8.4378 10.3892 2.6725 0.0000 0.0000 -5.1713 -6.1716 -4.4245 -8.4437 0.0000 -0.0000 -2.1049 40.8447 24.5021 -2.5517 -1.7086 -14.2037 -2.5160 2.4371 0.8965 -2.2840 -1.7194 0.3298 14.5755 8.6632 11.9990 -0.1765 2.7688 2.0173 -11.7968 3.3888 -0.3789 8.5918 -2.4033 -4.8557 -5.3005 -2.2771 11.5336 -28.6504 -46.8498 41.4661 -0.0000 0.0000 41.2371 -12.5995 -0.0506 -0.4433 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -1.1276 7.8740 -8.6155 21.4291 14.0340 -80.8668 -0.0000 0.0000 6.2482 3.4406 2.1028 -4.8690 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -14.0508 12.9858 -12.7205 21.7484 0.0000 0.0000 -8.0181 -4.2714 0.7067 -0.1523 0.0000 -0.0000 1.3231 8.3595 10.8805 3.0260 0.0000 0.0000 -6.5258 -6.1524 -5.6843 -7.8992 0.0000 -0.0000 -2.0765 40.3917 24.5129 -2.8571 -1.0759 -13.1411 -2.4112 2.5861 0.9550 -2.2685 -1.7499 0.2798 15.0074 7.7265 11.3680 -0.1584 2.5553 2.0141 -11.8650 3.0018 -0.2319 8.8924 -2.5467 -4.3395 -5.2319 -2.5239 11.5407 -27.7701 -45.4374 42.6847 -0.0000 0.0000 40.4825 -10.7829 -0.4732 -0.5190 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.2121 7.5325 -8.7586 21.7989 13.4609 -81.1618 -0.0000 0.0000 6.7541 5.1883 3.0278 -4.4991 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -16.2841 12.3209 -12.2677 17.7492 0.0000 0.0000 -2.6964 -5.3495 2.9456 -0.3573 0.0000 -0.0000 2.5145 7.9650 11.2488 3.8722 0.0000 0.0000 -7.9774 -5.4674 -7.0762 -7.5896 0.0000 -0.0000 -2.0565 39.9570 24.5083 -2.9764 -0.5623 -11.4723 -2.3898 2.8765 0.9391 -2.2600 -1.6424 0.2516 15.3874 6.6144 10.4894 -0.0918 2.2618 1.9647 -11.9777 2.5993 -0.3110 9.0278 -2.6196 -4.0800 -5.0742 -2.6414 11.6282 -26.8530 -43.8288 43.5365 -0.0000 0.0000 39.7561 -10.4098 -0.5619 0.0527 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -1.3476 6.6557 -9.1794 22.0886 13.0358 -81.5076 -0.0000 0.0000 7.1297 7.6390 4.5125 -4.1917 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -18.8908 11.7599 -11.4129 14.9683 0.0000 0.0000 2.3721 -6.3850 4.3615 -0.7323 0.0000 -0.0000 3.1333 7.4114 12.0120 5.4508 0.0000 0.0000 -9.8552 -4.4609 -9.3395 -7.6419 0.0000 -0.0000 -2.0405 39.5057 24.4891 -3.1817 -0.0557 -9.5508 -2.1912 3.0994 0.8442 -2.1312 -1.5220 0.2306 15.4379 5.4620 9.6843 -0.0129 1.9977 1.9507 -11.8557 2.4229 -0.5694 9.0533 -2.6037 -3.9955 -4.8806 -2.4376 11.6257 -26.1279 -42.9487 43.7051 -0.0000 0.0000 39.1606 -10.7294 0.2523 0.7056 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -1.3786 5.7745 -9.6251 22.3082 12.6823 -81.9474 -0.0000 0.0000 7.3337 9.6059 5.3411 -4.1005 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -21.4494 11.3124 -10.3681 13.2422 0.0000 0.0000 6.6626 -6.0497 5.2749 -1.4145 0.0000 -0.0000 3.7893 6.7193 13.0345 7.2422 0.0000 0.0000 -11.7916 -3.5594 -12.2064 -7.5639 0.0000 -0.0000 -2.0314 39.0220 24.4689 -3.5757 0.5402 -7.5883 -1.8023 3.2081 0.6950 -1.8891 -1.4665 0.2011 15.2723 4.3049 9.0242 0.0372 1.7606 1.9732 -11.5472 2.5007 -0.8515 9.0948 -2.4972 -3.9971 -4.6655 -2.1534 11.6169 -25.7820 -42.8443 43.2720 -0.0000 0.0000 38.6128 -11.1536 1.2361 0.9530 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -1.1910 5.1686 -9.9534 22.3326 12.5576 -82.4539 -0.0000 0.0000 7.4435 10.2634 4.9821 -4.0053 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -23.7019 10.7898 -9.7458 12.3123 0.0000 0.0000 9.9558 -4.7985 6.0248 -2.1028 0.0000 -0.0000 4.6525 5.8221 13.8661 9.1208 0.0000 0.0000 -13.6157 -2.8238 -14.9352 -7.0471 0.0000 -0.0000 -2.0322 38.5126 24.4490 -3.9450 1.1658 -5.4199 -1.4946 3.1878 0.5240 -1.6961 -1.3975 0.1688 15.1808 3.2575 8.2946 0.1282 1.5043 1.9500 -11.2820 2.5547 -1.1122 9.1918 -2.3936 -4.0641 -4.4851 -1.9935 11.6326 -25.5775 -42.8140 42.6977 0.0000 0.0000 37.9501 -11.2068 1.8685 0.9573 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.9784 4.4484 -10.2849 22.2568 12.8263 -82.9971 -0.0000 0.0000 7.4500 10.1059 4.0261 -3.9532 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -25.6721 10.1063 -9.7588 11.8193 0.0000 0.0000 12.0961 -4.4989 6.2988 -2.2523 0.0000 -0.0000 5.4745 4.7022 14.3364 11.0848 0.0000 0.0000 -15.3553 -2.0223 -17.4136 -6.5493 0.0000 -0.0000 -2.0335 37.9867 24.4158 -4.0523 1.6755 -2.9976 -1.4745 2.9954 0.3894 -1.6639 -1.2737 0.1403 15.2785 2.4902 7.4063 0.2908 1.2755 1.8325 -11.1799 2.4252 -1.4053 9.3328 -2.3850 -4.1618 -4.3544 -2.0032 11.5808 -24.9964 -42.1470 42.5947 0.0000 0.0000 36.9573 -10.8045 2.4273 1.0955 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -1.0234 3.5946 -10.6892 22.2729 13.0831 -83.4969 -0.0000 0.0000 7.3029 9.8407 3.4780 -4.0872 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -27.4168 9.3369 -9.8841 11.2007 0.0000 0.0000 12.9813 -5.6172 5.7125 -1.9626 0.0000 -0.0000 6.1232 3.5474 14.4696 12.8269 0.0000 0.0000 -16.9468 -1.2556 -19.8670 -6.5173 0.0000 -0.0000 -2.0252 37.4402 24.3617 -3.9518 1.9722 -0.6229 -1.6190 2.7546 0.2926 -1.6996 -1.1676 0.1141 15.4162 1.9819 6.5569 0.4178 1.1451 1.6901 -11.1905 2.1822 -1.7224 9.5445 -2.4102 -4.2365 -4.1826 -2.1846 11.5258 -24.0894 -40.7803 42.9075 0.0000 0.0000 35.6663 -10.4063 3.0740 1.3335 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.2235 3.0832 -11.0708 22.3124 12.9629 -83.8669 -0.0000 0.0000 7.0515 9.4199 3.5034 -4.2429 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -28.8370 8.5583 -9.7717 10.1381 0.0000 0.0000 13.0905 -6.7878 4.6948 -1.9329 0.0000 -0.0000 6.7666 2.6089 14.4265 14.1328 0.0000 0.0000 -18.3908 -0.8607 -22.2357 -6.7203 0.0000 -0.0000 -2.0083 36.8602 24.2957 -3.8038 1.9918 1.4804 -1.6988 2.7225 0.1542 -1.6726 -1.0953 0.0911 15.3806 1.5981 5.9474 0.4295 1.0247 1.5839 -11.2352 1.9366 -2.0250 9.7941 -2.4339 -4.2790 -3.8669 -2.4327 11.5215 -23.3281 -39.3708 43.1470 0.0000 0.0000 34.3469 -10.4731 3.6145 1.5412 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -1.2432 2.9361 -11.4334 22.2213 12.8730 -84.0620 -0.0000 0.0000 6.7665 8.7636 3.4670 -4.2081 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -29.8031 7.7895 -9.9290 8.9318 0.0000 0.0000 13.3000 -7.1116 4.3453 -2.2709 0.0000 -0.0000 7.6100 1.9880 14.3971 15.0551 0.0000 0.0000 -19.6034 -0.5428 -24.3176 -6.8790 0.0000 -0.0000 -1.9808 36.2468 24.2216 -3.4000 1.6602 3.4289 -1.8340 2.9335 0.0130 -1.6580 -0.9257 0.1014 15.1981 1.3068 5.3885 0.3641 0.8614 1.5064 -11.3766 1.7010 -2.3128 9.9524 -2.5664 -4.3302 -3.5457 -2.6747 11.4430 -22.6573 -38.3605 43.2821 0.0000 0.0000 33.0905 -10.8398 4.1876 1.8858 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.1333 2.7157 -11.8522 22.1394 13.1476 -84.1293 -0.0000 0.0000 6.4847 8.1555 3.2369 -4.1192 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -30.4942 7.0390 -10.6996 7.9616 0.0000 0.0000 13.4996 -6.4503 5.0596 -2.4383 0.0000 -0.0000 8.4662 1.7332 14.2035 15.5982 0.0000 0.0000 -20.3288 0.3459 -26.0342 -7.2603 0.0000 -0.0000 -1.9406 35.6057 24.1308 -2.5693 1.2989 5.4445 -2.1612 2.9420 -0.0735 -1.7835 -0.6722 0.1183 15.0614 1.1445 4.7315 0.2342 0.7822 1.3428 -11.7515 1.5131 -2.5643 9.9435 -2.8553 -4.4027 -3.2440 -3.1629 11.3184 -21.6704 -36.9119 43.8304 0.0000 0.0000 31.6387 -10.8678 5.1876 2.4616 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.1690 2.4822 -12.2729 22.2084 13.1998 -84.0960 -0.0000 0.0000 6.2437 7.5997 3.4445 -4.1647 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -30.9820 6.0799 -11.4099 7.0293 0.0000 0.0000 12.9594 -5.5351 5.5989 -2.1793 0.0000 -0.0000 9.1388 1.5411 13.6581 15.7707 0.0000 0.0000 -20.7939 1.6024 -27.5729 -8.0146 0.0000 -0.0000 -1.8898 34.9390 24.0209 -1.4093 1.3076 7.4324 -2.6344 2.5137 -0.1415 -2.0017 -0.4949 0.1139 14.9963 0.9726 4.0199 -0.0105 0.8248 1.1419 -12.4199 1.4140 -2.7217 9.7062 -3.1990 -4.4517 -2.8171 -4.0290 11.4773 -20.4542 -34.2255 44.7024 0.0000 0.0000 30.0499 -9.8572 6.6083 3.0203 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.3090 2.6502 -12.6299 22.2554 12.7341 -83.9104 -0.0000 0.0000 6.1206 6.9514 4.1374 -4.1901 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -31.4182 4.7109 -11.7034 6.1926 0.0000 0.0000 12.5301 -5.9690 5.0612 -1.8771 0.0000 -0.0000 9.5833 1.0570 13.1096 15.7912 0.0000 0.0000 -21.5301 2.3990 -29.0797 -8.7440 0.0000 -0.0000 -1.8242 34.2306 23.9005 -0.0539 1.4931 9.2960 -3.1569 2.1069 -0.2539 -2.2295 -0.4003 0.0882 14.8504 0.6362 3.3005 -0.3209 0.8156 0.9538 -13.3291 1.1988 -2.7862 8.9746 -3.7221 -4.3738 -2.3289 -4.9330 11.8859 -19.1674 -31.0783 45.4481 0.0000 0.0000 28.6767 -7.7184 8.3446 3.6669 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -1.3816 2.9589 -13.0045 22.1719 12.6255 -83.6090 -0.0000 0.0000 6.1793 6.4468 4.5586 -4.0701 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -31.8435 3.1825 -12.5546 6.0743 0.0000 0.0000 14.2027 -8.0483 4.8428 -1.9807 0.0000 -0.0000 9.8416 0.4203 12.9419 15.9123 0.0000 0.0000 -22.2535 3.0311 -30.6174 -9.3472 0.0000 -0.0000 -1.7234 33.4509 23.7510 1.6224 1.3145 11.3028 -3.8401 2.0590 -0.2901 -2.5601 -0.1437 0.0895 14.6069 0.2944 2.3317 -0.5720 0.6848 0.6973 -14.4139 0.5073 -2.8063 7.4091 -4.8844 -4.0034 -1.9617 -5.7579 11.9445 -17.3718 -28.1589 46.5359 0.0000 0.0000 27.2475 -5.5180 10.6793 5.0098 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -1.5899 3.0206 -13.4048 22.1844 13.2898 -83.3226 -0.0000 0.0000 6.3127 6.3667 4.6703 -4.0517 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -32.0362 2.0198 -13.8756 6.8718 0.0000 0.0000 17.8657 -8.8775 6.2426 -2.1134 0.0000 -0.0000 9.9574 0.1254 12.7523 16.0722 0.0000 0.0000 -22.3453 4.4563 -32.2619 -10.3672 0.0000 -0.0000 -1.5957 32.5916 23.5490 3.4559 1.4093 13.5432 -4.7343 1.4338 -0.1089 -3.1036 0.2501 0.1061 14.6046 0.2044 1.0587 -0.8662 0.5878 0.3172 -15.8074 -0.8781 -2.7145 5.0637 -6.8605 -3.2344 -1.6511 -6.9784 11.6804 -15.0218 -24.4484 48.1654 0.0000 0.0000 25.3349 -4.2416 13.6394 6.9626 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -1.9239 3.7403 -13.6279 22.0571 13.2958 -82.9157 -0.0000 0.0000 6.2823 6.4845 5.2118 -4.2504 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -31.9765 0.6956 -13.1380 8.4508 0.0000 0.0000 19.5110 -5.3018 7.0257 -1.4921 0.0000 -0.0000 9.9200 -0.5470 12.4987 16.5757 0.0000 0.0000 -22.6007 6.1104 -34.3240 -11.7817 0.0000 -0.0000 -1.4920 31.6785 23.3532 4.4274 2.9577 15.4371 -5.2264 -0.4724 0.1344 -3.5992 0.3173 0.0620 15.0247 0.0267 -0.1024 -1.4945 0.4053 -0.0041 -17.6821 -3.0760 -2.6303 2.5262 -9.1600 -2.0223 -0.6985 -8.6273 12.1025 -13.3117 -19.3341 49.1258 0.0000 0.0000 23.4559 -3.5528 16.7794 8.5708 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.5806 6.0707 -13.8150 20.9935 11.9366 -81.9565 -0.0000 0.0000 5.9067 6.4864 5.4169 -4.1777 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -32.0378 -1.9161 -8.8369 11.6845 0.0000 0.0000 15.7445 1.1026 4.2812 0.0573 0.0000 0.0000 9.6472 -3.1748 13.2548 18.8751 0.0000 0.0000 -23.8826 6.6050 -37.0672 -12.7078 0.0000 -0.0000 -1.4280 30.7600 23.3055 3.8483 5.1536 16.6383 -4.4783 -1.9444 0.2071 -3.4305 -0.0232 -0.0819 15.2535 -1.0686 -0.9568 -2.3524 -0.3662 -0.0092 -19.8653 -6.4354 -3.1611 0.3567 -11.2823 -0.4695 0.9595 -9.1844 13.4895 -12.5568 -15.8310 48.5559 0.0000 0.0000 22.3756 -2.8147 20.0806 9.4000 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0661 8.5220 -14.5552 19.1400 11.3598 -80.5877 -0.0000 0.0000 5.3030 6.2374 3.2821 -3.6086 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -31.8218 -5.0174 -4.3860 16.2596 0.0000 0.0000 9.7523 5.2765 -0.3403 1.2427 0.0000 0.0000 8.7723 -7.3670 14.2290 24.3634 0.0000 0.0000 -23.1618 6.7973 -39.5703 -13.1322 0.0000 -0.0000 -1.3683 29.8991 23.4908 2.8234 6.1811 17.6601 -2.9000 -1.4213 0.0602 -2.6295 -0.0101 -0.1632 14.6687 -2.7385 -1.7542 -2.8361 -1.9319 0.2273 -21.7582 -11.1544 -5.0891 -1.4153 -13.3270 0.9757 2.5815 -7.8179 14.3178 -11.0839 -16.1022 48.3272 0.0000 0.0000 20.8476 -3.1672 23.1206 9.8443 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 1.4485 8.6612 -16.0186 18.1294 13.3841 -79.4927 -0.0000 0.0000 4.6371 5.5118 -0.3358 -3.3862 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -30.3480 -6.3226 -3.6547 19.0707 0.0000 0.0000 5.7616 5.0066 -2.6400 1.2603 0.0000 0.0000 6.0374 -10.8530 12.5921 32.3535 0.0000 0.0000 -15.1087 9.7431 -40.3344 -13.1341 0.0000 -0.0000 -1.2840 29.0983 23.7828 2.4811 5.6982 18.7994 -1.5684 -0.0302 -0.1460 -1.9224 0.4755 -0.1197 13.3669 -3.4004 -2.4656 -2.7048 -3.4541 0.4852 -22.5732 -16.1479 -7.9401 -2.5840 -15.2220 1.2555 3.1810 -5.4229 13.4277 -6.6678 -18.4257 50.4627 0.0000 0.0000 16.8987 -4.9021 23.0727 9.3917 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 1.4689 6.4630 -17.5647 19.1267 16.4893 -79.3911 -0.0000 0.0000 3.8740 4.1616 -0.7648 -4.2216 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -27.6225 -5.7296 -5.2060 18.9384 0.0000 0.0000 4.0855 3.8038 -2.1522 0.9487 0.0000 0.0000 1.9445 -12.4583 8.9147 39.4072 0.0000 0.0000 -1.2206 17.0271 -39.8804 -10.5969 0.0000 -0.0000 -1.1769 28.3108 24.0124 2.5120 4.8265 19.3220 -1.0933 0.4679 -0.1180 -1.6873 0.7799 -0.0277 12.3156 -2.8597 -2.4217 -2.4452 -4.0307 0.7366 -22.1074 -19.0536 -10.0084 -2.3614 -16.3695 0.0291 2.6380 -3.5476 12.0684 0.1143 -19.4135 53.9769 0.0000 0.0000 11.3999 -5.0859 16.1591 6.6381 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.2249 4.9199 -18.3265 20.9254 17.7804 -80.2529 -0.0000 0.0000 3.2447 3.2378 4.2687 -5.2007 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -24.3328 -5.3006 -5.8030 17.3860 0.0000 0.0000 2.6982 4.7491 -1.2750 0.9192 0.0000 0.0000 -1.0488 -13.3773 6.4784 43.1939 0.0000 0.0000 6.9856 23.4070 -37.7475 -7.7815 0.0000 -0.0000 -1.0722 27.5330 24.1460 2.1881 4.5595 18.6511 -1.1944 -0.3464 0.0922 -1.7870 0.5490 0.0314 12.0391 -1.9806 -1.3611 -2.3655 -3.7949 0.9919 -20.6267 -18.9188 -10.5694 -0.3993 -16.3906 -1.4741 1.9872 -3.3285 11.7352 5.6981 -18.5589 56.0307 0.0000 0.0000 7.6547 -1.3574 3.5258 3.0609 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.9819 5.4880 -17.9897 21.4460 17.0930 -81.2524 -0.0000 0.0000 3.2549 3.7680 10.6397 -5.2215 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -21.2393 -6.0957 -4.5425 16.2835 0.0000 0.0000 0.6985 6.4326 -1.5442 0.9918 0.0000 0.0000 -2.1904 -15.1946 6.7477 44.1335 0.0000 0.0000 3.3760 24.0651 -31.4279 -8.1182 0.0000 -0.0000 -0.9911 26.8121 24.2214 1.7932 4.7124 17.5646 -1.5517 -1.4323 0.2175 -1.9680 0.1793 0.0481 12.1304 -1.4131 -0.2909 -2.2681 -3.3920 1.1546 -18.6393 -17.0894 -10.1022 2.0405 -15.5652 -2.3824 1.9220 -4.2707 11.8992 9.0186 -17.8479 56.7424 0.0000 0.0000 6.8103 3.2134 -7.3364 1.7752 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -1.6621 6.4031 -17.1310 20.4257 15.9874 -81.8507 -0.0000 0.0000 3.7591 5.0825 12.7432 -4.5204 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -19.1580 -7.2203 -3.1000 16.5679 0.0000 0.0000 -1.3299 6.8871 -2.2453 0.8810 0.0000 0.0000 -2.9065 -17.6027 8.5433 42.9011 0.0000 0.0000 -5.4092 19.1461 -22.9656 -8.9080 0.0000 -0.0000 -0.9170 26.1579 24.2698 1.5004 4.1951 17.2239 -1.7983 -1.6750 0.1919 -2.0781 0.2489 0.0757 12.2320 -1.1006 -0.1539 -1.9207 -3.0981 1.0785 -16.7807 -15.3938 -9.3706 3.4713 -14.6440 -2.8562 2.1105 -5.1274 11.5126 11.3334 -18.8903 57.8782 0.0000 0.0000 7.4366 4.1315 -11.4011 2.1006 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -2.2138 5.9992 -16.3380 18.8378 14.7160 -82.0128 -0.0000 0.0000 4.0731 5.5804 9.5525 -3.9416 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -17.6329 -7.3624 -2.3929 17.8631 0.0000 0.0000 -3.3559 6.8796 -2.6347 0.6772 0.0000 0.0000 -4.2400 -19.1114 9.2915 39.9863 0.0000 0.0000 -10.7677 14.2717 -16.1760 -8.7507 0.0000 -0.0000 -0.8335 25.5599 24.2917 1.1192 3.0020 17.4000 -1.8384 -1.3945 0.1300 -2.1039 0.5258 0.1171 12.4616 -0.5597 -0.4898 -1.4247 -2.7663 0.8505 -15.3983 -14.2595 -8.7794 3.8854 -14.0900 -3.2089 2.2864 -5.3925 10.8642 13.2537 -21.2375 59.3524 0.0000 0.0000 8.1031 0.6344 -9.8543 2.6651 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -2.9572 4.8636 -15.8345 17.0024 13.6314 -81.7027 -0.0000 0.0000 3.7391 4.8052 4.2852 -3.7901 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -16.1110 -6.7459 -1.7556 19.5630 0.0000 0.0000 -5.7008 7.5431 -2.9588 0.5265 0.0000 0.0000 -5.8790 -19.5467 8.8541 35.9090 0.0000 0.0000 -12.7767 11.4675 -11.8186 -9.2001 0.0000 -0.0000 -0.7479 25.0196 24.2876 0.5767 2.1957 16.9767 -1.8246 -1.5939 0.0914 -2.0977 0.6066 0.1484 12.8672 0.1898 -0.3100 -1.0003 -2.3503 0.7157 -14.4780 -13.2129 -8.3144 4.0077 -13.7152 -3.5282 2.6185 -5.1861 10.7148 14.3721 -23.5885 60.1972 0.0000 0.0000 8.4668 -3.2053 -6.4006 3.1437 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -3.7046 4.2074 -15.5825 14.6021 14.0915 -81.0724 -0.0000 0.0000 3.0037 3.7242 -0.0084 -3.9240 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -14.6505 -6.5317 -0.9675 21.1321 0.0000 0.0000 -7.9879 8.2263 -3.0373 0.4111 0.0000 0.0000 -7.3974 -20.1121 9.2032 31.1314 0.0000 0.0000 -13.9270 9.0703 -10.1727 -9.3399 0.0000 -0.0000 -0.6619 24.5311 24.2778 0.0656 2.0608 15.7684 -1.8542 -2.2563 0.0654 -2.0892 0.5423 0.1733 13.2272 0.8344 0.3933 -0.7070 -2.0192 0.7557 -13.8345 -12.2044 -7.8926 4.1255 -13.3288 -3.7927 3.0238 -4.8857 10.9456 14.8864 -25.2167 60.5064 0.0000 0.0000 8.6227 -3.9028 -3.3142 3.1282 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.3520 3.9831 -15.4027 12.0673 16.1769 -80.4800 -0.0000 0.0000 2.2950 3.0801 -2.4424 -4.1511 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -13.2135 -6.8796 -0.3214 21.9614 0.0000 0.0000 -9.6219 8.2921 -2.4956 0.3151 0.0000 0.0000 -9.2877 -21.1080 10.4044 26.3870 0.0000 0.0000 -14.6235 8.1852 -10.9368 -9.6003 0.0000 -0.0000 -0.5605 24.0648 24.2760 -0.4554 2.0425 14.6108 -1.7589 -2.8408 0.0296 -2.0155 0.6385 0.2148 13.3432 1.2067 0.9403 -0.5049 -1.8415 0.8238 -13.2693 -11.4897 -7.5335 4.2446 -13.0812 -3.9515 3.2060 -4.7538 10.9642 15.7016 -25.9491 61.0748 0.0000 0.0000 8.5305 -2.6905 -1.2658 2.8878 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -4.9772 3.5911 -15.1977 10.3008 17.6966 -80.1786 -0.0000 0.0000 1.7687 2.8189 -2.9913 -4.4133 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -11.3433 -7.2544 0.3662 21.8501 0.0000 0.0000 -10.7211 8.3122 -1.8998 0.2673 0.0000 0.0000 -11.8203 -21.7808 10.3800 22.1933 0.0000 0.0000 -14.3042 10.0447 -12.4482 -12.9919 0.0000 -0.0000 -0.4335 23.5979 24.2739 -1.2646 2.0025 13.8838 -1.3933 -3.4317 -0.0083 -1.7991 0.9219 0.2582 13.2431 1.4187 1.1107 -0.3745 -1.7467 0.8540 -12.7467 -10.9859 -7.2870 4.5306 -13.0638 -3.9577 3.1289 -4.5638 10.7148 16.8348 -26.3459 61.8371 0.0000 0.0000 8.3157 -2.1617 -0.6472 2.9564 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -5.5808 2.9751 -15.1367 9.4668 17.2632 -80.1093 -0.0000 0.0000 1.4769 2.8938 -2.0663 -4.6737 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.9076 -7.6236 1.4893 21.2895 0.0000 0.0000 -11.7603 8.6007 -2.0167 0.2656 0.0000 0.0000 -14.5432 -21.8916 8.1790 18.8087 0.0000 0.0000 -13.7568 12.1670 -13.1735 -17.1107 0.0000 -0.0000 -0.2813 23.1321 24.2701 -2.3352 1.9787 13.0718 -0.8403 -4.1016 -0.0139 -1.4838 1.2065 0.2983 13.1351 1.6259 1.3077 -0.2777 -1.6655 0.9025 -12.4120 -10.4849 -7.1362 5.0349 -13.1139 -3.8625 3.0523 -4.0620 10.6192 17.4983 -27.0846 62.0984 0.0000 0.0000 8.2689 -2.4997 -1.2036 3.2328 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.1214 2.3763 -15.3109 9.0586 16.1208 -80.0984 -0.0000 0.0000 1.5216 3.3277 -0.8604 -4.8222 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -6.2572 -7.9226 2.7910 20.8438 0.0000 0.0000 -12.8537 8.6508 -2.3131 0.3076 0.0000 0.0000 -16.9765 -21.6233 5.1834 16.3449 0.0000 0.0000 -14.1850 12.2344 -13.0728 -15.8871 0.0000 -0.0000 -0.1072 22.6740 24.2686 -3.3096 1.7622 11.8322 -0.3237 -4.5038 0.0148 -1.1883 1.3794 0.3370 13.1347 1.9371 1.7488 -0.1816 -1.5740 1.0004 -12.2858 -10.0151 -7.0217 5.4991 -13.1152 -3.8010 3.0915 -3.4337 10.7730 17.5972 -27.9834 61.8801 0.0000 0.0000 8.3496 -2.5092 -1.8409 3.4193 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.5856 1.8637 -15.5145 8.8019 15.6673 -80.1618 -0.0000 0.0000 1.8616 3.7756 -0.2155 -4.8148 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -3.7860 -7.7560 3.7397 20.6403 0.0000 0.0000 -13.9536 8.3378 -1.8790 0.3723 0.0000 0.0000 -19.1543 -20.9232 2.8336 14.3782 0.0000 0.0000 -14.9550 11.5758 -12.8483 -11.7351 0.0000 -0.0000 0.0939 22.2106 24.2620 -4.1730 1.1619 10.5149 0.1896 -4.4807 0.0450 -0.9289 1.4753 0.3762 13.1629 2.3476 2.1791 -0.1116 -1.4146 1.0583 -12.1725 -9.6399 -6.8928 5.7705 -13.1165 -3.8216 3.1564 -2.9740 10.8624 17.7739 -28.3277 61.8540 0.0000 0.0000 8.3152 -1.9989 -1.8205 3.4774 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.9190 1.4718 -15.5159 8.7707 15.4973 -80.3421 -0.0000 0.0000 2.1412 4.0459 0.0156 -4.7949 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.4465 -7.0012 4.4847 20.6777 0.0000 0.0000 -15.2085 8.1307 -1.1161 0.3941 0.0000 0.0000 -21.1143 -19.6148 1.0197 12.4905 0.0000 0.0000 -14.9335 12.0553 -12.4393 -9.9481 0.0000 -0.0000 0.3216 21.7257 24.2369 -5.1856 0.4626 9.4656 0.8284 -4.3711 0.0685 -0.6284 1.4967 0.3842 13.1187 2.7518 2.3939 -0.0951 -1.1624 1.0188 -11.9156 -9.2192 -6.7220 6.0008 -13.1294 -3.8492 3.2482 -2.6397 10.7385 18.1290 -28.1427 62.1538 0.0000 0.0000 8.2442 -1.7166 -1.4444 3.4123 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.9997 1.3211 -15.3435 8.8863 15.0128 -80.5234 -0.0000 0.0000 2.0733 4.3645 0.1731 -4.8498 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.9465 -6.1300 5.4785 21.0304 0.0000 0.0000 -16.6859 8.0974 -0.9248 0.3829 0.0000 0.0000 -22.7713 -17.9839 -0.5917 11.0137 0.0000 0.0000 -14.5388 13.1840 -11.7481 -10.4909 0.0000 -0.0000 0.5635 21.2253 24.1937 -6.1580 -0.0169 8.4372 1.3626 -4.3615 0.1037 -0.3693 1.4182 0.3717 13.0979 3.0815 2.5321 -0.0801 -0.8790 0.9580 -11.5900 -8.6641 -6.4866 6.3253 -13.0674 -3.7902 3.3870 -2.3456 10.5909 18.1377 -28.1236 62.2557 0.0000 0.0000 8.3836 -2.0802 -1.2491 3.3082 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -6.8407 1.4292 -15.1450 8.9656 14.7505 -80.6122 -0.0000 0.0000 1.8550 4.7921 0.2004 -4.9174 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 3.1368 -5.4066 6.6285 21.6532 0.0000 0.0000 -18.1998 7.9197 -1.0272 0.4547 0.0000 0.0000 -24.2333 -16.4147 -1.7225 10.2785 0.0000 0.0000 -14.7334 13.5778 -11.2087 -10.2338 0.0000 -0.0000 0.8111 20.7141 24.1444 -6.7558 -0.3260 7.0916 1.4988 -4.2997 0.1189 -0.2853 1.2962 0.3688 13.2289 3.3864 2.7783 -0.0040 -0.6384 0.9434 -11.2986 -8.1241 -6.1577 6.7015 -12.9223 -3.6045 3.4360 -2.2707 10.5607 17.7847 -28.3715 62.0378 0.0000 0.0000 8.6075 -2.7715 -1.2230 3.3388 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -6.6931 1.6355 -14.9905 9.1835 15.1121 -80.6322 -0.0000 0.0000 1.8818 5.0305 0.1491 -4.9852 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 4.9485 -4.5972 7.5236 22.1754 0.0000 0.0000 -19.5826 7.6089 -0.6012 0.5506 0.0000 0.0000 -25.5047 -14.9993 -2.5750 9.7343 0.0000 0.0000 -15.1868 13.3923 -10.7962 -9.0431 0.0000 -0.0000 1.0656 20.1792 24.0942 -7.0699 -0.6289 5.5622 1.3343 -4.0963 0.0864 -0.3362 1.2432 0.3838 13.4721 3.7014 3.0015 0.1119 -0.4600 0.9315 -11.0398 -7.7422 -5.7569 7.0978 -12.8071 -3.2877 3.2892 -2.4945 10.5623 17.6082 -28.3688 61.9638 0.0000 0.0000 8.6378 -3.1271 -1.1562 3.5214 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.7603 1.7659 -14.9057 9.8202 15.4188 -80.5968 -0.0000 0.0000 2.2910 4.9775 0.4875 -5.0758 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 6.6457 -3.5416 8.0808 22.3419 0.0000 0.0000 -20.8348 7.3330 0.2820 0.4582 0.0000 0.0000 -26.3760 -13.6690 -3.6489 8.8994 0.0000 0.0000 -15.2564 13.6851 -10.0586 -8.6232 0.0000 -0.0000 1.3172 19.6238 24.0328 -7.2285 -0.7501 4.1503 1.0891 -3.9147 0.0391 -0.4053 1.2646 0.3975 13.6726 3.9471 2.9972 0.1976 -0.3104 0.8649 -10.8762 -7.4775 -5.3591 7.5074 -12.7611 -2.8807 3.0939 -2.7730 10.5519 17.6344 -28.1351 62.1459 0.0000 0.0000 8.6266 -2.9592 -1.0788 3.6689 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -6.9780 1.7591 -14.9208 10.7153 15.1344 -80.4505 -0.0000 0.0000 2.8823 4.9641 1.4693 -5.0858 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 8.2228 -2.5968 8.6187 22.3950 0.0000 0.0000 -21.9457 6.9668 0.9529 0.2338 0.0000 0.0000 -27.0059 -12.5602 -4.5334 8.3124 0.0000 0.0000 -15.5740 14.5026 -9.3112 -8.7891 0.0000 -0.0000 1.5500 19.0699 23.9566 -7.0917 -0.4724 2.8689 0.8287 -3.8064 -0.0196 -0.5141 1.2336 0.3935 13.7901 4.0568 2.8258 0.2035 -0.1645 0.7634 -10.9635 -7.2266 -5.0043 7.8204 -12.6897 -2.4712 3.0245 -3.0275 10.6361 17.3557 -28.0708 62.1347 0.0000 0.0000 8.8728 -2.9825 -1.1143 3.6816 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -7.1230 1.7747 -14.9818 11.4014 14.5348 -80.1721 -0.0000 0.0000 3.3767 5.2189 2.6353 -4.9850 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 9.3504 -2.0686 9.2962 22.5979 0.0000 0.0000 -22.8319 6.3623 1.3788 0.0955 0.0000 0.0000 -27.7046 -11.8222 -4.5451 8.4537 0.0000 0.0000 -16.8372 14.8734 -9.1755 -8.7150 0.0000 -0.0000 1.7677 18.5170 23.8815 -6.4997 0.0851 1.7045 0.4208 -3.6472 -0.1356 -0.7394 1.1158 0.3760 13.9384 4.0881 2.5826 0.1039 -0.0406 0.6531 -11.3276 -6.9880 -4.7062 7.9835 -12.5382 -2.1252 3.0163 -3.6910 10.8191 16.7004 -27.8960 61.6701 0.0000 0.0000 9.2116 -3.7359 -1.3023 3.6477 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -7.0715 2.0722 -15.0119 11.7295 13.8673 -79.8332 -0.0000 0.0000 3.6543 5.5173 3.3805 -4.9125 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 10.0066 -1.7585 9.7131 22.6961 0.0000 0.0000 -23.3865 5.6112 2.1152 -0.1602 0.0000 -0.0000 -28.4489 -11.3027 -4.0897 8.8269 0.0000 0.0000 -18.2624 14.2782 -9.0910 -8.8052 0.0000 -0.0000 1.9908 17.9294 23.8227 -5.6067 0.6754 0.9100 -0.2007 -3.4320 -0.3191 -1.0231 1.0905 0.3648 14.1925 4.0891 2.1556 -0.0993 0.0219 0.5038 -11.8935 -6.7167 -4.4977 8.1959 -12.3788 -1.8661 2.9382 -4.9112 10.9459 16.1064 -27.2185 60.9844 0.0000 0.0000 9.2552 -4.4428 -1.5825 3.6648 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.9138 2.6628 -15.0736 11.9836 13.1083 -79.5416 -0.0000 0.0000 3.7802 5.5698 3.7193 -4.9591 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 10.6942 -1.3879 9.4402 22.2443 0.0000 0.0000 -23.4568 4.8513 3.2537 -0.9452 0.0000 -0.0000 -28.8337 -10.6514 -3.6338 8.9024 0.0000 0.0000 -18.9844 13.0370 -8.2376 -9.3862 0.0000 -0.0000 2.2224 17.2788 23.7696 -4.7013 1.3202 0.4665 -0.8129 -3.2631 -0.5129 -1.2808 1.2013 0.3682 14.4304 4.0454 1.5888 -0.3689 0.0716 0.3241 -12.7384 -6.2677 -4.3633 8.6423 -12.2169 -1.6819 2.8004 -6.0488 11.0376 15.6519 -26.7923 60.1240 0.0000 0.0000 9.0700 -4.1960 -1.8453 3.7827 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -6.7660 3.2583 -15.2921 12.3182 12.4707 -79.3514 -0.0000 0.0000 3.8938 5.5522 4.0946 -5.0679 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 11.7966 -1.0950 8.8595 21.2761 0.0000 0.0000 -23.0130 4.2162 4.2729 -2.0685 0.0000 -0.0000 -28.3443 -9.8511 -2.8103 8.7562 0.0000 0.0000 -19.8596 11.1701 -6.8271 -9.6958 0.0000 -0.0000 2.4366 16.5935 23.6958 -3.3101 2.2749 -0.1396 -1.6027 -3.1149 -0.6922 -1.6611 1.1671 0.3581 14.5996 3.9995 1.2307 -0.7206 0.1772 0.1913 -14.1433 -5.6113 -4.1854 9.1175 -11.9238 -1.5254 2.6650 -6.8243 11.3733 14.8504 -27.3066 58.6051 0.0000 0.0000 9.0273 -3.7921 -2.0560 4.0026 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -6.6504 3.9019 -15.6403 12.5708 11.8841 -79.2104 -0.0000 0.0000 4.0452 5.9568 4.6739 -5.2090 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 12.4295 -1.2396 8.7442 20.4233 0.0000 0.0000 -22.3716 3.8814 4.8533 -3.0012 0.0000 -0.0000 -27.4098 -9.3998 -1.6569 8.2802 0.0000 0.0000 -21.5956 8.2568 -5.3936 -9.3416 0.0000 -0.0000 2.6360 15.8973 23.6146 -1.1890 2.9775 -0.6732 -2.6888 -2.3519 -0.9152 -2.3374 0.9425 0.3366 14.9607 4.1525 0.9491 -1.2615 0.2635 0.0654 -16.3015 -5.0291 -4.0272 9.2168 -11.4706 -1.4151 2.5534 -8.3379 12.0574 13.2600 -27.8188 55.7464 0.0000 0.0000 9.3791 -4.5272 -2.2597 4.1647 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.4775 5.0121 -16.1199 12.6407 10.4980 -79.0302 -0.0000 0.0000 4.1406 6.7684 5.1960 -5.3979 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 12.2510 -1.2226 8.3686 19.7480 0.0000 0.0000 -21.7342 3.6011 5.4347 -3.8611 0.0000 -0.0000 -26.4914 -8.9608 -1.3906 6.5573 0.0000 0.0000 -22.0979 5.2923 -3.4953 -9.0033 0.0000 -0.0000 2.8604 15.1698 23.5725 0.9285 2.3390 0.3784 -3.5825 -0.4337 -1.1565 -3.0748 1.0850 0.3785 15.7235 4.8521 0.0115 -2.0767 0.2040 -0.2634 -19.1555 -4.6525 -4.3381 8.7895 -10.9585 -1.6612 2.7382 -11.4644 12.7932 10.6743 -27.3763 51.1582 0.0000 0.0000 10.3546 -5.9746 -2.0985 4.1188 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.1012 6.4445 -17.0462 12.6092 8.2788 -78.9617 -0.0000 0.0000 4.0341 7.4015 5.2086 -5.5357 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 12.3669 -0.0316 6.1134 18.7856 0.0000 0.0000 -20.7294 2.8746 6.2924 -5.1643 0.0000 -0.0000 -25.4760 -7.3173 -2.7480 3.1619 0.0000 0.0000 -18.6248 5.3606 -0.8167 -9.3277 0.0000 -0.0000 3.1258 14.3899 23.5899 2.1085 0.4283 3.5721 -3.2911 1.6536 -1.2575 -3.1399 1.8955 0.5240 16.2414 6.5516 -1.4625 -3.0298 0.2641 -0.8141 -22.2537 -3.7260 -5.3758 7.8804 -10.1603 -2.7913 3.6369 -14.7553 13.2976 6.8712 -27.4642 44.7034 0.0000 0.0000 12.2299 -6.9847 -0.9231 4.0475 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -5.1951 7.2117 -18.6577 12.4099 7.0675 -79.5563 -0.0000 0.0000 3.5895 7.6436 4.1314 -5.6198 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 13.8348 1.9826 2.4161 17.8292 0.0000 0.0000 -18.9067 1.9631 6.8078 -6.7369 0.0000 -0.0000 -23.9981 -4.2867 -5.2556 -0.5187 0.0000 -0.0000 -12.4442 9.5454 1.7433 -10.1698 0.0000 -0.0000 3.3770 13.6261 23.6712 3.0956 -1.1040 6.8070 -2.1846 2.2955 -1.1075 -2.4938 2.4223 0.6314 15.8975 9.0814 -1.9242 -3.8429 1.1256 -1.2296 -25.0949 -0.9499 -6.2889 6.3671 -8.4333 -4.9783 5.0700 -16.1871 13.6612 1.7629 -29.6611 36.3924 0.0000 0.0000 14.6805 -7.9972 0.9445 4.1710 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.5396 7.3200 -20.2840 11.9885 7.6528 -81.1636 -0.0000 0.0000 2.6298 7.6910 1.7476 -5.9850 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 14.5308 3.2333 0.1126 18.6057 0.0000 0.0000 -16.3576 1.6304 6.3371 -8.0845 0.0000 -0.0000 -23.2152 -1.5551 -7.5495 -2.0817 0.0000 -0.0000 -7.6970 13.4715 2.7269 -11.1351 0.0000 -0.0000 3.5506 12.9208 23.8341 4.6425 -1.1566 7.7532 -1.3151 1.6351 -0.7755 -1.9636 1.8298 0.6262 14.9533 11.7818 -0.3422 -4.3668 2.6887 -1.1738 -27.2742 3.8022 -5.7215 4.1674 -5.3560 -7.4683 6.3233 -16.0361 14.0022 -3.3875 -32.4219 27.7079 0.0000 0.0000 16.4264 -9.9720 1.9160 4.1508 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -1.5753 7.7296 -20.6916 12.0134 8.5032 -83.2950 -0.0000 0.0000 1.3146 7.0849 -1.1083 -6.6724 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 12.2836 3.4286 0.3656 22.0189 0.0000 0.0000 -12.9726 1.1241 5.7133 -9.4455 0.0000 -0.0000 -23.3975 -0.5939 -8.2713 -1.8896 0.0000 -0.0000 -5.8900 13.1963 1.9229 -12.3737 0.0000 -0.0000 3.6627 12.2557 24.0534 6.6332 -0.1403 6.5082 -1.0341 0.6239 -0.4056 -1.7798 0.7342 0.5969 13.6217 14.1815 2.2255 -4.6065 4.0558 -0.8768 -28.4273 8.9118 -3.5504 1.5400 -1.4342 -8.9269 6.7662 -15.8685 14.0459 -6.5114 -33.9565 21.5359 0.0000 0.0000 16.4122 -11.8917 1.0067 3.1897 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.2016 8.2401 -19.4257 13.2434 8.4304 -85.1660 -0.0000 0.0000 0.9369 4.9754 -3.1796 -7.0267 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 7.6499 3.2370 1.5274 27.2305 0.0000 0.0000 -8.0476 -1.7144 6.4053 -10.6001 0.0000 -0.0000 -23.9313 -1.3649 -8.2755 -1.4888 0.0000 -0.0000 -5.8063 10.4881 1.3683 -13.4038 0.0000 -0.0000 3.7850 11.6112 24.2642 8.3408 0.7803 4.9369 -0.9832 0.1196 -0.1042 -1.7085 0.2814 0.6153 12.3657 15.5038 3.8828 -4.6156 4.7359 -0.7515 -28.6142 12.9491 -0.7455 -0.8562 2.0905 -8.8263 6.3272 -15.9265 13.6551 -8.3917 -34.8043 18.0246 0.0000 0.0000 15.3359 -12.7638 -1.2069 1.2885 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0035 7.8600 -17.3807 15.5338 7.9362 -86.2137 -0.0000 0.0000 2.7812 2.1939 -3.8306 -6.4824 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 2.6156 3.5991 1.7265 33.0891 0.0000 0.0000 -1.7359 -7.2106 8.8963 -9.6208 0.0000 -0.0000 -24.2173 -2.4221 -8.2424 -1.1061 0.0000 -0.0000 -5.7584 9.2619 1.6970 -13.8404 0.0000 -0.0000 3.9504 10.9929 24.4175 9.2852 0.9858 3.9002 -0.9236 0.5226 0.1045 -1.6308 0.6441 0.6806 11.7235 15.3739 4.2268 -4.4392 4.9520 -0.8292 -28.2594 15.8637 1.9467 -2.1103 4.5625 -7.8434 5.6315 -15.5031 13.1034 -11.8333 -35.6842 14.7378 0.0000 0.0000 14.7429 -14.3846 -3.0691 -0.5609 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.6475 6.5915 -15.7192 18.0652 7.8394 -86.1589 -0.0000 0.0000 6.0861 1.2785 -3.0206 -5.7318 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -1.7800 5.0490 0.8165 39.0591 0.0000 0.0000 3.3380 -12.5346 11.7811 -6.5577 0.0000 -0.0000 -23.9982 -2.6675 -7.5884 -0.3342 0.0000 -0.0000 -5.4998 9.7175 1.6411 -13.9953 0.0000 -0.0000 4.1244 10.4116 24.5286 9.6088 0.8543 2.8167 -0.8821 1.4863 0.2266 -1.5840 0.9817 0.7093 11.6635 14.5493 4.3598 -4.1628 5.0647 -0.8698 -27.6338 18.1099 4.2312 -1.9921 6.3871 -6.7939 5.2310 -14.7172 12.6861 -17.4230 -35.8210 10.4005 0.0000 0.0000 15.5537 -17.9465 -3.2446 -1.6099 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -1.1573 5.4736 -14.4288 19.9268 7.5204 -85.2205 -0.0000 0.0000 8.5842 2.9606 -1.8847 -6.0299 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -5.7430 6.9547 -0.4252 44.6247 0.0000 0.0000 3.8085 -15.1550 12.0992 -4.4347 0.0000 -0.0000 -23.2726 -2.4810 -6.3137 0.6694 0.0000 0.0000 -5.4209 9.4320 0.8626 -14.0670 0.0000 -0.0000 4.2727 9.8611 24.6404 9.5567 0.9384 1.5317 -0.8902 2.3909 0.2841 -1.5556 0.9087 0.6983 11.8984 13.7652 4.7997 -3.8255 5.1510 -0.7934 -26.5698 19.8654 5.9156 -1.2015 8.0445 -5.9295 5.1091 -14.1598 12.3371 -22.6345 -34.2287 6.4939 0.0000 0.0000 17.5967 -20.0286 -1.8722 -1.6376 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.0245 5.1362 -12.8155 20.8925 6.2761 -84.1681 -0.0000 0.0000 9.1552 4.4344 -1.9715 -7.1618 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -9.3967 8.5482 -2.1440 48.5340 0.0000 0.0000 0.1226 -14.7616 8.4818 -4.3242 0.0000 -0.0000 -22.0973 -2.5560 -5.2822 1.3964 0.0000 0.0000 -5.4174 8.2255 0.2561 -14.1616 0.0000 -0.0000 4.3969 9.3302 24.7621 9.1741 1.4553 0.7370 -0.8469 2.8671 0.2813 -1.4893 0.7476 0.6547 12.3124 12.9558 5.1365 -3.3775 5.1806 -0.7315 -24.8898 21.0956 6.8285 -0.3047 9.3789 -5.2023 5.0765 -13.7151 11.8535 -25.5368 -31.3469 4.4981 0.0000 0.0000 20.2488 -17.0136 0.3458 -1.0518 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.6737 5.1721 -10.9296 21.3479 5.6249 -83.6536 -0.0000 0.0000 8.6574 3.1944 -3.1208 -7.9668 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -12.3372 9.7098 -5.0432 49.6365 0.0000 0.0000 -3.8184 -12.2178 3.0198 -4.7264 0.0000 -0.0000 -20.5688 -3.0263 -4.5839 1.7227 0.0000 0.0000 -5.1066 7.9302 -0.3000 -14.5124 0.0000 -0.0000 4.5118 8.8107 24.8743 8.4463 2.2185 0.6527 -0.6987 3.0516 0.2147 -1.3803 0.7056 0.6011 12.9250 11.8967 5.1124 -2.8232 5.1430 -0.7291 -22.8645 21.7564 7.0075 0.7869 10.0670 -4.5953 5.0808 -12.9827 11.2562 -26.9602 -28.0129 3.9217 0.0000 0.0000 23.0462 -10.9097 2.7908 -0.3088 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.5833 5.0443 -9.3645 21.6439 7.0033 -83.7898 -0.0000 0.0000 8.4219 0.8031 -4.2825 -8.1979 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -14.3807 10.7730 -8.8853 48.0267 0.0000 0.0000 -5.7564 -9.5296 -1.1839 -4.0930 0.0000 -0.0000 -18.7291 -3.6117 -3.5394 1.8276 0.0000 0.0000 -4.5728 8.6288 -1.6296 -14.6643 0.0000 -0.0000 4.6128 8.2948 24.9701 7.3941 3.0068 0.8181 -0.4145 3.2998 0.0908 -1.2791 0.6276 0.5323 13.6727 10.7021 4.9178 -2.2720 4.9675 -0.7174 -20.9158 21.8164 6.7481 2.2234 10.2162 -4.1124 5.0000 -12.0652 10.7096 -28.5006 -24.6426 3.8406 0.0000 0.0000 25.7517 -6.4095 4.7534 0.5226 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.6084 4.8538 -8.3719 21.8715 9.0897 -84.1793 -0.0000 0.0000 8.7059 0.1527 -5.1131 -8.2531 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.6349 11.7712 -12.8158 44.2736 0.0000 0.0000 -6.2535 -8.2730 -2.7358 -2.8097 0.0000 -0.0000 -16.6052 -4.1514 -1.8958 1.9791 0.0000 0.0000 -4.1566 8.7715 -3.7166 -13.4950 0.0000 -0.0000 4.6822 7.7999 25.0518 6.5535 3.8403 0.9129 -0.3048 3.6486 -0.0469 -1.2638 0.5132 0.4633 14.3610 9.4722 4.6486 -1.8061 4.6170 -0.6800 -19.0927 21.3127 6.3063 3.7914 10.1712 -3.7138 4.5897 -11.2372 10.2818 -30.5564 -21.6371 4.0666 0.0000 0.0000 28.3743 -4.0509 6.2924 1.1604 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.4397 4.8512 -7.7436 22.0701 9.9128 -84.4638 -0.0000 0.0000 8.9512 1.1169 -5.5749 -8.2786 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -16.8115 12.3411 -16.1233 38.7214 0.0000 0.0000 -5.5604 -8.2500 -1.6914 -1.7858 0.0000 -0.0000 -15.0218 -4.7926 0.2237 2.6862 0.0000 0.0000 -3.8515 7.7790 -6.1819 -10.9417 0.0000 -0.0000 4.7100 7.3318 25.1212 6.0608 4.9486 0.9803 -0.3531 3.7120 -0.1492 -1.3433 0.4476 0.4062 14.8228 8.2502 4.3013 -1.3854 4.1977 -0.6429 -17.1816 20.4572 5.6972 5.2453 10.0488 -3.4020 3.8032 -10.4510 9.8813 -32.5391 -19.3970 4.7436 0.0000 0.0000 31.1000 -1.2281 8.0939 1.2334 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.1461 4.8835 -7.2514 22.4043 9.7418 -84.7282 -0.0000 0.0000 8.9019 1.8540 -5.6551 -8.1557 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -18.0047 12.0084 -18.2752 31.4311 0.0000 0.0000 -3.1620 -7.8593 0.9527 -1.1263 0.0000 -0.0000 -14.2526 -5.8571 2.3690 4.0742 0.0000 0.0000 -3.4012 6.1528 -8.7374 -8.7795 0.0000 -0.0000 4.7038 6.8731 25.1716 5.7570 6.1920 1.0219 -0.5274 3.4611 -0.1778 -1.4551 0.3579 0.3612 15.1150 7.1730 4.0266 -0.9493 3.8272 -0.5945 -15.1173 19.5180 4.8571 6.5869 9.8409 -3.2703 2.8758 -9.5664 9.4003 -33.9017 -17.8513 5.8838 0.0000 0.0000 33.9785 2.7603 9.9894 0.9045 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0053 4.7179 -6.8409 22.9926 10.1469 -85.2447 -0.0000 0.0000 8.7294 1.9367 -5.4208 -7.8742 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -19.0186 10.9406 -18.8402 22.8536 0.0000 0.0000 0.2934 -6.1868 3.5043 -0.7073 0.0000 -0.0000 -13.8027 -7.1687 3.9153 5.5979 0.0000 0.0000 -2.9906 4.2882 -10.8395 -8.3143 0.0000 -0.0000 4.6900 6.3806 25.1952 5.1261 6.7499 1.1820 -0.5597 3.6515 -0.1564 -1.4618 0.2154 0.3213 15.3101 6.3046 3.9092 -0.4852 3.5060 -0.4961 -12.8897 18.5564 3.7767 7.9234 9.6234 -3.4295 2.0733 -8.6010 8.7927 -34.6575 -16.7088 7.3272 0.0000 0.0000 36.8186 6.3032 11.1634 0.7308 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0090 4.3428 -6.5022 23.8589 11.4946 -86.1389 -0.0000 0.0000 8.5248 2.1322 -5.0462 -7.5942 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -19.6183 10.4397 -18.3241 14.6073 0.0000 0.0000 3.2942 -4.5352 4.8854 -0.6455 0.0000 -0.0000 -12.5307 -7.7461 4.4926 6.4427 0.0000 0.0000 -3.1112 2.6683 -11.8301 -8.7817 0.0000 -0.0000 4.6759 5.8544 25.2008 4.2484 6.4559 1.7357 -0.4918 4.4110 -0.1306 -1.3735 0.0904 0.2977 15.4659 5.6616 3.7964 -0.0327 3.2068 -0.4021 -10.4761 17.4707 2.4380 9.2309 9.2965 -3.9475 1.4426 -7.8031 8.0961 -35.0854 -15.8666 8.9497 -0.0000 0.0000 39.3717 8.6417 11.5720 0.9381 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0853 4.0194 -6.1746 24.9284 12.7204 -87.2614 -0.0000 0.0000 8.2365 2.4443 -4.5610 -7.3626 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -20.6146 11.1461 -17.9185 8.9739 0.0000 0.0000 5.0085 -4.3843 5.2450 -0.8194 0.0000 -0.0000 -10.4575 -7.4223 4.4902 6.5013 0.0000 0.0000 -3.7466 2.0381 -12.0984 -9.0405 0.0000 -0.0000 4.6542 5.3144 25.2042 3.2483 5.9096 2.7234 -0.3259 5.0960 -0.1162 -1.2234 0.0106 0.2736 15.5729 5.2308 3.6147 0.4024 2.9567 -0.3616 -7.8532 16.1919 0.8218 10.4015 8.5591 -4.8523 0.9093 -7.1821 7.3771 -35.2120 -15.4742 10.7545 -0.0000 0.0000 41.4079 10.3745 11.8566 1.2292 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.2686 3.9600 -5.7376 26.1352 13.1930 -88.4974 -0.0000 0.0000 7.9626 2.4331 -3.9241 -7.1139 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -22.3859 12.5416 -17.9568 6.7406 0.0000 0.0000 5.6611 -5.0520 5.3221 -0.9475 0.0000 -0.0000 -7.9296 -6.9144 4.3784 5.9980 0.0000 0.0000 -4.4423 2.4365 -12.4091 -8.9958 0.0000 -0.0000 4.6209 4.7538 25.2015 1.9034 5.3847 4.0062 0.0657 5.5294 -0.1394 -0.9602 -0.0565 0.2425 15.6242 4.8767 3.4468 0.8534 2.7556 -0.3239 -5.0614 14.5546 -1.0160 11.4138 7.4011 -6.1123 0.4274 -6.4400 6.6694 -34.7636 -15.6052 12.7194 -0.0000 0.0000 42.7598 11.8424 12.2958 1.3291 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.5758 3.9392 -5.2050 27.4604 13.3080 -89.8775 -0.0000 0.0000 7.8113 2.3937 -3.3141 -6.8735 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -24.2960 14.1757 -17.5566 7.0476 0.0000 0.0000 5.9107 -4.8016 5.1322 -1.0150 0.0000 -0.0000 -4.8592 -6.5270 3.9813 5.1501 0.0000 0.0000 -5.0455 3.1114 -12.7570 -9.0106 0.0000 -0.0000 4.5649 4.1579 25.1867 0.2429 4.8899 5.5876 0.5692 5.8642 -0.1695 -0.6485 -0.0490 0.2219 15.7848 4.4466 3.2483 1.3266 2.4342 -0.2370 -2.3862 12.3874 -2.8848 12.3283 6.1526 -7.5956 0.0475 -5.6263 5.8562 -33.6267 -15.9770 15.0073 -0.0000 0.0000 43.3593 12.8877 12.6752 1.2715 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.8780 3.7489 -4.7736 28.7720 13.3106 -91.2506 -0.0000 0.0000 7.6447 2.7449 -2.9185 -6.7470 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -25.6204 15.6805 -16.1132 8.3310 0.0000 0.0000 6.3358 -2.9780 4.2833 -1.0609 0.0000 -0.0000 -1.5258 -6.3347 3.0734 4.4243 0.0000 0.0000 -5.8600 3.5741 -12.9900 -8.9643 0.0000 -0.0000 4.4777 3.5387 25.1616 -1.1436 4.5103 7.4422 0.7504 6.0482 -0.1344 -0.5318 0.0890 0.2220 16.2597 3.9355 2.9312 1.7794 1.9308 -0.1144 -0.2165 9.7801 -4.5518 13.1520 4.9991 -9.0788 -0.2194 -5.1553 4.9518 -32.0858 -16.1896 17.6050 -0.0000 0.0000 43.3962 13.7549 12.8578 1.1494 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -1.0671 3.6048 -4.5867 29.8141 12.9254 -92.2532 -0.0000 0.0000 7.3308 3.0142 -2.6499 -6.7534 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -26.3587 16.7267 -13.8174 9.2076 0.0000 0.0000 7.1740 -0.6616 3.3673 -1.1208 0.0000 -0.0000 1.1257 -6.5164 2.1782 4.4293 0.0000 0.0000 -7.0949 4.0134 -13.5608 -8.6208 0.0000 -0.0000 4.3593 2.9067 25.1252 -1.9471 4.3717 9.2135 0.4247 5.9956 -0.0305 -0.6939 0.1855 0.2276 16.9644 3.4105 2.6561 2.1818 1.4005 0.0443 1.2938 7.1164 -5.8618 13.8509 3.8138 -10.3601 -0.4106 -5.0800 4.2394 -30.4617 -16.1742 20.1072 -0.0000 0.0000 43.1684 14.8511 12.9136 0.9807 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -1.2111 3.7986 -4.5588 30.5271 12.3616 -92.7122 -0.0000 0.0000 6.9993 2.7300 -2.2772 -6.8472 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -26.8253 17.1550 -10.6405 9.1867 0.0000 0.0000 7.8392 0.5676 3.1069 -1.2125 0.0000 -0.0000 2.7652 -7.1713 2.0578 5.2625 0.0000 0.0000 -8.6397 4.6081 -14.8920 -8.1866 0.0000 -0.0000 4.2136 2.2524 25.0690 -2.4371 4.3901 10.5804 -0.1416 5.8700 0.0690 -0.9167 0.0464 0.2046 17.5339 2.8866 2.6405 2.5406 0.9530 0.2345 2.2453 4.6873 -6.8011 14.4133 2.4990 -11.3680 -0.5302 -5.0013 3.8864 -28.6762 -16.1414 22.2116 -0.0000 0.0000 42.8056 15.8742 12.8073 0.8703 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -1.3565 4.1400 -4.6106 31.0048 12.2856 -92.7411 -0.0000 0.0000 6.8346 2.3399 -1.6887 -7.0327 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -27.0587 17.0805 -7.4459 8.6097 0.0000 0.0000 7.6550 0.2497 3.6855 -1.1880 0.0000 -0.0000 3.9468 -8.1355 2.7532 6.5331 0.0000 0.0000 -10.3486 5.2337 -16.6858 -7.9649 0.0000 -0.0000 4.0489 1.5838 24.9830 -2.6900 4.2271 11.6755 -0.6662 5.8162 0.1139 -1.0912 -0.0931 0.1906 17.7961 2.4051 2.7148 2.8094 0.5088 0.4415 2.6756 2.4782 -7.5034 14.8098 1.1627 -12.1217 -0.5497 -4.8242 3.6996 -26.4986 -16.0155 24.1318 -0.0000 0.0000 42.2381 16.2038 12.3640 1.0089 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -1.4848 4.1994 -4.8762 31.1836 12.6192 -92.3692 -0.0000 0.0000 6.8118 2.3556 -0.9408 -7.2710 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -27.0755 16.8648 -6.2317 7.8768 0.0000 0.0000 7.0997 -0.5803 5.0793 -1.0802 0.0000 -0.0000 4.8563 -8.9879 3.5995 8.0227 0.0000 0.0000 -12.1516 5.8795 -18.3427 -7.8509 0.0000 -0.0000 3.8713 0.9128 24.8630 -2.4997 3.6602 12.6272 -1.1732 5.7904 0.1766 -1.3269 0.0317 0.2155 17.9303 2.0855 2.7063 2.9162 0.0580 0.6064 2.5138 0.4457 -8.0749 15.0223 -0.1232 -12.6749 -0.3407 -5.0053 3.5682 -24.1491 -15.2760 26.1992 -0.0000 0.0000 41.3523 15.9091 11.5503 1.3672 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -1.6427 4.0250 -5.3651 30.8933 12.5846 -91.4669 -0.0000 0.0000 6.7990 2.5877 -0.2068 -7.3919 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -27.0539 16.6849 -6.9931 7.0539 0.0000 0.0000 7.0890 -0.9451 6.4337 -1.2160 0.0000 -0.0000 5.4248 -9.4257 4.1672 9.4876 0.0000 0.0000 -13.8505 6.6895 -19.6141 -7.6526 0.0000 -0.0000 3.6799 0.2117 24.7138 -1.9944 2.7740 13.2396 -1.7641 5.7756 0.3147 -1.6196 0.2012 0.2570 18.0561 1.9985 2.7482 2.8880 -0.2880 0.7383 1.8443 -1.3012 -8.5715 15.1898 -1.4479 -13.0596 0.1633 -5.6878 3.6700 -22.1170 -13.9443 28.1916 -0.0000 0.0000 40.1612 15.5264 10.6079 1.7435 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -1.8777 4.0321 -5.8623 30.1492 12.1919 -90.0635 -0.0000 0.0000 6.8062 2.7791 0.2365 -7.2645 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -27.0796 16.4086 -7.7591 6.5695 0.0000 0.0000 7.1426 -1.5032 6.1644 -1.6433 0.0000 -0.0000 6.2013 -9.5095 4.6055 10.3859 0.0000 0.0000 -15.2304 7.6241 -20.5093 -7.5525 0.0000 -0.0000 3.4747 -0.5508 24.5419 -1.4487 1.6504 13.5985 -2.3506 5.8407 0.4623 -1.8742 0.2575 0.2871 18.0280 2.0841 2.8151 2.8086 -0.5250 0.8456 0.8811 -2.8257 -9.0177 15.4205 -2.8677 -13.2359 0.7470 -6.4386 3.9471 -20.2736 -12.9280 29.9445 -0.0000 0.0000 38.6379 15.0659 9.8986 2.0799 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -2.1096 4.2330 -6.3348 29.0330 12.3570 -88.2574 -0.0000 0.0000 6.8590 3.0222 0.3060 -7.0065 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -26.9530 16.0321 -8.8600 7.3616 0.0000 0.0000 5.7959 -3.1724 4.5996 -1.9304 0.0000 -0.0000 7.5786 -9.3606 4.9392 10.5224 0.0000 0.0000 -16.2450 8.5858 -21.0324 -7.7691 0.0000 -0.0000 3.2507 -1.3615 24.3394 -0.5241 0.2325 14.2246 -3.0685 5.9389 0.5434 -2.1948 0.5936 0.3468 17.8797 2.3237 2.5163 2.6468 -0.7870 0.8077 -0.3963 -4.3753 -9.3586 15.4784 -4.3523 -13.0657 1.1248 -7.1815 4.0631 -17.8168 -12.3280 32.0644 0.0000 0.0000 36.5160 13.9004 9.4740 2.5518 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -2.3697 4.4343 -7.0173 27.5004 13.0569 -85.6635 -0.0000 0.0000 6.6786 3.1893 0.4553 -6.9243 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -26.4421 15.7845 -12.3020 9.3275 0.0000 0.0000 3.6421 -5.1728 4.4004 -1.8458 0.0000 -0.0000 8.6708 -8.9699 4.8978 10.6001 0.0000 0.0000 -17.0186 9.7534 -21.4123 -8.0289 0.0000 -0.0000 2.9684 -2.2184 24.1042 0.9300 -0.9494 14.6866 -4.2009 5.4000 0.6745 -2.8615 1.3412 0.4776 18.1206 2.9044 1.9295 2.3120 -0.9920 0.6039 -2.3134 -5.9283 -9.3907 15.0811 -5.9664 -12.4123 1.2468 -8.4936 4.2115 -14.2978 -10.7439 35.1313 0.0000 0.0000 33.4939 11.7666 8.8358 3.2632 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -2.8052 5.2416 -7.8291 25.3584 12.5032 -81.5994 -0.0000 0.0000 5.9523 2.8005 1.2292 -7.1284 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -25.7512 14.8314 -15.2143 11.3951 0.0000 0.0000 3.4612 -6.1805 5.6018 -1.6624 0.0000 -0.0000 9.0814 -8.9319 5.1085 11.1210 0.0000 0.0000 -17.6622 11.3416 -21.9887 -8.0951 0.0000 -0.0000 2.5524 -3.1729 23.8752 1.9190 -0.3879 13.1855 -5.6221 3.1271 1.0292 -3.8792 1.5401 0.5651 19.0507 3.9520 1.9865 1.8226 -0.9025 0.4615 -4.8741 -7.2457 -8.9619 14.4177 -7.8912 -11.2075 1.3065 -10.3775 5.0670 -10.2052 -7.7938 38.7706 0.0000 0.0000 29.5486 9.1742 7.6364 3.8619 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.2473 7.5850 -8.3425 22.4949 9.6400 -76.1146 -0.0000 0.0000 4.9149 2.0590 2.1851 -7.2526 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -25.8475 10.8965 -11.8528 13.9902 0.0000 0.0000 5.3038 -5.5040 4.7652 -0.9899 0.0000 -0.0000 10.2230 -10.8582 7.3360 11.7536 0.0000 0.0000 -18.0342 13.1753 -22.6594 -8.7402 0.0000 -0.0000 1.9974 -4.2279 23.7122 1.6635 2.1226 9.4700 -6.3994 0.0941 1.3926 -4.5296 0.3115 0.3824 19.4822 4.6730 2.9583 1.3477 -0.5909 0.6029 -7.0741 -8.5545 -8.2002 13.9105 -10.1469 -9.5013 1.5523 -11.1174 6.3790 -6.0535 -6.5810 42.7763 0.0000 0.0000 24.7363 6.5096 6.3768 3.7989 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.2902 10.4841 -8.4947 19.2274 6.8734 -70.5499 -0.0000 0.0000 4.2428 1.9279 2.1038 -6.8121 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -26.9957 3.9865 -3.6729 18.9811 0.0000 0.0000 5.4133 -3.9189 1.2217 0.3128 0.0000 0.0000 13.0176 -14.8347 11.6791 12.9287 0.0000 0.0000 -17.4305 14.6725 -23.0457 -11.0857 0.0000 -0.0000 1.4366 -5.2746 23.6985 0.5882 4.2556 6.7682 -5.8602 -1.1874 1.1988 -4.1848 -0.8394 0.1342 18.3660 4.0174 3.5015 1.0367 -0.6693 0.8339 -8.0320 -10.8557 -7.5688 13.4073 -12.4916 -7.5439 1.7321 -9.4526 6.9461 -1.6157 -10.1912 47.8512 0.0000 0.0000 19.0476 3.5835 5.5724 2.9823 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -2.9160 11.5277 -8.6161 16.0584 6.9241 -66.3567 -0.0000 0.0000 4.1063 2.4864 0.9682 -5.9862 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -27.0660 -1.4685 0.3219 24.4501 0.0000 0.0000 2.2092 -2.5525 -0.7389 0.8692 0.0000 0.0000 15.0218 -18.6619 14.0710 16.7876 0.0000 0.0000 -14.6721 15.0217 -23.2198 -14.4402 0.0000 -0.0000 0.9844 -6.1975 23.8659 -0.3684 4.0057 7.3533 -4.6558 -0.2841 0.7343 -3.3972 -0.3528 0.1570 16.7274 2.9292 2.4360 0.7668 -1.5642 0.7904 -8.4765 -14.7744 -7.6961 12.4677 -14.6990 -5.9744 1.2372 -6.5412 6.5522 3.6246 -17.1901 53.3027 0.0000 0.0000 13.3138 0.6257 4.3019 2.1467 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -2.8232 10.0325 -9.2779 13.6732 8.7045 -63.5696 -0.0000 0.0000 3.5168 2.6153 0.5369 -5.6288 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -24.9307 -2.3909 -0.8465 26.8571 0.0000 0.0000 -1.9595 -1.5144 -0.8694 0.5808 0.0000 0.0000 12.2995 -20.6406 10.4456 25.0453 0.0000 0.0000 -9.4819 13.6697 -22.9409 -15.8269 0.0000 -0.0000 0.6208 -6.9783 24.0939 -0.7576 2.5708 9.8254 -3.3886 0.9071 0.3725 -2.6890 0.7936 0.2825 15.2989 2.4696 0.7493 0.4438 -2.6139 0.6111 -9.3656 -19.1862 -8.7304 11.1968 -16.4232 -5.4564 0.4755 -4.1396 6.0895 9.0757 -22.9350 57.4294 0.0000 0.0000 9.1000 -0.9240 0.9023 1.7163 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.3832 7.6126 -10.6470 12.0882 9.7395 -61.7674 -0.0000 0.0000 1.8461 1.8177 1.4979 -6.1608 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -21.5382 -1.5346 -2.9989 25.9927 0.0000 0.0000 -4.3307 0.0175 -1.0034 0.2158 0.0000 0.0000 5.3406 -20.9951 3.9722 36.1410 0.0000 0.0000 -3.1201 10.7995 -22.3486 -13.6997 0.0000 -0.0000 0.2862 -7.6979 24.2627 -1.0865 2.0138 11.0127 -2.4176 0.8593 0.2621 -2.2243 1.1794 0.3390 14.3662 2.4751 0.3802 0.1432 -3.2284 0.7350 -10.6207 -22.0231 -10.1312 10.1470 -17.3474 -5.8523 0.2906 -2.9827 6.0694 13.0723 -24.7470 59.6243 0.0000 0.0000 7.2033 -0.1655 -3.4668 1.5968 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -4.1741 6.1607 -12.1996 10.1005 9.8034 -60.7681 -0.0000 -0.0000 -0.0268 0.8734 2.0400 -6.9678 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -18.2640 -2.2798 -3.0932 24.1435 0.0000 0.0000 -5.1552 1.8442 -1.7590 0.0989 0.0000 0.0000 -1.5029 -21.5974 0.4854 46.2694 0.0000 0.0000 1.4900 7.3678 -20.6995 -11.5374 0.0000 -0.0000 -0.0187 -8.4094 24.3631 -1.4910 2.1502 9.8456 -1.9691 0.2552 0.3365 -2.0211 0.8553 0.3629 13.9481 2.4292 1.5513 -0.0155 -3.5662 1.2272 -11.3848 -22.6522 -11.0644 9.6544 -17.5720 -6.3171 0.7317 -2.9476 6.1675 15.0038 -24.0986 60.7735 0.0000 0.0000 6.9993 1.1963 -5.4282 1.7251 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.7185 5.7531 -13.2910 7.1451 10.1703 -60.3953 -0.0000 -0.0000 -0.9814 0.2883 0.7382 -7.3153 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -15.7377 -3.9454 -2.1010 23.1502 0.0000 0.0000 -6.3379 2.8255 -1.7284 0.0346 0.0000 0.0000 -6.2294 -23.0404 0.7517 53.1259 0.0000 0.0000 2.4555 5.0829 -16.7462 -11.1261 0.0000 -0.0000 -0.2620 -9.1097 24.4307 -1.6708 1.6941 7.9082 -1.8530 0.0841 0.3898 -1.9475 0.7457 0.4228 13.7121 2.3311 2.7848 -0.0260 -3.8567 1.7077 -11.2973 -22.2047 -11.1684 9.5808 -17.4508 -6.2973 1.2793 -3.4573 5.9835 15.8027 -23.9052 62.1888 0.0000 0.0000 7.5028 0.5641 -3.8528 1.6860 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.0960 5.3752 -13.7672 4.1811 10.7752 -60.1826 -0.0000 -0.0000 -1.0807 -0.1472 -1.3574 -7.2355 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -13.6523 -4.4561 -2.4077 22.9510 0.0000 0.0000 -8.2729 2.9221 0.2396 -0.0078 0.0000 -0.0000 -9.5287 -23.9353 2.4929 56.0713 0.0000 0.0000 0.9004 3.9831 -11.3792 -11.1862 0.0000 -0.0000 -0.4483 -9.7973 24.4852 -1.8113 0.5105 6.4824 -1.7314 0.1624 0.3781 -1.8607 1.0148 0.4997 13.5211 2.5329 3.2728 0.0249 -3.9529 1.8703 -10.8923 -21.7345 -10.7260 9.6294 -17.2667 -5.9353 1.5719 -3.9110 5.7616 16.4455 -25.0956 64.0019 0.0000 0.0000 8.3776 -1.9845 -1.1211 1.7328 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -5.7174 4.7336 -13.8888 2.0938 10.6638 -59.7417 -0.0000 -0.0000 -1.0231 -0.2799 -2.2623 -7.1457 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -11.5320 -3.8620 -3.2942 22.8980 0.0000 0.0000 -10.0769 2.9489 2.6778 0.1347 0.0000 0.0000 -12.1668 -23.8870 4.0340 55.4255 0.0000 0.0000 -0.8089 3.2061 -7.0845 -10.9057 0.0000 -0.0000 -0.6080 -10.4745 24.5278 -2.1122 -0.4578 5.2573 -1.5244 -0.1538 0.3665 -1.7534 1.1116 0.5287 13.4698 3.0832 3.5612 0.1099 -3.7327 1.8352 -10.6488 -21.2828 -10.1621 9.6335 -17.1094 -5.6207 1.6811 -3.8574 5.9042 17.0766 -26.6384 65.5845 0.0000 0.0000 9.4352 -3.9022 0.1482 1.9077 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -6.5630 4.1945 -13.8727 0.6385 9.9919 -59.3212 -0.0000 -0.0000 -1.0083 0.2463 -1.6907 -7.1825 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.3908 -3.4584 -3.3172 22.8735 0.0000 0.0000 -11.5664 2.9049 4.2334 0.4525 0.0000 0.0000 -14.1749 -24.0435 5.5415 51.9907 0.0000 0.0000 -1.6843 2.7498 -5.3076 -10.3755 0.0000 -0.0000 -0.7463 -11.1433 24.5567 -2.3810 -0.9095 3.7391 -1.3925 -0.8184 0.3743 -1.6863 0.9733 0.5470 13.5160 3.6542 4.1768 0.2157 -3.4126 1.8594 -10.5217 -20.7027 -9.6985 9.5585 -16.9493 -5.4771 1.7655 -3.3269 6.2653 17.6080 -27.4802 66.8298 0.0000 0.0000 10.1135 -3.8744 0.0444 1.9364 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -7.2701 3.8128 -13.7155 -0.5418 9.5627 -59.4249 -0.0000 -0.0000 -0.8419 0.9824 -0.8838 -7.1861 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.3399 -3.3902 -3.1371 22.7444 0.0000 0.0000 -13.0251 2.3213 5.6865 0.7728 0.0000 0.0000 -15.5607 -24.7209 7.6085 46.4753 0.0000 0.0000 -2.0310 2.5841 -5.5416 -9.6761 0.0000 -0.0000 -0.8513 -11.8043 24.5691 -2.3784 -1.3698 2.1593 -1.3578 -1.2759 0.3757 -1.6363 0.9093 0.5731 13.3887 4.1240 4.9640 0.2648 -3.2555 1.9846 -10.3663 -20.2457 -9.3391 9.5171 -16.8113 -5.3564 1.7284 -2.7477 6.4498 18.2576 -27.6784 68.0274 0.0000 0.0000 10.0591 -3.0134 -0.1473 1.8825 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -7.6874 3.4387 -13.4480 -1.1801 9.1846 -59.9877 -0.0000 -0.0000 -0.6632 1.1749 -0.3962 -7.1052 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.3944 -2.9718 -3.8232 22.3211 0.0000 0.0000 -14.4256 1.6787 7.9835 1.0390 0.0000 0.0000 -16.8067 -24.9779 9.7498 39.6361 0.0000 0.0000 -1.7405 2.1282 -6.7294 -8.9488 0.0000 -0.0000 -0.9186 -12.4566 24.5599 -2.1371 -2.0571 0.7064 -1.3050 -1.4321 0.3710 -1.5572 1.0479 0.6283 13.0175 4.4693 5.6447 0.1949 -3.1994 2.1265 -10.2534 -20.0490 -8.9839 9.6656 -16.7719 -5.1274 1.5309 -2.3590 6.4886 18.9395 -27.8293 69.0559 0.0000 0.0000 9.7061 -2.6111 -0.0851 1.6752 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -7.9865 3.1742 -13.2102 -1.2352 8.4254 -60.4375 -0.0000 -0.0000 -0.7322 0.9595 0.0742 -7.0975 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -3.7976 -2.1611 -4.7084 22.0551 0.0000 0.0000 -15.7856 1.6166 10.4728 1.2733 0.0000 0.0000 -18.4011 -24.3761 11.0578 32.4509 0.0000 0.0000 -0.5020 1.2736 -8.1326 -8.3787 0.0000 -0.0000 -0.9470 -13.1187 24.5281 -1.9353 -2.5966 -0.9186 -1.1741 -1.6587 0.3758 -1.4174 1.1074 0.6586 12.6000 4.7125 6.3188 0.0961 -3.0688 2.2560 -10.1798 -19.8208 -8.5376 9.9536 -16.8265 -4.7880 1.4169 -1.9530 6.6484 19.2127 -28.2722 69.6073 0.0000 0.0000 9.7983 -2.6626 0.0141 1.3256 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -8.2890 3.0637 -12.9855 -1.2649 7.9716 -60.4902 -0.0000 -0.0000 -0.8612 0.9433 0.5031 -7.1605 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -2.5224 -1.4235 -4.7553 22.3732 0.0000 0.0000 -17.2211 1.5951 12.3376 1.3525 0.0000 0.0000 -20.1167 -23.4989 11.6376 25.6863 0.0000 0.0000 1.3924 0.9630 -9.5230 -8.3349 0.0000 -0.0000 -0.9318 -13.8238 24.4807 -1.9553 -2.8725 -2.8954 -0.9996 -2.0642 0.3641 -1.2654 1.0264 0.6543 12.3260 4.8146 7.0503 0.0825 -2.8326 2.3815 -9.9660 -19.4102 -7.9666 10.1767 -16.8726 -4.3853 1.5157 -1.4466 6.9088 19.0657 -28.9087 69.8451 0.0000 0.0000 10.4911 -2.8772 0.2639 1.1201 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -8.5405 2.9507 -12.5893 -1.4746 8.3170 -60.3373 -0.0000 -0.0000 -0.7117 1.1434 0.6851 -7.1484 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.9958 -0.7085 -4.4358 22.7455 0.0000 0.0000 -18.5861 0.9410 14.1238 1.1787 0.0000 0.0000 -21.4995 -22.5935 12.1034 19.6381 0.0000 0.0000 3.3725 2.0138 -11.1269 -9.5246 0.0000 -0.0000 -0.8829 -14.5791 24.4226 -2.0403 -3.0974 -5.0026 -0.8529 -2.4061 0.3230 -1.1269 0.9225 0.6354 12.1101 4.8440 7.6658 0.0867 -2.6027 2.4738 -9.5639 -19.0627 -7.3335 10.3563 -16.8529 -3.9643 1.6342 -1.1318 7.0971 18.9358 -29.5278 70.1217 0.0000 0.0000 11.3359 -3.3006 0.7119 1.1927 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -8.6695 2.8277 -12.0355 -1.4713 8.6903 -60.0525 -0.0000 -0.0000 -0.3636 1.3273 0.8374 -7.0812 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 1.0090 0.2629 -4.5778 22.5039 0.0000 0.0000 -19.7701 0.1474 16.4861 0.8981 0.0000 0.0000 -22.8603 -21.4426 12.1141 14.7175 0.0000 0.0000 4.9105 4.1354 -12.8231 -11.8667 0.0000 -0.0000 -0.8229 -15.3700 24.3595 -2.0860 -3.3376 -7.1498 -0.6516 -2.4875 0.3598 -0.9339 0.8267 0.6075 11.7669 4.8026 8.1136 0.0021 -2.4621 2.5370 -9.1633 -18.9360 -6.7716 10.6822 -16.7983 -3.5920 1.6753 -1.0724 7.2240 18.9745 -30.0487 70.4497 0.0000 0.0000 11.9919 -3.6062 1.0919 1.2458 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.6989 2.7733 -11.5561 -1.1496 8.7629 -59.5090 -0.0000 -0.0000 -0.0505 1.6310 1.1788 -7.0425 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 3.1905 1.4371 -4.8930 21.8382 0.0000 0.0000 -20.7722 -0.4425 19.0628 0.6248 0.0000 0.0000 -24.7212 -20.1983 11.7943 11.8284 0.0000 0.0000 5.1499 6.2568 -14.0950 -13.7411 0.0000 -0.0000 -0.7674 -16.1856 24.2950 -1.9808 -3.4161 -9.4641 -0.4403 -2.3531 0.4993 -0.7271 0.6241 0.5807 11.3519 4.6423 8.5482 -0.1170 -2.4018 2.6435 -8.9412 -18.9337 -6.3894 11.0527 -16.7553 -3.3297 1.7464 -0.9326 7.3816 19.0369 -30.4843 70.7494 0.0000 0.0000 12.4559 -3.2613 1.3519 1.0448 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -8.7424 2.6133 -11.2056 -0.8341 9.3652 -58.8754 -0.0000 0.0000 0.3615 2.1629 1.5264 -6.9470 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 5.1306 2.5361 -4.5431 21.2186 0.0000 0.0000 -21.2878 -1.5249 21.1467 0.1285 0.0000 0.0000 -27.1041 -19.1365 12.7865 11.2038 0.0000 0.0000 3.7383 7.7536 -14.6521 -14.1624 0.0000 -0.0000 -0.7090 -17.0427 24.2171 -1.6598 -3.4940 -11.8901 -0.3859 -1.9594 0.6455 -0.6577 0.3162 0.5486 11.0660 4.4552 8.9946 -0.1993 -2.3587 2.7758 -8.8877 -19.0492 -6.1583 11.1742 -16.8183 -3.2011 1.7854 -0.6099 7.5495 19.3035 -30.7865 71.2694 0.0000 0.0000 12.5536 -2.7350 1.6068 0.8852 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -8.8982 2.2220 -10.7868 -0.4669 10.4612 -58.6557 -0.0000 0.0000 1.1273 2.8294 1.8031 -6.7093 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 6.8741 3.7219 -3.6378 20.5741 0.0000 0.0000 -21.3185 -3.1475 22.8144 -0.8037 0.0000 -0.0000 -29.3256 -17.7410 15.4472 11.2932 0.0000 0.0000 1.9929 8.7965 -13.8098 -14.1367 0.0000 -0.0000 -0.6448 -17.9588 24.0999 -1.0256 -3.7339 -14.0939 -0.6455 -1.3831 0.7463 -0.7345 0.0531 0.5341 10.9086 4.4149 9.2499 -0.3338 -2.3500 2.8434 -9.0107 -19.4147 -6.0676 11.0917 -17.1036 -3.2164 1.5449 -0.3921 7.7492 20.0630 -31.0575 72.0632 0.0000 0.0000 11.8793 -3.1031 1.7166 1.0469 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.1275 2.0092 -10.3212 0.2123 10.7887 -59.1176 -0.0000 0.0000 2.0854 3.8213 2.1444 -6.4244 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 8.5245 5.0692 -3.0134 19.7305 0.0000 0.0000 -21.5723 -4.0892 24.4624 -1.9455 0.0000 -0.0000 -31.2731 -15.6131 18.5973 10.7060 0.0000 0.0000 1.5654 9.4055 -11.7329 -14.4397 0.0000 -0.0000 -0.5947 -18.9566 23.9355 -0.3017 -3.7338 -16.0229 -1.0075 -1.0600 0.8883 -0.8140 -0.0666 0.5335 10.7923 4.5230 9.4087 -0.5643 -2.4258 2.8690 -9.4809 -19.9317 -6.2808 11.1141 -17.5457 -3.3986 1.1147 -0.1768 8.0590 21.1312 -31.7715 72.7736 0.0000 0.0000 10.4063 -4.3500 1.5674 1.1708 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -9.2340 2.4126 -10.1434 0.7069 10.3559 -60.0749 -0.0000 0.0000 2.8186 5.1372 2.3497 -6.2289 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 10.3709 6.1801 -2.7650 18.8197 0.0000 0.0000 -22.0348 -4.2272 26.0704 -2.9994 0.0000 -0.0000 -32.8197 -13.3198 21.3605 9.6610 0.0000 0.0000 2.2944 9.8749 -9.9110 -14.2957 0.0000 -0.0000 -0.5829 -20.0613 23.7254 0.3851 -3.0021 -18.0689 -1.3604 -1.2801 1.0252 -0.9202 -0.2847 0.5337 10.8008 4.7044 9.8546 -0.7553 -2.5041 2.9711 -10.3868 -20.3349 -6.8357 11.2390 -17.8799 -3.6716 0.9301 0.3419 8.4933 22.1013 -32.9223 73.2397 0.0000 0.0000 8.7401 -5.4835 1.3138 0.8308 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -9.1898 3.3118 -10.3295 0.4785 10.5360 -61.2029 -0.0000 0.0000 3.0907 5.9811 2.1800 -6.1710 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 12.5788 6.7122 -2.0296 17.9383 0.0000 0.0000 -21.5738 -4.9098 27.4257 -4.2819 0.0000 -0.0000 -33.2189 -11.5026 23.1967 8.6748 0.0000 0.0000 2.8856 11.2103 -10.0799 -13.4298 0.0000 -0.0000 -0.6070 -21.2772 23.4496 1.2927 -2.0692 -20.5093 -2.0082 -1.3853 0.9917 -1.2759 -0.8664 0.5022 11.0608 5.0090 10.5824 -0.9432 -2.4503 3.1226 -11.6630 -20.7693 -7.3983 11.2581 -17.9575 -3.8799 1.0268 0.4230 9.1231 22.8765 -33.6117 73.3916 0.0000 0.0000 7.5871 -5.8635 0.5847 0.3544 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -9.2278 4.5218 -10.3721 0.1581 10.9050 -62.4830 -0.0000 0.0000 3.1048 5.8682 2.1099 -6.3447 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 14.7389 7.2884 -0.9426 17.1862 0.0000 0.0000 -20.3204 -6.1690 28.9489 -6.2597 0.0000 -0.0000 -32.3434 -9.7441 22.3673 7.7865 0.0000 0.0000 3.7656 13.4012 -11.8619 -12.9569 0.0000 -0.0000 -0.6527 -22.5621 23.1330 2.2070 -2.1876 -23.0613 -2.9423 0.1247 0.8357 -1.9236 -1.6687 0.4439 11.6818 5.4838 11.0874 -1.5361 -2.4352 3.1851 -13.6005 -21.7699 -7.8702 11.1997 -17.8872 -4.0060 1.1364 -1.7574 10.2757 22.8694 -32.9061 72.0277 0.0000 0.0000 7.1751 -5.4934 -1.3455 0.3202 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -9.4765 6.5929 -10.0558 0.4633 9.3354 -64.0086 -0.0000 0.0000 3.2865 6.0155 2.4114 -6.5964 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 16.1971 9.2502 -1.6218 17.4036 0.0000 0.0000 -19.6925 -6.6722 31.9615 -8.7869 0.0000 -0.0000 -31.9960 -7.5011 17.4152 9.1563 0.0000 0.0000 5.6247 13.6309 -12.6067 -12.9082 0.0000 -0.0000 -0.7335 -23.8406 22.8879 2.7182 -2.3900 -25.1033 -3.4130 2.4663 0.3828 -2.4647 -2.1420 0.4271 12.5548 5.8684 11.4024 -2.7255 -2.8836 3.2795 -16.6168 -22.9743 -8.7713 11.0953 -17.8004 -4.2568 1.5136 -6.0357 12.1656 21.1774 -31.3657 67.8578 0.0000 0.0000 7.3270 -4.8815 -3.7320 0.6023 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -9.6066 9.6542 -10.2009 0.9162 6.8712 -65.4286 -0.0000 0.0000 3.7258 7.4322 2.0546 -6.5741 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 16.4748 11.7712 -3.8778 20.0138 0.0000 0.0000 -17.8040 -7.2458 36.8313 -11.2582 0.0000 -0.0000 -34.9159 -6.1939 10.6157 17.8790 0.0000 0.0000 5.7704 10.3158 -11.4528 -11.5177 0.0000 -0.0000 -0.9339 -25.1204 22.8276 2.2318 0.8696 -27.4248 -2.1230 2.0441 0.0663 -1.6529 -1.6898 0.5508 12.7088 5.3633 12.4258 -3.8117 -3.6563 3.7245 -19.7917 -22.6267 -10.1516 10.4082 -17.7871 -4.7475 2.6603 -8.6900 14.2429 18.3125 -31.2322 62.3946 0.0000 0.0000 7.6905 -5.2029 -4.1471 0.5542 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -8.9012 11.8431 -11.6719 1.0713 8.1130 -66.2686 -0.0000 0.0000 4.2383 8.6300 0.2282 -6.3994 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 16.6080 11.7788 -1.9902 24.6284 0.0000 0.0000 -8.2898 -10.0120 41.7091 -12.3715 0.0000 -0.0000 -37.0446 -8.9461 7.3704 30.7106 0.0000 0.0000 2.2786 5.9357 -11.4042 -8.9155 0.0000 -0.0000 -1.1761 -26.2912 23.0430 1.9174 6.0449 -30.2566 0.0383 -0.2320 0.1810 -0.2810 -1.4613 0.6478 12.4042 4.6238 14.1316 -4.2784 -3.9890 4.3224 -22.3853 -20.6786 -11.2472 8.6435 -17.3841 -5.1855 4.0928 -8.6370 15.5809 15.6603 -32.5337 58.2484 0.0000 0.0000 8.0240 -7.0641 -2.0812 0.1387 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -7.6268 12.1889 -13.8445 1.5155 12.8866 -66.4397 -0.0000 0.0000 4.7689 8.0287 -1.3506 -6.8069 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 15.2088 9.5245 5.0026 29.0078 0.0000 0.0000 10.0727 -15.6026 45.3843 -8.4758 0.0000 -0.0000 -34.9805 -14.0792 6.4823 38.3196 0.0000 0.0000 -3.1945 3.6771 -10.9221 -7.8647 0.0000 -0.0000 -1.3261 -27.2389 23.4475 3.5038 9.2597 -32.5624 1.0927 -1.7364 0.3695 0.1875 -1.7910 0.6206 12.0673 3.9576 14.9796 -4.4793 -3.7579 4.6147 -24.0478 -18.1113 -11.2593 6.6331 -16.1945 -5.0945 4.8620 -7.7203 15.8414 14.4601 -34.0748 56.5886 0.0000 0.0000 8.2681 -8.6417 -0.7770 0.0171 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -6.2901 11.7804 -15.4038 3.1363 16.4222 -66.3203 -0.0000 0.0000 5.4619 7.2935 -0.3026 -7.4089 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 11.0482 6.9408 11.3587 31.6168 0.0000 0.0000 22.1757 -20.7561 45.5996 -2.8529 0.0000 -0.0000 -31.8535 -17.2808 5.9883 38.7685 0.0000 0.0000 -7.2199 3.0761 -9.4547 -8.4130 0.0000 -0.0000 -1.4040 -28.0469 23.9283 5.9301 10.0661 -33.2422 0.9737 -1.8074 0.3819 0.0062 -1.9372 0.5274 11.7675 2.8527 14.1295 -4.8449 -3.3794 4.4320 -24.9404 -15.2145 -10.1121 5.5378 -14.2675 -4.4265 4.7476 -7.8225 15.5320 13.9492 -34.6820 55.9206 0.0000 0.0000 8.3211 -7.9300 -2.8281 0.2120 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -4.8298 12.0078 -15.9650 5.8657 16.5026 -66.5753 -0.0000 0.0000 6.3571 8.8464 2.1683 -7.2092 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 5.6961 5.4585 12.4261 33.0222 0.0000 0.0000 17.9082 -22.7913 39.5220 -1.4323 0.0000 -0.0000 -29.0886 -17.6352 5.1929 34.6550 0.0000 0.0000 -7.8035 2.3663 -8.2332 -9.0138 0.0000 -0.0000 -1.4499 -28.8220 24.3653 7.6498 9.8249 -32.8151 0.7304 -1.1195 0.3567 -0.1108 -1.6420 0.4559 11.1896 1.2953 12.7144 -5.2308 -3.0151 4.1093 -25.1440 -11.5573 -8.1605 5.3669 -11.9820 -3.6029 4.1986 -8.1959 15.2069 12.7792 -34.3520 54.5045 0.0000 0.0000 8.2343 -5.6117 -6.0772 0.3560 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -3.2241 12.3140 -16.2181 8.6312 16.3069 -67.5050 -0.0000 0.0000 7.2745 11.5853 3.2598 -6.5434 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 1.0792 5.8771 7.6945 32.5253 0.0000 0.0000 6.0286 -20.3247 30.6690 -2.0389 0.0000 -0.0000 -26.3996 -16.8986 5.4969 29.8521 0.0000 0.0000 -6.7155 1.2895 -8.1971 -8.8740 0.0000 -0.0000 -1.4796 -29.6082 24.6812 8.3117 10.0534 -32.7323 0.9890 -0.9053 0.3274 0.0423 -1.5664 0.4025 10.5023 0.1782 12.1234 -5.3146 -2.5413 3.9569 -24.7080 -7.6695 -5.8474 5.2538 -9.7897 -2.7965 3.6833 -7.7644 14.9631 11.2627 -32.3369 52.6451 0.0000 0.0000 8.4173 -3.8891 -6.9132 0.2974 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -1.8706 11.8587 -16.4142 10.6505 18.7541 -69.1558 -0.0000 0.0000 7.8181 12.4632 2.6777 -6.0055 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -2.1975 7.0541 1.5576 29.7045 0.0000 0.0000 0.0655 -17.6938 25.9752 -1.5310 0.0000 -0.0000 -23.1972 -16.7064 7.7155 26.6669 0.0000 0.0000 -6.7394 0.2234 -9.2734 -8.2583 0.0000 -0.0000 -1.4979 -30.3930 24.8636 8.2227 10.8806 -33.4246 1.5565 -1.1105 0.2705 0.2046 -1.8119 0.3652 10.2248 -0.2824 12.2147 -5.1624 -2.1173 3.9253 -23.8767 -4.8521 -3.5795 4.7506 -7.9329 -1.7111 3.3821 -7.1891 14.6968 10.5271 -27.0979 51.3512 0.0000 0.0000 9.3651 -2.9397 -4.7609 0.2136 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.9648 11.3199 -16.1035 11.8333 22.8938 -71.0114 -0.0000 0.0000 7.6809 10.4208 1.8440 -5.9515 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -4.6360 8.0139 -2.5766 25.3293 0.0000 0.0000 0.9633 -15.0763 25.6694 -1.2146 0.0000 -0.0000 -19.4819 -16.7341 10.0948 24.9211 0.0000 0.0000 -8.0163 -0.7267 -10.0281 -7.6441 0.0000 -0.0000 -1.5098 -31.1258 24.9398 8.0182 11.5581 -34.0932 1.7647 -1.0309 0.2227 0.2026 -1.8991 0.3339 10.4845 -0.6424 12.0153 -5.0074 -2.0220 3.8464 -23.0030 -3.5328 -1.6612 4.1366 -6.3866 -0.2327 3.2257 -7.4846 14.4186 10.4148 -18.7605 50.3500 0.0000 0.0000 11.0924 -0.8048 -1.4008 0.3971 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.3354 11.4567 -15.3502 12.1694 27.0723 -72.3336 -0.0000 0.0000 7.2002 6.9485 1.2533 -5.9921 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -7.2967 8.6433 -5.0934 20.3924 0.0000 0.0000 5.3199 -9.9538 26.2591 -1.7003 0.0000 -0.0000 -16.6202 -16.4487 11.4450 24.4444 0.0000 0.0000 -9.5575 -1.5166 -10.2705 -7.1991 0.0000 -0.0000 -1.5314 -31.8008 24.9623 7.7849 12.1628 -33.9019 1.6523 -0.7560 0.1845 0.0797 -1.7750 0.2945 11.1586 -1.2134 11.1310 -4.8192 -2.1423 3.6743 -22.2965 -2.9258 -0.2561 3.8102 -5.2230 1.2322 2.9205 -8.1130 14.1331 10.1013 -10.2514 49.0816 0.0000 0.0000 13.1105 2.8386 1.7814 0.7796 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0636 11.6852 -14.8195 11.8782 31.2105 -72.8346 -0.0000 0.0000 6.9501 3.8939 0.2360 -5.6691 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -10.2593 8.8985 -7.2838 15.9092 0.0000 0.0000 11.7197 -4.9399 24.7205 -2.1361 0.0000 -0.0000 -14.8191 -16.2935 12.6215 25.1467 0.0000 0.0000 -11.3474 -1.7927 -11.3010 -6.9856 0.0000 -0.0000 -1.5716 -32.4560 24.9634 7.3164 13.0150 -32.8454 1.5374 -0.7263 0.1380 -0.0136 -1.8045 0.2078 11.9477 -1.6831 9.8398 -4.4626 -2.0943 3.3750 -21.6958 -2.3965 0.6569 3.9080 -4.6195 2.2369 2.2659 -7.9013 13.7065 9.2331 -4.6859 48.0226 0.0000 0.0000 14.8888 5.8803 4.2201 1.1178 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.1627 11.0965 -14.6723 11.5961 35.1478 -72.8208 -0.0000 0.0000 7.1494 2.0880 -1.1417 -5.0613 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -13.1100 8.9385 -8.8279 12.6606 0.0000 0.0000 17.6480 -3.9480 20.4292 -2.0777 0.0000 -0.0000 -13.0065 -16.3848 14.0390 26.0098 0.0000 0.0000 -13.4239 -1.5865 -13.2711 -7.0121 0.0000 -0.0000 -1.6230 -33.1087 24.9569 6.3839 13.6440 -31.2910 1.5736 -0.6775 0.0433 -0.0509 -1.9214 0.0976 12.5116 -1.7306 8.4141 -4.0094 -1.7896 2.9214 -21.0690 -2.1168 1.2311 4.3200 -4.4807 2.7535 1.5128 -7.0155 13.1910 7.8024 -2.2039 47.5696 0.0000 0.0000 16.2236 7.2391 5.7176 1.4698 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0989 9.9271 -14.4093 11.6592 37.9371 -72.6834 -0.0000 0.0000 7.5150 1.4258 -1.9783 -4.3296 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -16.0882 9.4751 -9.2989 11.5701 0.0000 0.0000 18.5568 -5.0608 15.4748 -1.7978 0.0000 -0.0000 -10.6012 -15.8841 15.0763 26.0243 0.0000 0.0000 -15.0662 -1.3397 -15.1944 -7.0702 0.0000 -0.0000 -1.6849 -33.7249 24.9536 5.2994 13.3707 -29.4609 1.5107 -0.1124 -0.1204 -0.0981 -1.8036 0.0266 12.6851 -1.4182 7.0462 -3.6088 -1.4638 2.3911 -20.3466 -2.2090 1.5666 4.7346 -4.3940 2.9744 0.9565 -6.2895 12.6958 6.0804 -1.1536 47.4308 0.0000 0.0000 17.2292 7.8174 6.7022 1.9051 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.1415 8.8468 -13.8707 11.8102 39.4267 -72.4654 -0.0000 0.0000 7.6167 1.3444 -2.2653 -3.6780 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -20.0101 10.8145 -9.6766 12.6674 0.0000 0.0000 15.2843 -4.1954 11.9260 -1.3013 0.0000 -0.0000 -8.4216 -14.5198 15.6500 25.4532 0.0000 0.0000 -15.7534 -1.0546 -16.9206 -6.9340 0.0000 -0.0000 -1.7800 -34.3147 24.9743 4.2228 12.8574 -27.1840 1.4492 0.5302 -0.3325 -0.1205 -1.5329 -0.0034 12.6678 -1.0082 5.7985 -3.2407 -1.1919 1.9036 -19.5385 -2.1542 1.7341 4.8655 -4.0498 2.9767 0.5663 -5.8402 12.0662 4.3682 -0.5807 47.3409 0.0000 0.0000 18.1788 8.5521 7.5887 2.1533 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.3451 7.8990 -13.4234 11.8957 40.3835 -72.1714 -0.0000 0.0000 7.4160 1.3861 -2.7420 -3.3271 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -23.9007 12.1417 -10.8326 14.1406 0.0000 0.0000 13.3029 -2.1523 9.7904 -0.7029 0.0000 -0.0000 -6.4730 -13.2729 16.2475 24.8263 0.0000 0.0000 -15.8106 -0.4542 -19.1311 -6.7362 0.0000 -0.0000 -1.9173 -34.9190 25.0189 3.3400 13.0797 -24.3208 1.3510 0.3944 -0.4923 -0.1175 -1.3651 -0.0539 12.8693 -0.8387 4.5421 -2.8651 -0.7785 1.4184 -18.8209 -1.3510 1.9270 4.8106 -3.3910 2.7289 0.1600 -5.4448 11.3183 2.7355 -0.3880 47.2087 0.0000 0.0000 19.2293 9.2929 8.2726 2.1277 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.5951 6.9603 -13.1682 12.1092 40.9714 -72.0671 -0.0000 0.0000 7.2889 1.4810 -3.4338 -3.2536 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -26.4891 12.3986 -12.5188 14.3604 0.0000 0.0000 14.5157 -0.7567 7.6928 -0.6766 0.0000 -0.0000 -4.4382 -13.1216 16.8185 24.2712 0.0000 0.0000 -15.8544 0.2620 -22.0334 -6.9268 0.0000 -0.0000 -2.0824 -35.5516 25.0600 2.4190 13.8683 -21.0520 1.3687 -0.3071 -0.5982 -0.0935 -1.3807 -0.1431 13.2549 -0.9084 3.2472 -2.5536 -0.1467 0.8785 -18.3612 0.2765 2.3443 4.9627 -2.4315 2.2313 -0.2534 -5.1593 10.8157 1.1150 -0.5087 46.8852 0.0000 0.0000 20.2974 9.7774 8.8237 2.2322 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.8302 6.0183 -12.8047 12.5799 40.9495 -72.3473 -0.0000 0.0000 7.4438 1.6925 -3.9578 -3.1872 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -27.7534 11.7241 -13.6993 13.4086 0.0000 0.0000 16.3113 0.0033 5.4512 -1.2629 0.0000 -0.0000 -2.1802 -13.6856 16.8804 23.7409 0.0000 0.0000 -15.9591 0.9402 -24.9867 -7.7829 0.0000 -0.0000 -2.2448 -36.1644 25.0653 1.5535 14.0631 -17.9051 1.4316 -0.6269 -0.7637 -0.0020 -1.4981 -0.2336 13.4092 -0.9215 2.2295 -2.3824 0.6224 0.3424 -18.1778 2.4589 3.0562 5.4267 -1.2682 1.5725 -0.5506 -5.0802 10.7993 -0.4909 -0.7485 46.1654 0.0000 0.0000 21.4500 10.2815 9.6413 2.6464 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 1.0979 5.1162 -12.1881 13.1654 40.3332 -72.9406 -0.0000 0.0000 7.7171 1.7467 -4.2986 -2.9844 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -29.1943 11.1235 -13.8809 12.5604 0.0000 0.0000 16.4081 0.3820 4.4313 -1.7441 0.0000 -0.0000 -0.4482 -13.8420 16.2012 23.5248 0.0000 0.0000 -15.7992 1.7467 -27.2077 -9.0469 0.0000 -0.0000 -2.3878 -36.7479 25.0299 0.6913 13.3915 -15.1072 1.6898 -0.4289 -0.9787 0.1867 -1.6256 -0.2947 13.2118 -0.6574 1.6951 -2.2992 1.4493 -0.1065 -18.0779 4.9079 3.9539 5.8993 -0.1056 0.9521 -0.7610 -5.0133 11.0517 -1.8854 -1.0533 45.0446 0.0000 0.0000 22.9702 10.9312 10.5622 2.9660 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 1.3098 4.3052 -11.4919 13.8256 39.4484 -73.7367 -0.0000 0.0000 7.9230 1.4192 -4.5149 -2.7899 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -30.9250 10.8680 -13.8838 12.0021 0.0000 0.0000 15.5923 0.0500 5.5076 -1.7497 0.0000 -0.0000 0.9390 -13.1046 14.8755 23.4255 0.0000 0.0000 -15.5533 2.3851 -28.3280 -10.3073 0.0000 -0.0000 -2.5150 -37.3537 24.9636 -0.2039 12.4845 -12.4562 2.0325 -0.3244 -1.1073 0.3846 -1.7153 -0.3286 13.0659 -0.2147 1.4413 -2.2125 2.2510 -0.4795 -17.8888 7.3224 4.8793 6.1650 1.0452 0.5706 -0.9610 -4.8482 11.2595 -2.8450 -1.2259 43.7986 0.0000 0.0000 24.6427 11.4223 11.0143 2.9849 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 1.2803 3.7670 -10.8711 14.5460 38.7344 -74.5986 -0.0000 0.0000 8.0819 1.1337 -4.5400 -2.7981 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -32.1420 10.3296 -14.0027 11.1188 0.0000 0.0000 15.3979 -0.4685 7.1810 -1.7939 0.0000 -0.0000 2.6840 -11.9447 13.1101 22.8977 0.0000 0.0000 -15.9829 2.1620 -28.6268 -11.2489 0.0000 -0.0000 -2.6422 -38.0236 24.8836 -1.0969 11.8670 -9.7338 2.2608 -0.5667 -1.1181 0.5136 -1.8047 -0.3621 13.3232 0.1445 1.2221 -2.0910 2.8979 -0.7889 -17.6721 9.4337 5.7618 6.3109 2.3863 0.4380 -1.0489 -4.7247 11.3916 -3.3926 -1.0516 42.7151 0.0000 0.0000 25.6991 11.6152 11.2631 3.1145 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 1.1708 3.6378 -10.3165 15.0743 38.4500 -75.3829 -0.0000 0.0000 8.2826 1.3824 -4.6853 -3.0065 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -32.6879 9.0709 -13.8229 10.1048 0.0000 0.0000 15.6854 -0.7146 7.3604 -1.8855 0.0000 -0.0000 4.9381 -11.1550 11.3212 21.9827 0.0000 0.0000 -16.9455 1.4240 -28.9926 -11.7734 0.0000 -0.0000 -2.7711 -38.7424 24.8037 -1.7929 11.3013 -6.8560 2.2980 -0.7267 -1.1488 0.5663 -1.8926 -0.4037 13.8070 0.2309 0.9782 -1.9265 3.3277 -1.0132 -17.5249 11.1082 6.5132 6.4655 3.8571 0.2935 -0.9470 -4.6912 11.5125 -3.6605 -0.8806 41.8233 0.0000 0.0000 25.8315 11.6379 12.0473 3.6070 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 1.3461 3.6923 -9.8545 15.3819 38.2760 -76.1444 -0.0000 0.0000 8.5165 1.8825 -5.2381 -3.2370 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -33.0713 7.4723 -13.8691 9.4976 0.0000 0.0000 15.9047 -1.3467 6.6139 -1.5423 0.0000 -0.0000 6.9252 -10.8966 9.8858 21.4184 0.0000 0.0000 -17.3712 1.3263 -30.1516 -12.2136 0.0000 -0.0000 -2.8870 -39.4806 24.7140 -2.0112 10.4770 -3.6851 2.1745 -0.7035 -1.2178 0.5321 -1.8742 -0.4304 14.1056 0.1399 0.6146 -1.7342 3.5462 -1.1765 -17.3653 12.3827 6.8208 6.6719 5.0027 -0.0798 -0.8199 -4.6718 11.5053 -3.5473 -1.1322 41.0114 0.0000 0.0000 25.4510 11.3219 12.9474 4.1416 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 1.6643 3.6343 -9.6655 15.9555 37.6755 -76.9458 -0.0000 0.0000 8.7003 2.1687 -5.5763 -3.3083 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -33.3797 5.9621 -14.8481 8.8863 0.0000 0.0000 16.3174 -2.4776 7.1148 -1.1683 0.0000 -0.0000 7.9589 -10.8730 8.6792 21.6090 0.0000 0.0000 -17.3029 1.6749 -32.0210 -13.0946 0.0000 -0.0000 -2.9785 -40.2408 24.5859 -1.6585 9.5660 -0.2672 1.9248 -0.9210 -1.2311 0.3891 -1.7024 -0.4329 14.1475 0.0504 0.1376 -1.5807 3.6434 -1.3401 -17.2084 13.2156 6.5612 6.8888 5.6777 -0.6119 -0.8977 -4.6868 11.3905 -2.8484 -1.5445 40.1324 0.0000 0.0000 24.8904 10.5036 12.8127 4.3464 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 1.7188 3.4605 -9.7417 16.9767 36.7453 -77.6968 -0.0000 0.0000 8.8498 2.2924 -5.0772 -3.2329 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -33.7002 4.4515 -15.4300 8.0959 0.0000 0.0000 16.6443 -3.2008 8.4493 -1.3694 0.0000 -0.0000 8.2731 -10.8883 7.1938 22.1521 0.0000 0.0000 -17.9927 1.3894 -33.8096 -14.3742 0.0000 -0.0000 -3.0438 -41.0611 24.4134 -1.1617 8.7183 3.0192 1.6496 -1.2674 -1.2552 0.2706 -1.5795 -0.4330 14.2287 -0.0487 -0.2365 -1.4810 3.6073 -1.4140 -17.3286 13.5322 6.1614 6.8846 6.1597 -1.0587 -1.0132 -4.7168 11.4211 -1.8075 -1.5725 39.1785 0.0000 0.0000 24.0088 9.6832 11.8153 4.2400 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.6447 3.2048 -9.9367 17.8314 36.3759 -78.1838 -0.0000 0.0000 8.9398 2.4931 -4.4633 -3.1462 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -34.2955 2.8849 -14.5040 8.4589 0.0000 0.0000 14.9439 -3.4002 8.5424 -1.6267 0.0000 -0.0000 8.8046 -10.7844 5.0700 22.5028 0.0000 0.0000 -19.2979 0.7514 -34.7551 -15.2859 0.0000 -0.0000 -3.0633 -41.9904 24.2018 -1.0200 7.3296 6.2283 1.5199 -0.9080 -1.4069 0.2347 -1.4563 -0.4476 14.5078 -0.4541 -0.5822 -1.3317 3.3442 -1.3770 -17.7690 13.2602 5.9528 6.4724 6.4322 -1.2335 -0.8757 -4.6151 11.5490 -0.8825 -1.5759 38.4058 0.0000 0.0000 22.7970 9.4731 11.2158 4.0979 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 2.0597 2.7198 -10.3069 17.9182 36.6251 -78.2664 -0.0000 0.0000 8.8966 2.5415 -4.2701 -3.1101 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -34.4976 1.9256 -13.7488 10.6456 0.0000 0.0000 10.8025 -3.7616 8.1836 -1.5348 0.0000 -0.0000 10.2875 -9.9781 1.9381 22.3741 0.0000 0.0000 -19.7578 0.4812 -34.5741 -15.6978 0.0000 -0.0000 -3.0128 -43.0372 23.9175 -0.6164 5.0992 10.0620 1.1393 -0.0051 -1.5609 0.0297 -0.9788 -0.4366 14.7600 -1.0863 -1.5677 -1.1519 2.8975 -1.4206 -18.2402 12.4093 5.5496 5.9625 6.0503 -1.1084 -0.6206 -4.6377 11.2934 -0.0070 -2.1258 38.2410 0.0000 0.0000 21.4648 9.2544 10.9106 4.0538 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 2.6624 2.1189 -11.2352 17.4595 36.6176 -77.2447 -0.0000 0.0000 8.6397 2.4392 -3.5373 -3.0546 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -33.5576 2.1388 -13.5810 12.9798 0.0000 0.0000 7.4827 -4.4850 9.0774 -1.8223 0.0000 -0.0000 12.0513 -8.5402 -1.7997 21.9649 0.0000 0.0000 -20.0536 -0.0939 -34.4136 -16.8466 0.0000 -0.0000 -2.9105 -44.1445 23.5423 1.0074 3.1443 14.3440 0.0112 -0.0494 -1.4200 -0.6482 -0.2321 -0.3966 14.8314 -1.4430 -3.3270 -1.2054 2.6175 -1.7451 -18.9897 11.3165 4.8636 5.7782 4.9942 -0.8296 -0.8017 -5.3077 10.8891 1.2662 -2.8125 38.6590 0.0000 0.0000 19.9274 8.1151 9.2234 3.8645 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 2.6646 2.4484 -12.6063 16.3039 35.3309 -73.9457 -0.0000 0.0000 8.3977 2.7845 -1.7098 -2.8798 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -33.0133 2.6230 -10.2709 15.2894 0.0000 0.0000 7.2409 -4.4088 9.0318 -2.5300 0.0000 -0.0000 12.4090 -7.8387 -3.6887 22.5574 0.0000 0.0000 -21.7114 -1.1223 -36.8028 -19.5904 0.0000 -0.0000 -2.7971 -45.2638 23.1853 3.0014 2.3069 17.3120 -1.3121 -1.4159 -0.8556 -1.4936 0.0311 -0.4030 15.0104 -1.4288 -4.8525 -1.6391 2.7115 -2.2034 -20.6643 10.3913 4.7883 5.5096 3.8623 -0.4891 -1.4452 -6.4710 11.5148 2.7150 -2.8652 39.1096 0.0000 0.0000 17.8972 6.6165 5.8866 3.1270 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 2.4519 4.4606 -13.5022 13.5139 32.1557 -68.3563 -0.0000 0.0000 8.4322 3.8333 -0.3495 -2.5252 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -34.7984 1.9981 -2.4921 20.8028 0.0000 0.0000 7.0151 -3.0787 5.9406 -1.9194 0.0000 -0.0000 10.5825 -8.5114 -1.7826 26.5281 0.0000 0.0000 -21.6290 -0.1062 -41.8873 -22.0942 0.0000 -0.0000 -2.6698 -46.3958 23.0188 3.0792 1.4810 18.4987 -1.0410 -2.2133 -0.3540 -1.5914 -0.6390 -0.5617 15.1827 -1.8640 -5.3807 -2.2462 2.7176 -2.4201 -22.6156 9.1346 5.6057 4.2380 2.8709 -0.0734 -1.7107 -6.9651 13.4511 3.5715 -2.9932 39.2880 0.0000 0.0000 15.6738 5.9771 2.9552 2.0889 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 3.0962 6.5419 -13.4052 9.4199 27.7380 -62.7276 -0.0000 0.0000 8.4367 4.6866 -0.9238 -1.9534 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -36.2870 1.0656 2.7765 29.4206 0.0000 0.0000 3.2272 -1.7064 3.6370 -0.2355 0.0000 -0.0000 7.7337 -9.8240 1.3829 34.9588 0.0000 0.0000 -12.6367 4.3573 -45.2391 -21.4899 0.0000 -0.0000 -2.5685 -47.4717 23.1226 1.3980 0.8433 20.0470 0.5112 -1.9808 -0.4797 -0.9356 -1.2265 -0.7136 14.9067 -3.3312 -5.3887 -2.6780 1.8037 -2.1990 -23.0929 6.3332 5.5211 2.1137 1.2381 0.3186 -1.0485 -6.4115 14.8465 3.7701 -4.3286 39.6661 0.0000 0.0000 13.8568 5.7059 1.7340 1.4796 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 4.1531 6.4081 -12.7489 6.0534 24.1144 -59.1999 -0.0000 0.0000 7.8156 4.4063 -1.8820 -1.5531 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -34.4392 1.2274 2.1366 35.1947 0.0000 0.0000 -2.3014 -1.5966 3.0516 0.5911 0.0000 0.0000 3.8991 -12.4168 2.9287 44.8879 0.0000 0.0000 4.4865 13.3016 -43.9219 -15.3743 0.0000 -0.0000 -2.5073 -48.4634 23.4635 -0.2851 0.5258 22.9918 1.7350 -1.5007 -0.6912 -0.3964 -0.9096 -0.6631 14.2193 -4.7141 -5.2290 -2.7550 -0.0742 -1.6080 -21.7542 1.4958 2.5474 0.6574 -1.6909 0.3125 -0.0036 -6.0726 13.5996 4.1892 -6.8224 40.8647 0.0000 0.0000 12.3661 4.3000 0.9091 1.4499 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 3.7464 4.3039 -12.6445 4.3052 22.3559 -57.1589 -0.0000 0.0000 6.5882 3.4466 -0.5618 -1.8135 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -29.2709 1.7917 -0.7811 34.7281 0.0000 0.0000 -5.7063 -2.0120 2.5191 0.1830 0.0000 0.0000 -0.7727 -15.7498 3.2058 52.5631 0.0000 0.0000 13.1034 21.8111 -38.5926 -10.1548 0.0000 -0.0000 -2.4145 -49.3675 23.9002 -0.7308 -0.0258 25.5854 1.9654 -1.0015 -0.6022 -0.2663 -0.1434 -0.4522 13.1611 -5.0399 -4.3875 -2.6455 -2.0835 -0.6530 -20.2017 -4.2616 -2.3197 0.7433 -5.2528 -0.4741 0.4519 -6.0768 10.6112 5.2399 -9.9678 42.6383 0.0000 0.0000 10.7187 2.2482 -1.1483 1.4496 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 1.1737 2.4389 -14.1744 2.7663 21.4159 -54.1398 -0.0000 0.0000 5.3903 3.0460 2.4396 -2.0201 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -23.2049 1.9922 -2.1536 29.8156 0.0000 0.0000 -5.8434 -1.4009 1.9073 -0.5376 0.0000 -0.0000 -5.8624 -17.9284 4.2292 56.6192 0.0000 0.0000 7.9901 22.4456 -30.8428 -10.1914 0.0000 -0.0000 -2.2756 -50.1693 24.2578 -0.3618 -0.2721 25.8338 1.6679 -1.0313 -0.3601 -0.2766 0.3270 -0.2309 11.9520 -4.7558 -2.5984 -2.5048 -3.5641 0.5359 -19.4904 -9.0931 -6.2923 1.6784 -8.0849 -1.7758 0.2617 -5.2549 8.6675 6.0943 -13.0379 44.3490 0.0000 0.0000 9.2385 1.3532 -3.5685 1.1263 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -2.0195 1.6611 -16.3840 0.6463 18.7183 -49.4974 -0.0000 0.0000 4.4385 3.5804 3.8384 -1.5623 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -18.5497 1.5406 -1.6578 24.5578 0.0000 0.0000 -5.0468 0.0933 1.7165 -0.8272 0.0000 -0.0000 -10.2163 -19.4670 6.7108 56.8022 0.0000 0.0000 -0.0186 17.5108 -26.2075 -11.0925 0.0000 -0.0000 -2.1227 -50.8964 24.4559 -0.4250 -0.3921 24.1574 1.8731 -1.4411 -0.1372 -0.0847 0.3494 -0.0896 11.0937 -4.5535 -0.3486 -2.4462 -4.3978 1.6106 -19.3006 -11.9947 -8.3376 2.3743 -9.7364 -3.0504 0.3141 -4.0737 8.3957 5.7859 -14.5087 45.9626 0.0000 0.0000 9.0383 1.3969 -4.1901 0.8039 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -4.3861 0.8673 -17.7736 -0.8729 12.9584 -44.6327 -0.0000 0.0000 3.2141 4.0322 2.6158 -1.2568 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -15.1474 0.9170 -1.5281 21.5566 0.0000 0.0000 -5.6192 1.7342 2.9131 -0.7487 0.0000 -0.0000 -13.3938 -20.9029 8.1794 54.2973 0.0000 0.0000 -2.9550 16.0131 -25.5270 -10.2717 0.0000 -0.0000 -1.9736 -51.6049 24.5158 -1.1956 -0.8047 22.3892 2.6855 -1.7289 -0.0081 0.3071 0.2170 -0.0134 10.7399 -4.4891 1.6390 -2.5296 -4.7330 2.3542 -19.0706 -13.1836 -9.3839 2.3909 -10.8386 -4.2097 1.2768 -3.9617 8.3646 4.0719 -13.8765 47.7007 0.0000 0.0000 10.6258 0.4755 -1.8644 0.6464 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.9345 -0.5718 -18.1828 -1.9890 6.6167 -40.2941 -0.0000 0.0000 1.6227 3.4784 0.2050 -1.5630 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -12.0433 0.3887 -1.5607 20.6016 0.0000 0.0000 -7.2326 3.2576 4.1773 -0.6290 0.0000 -0.0000 -15.8478 -21.6517 7.0326 49.9013 0.0000 0.0000 -1.9136 15.9004 -24.8758 -9.4824 0.0000 -0.0000 -1.8180 -52.3082 24.5241 -1.9271 -1.2209 21.1850 3.1611 -1.8521 0.0644 0.5297 0.0435 0.0304 10.7672 -4.4939 3.0571 -2.5638 -4.7409 2.8116 -18.5656 -13.4283 -10.1006 2.1287 -11.9017 -5.2664 2.6548 -4.9370 8.0441 1.5230 -13.1845 49.3574 0.0000 0.0000 13.4572 -1.6249 2.4522 0.7641 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -7.4255 -2.2252 -18.0248 -4.2445 3.0940 -36.9076 -0.0000 0.0000 0.3557 2.0828 -1.8029 -2.0961 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -9.3381 -0.1625 -0.3100 20.4361 0.0000 0.0000 -8.6728 4.4696 3.9750 -0.6344 0.0000 -0.0000 -18.1351 -21.4019 4.3159 43.5973 0.0000 0.0000 0.5595 10.3111 -21.9644 -9.6546 0.0000 -0.0000 -1.6428 -52.9951 24.5577 -2.1733 -1.3327 20.2019 2.7880 -1.8711 0.1185 0.4253 -0.1186 0.0480 10.9432 -4.6971 3.9045 -2.3406 -4.7095 3.1347 -17.6596 -13.4192 -10.3314 2.1157 -12.7551 -5.9731 3.2924 -5.6269 7.8347 -0.4535 -14.8313 50.7173 0.0000 0.0000 16.5097 -2.8926 5.9985 1.2937 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -9.0664 -3.8374 -17.5638 -6.9199 2.5821 -34.7562 -0.0000 -0.0000 -0.0838 0.8327 -2.3431 -2.3395 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -7.0793 -0.5347 0.9222 19.9834 0.0000 0.0000 -9.8120 4.8652 3.7132 -0.7535 0.0000 -0.0000 -20.3696 -20.6745 1.8949 35.6751 0.0000 0.0000 5.8236 0.8731 -17.6985 -10.0448 0.0000 -0.0000 -1.4365 -53.6855 24.6210 -2.4145 -1.5679 19.4904 2.1954 -1.6522 0.1459 0.2629 -0.0527 0.0736 10.9153 -5.0556 4.2153 -1.9615 -4.8526 3.4048 -16.3923 -13.5212 -10.1844 2.3537 -13.1803 -6.3702 2.8860 -5.2982 7.6371 -0.6869 -18.3582 52.0680 0.0000 0.0000 18.5479 -2.3069 6.8341 1.7601 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -10.4482 -5.4137 -17.2025 -7.7014 2.6460 -33.5886 -0.0000 0.0000 0.0194 0.6958 -1.4919 -2.3439 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.2760 -0.2350 0.1984 18.6375 0.0000 0.0000 -10.8586 4.5057 5.1773 -0.9332 0.0000 -0.0000 -22.3065 -19.7991 1.2123 27.6666 0.0000 0.0000 12.5121 -4.0893 -12.9779 -10.2612 0.0000 -0.0000 -1.1917 -54.3870 24.6764 -3.1626 -2.3081 19.1413 2.1045 -1.3227 0.1638 0.3255 0.1959 0.1091 10.5720 -5.1565 4.3536 -1.6811 -5.0013 3.5995 -15.1230 -13.7211 -10.1853 2.5431 -13.4262 -6.8656 2.2705 -4.3871 7.1705 0.6186 -21.1326 53.9664 0.0000 0.0000 18.7024 -1.1941 5.8038 1.7548 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -11.3760 -6.7168 -17.2033 -6.5297 1.9568 -33.3701 -0.0000 0.0000 0.1553 1.2357 -0.1731 -2.5203 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.6282 0.6153 -1.6831 17.0617 0.0000 0.0000 -11.5559 4.0463 7.6288 -1.1676 0.0000 -0.0000 -23.9834 -18.5432 2.8797 21.6447 0.0000 0.0000 14.6737 -2.0099 -9.1952 -10.2469 0.0000 -0.0000 -0.9163 -55.0636 24.7122 -4.3596 -3.0641 18.5878 2.4402 -1.4354 0.2065 0.5427 0.2651 0.1160 10.2934 -4.7778 4.7880 -1.5356 -4.8742 3.7144 -14.1761 -13.7525 -10.4099 2.5681 -13.7993 -7.5498 2.0673 -3.1631 6.7394 2.4812 -21.9850 56.2344 0.0000 0.0000 17.4695 -1.0561 4.8748 1.4847 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -11.9279 -7.4313 -17.2630 -5.8641 1.5296 -33.8991 -0.0000 0.0000 0.1804 1.2945 0.4828 -2.8663 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 2.7988 1.2794 -2.3809 16.5406 0.0000 0.0000 -11.8844 3.8494 9.1178 -1.5276 0.0000 -0.0000 -25.5274 -17.0858 5.2294 17.6223 0.0000 0.0000 11.9938 2.5034 -8.4463 -9.7877 0.0000 -0.0000 -0.6310 -55.6889 24.7521 -5.5461 -3.6444 17.4784 2.8007 -1.7568 0.2389 0.7075 0.1546 0.1231 10.3724 -4.2317 5.4477 -1.3975 -4.5528 3.7485 -13.5535 -13.6103 -10.4987 2.4971 -14.2091 -8.1285 2.0691 -1.8417 6.7473 4.1743 -21.7911 58.1407 0.0000 0.0000 16.2240 -1.6955 4.6895 1.3010 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -12.2292 -7.6307 -17.0575 -6.6403 2.3069 -34.6809 -0.0000 0.0000 0.1725 0.5795 0.2850 -3.1869 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 5.3164 1.7489 -1.3463 17.2133 0.0000 0.0000 -12.1362 3.7292 9.0801 -2.1695 0.0000 -0.0000 -27.0697 -15.4548 5.2863 14.1867 0.0000 0.0000 10.4823 5.2058 -10.2818 -9.6143 0.0000 -0.0000 -0.3410 -56.3015 24.7941 -6.4971 -4.4837 16.1253 3.0617 -1.6325 0.3139 0.8440 0.1596 0.1347 10.5642 -3.7075 5.9075 -1.2266 -4.3194 3.7461 -13.0694 -13.5299 -10.4315 2.4233 -14.5124 -8.4785 1.9342 -0.7006 6.8474 5.4933 -21.9528 59.5125 0.0000 0.0000 15.7811 -1.9979 4.7200 1.2885 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -12.3491 -7.7825 -16.8151 -7.2663 3.5783 -35.3479 -0.0000 0.0000 0.1358 0.1690 0.0343 -3.4267 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 7.5968 2.4559 0.4603 17.9778 0.0000 0.0000 -12.4872 3.8219 8.0252 -3.0546 0.0000 -0.0000 -28.4708 -13.3623 2.5333 11.0326 0.0000 0.0000 11.3590 5.0578 -12.3507 -9.8295 0.0000 -0.0000 -0.0456 -56.9390 24.8018 -7.3828 -5.4794 14.7632 3.3221 -1.2522 0.4395 1.0030 0.3167 0.1622 10.6752 -3.1743 6.1261 -1.0568 -4.1386 3.7173 -12.6842 -13.5217 -10.4203 2.3366 -14.8152 -8.7154 1.7419 0.3258 6.6494 6.3558 -22.8474 60.6408 0.0000 0.0000 15.9585 -1.7907 4.5818 1.2898 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -12.3275 -8.0533 -16.7655 -6.7091 4.2944 -35.9666 -0.0000 0.0000 0.0970 0.7800 0.2996 -3.4801 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 10.2866 3.2055 2.6410 18.1373 0.0000 0.0000 -12.9258 4.5604 6.2797 -3.8075 0.0000 -0.0000 -29.6378 -11.1455 -0.7499 8.9511 0.0000 0.0000 11.6088 4.2413 -13.3694 -9.9559 0.0000 -0.0000 0.2506 -57.5719 24.7608 -8.2557 -6.1558 13.1749 3.5887 -1.0431 0.5319 1.1187 0.3032 0.1690 10.9403 -2.5737 6.3569 -0.9100 -3.7968 3.6321 -12.4998 -13.4218 -10.3604 2.1656 -15.2083 -8.8179 1.6364 1.2919 6.4714 6.6794 -23.5890 61.6261 0.0000 0.0000 16.2480 -1.6730 4.5032 1.2293 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -12.1979 -8.0190 -16.7023 -5.8249 4.3953 -36.5281 -0.0000 0.0000 0.0677 1.6628 0.6111 -3.4522 -0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 12.9386 3.8076 4.9593 18.1477 0.0000 0.0000 -13.5931 5.7001 4.5706 -4.1855 0.0000 -0.0000 -30.5703 -9.3799 -2.7362 7.8404 0.0000 0.0000 10.8157 5.1769 -13.3164 -10.4246 0.0000 -0.0000 0.5387 -58.1835 24.6922 -8.9501 -6.3855 11.3872 3.7414 -0.9880 0.5678 1.1723 0.1401 0.1554 11.3941 -2.0252 6.4907 -0.8157 -3.3709 3.4529 -12.4230 -13.3246 -10.0470 2.0307 -15.5892 -8.6597 1.4824 1.8912 6.6570 6.6992 -23.5952 62.3604 0.0000 0.0000 16.4784 -1.7733 4.7103 1.2290 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -11.9599 -7.4647 -16.4525 -5.4936 4.5671 -36.8917 -0.0000 0.0000 0.0215 1.9582 0.4226 -3.5131 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 15.0070 4.4220 6.6481 18.4533 0.0000 0.0000 -14.5811 6.6022 3.9298 -4.4249 0.0000 -0.0000 -31.3008 -8.1734 -3.4663 7.0617 0.0000 0.0000 10.6633 7.0919 -12.7903 -11.4841 0.0000 -0.0000 0.8159 -58.8118 24.6189 -9.1707 -6.4037 9.8549 3.6077 -0.7715 0.6110 1.1375 0.1188 0.1442 11.7062 -1.6835 6.2472 -0.7820 -3.1159 3.2144 -12.3192 -13.4765 -9.6474 2.2147 -15.8438 -8.2910 1.1710 2.0249 6.9188 6.7963 -23.6404 62.8101 0.0000 0.0000 16.8095 -1.7637 5.0341 1.3271 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -11.5798 -6.6946 -16.1340 -5.3878 5.2534 -37.2832 -0.0000 0.0000 0.0016 1.9929 0.0916 -3.5957 -0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 16.3718 5.1212 7.4023 19.0445 0.0000 0.0000 -15.4538 7.1241 4.3344 -4.8889 0.0000 -0.0000 -31.9000 -7.0592 -3.4237 6.6358 0.0000 0.0000 10.9422 7.7750 -12.3246 -12.2443 0.0000 -0.0000 1.0835 -59.4850 24.5370 -8.9037 -6.1121 8.7188 3.1718 -0.4841 0.6195 0.9333 0.1456 0.1294 11.7948 -1.4957 5.7503 -0.7355 -2.9870 2.9812 -12.3037 -13.8894 -9.4651 2.7531 -15.9989 -7.8766 0.8879 2.0691 6.9437 6.9588 -24.4201 63.0249 0.0000 0.0000 17.3003 -1.6808 5.2069 1.4105 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -11.0946 -6.0002 -15.9555 -4.8556 6.2445 -37.8877 -0.0000 0.0000 0.1175 2.2392 0.1798 -3.6580 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 17.2014 5.4847 7.9513 19.8177 0.0000 0.0000 -15.7147 7.5021 4.7475 -5.6721 0.0000 -0.0000 -32.1464 -5.9766 -3.0888 6.5583 0.0000 0.0000 10.4297 7.2562 -11.9935 -12.4248 0.0000 -0.0000 1.3471 -60.1993 24.4311 -8.4627 -5.3531 7.6980 2.5749 -0.3890 0.5141 0.5662 0.0381 0.1060 11.9848 -1.3677 5.2105 -0.6477 -2.7641 2.7335 -12.5087 -14.3753 -9.4675 3.3604 -16.1820 -7.4938 0.8002 1.9970 6.9333 7.0263 -24.8813 63.1485 0.0000 0.0000 17.6200 -1.8859 5.1477 1.4385 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -10.5432 -5.1838 -16.0192 -3.9331 6.9566 -38.3609 -0.0000 0.0000 0.3502 2.2081 0.4919 -3.9482 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 17.9539 5.3736 8.7277 20.4802 0.0000 0.0000 -15.5703 7.5432 4.7893 -6.8483 0.0000 -0.0000 -31.6455 -5.2122 -2.7984 6.3494 0.0000 0.0000 9.7831 7.2610 -11.5619 -13.1494 0.0000 -0.0000 1.6264 -60.9770 24.3023 -7.9548 -4.5822 6.7790 1.8296 -0.2301 0.4014 0.1608 -0.0268 0.0634 12.3013 -1.2924 4.4328 -0.6036 -2.5383 2.3767 -12.7505 -14.7743 -9.4108 3.9722 -16.4735 -7.1369 0.8347 1.3288 7.0505 7.2501 -24.0147 63.4404 0.0000 0.0000 17.4383 -2.3796 4.9997 1.4271 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.7704 -3.9653 -16.0528 -3.2387 7.6219 -38.5622 -0.0000 0.0000 0.5832 1.3953 0.2289 -4.4755 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 19.0959 5.4940 8.9444 20.5482 0.0000 0.0000 -15.4959 6.9501 5.3235 -8.4417 0.0000 -0.0000 -30.3703 -4.4013 -1.7971 6.2128 0.0000 0.0000 9.8154 7.9901 -10.9570 -14.3797 0.0000 -0.0000 1.9278 -61.8523 24.1424 -7.0320 -3.7043 5.9576 0.7273 -0.1002 0.3654 -0.3221 0.1105 0.0343 12.3767 -1.4770 3.3657 -0.6666 -2.4665 1.9708 -12.8842 -14.8490 -9.1630 4.8932 -16.7467 -6.7993 0.8354 0.4423 7.0762 7.8963 -23.4998 63.8679 0.0000 0.0000 17.1664 -2.7313 5.0447 1.2814 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -8.5168 -2.3141 -15.4648 -3.0902 9.2491 -38.9213 -0.0000 0.0000 0.5533 0.1456 -1.0114 -4.8590 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 20.1580 5.8295 8.3557 20.2252 0.0000 0.0000 -15.3350 6.1148 6.9191 -9.9028 0.0000 -0.0000 -28.6644 -3.6252 0.6750 7.0292 0.0000 0.0000 9.2501 8.3443 -10.6354 -14.1254 0.0000 -0.0000 2.2422 -62.8185 23.9190 -5.6839 -2.0732 4.3726 -0.7042 -0.3199 0.2104 -1.0233 -0.1380 -0.0292 12.3745 -1.9319 2.7371 -0.8186 -2.3028 1.7172 -13.2773 -14.5679 -8.7348 6.1044 -16.6983 -6.4030 0.8227 -0.2910 7.0358 8.4093 -24.9036 63.7516 0.0000 0.0000 17.8643 -2.6798 5.4271 1.0643 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -6.8488 0.1059 -13.9765 -2.5421 11.2328 -39.4294 -0.0000 -0.0000 -0.2310 -1.0096 -2.7839 -5.0751 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 20.5114 5.8846 7.9804 20.3027 0.0000 0.0000 -15.0147 5.5464 9.3275 -10.5652 0.0000 -0.0000 -26.0232 -3.8287 3.3533 8.0366 0.0000 0.0000 7.7439 8.1248 -10.6754 -12.1002 0.0000 -0.0000 2.6009 -63.8533 23.6485 -4.4493 -1.1371 1.3709 -2.1956 0.5993 -0.1474 -1.9938 -0.9359 -0.1466 13.3213 -2.5730 2.9185 -1.1119 -1.8465 1.6446 -14.4342 -14.6763 -8.2522 6.9707 -16.2653 -5.9662 0.8949 -2.7246 7.3323 8.0295 -25.3268 62.3176 0.0000 0.0000 19.9493 -2.5359 5.8008 1.1689 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.2748 4.5523 -12.0760 -0.1476 10.4776 -39.4489 -0.0000 -0.0000 -1.7513 -2.2317 -4.0594 -5.4112 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 20.6761 7.4654 7.4363 21.0115 0.0000 0.0000 -15.1981 4.6899 12.7752 -11.0521 0.0000 -0.0000 -21.6376 -3.5995 3.9436 6.9896 0.0000 0.0000 7.7639 7.6627 -9.5415 -10.4409 0.0000 -0.0000 3.0716 -65.0163 23.4467 -4.6248 -4.4854 -1.6684 -3.3513 5.5612 0.0032 -3.1192 -0.8142 -0.1328 15.7442 -3.3891 2.6968 -1.6624 -1.6177 1.4348 -15.9978 -16.2081 -8.1536 7.2172 -15.8363 -5.7991 0.8923 -8.3573 7.9550 7.6122 -22.0264 59.8056 0.0000 0.0000 22.2853 -2.7626 5.9984 1.6677 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -4.4479 11.0907 -10.5972 4.0330 6.7299 -38.4894 -0.0000 -0.0000 -2.8245 -3.4763 -4.3521 -5.4894 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 22.4489 13.9823 3.9160 22.1502 0.0000 0.0000 -15.1720 2.4815 17.8923 -13.2869 0.0000 -0.0000 -14.8755 1.2152 0.9763 2.1995 0.0000 0.0000 10.7196 7.1453 -5.2773 -9.8886 0.0000 -0.0000 3.6015 -66.2708 23.4074 -5.8493 -10.7947 -2.5771 -4.3216 11.3686 1.0828 -3.8833 2.0919 0.4153 17.7622 -3.3102 0.8804 -2.2639 -2.3743 0.8075 -16.9176 -19.1097 -9.0773 7.3521 -15.7341 -6.2783 0.6424 -14.1496 7.9426 9.0142 -18.9156 57.5725 0.0000 0.0000 22.7850 -3.3140 6.4722 1.8558 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -4.3594 16.3626 -9.9735 8.0955 5.9148 -37.6337 -0.0000 -0.0000 -1.9572 -3.6937 -3.4853 -4.5725 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 24.7219 22.6210 -1.7457 25.6665 0.0000 0.0000 -11.6915 0.0551 22.7038 -16.5553 0.0000 -0.0000 -7.7423 8.9250 -6.1382 -4.3656 0.0000 -0.0000 13.6804 7.2389 1.4207 -9.3654 0.0000 -0.0000 4.0897 -67.3386 23.5501 -6.1599 -14.6141 -1.0404 -4.5985 12.1126 1.4577 -3.7875 4.8860 1.0443 17.7633 0.4380 -1.4669 -2.5109 -3.1963 -0.0688 -17.7204 -22.0376 -11.2240 7.5930 -15.5405 -7.2897 0.5850 -16.6633 6.8657 11.8974 -19.4966 57.1314 0.0000 0.0000 19.9863 -3.9179 6.1902 0.9090 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -4.2043 18.0703 -10.3353 10.0411 11.0891 -38.4754 -0.0000 0.0000 1.0436 -2.0145 -0.7697 -3.3842 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 21.9934 26.9471 -2.8885 35.1482 0.0000 0.0000 -3.1514 -1.2840 23.1834 -15.1555 0.0000 -0.0000 -3.7757 13.6532 -14.5514 -6.7287 0.0000 -0.0000 12.1885 7.4379 7.8234 -8.7891 0.0000 -0.0000 4.4624 -68.0785 23.7450 -6.2160 -14.5764 -0.5197 -3.6602 9.6634 1.0452 -2.9971 3.8188 0.8050 16.3961 5.7028 -1.7762 -2.4464 -2.2426 -0.6374 -18.7384 -22.0587 -13.2125 7.5207 -14.8204 -8.2689 1.1834 -14.7055 6.2553 14.8558 -21.7578 58.6237 0.0000 0.0000 15.2614 -4.3383 2.1953 -0.8492 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -3.0896 17.4013 -11.6662 11.3500 17.8778 -40.6122 -0.0000 0.0000 3.9747 0.7252 3.9084 -3.5841 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 12.5736 26.4103 2.9506 49.3620 0.0000 0.0000 6.3896 -4.4582 19.0105 -8.5644 0.0000 -0.0000 -2.3911 14.8681 -15.6410 -4.7316 0.0000 -0.0000 8.5165 5.9878 8.3225 -8.6004 0.0000 -0.0000 4.6317 -68.6453 23.9023 -7.0758 -12.6046 -2.7027 -2.1456 7.8876 0.7514 -2.2113 1.5544 0.3489 15.5144 7.5576 -0.1767 -2.3894 -0.4865 -0.6123 -19.1537 -18.4397 -13.2181 6.6514 -13.2999 -8.8586 1.8681 -11.3328 6.8783 16.8771 -20.9021 60.2369 0.0000 0.0000 12.2905 -3.2259 -5.6440 -1.8091 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -1.3008 16.5783 -12.7906 15.1334 20.3858 -44.4028 -0.0000 0.0000 4.7338 2.3462 8.7136 -5.5921 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 1.6852 22.3178 10.6327 62.8132 0.0000 0.0000 8.5773 -7.7878 12.9488 -5.2986 0.0000 -0.0000 -1.4485 13.9360 -10.3629 -1.8612 0.0000 -0.0000 5.9872 3.1991 4.6696 -8.4714 0.0000 -0.0000 4.6311 -69.2264 24.0502 -8.4050 -10.6721 -5.4174 -0.9496 7.9387 0.7313 -1.7024 0.6761 0.1796 15.8049 6.5583 0.8586 -2.3656 0.1255 -0.3987 -18.7714 -13.7774 -11.4152 5.3480 -10.9676 -8.9354 2.2193 -10.8270 7.7156 16.8522 -17.1218 60.3637 0.0000 0.0000 12.6426 -0.1429 -12.4096 -0.8884 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.2168 16.2532 -12.7210 19.7385 18.8001 -48.8276 -0.0000 0.0000 4.0278 1.7315 10.4685 -7.8772 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.4713 17.0558 14.7605 71.7094 0.0000 0.0000 2.9419 -6.2479 6.6001 -4.6532 0.0000 -0.0000 0.4948 12.4729 -7.2957 -0.4808 0.0000 -0.0000 4.4374 0.6220 3.7806 -8.1076 0.0000 -0.0000 4.6062 -69.7990 24.1687 -9.0014 -9.5066 -6.5560 -0.7511 8.9527 0.7916 -1.6037 1.4667 0.2406 16.6101 3.9666 0.3101 -2.2344 -0.2031 -0.4610 -18.0083 -9.3013 -8.7121 4.2898 -8.5217 -8.4021 1.9963 -12.2107 8.3491 14.7407 -16.5794 59.1745 0.0000 0.0000 15.1302 1.4026 -14.1251 -0.2419 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.8401 16.1752 -11.8569 21.5552 17.9107 -52.1408 -0.0000 0.0000 3.5987 -0.0630 9.2131 -8.4857 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -12.7498 12.9347 14.7286 74.9822 0.0000 0.0000 -2.6017 -1.9136 1.4042 -4.6779 0.0000 -0.0000 2.6131 11.5401 -8.1834 -0.4408 0.0000 -0.0000 2.9568 -0.7708 5.7830 -7.6791 0.0000 -0.0000 4.6469 -70.3669 24.2376 -9.8000 -8.5143 -6.8882 -0.5569 9.2556 0.8504 -1.3787 2.2731 0.2792 17.2842 1.7398 -0.7452 -1.9875 -0.1549 -0.7374 -17.2824 -4.9264 -5.9583 3.6773 -6.3472 -7.4336 1.3180 -12.8418 8.8328 11.7352 -20.6771 57.3741 0.0000 0.0000 18.3287 -0.6491 -11.2314 -0.5731 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.8098 15.6100 -11.2273 20.9048 18.7315 -54.4224 -0.0000 0.0000 3.4460 -1.1654 6.5904 -7.9652 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -17.4498 10.0946 12.9716 73.5436 0.0000 0.0000 -3.8827 -0.2792 -2.9105 -4.6842 0.0000 -0.0000 5.6895 10.8516 -10.5462 -1.4459 0.0000 -0.0000 1.7496 -1.6585 8.3061 -7.3384 0.0000 -0.0000 4.7274 -70.9937 24.2840 -11.5599 -7.2061 -7.8634 0.1976 8.2841 0.9547 -0.9190 1.9707 0.1475 17.9945 1.3197 -1.0994 -1.7719 0.7292 -0.9911 -16.7920 -0.8315 -3.6188 3.4688 -4.2361 -6.3451 0.9482 -13.2601 9.1464 8.8584 -23.7329 55.5821 0.0000 0.0000 21.5374 -2.4970 -6.5194 -0.0756 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.7023 14.6219 -10.9664 19.7591 18.1800 -56.2471 -0.0000 0.0000 2.5462 -1.1533 3.3840 -7.7677 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -19.9246 7.9323 10.9960 68.0412 0.0000 0.0000 -3.7136 -1.1953 -7.0228 -3.9605 0.0000 -0.0000 9.9624 10.1213 -12.0554 -2.9080 0.0000 -0.0000 1.1466 -2.8404 10.2020 -7.0629 0.0000 -0.0000 4.8209 -71.6121 24.3051 -12.5092 -6.4603 -9.5043 0.3132 7.0995 1.1380 -0.8382 1.4378 0.0539 18.7137 2.0002 -0.8168 -1.5923 1.7740 -1.1512 -16.5208 2.6847 -1.6314 3.6642 -2.0053 -5.3198 0.9934 -14.3509 9.2750 6.6639 -23.4452 54.2573 0.0000 0.0000 24.6878 -0.6070 -1.8064 0.5878 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.6512 14.0728 -10.5371 18.4146 15.7814 -57.6571 -0.0000 0.0000 0.7412 -1.0817 -0.0538 -8.0017 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -21.9957 6.9123 8.9676 59.1784 0.0000 0.0000 -3.9774 -1.6378 -9.2491 -2.4314 0.0000 -0.0000 12.7728 10.1621 -12.1920 -3.6827 0.0000 -0.0000 0.4142 -4.1523 11.5074 -6.8011 0.0000 -0.0000 4.9385 -72.1037 24.2670 -11.4436 -7.1545 -11.2703 -0.8209 6.6364 1.3388 -1.4199 1.3771 0.1213 18.9770 2.9975 -0.3121 -1.3705 2.4116 -1.2279 -16.4056 5.4901 0.0425 4.0875 0.0754 -4.3674 0.8988 -15.2952 9.2787 4.9576 -22.8570 53.0395 0.0000 0.0000 27.5313 3.0833 1.4226 0.6074 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 0.4582 14.1072 -9.9152 16.2494 14.1092 -58.5453 -0.0000 -0.0000 -1.2683 -1.6286 -2.7082 -8.1087 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -25.6249 7.3482 6.8131 48.6154 0.0000 0.0000 -2.8760 -1.3292 -7.1380 -1.2931 0.0000 -0.0000 12.4995 11.5935 -11.0388 -3.2632 0.0000 -0.0000 -1.0424 -5.2000 11.9081 -6.5407 0.0000 -0.0000 5.0380 -72.5246 24.1948 -9.4599 -8.4029 -12.9606 -2.3194 6.6095 1.5523 -2.2176 1.4474 0.2568 18.7388 4.0587 0.3854 -1.1465 2.7007 -1.2015 -16.3080 7.5826 1.3017 4.4396 1.5747 -3.4929 0.4625 -15.4636 9.1817 3.4448 -23.6426 51.7288 0.0000 0.0000 29.4810 4.6444 1.7272 0.4790 -0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0700 14.2001 -9.4988 13.7634 13.8444 -59.2154 -0.0000 -0.0000 -2.8304 -2.2371 -3.8828 -7.8289 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -29.6965 7.8754 4.4131 37.4446 0.0000 0.0000 0.4959 -1.2355 -0.4203 -1.0787 0.0000 -0.0000 10.7303 13.3895 -8.3169 -2.2087 0.0000 -0.0000 -2.8588 -5.8843 10.8325 -6.2834 0.0000 -0.0000 5.0213 -73.0695 24.1607 -8.4388 -8.4663 -14.3139 -3.1343 6.4778 1.7971 -2.6193 1.2514 0.3036 18.6391 4.6145 1.0966 -0.9900 2.7978 -1.0648 -16.0806 9.0723 2.2018 4.7449 2.4318 -2.6909 -0.0425 -15.4590 9.0268 2.2042 -24.3142 50.5189 0.0000 0.0000 30.4282 4.1507 -0.1338 0.2225 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.2830 14.1956 -9.3023 11.9221 13.4880 -60.0954 -0.0000 -0.0000 -3.8672 -1.6936 -4.3455 -7.1063 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -31.0006 6.9682 1.5815 25.5219 0.0000 0.0000 5.0804 -1.8754 8.8256 -1.3013 0.0000 -0.0000 10.5724 13.8165 -5.4904 -1.5549 0.0000 -0.0000 -4.6217 -6.1622 9.2606 -6.0945 0.0000 -0.0000 4.8694 -73.7638 24.1700 -8.8545 -6.9626 -14.6362 -3.1190 6.3975 1.9966 -2.5527 0.9435 0.2485 19.0577 3.9251 1.3580 -0.8401 2.6754 -0.9113 -15.7574 10.2161 2.9750 5.2582 2.9695 -1.9447 -0.3946 -15.4806 8.8907 1.2379 -24.3284 49.3887 0.0000 0.0000 31.0244 4.5359 -2.1806 -0.3325 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.4123 14.1677 -9.0630 10.7924 13.0445 -61.2260 -0.0000 -0.0000 -4.9480 0.3126 -4.9708 -6.1778 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -29.1454 4.7532 -0.5138 14.1597 0.0000 0.0000 9.2610 -3.6028 16.3412 -1.6274 0.0000 -0.0000 13.1501 12.5175 -4.3051 -1.6273 0.0000 -0.0000 -6.4567 -5.8901 8.2206 -6.0122 0.0000 -0.0000 4.6982 -74.4337 24.1644 -9.3155 -5.3213 -13.7895 -3.0320 6.5729 2.1071 -2.4127 0.8213 0.1814 19.6589 2.4371 1.1375 -0.6722 2.4338 -0.8224 -15.6408 11.1347 3.6575 5.9187 3.4414 -1.3321 -0.5718 -15.3140 8.9083 -0.0159 -24.7564 47.8010 0.0000 0.0000 31.8328 6.2995 -3.1899 -0.6107 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.2873 14.1999 -8.8890 9.7099 13.3865 -62.1177 -0.0000 -0.0000 -6.6697 2.6182 -5.6429 -5.5149 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -27.8871 2.8015 -0.3538 6.4785 0.0000 0.0000 11.0586 -5.6775 18.6404 -1.9992 0.0000 -0.0000 15.9188 10.7877 -3.8831 -1.4203 0.0000 -0.0000 -8.5479 -5.2783 7.0060 -5.8373 0.0000 -0.0000 4.5905 -75.0640 24.1201 -9.1830 -4.5234 -12.6082 -2.8887 6.8261 2.0898 -2.2942 0.7535 0.1313 19.7247 1.3917 0.9635 -0.5578 2.2973 -0.7671 -15.6660 11.7577 4.0880 6.4606 3.8644 -0.9928 -0.5485 -15.0280 9.0627 -1.9959 -26.3836 45.3077 0.0000 0.0000 32.9665 7.3880 -3.0153 -0.3893 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0773 14.3135 -8.9334 8.6170 14.1743 -62.6534 -0.0000 -0.0000 -8.8656 3.9734 -6.0666 -5.3631 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -29.1213 2.0657 -0.5138 3.8759 0.0000 0.0000 10.2941 -6.6050 17.7928 -2.1749 0.0000 -0.0000 17.2274 9.7787 -2.5912 -0.2229 0.0000 -0.0000 -10.8321 -4.8203 4.6842 -5.3703 0.0000 -0.0000 4.5199 -75.7697 24.0428 -8.6252 -4.4777 -11.5323 -2.6676 7.0901 1.9104 -2.0807 0.5949 0.0958 18.9441 1.1337 1.1518 -0.4913 2.2978 -0.6909 -15.4040 12.0361 4.2130 6.9126 4.2346 -0.9469 -0.3474 -14.6340 9.0220 -4.5038 -29.5173 41.8000 0.0000 0.0000 34.8312 7.6283 -1.7205 -0.2353 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.6173 14.3313 -8.7710 8.1363 14.9880 -63.5636 -0.0000 -0.0000 -10.8817 4.8622 -6.7105 -5.2543 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -31.9250 2.2332 -2.4815 5.2753 0.0000 0.0000 9.0425 -6.0683 15.9565 -2.1041 0.0000 -0.0000 17.5312 9.4709 -0.7970 1.6057 0.0000 0.0000 -13.3034 -4.6655 1.9195 -4.7194 0.0000 -0.0000 4.4380 -76.5100 23.9396 -7.7332 -4.5470 -10.1910 -2.7170 7.0818 1.6968 -2.0259 0.5343 0.0972 18.2191 1.1757 1.4340 -0.4504 2.2452 -0.6134 -15.0914 12.1566 4.1576 7.4298 4.5287 -1.1211 -0.1737 -14.2353 8.7047 -7.5162 -33.7894 36.7673 -0.0000 0.0000 38.2589 8.6657 0.6211 -0.3080 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 1.0267 14.3707 -8.1375 8.5476 16.1980 -65.0701 -0.0000 -0.0000 -12.7017 6.3463 -7.9196 -4.8665 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -34.4447 2.8044 -4.9364 7.7936 0.0000 0.0000 9.0300 -4.5642 13.0236 -2.0538 0.0000 -0.0000 17.5947 9.0182 0.8264 3.5037 0.0000 0.0000 -15.9246 -4.2264 -0.8098 -4.0997 0.0000 -0.0000 4.3365 -77.2126 23.8110 -6.4093 -4.5352 -8.3728 -3.2788 6.7768 1.7056 -2.3158 0.5880 0.1332 18.2580 1.2285 1.5724 -0.4448 2.1014 -0.5644 -15.1989 12.3407 3.9938 7.9618 4.7111 -1.4586 -0.0087 -14.3871 8.4919 -11.3657 -37.6122 29.7341 -0.0000 0.0000 43.0894 10.2856 3.1074 0.2388 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 1.1074 14.7159 -7.5562 9.7793 17.7608 -66.3433 -0.0000 -0.0000 -14.7977 7.7625 -9.2084 -4.7883 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -35.8601 3.5933 -6.7918 9.2376 0.0000 0.0000 9.9742 -3.0571 9.7496 -1.8260 0.0000 -0.0000 17.4817 8.1229 2.3948 5.2586 0.0000 0.0000 -18.3539 -3.1099 -3.7763 -3.5980 0.0000 -0.0000 4.2229 -78.0108 23.6642 -4.8742 -4.5150 -6.4758 -4.0418 6.3755 1.8356 -2.6772 0.4975 0.1576 18.3957 1.4000 1.8234 -0.4537 2.0296 -0.4909 -15.4767 12.6069 3.7797 8.4577 4.8506 -1.8442 0.4183 -15.3877 8.5071 -15.4540 -39.8438 21.7366 -0.0000 0.0000 47.7264 10.8424 5.1796 1.6161 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 1.1427 15.3154 -7.2539 11.9434 18.7116 -67.0069 -0.0000 -0.0000 -16.9690 7.9110 -10.1210 -5.3173 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -36.0103 4.5209 -7.9268 9.6610 0.0000 0.0000 10.3070 -2.7725 7.4799 -1.3531 0.0000 -0.0000 17.6235 7.1212 3.4028 6.3096 0.0000 0.0000 -20.1890 -1.8072 -6.3244 -3.5697 0.0000 -0.0000 4.0930 -78.9849 23.4974 -3.2615 -4.4595 -4.8695 -4.8585 5.9161 1.8561 -2.9992 0.2433 0.1615 18.0721 1.7539 2.2872 -0.4293 2.0389 -0.3653 -15.7095 12.8290 3.6992 8.9355 5.0137 -2.0836 0.9595 -16.7362 8.3942 -18.3590 -41.3263 14.4480 -0.0000 0.0001 50.8140 10.6458 7.5770 2.8121 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 1.4837 15.8618 -6.7283 14.9273 18.5876 -67.3512 -0.0000 -0.0000 -18.7118 7.6849 -10.5970 -5.6337 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -34.8103 5.2945 -9.4445 9.9942 0.0000 0.0000 9.9343 -3.3883 6.7244 -1.1449 0.0000 -0.0000 18.3108 6.1760 3.6967 6.4520 0.0000 0.0000 -21.5129 -0.5767 -8.0009 -4.4244 0.0000 -0.0000 3.9313 -79.9680 23.3012 -1.1905 -4.2753 -3.4415 -6.1871 5.1027 2.0026 -3.7764 0.3260 0.2347 18.3249 2.1455 2.4981 -0.4418 1.9494 -0.3280 -16.6111 12.9611 3.8995 9.1642 5.0888 -2.1119 1.3334 -18.2862 8.1034 -19.1675 -42.4752 9.0848 -0.0000 0.0001 51.7596 10.7658 10.4148 3.4534 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 2.0722 16.6284 -5.9999 17.9213 17.2060 -66.9257 -0.0000 -0.0000 -19.8841 8.0594 -10.3095 -5.6924 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -32.3905 5.3399 -12.6454 9.4861 0.0000 0.0000 11.0789 -2.1032 6.9808 -1.4023 0.0000 -0.0000 18.4876 4.9788 4.2800 7.0144 0.0000 0.0000 -22.6435 1.0637 -9.6275 -5.6841 0.0000 -0.0000 3.6777 -80.9226 23.1292 1.0751 -2.7701 -2.0421 -7.9162 2.9279 2.3652 -5.2163 0.5205 0.3586 20.1766 2.8047 2.2222 -0.6494 1.6862 -0.4151 -18.5991 13.1166 4.2086 8.8126 5.0122 -2.0374 1.8880 -21.1834 8.0937 -16.8446 -41.4432 7.4153 -0.0000 0.0001 49.3067 9.7613 12.3620 4.5925 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 2.3683 18.6319 -5.9745 20.7490 13.5674 -64.6562 -0.0000 -0.0000 -19.6569 7.3699 -9.1256 -6.6582 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -28.2279 2.8947 -17.5140 5.5770 0.0000 0.0000 14.7988 3.0314 7.2762 -1.2729 0.0000 -0.0000 17.7419 2.0131 6.4003 9.2768 0.0000 0.0000 -23.6070 3.5146 -12.2254 -6.8596 0.0000 -0.0000 3.2747 -82.0616 23.0477 2.1914 1.5679 -1.2071 -8.8695 -0.7903 2.2723 -6.4108 -0.8143 0.0786 22.0391 3.7179 2.2631 -1.0857 1.6048 -0.4476 -20.3394 13.4659 4.5271 8.1264 5.1691 -1.8387 2.9433 -25.1359 8.5322 -9.8545 -37.7630 10.6957 -0.0000 0.0000 41.3187 5.1035 12.8628 6.0053 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 1.7834 21.5913 -6.7207 25.2888 8.4407 -61.1384 -0.0000 -0.0000 -15.9107 4.1276 -7.2612 -8.0290 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -21.8348 -3.8640 -19.8476 -2.3054 0.0000 -0.0000 19.1855 8.6677 5.4705 -0.5037 0.0000 -0.0000 17.7795 -4.2579 10.3294 12.8351 0.0000 0.0000 -23.9971 6.3121 -15.5975 -8.9376 0.0000 -0.0000 2.8293 -83.2794 23.0702 2.7534 7.4306 -1.9599 -8.8572 -4.2476 1.5487 -6.7102 -3.9123 -0.7242 21.6632 3.5143 3.3558 -1.5827 2.1499 -0.2231 -20.9367 14.5101 5.4828 7.7199 5.7303 -1.2498 3.7004 -27.0464 9.0070 1.9010 -34.3769 17.9645 0.0000 0.0000 28.0697 -2.2680 9.2246 4.2944 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.2318 23.8624 -7.2593 32.1287 6.1144 -58.3406 -0.0000 -0.0000 -7.9028 1.3067 -3.4055 -7.3887 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -16.9463 -11.6330 -13.9811 -7.3737 0.0000 -0.0000 20.7658 9.8167 -0.9473 0.1295 0.0000 0.0000 17.9978 -12.0460 15.5758 17.9794 0.0000 0.0000 -22.8926 8.2894 -19.0333 -13.1911 0.0000 -0.0000 2.4186 -84.2909 23.1973 3.3522 12.6405 -3.6159 -8.0721 -6.2222 0.8654 -6.0311 -5.9716 -1.1990 19.5553 0.5150 4.4305 -1.9083 2.7388 0.1258 -21.4376 15.8863 7.5132 7.5544 6.1526 -0.2512 3.8444 -24.8260 9.8211 13.1134 -35.2688 25.5725 0.0000 0.0000 15.3317 -5.9277 -2.3015 -2.0388 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.6089 23.3226 -7.7119 37.3084 9.7116 -57.7563 -0.0000 0.0000 1.2531 3.7637 3.2818 -4.6214 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -15.4721 -17.6564 -9.0802 -5.4700 0.0000 -0.0000 17.1858 9.0032 -4.9870 0.4999 0.0000 0.0000 16.2651 -19.5845 19.1674 26.8136 0.0000 0.0000 -18.8365 8.6514 -21.6265 -18.0862 0.0000 -0.0000 2.0842 -85.2116 23.3566 2.0365 15.2393 -2.7077 -6.0010 -6.5704 0.4879 -4.3822 -5.0615 -0.9435 17.0736 -3.0115 3.4722 -1.9445 2.3509 0.2025 -21.9004 15.5606 9.3057 6.6585 5.9998 0.6058 4.7052 -19.8386 10.9308 20.9673 -40.4654 32.5618 0.0000 0.0000 8.3664 -2.2592 -14.4749 -5.1931 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.8904 17.8495 -8.8914 39.8052 15.3701 -60.1193 -0.0000 0.0000 7.0658 9.9604 11.1874 -2.7492 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -13.4626 -20.5124 -10.5784 -1.4914 0.0000 -0.0000 12.0612 9.0923 -4.5081 0.7042 0.0000 0.0000 11.6022 -25.0950 15.4123 39.6836 0.0000 0.0000 -10.6931 7.6383 -21.8315 -18.2056 0.0000 -0.0000 1.8291 -86.1891 23.5023 -0.8675 15.7036 1.7828 -3.2941 -6.1986 0.1878 -2.9261 -3.3366 -0.6370 15.5112 -4.3683 1.2561 -1.8541 1.4728 -0.0656 -21.6693 13.5192 9.0972 4.7518 5.0461 0.6611 6.2410 -15.6995 11.1654 27.4767 -44.1202 38.9805 0.0000 0.0000 7.5412 2.8256 -22.6528 -1.9284 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 2.7827 10.7344 -10.4978 41.5520 16.7680 -63.0285 -0.0000 0.0000 7.6465 13.8229 18.8013 -3.5994 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -9.5180 -21.0332 -13.6577 -0.2950 0.0000 -0.0000 8.8306 10.0866 -4.6780 0.7949 0.0000 0.0000 2.9901 -27.6001 4.9730 54.0631 0.0000 0.0000 -0.9396 6.6877 -20.4900 -11.8485 0.0000 -0.0000 1.6385 -87.0543 23.6079 -2.9757 15.7326 6.3360 -1.3174 -6.3009 0.0631 -2.1042 -2.6500 -0.4946 14.7431 -4.0798 0.3926 -1.8617 0.9969 -0.1795 -20.6227 11.5682 7.0940 3.0699 3.7507 -0.3264 7.6834 -15.1402 10.5407 28.8578 -43.9598 39.9994 0.0000 0.0000 9.0278 2.1827 -26.3187 1.8086 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 3.3130 8.3895 -11.4198 40.5298 13.9117 -62.9232 -0.0000 0.0000 5.6674 11.9389 21.7213 -4.7537 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.9277 -21.5737 -14.7762 -1.1213 0.0000 -0.0000 6.9343 10.8038 -6.5975 0.8674 0.0000 0.0000 -7.6752 -27.3752 -5.5257 66.7721 0.0000 0.0000 3.8961 5.7407 -19.0580 -7.9700 0.0000 -0.0000 1.5230 -87.6832 23.6546 -3.3494 16.2398 7.6484 -0.7698 -7.2431 0.1781 -1.8086 -3.2905 -0.4542 14.4965 -2.6895 1.9861 -1.9987 1.1341 0.1859 -19.1648 10.3266 4.7266 2.9876 2.9281 -1.8874 7.9730 -16.5751 9.8157 25.9005 -41.7743 36.8658 0.0000 0.0000 9.5720 -3.3821 -25.0952 0.4935 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 2.5655 10.9224 -11.2366 36.4089 11.8357 -61.1119 -0.0000 0.0000 3.9436 6.2377 17.0824 -4.1601 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.9172 -22.5667 -13.6036 -1.3597 0.0000 -0.0000 5.0373 10.7058 -8.1877 0.9760 0.0000 0.0000 -17.3598 -26.1775 -11.0754 75.8881 0.0000 0.0000 1.7367 4.0753 -17.2050 -7.2907 0.0000 -0.0000 1.5185 -88.3266 23.6913 -3.6661 16.2002 6.2650 -0.5177 -8.2128 0.3612 -1.4936 -4.3843 -0.4387 14.6035 -0.7003 4.7655 -1.9736 1.5957 0.8345 -17.4532 9.5231 2.9443 4.5813 2.6938 -3.2283 7.2617 -16.9339 9.3425 23.0515 -38.8612 34.9547 0.0000 0.0000 9.4083 -4.1235 -18.9248 -1.6592 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 1.8618 13.1554 -10.3810 30.9391 12.9347 -60.7890 -0.0000 0.0000 2.5243 2.5188 7.2481 -5.0384 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -1.5646 -22.8034 -12.4387 -0.5063 0.0000 -0.0000 2.7538 10.3858 -7.2610 0.9256 0.0000 0.0000 -23.2720 -24.4173 -11.7150 79.9299 0.0000 0.0000 -2.5713 2.1625 -13.7494 -7.9727 0.0000 -0.0000 1.6253 -89.1584 23.7783 -5.3707 14.8040 4.7263 0.2854 -8.4768 0.4281 -0.9329 -4.7320 -0.3568 15.1307 0.8444 6.7200 -1.6288 1.9023 1.3149 -15.5847 9.1160 2.0155 6.7723 2.5164 -3.8661 6.2756 -15.7948 9.2079 21.3028 -35.4224 35.3772 0.0000 0.0000 9.8854 0.9510 -9.8805 -2.3228 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 1.8674 13.1325 -9.6002 26.2510 14.5073 -61.7864 -0.0000 0.0000 0.7424 0.1226 -2.2343 -6.9648 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 2.4905 -21.4054 -11.9331 0.4546 0.0000 0.0000 0.3356 10.1208 -5.1048 0.5512 0.0000 0.0000 -25.0551 -21.2147 -10.2978 78.6954 0.0000 0.0000 -4.7827 1.2357 -8.8608 -9.3098 0.0000 -0.0000 1.7808 -89.9432 23.8777 -7.2914 13.0184 3.9889 0.8672 -8.1734 0.2993 -0.5754 -4.5632 -0.2975 16.0078 1.5433 7.2638 -1.1367 1.9739 1.4263 -13.8036 9.0837 1.7599 8.6752 2.0790 -3.7641 5.1184 -14.8048 9.2514 18.1648 -31.9204 35.5194 0.0000 0.0000 11.6831 2.2239 -1.0185 -2.5557 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 1.4347 12.7884 -9.2304 23.1306 13.9945 -62.2707 -0.0000 -0.0000 -1.0551 -1.8454 -6.4542 -7.2468 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 6.3356 -19.2833 -11.1704 1.5574 0.0000 0.0000 -2.2083 9.5581 -4.1883 0.1190 0.0000 0.0000 -25.4872 -17.5159 -9.0417 73.2130 0.0000 0.0000 -5.9098 1.3560 -4.0229 -10.0795 0.0000 -0.0000 1.9128 -90.5372 23.9067 -7.6663 12.1354 3.5616 0.4736 -7.9223 0.0786 -0.7079 -4.5282 -0.3364 16.6138 1.5392 7.0099 -0.7474 2.0027 1.3025 -12.3024 9.2076 1.8752 10.1362 1.4977 -3.1585 3.6145 -14.2721 9.2407 12.8109 -29.9112 34.4326 0.0000 0.0000 15.1344 -2.2745 4.0976 -1.3962 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0099 12.9520 -9.0959 20.8325 12.6204 -61.8383 -0.0000 -0.0000 -2.4094 -1.3846 -3.9806 -5.5388 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 7.8042 -17.9122 -10.2617 3.4240 0.0000 0.0000 -4.9132 8.7153 -4.3884 -0.0354 0.0000 -0.0000 -27.0115 -15.4333 -7.9220 64.6040 0.0000 0.0000 -7.1562 1.3277 -0.8374 -9.2837 0.0000 -0.0000 1.9965 -91.1668 23.8613 -6.7615 12.2042 3.3633 -0.3832 -7.8439 -0.1140 -1.0687 -4.4998 -0.4188 16.3991 0.8937 6.3670 -0.4912 2.0074 1.1124 -11.1257 9.1922 2.1334 11.3246 1.0428 -2.3587 2.1416 -13.4357 9.1454 7.0000 -29.6526 33.2485 0.0000 0.0000 19.9005 -6.2442 5.6095 0.7308 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -1.5944 12.4525 -9.0377 18.6517 12.4347 -61.4284 -0.0000 -0.0000 -3.3432 0.4923 0.7740 -4.3607 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 7.7749 -17.5982 -10.1135 5.2295 0.0000 0.0000 -7.3592 7.9745 -4.2620 -0.1538 0.0000 -0.0000 -29.0269 -15.2964 -6.0882 53.3320 0.0000 0.0000 -7.2845 0.6276 -0.4657 -7.7958 0.0000 -0.0000 2.0618 -91.9382 23.7880 -5.6333 12.7096 3.6207 -1.3727 -7.9009 -0.3296 -1.4820 -4.2435 -0.4966 15.9653 -0.1048 5.4164 -0.2530 1.8862 0.9025 -10.3447 9.0631 2.3699 12.2933 0.8165 -1.6393 1.1033 -12.7014 9.2326 2.1816 -29.2450 32.6476 0.0000 0.0000 24.9252 -5.1599 5.8937 2.7526 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -2.6172 11.4849 -9.1677 16.5453 12.5587 -61.2671 -0.0000 -0.0000 -4.0464 1.5877 3.1316 -4.4664 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 8.1762 -17.9264 -10.5284 5.6844 0.0000 0.0000 -9.2145 7.4052 -3.7199 -0.6106 0.0000 -0.0000 -29.9685 -15.9637 -3.3227 39.7225 0.0000 0.0000 -4.9915 -0.1685 -3.7236 -6.7876 0.0000 -0.0000 2.1726 -92.6896 23.7019 -4.4090 13.1377 3.9212 -2.9138 -7.8380 -0.7782 -2.2753 -4.0767 -0.6110 16.5174 -1.0687 4.5179 0.0124 1.8038 0.6937 -10.1405 9.1934 2.6093 12.9511 0.6529 -1.1254 0.0726 -12.6671 9.6513 -1.0651 -27.4291 32.8992 0.0000 0.0000 28.9228 -0.8280 6.3631 3.7361 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -3.5428 11.8669 -9.4103 14.7115 11.3218 -60.7673 -0.0000 -0.0000 -4.6773 1.1958 2.9401 -4.6942 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 9.3743 -18.1731 -10.8553 4.8147 0.0000 0.0000 -10.7863 6.5952 -3.1117 -1.1101 0.0000 -0.0000 -29.7424 -16.1534 -0.0180 24.7672 0.0000 0.0000 0.6881 0.1756 -10.0152 -6.7808 0.0000 -0.0000 2.3752 -93.4449 23.5926 -3.0754 13.0359 3.5892 -4.8555 -7.6025 -1.3877 -3.3726 -4.0551 -0.7510 17.9370 -1.7467 4.0698 0.2214 2.0066 0.5103 -10.4116 9.6576 2.9413 13.4140 0.3543 -0.7619 -1.3796 -12.7129 10.2465 -2.6791 -25.3169 33.8439 0.0000 0.0000 31.4171 2.7917 6.8515 3.3653 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -4.7962 13.6473 -9.4283 13.0835 9.5766 -59.9921 -0.0000 -0.0000 -5.3780 0.2412 2.2164 -4.4782 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 11.1021 -17.5745 -10.9909 3.5552 0.0000 0.0000 -12.4889 5.2186 -2.1862 -1.1099 0.0000 -0.0000 -28.8920 -14.9737 -0.2089 10.6595 0.0000 0.0000 7.8560 2.7455 -12.9983 -7.8551 0.0000 -0.0000 2.6158 -94.4100 23.4662 -2.6632 12.1155 2.6834 -5.8426 -6.9852 -1.5644 -3.9231 -4.0568 -0.8384 18.7269 -1.8132 4.0037 0.2336 2.2729 0.3742 -10.6598 9.8894 3.1570 14.0198 -0.0052 -0.5146 -2.8863 -12.4961 10.7270 -3.3234 -24.1086 34.8974 0.0000 0.0000 32.6327 3.7867 6.5090 2.7067 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.9834 15.0137 -9.2124 11.6279 8.8752 -59.6604 -0.0000 -0.0000 -6.1099 -0.6731 1.7625 -4.3598 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 14.0796 -15.9171 -10.8269 2.4877 0.0000 0.0000 -14.2925 3.6656 -1.0317 -0.7373 0.0000 -0.0000 -27.4358 -13.6658 -7.1481 1.2500 0.0000 0.0000 8.9541 6.3351 -6.4810 -8.9662 0.0000 -0.0000 2.8315 -95.4686 23.3012 -2.5097 11.3518 1.4079 -6.0356 -6.6785 -1.5882 -3.9173 -4.0755 -0.8201 18.2412 -1.2639 4.3992 0.0129 2.3665 0.3690 -10.6651 9.8195 3.1567 14.7932 -0.2402 -0.4624 -3.9070 -12.3047 11.1014 -3.7926 -23.5318 35.6395 0.0000 0.0000 32.8457 3.2090 5.1936 2.4924 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.7759 15.6286 -8.9853 10.5881 8.9763 -59.8942 -0.0000 -0.0000 -6.8511 -1.2947 1.2749 -4.5109 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 16.8498 -14.2320 -9.8937 2.4432 0.0000 0.0000 -16.3392 2.7261 -0.5267 -0.3410 0.0000 -0.0000 -27.6723 -13.2721 -7.4777 -0.1647 0.0000 -0.0000 2.8820 5.4557 -2.9898 -8.8027 0.0000 -0.0000 3.0426 -96.4887 23.0681 -2.0649 11.4094 -1.3023 -6.1514 -7.0134 -1.6651 -3.8929 -4.7729 -0.8754 17.2909 -0.3974 5.8386 -0.2163 2.5857 0.6305 -10.5082 9.9617 3.2782 15.2905 -0.3616 -0.5110 -4.1657 -11.7771 11.5511 -4.1978 -23.1964 36.2530 0.0000 0.0000 32.5675 3.2057 3.6026 2.2013 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -7.1707 16.0793 -8.5117 9.9948 9.3715 -60.4487 -0.0000 -0.0000 -7.6447 -0.9940 0.9605 -4.5686 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 18.9987 -12.7200 -7.7150 3.5892 0.0000 0.0000 -18.8701 1.8499 -0.2118 0.1848 0.0000 0.0000 -28.2031 -14.5074 -1.4247 2.2037 0.0000 0.0000 -0.5792 2.4631 -3.0020 -8.5237 0.0000 -0.0000 3.2971 -97.5090 22.8209 -0.5421 11.3251 -5.8820 -7.0814 -6.4441 -1.8562 -4.7359 -7.1363 -1.3272 17.8051 0.6109 8.1605 -0.5689 3.2811 1.0517 -11.1645 10.4394 4.0769 15.0985 -0.7291 -0.2727 -4.1020 -11.7515 12.4434 -4.1860 -21.7196 37.0916 0.0000 0.0000 32.5051 4.1570 2.1569 1.5701 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -7.6486 17.4558 -7.4325 9.4807 8.5402 -60.6406 -0.0000 -0.0000 -8.4783 -0.3694 1.6677 -4.6805 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 19.4119 -10.1221 -5.9861 6.0572 0.0000 0.0000 -21.6162 -0.1927 1.5579 0.9910 0.0000 0.0000 -27.8886 -16.6351 4.6465 3.2268 0.0000 0.0000 5.6776 0.6940 -1.1402 -9.4679 0.0000 -0.0000 3.6673 -98.6455 22.6919 0.3559 8.4196 -9.7831 -8.0430 -1.9897 -2.0618 -6.6945 -11.3330 -2.5776 20.8403 2.5063 9.7122 -1.6257 4.1236 1.2306 -13.3941 10.6148 5.3881 14.8211 -1.4184 0.4559 -4.5935 -14.3111 13.4668 -3.2640 -17.9981 38.3786 0.0000 0.0000 32.5570 4.8482 0.4530 1.1812 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.0176 20.5344 -6.1765 9.3945 4.8833 -59.5109 -0.0000 -0.0000 -8.9849 -0.9865 3.6009 -5.2646 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 19.2124 -4.2983 -7.1652 9.0812 0.0000 0.0000 -23.3273 -3.3609 4.7469 1.3622 0.0000 0.0000 -25.0513 -15.0304 7.6449 0.7971 0.0000 0.0000 17.0559 1.7446 3.8759 -8.9411 0.0000 -0.0000 4.1615 -99.9482 22.7477 -3.0517 1.5402 -10.9268 -6.6525 5.5615 -1.3621 -7.6323 -15.3341 -4.1110 23.0460 8.1570 8.9655 -3.5046 3.6273 0.9360 -15.9689 9.2597 5.8238 15.5573 -1.2703 1.2500 -6.1977 -19.4958 13.0274 -0.9894 -14.9204 40.0530 0.0000 0.0000 31.6927 4.6544 -1.9862 1.1000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -11.1623 22.9730 -5.8312 10.7664 1.1930 -57.0291 -0.0000 -0.0000 -8.4974 -2.3975 5.7525 -5.7375 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 23.2865 5.7094 -11.3974 10.8362 0.0000 0.0000 -22.5986 -6.4308 7.3630 0.1179 0.0000 0.0000 -16.0930 -6.5314 6.4121 -5.9714 0.0000 -0.0000 23.4807 3.3646 11.0604 -6.5019 0.0000 -0.0000 4.6212 -100.9403 22.9243 -3.9742 -3.7299 -10.1361 -4.3251 6.7053 -1.1439 -4.0549 -24.7105 -5.6865 13.7238 30.0944 8.0922 -4.5719 -0.6901 0.4068 -17.1736 4.6493 3.7496 16.5365 1.2083 1.4357 -8.2905 -26.2873 9.3625 2.2414 -15.9216 42.2602 0.0000 0.0000 29.1562 4.1109 -4.7768 0.5400 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -11.5819 19.9347 -7.5168 12.5048 2.1363 -55.0317 -0.0000 -0.0000 -6.6341 -2.7412 6.6481 -5.1479 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 24.2280 12.3293 -13.2170 13.9457 0.0000 0.0000 -19.8390 -7.4904 6.2060 -2.7419 0.0000 -0.0000 -11.8950 0.7001 2.9986 -9.2123 0.0000 -0.0000 21.9255 2.1971 15.2557 -4.7505 0.0000 -0.0000 4.9698 -101.5947 23.1822 -1.6621 -4.7075 -8.9305 -3.2023 3.5240 -1.3128 -0.9145 -20.7287 -3.6088 6.8291 29.3326 8.3247 -5.1447 -0.0533 -0.2819 -20.0566 6.8953 3.9253 15.3570 2.7609 1.3070 -9.0294 -25.7201 8.1593 4.6028 -19.4162 44.2430 0.0000 0.0000 25.1664 3.0894 -6.9752 -0.5504 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -10.7123 19.2708 -8.1075 11.9672 5.2818 -54.1086 -0.0000 -0.0000 -4.5825 -2.1735 5.5709 -3.6923 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 19.2515 13.7350 -10.8109 20.6751 0.0000 0.0000 -16.0654 -7.9548 2.6741 -5.5635 0.0000 -0.0000 -13.2434 2.7787 1.9434 -7.6875 0.0000 -0.0000 17.9258 0.5049 15.2626 -4.8457 0.0000 -0.0000 5.2475 -102.1369 23.4434 -0.0703 -3.4527 -9.6277 -2.0614 0.5223 -1.1973 -0.7187 -9.8623 -1.4032 7.8543 13.0335 7.9414 -5.7576 4.3371 -0.6023 -25.0886 13.0234 7.2840 11.0639 2.8125 0.6775 -7.6538 -19.1284 11.6982 5.3757 -20.7834 45.5297 0.0000 0.0000 20.9816 1.0982 -8.3218 -1.1610 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -8.5538 19.4965 -8.6701 9.5242 8.1060 -54.1068 -0.0000 -0.0000 -2.8964 -2.7723 3.3495 -2.6515 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 12.0046 13.6269 -7.3637 30.6908 0.0000 0.0000 -10.9741 -8.8564 0.4402 -6.6558 0.0000 -0.0000 -14.9370 2.0556 4.7396 -4.4492 0.0000 -0.0000 15.2961 -0.2045 12.9126 -5.6459 0.0000 -0.0000 5.4879 -102.5179 23.6332 1.1664 -2.8729 -11.8913 -0.6360 -1.0180 -0.8841 -0.5065 -6.1666 -0.6258 7.6451 7.9460 9.2405 -5.8498 5.6085 -0.3061 -28.9750 15.1150 9.8677 5.4002 2.8228 -0.0006 -5.7420 -13.1849 15.5446 5.5993 -18.7970 46.2794 0.0000 0.0000 18.3024 -0.8280 -8.8853 -0.9698 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -5.7663 16.3491 -10.9403 7.8939 9.5790 -54.0717 -0.0000 -0.0000 -1.9417 -4.7952 2.0991 -2.6398 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 2.5775 14.2181 -3.5901 42.8903 0.0000 0.0000 -4.5295 -8.4197 -0.7540 -5.3029 0.0000 -0.0000 -16.6298 1.3088 8.9383 -1.2701 0.0000 -0.0000 12.9683 -0.7807 10.6654 -6.1098 0.0000 -0.0000 5.6946 -102.8226 23.7216 2.3375 -4.1743 -14.3565 -0.3401 -0.2299 -0.5206 -0.5581 -4.5699 -0.2393 7.6740 7.3401 10.4085 -5.9920 5.1292 0.2277 -31.4432 14.0835 10.5402 1.0033 2.6943 0.2145 -4.7337 -11.0059 17.1120 5.3434 -15.9409 47.2014 0.0000 0.0000 17.3459 -1.0964 -8.2396 -0.9142 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.6049 14.9022 -13.2918 7.8188 8.1027 -52.6604 -0.0000 -0.0000 -2.1618 -5.8463 2.9342 -3.3668 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -7.5004 15.7929 0.2233 54.1840 0.0000 0.0000 0.9577 -6.2396 -1.7458 -2.9731 0.0000 -0.0000 -17.3053 2.3018 11.0340 -0.6687 0.0000 -0.0000 10.7653 -1.3594 10.8359 -6.3640 0.0000 -0.0000 5.8269 -103.2418 23.7788 3.1256 -5.5274 -15.9121 -0.7371 1.3427 -0.2505 -0.6388 -3.8932 -0.0682 7.7037 7.4863 10.8034 -6.3848 4.4080 0.6144 -32.5537 11.8772 9.9894 -0.9822 2.6723 0.8425 -4.5733 -11.9333 16.6909 4.2652 -16.0646 48.7156 0.0000 0.0000 17.6625 -0.1840 -6.6126 -1.4486 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.5855 16.0341 -14.4052 7.7505 6.7059 -50.5459 -0.0000 -0.0000 -2.9945 -5.0141 4.0014 -3.9814 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -15.2811 16.5898 2.8274 61.6278 0.0000 0.0000 2.0363 -3.4790 -2.5674 -2.1482 0.0000 -0.0000 -16.3167 3.7395 9.9735 -2.5595 0.0000 -0.0000 9.8791 -1.4871 13.2247 -6.7000 0.0000 -0.0000 5.8774 -103.7976 23.8653 2.5781 -5.3779 -15.6641 -0.4576 2.3147 -0.1764 -0.4015 -3.7791 -0.1192 7.9961 6.9067 10.1437 -6.8636 4.1417 0.6092 -32.8955 10.4948 9.5755 -1.2780 2.7670 0.8296 -4.7722 -13.1597 16.2289 2.9637 -19.4686 49.3954 0.0000 0.0000 19.2961 -0.0918 -4.8970 -1.6215 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -4.5008 17.3515 -14.0425 6.7565 7.7335 -49.3263 -0.0000 -0.0000 -3.5685 -4.4332 3.3441 -3.7201 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -18.1557 16.2946 2.5488 64.1377 0.0000 0.0000 -1.3504 -1.5204 -3.4423 -2.7947 0.0000 -0.0000 -13.6592 4.4384 7.9785 -4.1421 0.0000 -0.0000 9.4816 -1.4770 14.6320 -6.9864 0.0000 -0.0000 5.8944 -104.3130 23.9717 1.2487 -4.5054 -13.4927 0.4074 2.6457 -0.3109 -0.0144 -3.4705 -0.2084 8.4033 5.5765 8.8879 -7.0950 4.1358 0.3645 -32.8348 10.5515 9.6115 -1.0212 2.8342 0.0550 -4.7170 -13.2660 16.6312 2.2641 -22.5547 48.7436 0.0000 0.0000 21.0284 -2.2301 -3.9969 -0.6938 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -3.8813 17.3352 -13.3445 6.2387 10.0659 -49.7194 -0.0000 -0.0000 -3.2693 -5.3774 1.5292 -3.0804 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -17.8728 15.8523 0.1112 62.5626 0.0000 0.0000 -5.4892 -0.7927 -5.4421 -3.0658 0.0000 -0.0000 -11.2299 4.8420 7.2033 -3.3559 0.0000 -0.0000 7.8271 -1.8789 12.9792 -7.0519 0.0000 -0.0000 5.8940 -104.7092 24.0593 0.5737 -3.8628 -10.7891 0.8590 2.5531 -0.4252 0.1019 -2.9598 -0.2150 8.4706 4.5006 8.1602 -6.9425 4.0659 0.2336 -32.3084 11.2061 9.5456 -0.5953 2.9272 -0.6987 -4.3414 -12.6730 17.1199 2.4496 -23.1902 48.1853 0.0000 0.0000 21.3228 -4.9014 -4.3247 0.3337 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.2734 16.4117 -13.2047 7.5627 11.5687 -51.2809 -0.0000 -0.0000 -2.3245 -6.1840 1.3320 -2.9265 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -18.0775 15.1893 -1.8570 58.7913 0.0000 0.0000 -8.0012 -0.5833 -9.2296 -2.5671 0.0000 -0.0000 -10.3055 5.0582 7.6772 -1.3238 0.0000 -0.0000 5.3988 -2.3751 9.7136 -7.0119 0.0000 -0.0000 5.8653 -105.0559 24.1153 0.7686 -3.5620 -8.9390 0.6365 2.3143 -0.3736 -0.0852 -2.7962 -0.1667 8.3723 4.3566 8.4683 -6.6534 4.0015 0.3665 -31.5198 11.6199 9.2708 0.1541 3.0202 -0.9375 -4.2047 -12.0984 17.0895 3.1941 -22.6625 48.4360 0.0000 0.0000 20.3247 -5.1527 -5.7171 0.2117 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -3.1860 15.7020 -13.4448 9.7051 11.6149 -52.7900 -0.0000 -0.0000 -1.6200 -5.0793 3.8752 -3.3602 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -19.8458 14.1308 -1.5963 54.0809 0.0000 0.0000 -9.6611 -0.2666 -13.1697 -2.2935 0.0000 -0.0000 -10.2333 5.0537 7.9631 0.0611 0.0000 0.0000 3.7468 -2.4044 7.5986 -7.1636 0.0000 -0.0000 5.8116 -105.3849 24.1422 0.8558 -3.7108 -7.5941 0.3879 2.2871 -0.2304 -0.1790 -2.9135 -0.1306 8.3229 4.9157 9.2084 -6.4921 4.1033 0.5341 -30.7758 11.5784 9.0193 1.3129 2.8380 -0.8975 -4.5499 -11.9458 16.8758 3.7274 -22.7226 48.7568 0.0000 0.0000 19.1937 -2.8827 -7.3848 -0.7257 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -3.4506 15.5069 -13.5700 11.1005 11.0478 -53.4967 -0.0000 -0.0000 -1.4373 -2.9682 7.0383 -4.0176 -0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -21.6786 13.3416 0.4216 48.9166 0.0000 0.0000 -11.0941 0.6577 -14.2146 -2.2693 0.0000 -0.0000 -9.8061 5.3738 7.3282 0.5854 0.0000 0.0000 2.8432 -2.1632 6.8750 -7.4954 0.0000 -0.0000 5.7285 -105.6696 24.1510 0.5783 -4.1531 -5.3367 0.4393 2.4816 -0.1225 -0.0206 -3.0274 -0.1256 8.1296 5.7834 9.4916 -6.4563 4.2019 0.5290 -29.9570 11.2220 8.6734 2.7842 2.1716 -0.8800 -5.0599 -12.2631 16.6867 3.6436 -23.7037 48.3385 0.0000 0.0000 18.4918 -1.6273 -8.4027 -1.4004 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -3.7391 15.4505 -13.5117 11.6459 10.6774 -53.7360 -0.0000 -0.0000 -1.3303 -2.0998 8.2851 -4.2645 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -22.5019 13.2491 2.6725 43.5198 0.0000 0.0000 -11.7809 1.9975 -10.8343 -1.8521 0.0000 -0.0000 -8.7695 6.0996 5.4111 0.6293 0.0000 0.0000 1.9331 -1.8960 6.3954 -7.7996 0.0000 -0.0000 5.6085 -105.9433 24.1646 0.3841 -4.4458 -1.6204 0.5228 2.6788 -0.0144 0.1627 -2.9246 -0.1334 7.7779 6.2791 9.2059 -6.3832 4.1922 0.3724 -28.8091 10.6990 8.1542 4.4208 1.2031 -0.7543 -5.5244 -12.6457 16.3334 3.0586 -25.1684 47.1343 0.0000 0.0000 17.8831 -4.4933 -8.7726 -1.5776 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -3.9356 15.4689 -13.3290 11.9486 10.5845 -54.1264 -0.0000 -0.0000 -1.0656 -2.5311 7.1644 -4.2600 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -22.3744 13.6244 4.4057 37.8350 0.0000 0.0000 -11.9785 2.0942 -3.6107 -1.5972 0.0000 -0.0000 -7.3798 6.6636 1.9239 0.0223 0.0000 0.0000 1.1000 -1.2992 6.0321 -8.0657 0.0000 -0.0000 5.4469 -106.2468 24.1981 0.3012 -4.2778 2.9263 0.4806 2.7418 0.1559 0.2461 -2.9077 -0.1558 7.5954 6.4214 8.7862 -6.2432 4.0545 0.2686 -27.4609 10.0530 7.6973 5.9790 0.3252 -0.3131 -6.0223 -12.8512 15.6847 2.0357 -26.6438 45.6049 0.0000 0.0000 16.9092 -10.4593 -9.0391 -1.8343 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -4.0899 15.7879 -13.0075 12.0935 10.4870 -54.7222 -0.0000 -0.0000 -0.9642 -2.8570 5.1939 -4.5049 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -21.5736 13.9224 6.4188 31.9193 0.0000 0.0000 -11.6481 -1.2454 5.0249 -2.1789 0.0000 -0.0000 -5.9541 6.5356 -2.0780 -0.8456 0.0000 -0.0000 0.4565 -0.1830 5.4597 -8.3381 0.0000 -0.0000 5.2525 -106.5433 24.2337 -0.0296 -4.0635 7.7435 0.5848 2.8663 0.2835 0.3867 -3.0369 -0.1891 7.6284 6.4515 8.6305 -6.1258 3.8658 0.2687 -26.1242 9.3527 7.4506 7.1683 -0.2522 0.3088 -6.5906 -12.9112 14.9380 0.3860 -27.9837 43.9804 0.0000 0.0000 15.6607 -15.7974 -8.8082 -2.6584 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -4.3353 16.2837 -12.5967 11.9554 10.3588 -55.2068 -0.0000 -0.0000 -1.2427 -2.7457 3.8228 -4.8029 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -20.5742 14.1464 9.9853 27.2891 0.0000 0.0000 -10.2675 -7.1113 11.7080 -2.7910 0.0000 -0.0000 -4.8690 6.1386 -4.3987 -0.7958 0.0000 -0.0000 -0.3282 0.9814 2.9896 -8.4021 0.0000 -0.0000 5.0323 -106.7787 24.2401 -0.2389 -4.3208 13.0002 0.8840 3.2415 0.2643 0.6226 -3.1179 -0.1913 7.4669 6.5564 8.6640 -6.0332 3.6634 0.2992 -24.7661 8.7482 7.1844 7.9303 -0.5949 0.7671 -7.0869 -12.9001 14.3027 -1.8407 -29.0832 42.2977 0.0000 0.0000 14.5535 -18.8952 -7.1952 -3.7715 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.7736 16.5727 -12.2972 11.7376 10.3005 -55.3545 -0.0000 -0.0000 -1.6384 -2.7329 3.3483 -4.9095 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -20.6471 14.6075 14.6057 26.7640 0.0000 0.0000 -9.7400 -11.7796 15.1807 -2.8893 0.0000 -0.0000 -4.6886 6.1434 -4.7225 0.5062 0.0000 0.0000 -1.1050 1.8443 -1.7682 -8.0963 0.0000 -0.0000 4.7873 -106.9878 24.2147 0.0877 -4.9828 18.9392 1.1382 3.7028 0.2245 0.8685 -3.0366 -0.1669 7.0248 6.7943 8.6121 -5.8951 3.5012 0.2766 -23.3640 8.3241 6.7062 8.5479 -0.8072 0.8814 -7.4722 -12.8090 13.8025 -4.1588 -29.8703 40.6846 0.0000 0.0000 13.8506 -21.1684 -4.0378 -4.7977 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -5.3778 16.5512 -12.1366 11.6155 10.2341 -55.1756 -0.0000 -0.0000 -1.8089 -2.8550 3.2598 -4.9952 -0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -22.0017 15.3017 18.3841 30.8458 0.0000 0.0000 -12.0928 -13.2105 16.3054 -2.6198 0.0000 -0.0000 -4.9073 6.5616 -5.8171 1.4383 0.0000 0.0000 -1.1786 2.9498 -6.1505 -7.7823 0.0000 -0.0000 4.5362 -107.2274 24.1817 0.6948 -5.9029 25.2446 1.3158 3.9564 0.3182 1.1273 -2.9031 -0.1386 6.6872 7.2894 8.5474 -5.7321 3.5290 0.1799 -22.1166 8.0397 6.1403 9.3442 -0.8958 0.7464 -7.9017 -12.6807 13.2440 -6.2669 -30.6900 39.3248 0.0000 0.0000 13.4550 -23.6829 0.1253 -5.6024 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.0945 16.5025 -11.8687 11.4635 10.0524 -54.6890 -0.0000 -0.0000 -1.8330 -2.6574 2.9748 -5.0690 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -23.2433 16.1839 21.0193 36.9305 0.0000 0.0000 -16.6659 -12.7302 15.7061 -1.9144 0.0000 -0.0000 -4.2564 7.1290 -9.6441 0.4503 0.0000 0.0000 -0.4711 4.9897 -8.1261 -7.8035 0.0000 -0.0000 4.2848 -107.4881 24.1499 1.3846 -6.8736 31.3296 1.4707 3.7995 0.5887 1.5049 -3.3029 -0.1678 6.3897 8.7435 8.8418 -5.6074 3.7143 0.1150 -21.1200 7.7498 5.5896 10.3274 -0.8374 0.5799 -8.4854 -12.7147 12.4000 -8.5437 -32.2257 38.0772 0.0000 0.0000 13.0960 -25.8891 4.3831 -6.0962 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -6.8633 16.4748 -11.4166 11.1508 9.9256 -53.7815 -0.0000 -0.0000 -1.9686 -2.2787 2.3585 -4.9630 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 -23.5212 16.9855 22.9562 42.5754 0.0000 0.0000 -21.4527 -12.1940 14.2534 -0.9306 0.0000 -0.0000 -2.7299 7.3674 -15.0112 -2.0308 0.0000 -0.0000 0.2165 7.4376 -8.5270 -7.8387 0.0000 -0.0000 4.0139 -107.7400 24.1027 2.5115 -7.6235 37.0386 1.4873 3.3718 0.8734 1.8286 -3.9827 -0.1830 5.8325 10.7505 9.7246 -5.4603 4.0111 0.1262 -20.2536 7.4916 5.1541 11.2432 -0.7207 0.5250 -9.1046 -12.9412 11.5566 -11.2653 -34.2873 36.5187 0.0000 0.0000 12.8075 -27.8409 7.7999 -6.2629 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -7.5480 16.3208 -10.8915 10.6736 9.9756 -52.4659 -0.0000 -0.0000 -2.0863 -2.5595 1.6442 -4.9176 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -23.1937 17.7710 23.8555 46.8538 0.0000 0.0000 -25.2336 -11.7189 13.1362 -0.1781 0.0000 -0.0000 -1.7710 7.4051 -19.4260 -4.3068 0.0000 -0.0000 0.5644 9.4440 -9.2916 -7.5600 0.0000 -0.0000 3.6932 -107.9860 24.0332 4.1198 -7.9668 42.4120 1.3247 3.0245 1.0648 1.9591 -4.7484 -0.1820 5.0900 12.7617 11.1678 -5.2139 4.1936 0.2578 -19.5035 7.5133 5.0167 11.8844 -0.7385 0.5405 -9.6018 -13.1597 11.2357 -13.5980 -35.5057 34.8181 0.0000 0.0000 12.9985 -30.3498 9.7649 -6.3251 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -8.0854 16.2955 -10.3570 10.0228 9.7588 -50.8941 -0.0000 -0.0000 -1.9205 -3.7120 0.9390 -5.0825 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -22.5739 18.4452 23.8985 49.9239 0.0000 0.0000 -28.3967 -11.0134 12.1761 0.0159 0.0000 0.0000 -2.1457 7.5790 -22.2146 -5.4146 0.0000 -0.0000 1.0570 11.4799 -10.9260 -7.3481 0.0000 -0.0000 3.2968 -108.2247 23.9485 5.8608 -7.7974 47.3172 0.9937 2.7239 1.1854 1.9393 -5.4949 -0.1644 4.6244 14.3881 13.0649 -4.9695 4.3110 0.5175 -19.0512 7.8981 5.2231 12.2659 -0.9402 0.5280 -9.8676 -13.1666 11.4396 -14.5786 -35.2360 33.8070 0.0000 0.0000 13.7766 -32.6499 10.2139 -6.4477 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.7430 16.9219 -9.7053 9.2970 8.7592 -49.0555 -0.0000 -0.0000 -1.6991 -4.5285 0.1115 -4.9981 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -21.8254 18.3984 24.1176 52.1983 0.0000 0.0000 -31.3955 -10.7455 10.7783 -0.1166 0.0000 -0.0000 -3.7124 7.7756 -23.9396 -5.4229 0.0000 -0.0000 2.0028 14.0614 -13.3166 -7.4829 0.0000 -0.0000 2.8300 -108.4544 23.8570 7.3544 -7.3297 51.6908 0.8949 2.2198 1.2498 2.0818 -6.4096 -0.1401 4.1314 16.0602 15.3437 -4.8514 4.5720 0.8602 -18.8018 8.2577 5.4643 12.4670 -1.1226 0.5240 -9.6922 -13.0006 11.6727 -14.7559 -34.6785 33.7187 0.0000 0.0000 14.7141 -33.1618 9.9671 -6.1469 0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -9.7543 17.7649 -8.9096 8.5670 7.6812 -46.7247 -0.0000 -0.0000 -1.8167 -3.8984 -0.8496 -4.5176 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -20.5815 17.5513 24.5399 52.9286 0.0000 0.0000 -33.0703 -11.4027 9.9618 -0.2074 0.0000 -0.0000 -5.7188 7.8173 -25.1303 -4.9539 0.0000 -0.0000 3.1478 16.2814 -16.1920 -7.5413 0.0000 -0.0000 2.2924 -108.6868 23.7460 8.8222 -6.6408 55.6993 1.2569 1.4564 1.2858 2.5232 -7.0863 -0.0404 2.9115 17.8032 17.8248 -4.8564 5.0175 1.2045 -18.4846 8.3068 5.5113 12.4167 -1.1561 0.6824 -9.0172 -12.7898 11.7426 -14.9813 -35.0226 34.1925 0.0000 0.0000 15.5202 -32.6581 9.9106 -4.9881 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -10.7647 17.9249 -8.0761 7.4909 7.4806 -43.9237 -0.0000 -0.0000 -2.0131 -2.7347 -1.7415 -4.1186 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -18.7221 16.6230 24.1736 50.6263 0.0000 0.0000 -32.0687 -11.9544 10.7097 -0.2792 0.0000 -0.0000 -7.9371 7.7542 -26.6677 -4.7058 0.0000 -0.0000 4.0279 17.7611 -18.0365 -7.3072 0.0000 -0.0000 1.6350 -108.9398 23.5971 10.1395 -5.4245 59.3439 2.0308 0.3987 1.3332 3.2251 -7.4479 0.1315 1.0405 19.3429 20.3941 -4.9885 5.5483 1.5017 -18.2380 8.3161 5.6689 12.0331 -1.1651 1.0616 -8.1596 -12.5052 11.8882 -14.3984 -35.4043 35.4657 0.0000 0.0000 16.3139 -33.2015 9.7917 -3.4170 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -11.3349 17.6726 -7.1876 5.9258 7.3391 -41.1241 -0.0000 -0.0000 -1.7873 -2.4341 -2.4788 -3.8212 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -16.6464 15.4174 23.0817 45.4623 0.0000 0.0000 -29.7011 -10.5398 11.0902 -0.3180 0.0000 -0.0000 -10.6719 7.1476 -29.3900 -4.9036 0.0000 -0.0000 4.7065 20.0675 -17.9554 -7.2884 0.0000 -0.0000 0.8007 -109.2016 23.4289 10.2787 -3.4258 62.4008 3.2567 -1.3756 1.4075 4.2503 -8.3394 0.2742 -0.7354 20.5919 23.1959 -5.2962 6.3684 1.7068 -18.5426 8.8072 6.6083 11.5030 -1.2981 1.6267 -7.4815 -11.9296 12.2621 -11.7651 -34.2162 38.2591 0.0000 0.0000 17.0569 -33.7727 9.3666 -2.4766 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -11.9056 18.3743 -5.7666 4.7340 5.6543 -38.8823 -0.0000 -0.0000 -1.3939 -2.9856 -2.9443 -3.2960 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -15.5910 12.4929 22.6903 40.5991 0.0000 0.0000 -28.4867 -6.9946 8.6100 -0.1144 0.0000 -0.0000 -14.2909 5.2310 -32.1957 -4.5734 0.0000 -0.0000 5.2436 23.2270 -18.1057 -7.4938 0.0000 -0.0000 -0.1762 -109.4483 23.2987 8.5453 -0.8629 65.0665 4.7791 -3.9024 1.5308 5.5075 -10.0364 0.3838 -1.6223 20.7259 26.1357 -5.6602 7.6637 1.8188 -19.3482 10.1304 8.7969 11.1338 -1.5397 2.4226 -6.9434 -10.6658 12.9087 -7.4676 -31.4044 42.3353 0.0000 0.0000 17.3956 -31.8639 9.5658 -2.5111 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -13.1780 20.5211 -3.1834 4.7667 3.0646 -37.4227 -0.0000 -0.0000 -1.1628 -3.9860 -3.0551 -2.7563 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -16.8194 7.4493 22.6790 39.1987 0.0000 0.0000 -28.2034 -3.1358 4.4936 0.5326 0.0000 0.0000 -18.7229 2.1784 -32.5929 -2.3673 0.0000 -0.0000 4.8178 23.5810 -20.1732 -7.3269 0.0000 -0.0000 -1.1133 -109.6990 23.2519 5.6429 1.1222 68.2738 6.1241 -6.2701 1.7226 6.1869 -10.6548 0.5053 -0.6276 17.9223 28.1548 -5.7546 8.8792 1.8924 -19.7955 11.8304 11.8660 10.9376 -1.6837 3.4944 -6.2530 -8.4837 14.0362 -2.6553 -28.5780 46.4790 0.0000 0.0000 16.9815 -28.3410 10.8689 -2.7191 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -14.6340 22.4559 0.4259 5.6073 2.6081 -36.7645 -0.0000 -0.0000 -0.3019 -4.9899 -2.6525 -2.2018 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -18.8376 2.5491 20.3319 39.8142 0.0000 0.0000 -26.9508 -0.8551 1.9693 1.1794 0.0000 0.0000 -22.5963 -0.6694 -29.6790 1.2190 0.0000 0.0000 2.0304 18.7906 -20.8401 -7.4323 0.0000 -0.0000 -1.8255 -109.9675 23.3189 3.2561 1.5135 72.9081 6.9775 -7.8356 1.9372 5.8149 -9.3581 0.5207 1.4498 13.9626 28.5237 -5.4248 8.8152 2.0786 -19.3066 12.2088 14.1476 10.6582 -1.5847 4.5462 -5.2807 -6.3722 15.2868 2.2626 -27.0820 50.0738 0.0000 0.0000 15.6172 -25.9692 12.1628 -2.5446 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -14.5443 21.8811 2.9845 6.6463 5.6811 -36.5752 -0.0000 0.0000 2.0318 -4.4132 -0.4894 -1.2360 -0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -18.8720 0.2834 15.5640 38.7756 0.0000 0.0000 -24.4625 0.2005 1.1876 1.4111 0.0000 0.0000 -24.3520 -1.7403 -24.1945 4.0487 0.0000 0.0000 -1.4190 11.3977 -16.5392 -8.6545 0.0000 -0.0000 -2.3247 -110.2159 23.4989 2.4534 1.0596 79.2002 7.1073 -8.5917 2.0116 4.8056 -7.4014 0.5156 3.3097 11.6453 27.5500 -4.9022 7.7100 2.3679 -18.4960 10.3668 14.3413 10.0667 -1.6660 4.9213 -3.9715 -5.3424 16.0325 6.7835 -27.3906 53.3659 0.0000 0.0000 13.1863 -24.0862 11.6558 -3.1411 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -12.6332 19.0166 2.7457 8.4488 9.5076 -36.1369 -0.0000 0.0000 4.7140 -0.7555 5.0097 -0.5735 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -16.8027 0.3504 10.7855 35.2143 0.0000 0.0000 -21.9149 1.4006 -0.3227 1.3232 0.0000 0.0000 -24.6892 -0.4776 -16.4463 5.6695 0.0000 0.0000 -2.7633 5.7498 -9.0274 -9.5567 0.0000 -0.0000 -2.7413 -110.4544 23.7226 2.2606 1.1260 86.6056 6.6478 -8.9727 1.9360 3.8039 -6.1025 0.5533 4.4639 10.9960 26.4040 -4.4722 6.5890 2.6789 -18.1810 7.5291 12.7248 9.1048 -2.4040 4.1054 -2.4584 -4.8451 16.3426 10.5785 -29.3161 56.7035 0.0000 0.0000 10.2645 -20.4165 8.5868 -5.3191 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -10.4264 16.0377 0.8237 11.5013 10.6882 -35.8264 -0.0000 0.0000 5.9855 6.0491 12.8214 -1.7215 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -14.6516 0.4571 7.5095 30.8860 0.0000 0.0000 -19.6240 2.9717 -4.2044 1.0583 0.0000 0.0000 -25.3338 1.2022 -7.2887 7.4178 0.0000 0.0000 -3.2357 3.4965 -4.3497 -9.1001 0.0000 -0.0000 -3.1392 -110.7220 23.9031 1.4945 1.7729 93.9972 6.1958 -9.3730 1.9030 3.2033 -5.7583 0.6129 4.7721 11.0888 26.0681 -4.2797 5.9041 2.9232 -18.4923 5.2256 10.3700 7.9554 -3.6272 2.1510 -1.2300 -4.3178 16.7334 14.7069 -30.4228 60.4448 0.0000 0.0000 8.3987 -15.3516 3.2325 -7.1738 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -9.0966 14.2950 -0.7996 14.1514 9.1476 -36.0063 -0.0000 0.0000 5.7452 13.1414 19.0258 -4.3057 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -13.6234 -0.2997 4.9556 27.2370 0.0000 0.0000 -17.1296 4.1636 -9.1525 0.5551 0.0000 0.0000 -26.5505 1.3713 1.7231 9.9421 0.0000 0.0000 -3.9464 2.0424 -5.1813 -8.8697 0.0000 -0.0000 -3.5108 -111.0053 23.9950 0.2731 2.3889 100.7012 6.0506 -9.7240 1.9731 3.0400 -5.8309 0.6654 4.5243 11.2803 26.5073 -4.3336 5.5535 3.1418 -19.0988 3.9007 8.1511 6.8987 -4.7885 -0.3315 -0.6039 -3.9374 17.4478 19.6407 -27.4497 64.4668 0.0000 0.0000 8.6749 -8.6732 -3.6705 -6.1465 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -8.7260 13.6588 -1.5728 14.0114 7.3538 -36.1863 -0.0000 0.0000 5.0017 14.8218 20.5072 -4.8759 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -13.3147 -1.2303 1.6083 24.1883 0.0000 0.0000 -14.6921 5.0786 -12.9435 0.0292 0.0000 0.0000 -27.8970 0.2192 9.3215 13.3789 0.0000 0.0000 -4.8363 -0.3544 -7.7290 -9.1926 0.0000 -0.0000 -3.8342 -111.2718 24.0204 -1.0770 2.6050 106.9803 6.1195 -9.9738 2.0305 3.1055 -6.0293 0.6952 4.2704 11.4149 27.1256 -4.5615 5.4106 3.3686 -19.7987 3.0339 6.2733 6.0602 -5.5829 -2.6934 -0.2347 -4.2440 18.2844 23.3092 -20.7676 67.5734 0.0000 0.0000 10.4152 -0.9171 -8.0713 -1.5396 0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -8.8230 13.5772 -2.1692 11.1700 6.5910 -36.0091 -0.0000 0.0000 4.1093 10.2907 17.0290 -3.3895 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -12.9589 -2.1405 -2.2586 21.3438 0.0000 0.0000 -12.6802 6.7576 -15.5248 -0.0631 0.0000 -0.0000 -28.9207 -1.5853 14.6066 17.7148 0.0000 0.0000 -6.0321 -2.1386 -7.6138 -9.1308 0.0000 -0.0000 -4.0892 -111.4975 24.0464 -2.7455 2.5309 113.3832 5.9218 -10.3351 2.0130 3.1773 -6.5551 0.6748 4.2052 11.7495 27.5478 -4.8437 5.3448 3.5363 -20.6565 2.0344 4.4809 5.4379 -6.1634 -4.6746 0.0694 -5.3107 18.6572 24.4354 -15.3712 69.6745 0.0000 0.0000 12.0544 2.3929 -7.8167 1.8749 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.0164 14.1587 -2.9249 7.7636 5.6956 -35.7712 -0.0000 0.0000 2.7020 4.7114 11.5425 -3.0802 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -12.3719 -3.3241 -6.0896 18.1707 0.0000 0.0000 -10.6374 8.7592 -17.8368 0.2538 0.0000 0.0000 -29.2961 -3.7480 17.0955 21.5335 0.0000 0.0000 -7.4564 -2.2940 -4.8602 -8.3573 0.0000 -0.0000 -4.2531 -111.6582 24.1161 -4.6968 2.2485 120.2550 5.2661 -10.7225 1.9085 3.1195 -7.2972 0.6123 4.0598 12.3372 27.5120 -5.1173 5.1436 3.5753 -21.7199 0.5406 2.4735 5.0318 -6.7415 -6.3078 0.1887 -6.9798 18.2581 23.9978 -14.2961 71.4291 0.0000 0.0000 13.1735 1.4880 -5.3378 1.9642 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -9.2533 15.2388 -3.5728 5.3411 4.1485 -36.0515 -0.0000 0.0000 0.7623 1.1980 6.9198 -3.7753 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -10.9953 -4.6754 -10.9226 13.3932 0.0000 0.0000 -8.1231 9.3482 -19.6266 0.4537 0.0000 0.0000 -28.9211 -5.8485 17.8144 23.5873 0.0000 0.0000 -9.3481 -3.5109 -3.0970 -7.8449 0.0000 -0.0000 -4.3288 -111.7372 24.1856 -6.3939 1.7764 127.4225 4.3979 -10.5525 1.7860 2.9578 -7.6414 0.5678 3.6581 12.5196 26.7885 -5.3977 4.6400 3.5516 -22.8244 -1.2793 0.2467 4.7691 -7.2759 -7.7061 0.2255 -8.5407 17.5760 23.1737 -16.5161 72.6500 0.0000 0.0000 14.7485 0.3182 -1.0089 1.1046 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -9.4589 15.8895 -4.1962 3.9618 3.1413 -36.6801 -0.0000 -0.0000 -1.0885 0.1782 3.9896 -4.3332 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 -8.5373 -6.0923 -16.9810 6.8593 0.0000 0.0000 -5.6773 8.3320 -20.2686 0.2736 0.0000 0.0000 -28.0479 -7.5926 17.6687 24.8243 0.0000 0.0000 -11.7739 -7.3600 -2.9166 -8.4097 0.0000 -0.0000 -4.3764 -111.7507 24.1890 -7.8598 1.2170 133.9163 3.6651 -9.8016 1.7730 2.8299 -7.5722 0.5934 3.0494 12.0028 25.8375 -5.7463 4.0506 3.6234 -23.8326 -2.8469 -1.8881 4.4421 -7.6670 -8.9418 0.3413 -9.2934 17.1829 22.3160 -19.6582 72.9070 0.0000 0.0000 17.7124 1.1400 3.7349 1.0473 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.4965 15.8557 -4.9595 3.3887 2.9983 -37.3787 -0.0000 -0.0000 -2.0389 0.8293 2.9826 -4.5716 0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -6.5607 -7.6717 -21.2854 1.2718 0.0000 0.0000 -3.9054 7.5413 -21.1971 0.0305 0.0000 0.0000 -27.1437 -9.7341 16.8568 26.5880 0.0000 0.0000 -13.5426 -10.2896 -1.5866 -9.0693 0.0000 -0.0000 -4.4423 -111.7169 24.1431 -9.6732 0.2197 138.7885 3.3525 -9.3522 1.7700 2.9180 -7.9455 0.6070 2.0703 11.7240 25.5500 -6.1947 3.6820 3.7613 -24.9316 -4.2453 -3.6847 3.9764 -7.9719 -9.8701 0.6266 -10.3677 17.0145 21.4786 -21.6808 72.1032 0.0000 0.0000 22.3643 3.4644 6.5307 1.3521 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -9.4857 16.0193 -5.4053 3.4830 2.6243 -37.9398 -0.0000 -0.0000 -2.2746 1.8940 3.3227 -4.3851 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.2294 -9.4410 -22.9252 -1.2553 0.0000 -0.0000 -2.8193 7.4440 -23.3972 -0.0410 0.0000 -0.0000 -26.1723 -13.5711 17.1700 28.1598 0.0000 0.0000 -13.4943 -7.4413 -0.2797 -8.3176 0.0000 -0.0000 -4.5471 -111.6291 24.0938 -11.9853 -0.7361 142.2918 2.9223 -9.1593 1.7160 3.0134 -8.6792 0.5903 0.7803 12.0785 25.4452 -6.6638 3.2796 3.8103 -26.2980 -6.0996 -5.1736 3.4011 -8.3953 -10.2066 1.3310 -13.1916 16.8619 20.8830 -21.7246 70.4902 0.0000 0.0000 28.4945 6.5457 7.2026 1.5997 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -9.3439 16.8199 -5.3611 3.4423 2.1604 -37.4385 -0.0000 -0.0000 -2.8857 2.6007 3.3996 -3.7519 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -7.8056 -10.8581 -24.5080 -1.1066 0.0000 -0.0000 -2.5984 6.4092 -26.1531 -0.1152 0.0000 -0.0000 -25.7741 -18.0513 20.5808 28.3524 0.0000 0.0000 -12.3636 -0.2231 -3.5711 -6.4102 0.0000 -0.0000 -4.6911 -111.4248 24.0806 -13.4147 -1.0194 145.8870 2.0250 -8.3012 1.4508 2.4697 -8.2148 0.5384 0.8700 11.9936 23.9461 -6.9337 2.3709 3.7595 -27.9848 -8.2517 -6.4884 2.4157 -9.0635 -9.9436 2.4643 -16.4289 16.8701 20.7060 -21.5080 68.3978 0.0000 0.0000 35.2632 9.9487 7.6352 2.1105 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -8.5606 17.8158 -5.9316 2.2312 3.3264 -34.9278 -0.0000 -0.0000 -4.0821 1.7934 1.4579 -3.3896 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -9.4505 -10.4470 -27.4009 0.1160 0.0000 0.0000 -3.5763 4.8095 -27.2540 -0.1626 0.0000 -0.0000 -25.9285 -19.5238 24.5957 27.3636 0.0000 0.0000 -10.7926 4.5822 -10.4502 -4.8963 0.0000 -0.0000 -4.8396 -111.0637 24.1207 -12.5457 -1.1054 150.1135 1.1327 -6.3394 0.9179 1.3028 -6.1552 0.4983 3.7367 10.3846 21.1780 -6.7770 1.0619 3.8138 -29.6378 -9.8208 -7.6913 0.7333 -9.8436 -9.3631 3.5471 -17.0894 17.0296 21.1781 -23.3767 66.5264 -0.0000 0.0000 40.6332 11.7770 9.1180 3.4767 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.6441 18.3550 -7.9572 0.2927 6.8730 -31.8476 -0.0000 -0.0000 -3.9778 -1.8598 -2.2651 -3.8297 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.7073 -7.8440 -28.6832 2.1414 0.0000 0.0000 -5.2751 4.9384 -24.0787 -0.4596 0.0000 -0.0000 -24.9336 -16.8105 24.4963 25.6552 0.0000 0.0000 -10.3112 4.6210 -14.4191 -4.5038 0.0000 -0.0000 -4.9607 -110.6357 24.1963 -10.3998 -1.5918 153.7624 0.6941 -3.9746 0.5085 0.3795 -4.2615 0.5247 7.1288 8.1059 19.2716 -6.2423 -0.1889 4.0745 -30.4451 -10.6570 -8.7015 -0.9952 -10.6157 -8.8256 4.2675 -15.0221 16.8971 22.7776 -26.1070 66.1334 -0.0000 0.0000 41.6640 10.3812 10.2921 5.9829 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -4.1936 18.0646 -10.2917 0.0055 11.9194 -31.3232 -0.0000 -0.0000 -0.9528 -6.5187 -5.1449 -3.5470 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.5490 -4.6142 -23.7096 6.2606 0.0000 0.0000 -7.7248 6.1901 -17.0488 -1.3231 0.0000 -0.0000 -22.1963 -13.1995 20.9133 23.5374 0.0000 0.0000 -10.4116 3.0500 -13.5530 -4.6471 0.0000 -0.0000 -5.0179 -110.2947 24.2923 -9.5139 -2.7386 156.3980 0.1440 -2.4009 0.4504 -0.1967 -3.6556 0.5182 8.8930 6.5137 18.6084 -5.8395 -1.0760 4.3323 -30.4859 -11.4928 -9.5169 -1.5236 -11.3632 -8.5797 4.7919 -13.5338 16.5934 25.2692 -25.0999 67.2679 0.0000 0.0000 36.9697 7.5896 8.3393 7.9740 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -2.8555 17.7839 -11.2837 2.8211 16.8266 -34.2020 -0.0000 0.0000 3.4335 -7.3946 -3.8814 -0.9821 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -5.9487 -3.0722 -14.4674 11.6096 0.0000 0.0000 -10.2178 5.0267 -7.7199 -1.6692 0.0000 -0.0000 -19.9506 -12.1977 18.7254 21.6283 0.0000 0.0000 -9.9019 2.8766 -13.3369 -4.6460 0.0000 -0.0000 -4.9874 -110.0386 24.4153 -10.0118 -4.7154 159.4461 -0.4805 -2.1038 0.4298 -0.5364 -3.6059 0.4666 9.1245 5.7112 17.9460 -5.8829 -1.5444 4.3196 -30.5532 -12.6421 -10.4488 -0.6088 -11.9150 -8.8138 5.4813 -14.6211 16.7486 27.7647 -17.9041 68.2649 0.0000 0.0000 28.4937 6.1960 2.8403 7.5095 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -2.8208 18.1672 -11.0287 7.7486 20.2607 -38.7039 -0.0000 0.0000 6.1616 -2.7544 1.4970 0.7733 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -6.1587 -3.5855 -7.8390 15.0318 0.0000 0.0000 -10.7333 0.7439 1.5269 -0.8668 0.0000 -0.0000 -19.0383 -13.5414 19.3052 19.9565 0.0000 0.0000 -8.8809 3.9900 -17.3869 -4.5683 0.0000 -0.0000 -4.9094 -109.7876 24.5425 -10.3111 -6.8626 163.8218 -0.7801 -2.4527 0.3296 -0.6357 -3.2707 0.4510 8.9436 5.5488 16.9311 -6.1505 -1.7753 4.1264 -31.1290 -13.2838 -11.8908 0.4643 -11.9911 -9.7093 6.1933 -16.3122 17.1876 30.4940 -8.1036 68.0956 0.0000 0.0000 19.7053 5.3948 -3.9632 5.7114 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -2.8061 18.5496 -11.1113 13.1412 22.4139 -43.4619 -0.0000 0.0000 5.9996 4.3324 6.3162 -1.4353 0.0000 -0.0000 0.0000 0.0000 0.0000 0.0000 -5.4381 -4.4472 -5.1257 15.8427 0.0000 0.0000 -9.7245 -3.0265 6.1396 -0.1439 0.0000 -0.0000 -18.5897 -14.6984 19.2199 18.2494 0.0000 0.0000 -7.6307 5.0351 -22.2547 -4.6488 0.0000 -0.0000 -4.8279 -109.5348 24.6466 -9.7721 -8.4473 168.6872 -0.7117 -2.5165 0.2515 -0.6557 -2.9152 0.4795 9.2501 5.9314 16.3626 -6.3243 -1.8503 4.0602 -32.1703 -12.7321 -13.7834 0.3789 -11.5610 -11.1504 6.3185 -16.5123 16.9582 33.1682 -1.8747 66.9846 0.0000 0.0000 12.9913 4.5755 -10.3402 3.2578 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -1.9093 18.7957 -12.2963 17.4814 23.8468 -48.2717 -0.0000 0.0000 4.1588 7.1688 7.5688 -5.3035 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -3.8360 -4.6787 -5.4315 15.4548 0.0000 0.0000 -8.5267 -3.1351 4.9036 -0.2166 0.0000 -0.0000 -17.6429 -14.7819 17.1609 16.0987 0.0000 0.0000 -6.1120 6.0212 -24.8122 -4.8194 0.0000 -0.0000 -4.7421 -109.3614 24.7249 -9.6576 -9.6984 172.6433 -0.7914 -2.4238 0.2354 -0.8443 -2.9054 0.5102 9.8376 6.5963 16.4298 -6.3860 -1.7564 4.1546 -33.3250 -11.4116 -15.4759 -0.7599 -11.0547 -12.6427 6.1141 -16.0995 16.0910 34.0816 -0.9690 65.0069 0.0000 0.0000 9.6555 5.2848 -14.4862 0.6193 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.4803 19.5470 -13.4853 19.8761 24.9894 -52.6170 -0.0000 0.0000 2.3386 2.4834 6.8837 -7.0510 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -3.4531 -4.6429 -7.9884 15.4485 0.0000 0.0000 -6.2699 -0.7823 1.3538 -0.4107 0.0000 -0.0000 -17.1952 -15.0388 15.2131 13.8729 0.0000 0.0000 -4.2753 7.1610 -26.5404 -4.9285 0.0000 -0.0000 -4.6455 -109.2900 24.7826 -10.4755 -10.8944 175.2128 -1.1715 -2.5858 0.2608 -1.1194 -2.9705 0.5262 10.2337 7.3965 16.4596 -6.4619 -1.4798 4.1494 -34.2534 -10.0547 -16.3825 -2.0553 -10.9111 -13.7030 5.9964 -16.3328 15.4422 32.4753 -3.3335 62.0224 0.0000 0.0000 9.7121 6.6894 -14.7236 -0.1400 -0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 0.8228 20.8326 -13.8147 20.3824 26.2595 -55.4520 -0.0000 0.0000 1.1525 -3.8006 5.1980 -6.6311 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -4.9856 -4.2682 -11.0432 16.4012 0.0000 0.0000 -3.7223 0.5963 -0.8629 -0.3771 0.0000 -0.0000 -17.9403 -15.7118 13.9555 12.1695 0.0000 0.0000 -2.7692 7.7409 -28.2177 -4.9732 0.0000 -0.0000 -4.5587 -109.2359 24.8194 -10.9019 -11.5208 176.6576 -1.2601 -2.6937 0.3254 -1.1645 -2.8162 0.5556 10.6259 8.2926 16.1920 -6.5246 -1.0776 4.0038 -34.7360 -8.7119 -16.3800 -3.0919 -10.9835 -14.2440 5.7845 -16.7716 15.2312 28.9187 -7.2648 58.7547 0.0000 0.0000 11.5387 4.8776 -12.0726 1.0462 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 1.8025 21.8595 -13.7824 19.9600 27.3971 -56.6597 -0.0000 0.0000 0.6504 -5.7540 2.7384 -5.9819 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.2809 -2.9579 -12.5813 17.4374 0.0000 0.0000 -2.6724 0.5795 -1.2095 -0.3001 0.0000 -0.0000 -18.0814 -15.7809 11.8214 10.6392 0.0000 0.0000 -2.1320 7.4857 -27.6813 -5.0491 0.0000 -0.0000 -4.4838 -109.1523 24.8369 -10.3361 -11.4545 177.2558 -0.9274 -2.4538 0.4071 -0.9744 -2.6562 0.5759 11.3135 9.1715 15.9142 -6.4738 -0.6223 3.8405 -34.7692 -7.1772 -15.6191 -4.0261 -10.7794 -14.4208 5.1985 -16.7692 14.9608 23.9906 -12.4867 55.9584 0.0000 0.0000 13.6394 -0.7111 -8.7733 2.1044 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 2.5006 22.1668 -13.7835 19.9168 27.5986 -57.3074 -0.0000 0.0000 0.9978 -4.6505 0.2764 -5.7172 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.0372 -1.0399 -11.9717 17.4047 0.0000 0.0000 -2.7788 0.7475 -0.7070 -0.0933 0.0000 -0.0000 -16.6072 -15.2744 8.8313 8.8821 0.0000 0.0000 -1.8690 7.1147 -24.7558 -5.2291 0.0000 -0.0000 -4.3919 -109.0941 24.8460 -9.8306 -11.3759 177.2550 -0.6505 -2.2467 0.4563 -0.8440 -2.6316 0.5723 11.9385 9.7603 15.6646 -6.3384 -0.1005 3.6843 -34.5069 -5.4814 -14.3498 -4.9567 -10.1261 -14.3473 4.4781 -16.7016 14.4428 17.9455 -18.3163 53.4256 0.0000 0.0000 15.8633 -4.2428 -5.2026 2.1113 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 2.9259 22.0141 -13.5332 20.5792 26.9498 -57.9109 -0.0000 0.0000 1.9527 -3.9308 -1.7144 -5.2267 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -5.5575 0.5554 -10.6607 16.5288 0.0000 0.0000 -2.9297 1.6035 0.2558 0.3966 0.0000 0.0000 -15.1427 -15.1829 6.9758 7.3894 0.0000 0.0000 -1.4734 7.1254 -22.5116 -5.5288 0.0000 -0.0000 -4.2715 -109.0968 24.8576 -9.9718 -11.5764 177.0512 -0.5106 -2.3310 0.4558 -0.8228 -2.6446 0.5490 12.0159 9.9512 15.3018 -6.2018 0.5221 3.4674 -34.0897 -3.6362 -12.7549 -5.7636 -9.1626 -14.1264 4.1028 -17.0283 13.9554 11.8850 -22.5431 51.0719 0.0000 0.0000 18.3757 -2.4194 -1.4937 1.6384 0.0000 -0.0000 -0.0000 0.0000 -0.0000 0.0000 3.2194 21.6018 -12.8838 21.1362 26.6138 -58.2011 -0.0000 0.0000 2.9911 -4.2530 -3.0068 -4.4410 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -5.8874 1.5965 -10.5007 15.7884 0.0000 0.0000 -3.0288 2.1638 1.7077 0.9016 0.0000 0.0000 -14.7701 -15.6556 6.7135 6.4906 0.0000 0.0000 -1.0287 7.2507 -22.1930 -5.8847 0.0000 -0.0000 -4.1387 -109.1234 24.8656 -10.1998 -11.6323 176.8509 -0.3456 -2.4038 0.4510 -0.7384 -2.5578 0.5336 11.7358 9.7993 14.9059 -6.0619 1.1792 3.2137 -33.4710 -1.4592 -10.8893 -6.3780 -8.0273 -13.8774 4.1795 -17.3663 13.6222 7.2894 -23.7912 49.4296 0.0000 0.0000 20.8280 0.4671 1.5508 1.3134 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.7138 20.8913 -12.1099 21.1261 27.0827 -58.3789 -0.0000 0.0000 3.9449 -4.4564 -3.8527 -3.7755 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -6.5254 2.5244 -11.4665 15.6258 0.0000 0.0000 -3.2446 1.6114 2.5859 0.8408 0.0000 0.0000 -14.6235 -16.0036 6.4228 5.7311 0.0000 0.0000 -0.6463 7.2539 -21.8011 -6.1023 0.0000 -0.0000 -4.0047 -109.1270 24.8594 -9.6887 -11.2576 176.7371 0.0895 -2.2350 0.4601 -0.5274 -2.3755 0.5329 11.5813 9.5516 14.5633 -5.8764 1.7465 2.9895 -32.5927 0.9526 -8.8545 -6.7546 -6.8670 -13.6402 4.3696 -17.4094 13.3736 4.2324 -23.0290 48.3246 0.0000 0.0000 22.9937 0.4152 3.3936 1.2838 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 4.3908 20.0873 -11.3159 21.1054 27.4752 -59.0131 -0.0000 0.0000 4.8121 -4.2503 -4.5260 -3.0020 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -6.4506 3.4976 -12.0626 15.8840 0.0000 0.0000 -3.6843 0.1193 1.7033 0.1055 0.0000 0.0000 -13.4105 -15.8609 5.2513 4.5693 0.0000 0.0000 -0.2322 7.4315 -20.1190 -6.0834 0.0000 -0.0000 -3.8565 -109.1386 24.8360 -8.8990 -10.6568 176.7373 0.5167 -2.0163 0.4616 -0.3501 -2.1977 0.5328 11.5776 9.4624 14.1396 -5.6774 2.2025 2.7332 -31.5245 3.1133 -6.8727 -6.7885 -5.8566 -13.3273 4.5061 -17.5701 13.2450 1.8157 -21.7103 47.1965 0.0000 0.0000 25.0156 -0.9914 3.7928 1.3349 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 4.8868 19.6746 -10.3491 21.4840 26.9504 -59.9624 -0.0000 0.0000 5.3838 -3.9621 -4.9512 -1.8960 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -6.2849 4.1749 -11.4596 16.8112 0.0000 0.0000 -5.3808 -1.6226 -0.3789 -0.5847 0.0000 -0.0000 -11.9819 -15.5492 4.3266 3.4938 0.0000 0.0000 0.1626 7.8548 -18.8086 -5.9340 0.0000 -0.0000 -3.6805 -109.1912 24.7972 -8.3937 -9.9750 176.9374 0.6894 -1.8016 0.4415 -0.2841 -2.0830 0.5090 11.5103 9.4760 13.5283 -5.4895 2.6267 2.3773 -30.3164 4.7227 -5.0815 -6.5113 -4.9459 -12.8579 4.5805 -18.0480 13.1751 -0.3066 -20.6900 46.0637 0.0000 0.0000 26.8512 -0.7742 3.2524 1.4103 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 5.0779 19.6607 -9.2206 21.9666 26.0481 -60.6928 -0.0000 0.0000 5.4537 -3.6274 -5.2754 -1.1671 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.5800 4.4340 -10.4994 18.2549 0.0000 0.0000 -8.9471 -3.2636 -1.7451 -0.7613 0.0000 -0.0000 -11.3948 -15.2462 4.3306 3.0867 0.0000 0.0000 0.4239 8.2521 -18.9542 -5.8334 0.0000 -0.0000 -3.4835 -109.2628 24.7461 -7.8550 -9.1505 177.2701 0.7480 -1.5042 0.4069 -0.2615 -1.9869 0.4831 11.4778 9.3998 12.8665 -5.2577 2.9786 2.0255 -28.9658 6.0889 -3.4451 -6.1394 -3.8977 -12.2291 4.3940 -18.4011 12.8886 -1.8252 -20.3767 45.2308 0.0000 0.0000 28.1643 0.6337 2.7292 1.4980 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 5.1750 19.6378 -8.2057 22.3420 25.7281 -61.2283 -0.0000 0.0000 5.1446 -3.5414 -5.8972 -1.5022 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -6.5587 4.4712 -10.1601 19.1582 0.0000 0.0000 -12.9595 -5.1231 -1.3292 -0.8091 0.0000 -0.0000 -11.0875 -14.8457 4.4538 3.0432 0.0000 0.0000 0.6598 8.6155 -19.2674 -5.8438 0.0000 -0.0000 -3.2743 -109.3500 24.6865 -7.1006 -8.2073 177.3829 0.7953 -1.2888 0.3820 -0.2785 -1.9151 0.4625 11.6416 9.3268 12.3970 -4.9569 3.2203 1.7845 -27.6102 7.5719 -1.9262 -5.7592 -2.6209 -11.4460 3.8179 -18.4856 12.3259 -2.5803 -20.6116 44.8976 0.0000 0.0000 28.6293 0.9087 2.5438 1.3616 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 5.2260 19.4732 -7.4131 22.8262 25.8687 -61.9503 -0.0000 0.0000 4.7819 -4.2949 -6.6037 -2.3739 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -6.0374 4.2893 -9.9671 19.2817 0.0000 0.0000 -15.9849 -7.0817 0.0738 -0.8480 0.0000 -0.0000 -10.5275 -14.3975 4.2422 2.9850 0.0000 0.0000 0.9621 9.2150 -18.7749 -5.9448 0.0000 -0.0000 -3.0496 -109.4968 24.6159 -6.5897 -7.1494 176.9624 0.7296 -1.2465 0.3914 -0.3794 -1.9160 0.4586 11.8141 9.3980 12.1475 -4.6637 3.4221 1.6349 -26.4206 9.1492 -0.5234 -5.2421 -1.3062 -10.5208 3.0225 -18.4242 11.7589 -2.6637 -21.0592 45.1603 0.0000 0.0000 28.2586 -0.2229 2.3426 1.0207 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 0.0000 5.0771 19.3452 -6.7772 23.4692 25.9485 -62.7511 -0.0000 0.0000 4.4674 -5.5752 -6.9382 -2.7559 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -6.1990 3.8434 -8.7460 19.7743 0.0000 0.0000 -18.7800 -7.9619 1.1525 -0.2918 0.0000 -0.0000 -10.3787 -13.9944 4.5848 3.2827 0.0000 0.0000 1.1595 9.9693 -18.4761 -6.1049 0.0000 -0.0000 -2.8027 -109.7191 24.5232 -6.5207 -5.8381 176.1588 0.4841 -1.1237 0.4228 -0.5027 -1.9903 0.4459 11.8161 9.4543 11.9483 -4.4093 3.7129 1.4878 -25.4165 10.5147 0.7529 -4.5544 -0.1675 -9.4719 2.2721 -18.1218 11.3950 -2.0696 -21.3966 46.0402 0.0000 0.0000 27.4716 -1.1153 1.8091 0.7672 0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 4.7235 19.0323 -6.3062 24.0302 26.3103 -63.3584 -0.0000 0.0000 4.1835 -6.4142 -7.0548 -2.6250 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -7.4389 3.3046 -6.5180 20.8759 0.0000 0.0000 -21.7535 -6.9406 1.4252 0.8898 0.0000 0.0000 -11.1501 -13.5424 5.9072 4.3300 0.0000 0.0000 1.1665 10.5710 -19.1211 -6.2937 0.0000 -0.0000 -2.5472 -109.9655 24.4017 -6.1136 -4.0536 175.3923 0.3907 -0.7488 0.4329 -0.5369 -2.0766 0.4240 11.9295 9.5187 11.6347 -4.1218 4.0339 1.3084 -24.4782 11.6048 1.8820 -3.8890 0.7044 -8.3729 1.6293 -17.4919 11.1362 -0.8412 -21.1609 47.4163 0.0000 0.0000 26.7907 -0.8090 0.9901 0.6951 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 4.2916 18.2618 -6.2121 24.4767 27.0712 -63.7856 -0.0000 0.0000 4.0105 -6.5512 -7.0334 -2.6961 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -8.1179 3.2312 -4.6374 21.0263 0.0000 0.0000 -22.7520 -4.7806 1.1597 1.7825 0.0000 0.0000 -11.7223 -12.6529 7.0567 5.4728 0.0000 0.0000 1.1962 11.1045 -19.4242 -6.4629 0.0000 -0.0000 -2.2944 -110.2412 24.2583 -5.4138 -1.9421 174.6811 0.4281 -0.7428 0.4251 -0.5613 -2.1343 0.3988 12.3624 10.1079 11.2854 -3.8039 4.3860 1.0630 -23.6557 12.5572 2.8312 -3.3474 1.3449 -7.3454 1.0151 -17.0391 10.8389 0.5906 -19.9733 49.0681 0.0000 0.0000 26.3875 0.1438 0.2230 0.7636 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.5952 17.6039 -6.5166 25.0807 26.5786 -63.9481 -0.0000 0.0000 3.9383 -6.3705 -6.0868 -3.1538 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 -8.0952 3.8468 -3.6790 19.8806 0.0000 0.0000 -20.4035 -2.9751 0.4929 1.8014 0.0000 0.0000 -11.8729 -11.3618 7.4471 6.1131 0.0000 0.0000 1.3873 11.8721 -18.6747 -6.5881 0.0000 -0.0000 -2.0211 -110.6131 24.1167 -5.3619 -0.2676 173.7721 0.4687 -1.9253 0.4447 -0.6943 -2.4892 0.3453 12.6650 11.5564 11.0013 -3.5977 4.9398 0.7292 -23.1188 13.3041 3.6733 -2.8280 1.8899 -6.4008 0.3188 -16.9792 10.5865 1.9709 -18.4061 50.8820 0.0000 0.0000 25.9946 0.8589 -0.1337 1.0061 0.0000 -0.0000 -0.0000 0.0000 0.0000 0.0000 2.6388 17.8837 -6.8375 25.7600 23.1872 -63.5110 -0.0000 0.0000 3.6869 -5.8554 -3.9211 -3.7728 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -9.3795 4.3102 -2.9549 19.5665 0.0000 0.0000 -16.9915 -2.0953 -0.2010 1.3382 0.0000 0.0000 -12.7539 -10.6893 7.8172 6.5170 0.0000 0.0000 1.7148 12.7776 -18.0572 -6.7373 0.0000 -0.0000 -1.6913 -111.1056 23.9960 -6.6047 0.3146 172.8695 0.2609 -3.8656 0.5571 -0.8883 -3.0167 0.2380 12.3755 12.3410 10.5630 -3.5144 5.6743 0.3185 -22.9214 13.5245 4.6529 -2.4082 2.4790 -5.2991 -0.5106 -16.4147 10.6912 3.5318 -17.3901 52.8905 0.0000 0.0000 25.2792 1.0459 -0.1479 1.4261 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 2.0829 18.5695 -6.9296 25.9496 18.5185 -62.6195 -0.0000 0.0000 3.1601 -4.6874 -2.2610 -4.6573 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -13.3868 3.5606 -1.8896 21.9866 0.0000 0.0000 -15.7372 -1.2899 -0.6469 1.2602 0.0000 0.0000 -15.5636 -11.5977 8.6993 7.5812 0.0000 0.0000 2.4212 13.4381 -18.7639 -7.0800 0.0000 -0.0000 -1.3025 -111.5819 23.9206 -7.4976 -0.2065 172.7837 0.1679 -5.0482 0.5845 -0.8983 -3.0931 0.1027 12.1383 10.5108 9.3739 -3.3396 5.9009 -0.0275 -22.8178 12.8936 5.8097 -2.4474 3.0389 -3.7698 -1.5111 -14.4888 11.2878 5.1638 -17.1563 54.8863 0.0000 0.0000 24.2890 1.2728 -0.4690 1.7711 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 2.5132 17.9522 -7.1320 25.3266 16.0865 -62.3466 -0.0000 0.0000 2.9248 -3.3663 -2.5355 -5.7057 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -16.8093 1.7696 -1.7014 24.8658 0.0000 0.0000 -16.2249 0.0550 -0.7681 1.7634 0.0000 0.0000 -18.5961 -13.5891 9.2250 9.3745 0.0000 0.0000 3.7956 13.7127 -19.8878 -7.7222 0.0000 -0.0000 -0.9133 -111.9355 23.9205 -6.9817 -1.1416 173.6934 0.2792 -5.1723 0.4329 -0.8356 -2.4298 0.0186 12.7271 7.0919 7.3848 -2.9702 4.9807 -0.1398 -22.4397 11.0169 6.4526 -2.9360 3.2401 -1.8690 -2.5726 -12.2879 11.8916 5.9949 -17.1155 56.4216 0.0000 0.0000 23.3306 2.2894 -1.5456 1.7190 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 3.2073 15.2813 -8.0232 24.6917 16.4748 -62.9586 -0.0000 0.0000 3.1346 -2.6687 -3.0904 -6.6312 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -17.0836 0.0080 -2.7790 25.2705 0.0000 0.0000 -16.0245 1.5573 -0.9182 2.4028 0.0000 0.0000 -20.4549 -15.3107 9.1736 11.6714 0.0000 0.0000 5.2834 13.6510 -20.0172 -8.4537 0.0000 -0.0000 -0.6097 -112.1949 23.9889 -6.0004 -1.2341 174.4744 0.2622 -4.5044 0.2695 -0.8859 -1.5144 0.0236 13.6363 4.3652 5.7552 -2.5480 3.3258 0.0314 -21.6128 7.9367 6.0062 -3.0933 2.7157 -0.1025 -3.4320 -11.0344 11.8765 5.7159 -17.2373 57.4264 0.0000 0.0000 22.4819 3.9016 -2.6754 1.2605 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 2.9721 12.3365 -9.4468 24.8313 16.6754 -63.3408 -0.0000 0.0000 3.0973 -2.1670 -1.8306 -7.6308 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -15.8316 -0.6801 -3.7996 23.6680 0.0000 0.0000 -14.6662 2.6269 -0.9393 3.0276 0.0000 0.0000 -21.5672 -15.7038 9.6444 14.5229 0.0000 0.0000 5.5434 13.2657 -19.1459 -8.9008 0.0000 -0.0000 -0.4351 -112.4013 24.0922 -5.4182 -0.0256 173.7651 0.0976 -3.6177 0.2309 -0.9978 -0.8701 0.1146 14.0833 3.3901 5.4612 -2.2848 1.8837 0.3907 -20.5733 4.3178 4.7794 -2.2901 1.2851 0.9568 -3.9430 -10.3736 11.3527 5.1755 -17.7020 58.3434 0.0000 0.0000 21.5923 4.9137 -2.6523 0.6715 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 1.9453 11.2764 -10.5801 24.7644 14.9247 -62.5483 -0.0000 0.0000 2.3890 -1.1533 0.0896 -8.7605 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -15.2393 0.0320 -3.9319 22.2457 0.0000 0.0000 -13.4926 3.1873 0.1260 3.6896 0.0000 0.0000 -22.0448 -14.8010 10.8594 17.5332 0.0000 0.0000 4.0904 12.6398 -18.1050 -9.0244 0.0000 -0.0000 -0.3644 -112.5572 24.1945 -5.1281 1.8533 171.5009 -0.0451 -3.0794 0.3051 -1.0205 -0.7363 0.2101 13.8887 3.8630 6.2737 -2.1404 1.1143 0.7851 -19.5538 0.7793 3.3989 -0.9623 -0.8292 1.3350 -4.1412 -9.4050 10.8612 5.1967 -18.0352 59.5970 0.0000 0.0000 20.6967 4.7393 -1.4763 0.2839 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 0.9603 11.6845 -10.9074 23.0344 13.0849 -60.8802 -0.0000 0.0000 1.2649 -0.3115 0.3208 -9.2095 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -15.6455 1.4997 -3.4137 21.8122 0.0000 0.0000 -12.9570 3.3755 2.3927 4.1282 0.0000 0.0000 -21.7062 -13.2643 11.4777 19.9566 0.0000 0.0000 2.0140 11.9204 -17.4430 -8.9897 0.0000 -0.0000 -0.3349 -112.6588 24.2734 -4.6579 3.5409 168.8331 -0.0166 -2.9397 0.3958 -0.9694 -0.8322 0.2704 13.5206 4.6082 7.2401 -1.9253 0.7397 1.1187 -18.5914 -2.4154 2.2648 -0.0657 -2.9962 1.5103 -4.2099 -8.0689 10.5906 5.5055 -17.8478 61.1911 0.0000 0.0000 20.1171 4.2557 -0.5227 0.1398 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 0.2427 11.9794 -10.7983 19.6215 12.7764 -59.0331 -0.0000 0.0000 0.0158 -0.6689 -1.1878 -8.4907 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -15.9670 2.7984 -2.5718 21.4821 0.0000 0.0000 -12.3493 3.3882 4.5622 4.1036 0.0000 0.0000 -20.7100 -11.6029 10.2166 21.5901 0.0000 0.0000 0.3325 11.0497 -17.1691 -8.7350 0.0000 -0.0000 -0.2981 -112.7381 24.3214 -4.2698 4.5831 166.8957 -0.0605 -3.0241 0.4632 -0.9836 -0.8498 0.2944 13.3737 4.8003 7.6722 -1.6347 0.2810 1.3596 -17.6985 -5.2248 1.4376 0.0586 -4.5914 1.7728 -4.3789 -7.0624 10.3483 5.3544 -17.7193 62.6660 0.0000 0.0000 20.1423 4.3764 -0.5766 0.0371 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.5102 11.6629 -10.8417 16.0943 12.9877 -57.2528 -0.0000 -0.0000 -1.2571 -1.9899 -3.0686 -7.4420 -0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -15.9922 3.3843 -1.4432 20.8308 0.0000 0.0000 -11.5669 3.5391 5.4648 3.8888 0.0000 0.0000 -20.0890 -10.2574 7.3955 23.1567 0.0000 0.0000 -0.9619 9.9548 -17.4496 -8.2191 0.0000 -0.0000 -0.2435 -112.8163 24.3495 -4.0659 5.0147 166.1372 -0.0535 -3.0393 0.4738 -1.0129 -0.7425 0.2871 13.2982 4.1758 7.4785 -1.4303 -0.4133 1.5606 -16.9522 -7.5871 0.7971 -0.1123 -5.4225 2.0180 -4.7658 -6.7637 10.0662 4.7674 -18.1453 63.4814 0.0000 0.0000 20.8075 4.6726 -0.8485 -0.2141 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -1.3682 10.8439 -11.1903 13.7119 12.6822 -55.9210 -0.0000 -0.0000 -2.2586 -3.4834 -4.3169 -6.9757 -0.0000 -0.0000 0.0000 0.0000 -0.0000 0.0000 -15.8850 3.4135 -0.5021 20.2394 0.0000 0.0000 -11.0925 3.8851 5.3566 3.8283 0.0000 0.0000 -20.2893 -9.4132 4.7151 25.2130 0.0000 0.0000 -1.8443 9.0191 -18.6390 -7.6722 0.0000 -0.0000 -0.1865 -112.9032 24.3669 -4.0012 5.1332 166.4016 0.1223 -2.7580 0.4235 -0.9308 -0.5240 0.2681 13.0747 2.7732 6.8962 -1.4186 -1.2819 1.7809 -16.4630 -9.3376 0.1696 -0.0757 -5.7288 2.0511 -5.2089 -6.9099 9.8528 4.1686 -18.3470 63.5983 0.0000 0.0000 21.7452 4.3590 -0.2404 -0.6639 -0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -2.1100 9.4901 -11.7745 12.2669 12.3413 -55.3911 -0.0000 -0.0000 -2.6466 -4.5212 -4.3646 -7.0188 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -15.8826 3.3896 -0.5855 20.0112 0.0000 0.0000 -10.8548 4.0666 5.2589 3.7825 0.0000 0.0000 -21.2363 -8.9499 3.5251 27.5808 0.0000 0.0000 -1.8404 8.7181 -20.1264 -7.3721 0.0000 -0.0000 -0.1453 -112.9949 24.3795 -3.9596 5.1987 167.2112 0.4760 -2.3072 0.3454 -0.7511 -0.2733 0.2386 12.7518 1.1217 6.2402 -1.5484 -2.1847 2.0359 -16.2685 -10.5834 -0.5977 0.1170 -5.8219 1.8297 -5.4578 -7.2164 9.7000 3.5712 -17.7715 63.5675 0.0000 0.0000 22.2115 3.8112 1.1437 -1.2235 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -2.6761 7.7304 -12.6184 11.1240 12.1877 -55.5327 -0.0000 -0.0000 -2.3239 -4.5900 -2.8306 -7.0099 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -15.9277 3.5957 -1.6338 19.9442 0.0000 0.0000 -10.4352 3.7843 5.4940 3.4652 0.0000 0.0000 -22.4329 -8.6265 3.9087 29.5833 0.0000 0.0000 -1.0896 8.9984 -20.5253 -7.3496 0.0000 -0.0000 -0.1333 -113.0746 24.3956 -3.9413 5.4159 168.0357 0.8686 -1.9602 0.2834 -0.5897 -0.0292 0.2302 12.4545 -0.2144 5.7392 -1.7069 -2.9401 2.2793 -16.3032 -11.6199 -1.4772 0.1874 -5.8954 1.4661 -5.5840 -7.4177 9.5976 2.8681 -17.6857 63.8472 0.0000 0.0000 21.6841 3.8445 2.3486 -1.8195 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -3.2852 6.0997 -13.6670 10.2113 11.6431 -55.8922 -0.0000 -0.0000 -1.5567 -3.4742 -0.2881 -6.8615 0.0000 0.0000 0.0000 0.0000 0.0000 -0.0000 -16.0104 4.0365 -2.6297 19.8664 0.0000 0.0000 -9.9168 3.2965 5.6760 3.0105 0.0000 0.0000 -23.3655 -8.1762 5.2035 30.5159 0.0000 0.0000 -0.5500 9.4383 -19.3794 -7.3878 0.0000 -0.0000 -0.1466 -113.1260 24.4218 -4.0170 5.7847 168.6197 1.1591 -1.7997 0.2334 -0.4781 0.1109 0.2174 12.1476 -1.0692 5.4557 -1.8197 -3.4362 2.4654 -16.4591 -12.6370 -2.2762 0.1511 -6.0198 1.1176 -5.8523 -7.2639 9.7349 2.2143 -19.4620 64.1681 0.0000 0.0000 20.5338 4.4315 2.8229 -2.3410 0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -4.0000 4.7640 -14.6257 9.6209 10.7101 -56.3007 -0.0000 -0.0000 -0.7324 -1.7652 1.8045 -6.7922 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -16.1333 4.5451 -3.0571 19.6779 0.0000 0.0000 -9.5820 3.1445 5.6369 2.7924 0.0000 0.0000 -23.8270 -7.5417 6.5533 30.0469 0.0000 0.0000 -0.6270 9.7480 -17.7474 -7.4499 0.0000 -0.0000 -0.1675 -113.1517 24.4518 -4.1614 6.1084 169.0502 1.3714 -1.7329 0.1800 -0.3782 0.1771 0.1950 11.7788 -1.7414 5.2550 -1.8785 -3.7927 2.6168 -16.6599 -13.5698 -2.8627 0.2012 -6.2132 0.8959 -6.2571 -6.7594 10.1873 1.8554 -22.1221 64.1281 0.0000 0.0000 19.5725 4.9555 2.7454 -2.6755 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -4.7166 3.4434 -15.2991 9.1096 10.1163 -56.7744 -0.0000 -0.0000 -0.1872 -0.4200 2.7104 -6.7200 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -16.1417 4.9293 -3.2870 19.2326 0.0000 0.0000 -9.3440 3.5385 5.5500 2.9450 0.0000 0.0000 -23.8841 -6.8876 7.2527 28.4004 0.0000 0.0000 -0.8099 9.8982 -16.8479 -7.7379 0.0000 -0.0000 -0.1823 -113.1735 24.4724 -4.3558 6.1869 169.5519 1.5820 -1.6970 0.1298 -0.2935 0.2437 0.1646 11.4089 -2.4737 5.0094 -1.9192 -4.1793 2.7793 -16.9232 -14.3886 -3.3422 0.3223 -6.4296 0.8135 -6.5472 -6.3535 10.6145 1.8733 -23.4627 64.0252 0.0000 0.0000 19.0709 5.1852 2.4053 -2.8887 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -5.3681 2.0898 -15.8197 8.3235 9.9868 -57.2221 -0.0000 -0.0000 -0.1224 0.1909 2.9673 -6.6151 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -15.9946 5.0455 -3.6802 18.5486 0.0000 0.0000 -9.0240 4.1949 5.4460 3.2902 0.0000 0.0000 -23.8360 -6.4418 7.1678 26.2698 0.0000 0.0000 -0.7324 9.9482 -16.9324 -8.1848 0.0000 -0.0000 -0.1927 -113.2025 24.4823 -4.6095 6.0395 170.2321 1.7885 -1.6844 0.0989 -0.2414 0.3527 0.1461 11.1115 -3.2501 4.7076 -1.9789 -4.6230 2.9477 -17.2756 -15.1345 -3.8746 0.3225 -6.6343 0.7688 -6.6358 -6.3754 10.6761 2.0896 -23.2078 64.3048 0.0000 0.0000 18.6009 5.3251 2.0331 -2.9846 0.0000 -0.0000 0.0000 0.0000 0.0000 -0.0000 -5.9547 1.0320 -16.3973 7.1442 9.8221 -57.5150 -0.0000 -0.0000 -0.5272 0.2648 3.1162 -6.6629 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -0.0000 -15.8302 4.9734 -4.2827 17.8540 0.0000 0.0000 -8.6986 4.6708 5.3270 3.5651 0.0000 0.0000 -23.9322 -6.2122 6.7849 24.3061 0.0000 0.0000 -0.5362 10.0209 -17.3864 -8.4175 0.0000 -0.0000 -0.2062 -113.2297 24.4907 -4.8973 5.8076 171.0230 1.9649 -1.7056 0.0702 -0.1911 0.4302 0.1291 10.8410 -3.8969 4.4254 -2.0689 -5.0074 3.0944 -17.6626 -15.8448 -4.4797 0.1772 -6.8273 0.6784 -6.6810 -6.6634 10.4877 2.2499 -22.9056 64.7230 0.0000 0.0000 17.9298 5.3296 1.7805 -2.9128 0.0000 0.0000 -0.0000 -0.0000 0.0000 -0.0000 -6.4573 0.2676 -17.0130 5.6884 9.6128 -57.7755 -0.0000 -0.0000 -1.1466 -0.2030 3.0683 -6.8535 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.7213 4.9117 -5.1669 17.2877 0.0000 0.0000 -8.4347 4.7247 5.3909 3.5961 0.0000 0.0000 -24.1672 -6.0459 6.6422 22.7513 0.0000 0.0000 -0.3968 10.2749 -17.4834 -8.2948 0.0000 -0.0000 -0.2341 -113.2449 24.5012 -5.1168 5.6793 171.7269 2.1766 -1.6753 0.0362 -0.0999 0.4788 0.1158 10.5097 -4.3887 4.2256 -2.2006 -5.2930 3.2194 -17.9582 -16.4264 -5.0162 0.0406 -7.0204 0.5457 -6.7484 -6.7981 10.3606 2.3626 -23.3335 64.8746 0.0000 0.0000 17.2988 5.0156 1.6300 -2.7379 0.0000 0.0000 0.0000 0.0000 -0.0000 -0.0000 -6.8844 -0.4558 -17.5029 4.2355 9.7160 -58.2023 -0.0000 -0.0000 -1.7193 -1.2394 2.7620 -7.0172 0.0000 0.0000 0.0000 -0.0000 -0.0000 0.0000 -15.6558 5.0554 -6.2133 16.9192 0.0000 0.0000 -8.1808 4.4014 5.7119 3.3748 0.0000 0.0000 -24.3006 -5.7293 6.8612 21.4806 0.0000 0.0000 -0.3494 10.6350 -16.9256 -8.0527 0.0000 -0.0000 -0.2866 -113.2515 24.5090 -5.2842 5.7032 172.2359 2.4259 -1.5428 -0.0011 0.0271 0.5416 0.1071 10.1117 -4.7972 4.1107 -2.3740 -5.5168 3.3362 -18.0984 -16.8303 -5.3887 -0.0252 -7.1848 0.4151 -6.7278 -6.7150 10.3875 2.5489 -23.7940 64.8187 0.0000 0.0000 16.8309 4.6580 1.3368 -2.5586 0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -7.2488 -1.1605 -17.7839 3.0739 9.9366 -58.8729 -0.0000 -0.0000 -2.1254 -2.2554 2.4738 -7.1481 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.7374 5.3827 -6.9452 16.8385 0.0000 0.0000 -7.9452 3.9035 5.9329 3.0336 0.0000 0.0000 -24.3166 -5.2238 7.1243 20.4661 0.0000 0.0000 -0.4316 10.8342 -15.9923 -7.9684 0.0000 -0.0000 -0.3615 -113.2502 24.5123 -5.4158 5.7336 172.6257 2.6491 -1.3957 -0.0368 0.1386 0.5951 0.0970 9.7802 -5.1354 4.0181 -2.5424 -5.7032 3.4205 -18.1264 -17.1043 -5.6130 -0.0968 -7.3063 0.2810 -6.5624 -6.6417 10.4975 2.7728 -23.7460 64.8386 0.0000 0.0000 16.2798 4.6508 0.7391 -2.3613 0.0000 -0.0000 -0.0000 -0.0000 0.0000 0.0000 -7.6009 -1.7164 -17.9262 2.3245 9.8861 -59.6951 -0.0000 -0.0000 -2.4082 -2.4817 2.4036 -7.2972 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 -15.8931 5.7076 -7.1956 16.9505 0.0000 0.0000 -7.8001 3.4034 5.8189 2.7293 0.0000 0.0000 -24.3108 -4.7013 7.0830 19.8481 0.0000 0.0000 -0.5675 10.7659 -15.2203 -8.0341 0.0000 -0.0000 -0.4442 -113.2380 24.5131 -5.5032 5.6135 172.9739 2.7755 -1.3334 -0.0568 0.2085 0.5776 0.0659 9.6053 -5.3996 3.9098 -2.6300 -5.8355 3.4659 -18.1125 -17.3228 -5.7531 -0.1684 -7.4078 0.1459 -6.3862 -6.6495 10.6653 2.9382 -23.6144 64.9031 0.0000 0.0000 15.5709 4.8274 0.0578 -2.1691 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -7.9351 -2.1871 -18.0298 1.8640 9.6221 -60.5245 -0.0000 -0.0000 -2.6451 -2.0370 2.5365 -7.3937 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -15.9233 5.8870 -7.3957 16.9963 0.0000 0.0000 -7.7096 2.9681 5.6766 2.5465 0.0000 0.0000 -24.3024 -4.3901 6.8362 19.6779 0.0000 0.0000 -0.5123 10.6025 -15.0206 -8.0608 0.0000 -0.0000 -0.5272 -113.2217 24.5086 -5.5756 5.2818 173.2059 2.8566 -1.3743 -0.0714 0.2630 0.5696 0.0592 9.4977 -5.6889 3.8082 -2.6461 -5.9716 3.5220 -18.1139 -17.5446 -5.8352 -0.1272 -7.4854 0.0545 -6.3770 -6.5943 10.8615 3.1109 -23.9154 64.8499 0.0000 0.0000 14.9388 4.7670 -0.3710 -2.1774 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -8.2410 -2.7114 -18.1118 1.5326 9.5784 -61.3038 -0.0000 -0.0000 -2.8457 -1.6141 2.7668 -7.3777 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -15.8091 5.8612 -7.8653 16.8427 0.0000 0.0000 -7.5665 2.5823 5.8532 2.4842 0.0000 0.0000 -24.3348 -4.4402 6.7428 19.9935 0.0000 0.0000 -0.1943 10.6357 -15.3718 -8.0846 0.0000 -0.0000 -0.6210 -113.2160 24.4942 -5.6918 4.7710 173.2006 3.0375 -1.3972 -0.0641 0.3508 0.5567 0.0498 9.2923 -5.9754 3.8234 -2.6853 -6.2256 3.6663 -18.2022 -17.8631 -5.9027 0.0040 -7.4715 0.0425 -6.5182 -6.5179 10.9905 3.3124 -24.4449 64.6949 0.0000 0.0000 14.4251 4.5974 -0.5108 -2.4134 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -8.5140 -3.2532 -18.1812 1.2513 9.9919 -62.0961 -0.0000 -0.0000 -2.9812 -1.4894 2.9358 -7.3344 -0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -15.7506 5.6321 -8.3196 16.6225 0.0000 0.0000 -7.3817 2.2044 6.2132 2.4889 0.0000 0.0000 -24.6283 -4.8400 6.8939 21.0763 0.0000 0.0000 0.1618 10.9584 -15.7593 -8.3452 0.0000 -0.0000 -0.7363 -113.2214 24.4698 -5.7661 4.1148 172.9605 3.4120 -1.3947 -0.0193 0.5325 0.5887 0.0610 8.9811 -6.2993 3.9836 -2.7911 -6.5942 3.9179 -18.4075 -18.3297 -5.9883 0.0363 -7.3314 0.1088 -6.7388 -6.5153 11.0759 3.3897 -24.9418 64.4041 0.0000 0.0000 13.8670 4.8841 -0.3620 -2.6552 0.0000 -0.0000 0.0000 0.0000 -0.0000 -0.0000 -8.7841 -3.7569 -18.2509 1.0255 10.7910 -62.9842 -0.0000 -0.0000 -3.0946 -1.5014 3.0016 -7.3397 0.0000 0.0000 -0.0000 0.0000 0.0000 -0.0000 -15.7199 5.2191 -8.3437 16.4321 0.0000 0.0000 -7.2272 1.8333 6.3626 2.5028 0.0000 0.0000 -25.2693 -5.4904 7.0926 23.2082 0.0000 0.0000 0.3463 11.2713 -15.6923 -8.7232 0.0000 -0.0000 -0.8691 -113.2246 24.4368 -5.6905 3.2484 172.5958 3.9226 -1.5055 0.0542 0.7869 0.5808 0.0704 8.7267 -6.6149 4.2730 -2.9042 -6.9980 4.2326 -18.6648 -18.9224 -6.0631 -0.1041 -7.1520 0.2404 -6.8767 -6.6474 11.1859 3.1512 -25.1967 63.9708 0.0000 0.0000 13.2452 5.4540 0.2646 -2.8891 0.0000 -0.0000 -0.0000 0.0000 0.0000 -0.0000 -9.1169 -4.2813 -18.3338 0.9611 11.6249 -63.9384 -0.0000 -0.0000 -3.2539 -1.6157 3.2319 -7.3587 0.0000 -0.0000 0.0000 -0.0000 -0.0000 0.0000 -15.4882 4.5741 -7.9698 16.1660 0.0000 0.0000 -7.0610 1.4918 6.1737 2.4986 0.0000 0.0000 -26.0617 -6.3807 7.2578 26.1900 0.0000 0.0000 0.1832 11.1191 -15.3150 -8.7410 0.0000 -0.0000 -1.0306 -113.2160 24.3971 -5.5750 2.2767 172.1607 4.3776 -1.6770 0.1241 1.0049 0.5605 0.0767 8.6612 -6.9861 4.5963 -2.9643 -7.3951 4.5506 -18.9058 -19.6167 -6.0917 -0.2455 -7.0580 0.4180 -6.9522 -6.8791 11.2777 2.7806 -25.3362 63.5555 0.0000 0.0000 12.7553 5.6442 1.2482 -3.4196 0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -9.5504 -4.8096 -18.4089 1.1838 12.0060 -64.8730 -0.0000 -0.0000 -3.3792 -1.8077 3.8191 -7.3969 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -15.1759 3.8814 -7.4821 15.8718 0.0000 0.0000 -6.8573 1.1019 5.8999 2.4786 0.0000 0.0000 -26.7684 -7.3152 7.5307 29.2761 0.0000 0.0000 -0.7314 10.3813 -14.9624 -8.3753 0.0000 -0.0000 -1.2454 -113.1950 24.3535 -5.6508 1.3878 171.7100 4.6196 -1.7186 0.1594 1.1013 0.5984 0.0823 8.7396 -7.4287 4.8055 -2.9812 -7.8194 4.8249 -19.1400 -20.4272 -6.1516 -0.2364 -7.0562 0.5921 -7.0664 -7.2209 11.2684 2.5731 -25.5835 63.3825 0.0000 0.0000 12.3295 5.3575 1.9419 -4.0661 -0.0000 0.0000 -0.0000 0.0000 0.0000 0.0000 -10.0204 -5.2474 -18.5023 1.6006 11.8177 -65.6821 -0.0000 -0.0000 -3.3157 -1.7326 4.5093 -7.5298 0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -15.1473 3.4193 -7.0595 15.7533 0.0000 0.0000 -6.6820 0.5214 5.7558 2.4454 0.0000 0.0000 -27.3739 -7.9653 7.8330 31.7106 0.0000 0.0000 -2.5997 9.5543 -14.3243 -8.2659 0.0000 -0.0000 -1.5090 -113.1567 24.3060 -5.8651 0.6122 171.3215 4.7287 -1.6421 0.1810 1.1644 0.7115 0.0896 8.7708 -7.8733 4.8007 -2.9932 -8.2631 5.0387 -19.3525 -21.3177 -6.3024 -0.1535 -7.0104 0.7205 -7.1587 -7.6371 11.2817 2.5031 -25.9894 63.3388 0.0000 0.0000 11.7110 5.0030 2.2526 -4.0166 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -10.3822 -5.5829 -18.6490 1.8778 11.4993 -66.2481 -0.0000 -0.0000 -3.1168 -1.2172 5.0565 -7.6831 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 -15.3710 3.2147 -6.6182 15.8927 0.0000 0.0000 -6.6341 -0.2243 5.6074 2.4255 0.0000 0.0000 -27.6668 -8.2435 7.9479 32.8610 0.0000 0.0000 -4.6398 9.1712 -12.8919 -8.8088 0.0000 -0.0000 -1.7863 -113.1008 24.2411 -6.2042 -0.2932 170.9659 4.7962 -1.6730 0.2111 1.2124 0.8121 0.0808 8.6396 -8.3143 4.6978 -3.0450 -8.6806 5.1941 -19.4676 -22.2426 -6.4371 -0.1162 -6.7991 0.8314 -7.0027 -8.0941 11.5034 2.3911 -26.3146 63.1544 0.0000 0.0000 10.9068 4.5530 3.5225 -3.0575 0.0000 0.0000 -0.0000 0.0000 -0.0000 -0.0000 -10.5963 -5.7949 -18.8274 1.8942 11.3625 -66.4370 -0.0000 -0.0000 -3.1351 -0.7584 5.5511 -7.6733 0.0000 -0.0000 0.0000 -0.0000 0.0000 -0.0000 -15.7702 2.8793 -5.9332 16.2618 0.0000 0.0000 -6.7580 -0.9424 5.1542 2.4500 0.0000 0.0000 -27.4614 -8.6120 7.9874 32.4616 0.0000 0.0000 -5.9235 9.0376 -11.2851 -9.4232 0.0000 -0.0000 -2.0794 -113.0299 24.1507 -6.8805 -1.3788 170.4801 4.7027 -1.6579 0.2053 1.1655 0.9296 0.0692 8.3650 -8.9239 4.6366 -3.1562 -9.1370 5.3344 -19.5729 -23.2843 -6.5262 -0.0730 -6.4967 0.9644 -6.5598 -8.8408 11.7749 2.3262 -26.3292 62.9330 0.0000 0.0000 10.0790 3.3101 7.1431 -2.1788 -0.0000 0.0000 -0.0000 -0.0000 -0.0000 0.0000 -10.6953 -5.6717 -19.0896 1.9754 10.8718 -66.1553 -0.0000 -0.0000 -3.6931 -1.0008 5.7890 -7.5582 -0.0000 0.0000 -0.0000 0.0000 -0.0000 0.0000 -16.5662 2.3134 -5.0334 16.8543 0.0000 0.0000 -7.0443 -1.6560 4.5228 2.4634 0.0000 0.0000 -26.8981 -9.2904 8.3650 30.8461 0.0000 0.0000 -6.6891 8.5081 -10.8510 -9.2187 0.0000 -0.0000 -2.4270 -112.9466 24.0570 -8.0371 -2.2435 169.9019 4.2131 -1.0467 0.0911 0.9020 1.2072 0.0863 8.1546 -9.7572 4.5549 -3.2742 -9.7660 5.5026 -20.0235 -24.5230 -6.9225 0.0724 -6.3238 1.0895 -6.2040 -10.2128 11.7096 2.5607 -26.1881 62.9682 0.0000 0.0000 9.1337 1.4543 12.6997 -2.2492 0.0000 0.0000 0.0000 -0.0000 0.0000 0.0000 -10.6992 -5.0900 -19.7499 2.4942 9.3694 -65.3342 -0.0000 -0.0000 -4.8057 -1.8859 4.9009 -7.6259 0.0000 0.0000 0.0000 -0.0000 0.0000 -0.0000 -17.8783 2.0764 -4.4197 17.4740 0.0000 0.0000 -7.3372 -2.6668 4.2969 2.3335 0.0000 0.0000 -26.5322 -9.6428 8.9723 28.9242 0.0000 0.0000 -7.8374 7.3520 -11.6254 -8.1777 0.0000 -0.0000 -2.7957 -112.8545 24.0007 -9.1618 -2.5305 169.5924 3.4844 0.2447 -0.1027 0.5052 1.6113 0.1324 8.2166 -10.4683 4.3002 -3.3004 -10.5162 5.6783 -21.0047 -25.7229 -7.9316 0.2661 -6.3794 1.1397 -6.2894 -11.9344 11.2194 3.0223 -26.2301 63.2269 0.0000 0.0000 7.9699 0.3563 17.9863 -3.1337 -0.0000 -0.0000 -0.0000 0.0000 -0.0000 -0.0000 -10.6367 -4.3916 -21.0184 3.3554 7.2801 -64.0320 -0.0000 -0.0000 -6.1852 -2.8049 2.5370 -7.9483 -0.0000 0.0000 -0.0000 -0.0000 0.0000 0.0000 -18.9928 2.6280 -4.5304 17.6728 0.0000 0.0000 -7.4071 -3.9720 4.7432 2.0511 0.0000 0.0000 -26.5675 -9.0491 9.1003 27.5870 0.0000 0.0000 -9.3007 5.9461 -12.1104 -7.0772 0.0000 -0.0000 -3.0587 -112.7812 23.9912 -9.7384 -2.4169 169.7111 2.8909 1.3978 -0.2279 0.2159 1.9806 0.1824 8.4843 -10.7557 3.9761 -3.2297 -11.0579 5.7862 -22.0824 -26.4590 -9.1423 0.3553 -6.5326 1.1151 -6.6959 -13.1551 10.6297 3.3972 -26.5336 63.4323 0.0000 0.0000 6.9529 0.3824 20.8984 -3.8625 -0.0000 -0.0000 0.0000 -0.0000 0.0000 0.0000 -10.5862 -4.0609 -22.4528 4.0487 5.7802 -62.7192 -0.0000 -0.0000 -7.3311 -3.3573 -0.0031 -8.2389 0.0000 0.0000 0.0000 0.0000 -0.0000 0.0000 -19.3537 3.4984 -5.0777 17.4115 0.0000 0.0000 -7.2628 -5.0103 5.3638 1.7985 0.0000 0.0000 -26.8311 -8.0164 8.6075 27.1461 0.0000 0.0000 -10.1003 4.8465 -11.5585 -6.5691 0.0000 -0.0000 ================================================ FILE: projects/animated_drawings/characters/slamdunk/char_cfg.yaml ================================================ height: 512 skeleton: - loc: - 260 - 230 name: root parent: null - loc: - 260 - 230 name: hip parent: root - loc: - 257 - 93 name: torso parent: hip - loc: - 250 - 54 name: neck parent: torso - loc: - 213 - 95 name: right_shoulder parent: torso - loc: - 172 - 157 name: right_elbow parent: right_shoulder - loc: - 145 - 228 name: right_hand parent: right_elbow - loc: - 302 - 88 name: left_shoulder parent: torso - loc: - 342 - 150 name: left_elbow parent: left_shoulder - loc: - 373 - 212 name: left_hand parent: left_elbow - loc: - 231 - 230 name: right_hip parent: root - loc: - 212 - 341 name: right_knee parent: right_hip - loc: - 192 - 454 name: right_foot parent: right_knee - loc: - 290 - 231 name: left_hip parent: root - loc: - 303 - 338 name: left_knee parent: left_hip - loc: - 325 - 452 name: left_foot parent: left_knee width: 512 ================================================ FILE: projects/animated_drawings/configs/motion/zombie.yaml ================================================ filepath: bvh/zombie.bvh start_frame_idx: 0 end_frame_idx: 320 groundplane_joint: LeftFoot forward_perp_joint_vectors: - - LeftShoulder - RightShoulder - - LeftUpLeg - RightUpLeg scale: 0.025 up: +z ================================================ FILE: projects/animated_drawings/configs/mvc/slamdunk.yaml ================================================ scene: ANIMATED_CHARACTERS: - character_cfg: characters/slamdunk/char_cfg.yaml motion_cfg: configs/motion/zombie.yaml retarget_cfg: configs/retarget/fair1_spf.yaml view: CAMERA_POS: [1.6, 1.7, 4.0] CAMERA_FWD: [0.0, 0.5, 2.0] BACKGROUND_IMAGE: resources/basketball_playground.png controller: MODE: video_render OUTPUT_VIDEO_PATH: ./resources/slamdunk_video.mp4 OUTPUT_VIDEO_CODEC: mp4v ================================================ FILE: projects/animated_drawings/configs/retarget/fair1_spf.yaml ================================================ char_starting_location: [0.0, 0.0, 0.0] bvh_projection_bodypart_groups: - bvh_joint_names: - RightShoulder - RightArm - RightForeArm - RightHand - RightHandEnd - LeftShoulder - LeftArm - LeftForeArm - LeftHand - LeftHandEnd method: sagittal name: Upper Limbs - bvh_joint_names: - RightUpLeg - RightLeg - RightFoot - RightToeBase - LeftUpLeg - LeftLeg - LeftFoot - LeftToeBase method: pca name: Lower Limbs - bvh_joint_names: - Hips - Spine - Spine1 - Spine2 - Spine3 - Neck - Head method: frontal name: Trunk char_bodypart_groups: - bvh_depth_drivers: - Hips char_joints: - right_shoulder - left_shoulder - right_hip - left_hip - hip - torso - neck - bvh_depth_drivers: - LeftHand char_joints: - left_elbow - left_hand - bvh_depth_drivers: - RightHand char_joints: - right_elbow - right_hand - bvh_depth_drivers: - LeftFoot char_joints: - left_knee - left_foot - bvh_depth_drivers: - RightFoot char_joints: - right_knee - right_foot char_bvh_root_offset: bvh_projection_bodypart_group_for_offset: Lower Limbs bvh_joints: - - RightFoot - RightLeg - RightUpLeg - - LeftFoot - LeftLeg - LeftUpLeg char_joints: - - left_foot - left_knee - left_hip - - right_foot - right_knee - right_hip char_joint_bvh_joints_mapping: left_elbow: !!python/tuple - LeftArm - LeftForeArm left_foot: !!python/tuple - LeftLeg - LeftFoot left_hand: !!python/tuple - LeftForeArm - LeftHand left_knee: !!python/tuple - LeftUpLeg - LeftLeg torso: !!python/tuple - Hips - Spine3 neck: !!python/tuple - Hips - Neck right_elbow: !!python/tuple - RightArm - RightForeArm right_foot: !!python/tuple - RightLeg - RightFoot right_hand: !!python/tuple - RightForeArm - RightHand right_knee: !!python/tuple - RightUpLeg - RightLeg char_runtime_checks: - - above - neck - right_shoulder - left_shoulder ================================================ FILE: projects/animated_drawings/tools/generate_character.py ================================================ import os from argparse import ArgumentParser import cv2 import numpy as np import PIL.Image as Image import torch import yaml from controlnet_aux import OpenposeDetector from controlnet_aux.open_pose.face import faceDetect from controlnet_aux.open_pose.hand import handDetect from controlnet_aux.open_pose.util import (HWC3, draw_bodypose, draw_facepose, draw_handpose, resize_image) def draw_pose(pose, H, W, draw_body=True, draw_hand=True, draw_face=True): bodies = pose['bodies'] faces = pose['faces'] hands = pose['hands'] candidate = bodies['candidate'] subset = bodies['subset'] canvas = np.zeros(shape=(H, W, 3), dtype=np.uint8) if draw_body: canvas = draw_bodypose(canvas, candidate, subset) if draw_hand: canvas = draw_handpose(canvas, hands) if draw_face: canvas = draw_facepose(canvas, faces) return canvas class OpenposeDetectorPoint(OpenposeDetector): def __call__(self, input_image, detect_resolution=512, image_resolution=512, hand_and_face=False, return_pil=True): # hand = False if not isinstance(input_image, np.ndarray): input_image = np.array(input_image, dtype=np.uint8) input_image = HWC3(input_image) input_image = resize_image(input_image, detect_resolution) input_image = input_image[:, :, ::-1].copy() H, W, C = input_image.shape with torch.no_grad(): candidate, subset = self.body_estimation(input_image) hands = [] faces = [] if hand_and_face: # Hand hands_list = handDetect(candidate, subset, input_image) for x, y, w, is_left in hands_list: peaks = self.hand_estimation( input_image[y:y + w, x:x + w, :]).astype(np.float32) if peaks.ndim == 2 and peaks.shape[1] == 2: peaks[:, 0] = np.where(peaks[:, 0] < 1e-6, -1, peaks[:, 0] + x) / float(W) peaks[:, 1] = np.where(peaks[:, 1] < 1e-6, -1, peaks[:, 1] + y) / float(H) hands.append(peaks.tolist()) # Face faces_list = faceDetect(candidate, subset, input_image) for x, y, w in faces_list: heatmaps = self.face_estimation(input_image[y:y + w, x:x + w, :]) peaks = self.face_estimation.compute_peaks_from_heatmaps( heatmaps).astype(np.float32) if peaks.ndim == 2 and peaks.shape[1] == 2: peaks[:, 0] = np.where(peaks[:, 0] < 1e-6, -1, peaks[:, 0] + x) / float(W) peaks[:, 1] = np.where(peaks[:, 1] < 1e-6, -1, peaks[:, 1] + y) / float(H) faces.append(peaks.tolist()) if candidate.ndim == 2 and candidate.shape[1] == 4: candidate = candidate[:, :2] candidate[:, 0] /= float(W) candidate[:, 1] /= float(H) bodies = dict(candidate=candidate.tolist(), subset=subset.tolist()) pose = dict(bodies=bodies, hands=hands, faces=faces) canvas = draw_pose(pose, H, W) detected_map = HWC3(canvas) img = resize_image(input_image, image_resolution) H, W, C = img.shape detected_map = cv2.resize( detected_map, (W, H), interpolation=cv2.INTER_NEAREST) if return_pil: detected_map = Image.fromarray(detected_map) return detected_map, candidate, subset def parse_args(): parser = ArgumentParser() parser.add_argument( '--chardir', type=str, default='characters', help='Characters root dir.') parser.add_argument( '--charname', type=str, default='slamdunk', help='Character name.') parser.add_argument( '--img', type=str, default='resources/sakuragi.png', help='Img name.') parser.add_argument( '--mask', type=str, default='resources/sakuragi_mask.png', help='Img mask name.') args, unknown = parser.parse_known_args() return args, unknown def main(): args, unknown = parse_args() detect_resolution = 512 control_detector = 'lllyasviel/ControlNet' posedet = OpenposeDetectorPoint.from_pretrained(control_detector) char_root_dir = args.chardir char_name = args.charname image_name = args.img mask_name = args.mask image = Image.open(image_name) detected_map, candidate, subset = posedet(image) pose_name = 'pose.png' detected_map.save(os.path.join(char_root_dir, char_name, pose_name)) # resize image image_np = np.array(image, dtype=np.uint8) image_np = HWC3(image_np) image_np = resize_image(image_np, detect_resolution) image_resized = Image.fromarray(image_np) image_resized.save(os.path.join(char_root_dir, char_name, 'texture.png')) # resize mask image mask = Image.open(mask_name) mask_np = np.array(mask, dtype=np.uint8) mask_np = HWC3(mask_np) mask_np = resize_image(mask_np, detect_resolution) image_resized = Image.fromarray(mask_np) image_resized.save(os.path.join(char_root_dir, char_name, 'mask.png')) W, H = image_resized.size config_file = os.path.join(char_root_dir, char_name, 'char_cfg.yaml') config_dict = {} config_dict['width'] = detected_map.size[0] config_dict['height'] = detected_map.size[1] # yapf: disable kpts = candidate kpts[:, 0] = kpts[:, 0] * W kpts[:, 1] = kpts[:, 1] * H skeleton = [] skeleton.append({'loc' : [round(x) for x in (kpts[8]+kpts[11])/2], 'name': 'root' , 'parent': None}) # noqa skeleton.append({'loc' : [round(x) for x in (kpts[8]+kpts[11])/2], 'name': 'hip' , 'parent': 'root'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[1] ], 'name': 'torso' , 'parent': 'hip'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[0] ], 'name': 'neck' , 'parent': 'torso'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[2] ], 'name': 'right_shoulder', 'parent': 'torso'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[3] ], 'name': 'right_elbow' , 'parent': 'right_shoulder'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[4] ], 'name': 'right_hand' , 'parent': 'right_elbow'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[5] ], 'name': 'left_shoulder' , 'parent': 'torso'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[6] ], 'name': 'left_elbow' , 'parent': 'left_shoulder'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[7] ], 'name': 'left_hand' , 'parent': 'left_elbow'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[8] ], 'name': 'right_hip' , 'parent': 'root'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[9] ], 'name': 'right_knee' , 'parent': 'right_hip'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[10] ], 'name': 'right_foot' , 'parent': 'right_knee'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[11] ], 'name': 'left_hip' , 'parent': 'root'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[12] ], 'name': 'left_knee' , 'parent': 'left_hip'}) # noqa skeleton.append({'loc' : [round(x) for x in kpts[13] ], 'name': 'left_foot' , 'parent': 'left_knee'}) # noqa # yapf: enable config_dict['skeleton'] = skeleton with open(config_file, 'w') as file: yaml.dump(config_dict, file) if __name__ == '__main__': main() ================================================ FILE: projects/animated_drawings/tools/generate_video.py ================================================ from animated_drawings import render render.start('./configs/mvc/slamdunk.yaml') ================================================ FILE: projects/example_project/README.md ================================================ # Example Project This is an example README for community `projects/`. You can write your README in your own project. Here are some recommended parts of a README for others to understand and use your project, you can copy or modify them according to your project. ## Description \[required\] You can share any information you would like others to know. For example: ``` Author: @xxx. This is an implementation of \[XXX\]. ``` ## Usage \[required\] ### Setup Environment \[required\] Please refer to [Get Started](https://mmagic.readthedocs.io/en/latest/get_started/I.html) to install MMagic. At first, add the current folder to `PYTHONPATH`, so that Python can find your code. Run command in the current directory to add it. > Please run it every time after you opened a new shell. ```shell export PYTHONPATH=`pwd`:$PYTHONPATH ``` ### Data Preparation \[optional\] Prepare the ImageNet-2012 dataset according to the [instruction](https://mmagic.readthedocs.io/en/latest/user_guides/dataset_prepare.html#imagenet). ### Training commands \[optional\] **To train with single GPU:** ```bash mim train mmagic configs/examplenet_8xb32_in1k.py ``` **To train with multiple GPUs:** ```bash mim train mmagic configs/examplenet_8xb32_in1k.py --launcher pytorch --gpus 8 ``` **To train with multiple GPUs by slurm:** ```bash mim train mmagic configs/examplenet_8xb32_in1k.py --launcher slurm \ --gpus 16 --gpus-per-node 8 --partition $PARTITION ``` ### Testing commands \[required\] **To test with single GPU:** ```bash mim test mmagic configs/examplenet_8xb32_in1k.py $CHECKPOINT ``` **To test with multiple GPUs:** ```bash mim test mmagic configs/examplenet_8xb32_in1k.py $CHECKPOINT --launcher pytorch --gpus 8 ``` **To test with multiple GPUs by slurm:** ```bash mim test mmagic configs/examplenet_8xb32_in1k.py $CHECKPOINT --launcher slurm \ --gpus 16 --gpus-per-node 8 --partition $PARTITION ``` ## Results \[required\] | Model | Pretrain | Top-1 (%) | Top-5 (%) | Config | Download | | :----------------: | :----------: | :-------: | :-------: | :----------------------------------------: | :------------------------------------: | | ExampleNet-tiny | From scratch | 82.33 | 96.15 | [config](configs/examplenet_8xb32_in1k.py) | [model](MODEL-LINK) \| [log](LOG-LINK) | | ExampleNet-small\* | From scratch | 83.63 | 96.51 | [config](configs/examplenet_8xb32_in1k.py) | [model](MODEL-LINK) | | ExampleNet-base\* | From scratch | 84.34 | 96.86 | [config](configs/examplenet_8xb32_in1k.py) | [model](MODEL-LINK) | *Models with * are converted from the [official repo](REPO-LINK). The config files of these models are only for inference. We don't ensure these config files' training accuracy and welcome you to contribute your reproduction results.* You can also paste some visual results here if the model doesn't have quantitative results. ## Citation \[required\] ```bibtex @misc{mmagic2023, title = {{MMagic}: {OpenMMLab} Multimodal Advanced, Generative, and Intelligent Creation Toolbox}, author = {{MMagic Contributors}}, howpublished = {\url{https://github.com/open-mmlab/mmagic}}, year = {2023} } ``` ## Checklist \[required\] Here is a checklist of this project's progress. And you can ignore this part if you don't plan to contribute to MMagic projects. - [ ] Milestone 1: PR-ready, and acceptable to be one of the `projects/`. - [ ] Finish the code - [ ] Basic docstrings & proper citation - [ ] Converted checkpoint and results (Only for reproduction) - [ ] Milestone 2: Indicates a successful model implementation. - [ ] Training results - [ ] Milestone 3: Good to be a part of our core package! - [ ] Unit tests - [ ] Code style - [ ] `metafile.yml` and `README.md` ================================================ FILE: projects/example_project/configs/examplenet_8xb32_in1k.py ================================================ # Directly inherit the entire recipe you want to use. _base_ = 'mmagic::srcnn/srcnn_x4k915_1xb16-1000k_div2k.py' # This line is to import your own modules. custom_imports = dict(imports='models') # Set your model, training, testing configurations. ================================================ FILE: projects/example_project/models/__init__.py ================================================ from .example_net import ExampleNet __all__ = ['ExampleNet'] ================================================ FILE: projects/example_project/models/example_net.py ================================================ from mmagic.models import ResNet from mmagic.registry import MODELS # Register your model to the `MODELS`. @MODELS.register_module() class ExampleNet(ResNet): """Implements an example backbone. Implement the backbone network just like a normal pytorch network. """ def __init__(self, **kwargs) -> None: print('#############################\n' '# Hello MMagic! #\n' '#############################') super().__init__(**kwargs) def forward(self, x): """The forward method of the network. Args: x (torch.Tensor): A tensor of image batch with shape ``(batch_size, num_channels, height, width)``. Returns: Tuple[torch.Tensor]: Please return a tuple of tensors and every tensor is a feature map of specified scale. If you only want the final feature map, simply return a tuple with one item. """ return super().forward(x) ================================================ FILE: projects/flow_style_vton/.gitignore ================================================ *.jpg *.zip ================================================ FILE: projects/flow_style_vton/README.md ================================================ # Style-Based Global Appearance Flow for Virtual Try-On (CVPR 2022) ## Description Awesome try-on desplays are like this: ![image1](examples/000010_0.png) ``` Author: @FerryHuang. This is an implementation of https://github.com/SenHe/Flow-Style-VTON adapting to mmediting. Only inference is supported so far. ``` ## Usage ### Setup Environment Please refer to [Get Started](https://mmediting.readthedocs.io/en/latest/get_started/I.html) to install MMEditing. At first, add the current folder to `PYTHONPATH`, so that Python can find your code. Run command in the current directory to add it. > Please run it every time after you opened a new shell. ```shell export PYTHONPATH=`pwd`:$PYTHONPATH ``` ### Data Preparation Please check the [official repo](https://github.com/SenHe/Flow-Style-VTON) and download test-set and pretrained checkpoints and put them under the folder projects/flow_style_vton ### Testing commands **To test with single GPU:** ```bash cd projects/flow_style_vton python inference.py ``` Expectedly, two folders will be made im_gar_flow_wg and our_t_results, containing the try-on procedures and the final results, respectively. ## Citation ```bibtex @inproceedings{he2022fs_vton, title={Style-Based Global Appearance Flow for Virtual Try-On}, author={He, Sen and Song, Yi-Zhe and Xiang, Tao}, booktitle={CVPR}, year={2022} } ``` ## Checklist \[required\] Here is a checklist of this project's progress. And you can ignore this part if you don't plan to contribute to MMediting projects. - [ ] Milestone 1: PR-ready, and acceptable to be one of the `projects/`. - [ ] Finish the code - [ ] Basic docstrings & proper citation - [ ] Converted checkpoint and results (Only for reproduction) - [ ] Milestone 2: Indicates a successful model implementation. - [ ] Training results - [ ] Milestone 3: Good to be a part of our core package! - [ ] Unit tests - [ ] Code style - [ ] `metafile.yml` and `README.md` ================================================ FILE: projects/flow_style_vton/configs/flow_style_vton_PFAFN_epoch_101.py ================================================ model = dict( type='FlowStyleVTON', warp_model=dict(type='AFWM', input_nc=3), gen_model=dict( type='ResUnetGenerator', input_nc=7, output_nc=4, num_downs=5), pretrained_cfgs=dict( warp_model=dict(ckpt_path='ckp/aug/PFAFN_warp_epoch_101.pth'), gen_model=dict(ckpt_path='ckp/aug/PFAFN_gen_epoch_101.pth'))) ================================================ FILE: projects/flow_style_vton/inference.py ================================================ import os from argparse import ArgumentParser import torch from mmengine.registry import init_default_scope from torch.utils.data import DataLoader from torchvision.utils import save_image from tqdm import tqdm from vton_dataset import AlignedDataset from mmagic.apis.inferencers.inference_functions import init_model from projects.flow_style_vton.models import FlowStyleVTON init_default_scope('mmagic') config = 'configs/flow_style_vton_PFAFN_epoch_101.py' parser = ArgumentParser() parser.add_argument('--gpu_id', type=int, default=0) parser.add_argument( '--loadSize', type=int, default=512, help='scale images to this size') parser.add_argument( '--fineSize', type=int, default=512, help='then crop to this size') parser.add_argument('--dataroot', type=str, default='VITON_test') parser.add_argument('--test_pairs', type=str, default='test_pairs.txt') parser.add_argument( '--resize_or_crop', type=str, default='scale_width', help='scaling and cropping of images at load time \ [resize_and_crop|crop|scale_width|scale_width_and_crop]') parser.add_argument('--phase', type=str, default='test') parser.add_argument('--isTrain', default=False) parser.add_argument( '--no_flip', action='store_true', help='if specified, do not flip the images for data argumentation') parser.add_argument('--batch_size', type=int, default=1) parser.add_argument('--num_workers', type=int, default=4) parser.add_argument('--output_dir', type=str, default='inference_results') opt = parser.parse_args() dataset = AlignedDataset(opt) dataloader = DataLoader(dataset, opt.batch_size, num_workers=opt.num_workers) device = torch.device( f'cuda:{opt.gpu_id}' if torch.cuda.is_available() else 'cpu') # pretrained is set inside the config model = init_model(config).to(device).eval() assert isinstance(model, FlowStyleVTON) os.makedirs('our_t_results', exist_ok=True) os.makedirs('im_gar_flow_wg', exist_ok=True) for i, data in enumerate(tqdm(dataloader)): p_tryon, combine = model.infer(data) save_image( p_tryon, os.path.join('our_t_results', data['p_name'][0]), nrow=int(1), normalize=True, value_range=(-1, 1)) save_image( combine, os.path.join('im_gar_flow_wg', data['p_name'][0]), nrow=int(1), normalize=True, range=(-1, 1), ) ================================================ FILE: projects/flow_style_vton/models/__init__.py ================================================ from .afwm import AFWM from .flow_style_vton_model import FlowStyleVTON from .generator import ResUnetGenerator __all__ = ['FlowStyleVTON', 'AFWM', 'ResUnetGenerator'] ================================================ FILE: projects/flow_style_vton/models/afwm.py ================================================ from math import sqrt import torch import torch.nn as nn import torch.nn.functional as F from mmagic.registry import MODELS @MODELS.register_module() class AFWM(nn.Module): def __init__(self, input_nc): super(AFWM, self).__init__() num_filters = [64, 128, 256, 256, 256] self.image_features = FeatureEncoder(3, num_filters) self.cond_features = FeatureEncoder(input_nc, num_filters) self.image_FPN = RefinePyramid(num_filters) self.cond_FPN = RefinePyramid(num_filters) self.aflow_net = AFlowNet(len(num_filters)) def forward(self, cond_input, image_input): # import ipdb; ipdb.set_trace() cond_pyramids = self.cond_FPN( self.cond_features(cond_input)) # maybe use nn.Sequential image_pyramids = self.image_FPN(self.image_features(image_input)) x_warp, last_flow = self.aflow_net(image_input, image_pyramids, cond_pyramids) return x_warp, last_flow def apply_offset(offset): sizes = list(offset.size()[2:]) grid_list = torch.meshgrid( [torch.arange(size, device=offset.device) for size in sizes]) grid_list = reversed(grid_list) # apply offset grid_list = [ grid.float().unsqueeze(0) + offset[:, dim, ...] for dim, grid in enumerate(grid_list) ] # normalize grid_list = [ grid / ((size - 1.0) / 2.0) - 1.0 for grid, size in zip(grid_list, reversed(sizes)) ] return torch.stack(grid_list, dim=-1) def TVLoss(x): tv_h = x[:, :, 1:, :] - x[:, :, :-1, :] tv_w = x[:, :, :, 1:] - x[:, :, :, :-1] return torch.mean(torch.abs(tv_h)) + torch.mean(torch.abs(tv_w)) # backbone class EqualLR: def __init__(self, name): self.name = name def compute_weight(self, module): weight = getattr(module, self.name + '_orig') fan_in = weight.data.size(1) * weight.data[0][0].numel() return weight * sqrt(2 / fan_in) @staticmethod def apply(module, name): fn = EqualLR(name) weight = getattr(module, name) del module._parameters[name] module.register_parameter(name + '_orig', nn.Parameter(weight.data)) module.register_forward_pre_hook(fn) return fn def __call__(self, module, input): weight = self.compute_weight(module) setattr(module, self.name, weight) def equal_lr(module, name='weight'): EqualLR.apply(module, name) return module class EqualLinear(nn.Module): def __init__(self, in_dim, out_dim): super().__init__() linear = nn.Linear(in_dim, out_dim) linear.weight.data.normal_() linear.bias.data.zero_() self.linear = equal_lr(linear) def forward(self, input): return self.linear(input) class ModulatedConv2d(nn.Module): def __init__(self, fin, fout, kernel_size, padding_type='zero', upsample=False, downsample=False, latent_dim=512, normalize_mlp=False): super(ModulatedConv2d, self).__init__() self.in_channels = fin self.out_channels = fout self.kernel_size = kernel_size padding_size = kernel_size // 2 if kernel_size == 1: self.demudulate = False else: self.demudulate = True self.weight = nn.Parameter( torch.Tensor(fout, fin, kernel_size, kernel_size)) self.bias = nn.Parameter(torch.Tensor(1, fout, 1, 1)) if not normalize_mlp: self.mlp_class_std = EqualLinear(latent_dim, fin) if padding_type == 'reflect': self.padding = nn.ReflectionPad2d(padding_size) else: self.padding = nn.ZeroPad2d(padding_size) self.weight.data.normal_() self.bias.data.zero_() def forward(self, input, latent): fan_in = self.weight.data.size(1) * self.weight.data[0][0].numel() weight = self.weight * sqrt(2 / fan_in) weight = weight.view(1, self.out_channels, self.in_channels, self.kernel_size, self.kernel_size) s = self.mlp_class_std(latent).view(-1, 1, self.in_channels, 1, 1) weight = s * weight if self.demudulate: d = torch.rsqrt((weight**2).sum(4).sum(3).sum(2) + 1e-5).view(-1, self.out_channels, 1, 1, 1) weight = (d * weight).view(-1, self.in_channels, self.kernel_size, self.kernel_size) else: weight = weight.view(-1, self.in_channels, self.kernel_size, self.kernel_size) batch, _, height, width = input.shape input = input.view(1, -1, height, width) input = self.padding(input) out = F.conv2d( input, weight, groups=batch).view(batch, self.out_channels, height, width) + self.bias return out class StyledConvBlock(nn.Module): def __init__(self, fin, fout, latent_dim=256, padding='zero', actvn='lrelu', normalize_affine_output=False, modulated_conv=False): super(StyledConvBlock, self).__init__() if not modulated_conv: if padding == 'reflect': padding_layer = nn.ReflectionPad2d else: padding_layer = nn.ZeroPad2d if modulated_conv: conv2d = ModulatedConv2d if modulated_conv: self.actvn_gain = sqrt(2) else: self.actvn_gain = 1.0 self.modulated_conv = modulated_conv if actvn == 'relu': activation = nn.ReLU(True) else: activation = nn.LeakyReLU(0.2, True) if self.modulated_conv: self.conv0 = conv2d( fin, fout, kernel_size=3, padding_type=padding, upsample=False, latent_dim=latent_dim, normalize_mlp=normalize_affine_output) else: conv0 = conv2d(fin, fout, kernel_size=3) seq0 = [padding_layer(1), conv0] self.conv0 = nn.Sequential(*seq0) self.actvn0 = activation if self.modulated_conv: self.conv1 = conv2d( fout, fout, kernel_size=3, padding_type=padding, downsample=False, latent_dim=latent_dim, normalize_mlp=normalize_affine_output) else: conv1 = conv2d(fout, fout, kernel_size=3) seq1 = [padding_layer(1), conv1] self.conv1 = nn.Sequential(*seq1) self.actvn1 = activation def forward(self, input, latent=None): if self.modulated_conv: out = self.conv0(input, latent) else: out = self.conv0(input) out = self.actvn0(out) * self.actvn_gain if self.modulated_conv: out = self.conv1(out, latent) else: out = self.conv1(out) out = self.actvn1(out) * self.actvn_gain return out class Styled_F_ConvBlock(nn.Module): def __init__(self, fin, fout, latent_dim=256, padding='zero', actvn='lrelu', normalize_affine_output=False, modulated_conv=False): super(Styled_F_ConvBlock, self).__init__() if not modulated_conv: if padding == 'reflect': padding_layer = nn.ReflectionPad2d else: padding_layer = nn.ZeroPad2d if modulated_conv: conv2d = ModulatedConv2d if modulated_conv: self.actvn_gain = sqrt(2) else: self.actvn_gain = 1.0 self.modulated_conv = modulated_conv if actvn == 'relu': activation = nn.ReLU(True) else: activation = nn.LeakyReLU(0.2, True) if self.modulated_conv: self.conv0 = conv2d( fin, 128, kernel_size=3, padding_type=padding, upsample=False, latent_dim=latent_dim, normalize_mlp=normalize_affine_output) else: conv0 = conv2d(fin, 128, kernel_size=3) seq0 = [padding_layer(1), conv0] self.conv0 = nn.Sequential(*seq0) self.actvn0 = activation if self.modulated_conv: self.conv1 = conv2d( 128, fout, kernel_size=3, padding_type=padding, downsample=False, latent_dim=latent_dim, normalize_mlp=normalize_affine_output) else: conv1 = conv2d(128, fout, kernel_size=3) seq1 = [padding_layer(1), conv1] self.conv1 = nn.Sequential(*seq1) def forward(self, input, latent=None): if self.modulated_conv: out = self.conv0(input, latent) else: out = self.conv0(input) out = self.actvn0(out) * self.actvn_gain if self.modulated_conv: out = self.conv1(out, latent) else: out = self.conv1(out) return out class ResBlock(nn.Module): def __init__(self, in_channels): super(ResBlock, self).__init__() self.block = nn.Sequential( nn.BatchNorm2d(in_channels), nn.ReLU(inplace=True), nn.Conv2d( in_channels, in_channels, kernel_size=3, padding=1, bias=False), nn.BatchNorm2d(in_channels), nn.ReLU(inplace=True), nn.Conv2d( in_channels, in_channels, kernel_size=3, padding=1, bias=False)) def forward(self, x): return self.block(x) + x class DownSample(nn.Module): def __init__(self, in_channels, out_channels): super(DownSample, self).__init__() self.block = nn.Sequential( nn.BatchNorm2d(in_channels), nn.ReLU(inplace=True), nn.Conv2d( in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False)) def forward(self, x): return self.block(x) class FeatureEncoder(nn.Module): def __init__(self, in_channels, chns=[64, 128, 256, 256, 256]): super(FeatureEncoder, self).__init__() self.encoders = [] for i, out_chns in enumerate(chns): if i == 0: encoder = nn.Sequential( DownSample(in_channels, out_chns), ResBlock(out_chns), ResBlock(out_chns)) else: encoder = nn.Sequential( DownSample(chns[i - 1], out_chns), ResBlock(out_chns), ResBlock(out_chns)) self.encoders.append(encoder) self.encoders = nn.ModuleList(self.encoders) def forward(self, x): encoder_features = [] for encoder in self.encoders: x = encoder(x) encoder_features.append(x) return encoder_features class RefinePyramid(nn.Module): def __init__(self, chns=[64, 128, 256, 256, 256], fpn_dim=256): super(RefinePyramid, self).__init__() self.chns = chns # adaptive self.adaptive = [] for in_chns in list(reversed(chns)): adaptive_layer = nn.Conv2d(in_chns, fpn_dim, kernel_size=1) self.adaptive.append(adaptive_layer) self.adaptive = nn.ModuleList(self.adaptive) # output conv self.smooth = [] for i in range(len(chns)): smooth_layer = nn.Conv2d( fpn_dim, fpn_dim, kernel_size=3, padding=1) self.smooth.append(smooth_layer) self.smooth = nn.ModuleList(self.smooth) def forward(self, x): conv_ftr_list = x feature_list = [] last_feature = None for i, conv_ftr in enumerate(list(reversed(conv_ftr_list))): # adaptive feature = self.adaptive[i](conv_ftr) # fuse if last_feature is not None: feature = feature + F.interpolate( last_feature, scale_factor=2, mode='nearest') # smooth feature = self.smooth[i](feature) last_feature = feature feature_list.append(feature) return tuple(reversed(feature_list)) class AFlowNet(nn.Module): def __init__(self, num_pyramid, fpn_dim=256): super(AFlowNet, self).__init__() padding_type = 'zero' actvn = 'lrelu' normalize_mlp = False modulated_conv = True self.netRefine = [] self.netStyle = [] self.netF = [] for i in range(num_pyramid): netRefine_layer = torch.nn.Sequential( torch.nn.Conv2d( 2 * fpn_dim, out_channels=128, kernel_size=3, stride=1, padding=1), torch.nn.LeakyReLU(inplace=False, negative_slope=0.1), torch.nn.Conv2d( in_channels=128, out_channels=64, kernel_size=3, stride=1, padding=1), torch.nn.LeakyReLU(inplace=False, negative_slope=0.1), torch.nn.Conv2d( in_channels=64, out_channels=32, kernel_size=3, stride=1, padding=1), torch.nn.LeakyReLU(inplace=False, negative_slope=0.1), torch.nn.Conv2d( in_channels=32, out_channels=2, kernel_size=3, stride=1, padding=1)) style_block = StyledConvBlock( 256, 49, latent_dim=256, padding=padding_type, actvn=actvn, normalize_affine_output=normalize_mlp, modulated_conv=modulated_conv) style_F_block = Styled_F_ConvBlock( 49, 2, latent_dim=256, padding=padding_type, actvn=actvn, normalize_affine_output=normalize_mlp, modulated_conv=modulated_conv) self.netRefine.append(netRefine_layer) self.netStyle.append(style_block) self.netF.append(style_F_block) self.netRefine = nn.ModuleList(self.netRefine) self.netStyle = nn.ModuleList(self.netStyle) self.netF = nn.ModuleList(self.netF) self.cond_style = torch.nn.Sequential( torch.nn.Conv2d(256, 128, kernel_size=(8, 6), stride=1, padding=0), torch.nn.LeakyReLU(inplace=False, negative_slope=0.1)) self.image_style = torch.nn.Sequential( torch.nn.Conv2d(256, 128, kernel_size=(8, 6), stride=1, padding=0), torch.nn.LeakyReLU(inplace=False, negative_slope=0.1)) def forward(self, x, x_warps, x_conds, warp_feature=True): last_flow = None B = x_conds[len(x_warps) - 1].shape[0] cond_style = self.cond_style(x_conds[len(x_warps) - 1]).view(B, -1) image_style = self.image_style(x_warps[len(x_warps) - 1]).view(B, -1) style = torch.cat([cond_style, image_style], 1) for i in range(len(x_warps)): x_warp = x_warps[len(x_warps) - 1 - i] x_cond = x_conds[len(x_warps) - 1 - i] if last_flow is not None and warp_feature: x_warp_after = F.grid_sample( x_warp, last_flow.detach().permute(0, 2, 3, 1), mode='bilinear', padding_mode='border') else: x_warp_after = x_warp stylemap = self.netStyle[i](x_warp_after, style) flow = self.netF[i](stylemap, style) flow = apply_offset(flow) if last_flow is not None: flow = F.grid_sample( last_flow, flow, mode='bilinear', padding_mode='border') else: flow = flow.permute(0, 3, 1, 2) last_flow = flow x_warp = F.grid_sample( x_warp, flow.permute(0, 2, 3, 1), mode='bilinear', padding_mode='border') concat = torch.cat([x_warp, x_cond], 1) flow = self.netRefine[i](concat) flow = apply_offset(flow) flow = F.grid_sample( last_flow, flow, mode='bilinear', padding_mode='border') last_flow = F.interpolate(flow, scale_factor=2, mode='bilinear') x_warp = F.grid_sample( x, last_flow.permute(0, 2, 3, 1), mode='bilinear', padding_mode='border') return x_warp, last_flow ================================================ FILE: projects/flow_style_vton/models/flow_style_vton_model.py ================================================ import mmengine import numpy as np import torch import torch.nn.functional as F from mmengine.model import BaseModel from mmengine.runner.checkpoint import _load_checkpoint from mmagic.registry import MODELS from mmagic.utils.typing import ForwardInputs @MODELS.register_module() class FlowStyleVTON(BaseModel): def __init__(self, warp_model, gen_model, pretrained_cfgs=None): super().__init__() self.warp_model = MODELS.build(warp_model) self.gen_model = MODELS.build(gen_model) if pretrained_cfgs: self.load_pretrained_models(pretrained_cfgs) def load_pretrained_models(self, pretrained_cfgs): """_summary_ Args: pretrained_cfgs (_type_): _description_ """ for key, ckpt_cfg in pretrained_cfgs.items(): map_location = ckpt_cfg.get('map_location', 'cpu') strict = ckpt_cfg.get('strict', False) ckpt_path = ckpt_cfg.get('ckpt_path') state_dict = _load_checkpoint(ckpt_path, map_location) getattr(self, key).load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained {key} from {ckpt_path}') @property def device(self): """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device def infer(self, inputs): real_image = inputs['image'] clothes = inputs['clothes'] edge = inputs['edge'] edge = torch.FloatTensor( (edge.detach().numpy() > 0.5).astype(np.int64)) clothes = clothes * edge device = self.device real_image, clothes, edge = real_image.to(device), clothes.to( device), edge.to(device) warped_cloth, last_flow = self.warp_model(real_image, clothes) warped_edge = F.grid_sample( edge, last_flow.permute(0, 2, 3, 1), mode='bilinear', padding_mode='zeros') gen_inputs = torch.cat([real_image, warped_cloth, warped_edge], 1) gen_outputs = self.gen_model(gen_inputs) p_rendered, m_composite = torch.split(gen_outputs, [3, 1], 1) p_rendered = torch.tanh(p_rendered) m_composite = torch.sigmoid(m_composite) m_composite = m_composite * warped_edge p_tryon = warped_cloth * m_composite + p_rendered * (1 - m_composite) flow_offset = de_offset(last_flow) flow_color = flow2color()(flow_offset) combine = torch.cat([ real_image[0], clothes[0], flow_color.to(device), warped_cloth.to(device)[0], p_tryon[0] ], 2).squeeze() return p_tryon, combine def forward(self, inputs: ForwardInputs): return self.infer(inputs) def make_colorwheel(): """Generates a color wheel for optical flow visualization as presented in: Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007) URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf According to the C++ source code of Daniel Scharstein According to the Matlab source code of Deqing Sun """ RY = 15 YG = 6 GC = 4 CB = 11 BM = 13 MR = 6 ncols = RY + YG + GC + CB + BM + MR colorwheel = np.zeros((ncols, 3)) col = 0 # RY colorwheel[0:RY, 0] = 255 colorwheel[0:RY, 1] = np.floor(255 * np.arange(0, RY) / RY) col = col + RY # YG colorwheel[col:col + YG, 0] = 255 - np.floor(255 * np.arange(0, YG) / YG) colorwheel[col:col + YG, 1] = 255 col = col + YG # GC colorwheel[col:col + GC, 1] = 255 colorwheel[col:col + GC, 2] = np.floor(255 * np.arange(0, GC) / GC) col = col + GC # CB colorwheel[col:col + CB, 1] = 255 - np.floor(255 * np.arange(CB) / CB) colorwheel[col:col + CB, 2] = 255 col = col + CB # BM colorwheel[col:col + BM, 2] = 255 colorwheel[col:col + BM, 0] = np.floor(255 * np.arange(0, BM) / BM) col = col + BM # MR colorwheel[col:col + MR, 2] = 255 - np.floor(255 * np.arange(MR) / MR) colorwheel[col:col + MR, 0] = 255 return colorwheel class flow2color(): # code from: https://github.com/tomrunia/OpticalFlow_Visualization # MIT License # # Copyright (c) 2018 Tom Runia # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is # furnished to do so, subject to conditions. # # Author: Tom Runia # Date Created: 2018-08-03 def __init__(self): self.colorwheel = make_colorwheel() def flow_compute_color(self, u, v, convert_to_bgr=False): """Applies the flow color wheel to (possibly clipped) flow components u and v. According to the C++ source code of Daniel Scharstein According to the Matlab source code of Deqing Sun. :param u: np.ndarray, input horizontal flow :param v: np.ndarray, input vertical flow :param convert_to_bgr: bool, whether to change ordering and output BGR instead of RGB :return: """ flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8) ncols = self.colorwheel.shape[0] rad = np.sqrt(np.square(u) + np.square(v)) a = np.arctan2(-v, -u) / np.pi fk = (a + 1) / 2 * (ncols - 1) k0 = np.floor(fk).astype(np.int32) k1 = k0 + 1 k1[k1 == ncols] = 0 f = fk - k0 for i in range(self.colorwheel.shape[1]): tmp = self.colorwheel[:, i] col0 = tmp[k0] / 255.0 col1 = tmp[k1] / 255.0 col = (1 - f) * col0 + f * col1 idx = (rad <= 1) col[idx] = 1 - rad[idx] * (1 - col[idx]) col[~idx] = col[~idx] * 0.75 # out of range? # Note the 2-i => BGR instead of RGB ch_idx = 2 - i if convert_to_bgr else i flow_image[:, :, ch_idx] = np.floor(255 * col) return flow_image def __call__(self, flow_uv, clip_flow=None, convert_to_bgr=False): """Expects a two dimensional flow image of shape [H,W,2] According to the C++ source code of Daniel Scharstein According to the Matlab source code of Deqing Sun. :param flow_uv: np.ndarray of shape [H,W,2] :param clip_flow: float, maximum clipping value for flow :return: """ if len(flow_uv.size()) != 3: flow_uv = flow_uv[0] flow_uv = flow_uv.permute(1, 2, 0).cpu().detach().numpy() assert flow_uv.ndim == 3, 'input flow must have three dimensions' assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]' if clip_flow is not None: flow_uv = np.clip(flow_uv, 0, clip_flow) u = flow_uv[:, :, 1] v = flow_uv[:, :, 0] rad = np.sqrt(np.square(u) + np.square(v)) rad_max = np.max(rad) epsilon = 1e-5 u = u / (rad_max + epsilon) v = v / (rad_max + epsilon) image = self.flow_compute_color(u, v, convert_to_bgr) image = torch.tensor(image).float().permute(2, 0, 1) / 255.0 * 2 - 1 return image def de_offset(s_grid): [b, _, h, w] = s_grid.size() x = torch.arange(w).view(1, -1).expand(h, -1).float() y = torch.arange(h).view(-1, 1).expand(-1, w).float() x = 2 * x / (w - 1) - 1 y = 2 * y / (h - 1) - 1 grid = torch.stack([x, y], dim=0).float().cuda() grid = grid.unsqueeze(0).expand(b, -1, -1, -1) offset = grid - s_grid offset_x = offset[:, 0, :, :] * (w - 1) / 2 offset_y = offset[:, 1, :, :] * (h - 1) / 2 offset = torch.cat((offset_y, offset_x), 0) return offset ================================================ FILE: projects/flow_style_vton/models/generator.py ================================================ import os import torch import torch.nn as nn from mmagic.registry import MODELS @MODELS.register_module() class ResUnetGenerator(nn.Module): def __init__(self, input_nc, output_nc, num_downs, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False): super(ResUnetGenerator, self).__init__() # construct unet structure unet_block = ResUnetSkipConnectionBlock( ngf * 8, ngf * 8, input_nc=None, submodule=None, norm_layer=norm_layer, innermost=True) for i in range(num_downs - 5): unet_block = ResUnetSkipConnectionBlock( ngf * 8, ngf * 8, input_nc=None, submodule=unet_block, norm_layer=norm_layer, use_dropout=use_dropout) unet_block = ResUnetSkipConnectionBlock( ngf * 4, ngf * 8, input_nc=None, submodule=unet_block, norm_layer=norm_layer) unet_block = ResUnetSkipConnectionBlock( ngf * 2, ngf * 4, input_nc=None, submodule=unet_block, norm_layer=norm_layer) unet_block = ResUnetSkipConnectionBlock( ngf, ngf * 2, input_nc=None, submodule=unet_block, norm_layer=norm_layer) unet_block = ResUnetSkipConnectionBlock( output_nc, ngf, input_nc=input_nc, submodule=unet_block, outermost=True, norm_layer=norm_layer) self.model = unet_block def forward(self, input): return self.model(input) class ResidualBlock(nn.Module): def __init__(self, in_features=64, norm_layer=nn.BatchNorm2d): super(ResidualBlock, self).__init__() self.relu = nn.ReLU(True) if norm_layer is None: self.block = nn.Sequential( nn.Conv2d(in_features, in_features, 3, 1, 1, bias=False), nn.ReLU(inplace=True), nn.Conv2d(in_features, in_features, 3, 1, 1, bias=False), ) else: self.block = nn.Sequential( nn.Conv2d(in_features, in_features, 3, 1, 1, bias=False), norm_layer(in_features), nn.ReLU(inplace=True), nn.Conv2d(in_features, in_features, 3, 1, 1, bias=False), norm_layer(in_features)) def forward(self, x): residual = x out = self.block(x) out += residual out = self.relu(out) return out # Defines the submodule with skip connection. # X -------------------identity---------------------- X # |-- downsampling -- |submodule| -- upsampling --| class ResUnetSkipConnectionBlock(nn.Module): def __init__(self, outer_nc, inner_nc, input_nc=None, submodule=None, outermost=False, innermost=False, norm_layer=nn.BatchNorm2d, use_dropout=False): super(ResUnetSkipConnectionBlock, self).__init__() self.outermost = outermost use_bias = norm_layer == nn.InstanceNorm2d if input_nc is None: input_nc = outer_nc downconv = nn.Conv2d( input_nc, inner_nc, kernel_size=3, stride=2, padding=1, bias=use_bias) # add two resblock res_downconv = [ ResidualBlock(inner_nc, norm_layer), ResidualBlock(inner_nc, norm_layer) ] res_upconv = [ ResidualBlock(outer_nc, norm_layer), ResidualBlock(outer_nc, norm_layer) ] downrelu = nn.ReLU(True) uprelu = nn.ReLU(True) if norm_layer is not None: downnorm = norm_layer(inner_nc) upnorm = norm_layer(outer_nc) if outermost: upsample = nn.Upsample(scale_factor=2, mode='nearest') upconv = nn.Conv2d( inner_nc * 2, outer_nc, kernel_size=3, stride=1, padding=1, bias=use_bias) down = [downconv, downrelu] + res_downconv up = [upsample, upconv] model = down + [submodule] + up elif innermost: upsample = nn.Upsample(scale_factor=2, mode='nearest') upconv = nn.Conv2d( inner_nc, outer_nc, kernel_size=3, stride=1, padding=1, bias=use_bias) down = [downconv, downrelu] + res_downconv if norm_layer is None: up = [upsample, upconv, uprelu] + res_upconv else: up = [upsample, upconv, upnorm, uprelu] + res_upconv model = down + up else: upsample = nn.Upsample(scale_factor=2, mode='nearest') upconv = nn.Conv2d( inner_nc * 2, outer_nc, kernel_size=3, stride=1, padding=1, bias=use_bias) if norm_layer is None: down = [downconv, downrelu] + res_downconv up = [upsample, upconv, uprelu] + res_upconv else: down = [downconv, downnorm, downrelu] + res_downconv up = [upsample, upconv, upnorm, uprelu] + res_upconv if use_dropout: model = down + [submodule] + up + [nn.Dropout(0.5)] else: model = down + [submodule] + up self.model = nn.Sequential(*model) def forward(self, x): if self.outermost: return self.model(x) else: return torch.cat([x, self.model(x)], 1) def load_checkpoint(model, checkpoint_path): if not os.path.exists(checkpoint_path): print('No checkpoint!') return checkpoint = torch.load(checkpoint_path) checkpoint_new = model.state_dict() for param in checkpoint_new: checkpoint_new[param] = checkpoint[param] model.load_state_dict(checkpoint_new) ================================================ FILE: projects/flow_style_vton/test_pairs.txt ================================================ 000001_0.jpg 001744_1.jpg 000010_0.jpg 004325_1.jpg 000020_0.jpg 002022_1.jpg 000028_0.jpg 014652_1.jpg 000038_0.jpg 010143_1.jpg 000048_0.jpg 010608_1.jpg 000057_0.jpg 012578_1.jpg 000066_0.jpg 009595_1.jpg 000074_0.jpg 015392_1.jpg 000082_0.jpg 003291_1.jpg 000097_0.jpg 019522_1.jpg 000109_0.jpg 018778_1.jpg 000118_0.jpg 005533_1.jpg 000129_0.jpg 007365_1.jpg 000143_0.jpg 016246_1.jpg 000154_0.jpg 003898_1.jpg 000164_0.jpg 003514_1.jpg 000174_0.jpg 016866_1.jpg 000183_0.jpg 019332_1.jpg 000192_0.jpg 007692_1.jpg 000200_0.jpg 015272_1.jpg 000209_0.jpg 013780_1.jpg 000220_0.jpg 001360_1.jpg 000228_0.jpg 019540_1.jpg 000240_0.jpg 018746_1.jpg 000248_0.jpg 001583_1.jpg 000258_0.jpg 019037_1.jpg 000266_0.jpg 015836_1.jpg 000274_0.jpg 008560_1.jpg 000284_0.jpg 019552_1.jpg 000293_0.jpg 007415_1.jpg 000303_0.jpg 013245_1.jpg 000312_0.jpg 007484_1.jpg 000320_0.jpg 019029_1.jpg 000330_0.jpg 005053_1.jpg 000339_0.jpg 001879_1.jpg 000347_0.jpg 016367_1.jpg 000356_0.jpg 014701_1.jpg 000370_0.jpg 002397_1.jpg 000378_0.jpg 005666_1.jpg 000386_0.jpg 015308_1.jpg 000395_0.jpg 011689_1.jpg 000404_0.jpg 004922_1.jpg 000417_0.jpg 008406_1.jpg 000426_0.jpg 014794_1.jpg 000437_0.jpg 000846_1.jpg 000445_0.jpg 008645_1.jpg 000456_0.jpg 015759_1.jpg 000466_0.jpg 000514_1.jpg 000477_0.jpg 006976_1.jpg 000488_0.jpg 007986_1.jpg 000501_0.jpg 016300_1.jpg 000514_0.jpg 012652_1.jpg 000523_0.jpg 017868_1.jpg 000532_0.jpg 013214_1.jpg 000542_0.jpg 014149_1.jpg 000560_0.jpg 006640_1.jpg 000568_0.jpg 004342_1.jpg 000576_0.jpg 001192_1.jpg 000585_0.jpg 008471_1.jpg 000593_0.jpg 003998_1.jpg 000602_0.jpg 012860_1.jpg 000610_0.jpg 014979_1.jpg 000619_0.jpg 008744_1.jpg 000629_0.jpg 001144_1.jpg 000639_0.jpg 008420_1.jpg 000651_0.jpg 003422_1.jpg 000659_0.jpg 015362_1.jpg 000668_0.jpg 008959_1.jpg 000676_0.jpg 010105_1.jpg 000685_0.jpg 011944_1.jpg 000696_0.jpg 012605_1.jpg 000706_0.jpg 016474_1.jpg 000716_0.jpg 006808_1.jpg 000724_0.jpg 007243_1.jpg 000734_0.jpg 014888_1.jpg 000742_0.jpg 009390_1.jpg 000750_0.jpg 013654_1.jpg 000760_0.jpg 005368_1.jpg 000768_0.jpg 017886_1.jpg 000776_0.jpg 008506_1.jpg 000786_0.jpg 007957_1.jpg 000795_0.jpg 006859_1.jpg 000803_0.jpg 005203_1.jpg 000812_0.jpg 003821_1.jpg 000827_0.jpg 002297_1.jpg 000837_0.jpg 004710_1.jpg 000846_0.jpg 001606_1.jpg 000855_0.jpg 011816_1.jpg 000867_0.jpg 002111_1.jpg 000877_0.jpg 010543_1.jpg 000889_0.jpg 004080_1.jpg 000898_0.jpg 011173_1.jpg 000907_0.jpg 004123_1.jpg 000915_0.jpg 016049_1.jpg 000924_0.jpg 007286_1.jpg 000934_0.jpg 017466_1.jpg 000943_0.jpg 010463_1.jpg 000957_0.jpg 012322_1.jpg 000968_0.jpg 005328_1.jpg 000979_0.jpg 014765_1.jpg 000988_0.jpg 016059_1.jpg 000997_0.jpg 019224_1.jpg 001009_0.jpg 000889_1.jpg 001017_0.jpg 010744_1.jpg 001028_0.jpg 004844_1.jpg 001038_0.jpg 003721_1.jpg 001048_0.jpg 002076_1.jpg 001056_0.jpg 005396_1.jpg 001064_0.jpg 017438_1.jpg 001073_0.jpg 000724_1.jpg 001083_0.jpg 007609_1.jpg 001092_0.jpg 000154_1.jpg 001101_0.jpg 018962_1.jpg 001109_0.jpg 016951_1.jpg 001118_0.jpg 002874_1.jpg 001126_0.jpg 011042_1.jpg 001136_0.jpg 019045_1.jpg 001144_0.jpg 016172_1.jpg 001153_0.jpg 018210_1.jpg 001162_0.jpg 019009_1.jpg 001173_0.jpg 007505_1.jpg 001181_0.jpg 002103_1.jpg 001192_0.jpg 017002_1.jpg 001203_0.jpg 009236_1.jpg 001211_0.jpg 014192_1.jpg 001219_0.jpg 009995_1.jpg 001228_0.jpg 003731_1.jpg 001236_0.jpg 007149_1.jpg 001245_0.jpg 010891_1.jpg 001255_0.jpg 017091_1.jpg 001269_0.jpg 014262_1.jpg 001283_0.jpg 002137_1.jpg 001292_0.jpg 013047_1.jpg 001301_0.jpg 003813_1.jpg 001310_0.jpg 014854_1.jpg 001320_0.jpg 003208_1.jpg 001328_0.jpg 011615_1.jpg 001337_0.jpg 012174_1.jpg 001349_0.jpg 008241_1.jpg 001360_0.jpg 008451_1.jpg 001369_0.jpg 019279_1.jpg 001378_0.jpg 000466_1.jpg 001387_0.jpg 015325_1.jpg 001399_0.jpg 005711_1.jpg 001408_0.jpg 002980_1.jpg 001419_0.jpg 010337_1.jpg 001428_0.jpg 007617_1.jpg 001437_0.jpg 001476_1.jpg 001448_0.jpg 016067_1.jpg 001457_0.jpg 008804_1.jpg 001467_0.jpg 017235_1.jpg 001476_0.jpg 010281_1.jpg 001485_0.jpg 018420_1.jpg 001494_0.jpg 008928_1.jpg 001502_0.jpg 015150_1.jpg 001512_0.jpg 018031_1.jpg 001520_0.jpg 012395_1.jpg 001528_0.jpg 015688_1.jpg 001537_0.jpg 001825_1.jpg 001547_0.jpg 003357_1.jpg 001559_0.jpg 011190_1.jpg 001567_0.jpg 001567_1.jpg 001575_0.jpg 018544_1.jpg 001583_0.jpg 019087_1.jpg 001594_0.jpg 013527_1.jpg 001606_0.jpg 010115_1.jpg 001614_0.jpg 005975_1.jpg 001623_0.jpg 010300_1.jpg 001635_0.jpg 019573_1.jpg 001645_0.jpg 009342_1.jpg 001655_0.jpg 000576_1.jpg 001664_0.jpg 004061_1.jpg 001673_0.jpg 008863_1.jpg 001683_0.jpg 008206_1.jpg 001695_0.jpg 017175_1.jpg 001706_0.jpg 010735_1.jpg 001715_0.jpg 006581_1.jpg 001725_0.jpg 002892_1.jpg 001735_0.jpg 001645_1.jpg 001744_0.jpg 001328_1.jpg 001756_0.jpg 002999_1.jpg 001765_0.jpg 006834_1.jpg 001776_0.jpg 007899_1.jpg 001789_0.jpg 011288_1.jpg 001798_0.jpg 001735_1.jpg 001809_0.jpg 010995_1.jpg 001817_0.jpg 003777_1.jpg 001825_0.jpg 017945_1.jpg 001834_0.jpg 005044_1.jpg 001845_0.jpg 000395_1.jpg 001858_0.jpg 019402_1.jpg 001868_0.jpg 011270_1.jpg 001879_0.jpg 004727_1.jpg 001891_0.jpg 018348_1.jpg 001900_0.jpg 011544_1.jpg 001908_0.jpg 011515_1.jpg 001919_0.jpg 001211_1.jpg 001928_0.jpg 013155_1.jpg 001937_0.jpg 005887_1.jpg 001947_0.jpg 002990_1.jpg 001957_0.jpg 002749_1.jpg 001966_0.jpg 007932_1.jpg 001974_0.jpg 008101_1.jpg 001983_0.jpg 004423_1.jpg 001991_0.jpg 004981_1.jpg 002000_0.jpg 016628_1.jpg 002011_0.jpg 005440_1.jpg 002022_0.jpg 017204_1.jpg 002031_0.jpg 008967_1.jpg 002039_0.jpg 018769_1.jpg 002049_0.jpg 003124_1.jpg 002059_0.jpg 008092_1.jpg 002068_0.jpg 010415_1.jpg 002076_0.jpg 000716_1.jpg 002085_0.jpg 001236_1.jpg 002093_0.jpg 018971_1.jpg 002103_0.jpg 017070_1.jpg 002111_0.jpg 017012_1.jpg 002119_0.jpg 016445_1.jpg 002128_0.jpg 005360_1.jpg 002137_0.jpg 015579_1.jpg 002147_0.jpg 005603_1.jpg 002156_0.jpg 018431_1.jpg 002169_0.jpg 009094_1.jpg 002180_0.jpg 019066_1.jpg 002191_0.jpg 009215_1.jpg 002200_0.jpg 008632_1.jpg 002208_0.jpg 009435_1.jpg 002217_0.jpg 002119_1.jpg 002226_0.jpg 016145_1.jpg 002236_0.jpg 006213_1.jpg 002248_0.jpg 012338_1.jpg 002259_0.jpg 013391_1.jpg 002268_0.jpg 000760_1.jpg 002276_0.jpg 003338_1.jpg 002287_0.jpg 018569_1.jpg 002297_0.jpg 013883_1.jpg 002307_0.jpg 014416_1.jpg 002317_0.jpg 017243_1.jpg 002327_0.jpg 015724_1.jpg 002337_0.jpg 002439_1.jpg 002345_0.jpg 015607_1.jpg 002353_0.jpg 016653_1.jpg 002362_0.jpg 018401_1.jpg 002371_0.jpg 005877_1.jpg 002379_0.jpg 011240_1.jpg 002388_0.jpg 005081_1.jpg 002397_0.jpg 009496_1.jpg 002405_0.jpg 018496_1.jpg 002413_0.jpg 008023_1.jpg 002422_0.jpg 015125_1.jpg 002431_0.jpg 007797_1.jpg 002439_0.jpg 004185_1.jpg 002447_0.jpg 000240_1.jpg 002455_0.jpg 011891_1.jpg 002464_0.jpg 010851_1.jpg 002474_0.jpg 004268_1.jpg 002486_0.jpg 017348_1.jpg 002494_0.jpg 013836_1.jpg 002502_0.jpg 004333_1.jpg 002511_0.jpg 000020_1.jpg 002523_0.jpg 009114_1.jpg 002533_0.jpg 019340_1.jpg 002545_0.jpg 004006_1.jpg 002553_0.jpg 012763_1.jpg 002561_0.jpg 012644_1.jpg 002575_0.jpg 012996_1.jpg 002589_0.jpg 013891_1.jpg 002599_0.jpg 005648_1.jpg 002610_0.jpg 015465_1.jpg 002620_0.jpg 003749_1.jpg 002628_0.jpg 016739_1.jpg 002639_0.jpg 000143_1.jpg 002651_0.jpg 016636_1.jpg 002659_0.jpg 003935_1.jpg 002670_0.jpg 010710_1.jpg 002681_0.jpg 000312_1.jpg 002691_0.jpg 015256_1.jpg 002699_0.jpg 001118_1.jpg 002712_0.jpg 013583_1.jpg 002720_0.jpg 019514_1.jpg 002728_0.jpg 001991_1.jpg 002739_0.jpg 005952_1.jpg 002749_0.jpg 011523_1.jpg 002758_0.jpg 012256_1.jpg 002769_0.jpg 010806_1.jpg 002778_0.jpg 001512_1.jpg 002787_0.jpg 002787_1.jpg 002795_0.jpg 018138_1.jpg 002803_0.jpg 016238_1.jpg 002812_0.jpg 004497_1.jpg 002820_0.jpg 011761_1.jpg 002828_0.jpg 000968_1.jpg 002839_0.jpg 009178_1.jpg 002852_0.jpg 007261_1.jpg 002865_0.jpg 004167_1.jpg 002874_0.jpg 008429_1.jpg 002883_0.jpg 009141_1.jpg 002892_0.jpg 016290_1.jpg 002901_0.jpg 015627_1.jpg 002911_0.jpg 013355_1.jpg 002922_0.jpg 012975_1.jpg 002930_0.jpg 016002_1.jpg 002942_0.jpg 015371_1.jpg 002952_0.jpg 011381_1.jpg 002962_0.jpg 012553_1.jpg 002970_0.jpg 016593_1.jpg 002980_0.jpg 004366_1.jpg 002990_0.jpg 003684_1.jpg 002999_0.jpg 018393_1.jpg 003008_0.jpg 007455_1.jpg 003016_0.jpg 012811_1.jpg 003024_0.jpg 001245_1.jpg 003032_0.jpg 005797_1.jpg 003041_0.jpg 001673_1.jpg 003049_0.jpg 008822_1.jpg 003060_0.jpg 002720_1.jpg 003069_0.jpg 013680_1.jpg 003077_0.jpg 000639_1.jpg 003086_0.jpg 006057_1.jpg 003094_0.jpg 018452_1.jpg 003107_0.jpg 002795_1.jpg 003115_0.jpg 007772_1.jpg 003124_0.jpg 010591_1.jpg 003133_0.jpg 010125_1.jpg 003142_0.jpg 011068_1.jpg 003150_0.jpg 011736_1.jpg 003158_0.jpg 012350_1.jpg 003167_0.jpg 006606_1.jpg 003179_0.jpg 010937_1.jpg 003187_0.jpg 011212_1.jpg 003195_0.jpg 009282_1.jpg 003208_0.jpg 001255_1.jpg 003218_0.jpg 016541_1.jpg 003226_0.jpg 010177_1.jpg 003236_0.jpg 005251_1.jpg 003250_0.jpg 017410_1.jpg 003259_0.jpg 002639_1.jpg 003270_0.jpg 017796_1.jpg 003280_0.jpg 017526_1.jpg 003291_0.jpg 011708_1.jpg 003303_0.jpg 003491_1.jpg 003311_0.jpg 013827_1.jpg 003319_0.jpg 015192_1.jpg 003328_0.jpg 012273_1.jpg 003338_0.jpg 010567_1.jpg 003349_0.jpg 001101_1.jpg 003357_0.jpg 013374_1.jpg 003367_0.jpg 002353_1.jpg 003376_0.jpg 014006_1.jpg 003386_0.jpg 018479_1.jpg 003395_0.jpg 010726_1.jpg 003404_0.jpg 015844_1.jpg 003414_0.jpg 000855_1.jpg 003422_0.jpg 000456_1.jpg 003434_0.jpg 010718_1.jpg 003443_0.jpg 003945_1.jpg 003451_0.jpg 011336_1.jpg 003461_0.jpg 004814_1.jpg 003472_0.jpg 006470_1.jpg 003481_0.jpg 016726_1.jpg 003491_0.jpg 017298_1.jpg 003501_0.jpg 010270_1.jpg 003514_0.jpg 018608_1.jpg 003526_0.jpg 001858_1.jpg 003535_0.jpg 009852_1.jpg 003545_0.jpg 002085_1.jpg 003555_0.jpg 013564_1.jpg 003565_0.jpg 005525_1.jpg 003578_0.jpg 013007_1.jpg 003591_0.jpg 005720_1.jpg 003600_0.jpg 015938_1.jpg 003611_0.jpg 013715_1.jpg 003621_0.jpg 000274_1.jpg 003632_0.jpg 000585_1.jpg 003641_0.jpg 014876_1.jpg 003649_0.jpg 019140_1.jpg 003658_0.jpg 016465_1.jpg 003668_0.jpg 010234_1.jpg 003676_0.jpg 007601_1.jpg 003684_0.jpg 006381_1.jpg 003693_0.jpg 015590_1.jpg 003703_0.jpg 011883_1.jpg 003712_0.jpg 014621_1.jpg 003721_0.jpg 001126_1.jpg 003731_0.jpg 015715_1.jpg 003739_0.jpg 004804_1.jpg 003749_0.jpg 014140_1.jpg 003760_0.jpg 008397_1.jpg 003768_0.jpg 015697_1.jpg 003777_0.jpg 000082_1.jpg 003787_0.jpg 001966_1.jpg 003795_0.jpg 003414_1.jpg 003803_0.jpg 011916_1.jpg 003813_0.jpg 014612_1.jpg 003821_0.jpg 014292_1.jpg 003833_0.jpg 008326_1.jpg 003842_0.jpg 012219_1.jpg 003852_0.jpg 011466_1.jpg 003861_0.jpg 011962_1.jpg 003874_0.jpg 014349_1.jpg 003882_0.jpg 017583_1.jpg 003890_0.jpg 018921_1.jpg 003898_0.jpg 004196_1.jpg 003915_0.jpg 013688_1.jpg 003925_0.jpg 004397_1.jpg 003935_0.jpg 012889_1.jpg 003945_0.jpg 000898_1.jpg 003953_0.jpg 002379_1.jpg 003963_0.jpg 008160_1.jpg 003972_0.jpg 012694_1.jpg 003981_0.jpg 008307_1.jpg 003990_0.jpg 004636_1.jpg 003998_0.jpg 007405_1.jpg 004006_0.jpg 001725_1.jpg 004015_0.jpg 015785_1.jpg 004023_0.jpg 000488_1.jpg 004033_0.jpg 010583_1.jpg 004042_0.jpg 004580_1.jpg 004051_0.jpg 000028_1.jpg 004061_0.jpg 012531_1.jpg 004071_0.jpg 012838_1.jpg 004080_0.jpg 012006_1.jpg 004091_0.jpg 002769_1.jpg 004099_0.jpg 000320_1.jpg 004107_0.jpg 005317_1.jpg 004115_0.jpg 009949_1.jpg 004123_0.jpg 008196_1.jpg 004131_0.jpg 013199_1.jpg 004139_0.jpg 017814_1.jpg 004148_0.jpg 017555_1.jpg 004158_0.jpg 017130_1.jpg 004167_0.jpg 005388_1.jpg 004177_0.jpg 015133_1.jpg 004185_0.jpg 000501_1.jpg 004196_0.jpg 004158_1.jpg 004210_0.jpg 008663_1.jpg 004220_0.jpg 014332_1.jpg 004234_0.jpg 009766_1.jpg 004243_0.jpg 010454_1.jpg 004252_0.jpg 004553_1.jpg 004260_0.jpg 013899_1.jpg 004268_0.jpg 017474_1.jpg 004277_0.jpg 017545_1.jpg 004285_0.jpg 008110_1.jpg 004294_0.jpg 015560_1.jpg 004304_0.jpg 009689_1.jpg 004314_0.jpg 017896_1.jpg 004325_0.jpg 003600_1.jpg 004333_0.jpg 007579_1.jpg 004342_0.jpg 018460_1.jpg 004357_0.jpg 001559_1.jpg 004366_0.jpg 002812_1.jpg 004378_0.jpg 008367_1.jpg 004387_0.jpg 010244_1.jpg 004397_0.jpg 008672_1.jpg 004415_0.jpg 002000_1.jpg 004423_0.jpg 011034_1.jpg 004431_0.jpg 001181_1.jpg 004441_0.jpg 009545_1.jpg 004451_0.jpg 007789_1.jpg 004462_0.jpg 004015_1.jpg 004470_0.jpg 008900_1.jpg 004478_0.jpg 011015_1.jpg 004487_0.jpg 003349_1.jpg 004497_0.jpg 015209_1.jpg 004508_0.jpg 009709_1.jpg 004516_0.jpg 001974_1.jpg 004529_0.jpg 005995_1.jpg 004537_0.jpg 019429_1.jpg 004545_0.jpg 014396_1.jpg 004553_0.jpg 017400_1.jpg 004561_0.jpg 019174_1.jpg 004572_0.jpg 002180_1.jpg 004580_0.jpg 019252_1.jpg 004590_0.jpg 011833_1.jpg 004598_0.jpg 014939_1.jpg 004609_0.jpg 013698_1.jpg 004620_0.jpg 002464_1.jpg 004628_0.jpg 011825_1.jpg 004636_0.jpg 013806_1.jpg 004646_0.jpg 001109_1.jpg 004657_0.jpg 000258_1.jpg 004666_0.jpg 002628_1.jpg 004674_0.jpg 007732_1.jpg 004683_0.jpg 012330_1.jpg 004691_0.jpg 019287_1.jpg 004702_0.jpg 010869_1.jpg 004710_0.jpg 005022_1.jpg 004718_0.jpg 017496_1.jpg 004727_0.jpg 008771_1.jpg 004737_0.jpg 000248_1.jpg 004745_0.jpg 014591_1.jpg 004758_0.jpg 001715_1.jpg 004766_0.jpg 004628_1.jpg 004774_0.jpg 005120_1.jpg 004785_0.jpg 000445_1.jpg 004795_0.jpg 005262_1.jpg 004804_0.jpg 013907_1.jpg 004814_0.jpg 002268_1.jpg 004823_0.jpg 000183_1.jpg 004833_0.jpg 014014_1.jpg 004844_0.jpg 015497_1.jpg 004854_0.jpg 018047_1.jpg 004867_0.jpg 016777_1.jpg 004878_0.jpg 013338_1.jpg 004888_0.jpg 006429_1.jpg 004896_0.jpg 015803_1.jpg 004904_0.jpg 012072_1.jpg 004912_0.jpg 009605_1.jpg 004922_0.jpg 000934_1.jpg 004933_0.jpg 010381_1.jpg 004941_0.jpg 016533_1.jpg 004949_0.jpg 004451_1.jpg 004957_0.jpg 006959_1.jpg 004965_0.jpg 018532_1.jpg 004981_0.jpg 002820_1.jpg 004989_0.jpg 010261_1.jpg 004997_0.jpg 004933_1.jpg 005006_0.jpg 004415_1.jpg 005014_0.jpg 008891_1.jpg 005022_0.jpg 009780_1.jpg 005031_0.jpg 003218_1.jpg 005044_0.jpg 012944_1.jpg 005053_0.jpg 012127_1.jpg 005062_0.jpg 015767_1.jpg 005072_0.jpg 018826_1.jpg 005081_0.jpg 013410_1.jpg 005091_0.jpg 012404_1.jpg 005101_0.jpg 007304_1.jpg 005110_0.jpg 005349_1.jpg 005120_0.jpg 003842_1.jpg 005131_0.jpg 007473_1.jpg 005145_0.jpg 003693_1.jpg 005153_0.jpg 006658_1.jpg 005166_0.jpg 007446_1.jpg 005175_0.jpg 007434_1.jpg 005186_0.jpg 013948_1.jpg 005195_0.jpg 002561_1.jpg 005203_0.jpg 016888_1.jpg 005213_0.jpg 015264_1.jpg 005222_0.jpg 007065_1.jpg 005231_0.jpg 002431_1.jpg 005241_0.jpg 006789_1.jpg 005251_0.jpg 014314_1.jpg 005262_0.jpg 018192_1.jpg 005271_0.jpg 011954_1.jpg 005285_0.jpg 006285_1.jpg 005298_0.jpg 015280_1.jpg 005306_0.jpg 018681_1.jpg 005317_0.jpg 011436_1.jpg 005328_0.jpg 000997_1.jpg 005336_0.jpg 000404_1.jpg 005349_0.jpg 006717_1.jpg 005360_0.jpg 010967_1.jpg 005368_0.jpg 005379_1.jpg 005379_0.jpg 016962_1.jpg 005388_0.jpg 006137_1.jpg 005396_0.jpg 012545_1.jpg 005404_0.jpg 013572_1.jpg 005413_0.jpg 005413_1.jpg 005422_0.jpg 018470_1.jpg 005430_0.jpg 004537_1.jpg 005440_0.jpg 015825_1.jpg 005449_0.jpg 017904_1.jpg 005457_0.jpg 017315_1.jpg 005470_0.jpg 010599_1.jpg 005480_0.jpg 000988_1.jpg 005489_0.jpg 007518_1.jpg 005501_0.jpg 008784_1.jpg 005510_0.jpg 004294_1.jpg 005525_0.jpg 006339_1.jpg 005533_0.jpg 016662_1.jpg 005542_0.jpg 007345_1.jpg 005552_0.jpg 012505_1.jpg 005562_0.jpg 007864_1.jpg 005570_0.jpg 010481_1.jpg 005578_0.jpg 019454_1.jpg 005586_0.jpg 019494_1.jpg 005594_0.jpg 006016_1.jpg 005603_0.jpg 017667_1.jpg 005614_0.jpg 019110_1.jpg 005622_0.jpg 010947_1.jpg 005631_0.jpg 019384_1.jpg 005648_0.jpg 018946_1.jpg 005657_0.jpg 003443_1.jpg 005666_0.jpg 016281_1.jpg 005675_0.jpg 001301_1.jpg 005683_0.jpg 012099_1.jpg 005691_0.jpg 011355_1.jpg 005702_0.jpg 001798_1.jpg 005711_0.jpg 010096_1.jpg 005720_0.jpg 009758_1.jpg 005728_0.jpg 014114_1.jpg 005737_0.jpg 012063_1.jpg 005747_0.jpg 004529_1.jpg 005755_0.jpg 014370_1.jpg 005763_0.jpg 007834_1.jpg 005771_0.jpg 018069_1.jpg 005784_0.jpg 018700_1.jpg 005797_0.jpg 015881_1.jpg 005809_0.jpg 010371_1.jpg 005820_0.jpg 016899_1.jpg 005828_0.jpg 002049_1.jpg 005837_0.jpg 016183_1.jpg 005846_0.jpg 008006_1.jpg 005857_0.jpg 010628_1.jpg 005866_0.jpg 013469_1.jpg 005877_0.jpg 010021_1.jpg 005887_0.jpg 013593_1.jpg 005898_0.jpg 000057_1.jpg 005908_0.jpg 000867_1.jpg 005920_0.jpg 013327_1.jpg 005929_0.jpg 011401_1.jpg 005940_0.jpg 000593_1.jpg 005952_0.jpg 014201_1.jpg 005963_0.jpg 009922_1.jpg 005975_0.jpg 010431_1.jpg 005984_0.jpg 007710_1.jpg 005995_0.jpg 001083_1.jpg 006004_0.jpg 018954_1.jpg 006016_0.jpg 010691_1.jpg 006026_0.jpg 003641_1.jpg 006036_0.jpg 000750_1.jpg 006045_0.jpg 008681_1.jpg 006057_0.jpg 010910_1.jpg 006065_0.jpg 011415_1.jpg 006073_0.jpg 010840_1.jpg 006081_0.jpg 008908_1.jpg 006090_0.jpg 007997_1.jpg 006099_0.jpg 015900_1.jpg 006110_0.jpg 009034_1.jpg 006118_0.jpg 015861_1.jpg 006129_0.jpg 006165_1.jpg 006137_0.jpg 008379_1.jpg 006145_0.jpg 016379_1.jpg 006155_0.jpg 016878_1.jpg 006165_0.jpg 010040_1.jpg 006173_0.jpg 001776_1.jpg 006186_0.jpg 007891_1.jpg 006194_0.jpg 015969_1.jpg 006203_0.jpg 005820_1.jpg 006213_0.jpg 014900_1.jpg 006224_0.jpg 016748_1.jpg 006232_0.jpg 010636_1.jpg 006241_0.jpg 018327_1.jpg 006250_0.jpg 013097_1.jpg 006260_0.jpg 007103_1.jpg 006268_0.jpg 007073_1.jpg 006276_0.jpg 011128_1.jpg 006285_0.jpg 019319_1.jpg 006296_0.jpg 002952_1.jpg 006304_0.jpg 002371_1.jpg 006313_0.jpg 014553_1.jpg 006321_0.jpg 014489_1.jpg 006329_0.jpg 005866_1.jpg 006339_0.jpg 019368_1.jpg 006347_0.jpg 006402_1.jpg 006358_0.jpg 002422_1.jpg 006371_0.jpg 011842_1.jpg 006381_0.jpg 019446_1.jpg 006393_0.jpg 012015_1.jpg 006402_0.jpg 013382_1.jpg 006410_0.jpg 000038_1.jpg 006419_0.jpg 014959_1.jpg 006429_0.jpg 018837_1.jpg 006440_0.jpg 017750_1.jpg 006452_0.jpg 003259_1.jpg 006462_0.jpg 018009_1.jpg 006470_0.jpg 013309_1.jpg 006478_0.jpg 014712_1.jpg 006486_0.jpg 000228_1.jpg 006494_0.jpg 005614_1.jpg 006502_0.jpg 010535_1.jpg 006512_0.jpg 007741_1.jpg 006523_0.jpg 015990_1.jpg 006535_0.jpg 011231_1.jpg 006545_0.jpg 016584_1.jpg 006555_0.jpg 015105_1.jpg 006563_0.jpg 001494_1.jpg 006571_0.jpg 007376_1.jpg 006581_0.jpg 003404_1.jpg 006589_0.jpg 008346_1.jpg 006597_0.jpg 008014_1.jpg 006606_0.jpg 002511_1.jpg 006620_0.jpg 017196_1.jpg 006628_0.jpg 009084_1.jpg 006640_0.jpg 014086_1.jpg 006649_0.jpg 004508_1.jpg 006658_0.jpg 014131_1.jpg 006670_0.jpg 000979_1.jpg 006678_0.jpg 002523_1.jpg 006688_0.jpg 011988_1.jpg 006697_0.jpg 018200_1.jpg 006709_0.jpg 017840_1.jpg 006717_0.jpg 018524_1.jpg 006728_0.jpg 013418_1.jpg 006738_0.jpg 011457_1.jpg 006748_0.jpg 016031_1.jpg 006757_0.jpg 001520_1.jpg 006768_0.jpg 008172_1.jpg 006776_0.jpg 000651_1.jpg 006789_0.jpg 017110_1.jpg 006799_0.jpg 001292_1.jpg 006808_0.jpg 002128_1.jpg 006817_0.jpg 004357_1.jpg 006825_0.jpg 012245_1.jpg 006834_0.jpg 014324_1.jpg 006842_0.jpg 009635_1.jpg 006850_0.jpg 012166_1.jpg 006859_0.jpg 003086_1.jpg 006868_0.jpg 010859_1.jpg 006881_0.jpg 004646_1.jpg 006889_0.jpg 014507_1.jpg 006897_0.jpg 012849_1.jpg 006908_0.jpg 006535_1.jpg 006916_0.jpg 000696_1.jpg 006928_0.jpg 017290_1.jpg 006937_0.jpg 008276_1.jpg 006945_0.jpg 009197_1.jpg 006959_0.jpg 013706_1.jpg 006968_0.jpg 015908_1.jpg 006976_0.jpg 018929_1.jpg 006984_0.jpg 005631_1.jpg 006992_0.jpg 000837_1.jpg 007003_0.jpg 010168_1.jpg 007013_0.jpg 006984_1.jpg 007021_0.jpg 006321_1.jpg 007029_0.jpg 007808_1.jpg 007037_0.jpg 011278_1.jpg 007045_0.jpg 008496_1.jpg 007056_0.jpg 016943_1.jpg 007065_0.jpg 015381_1.jpg 007073_0.jpg 007013_1.jpg 007086_0.jpg 017264_1.jpg 007094_0.jpg 004210_1.jpg 007103_0.jpg 011585_1.jpg 007113_0.jpg 016992_1.jpg 007121_0.jpg 009263_1.jpg 007129_0.jpg 000220_1.jpg 007138_0.jpg 017428_1.jpg 007149_0.jpg 010816_1.jpg 007159_0.jpg 018227_1.jpg 007168_0.jpg 002589_1.jpg 007180_0.jpg 011300_1.jpg 007188_0.jpg 000943_1.jpg 007199_0.jpg 016358_1.jpg 007212_0.jpg 007094_1.jpg 007221_0.jpg 002962_1.jpg 007232_0.jpg 005570_1.jpg 007243_0.jpg 004888_1.jpg 007252_0.jpg 003803_1.jpg 007261_0.jpg 006850_1.jpg 007269_0.jpg 017639_1.jpg 007278_0.jpg 001369_1.jpg 007286_0.jpg 009131_1.jpg 007294_0.jpg 004774_1.jpg 007304_0.jpg 003395_1.jpg 007313_0.jpg 014184_1.jpg 007324_0.jpg 008847_1.jpg 007336_0.jpg 001537_1.jpg 007345_0.jpg 015979_1.jpg 007357_0.jpg 019561_1.jpg 007365_0.jpg 005828_1.jpg 007376_0.jpg 010078_1.jpg 007388_0.jpg 006945_1.jpg 007397_0.jpg 012236_1.jpg 007405_0.jpg 015732_1.jpg 007415_0.jpg 009426_1.jpg 007423_0.jpg 012879_1.jpg 007434_0.jpg 012597_1.jpg 007446_0.jpg 015317_1.jpg 007455_0.jpg 009274_1.jpg 007463_0.jpg 003016_1.jpg 007473_0.jpg 013725_1.jpg 007484_0.jpg 003501_1.jpg 007495_0.jpg 005908_1.jpg 007505_0.jpg 011970_1.jpg 007518_0.jpg 005784_1.jpg 007526_0.jpg 015550_1.jpg 007536_0.jpg 015853_1.jpg 007549_0.jpg 015420_1.jpg 007561_0.jpg 013036_1.jpg 007570_0.jpg 005306_1.jpg 007579_0.jpg 006628_1.jpg 007592_0.jpg 001623_1.jpg 007601_0.jpg 014463_1.jpg 007609_0.jpg 009525_1.jpg 007617_0.jpg 015085_1.jpg 007628_0.jpg 000074_1.jpg 007639_0.jpg 014477_1.jpg 007648_0.jpg 004099_1.jpg 007656_0.jpg 008138_1.jpg 007664_0.jpg 002217_1.jpg 007672_0.jpg 016550_1.jpg 007681_0.jpg 004833_1.jpg 007692_0.jpg 003852_1.jpg 007702_0.jpg 015291_1.jpg 007710_0.jpg 011050_1.jpg 007719_0.jpg 005963_1.jpg 007732_0.jpg 008715_1.jpg 007741_0.jpg 019302_1.jpg 007750_0.jpg 018690_1.jpg 007762_0.jpg 006597_1.jpg 007772_0.jpg 002691_1.jpg 007781_0.jpg 002942_1.jpg 007789_0.jpg 017370_1.jpg 007797_0.jpg 006916_1.jpg 007808_0.jpg 014844_1.jpg 007817_0.jpg 015916_1.jpg 007826_0.jpg 004766_1.jpg 007834_0.jpg 011447_1.jpg 007848_0.jpg 008051_1.jpg 007856_0.jpg 000129_1.jpg 007864_0.jpg 001017_1.jpg 007874_0.jpg 004033_1.jpg 007882_0.jpg 003890_1.jpg 007891_0.jpg 008696_1.jpg 007899_0.jpg 002317_1.jpg 007914_0.jpg 019130_1.jpg 007923_0.jpg 000417_1.jpg 007932_0.jpg 011670_1.jpg 007940_0.jpg 004441_1.jpg 007949_0.jpg 018018_1.jpg 007957_0.jpg 002599_1.jpg 007966_0.jpg 017761_1.jpg 007974_0.jpg 000523_1.jpg 007986_0.jpg 011560_1.jpg 007997_0.jpg 007592_1.jpg 008006_0.jpg 004718_1.jpg 008014_0.jpg 015006_1.jpg 008023_0.jpg 000803_1.jpg 008032_0.jpg 003167_1.jpg 008041_0.jpg 006992_1.jpg 008051_0.jpg 006697_1.jpg 008062_0.jpg 009008_1.jpg 008071_0.jpg 014805_1.jpg 008080_0.jpg 003578_1.jpg 008092_0.jpg 007113_1.jpg 008101_0.jpg 011596_1.jpg 008110_0.jpg 007628_1.jpg 008118_0.jpg 005231_1.jpg 008126_0.jpg 014816_1.jpg 008138_0.jpg 000266_1.jpg 008151_0.jpg 011392_1.jpg 008160_0.jpg 013127_1.jpg 008172_0.jpg 015026_1.jpg 008180_0.jpg 009482_1.jpg 008188_0.jpg 008938_1.jpg 008196_0.jpg 004737_1.jpg 008206_0.jpg 002865_1.jpg 008214_0.jpg 018902_1.jpg 008224_0.jpg 012626_1.jpg 008233_0.jpg 002620_1.jpg 008241_0.jpg 007826_1.jpg 008250_0.jpg 002486_1.jpg 008258_0.jpg 003158_1.jpg 008266_0.jpg 015571_1.jpg 008276_0.jpg 009418_1.jpg 008285_0.jpg 004965_1.jpg 008295_0.jpg 017678_1.jpg 008307_0.jpg 001428_1.jpg 008317_0.jpg 011577_1.jpg 008326_0.jpg 006881_1.jpg 008334_0.jpg 014863_1.jpg 008346_0.jpg 014341_1.jpg 008354_0.jpg 007914_1.jpg 008367_0.jpg 004904_1.jpg 008379_0.jpg 004957_1.jpg 008389_0.jpg 004878_1.jpg 008397_0.jpg 016786_1.jpg 008406_0.jpg 015428_1.jpg 008420_0.jpg 001448_1.jpg 008429_0.jpg 005747_1.jpg 008443_0.jpg 011087_1.jpg 008451_0.jpg 000619_1.jpg 008462_0.jpg 008224_1.jpg 008471_0.jpg 012743_1.jpg 008479_0.jpg 006129_1.jpg 008487_0.jpg 001378_1.jpg 008496_0.jpg 015141_1.jpg 008506_0.jpg 006110_1.jpg 008515_0.jpg 017630_1.jpg 008523_0.jpg 002236_1.jpg 008533_0.jpg 017457_1.jpg 008542_0.jpg 010620_1.jpg 008551_0.jpg 016799_1.jpg 008560_0.jpg 016317_1.jpg 008570_0.jpg 007648_1.jpg 008580_0.jpg 018219_1.jpg 008590_0.jpg 003179_1.jpg 008598_0.jpg 010527_1.jpg 008608_0.jpg 016716_1.jpg 008616_0.jpg 010206_1.jpg 008624_0.jpg 007664_1.jpg 008632_0.jpg 019411_1.jpg 008645_0.jpg 014434_1.jpg 008653_0.jpg 018710_1.jpg 008663_0.jpg 007397_1.jpg 008672_0.jpg 010662_1.jpg 008681_0.jpg 005552_1.jpg 008696_0.jpg 014302_1.jpg 008706_0.jpg 011097_1.jpg 008715_0.jpg 001437_1.jpg 008725_0.jpg 004304_1.jpg 008736_0.jpg 012734_1.jpg 008744_0.jpg 018796_1.jpg 008753_0.jpg 003472_1.jpg 008763_0.jpg 007856_1.jpg 008771_0.jpg 005186_1.jpg 008784_0.jpg 006329_1.jpg 008793_0.jpg 014240_1.jpg 008804_0.jpg 013490_1.jpg 008813_0.jpg 011347_1.jpg 008822_0.jpg 002553_1.jpg 008830_0.jpg 017118_1.jpg 008839_0.jpg 013989_1.jpg 008847_0.jpg 012754_1.jpg 008855_0.jpg 005241_1.jpg 008863_0.jpg 018848_1.jpg 008871_0.jpg 006738_1.jpg 008881_0.jpg 002739_1.jpg 008891_0.jpg 015816_1.jpg 008900_0.jpg 019376_1.jpg 008908_0.jpg 009975_1.jpg 008919_0.jpg 011798_1.jpg 008928_0.jpg 001337_1.jpg 008938_0.jpg 009074_1.jpg 008949_0.jpg 002039_1.jpg 008959_0.jpg 002681_1.jpg 008967_0.jpg 012033_1.jpg 008976_0.jpg 006440_1.jpg 008986_0.jpg 015524_1.jpg 008997_0.jpg 003226_1.jpg 009008_0.jpg 004691_1.jpg 009016_0.jpg 013855_1.jpg 009024_0.jpg 014379_1.jpg 009034_0.jpg 012385_1.jpg 009042_0.jpg 000685_1.jpg 009054_0.jpg 015403_1.jpg 009064_0.jpg 017449_1.jpg 009074_0.jpg 018112_1.jpg 009084_0.jpg 014220_1.jpg 009094_0.jpg 014076_1.jpg 009106_0.jpg 016039_1.jpg 009114_0.jpg 010653_1.jpg 009123_0.jpg 001756_1.jpg 009131_0.jpg 003953_1.jpg 009141_0.jpg 012917_1.jpg 009149_0.jpg 015476_1.jpg 009159_0.jpg 010762_1.jpg 009169_0.jpg 017648_1.jpg 009178_0.jpg 008919_1.jpg 009189_0.jpg 007463_1.jpg 009197_0.jpg 006065_1.jpg 009205_0.jpg 014537_1.jpg 009215_0.jpg 007252_1.jpg 009228_0.jpg 007212_1.jpg 009236_0.jpg 017622_1.jpg 009246_0.jpg 007232_1.jpg 009254_0.jpg 010918_1.jpg 009263_0.jpg 016094_1.jpg 009274_0.jpg 007221_1.jpg 009282_0.jpg 005691_1.jpg 009291_0.jpg 002345_1.jpg 009300_0.jpg 009300_1.jpg 009312_0.jpg 014629_1.jpg 009323_0.jpg 010133_1.jpg 009332_0.jpg 016697_1.jpg 009342_0.jpg 016262_1.jpg 009356_0.jpg 011568_1.jpg 009365_0.jpg 003115_1.jpg 009374_0.jpg 008542_1.jpg 009382_0.jpg 010789_1.jpg 009390_0.jpg 013743_1.jpg 009399_0.jpg 009374_1.jpg 009409_0.jpg 011106_1.jpg 009418_0.jpg 013620_1.jpg 009426_0.jpg 006817_1.jpg 009435_0.jpg 012702_1.jpg 009446_0.jpg 002575_1.jpg 009454_0.jpg 017730_1.jpg 009462_0.jpg 016831_1.jpg 009474_0.jpg 006194_1.jpg 009482_0.jpg 007086_1.jpg 009496_0.jpg 001064_1.jpg 009505_0.jpg 011004_1.jpg 009515_0.jpg 014968_1.jpg 009525_0.jpg 002259_1.jpg 009537_0.jpg 003545_1.jpg 009545_0.jpg 002147_1.jpg 009561_0.jpg 003833_1.jpg 009571_0.jpg 007966_1.jpg 009586_0.jpg 017877_1.jpg 009595_0.jpg 007003_1.jpg 009605_0.jpg 016220_1.jpg 009619_0.jpg 017306_1.jpg 009627_0.jpg 010644_1.jpg 009635_0.jpg 008295_1.jpg 009643_0.jpg 018318_1.jpg 009651_0.jpg 013173_1.jpg 009660_0.jpg 010445_1.jpg 009668_0.jpg 002068_1.jpg 009679_0.jpg 003187_1.jpg 009689_0.jpg 011058_1.jpg 009699_0.jpg 005657_1.jpg 009709_0.jpg 009882_1.jpg 009722_0.jpg 009228_1.jpg 009730_0.jpg 015794_1.jpg 009741_0.jpg 009399_1.jpg 009758_0.jpg 013555_1.jpg 009766_0.jpg 013265_1.jpg 009780_0.jpg 013863_1.jpg 009790_0.jpg 001283_1.jpg 009799_0.jpg 018755_1.jpg 009809_0.jpg 006393_1.jpg 009822_0.jpg 009903_1.jpg 009832_0.jpg 004148_1.jpg 009843_0.jpg 018561_1.jpg 009852_0.jpg 018059_1.jpg 009860_0.jpg 010575_1.jpg 009872_0.jpg 008266_1.jpg 009882_0.jpg 015615_1.jpg 009894_0.jpg 006250_1.jpg 009903_0.jpg 014232_1.jpg 009912_0.jpg 015707_1.jpg 009922_0.jpg 016812_1.jpg 009932_0.jpg 007672_1.jpg 009941_0.jpg 012785_1.jpg 009949_0.jpg 000924_1.jpg 009959_0.jpg 009016_1.jpg 009967_0.jpg 008976_1.jpg 009975_0.jpg 017688_1.jpg 009984_0.jpg 016426_1.jpg 009995_0.jpg 003376_1.jpg 010003_0.jpg 015637_1.jpg 010011_0.jpg 014498_1.jpg 010021_0.jpg 018236_1.jpg 010031_0.jpg 016112_1.jpg 010040_0.jpg 001957_1.jpg 010049_0.jpg 015181_1.jpg 010057_0.jpg 017860_1.jpg 010067_0.jpg 015173_1.jpg 010078_0.jpg 008706_1.jpg 010088_0.jpg 009323_1.jpg 010096_0.jpg 019096_1.jpg 010105_0.jpg 001983_1.jpg 010115_0.jpg 013165_1.jpg 010125_0.jpg 001947_1.jpg 010133_0.jpg 004785_1.jpg 010143_0.jpg 010225_1.jpg 010152_0.jpg 000610_1.jpg 010160_0.jpg 004023_1.jpg 010168_0.jpg 019001_1.jpg 010177_0.jpg 006478_1.jpg 010185_0.jpg 007336_1.jpg 010195_0.jpg 017831_1.jpg 010206_0.jpg 003712_1.jpg 010215_0.jpg 015036_1.jpg 010225_0.jpg 003972_1.jpg 010234_0.jpg 001891_1.jpg 010244_0.jpg 001387_1.jpg 010253_0.jpg 014736_1.jpg 010261_0.jpg 013923_1.jpg 010270_0.jpg 006728_1.jpg 010281_0.jpg 004896_1.jpg 010289_0.jpg 011076_1.jpg 010300_0.jpg 012303_1.jpg 010308_0.jpg 001092_1.jpg 010318_0.jpg 012089_1.jpg 010329_0.jpg 006452_1.jpg 010337_0.jpg 018263_1.jpg 010346_0.jpg 016191_1.jpg 010357_0.jpg 017145_1.jpg 010371_0.jpg 010515_1.jpg 010381_0.jpg 006709_1.jpg 010392_0.jpg 013319_1.jpg 010404_0.jpg 000659_1.jpg 010415_0.jpg 016562_1.jpg 010431_0.jpg 016254_1.jpg 010445_0.jpg 014744_1.jpg 010454_0.jpg 017722_1.jpg 010463_0.jpg 003795_1.jpg 010473_0.jpg 013753_1.jpg 010481_0.jpg 009409_1.jpg 010493_0.jpg 015230_1.jpg 010503_0.jpg 017701_1.jpg 010515_0.jpg 002930_1.jpg 010527_0.jpg 008986_1.jpg 010535_0.jpg 000827_1.jpg 010543_0.jpg 008354_1.jpg 010551_0.jpg 015069_1.jpg 010559_0.jpg 012514_1.jpg 010567_0.jpg 012681_1.jpg 010575_0.jpg 017710_1.jpg 010583_0.jpg 002852_1.jpg 010591_0.jpg 006825_1.jpg 010599_0.jpg 016154_1.jpg 010608_0.jpg 015450_1.jpg 010620_0.jpg 009064_1.jpg 010628_0.jpg 002922_1.jpg 010636_0.jpg 004131_1.jpg 010644_0.jpg 007021_1.jpg 010653_0.jpg 019438_1.jpg 010662_0.jpg 003535_1.jpg 010670_0.jpg 003060_1.jpg 010683_0.jpg 001349_1.jpg 010691_0.jpg 003874_1.jpg 010699_0.jpg 017167_1.jpg 010710_0.jpg 018441_1.jpg 010718_0.jpg 011425_1.jpg 010726_0.jpg 001038_1.jpg 010735_0.jpg 007536_1.jpg 010744_0.jpg 000676_1.jpg 010753_0.jpg 011485_1.jpg 010762_0.jpg 002200_1.jpg 010770_0.jpg 007495_1.jpg 010778_0.jpg 006462_1.jpg 010789_0.jpg 016086_1.jpg 010797_0.jpg 013298_1.jpg 010806_0.jpg 015869_1.jpg 010816_0.jpg 009832_1.jpg 010830_0.jpg 013734_1.jpg 010840_0.jpg 010011_1.jpg 010851_0.jpg 009189_1.jpg 010859_0.jpg 004997_1.jpg 010869_0.jpg 004572_1.jpg 010882_0.jpg 012898_1.jpg 010891_0.jpg 011680_1.jpg 010900_0.jpg 001919_1.jpg 010910_0.jpg 006186_1.jpg 010918_0.jpg 010346_1.jpg 010929_0.jpg 007199_1.jpg 010937_0.jpg 016388_1.jpg 010947_0.jpg 017051_1.jpg 010959_0.jpg 017273_1.jpg 010967_0.jpg 012487_1.jpg 010976_0.jpg 018980_1.jpg 010984_0.jpg 018636_1.jpg 010995_0.jpg 008126_1.jpg 011004_0.jpg 014693_1.jpg 011015_0.jpg 008080_1.jpg 011023_0.jpg 002413_1.jpg 011034_0.jpg 018807_1.jpg 011042_0.jpg 007029_1.jpg 011050_0.jpg 012116_1.jpg 011058_0.jpg 019204_1.jpg 011068_0.jpg 007681_1.jpg 011076_0.jpg 000293_1.jpg 011087_0.jpg 012265_1.jpg 011097_0.jpg 019053_1.jpg 011106_0.jpg 003668_1.jpg 011120_0.jpg 014387_1.jpg 011128_0.jpg 009159_1.jpg 011137_0.jpg 003611_1.jpg 011152_0.jpg 003676_1.jpg 011164_0.jpg 018375_1.jpg 011173_0.jpg 009106_1.jpg 011181_0.jpg 005763_1.jpg 011190_0.jpg 000370_1.jpg 011203_0.jpg 001528_1.jpg 011212_0.jpg 018737_1.jpg 011221_0.jpg 005062_1.jpg 011231_0.jpg 016021_1.jpg 011240_0.jpg 008285_1.jpg 011249_0.jpg 016612_1.jpg 011258_0.jpg 012183_1.jpg 011270_0.jpg 005510_1.jpg 011278_0.jpg 014987_1.jpg 011288_0.jpg 002651_1.jpg 011300_0.jpg 006045_1.jpg 011309_0.jpg 003981_1.jpg 011318_0.jpg 006371_1.jpg 011328_0.jpg 004091_1.jpg 011336_0.jpg 009941_1.jpg 011347_0.jpg 014360_1.jpg 011355_0.jpg 004702_1.jpg 011363_0.jpg 010195_1.jpg 011372_0.jpg 008523_1.jpg 011381_0.jpg 003077_1.jpg 011392_0.jpg 018357_1.jpg 011401_0.jpg 001056_1.jpg 011415_0.jpg 016971_1.jpg 011425_0.jpg 009799_1.jpg 011436_0.jpg 009246_1.jpg 011447_0.jpg 006502_1.jpg 011457_0.jpg 005430_1.jpg 011466_0.jpg 002447_1.jpg 011475_0.jpg 015487_1.jpg 011485_0.jpg 014666_1.jpg 011495_0.jpg 009967_1.jpg 011506_0.jpg 002839_1.jpg 011515_0.jpg 006145_1.jpg 011523_0.jpg 017990_1.jpg 011536_0.jpg 010067_1.jpg 011544_0.jpg 014280_1.jpg 011552_0.jpg 017974_1.jpg 011560_0.jpg 000734_1.jpg 011568_0.jpg 012495_1.jpg 011577_0.jpg 013601_1.jpg 011585_0.jpg 018146_1.jpg 011596_0.jpg 012149_1.jpg 011604_0.jpg 002059_1.jpg 011615_0.jpg 008736_1.jpg 011623_0.jpg 004854_1.jpg 011631_0.jpg 009332_1.jpg 011641_0.jpg 003565_1.jpg 011654_0.jpg 005898_1.jpg 011662_0.jpg 000001_1.jpg 011670_0.jpg 016484_1.jpg 011680_0.jpg 015654_1.jpg 011689_0.jpg 001655_1.jpg 011699_0.jpg 006512_1.jpg 011708_0.jpg 000768_1.jpg 011716_0.jpg 001162_1.jpg 011724_0.jpg 016495_1.jpg 011736_0.jpg 012926_1.jpg 011745_0.jpg 012202_1.jpg 011761_0.jpg 006563_1.jpg 011769_0.jpg 003133_1.jpg 011781_0.jpg 002494_1.jpg 011790_0.jpg 008997_1.jpg 011798_0.jpg 012907_1.jpg 011806_0.jpg 005622_1.jpg 011816_0.jpg 014685_1.jpg 011825_0.jpg 014582_1.jpg 011833_0.jpg 008839_1.jpg 011842_0.jpg 006670_1.jpg 011850_0.jpg 015928_1.jpg 011862_0.jpg 016839_1.jpg 011872_0.jpg 000877_1.jpg 011883_0.jpg 016644_1.jpg 011891_0.jpg 010253_1.jpg 011899_0.jpg 018488_1.jpg 011908_0.jpg 011604_1.jpg 011916_0.jpg 010057_1.jpg 011924_0.jpg 000668_1.jpg 011933_0.jpg 006410_1.jpg 011944_0.jpg 011623_1.jpg 011954_0.jpg 005195_1.jpg 011962_0.jpg 004867_1.jpg 011970_0.jpg 012616_1.jpg 011980_0.jpg 009024_1.jpg 011988_0.jpg 002610_1.jpg 011996_0.jpg 012803_1.jpg 012006_0.jpg 001457_1.jpg 012015_0.jpg 018644_1.jpg 012025_0.jpg 011790_1.jpg 012033_0.jpg 006968_1.jpg 012044_0.jpg 015095_1.jpg 012054_0.jpg 007313_1.jpg 012063_0.jpg 015516_1.jpg 012072_0.jpg 006486_1.jpg 012081_0.jpg 018590_1.jpg 012089_0.jpg 013147_1.jpg 012099_0.jpg 006224_1.jpg 012107_0.jpg 001467_1.jpg 012116_0.jpg 009454_1.jpg 012127_0.jpg 005213_1.jpg 012137_0.jpg 001269_1.jpg 012149_0.jpg 010830_1.jpg 012158_0.jpg 013510_1.jpg 012166_0.jpg 018729_1.jpg 012174_0.jpg 000957_1.jpg 012183_0.jpg 018291_1.jpg 012193_0.jpg 011249_1.jpg 012202_0.jpg 003882_1.jpg 012219_0.jpg 004277_1.jpg 012228_0.jpg 006555_1.jpg 012236_0.jpg 015045_1.jpg 012245_0.jpg 008258_1.jpg 012256_0.jpg 017099_1.jpg 012265_0.jpg 009462_1.jpg 012273_0.jpg 004516_1.jpg 012282_0.jpg 008233_1.jpg 012291_0.jpg 001009_1.jpg 012303_0.jpg 018876_1.jpg 012311_0.jpg 001845_1.jpg 012322_0.jpg 013060_1.jpg 012330_0.jpg 015645_1.jpg 012338_0.jpg 000812_1.jpg 012350_0.jpg 011023_1.jpg 012359_0.jpg 013117_1.jpg 012369_0.jpg 009474_1.jpg 012377_0.jpg 017227_1.jpg 012385_0.jpg 005110_1.jpg 012395_0.jpg 015662_1.jpg 012404_0.jpg 000174_1.jpg 012413_0.jpg 007949_1.jpg 012422_0.jpg 009042_1.jpg 012430_0.jpg 006620_1.jpg 012440_0.jpg 009446_1.jpg 012451_0.jpg 007159_1.jpg 012460_0.jpg 012025_1.jpg 012469_0.jpg 015334_1.jpg 012479_0.jpg 017021_1.jpg 012487_0.jpg 014055_1.jpg 012495_0.jpg 002156_1.jpg 012505_0.jpg 002911_1.jpg 012514_0.jpg 004285_1.jpg 012522_0.jpg 015740_1.jpg 012531_0.jpg 005702_1.jpg 012545_0.jpg 005755_1.jpg 012553_0.jpg 016415_1.jpg 012564_0.jpg 013931_1.jpg 012578_0.jpg 014252_1.jpg 012587_0.jpg 016687_1.jpg 012597_0.jpg 016309_1.jpg 012605_0.jpg 004561_1.jpg 012616_0.jpg 009790_1.jpg 012626_0.jpg 000209_1.jpg 012636_0.jpg 004666_1.jpg 012644_0.jpg 017922_1.jpg 012652_0.jpg 002545_1.jpg 012660_0.jpg 017957_1.jpg 012669_0.jpg 005846_1.jpg 012681_0.jpg 015955_1.jpg 012694_0.jpg 001683_1.jpg 012702_0.jpg 015671_1.jpg 012712_0.jpg 005457_1.jpg 012725_0.jpg 019243_1.jpg 012734_0.jpg 008041_1.jpg 012743_0.jpg 001928_1.jpg 012754_0.jpg 003142_1.jpg 012763_0.jpg 006776_1.jpg 012773_0.jpg 009679_1.jpg 012785_0.jpg 015412_1.jpg 012795_0.jpg 018337_1.jpg 012803_0.jpg 013997_1.jpg 012811_0.jpg 001834_1.jpg 012822_0.jpg 013284_1.jpg 012830_0.jpg 008479_1.jpg 012838_0.jpg 015889_1.jpg 012849_0.jpg 015439_1.jpg 012860_0.jpg 012107_1.jpg 012868_0.jpg 003250_1.jpg 012879_0.jpg 017282_1.jpg 012889_0.jpg 000795_1.jpg 012898_0.jpg 002758_1.jpg 012907_0.jpg 012987_1.jpg 012917_0.jpg 016102_1.jpg 012926_0.jpg 016328_1.jpg 012934_0.jpg 010551_1.jpg 012944_0.jpg 016921_1.jpg 012953_0.jpg 001310_1.jpg 012964_0.jpg 006203_1.jpg 012975_0.jpg 007423_1.jpg 012987_0.jpg 015200_1.jpg 012996_0.jpg 012669_1.jpg 013007_0.jpg 014920_1.jpg 013019_0.jpg 003069_1.jpg 013028_0.jpg 000164_1.jpg 013036_0.jpg 008598_1.jpg 013047_0.jpg 018507_1.jpg 013060_0.jpg 009741_1.jpg 013068_0.jpg 012081_1.jpg 013076_0.jpg 011654_1.jpg 013084_0.jpg 012830_1.jpg 013097_0.jpg 002307_1.jpg 013106_0.jpg 000542_1.jpg 013117_0.jpg 014755_1.jpg 013127_0.jpg 008763_1.jpg 013139_0.jpg 009809_1.jpg 013147_0.jpg 008462_1.jpg 013155_0.jpg 013789_1.jpg 013165_0.jpg 007526_1.jpg 013173_0.jpg 010404_1.jpg 013181_0.jpg 005222_1.jpg 013190_0.jpg 014908_1.jpg 013199_0.jpg 019486_1.jpg 013214_0.jpg 017770_1.jpg 013224_0.jpg 004590_1.jpg 013233_0.jpg 007357_1.jpg 013245_0.jpg 005562_1.jpg 013256_0.jpg 012773_1.jpg 013265_0.jpg 018039_1.jpg 013273_0.jpg 017062_1.jpg 013284_0.jpg 002474_1.jpg 013298_0.jpg 002208_1.jpg 013309_0.jpg 002031_1.jpg 013319_0.jpg 009169_1.jpg 013327_0.jpg 006036_1.jpg 013338_0.jpg 012311_1.jpg 013355_0.jpg 018626_1.jpg 013365_0.jpg 014272_1.jpg 013374_0.jpg 014035_1.jpg 013382_0.jpg 016515_1.jpg 013391_0.jpg 004758_1.jpg 013400_0.jpg 002093_1.jpg 013410_0.jpg 004462_1.jpg 013418_0.jpg 000284_1.jpg 013428_0.jpg 008188_1.jpg 013437_0.jpg 006260_1.jpg 013447_0.jpg 007188_1.jpg 013456_0.jpg 017563_1.jpg 013469_0.jpg 009984_1.jpg 013478_0.jpg 005166_1.jpg 013490_0.jpg 009205_1.jpg 013502_0.jpg 008032_1.jpg 013510_0.jpg 005153_1.jpg 013518_0.jpg 000200_1.jpg 013527_0.jpg 013478_1.jpg 013539_0.jpg 012469_1.jpg 013547_0.jpg 017779_1.jpg 013555_0.jpg 019505_1.jpg 013564_0.jpg 016271_1.jpg 013572_0.jpg 014406_1.jpg 013583_0.jpg 006296_1.jpg 013593_0.jpg 009959_1.jpg 013601_0.jpg 013968_1.jpg 013611_0.jpg 004051_1.jpg 013620_0.jpg 010160_1.jpg 013634_0.jpg 009571_1.jpg 013642_0.jpg 019475_1.jpg 013654_0.jpg 011850_1.jpg 013665_0.jpg 015352_1.jpg 013680_0.jpg 018515_1.jpg 013688_0.jpg 012137_1.jpg 013698_0.jpg 015015_1.jpg 013706_0.jpg 014834_1.jpg 013715_0.jpg 019393_1.jpg 013725_0.jpg 005920_1.jpg 013734_0.jpg 007974_1.jpg 013743_0.jpg 018411_1.jpg 013753_0.jpg 008443_1.jpg 013764_0.jpg 004431_1.jpg 013772_0.jpg 000915_1.jpg 013780_0.jpg 006026_1.jpg 013789_0.jpg 005586_1.jpg 013798_0.jpg 009505_1.jpg 013806_0.jpg 019310_1.jpg 013816_0.jpg 018671_1.jpg 013827_0.jpg 010683_1.jpg 013836_0.jpg 007129_1.jpg 013845_0.jpg 019183_1.jpg 013855_0.jpg 009149_1.jpg 013863_0.jpg 005984_1.jpg 013875_0.jpg 003367_1.jpg 013883_0.jpg 005298_1.jpg 013891_0.jpg 005336_1.jpg 013899_0.jpg 003311_1.jpg 013907_0.jpg 005480_1.jpg 013915_0.jpg 014574_1.jpg 013923_0.jpg 013981_1.jpg 013931_0.jpg 001408_1.jpg 013939_0.jpg 010900_1.jpg 013948_0.jpg 012193_1.jpg 013959_0.jpg 003008_1.jpg 013968_0.jpg 003041_1.jpg 013981_0.jpg 003632_1.jpg 013989_0.jpg 003303_1.jpg 013997_0.jpg 001485_1.jpg 014006_0.jpg 005131_1.jpg 014014_0.jpg 005837_1.jpg 014025_0.jpg 001547_1.jpg 014035_0.jpg 005271_1.jpg 014046_0.jpg 014106_1.jpg 014055_0.jpg 011120_1.jpg 014066_0.jpg 019119_1.jpg 014076_0.jpg 008062_1.jpg 014086_0.jpg 016765_1.jpg 014096_0.jpg 010289_1.jpg 014106_0.jpg 003195_1.jpg 014114_0.jpg 000706_1.jpg 014123_0.jpg 016757_1.jpg 014131_0.jpg 015507_1.jpg 014140_0.jpg 005489_1.jpg 014149_0.jpg 012934_1.jpg 014159_0.jpg 012359_1.jpg 014167_0.jpg 009860_1.jpg 014176_0.jpg 011769_1.jpg 014184_0.jpg 004260_1.jpg 014192_0.jpg 018167_1.jpg 014201_0.jpg 012451_1.jpg 014209_0.jpg 003526_1.jpg 014220_0.jpg 013028_1.jpg 014232_0.jpg 005006_1.jpg 014240_0.jpg 004598_1.jpg 014252_0.jpg 011806_1.jpg 014262_0.jpg 014176_1.jpg 014272_0.jpg 008071_1.jpg 014280_0.jpg 007817_1.jpg 014292_0.jpg 013634_1.jpg 014302_0.jpg 007719_1.jpg 014314_0.jpg 013764_1.jpg 014324_0.jpg 000532_1.jpg 014332_0.jpg 012587_1.jpg 014341_0.jpg 016397_1.jpg 014349_0.jpg 018300_1.jpg 014360_0.jpg 008118_1.jpg 014370_0.jpg 000118_1.jpg 014379_0.jpg 006173_1.jpg 014387_0.jpg 002287_1.jpg 014396_0.jpg 002405_1.jpg 014406_0.jpg 011181_1.jpg 014416_0.jpg 002388_1.jpg 014426_0.jpg 003461_1.jpg 014434_0.jpg 001937_1.jpg 014443_0.jpg 019465_1.jpg 014452_0.jpg 017657_1.jpg 014463_0.jpg 001664_1.jpg 014477_0.jpg 010984_1.jpg 014489_0.jpg 014046_1.jpg 014498_0.jpg 017932_1.jpg 014507_0.jpg 003451_1.jpg 014518_0.jpg 016338_1.jpg 014528_0.jpg 008753_1.jpg 014537_0.jpg 012660_1.jpg 014553_0.jpg 017323_1.jpg 014564_0.jpg 000568_1.jpg 014574_0.jpg 013106_1.jpg 014582_0.jpg 018894_1.jpg 014591_0.jpg 013502_1.jpg 014604_0.jpg 012712_1.jpg 014612_0.jpg 005737_1.jpg 014621_0.jpg 017041_1.jpg 014629_0.jpg 019420_1.jpg 014639_0.jpg 001868_1.jpg 014652_0.jpg 016435_1.jpg 014666_0.jpg 005285_1.jpg 014675_0.jpg 004795_1.jpg 014685_0.jpg 003434_1.jpg 014693_0.jpg 013611_1.jpg 014701_0.jpg 006589_1.jpg 014712_0.jpg 011309_1.jpg 014720_0.jpg 009586_1.jpg 014728_0.jpg 015220_1.jpg 014736_0.jpg 011137_1.jpg 014744_0.jpg 007570_1.jpg 014755_0.jpg 007056_1.jpg 014765_0.jpg 012044_1.jpg 014774_0.jpg 018254_1.jpg 014785_0.jpg 000786_1.jpg 014794_0.jpg 011372_1.jpg 014805_0.jpg 001695_1.jpg 014816_0.jpg 015598_1.jpg 014825_0.jpg 002712_1.jpg 014834_0.jpg 014452_1.jpg 014844_0.jpg 011908_1.jpg 014854_0.jpg 018129_1.jpg 014863_0.jpg 017153_1.jpg 014876_0.jpg 010976_1.jpg 014888_0.jpg 016929_1.jpg 014900_0.jpg 009365_1.jpg 014908_0.jpg 012282_1.jpg 014920_0.jpg 008389_1.jpg 014930_0.jpg 012460_1.jpg 014939_0.jpg 011631_1.jpg 014950_0.jpg 013273_1.jpg 014959_0.jpg 003768_1.jpg 014968_0.jpg 002248_1.jpg 014979_0.jpg 005675_1.jpg 014987_0.jpg 013365_1.jpg 014995_0.jpg 006688_1.jpg 015006_0.jpg 006268_1.jpg 015015_0.jpg 017982_1.jpg 015026_0.jpg 006241_1.jpg 015036_0.jpg 014167_1.jpg 015045_0.jpg 016981_1.jpg 015060_0.jpg 009382_1.jpg 015069_0.jpg 005501_1.jpg 015077_0.jpg 014518_1.jpg 015085_0.jpg 016130_1.jpg 015095_0.jpg 001614_1.jpg 015105_0.jpg 011862_1.jpg 015114_0.jpg 002455_1.jpg 015125_0.jpg 016707_1.jpg 015133_0.jpg 014443_1.jpg 015141_0.jpg 000339_1.jpg 015150_0.jpg 014825_1.jpg 015158_0.jpg 005771_1.jpg 015173_0.jpg 005929_1.jpg 015181_0.jpg 003150_1.jpg 015192_0.jpg 004683_1.jpg 015200_0.jpg 007388_1.jpg 015209_0.jpg 009356_1.jpg 015220_0.jpg 011699_1.jpg 015230_0.jpg 004487_1.jpg 015238_0.jpg 013224_1.jpg 015247_0.jpg 004674_1.jpg 015256_0.jpg 018817_1.jpg 015264_0.jpg 007561_1.jpg 015272_0.jpg 010959_1.jpg 015280_0.jpg 013845_1.jpg 015291_0.jpg 011506_1.jpg 015299_0.jpg 010670_1.jpg 015308_0.jpg 019018_1.jpg 015317_0.jpg 010185_1.jpg 015325_0.jpg 006155_1.jpg 015334_0.jpg 005578_1.jpg 015344_0.jpg 000742_1.jpg 015352_0.jpg 002327_1.jpg 015362_0.jpg 005072_1.jpg 015371_0.jpg 009912_1.jpg 015381_0.jpg 009822_1.jpg 015392_0.jpg 001073_1.jpg 015403_0.jpg 005014_1.jpg 015412_0.jpg 015542_1.jpg 015420_0.jpg 007037_1.jpg 015428_0.jpg 018245_1.jpg 015439_0.jpg 006748_1.jpg 015450_0.jpg 006099_1.jpg 015465_0.jpg 008580_1.jpg 015476_0.jpg 000330_1.jpg 015487_0.jpg 013076_1.jpg 015497_0.jpg 012953_1.jpg 015507_0.jpg 018652_1.jpg 015516_0.jpg 012430_1.jpg 015524_0.jpg 014159_1.jpg 015542_0.jpg 019531_1.jpg 015550_0.jpg 013875_1.jpg 015560_0.jpg 012422_1.jpg 015571_0.jpg 018618_1.jpg 015579_0.jpg 005031_1.jpg 015590_0.jpg 003963_1.jpg 015598_0.jpg 018159_1.jpg 015607_0.jpg 005422_1.jpg 015615_0.jpg 010699_1.jpg 015627_0.jpg 018884_1.jpg 015637_0.jpg 012522_1.jpg 015645_0.jpg 017536_1.jpg 015654_0.jpg 009843_1.jpg 015662_0.jpg 002011_1.jpg 015671_0.jpg 011152_1.jpg 015680_0.jpg 005449_1.jpg 015688_0.jpg 001419_1.jpg 015697_0.jpg 004314_1.jpg 015707_0.jpg 018121_1.jpg 015715_0.jpg 013084_1.jpg 015724_0.jpg 006313_1.jpg 015732_0.jpg 013816_1.jpg 015740_0.jpg 014995_1.jpg 015748_0.jpg 001502_1.jpg 015759_0.jpg 003649_1.jpg 015767_0.jpg 000437_1.jpg 015776_0.jpg 009651_1.jpg 015785_0.jpg 005470_1.jpg 015794_0.jpg 009123_1.jpg 015803_0.jpg 005145_1.jpg 015816_0.jpg 004115_1.jpg 015825_0.jpg 008871_1.jpg 015836_0.jpg 006118_1.jpg 015844_0.jpg 007294_1.jpg 015853_0.jpg 005101_1.jpg 015861_0.jpg 017592_1.jpg 015869_0.jpg 011724_1.jpg 015881_0.jpg 008180_1.jpg 015889_0.jpg 009699_1.jpg 015900_0.jpg 017079_1.jpg 015908_0.jpg 008533_1.jpg 015916_0.jpg 002533_1.jpg 015928_0.jpg 017418_1.jpg 015938_0.jpg 007874_1.jpg 015946_0.jpg 014426_1.jpg 015955_0.jpg 018662_1.jpg 015969_0.jpg 009561_1.jpg 015979_0.jpg 007848_1.jpg 015990_0.jpg 010882_1.jpg 016002_0.jpg 006358_1.jpg 016013_0.jpg 014528_1.jpg 016021_0.jpg 003621_1.jpg 016031_0.jpg 002883_1.jpg 016039_0.jpg 009894_1.jpg 016049_0.jpg 004252_1.jpg 016059_0.jpg 012291_1.jpg 016067_0.jpg 006523_1.jpg 016075_0.jpg 007121_1.jpg 016086_0.jpg 016505_1.jpg 016094_0.jpg 004378_1.jpg 016102_0.jpg 011716_1.jpg 016112_0.jpg 000560_1.jpg 016121_0.jpg 004478_1.jpg 016130_0.jpg 002803_1.jpg 016145_0.jpg 016455_1.jpg 016154_0.jpg 008949_1.jpg 016163_0.jpg 002276_1.jpg 016172_0.jpg 016163_1.jpg 016183_0.jpg 005728_1.jpg 016191_0.jpg 011536_1.jpg 016206_0.jpg 015344_1.jpg 016220_0.jpg 002670_1.jpg 016230_0.jpg 002226_1.jpg 016238_0.jpg 008855_1.jpg 016246_0.jpg 003481_1.jpg 016254_0.jpg 015060_1.jpg 016262_0.jpg 007138_1.jpg 016271_0.jpg 017390_1.jpg 016281_0.jpg 018598_1.jpg 016290_0.jpg 015680_1.jpg 016300_0.jpg 009627_1.jpg 016309_0.jpg 015238_1.jpg 016317_0.jpg 004107_1.jpg 016328_0.jpg 015776_1.jpg 016338_0.jpg 009668_1.jpg 016349_0.jpg 008250_1.jpg 016358_0.jpg 006889_1.jpg 016367_0.jpg 008813_1.jpg 016379_0.jpg 003107_1.jpg 016388_0.jpg 014785_1.jpg 016397_0.jpg 002728_1.jpg 016405_0.jpg 000356_1.jpg 016415_0.jpg 014096_1.jpg 016426_0.jpg 016230_1.jpg 016435_0.jpg 005175_1.jpg 016445_0.jpg 010770_1.jpg 016455_0.jpg 013518_1.jpg 016465_0.jpg 012158_1.jpg 016474_0.jpg 017613_1.jpg 016484_0.jpg 019166_1.jpg 016495_0.jpg 009722_1.jpg 016505_0.jpg 018858_1.jpg 016515_0.jpg 009515_1.jpg 016524_0.jpg 009537_1.jpg 016533_0.jpg 006276_1.jpg 016541_0.jpg 016853_1.jpg 016550_0.jpg 013772_1.jpg 016562_0.jpg 019154_1.jpg 016571_0.jpg 017514_1.jpg 016584_0.jpg 013447_1.jpg 016593_0.jpg 018309_1.jpg 016602_0.jpg 010088_1.jpg 016612_0.jpg 003658_1.jpg 016620_0.jpg 003760_1.jpg 016628_0.jpg 007750_1.jpg 016636_0.jpg 004470_1.jpg 016644_0.jpg 015158_1.jpg 016653_0.jpg 008725_1.jpg 016662_0.jpg 010357_1.jpg 016676_0.jpg 016013_1.jpg 016687_0.jpg 014025_1.jpg 016697_0.jpg 008487_1.jpg 016707_0.jpg 003094_1.jpg 016716_0.jpg 014066_1.jpg 016726_0.jpg 011164_1.jpg 016739_0.jpg 017805_1.jpg 016748_0.jpg 012822_1.jpg 016757_0.jpg 009730_1.jpg 016765_0.jpg 007180_1.jpg 016777_0.jpg 000066_1.jpg 016786_0.jpg 017340_1.jpg 016799_0.jpg 007656_1.jpg 016812_0.jpg 003032_1.jpg 016820_0.jpg 000776_1.jpg 016831_0.jpg 007702_1.jpg 016839_0.jpg 004609_1.jpg 016853_0.jpg 003386_1.jpg 016866_0.jpg 010778_1.jpg 016878_0.jpg 012479_1.jpg 016888_0.jpg 003703_1.jpg 016899_0.jpg 002778_1.jpg 016908_0.jpg 018867_1.jpg 016921_0.jpg 004177_1.jpg 016929_0.jpg 005683_1.jpg 016943_0.jpg 000109_1.jpg 016951_0.jpg 006928_1.jpg 016962_0.jpg 014675_1.jpg 016971_0.jpg 007940_1.jpg 016981_0.jpg 019270_1.jpg 016992_0.jpg 013547_1.jpg 017002_0.jpg 013665_1.jpg 017012_0.jpg 008881_1.jpg 017021_0.jpg 000048_1.jpg 017030_0.jpg 004139_1.jpg 017041_0.jpg 003236_1.jpg 017051_0.jpg 001136_1.jpg 017062_0.jpg 001320_1.jpg 017070_0.jpg 016121_1.jpg 017079_0.jpg 014728_1.jpg 017091_0.jpg 010215_1.jpg 017099_0.jpg 004941_1.jpg 017110_0.jpg 018183_1.jpg 017118_0.jpg 001048_1.jpg 017130_0.jpg 002901_1.jpg 017145_0.jpg 008793_1.jpg 017153_0.jpg 015114_1.jpg 017167_0.jpg 007168_1.jpg 017175_0.jpg 014639_1.jpg 017188_0.jpg 001706_1.jpg 017196_0.jpg 010308_1.jpg 017204_0.jpg 016349_1.jpg 017213_0.jpg 002362_1.jpg 017227_0.jpg 001219_1.jpg 017235_0.jpg 010559_1.jpg 017243_0.jpg 003024_1.jpg 017254_0.jpg 003591_1.jpg 017264_0.jpg 017358_1.jpg 017273_0.jpg 004042_1.jpg 017282_0.jpg 012377_1.jpg 017290_0.jpg 007762_1.jpg 017298_0.jpg 015247_1.jpg 017306_0.jpg 018787_1.jpg 017315_0.jpg 010503_1.jpg 017323_0.jpg 000602_1.jpg 017332_0.jpg 001635_1.jpg 017340_0.jpg 006842_1.jpg 017348_0.jpg 017482_1.jpg 017358_0.jpg 012440_1.jpg 017370_0.jpg 019215_1.jpg 017382_0.jpg 019590_1.jpg 017390_0.jpg 003990_1.jpg 017400_0.jpg 008334_1.jpg 017410_0.jpg 017213_1.jpg 017418_0.jpg 010392_1.jpg 017428_0.jpg 018991_1.jpg 017438_0.jpg 001817_1.jpg 017449_0.jpg 014950_1.jpg 017457_0.jpg 006649_1.jpg 017466_0.jpg 013437_1.jpg 017474_0.jpg 016602_1.jpg 017482_0.jpg 007269_1.jpg 017496_0.jpg 011495_1.jpg 017505_0.jpg 000386_1.jpg 017514_0.jpg 013190_1.jpg 017526_0.jpg 004387_1.jpg 017536_0.jpg 003328_1.jpg 017545_0.jpg 006799_1.jpg 017555_0.jpg 012413_1.jpg 017563_0.jpg 008515_1.jpg 017575_0.jpg 010152_1.jpg 017583_0.jpg 011328_1.jpg 017592_0.jpg 018910_1.jpg 017600_0.jpg 018718_1.jpg 017613_0.jpg 000378_1.jpg 017622_0.jpg 019193_1.jpg 017630_0.jpg 018280_1.jpg 017639_0.jpg 013181_1.jpg 017648_0.jpg 011363_1.jpg 017657_0.jpg 001173_1.jpg 017667_0.jpg 004243_1.jpg 017678_0.jpg 013959_1.jpg 017688_0.jpg 016908_1.jpg 017701_0.jpg 013539_1.jpg 017710_0.jpg 013456_1.jpg 017722_0.jpg 004234_1.jpg 017730_0.jpg 001203_1.jpg 017740_0.jpg 013400_1.jpg 017750_0.jpg 011781_1.jpg 017761_0.jpg 011258_1.jpg 017770_0.jpg 006908_1.jpg 017779_0.jpg 009660_1.jpg 017788_0.jpg 002191_1.jpg 017796_0.jpg 006757_1.jpg 017805_0.jpg 005857_1.jpg 017814_0.jpg 011641_1.jpg 017823_0.jpg 007923_1.jpg 017831_0.jpg 004949_1.jpg 017840_0.jpg 018580_1.jpg 017852_0.jpg 017999_1.jpg 017860_0.jpg 008653_1.jpg 017868_0.jpg 011980_1.jpg 017877_0.jpg 017382_1.jpg 017886_0.jpg 011899_1.jpg 017896_0.jpg 002169_1.jpg 017904_0.jpg 010318_1.jpg 017914_0.jpg 017740_1.jpg 017922_0.jpg 011221_1.jpg 017932_0.jpg 004989_1.jpg 017945_0.jpg 003915_1.jpg 017957_0.jpg 001789_1.jpg 017965_0.jpg 003925_1.jpg 017974_0.jpg 002337_1.jpg 017982_0.jpg 008624_1.jpg 017990_0.jpg 004220_1.jpg 017999_0.jpg 001594_1.jpg 018009_0.jpg 006004_1.jpg 018018_0.jpg 019350_1.jpg 018031_0.jpg 018552_1.jpg 018039_0.jpg 010031_1.jpg 018047_0.jpg 013256_1.jpg 018059_0.jpg 001809_1.jpg 018069_0.jpg 006868_1.jpg 018080_0.jpg 000303_1.jpg 018089_0.jpg 007882_1.jpg 018102_0.jpg 016676_1.jpg 018112_0.jpg 009619_1.jpg 018121_0.jpg 017965_1.jpg 018129_0.jpg 010049_1.jpg 018138_0.jpg 018938_1.jpg 018146_0.jpg 014209_1.jpg 018159_0.jpg 007549_1.jpg 018167_0.jpg 009054_1.jpg 018175_0.jpg 008214_1.jpg 018183_0.jpg 003319_1.jpg 018192_0.jpg 016206_1.jpg 018200_0.jpg 017914_1.jpg 018210_0.jpg 016820_1.jpg 018219_0.jpg 007781_1.jpg 018227_0.jpg 006545_1.jpg 018236_0.jpg 001153_1.jpg 018245_0.jpg 000426_1.jpg 018254_0.jpg 014123_1.jpg 018263_0.jpg 006678_1.jpg 018271_0.jpg 017254_1.jpg 018280_0.jpg 001900_1.jpg 018291_0.jpg 019234_1.jpg 018300_0.jpg 012636_1.jpg 018309_0.jpg 001908_1.jpg 018318_0.jpg 017188_1.jpg 018327_0.jpg 009291_1.jpg 018337_0.jpg 009932_1.jpg 018348_0.jpg 003049_1.jpg 018357_0.jpg 003280_1.jpg 018366_0.jpg 000010_1.jpg 018375_0.jpg 015946_1.jpg 018393_0.jpg 002699_1.jpg 018401_0.jpg 002502_1.jpg 018411_0.jpg 004620_1.jpg 018420_0.jpg 002828_1.jpg 018431_0.jpg 016524_1.jpg 018441_0.jpg 005091_1.jpg 018452_0.jpg 015299_1.jpg 018460_0.jpg 011996_1.jpg 018470_0.jpg 006937_1.jpg 018479_0.jpg 003861_1.jpg 018488_0.jpg 015748_1.jpg 018496_0.jpg 005940_1.jpg 018507_0.jpg 001765_1.jpg 018515_0.jpg 013798_1.jpg 018524_0.jpg 017332_1.jpg 018532_0.jpg 005404_1.jpg 018544_0.jpg 010797_1.jpg 018552_0.jpg 006419_1.jpg 018561_0.jpg 019078_1.jpg 018569_0.jpg 014564_1.jpg 018580_0.jpg 008830_1.jpg 018590_0.jpg 016571_1.jpg 018598_0.jpg 011745_1.jpg 018608_0.jpg 000347_1.jpg 018618_0.jpg 003739_1.jpg 018626_0.jpg 011662_1.jpg 018636_0.jpg 001399_1.jpg 018644_0.jpg 004912_1.jpg 018652_0.jpg 017600_1.jpg 018662_0.jpg 018175_1.jpg 018671_0.jpg 013939_1.jpg 018681_0.jpg 006768_1.jpg 018690_0.jpg 014604_1.jpg 018700_0.jpg 009643_1.jpg 018710_0.jpg 005542_1.jpg 018718_0.jpg 003555_1.jpg 018729_0.jpg 006073_1.jpg 018737_0.jpg 014720_1.jpg 018746_0.jpg 017030_1.jpg 018755_0.jpg 017505_1.jpg 018769_0.jpg 003270_1.jpg 018778_0.jpg 007045_1.jpg 018787_0.jpg 004823_1.jpg 018796_0.jpg 007278_1.jpg 018807_0.jpg 002659_1.jpg 018817_0.jpg 008551_1.jpg 018826_0.jpg 011318_1.jpg 018837_0.jpg 016620_1.jpg 018848_0.jpg 011933_1.jpg 018858_0.jpg 019360_1.jpg 018867_0.jpg 004545_1.jpg 018876_0.jpg 000192_1.jpg 018884_0.jpg 005809_1.jpg 018894_0.jpg 012369_1.jpg 018902_0.jpg 019581_1.jpg 018910_0.jpg 004745_1.jpg 018921_0.jpg 013233_1.jpg 018929_0.jpg 008570_1.jpg 018938_0.jpg 012564_1.jpg 018946_0.jpg 013915_1.jpg 018954_0.jpg 011872_1.jpg 018962_0.jpg 014930_1.jpg 018971_0.jpg 017823_1.jpg 018980_0.jpg 018366_1.jpg 018991_0.jpg 006897_1.jpg 019001_0.jpg 010473_1.jpg 019009_0.jpg 011924_1.jpg 019018_0.jpg 001575_1.jpg 019029_0.jpg 002970_1.jpg 019037_0.jpg 000477_1.jpg 019045_0.jpg 018080_1.jpg 019053_0.jpg 008616_1.jpg 019066_0.jpg 017852_1.jpg 019078_0.jpg 007639_1.jpg 019087_0.jpg 000907_1.jpg 019096_0.jpg 009312_1.jpg 019110_0.jpg 004657_1.jpg 019119_0.jpg 001028_1.jpg 019130_0.jpg 006232_1.jpg 019140_0.jpg 011203_1.jpg 019154_0.jpg 012795_1.jpg 019166_0.jpg 013068_1.jpg 019174_0.jpg 000097_1.jpg 019183_0.jpg 009872_1.jpg 019193_0.jpg 013428_1.jpg 019204_0.jpg 016075_1.jpg 019215_0.jpg 004071_1.jpg 019224_0.jpg 011475_1.jpg 019234_0.jpg 013642_1.jpg 019243_0.jpg 018271_1.jpg 019252_0.jpg 011552_1.jpg 019262_0.jpg 005594_1.jpg 019270_0.jpg 016405_1.jpg 019279_0.jpg 010329_1.jpg 019287_0.jpg 010493_1.jpg 019302_0.jpg 018089_1.jpg 019310_0.jpg 019262_1.jpg 019319_0.jpg 017788_1.jpg 019332_0.jpg 014774_1.jpg 019340_0.jpg 009254_1.jpg 019350_0.jpg 012725_1.jpg 019360_0.jpg 008317_1.jpg 019368_0.jpg 000629_1.jpg 019376_0.jpg 017575_1.jpg 019384_0.jpg 007324_1.jpg 019393_0.jpg 013139_1.jpg 019402_0.jpg 012868_1.jpg 019411_0.jpg 001228_1.jpg 019420_0.jpg 006347_1.jpg 019429_0.jpg 006494_1.jpg 019438_0.jpg 008590_1.jpg 019446_0.jpg 006571_1.jpg 019454_0.jpg 012228_1.jpg 019465_0.jpg 010003_1.jpg 019475_0.jpg 006304_1.jpg 019486_0.jpg 013019_1.jpg 019494_0.jpg 010929_1.jpg 019505_0.jpg 010753_1.jpg 019514_0.jpg 012054_1.jpg 019522_0.jpg 018102_1.jpg 019531_0.jpg 015077_1.jpg 019540_0.jpg 008151_1.jpg 019552_0.jpg 003787_1.jpg 019561_0.jpg 006090_1.jpg 019573_0.jpg 008608_1.jpg 019581_0.jpg 006081_1.jpg 019590_0.jpg 012964_1.jpg ================================================ FILE: projects/flow_style_vton/vton_dataset.py ================================================ import os.path import random import numpy as np from PIL import Image from torch.utils.data import Dataset from torchvision import transforms class AlignedDataset(Dataset): def __init__(self, opt): self.opt = opt self.root = opt.dataroot self.fine_height = 256 self.fine_width = 192 self.text = opt.test_pairs dir_I = '_img' self.dir_I = os.path.join(opt.dataroot, opt.phase + dir_I) dir_C = '_clothes' self.dir_C = os.path.join(opt.dataroot, opt.phase + dir_C) dir_E = '_edge' self.dir_E = os.path.join(opt.dataroot, opt.phase + dir_E) self.im_name = [] self.c_name = [] self.e_name = [] self.get_file_name() self.dataset_size = len(self.im_name) def get_file_name(self): with open(self.text, 'r') as f: for line in f.readlines(): im_name, c_name = line.strip().split() self.im_name.append(os.path.join(self.dir_I, im_name)) self.c_name.append(os.path.join(self.dir_C, c_name)) self.e_name.append(os.path.join(self.dir_E, c_name)) def __getitem__(self, index): I_path = os.path.join(self.im_name[index]) img = Image.open(I_path).convert('RGB') params = get_params(self.opt, img.size) transform = get_transform(self.opt, params) transform_E = get_transform( self.opt, params, method=Image.NEAREST, normalize=False) I_tensor = transform(img) C_path = os.path.join(self.c_name[index]) C = Image.open(C_path).convert('RGB') C_tensor = transform(C) E_path = os.path.join(self.e_name[index]) E = Image.open(E_path).convert('L') E_tensor = transform_E(E) input_dict = { 'image': I_tensor, 'clothes': C_tensor, 'edge': E_tensor, 'p_name': self.im_name[index].split('/')[-1] } return input_dict def __len__(self): return self.dataset_size def get_params(opt, size): w, h = size new_h = h new_w = w if opt.resize_or_crop == 'resize_and_crop': new_h = new_w = opt.loadSize elif opt.resize_or_crop == 'scale_width_and_crop': new_w = opt.loadSize new_h = opt.loadSize * h // w x = random.randint(0, np.maximum(0, new_w - opt.fineSize)) y = random.randint(0, np.maximum(0, new_h - opt.fineSize)) flip = 0 return {'crop_pos': (x, y), 'flip': flip} def get_transform_resize(opt, params, method=Image.BICUBIC, normalize=True): transform_list = [] transform_list.append( transforms.Lambda( lambda img: __scale_width(img, opt.loadSize, method))) osize = [256, 192] transform_list.append(transforms.Scale(osize, method)) if 'crop' in opt.resize_or_crop: transform_list.append( transforms.Lambda( lambda img: __crop(img, params['crop_pos'], opt.fineSize))) if opt.resize_or_crop == 'none': base = float(2**opt.n_downsample_global) if opt.netG == 'local': base *= (2**opt.n_local_enhancers) transform_list.append( transforms.Lambda(lambda img: __make_power_2(img, base, method))) if opt.isTrain and not opt.no_flip: transform_list.append( transforms.Lambda(lambda img: __flip(img, params['flip']))) transform_list += [transforms.ToTensor()] if normalize: transform_list += [ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ] return transforms.Compose(transform_list) def get_transform(opt, params, method=Image.BICUBIC, normalize=True): transform_list = [] if 'resize' in opt.resize_or_crop: osize = [opt.loadSize, opt.loadSize] transform_list.append(transforms.Resize(osize, method)) elif 'scale_width' in opt.resize_or_crop: transform_list.append( transforms.Lambda( lambda img: __scale_width(img, opt.loadSize, method))) osize = [256, 192] transform_list.append(transforms.Resize(osize, method)) if 'crop' in opt.resize_or_crop: transform_list.append( transforms.Lambda( lambda img: __crop(img, params['crop_pos'], opt.fineSize))) if opt.resize_or_crop == 'none': base = float(16) transform_list.append( transforms.Lambda(lambda img: __make_power_2(img, base, method))) if opt.isTrain and not opt.no_flip: transform_list.append( transforms.Lambda(lambda img: __flip(img, params['flip']))) transform_list += [transforms.ToTensor()] if normalize: transform_list += [ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ] return transforms.Compose(transform_list) def normalize(): return transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) def __make_power_2(img, base, method=Image.BICUBIC): ow, oh = img.size h = int(round(oh / base) * base) w = int(round(ow / base) * base) if (h == oh) and (w == ow): return img return img.resize((w, h), method) def __scale_width(img, target_width, method=Image.BICUBIC): ow, oh = img.size if (ow == target_width): return img w = target_width h = int(target_width * oh / ow) return img.resize((w, h), method) def __crop(img, pos, size): ow, oh = img.size x1, y1 = pos tw = th = size if (ow > tw or oh > th): return img.crop((x1, y1, x1 + tw, y1 + th)) return img def __flip(img, flip): if flip: return img.transpose(Image.FLIP_LEFT_RIGHT) return img ================================================ FILE: projects/glide/configs/README.md ================================================ # GLIDE (Arxiv'2021) > [GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models](https://papers.nips.cc/paper/2021/file/49ad23d1ec9fa4bd8d77d02681df5cfa-Paper.pdf) > **Task**: Text2Image, diffusion ## Abstract Diffusion models have recently been shown to generate high-quality synthetic images, especially when paired with a guidance technique to trade off diversity for fidelity. We explore diffusion models for the problem of text-conditional image synthesis and compare two different guidance strategies: CLIP guidance and classifier-free guidance. We find that the latter is preferred by human evaluators for both photorealism and caption similarity, and often produces photorealistic samples. Samples from a 3.5 billion parameter text-conditional diffusion model using classifierfree guidance are favored by human evaluators to those from DALL-E, even when the latter uses expensive CLIP reranking. Additionally, we find that our models can be fine-tuned to perform image inpainting, enabling powerful text-driven image editing. We train a smaller model on a filtered dataset and release the code and weights at https://github.com/openai/glide-text2im.
## Results and models
an oil painting of a corgi
an cartoon painting of a cat
**Laion** | Method | Resolution | Config | Weights | | ------ | ---------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | Glide | 64x64 | [config](projects/glide/configs/glide_ddim-classifier-free_laion-64x64.py) | [model](https://download.openmmlab.com/mmediting/glide/glide_laion-64x64-02afff47.pth) | | Glide | 64x64 -> 256x256 | [config](projects/glide/configs/glide_ddim-classifier-free_laion-64-256.py) | [model](https://download.openxlab.org.cn/models/mmediting/GLIDE/weight/glide_laion-64-256) | ## Quick Start You can run glide as follows: ```python import torch from mmagic.apis import init_model from mmengine.registry import init_default_scope from projects.glide.models import * init_default_scope('mmagic') config = 'projects/glide/configs/glide_ddim-classifier-free_laion-64x64.py' ckpt = 'https://download.openmmlab.com/mmagic/glide/glide_laion-64x64-02afff47.pth' model = init_model(config, ckpt).cuda().eval() prompt = "an oil painting of a corgi" with torch.no_grad(): samples = model.infer(init_image=None, prompt=prompt, batch_size=16, guidance_scale=3., num_inference_steps=100, labels=None, classifier_scale=0.0, show_progress=True)['samples'] ``` You can synthesis images with 256x256 resolution: ```python import torch from torchvision.utils import save_image from mmagic.apis import init_model from mmengine.registry import init_default_scope from projects.glide.models import * init_default_scope('mmagic') config = 'projects/glide/configs/glide_ddim-classifier-free_laion-64-256.py' ckpt = 'https://download.openxlab.org.cn/models/mmediting/GLIDE/weight/glide_laion-64-256' model = init_model(config, ckpt).cuda().eval() prompt = "an oil painting of a corgi" with torch.no_grad(): samples = model.infer(init_image=None, prompt=prompt, batch_size=16, guidance_scale=3., num_inference_steps=100, labels=None, classifier_scale=0.0, show_progress=True)['samples'] save_image(samples, "corgi.png", nrow=4, normalize=True, value_range=(-1, 1)) ``` ## Citation ```bibtex @article{2021GLIDE, title={GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models}, author={ Nichol, A. and Dhariwal, P. and Ramesh, A. and Shyam, P. and Mishkin, P. and Mcgrew, B. and Sutskever, I. and Chen, M. }, year={2021}, } ``` ================================================ FILE: projects/glide/configs/glide_ddim-classifier-free_laion-64-256.py ================================================ unet_cfg = dict( type='Text2ImUNet', image_size=64, base_channels=192, in_channels=3, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=0, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=1, num_head_channels=64, use_new_attention_order=False, encoder_channels=512), use_scale_shift_norm=True, text_ctx=128, xf_width=512, xf_layers=16, xf_heads=8, xf_final_ln=True, xf_padding=True, ) unet_up_cfg = dict( type='SuperResText2ImUNet', image_size=256, base_channels=192, in_channels=3, output_cfg=dict(var='FIXED'), resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=0, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=1, num_head_channels=64, use_new_attention_order=False, encoder_channels=512), use_scale_shift_norm=True, text_ctx=128, xf_width=512, xf_layers=16, xf_heads=8, xf_final_ln=True, xf_padding=True, ) model = dict( type='Glide', data_preprocessor=dict(type='DataPreprocessor', mean=[127.5], std=[127.5]), unet=unet_cfg, diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='squaredcos_cap_v2'), unet_up=unet_up_cfg, diffusion_scheduler_up=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear'), use_fp16=False) ================================================ FILE: projects/glide/configs/glide_ddim-classifier-free_laion-64x64.py ================================================ model = dict( type='Glide', data_preprocessor=dict(type='DataPreprocessor', mean=[127.5], std=[127.5]), unet=dict( type='Text2ImUNet', image_size=64, base_channels=192, in_channels=3, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=0, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=1, num_head_channels=64, use_new_attention_order=False, encoder_channels=512), use_scale_shift_norm=True, text_ctx=128, xf_width=512, xf_layers=16, xf_heads=8, xf_final_ln=True, xf_padding=True, ), diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='squaredcos_cap_v2'), use_fp16=False) ================================================ FILE: projects/glide/models/__init__.py ================================================ from .glide import Glide from .text2im_unet import SuperResText2ImUNet, Text2ImUNet __all__ = ['Text2ImUNet', 'Glide', 'SuperResText2ImUNet'] ================================================ FILE: projects/glide/models/glide.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from typing import Dict, List, Optional, Union import mmengine import torch import torch.nn as nn import torch.nn.functional as F from mmengine import MessageHub from mmengine.model import BaseModel, is_model_wrapper from mmengine.optim import OptimWrapperDict from mmengine.runner.checkpoint import _load_checkpoint_with_prefix from tqdm import tqdm from mmagic.registry import DIFFUSION_SCHEDULERS, MODELS from mmagic.structures import DataSample from mmagic.utils.typing import ForwardInputs, SampleList ModelType = Union[Dict, nn.Module] def classifier_grad(classifier, x, t, y=None, classifier_scale=1.0): """compute classification gradient to x.""" assert y is not None with torch.enable_grad(): x_in = x.detach().requires_grad_(True) logits = classifier(x_in, t) log_probs = F.log_softmax(logits, dim=-1) selected = log_probs[range(len(logits)), y.view(-1)] return torch.autograd.grad(selected.sum(), x_in)[0] * classifier_scale @MODELS.register_module('GLIDE') @MODELS.register_module() class Glide(BaseModel): """GLIDE: Guided language to image diffusion for generation and editing. Refer to: https://github.com/openai/glide-text2im. Args: data_preprocessor (dict, optional): The pre-process configuration for :class:`BaseDataPreprocessor`. unet (ModelType): Configuration for the denoising Unet. diffusion_scheduler (ModelType): Configuration for the diffusion scheduler. unet_up (ModelType, optional): Configuration for the upsampling denoising UNet. Defaults to None. diffusion_scheduler_up (ModelType, optional): Configuration for the upsampling diffusion scheduler. Defaults to None. use_fp16 (bool, optional): Whether to use fp16 for the unet model. Defaults to False. classifier (ModelType, optional): Configuration for the classifier. Defaults to None. classifier_scale (float): Classifier scale for classifier guidance. Defaults to 1.0. data_preprocessor (Optional[ModelType]): Configuration for the data preprocessor. pretrained_cfgs (dict, optional): Path configuration for pretrained weights. Usually, this is a dict containing the module name and the corresponding ckpt path. Defaults to None. """ def __init__(self, unet: ModelType, diffusion_scheduler: ModelType, unet_up: Optional[ModelType] = None, diffusion_scheduler_up: Optional[ModelType] = None, use_fp16: Optional[bool] = False, classifier: Optional[dict] = None, classifier_scale: float = 1.0, data_preprocessor: Optional[ModelType] = dict( type='DataPreprocessor'), pretrained_cfgs: Optional[dict] = None): super().__init__(data_preprocessor=data_preprocessor) self.unet = unet if isinstance(unet, nn.Module) else MODELS.build(unet) self.diffusion_scheduler = DIFFUSION_SCHEDULERS.build( diffusion_scheduler) if isinstance(diffusion_scheduler, dict) else diffusion_scheduler self.unet_up = None self.diffusion_scheduler_up = None if unet_up: self.unet_up = unet_up if isinstance( unet_up, nn.Module) else MODELS.build(unet_up) if diffusion_scheduler_up: self.diffusion_scheduler_up = DIFFUSION_SCHEDULERS.build( diffusion_scheduler_up) if isinstance( diffusion_scheduler_up, dict) else diffusion_scheduler_up else: self.diffusion_scheduler_up = deepcopy( self.diffusion_scheduler) if classifier: self.classifier = MODELS.build(classifier) else: self.classifier = None self.classifier_scale = classifier_scale if pretrained_cfgs: self.load_pretrained_models(pretrained_cfgs) if use_fp16: mmengine.print_log('Convert unet modules to floatpoint16') self.unet.convert_to_fp16() def load_pretrained_models(self, pretrained_cfgs): """_summary_ Args: pretrained_cfgs (_type_): _description_ """ for key, ckpt_cfg in pretrained_cfgs.items(): prefix = ckpt_cfg.get('prefix', '') map_location = ckpt_cfg.get('map_location', 'cpu') strict = ckpt_cfg.get('strict', True) ckpt_path = ckpt_cfg.get('ckpt_path') state_dict = _load_checkpoint_with_prefix(prefix, ckpt_path, map_location) getattr(self, key).load_state_dict(state_dict, strict=strict) mmengine.print_log(f'Load pretrained {key} from {ckpt_path}') @property def device(self): """Get current device of the model. Returns: torch.device: The current device of the model. """ return next(self.parameters()).device @torch.no_grad() def infer(self, init_image: Optional[torch.Tensor] = None, prompt: str = None, batch_size: Optional[int] = 1, guidance_scale: float = 3., num_inference_steps: int = 50, num_inference_steps_up: Optional[int] = 27, labels: Optional[torch.Tensor] = None, classifier_scale: float = 0.0, show_progress: Optional[bool] = False): """Inference function for guided diffusion. Args: init_image (torch.Tensor, optional): Starting noise for diffusion. Defaults to None. prompt (str): The prompt to guide the image generation. batch_size (int, optional): Batch size for generation. Defaults to 1. num_inference_steps (int, optional): The number of denoising steps. Defaults to 50. num_inference_steps_up (int, optional): The number of upsampling denoising steps. Defaults to 27. labels (torch.Tensor, optional): Labels for the classifier. Defaults to None. show_progress (bool, optional): Whether to show the progress bar. Defaults to False. Returns: torch.Tensor: Generated images. """ # Sample gaussian noise to begin loop if init_image is None: image = torch.randn((2 * batch_size, self.unet.in_channels, self.unet.image_size, self.unet.image_size)) image = image.to(self.device) else: image = init_image # set step values if num_inference_steps > 0: self.diffusion_scheduler.set_timesteps(num_inference_steps) timesteps = self.diffusion_scheduler.timesteps # text embedding tokens = self.unet.tokenizer.encode(prompt) tokens, mask = self.unet.tokenizer.padded_tokens_and_mask(tokens, 128) # Create the classifier-free guidance tokens (empty) # full_batch_size = batch_size * 2 uncond_tokens, uncond_mask = \ self.unet.tokenizer.padded_tokens_and_mask( [], 128) tokens = torch.tensor( [tokens] * batch_size + [uncond_tokens] * batch_size, device=self.device) mask = torch.tensor( [mask] * batch_size + [uncond_mask] * batch_size, dtype=torch.bool, device=self.device) if show_progress and mmengine.dist.is_main_process(): timesteps = tqdm(timesteps) for t in timesteps: # 1. predicted model_output half = image[:len(image) // 2] combined = torch.cat([half, half], dim=0) model_output = self.unet(combined, t, tokens=tokens, mask=mask) eps, rest = model_output[:, :3], model_output[:, 3:] cond_eps, uncond_eps = torch.split(eps, len(eps) // 2, dim=0) half_eps = uncond_eps + guidance_scale * (cond_eps - uncond_eps) eps = torch.cat([half_eps, half_eps], dim=0) noise_pred = torch.cat([eps, rest], dim=1) # 2. compute previous image: x_t -> x_t-1 diffusion_scheduler_output = self.diffusion_scheduler.step( noise_pred, t, image) # 3. applying classifier guide if self.classifier and classifier_scale != 0.0: gradient = classifier_grad( self.classifier, image, t, labels, classifier_scale=classifier_scale) guided_mean = ( diffusion_scheduler_output['mean'].float() + diffusion_scheduler_output['sigma'] * gradient.float()) image = guided_mean + diffusion_scheduler_output[ 'sigma'] * diffusion_scheduler_output['noise'] else: image = diffusion_scheduler_output['prev_sample'] # abandon unconditional image image = image[:image.shape[0] // 2] if self.unet_up: image = self.infer_up( low_res_img=image, batch_size=batch_size, prompt=prompt, num_inference_steps=num_inference_steps_up) return {'samples': image} @torch.no_grad() def infer_up(self, low_res_img: torch.Tensor, batch_size: int = 1, init_image: Optional[torch.Tensor] = None, prompt: Optional[str] = None, num_inference_steps: int = 27, show_progress: bool = False): """Inference function for upsampling guided diffusion. Args: low_res_img (torch.Tensor): Low resolution image (shape: [B, C, H, W]) for upsampling. batch_size (int, optional): Batch size for generation. Defaults to 1. init_image (torch.Tensor, optional): Starting noise (shape: [B, C, H, W]) for diffusion. Defaults to None. prompt (str, optional): The text prompt to guide the image generation. Defaults to None. num_inference_steps (int, optional): The number of denoising steps. Defaults to 27. show_progress (bool, optional): Whether to show the progress bar. Defaults to False. Returns: torch.Tensor: Generated upsampled images (shape: [B, C, H, W]). """ if init_image is None: image = torch.randn( (batch_size, self.unet_up.in_channels // 2, self.unet_up.image_size, self.unet_up.image_size)) image = image.to(self.device) else: image = init_image # set step values if num_inference_steps > 0: self.diffusion_scheduler_up.set_timesteps(num_inference_steps) timesteps = self.diffusion_scheduler_up.timesteps # text embedding tokens = self.unet.tokenizer.encode(prompt) tokens, mask = self.unet.tokenizer.padded_tokens_and_mask(tokens, 128) tokens = torch.tensor( [tokens] * batch_size, dtype=torch.bool, device=self.device) mask = torch.tensor( [mask] * batch_size, dtype=torch.bool, device=self.device) if show_progress and mmengine.dist.is_main_process(): timesteps = tqdm(timesteps) for t in timesteps: noise_pred = self.unet_up( image, t, low_res=low_res_img, tokens=tokens, mask=mask) # compute previous image: x_t -> x_t-1 diffusion_scheduler_output = self.diffusion_scheduler_up.step( noise_pred, t, image) image = diffusion_scheduler_output['prev_sample'] return image def forward(self, inputs: ForwardInputs, data_samples: Optional[list] = None, mode: Optional[str] = None) -> List[DataSample]: """_summary_ Args: inputs (ForwardInputs): _description_ data_samples (Optional[list], optional): _description_. Defaults to None. mode (Optional[str], optional): _description_. Defaults to None. Returns: List[DataSample]: _description_ """ init_image = inputs.get('init_image', None) batch_size = inputs.get('batch_size', 1) labels = data_samples.get('labels', None) sample_kwargs = inputs.get('sample_kwargs', dict()) num_inference_steps = sample_kwargs.get( 'num_inference_steps', self.diffusion_scheduler.num_train_timesteps) show_progress = sample_kwargs.get('show_progress', False) classifier_scale = sample_kwargs.get('classifier_scale', self.classifier_scale) outputs = self.infer( init_image=init_image, batch_size=batch_size, num_inference_steps=num_inference_steps, show_progress=show_progress, classifier_scale=classifier_scale) batch_sample_list = [] for idx in range(batch_size): gen_sample = DataSample() if data_samples: gen_sample.update(data_samples[idx]) if isinstance(outputs, dict): gen_sample.ema = DataSample( fake_img=outputs['ema'][idx], sample_model='ema') gen_sample.orig = DataSample( fake_img=outputs['orig'][idx], sample_model='orig') gen_sample.sample_model = 'ema/orig' gen_sample.set_gt_label(labels[idx]) gen_sample.ema.set_gt_label(labels[idx]) gen_sample.orig.set_gt_label(labels[idx]) else: gen_sample.fake_img = outputs[idx] gen_sample.set_gt_label(labels[idx]) # Append input condition (noise and sample_kwargs) to # batch_sample_list if init_image is not None: gen_sample.noise = init_image[idx] gen_sample.sample_kwargs = deepcopy(sample_kwargs) batch_sample_list.append(gen_sample) return batch_sample_list @torch.no_grad() def val_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Calls ``self.data_preprocessor(data)`` and ``self(inputs, data_sample, mode=None)`` in order. Return the generated results which will be passed to evaluator. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: SampleList: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs @torch.no_grad() def test_step(self, data: dict) -> SampleList: """Gets the generated image of given data. Same as :meth:`val_step`. Args: data (dict): Data sampled from metric specific sampler. More details in `Metrics` and `Evaluator`. Returns: List[DataSample]: Generated image or image dict. """ data = self.data_preprocessor(data) outputs = self(**data) return outputs def train_step(self, data: dict, optim_wrapper: OptimWrapperDict): """_summary_ Args: data (dict): _description_ optim_wrapper (OptimWrapperDict): _description_ Returns: _type_: _description_ """ message_hub = MessageHub.get_current_instance() curr_iter = message_hub.get_info('iter') # sampling x0 and timestep data = self.data_preprocessor(data) real_imgs = data['inputs'] timestep = self.diffusion_scheduler.sample_timestep() # calculating loss loss_dict = self.diffusion_scheduler.training_loss( self.unet, real_imgs, timestep) loss, log_vars = self._parse_losses(loss_dict) optim_wrapper['denoising'].update_params(loss) # update EMA if self.with_ema_denoising and (curr_iter + 1) >= self.ema_start: self.denoising_ema.update_parameters( self.denoising_ema. module if is_model_wrapper(self.denoising) else self.denoising) # if not update buffer, copy buffer from orig model if not self.denoising_ema.update_buffers: self.denoising_ema.sync_buffers( self.denoising.module if is_model_wrapper(self.denoising) else self.denoising) elif self.with_ema_denoising: # before ema, copy weights from orig self.denoising_ema.sync_parameters( self.denoising. module if is_model_wrapper(self.denoising) else self.denoising) return log_vars ================================================ FILE: projects/glide/models/glide_modules.py ================================================ import math import torch import torch.nn as nn class QKVMultiheadAttention(nn.Module): def __init__(self, n_heads: int, n_ctx: int): super().__init__() self.n_heads = n_heads self.n_ctx = n_ctx def forward(self, qkv): bs, n_ctx, width = qkv.shape attn_ch = width // self.n_heads // 3 scale = 1 / math.sqrt(math.sqrt(attn_ch)) qkv = qkv.view(bs, n_ctx, self.n_heads, -1) q, k, v = torch.split(qkv, attn_ch, dim=-1) weight = torch.einsum( 'bthc,bshc->bhts', q * scale, k * scale) # More stable with f16 than dividing afterwards wdtype = weight.dtype weight = torch.softmax(weight.float(), dim=-1).type(wdtype) return torch.einsum('bhts,bshc->bthc', weight, v).reshape(bs, n_ctx, -1) class MultiheadAttention(nn.Module): def __init__(self, n_ctx, width, heads): super().__init__() self.n_ctx = n_ctx self.width = width self.heads = heads self.c_qkv = nn.Linear(width, width * 3) self.c_proj = nn.Linear(width, width) self.attention = QKVMultiheadAttention(heads, n_ctx) def forward(self, x): x = self.c_qkv(x) x = self.attention(x) x = self.c_proj(x) return x class MLP(nn.Module): def __init__(self, width): super().__init__() self.width = width self.c_fc = nn.Linear(width, width * 4) self.c_proj = nn.Linear(width * 4, width) self.gelu = nn.GELU() def forward(self, x): return self.c_proj(self.gelu(self.c_fc(x))) class ResidualAttentionBlock(nn.Module): def __init__( self, n_ctx: int, width: int, heads: int, ): super().__init__() self.attn = MultiheadAttention( n_ctx, width, heads, ) # TODO should the LayerNorm support fp15 gain # and bias but fp32 mean and std? self.ln_1 = nn.LayerNorm(width) self.mlp = MLP(width) self.ln_2 = nn.LayerNorm(width) def forward(self, x: torch.Tensor): x = x + self.attn(self.ln_1(x)) x = x + self.mlp(self.ln_2(x)) return x class Transformer(nn.Module): def __init__( self, n_ctx: int, width: int, layers: int, heads: int, ): super().__init__() self.n_ctx = n_ctx self.width = width self.layers = layers self.resblocks = nn.ModuleList([ ResidualAttentionBlock( n_ctx, width, heads, ) for _ in range(layers) ]) def forward(self, x: torch.Tensor): for block in self.resblocks: x = block(x) return x ================================================ FILE: projects/glide/models/glide_tokenizer/__init__.py ================================================ from .bpe import get_encoder __all__ = ['get_encoder'] ================================================ FILE: projects/glide/models/glide_tokenizer/bpe.py ================================================ """Byte pair encoding utilities adapted from: https://github.com/openai/gpt-2/blob/master/src/encoder.py """ import gzip import json import os from functools import lru_cache from typing import List, Tuple import regex as re @lru_cache() def bytes_to_unicode(): """Returns list of utf-8 byte and a corresponding list of unicode strings. The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup tables between utf-8 bytes and unicode strings. And avoids mapping to whitespace/control characters the bpe code barfs on. """ bs = ( list(range(ord('!'), ord('~') + 1)) + list(range(ord('¡'), ord('¬') + 1)) + list(range(ord('®'), ord('ÿ') + 1))) cs = bs[:] n = 0 for b in range(2**8): if b not in bs: bs.append(b) cs.append(2**8 + n) n += 1 cs = [chr(n) for n in cs] return dict(zip(bs, cs)) def get_pairs(word): """Return set of symbol pairs in a word. Word is represented as tuple of symbols (symbols being variable-length strings). """ pairs = set() prev_char = word[0] for char in word[1:]: pairs.add((prev_char, char)) prev_char = char return pairs class Encoder: def __init__(self, encoder, bpe_merges, errors='replace'): self.encoder = encoder self.decoder = {v: k for k, v in self.encoder.items()} self.errors = errors # how to handle errors in decoding self.byte_encoder = bytes_to_unicode() self.byte_decoder = {v: k for k, v in self.byte_encoder.items()} self.bpe_ranks = dict(zip(bpe_merges, range(len(bpe_merges)))) self.cache = {} # Should haved added re.IGNORECASE so BPE merges can happen for # capitalized versions of contractions self.pat = re.compile( r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}] +|\s+(?!\S)|\s+""") @property def n_vocab(self) -> int: return len(self.encoder) @property def end_token(self) -> int: return self.n_vocab - 1 def padded_tokens_and_mask(self, tokens: List[int], text_ctx: int) -> Tuple[List[int], List[bool]]: tokens = tokens[:text_ctx] padding = text_ctx - len(tokens) padded_tokens = tokens + [self.end_token] * padding mask = [True] * len(tokens) + [False] * padding return padded_tokens, mask def bpe(self, token): if token in self.cache: return self.cache[token] word = tuple(token) pairs = get_pairs(word) if not pairs: return token while True: bigram = min( pairs, key=lambda pair: self.bpe_ranks.get(pair, float('inf'))) if bigram not in self.bpe_ranks: break first, second = bigram new_word = [] i = 0 while i < len(word): try: j = word.index(first, i) new_word.extend(word[i:j]) i = j except: # noqa: E722 new_word.extend(word[i:]) break if word[i] == first and i < len(word) - 1 and word[ i + 1] == second: new_word.append(first + second) i += 2 else: new_word.append(word[i]) i += 1 new_word = tuple(new_word) word = new_word if len(word) == 1: break else: pairs = get_pairs(word) word = ' '.join(word) self.cache[token] = word return word def encode(self, text): text = text.lower() bpe_tokens = [] for token in re.findall(self.pat, text): token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8')) bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' ')) return bpe_tokens def decode(self, tokens): text = ''.join([self.decoder[token] for token in tokens]) text = bytearray([self.byte_decoder[c] for c in text]).decode( 'utf-8', errors=self.errors) return text def get_encoder(): root_dir = os.path.dirname(os.path.abspath(__file__)) with gzip.open(os.path.join(root_dir, 'encoder.json.gz'), 'r') as f: encoder = json.load(f) with gzip.open(os.path.join(root_dir, 'vocab.bpe.gz'), 'r') as f: bpe_data = str(f.read(), 'utf-8') bpe_merges = [ tuple(merge_str.split()) for merge_str in bpe_data.split('\n')[1:-1] ] return Encoder( encoder=encoder, bpe_merges=bpe_merges, ) ================================================ FILE: projects/glide/models/glide_tokenizer/simple_tokenizer.py ================================================ """Copied from: https://github.com/openai/CLIP/blob/573315e83f07b53a61ff5098757 e8fc885f1703e/clip/simple_tokenizer.py.""" import gzip import html import os from functools import lru_cache from typing import List, Tuple import ftfy import regex as re @lru_cache() def default_bpe(): return os.path.join( os.path.dirname(os.path.abspath(__file__)), 'bpe_simple_vocab_16e6.txt.gz') @lru_cache() def bytes_to_unicode(): """Returns list of utf-8 byte and a corresponding list of unicode strings. The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup tables between utf-8 bytes and unicode strings. And avoids mapping to whitespace/control characters the bpe code barfs on. """ bs = ( list(range(ord('!'), ord('~') + 1)) + list(range(ord('¡'), ord('¬') + 1)) + list(range(ord('®'), ord('ÿ') + 1))) cs = bs[:] n = 0 for b in range(2**8): if b not in bs: bs.append(b) cs.append(2**8 + n) n += 1 cs = [chr(n) for n in cs] return dict(zip(bs, cs)) def get_pairs(word): """Return set of symbol pairs in a word. Word is represented as tuple of symbols (symbols being variable-length strings). """ pairs = set() prev_char = word[0] for char in word[1:]: pairs.add((prev_char, char)) prev_char = char return pairs def basic_clean(text): text = ftfy.fix_text(text) text = html.unescape(html.unescape(text)) return text.strip() def whitespace_clean(text): text = re.sub(r'\s+', ' ', text) text = text.strip() return text class SimpleTokenizer(object): def __init__(self, bpe_path: str = default_bpe()): self.byte_encoder = bytes_to_unicode() self.byte_decoder = {v: k for k, v in self.byte_encoder.items()} merges = gzip.open(bpe_path).read().decode('utf-8').split('\n') merges = merges[1:49152 - 256 - 2 + 1] merges = [tuple(merge.split()) for merge in merges] vocab = list(bytes_to_unicode().values()) vocab = vocab + [v + '' for v in vocab] for merge in merges: vocab.append(''.join(merge)) vocab.extend(['<|startoftext|>', '<|endoftext|>']) self.encoder = dict(zip(vocab, range(len(vocab)))) self.decoder = {v: k for k, v in self.encoder.items()} self.bpe_ranks = dict(zip(merges, range(len(merges)))) self.cache = { '<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>' } self.pat = re.compile( r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p {L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE, ) @property def start_token(self): return self.encoder['<|startoftext|>'] @property def end_token(self): return self.encoder['<|endoftext|>'] def padded_tokens_and_len(self, tokens: List[int], text_ctx: int) -> Tuple[List[int], int]: tokens = [self.start_token] + tokens[:text_ctx - 2] + [self.end_token] text_len = len(tokens) padding = text_ctx - len(tokens) padded_tokens = tokens + [0] * padding return padded_tokens, text_len def bpe(self, token): if token in self.cache: return self.cache[token] word = tuple(token[:-1]) + (token[-1] + '', ) pairs = get_pairs(word) if not pairs: return token + '' while True: bigram = min( pairs, key=lambda pair: self.bpe_ranks.get(pair, float('inf'))) if bigram not in self.bpe_ranks: break first, second = bigram new_word = [] i = 0 while i < len(word): try: j = word.index(first, i) new_word.extend(word[i:j]) i = j except: # noqa: E722 new_word.extend(word[i:]) break if word[i] == first and i < len(word) - 1 and word[ i + 1] == second: new_word.append(first + second) i += 2 else: new_word.append(word[i]) i += 1 new_word = tuple(new_word) word = new_word if len(word) == 1: break else: pairs = get_pairs(word) word = ' '.join(word) self.cache[token] = word return word def encode(self, text): bpe_tokens = [] text = whitespace_clean(basic_clean(text)).lower() for token in re.findall(self.pat, text): token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8')) bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' ')) return bpe_tokens def decode(self, tokens): text = ''.join([self.decoder[token] for token in tokens]) text = ( bytearray([self.byte_decoder[c] for c in text ]).decode('utf-8', errors='replace').replace('', ' ')) return text ================================================ FILE: projects/glide/models/text2im_unet.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from mmagic.models import DenoisingUnet from mmagic.registry import MODELS from .glide_modules import Transformer from .glide_tokenizer import get_encoder @MODELS.register_module() class Text2ImUNet(DenoisingUnet): """A UNetModel used in GLIDE that conditions on text with an encoding transformer. Expects an extra kwarg `tokens` of text. Args: text_ctx (int): Number of text tokens to expect. xf_width (int): Width of the transformer. xf_layers (int): Depth of the transformer. xf_heads (int): Number of heads in the transformer. xf_final_ln (bool): Whether to use a LayerNorm after the output layer. tokenizer (callable, optional): Text tokenizer for sampling/vocab size. Defaults to get_encoder(). cache_text_emb (bool, optional): Whether to cache text embeddings. Defaults to False. xf_ar (float, optional): Autoregressive weight for the transformer. Defaults to 0.0. xf_padding (bool, optional): Whether to use padding in the transformer. Defaults to False. share_unemb (bool, optional): Whether to share UNet embeddings. Defaults to False. """ def __init__( self, text_ctx, xf_width, xf_layers, xf_heads, xf_final_ln, *args, tokenizer=get_encoder(), cache_text_emb=False, xf_ar=0.0, xf_padding=False, share_unemb=False, **kwargs, ): self.text_ctx = text_ctx self.xf_width = xf_width self.xf_ar = xf_ar self.xf_padding = xf_padding self.tokenizer = tokenizer if not xf_width: super().__init__(*args, **kwargs, encoder_channels=None) else: super().__init__(*args, **kwargs, encoder_channels=xf_width) if self.xf_width: self.transformer = Transformer( text_ctx, xf_width, xf_layers, xf_heads, ) if xf_final_ln: self.final_ln = nn.LayerNorm(xf_width) else: self.final_ln = None self.token_embedding = nn.Embedding(self.tokenizer.n_vocab, xf_width) self.positional_embedding = nn.Parameter( torch.empty(text_ctx, xf_width, dtype=torch.float32)) self.transformer_proj = nn.Linear(xf_width, self.base_channels * 4) if self.xf_padding: self.padding_embedding = nn.Parameter( torch.empty(text_ctx, xf_width, dtype=torch.float32)) if self.xf_ar: self.unemb = nn.Linear(xf_width, self.tokenizer.n_vocab) if share_unemb: self.unemb.weight = self.token_embedding.weight self.cache_text_emb = cache_text_emb self.cache = None def get_text_emb(self, tokens, mask): assert tokens is not None if self.cache_text_emb and self.cache is not None: assert (tokens == self.cache['tokens']).all( ), f"Tokens {tokens.cpu().numpy().tolist()} do not match \ cache {self.cache['tokens'].cpu().numpy().tolist()}" return self.cache xf_in = self.token_embedding(tokens.long()) xf_in = xf_in + self.positional_embedding[None] if self.xf_padding: assert mask is not None xf_in = torch.where(mask[..., None], xf_in, self.padding_embedding[None]) xf_out = self.transformer(xf_in.to(self.dtype)) if self.final_ln is not None: xf_out = self.final_ln(xf_out) xf_proj = self.transformer_proj(xf_out[:, -1]) xf_out = xf_out.permute(0, 2, 1) # NLC -> NCL outputs = dict(xf_proj=xf_proj, xf_out=xf_out) if self.cache_text_emb: self.cache = dict( tokens=tokens, xf_proj=xf_proj.detach(), xf_out=xf_out.detach() if xf_out is not None else None, ) return outputs def del_cache(self): self.cache = None def forward(self, x, timesteps, tokens=None, mask=None): hs = [] if not torch.is_tensor(timesteps): timesteps = torch.tensor([timesteps], dtype=torch.long, device=x.device) elif torch.is_tensor(timesteps) and len(timesteps.shape) == 0: timesteps = timesteps[None].to(x.device) if timesteps.shape[0] != x.shape[0]: timesteps = timesteps.repeat(x.shape[0]) emb = self.time_embedding(timesteps) if self.xf_width: text_outputs = self.get_text_emb(tokens, mask) xf_proj, xf_out = text_outputs['xf_proj'], text_outputs['xf_out'] emb = emb + xf_proj.to(emb) else: xf_out = None h = x.type(self.dtype) for module in self.in_blocks: h = module(h, emb, xf_out) hs.append(h) h = self.mid_blocks(h, emb, xf_out) for module in self.out_blocks: h = torch.cat([h, hs.pop()], dim=1) h = module(h, emb, xf_out) h = h.type(x.dtype) h = self.out(h) return h @MODELS.register_module() class SuperResText2ImUNet(Text2ImUNet): """A UNetModel that performs super-resolution. Expects an extra kwarg `low_res` to condition on a low-resolution image. """ def __init__(self, *args, **kwargs): if 'in_channels' in kwargs: kwargs = dict(kwargs) kwargs['in_channels'] = kwargs['in_channels'] * 2 else: args = list(args) args[1] = args[1] * 2 super().__init__(*args, **kwargs) def forward(self, x, timesteps, low_res=None, **kwargs): _, _, new_height, new_width = x.shape upsampled = F.interpolate( low_res, (new_height, new_width), mode='bilinear', align_corners=False) x = torch.cat([x, upsampled], dim=1) return super().forward(x, timesteps, **kwargs) ================================================ FILE: projects/magicmaker/index.html ================================================ My static Space
================================================ FILE: projects/powerpaint/README.md ================================================ # A Task is Worth One Word: Learning with Task Prompts for High-Quality Versatile Image Inpainting ### [Project Page](https://powerpaint.github.io/) | [Paper](https://arxiv.org/abs/2312.03594) | [Online Demo(OpenXlab)](https://openxlab.org.cn/apps/detail/rangoliu/PowerPaint#basic-information) This README provides a step-by-step guide to download the repository, set up the required virtual environment named "PowerPaint" using conda, and run PowerPaint with or without ControlNet. ## News **December 18, 2023** *Enhanced PowerPaint Model* - We are delighted to announce the release of more stable model weights. These refined weights can now be accessed on [Hugging Face](https://huggingface.co/JunhaoZhuang/PowerPaint-v1/tree/main). The `gradio_PowerPaint.py` file and [Online Demo](https://openxlab.org.cn/apps/detail/rangoliu/PowerPaint) have also been updated as part of this release. **December 22, 2023** - The logical error in loading ControlNet has been rectified. The `gradio_PowerPaint.py` file and [Online Demo](https://openxlab.org.cn/apps/detail/rangoliu/PowerPaint) have also been updated. ## Next **Stronger Model Weights Coming Soon!** ______________________________________________________________________ ## Getting Started ```bash # Clone the Repository git clone https://github.com/open-mmlab/mmagic.git # Navigate to the Repository cd projects/powerpaint # Create Virtual Environment with Conda conda create --name PowerPaint python=3.9 conda activate PowerPaint # Install Dependencies pip install -r requirements.txt # Create Models Folder mkdir models # Set up Git LFS git lfs install # Clone PowerPaint Model git lfs clone https://huggingface.co/JunhaoZhuang/PowerPaint-v1/ ./models ``` ## Run PowerPaint To run PowerPaint, execute the following command: ```bash python gradio_PowerPaint.py ``` This command will launch the Gradio interface for PowerPaint. Feel free to explore and create stunning images with PowerPaint! ## BibTeX ``` @misc{zhuang2023task, title={A Task is Worth One Word: Learning with Task Prompts for High-Quality Versatile Image Inpainting}, author={Junhao Zhuang and Yanhong Zeng and Wenran Liu and Chun Yuan and Kai Chen}, year={2023}, eprint={2312.03594}, archivePrefix={arXiv}, primaryClass={cs.CV} } ``` ================================================ FILE: projects/powerpaint/gradio_PowerPaint.py ================================================ import random import cv2 import gradio as gr import numpy as np import torch from controlnet_aux import HEDdetector, OpenposeDetector from diffusers.pipelines.controlnet.pipeline_controlnet import ControlNetModel from PIL import Image, ImageFilter from pipeline.pipeline_PowerPaint import \ StableDiffusionInpaintPipeline as Pipeline from pipeline.pipeline_PowerPaint_ControlNet import \ StableDiffusionControlNetInpaintPipeline as controlnetPipeline from safetensors.torch import load_model from transformers import DPTFeatureExtractor, DPTForDepthEstimation from utils.utils import TokenizerWrapper, add_tokens torch.set_grad_enabled(False) weight_dtype = torch.float16 global pipe pipe = Pipeline.from_pretrained( 'runwayml/stable-diffusion-inpainting', torch_dtype=weight_dtype) pipe.tokenizer = TokenizerWrapper( from_pretrained='runwayml/stable-diffusion-v1-5', subfolder='tokenizer', revision=None) add_tokens( tokenizer=pipe.tokenizer, text_encoder=pipe.text_encoder, placeholder_tokens=['P_ctxt', 'P_shape', 'P_obj'], initialize_tokens=['a', 'a', 'a'], num_vectors_per_token=10) load_model(pipe.unet, './models/unet/diffusion_pytorch_model.safetensors') pipe.text_encoder.load_state_dict( torch.load('./models/text_encoder/pytorch_model.bin'), strict=False) pipe = pipe.to('cuda') depth_estimator = DPTForDepthEstimation.from_pretrained( 'Intel/dpt-hybrid-midas').to('cuda') feature_extractor = DPTFeatureExtractor.from_pretrained( 'Intel/dpt-hybrid-midas') openpose = OpenposeDetector.from_pretrained('lllyasviel/ControlNet') hed = HEDdetector.from_pretrained('lllyasviel/ControlNet') global current_control current_control = 'canny' # controlnet_conditioning_scale = 0.8 def set_seed(seed): torch.manual_seed(seed) torch.cuda.manual_seed(seed) torch.cuda.manual_seed_all(seed) np.random.seed(seed) random.seed(seed) def get_depth_map(image): image = feature_extractor( images=image, return_tensors='pt').pixel_values.to('cuda') with torch.no_grad(), torch.autocast('cuda'): depth_map = depth_estimator(image).predicted_depth depth_map = torch.nn.functional.interpolate( depth_map.unsqueeze(1), size=(1024, 1024), mode='bicubic', align_corners=False, ) depth_min = torch.amin(depth_map, dim=[1, 2, 3], keepdim=True) depth_max = torch.amax(depth_map, dim=[1, 2, 3], keepdim=True) depth_map = (depth_map - depth_min) / (depth_max - depth_min) image = torch.cat([depth_map] * 3, dim=1) image = image.permute(0, 2, 3, 1).cpu().numpy()[0] image = Image.fromarray((image * 255.0).clip(0, 255).astype(np.uint8)) return image def add_task(prompt, negative_prompt, control_type): # print(control_type) if control_type == 'object-removal': promptA = prompt + ' P_ctxt' promptB = prompt + ' P_ctxt' negative_promptA = negative_prompt + ' P_obj' negative_promptB = negative_prompt + ' P_obj' elif control_type == 'shape-guided': promptA = prompt + ' P_shape' promptB = prompt + ' P_ctxt' negative_promptA = negative_prompt negative_promptB = negative_prompt elif control_type == 'image-outpainting': promptA = prompt + ' P_ctxt' promptB = prompt + ' P_ctxt' negative_promptA = negative_prompt + ' P_obj' negative_promptB = negative_prompt + ' P_obj' else: promptA = prompt + ' P_obj' promptB = prompt + ' P_obj' negative_promptA = negative_prompt negative_promptB = negative_prompt return promptA, promptB, negative_promptA, negative_promptB def predict(input_image, prompt, fitting_degree, ddim_steps, scale, seed, negative_prompt, task, vertical_expansion_ratio, horizontal_expansion_ratio): size1, size2 = input_image['image'].convert('RGB').size if task != 'image-outpainting': if size1 < size2: input_image['image'] = input_image['image'].convert('RGB').resize( (640, int(size2 / size1 * 640))) else: input_image['image'] = input_image['image'].convert('RGB').resize( (int(size1 / size2 * 640), 640)) else: if size1 < size2: input_image['image'] = input_image['image'].convert('RGB').resize( (512, int(size2 / size1 * 512))) else: input_image['image'] = input_image['image'].convert('RGB').resize( (int(size1 / size2 * 512), 512)) if (vertical_expansion_ratio is not None and horizontal_expansion_ratio is not None): o_W, o_H = input_image['image'].convert('RGB').size c_W = int(horizontal_expansion_ratio * o_W) c_H = int(vertical_expansion_ratio * o_H) expand_img = np.ones((c_H, c_W, 3), dtype=np.uint8) * 127 original_img = np.array(input_image['image']) expand_img[int((c_H - o_H) / 2.0):int((c_H - o_H) / 2.0) + o_H, int((c_W - o_W) / 2.0):int((c_W - o_W) / 2.0) + o_W, :] = original_img blurry_gap = 10 expand_mask = np.ones((c_H, c_W, 3), dtype=np.uint8) * 255 if vertical_expansion_ratio == 1 and horizontal_expansion_ratio != 1: expand_mask[int((c_H - o_H) / 2.0):int((c_H - o_H) / 2.0) + o_H, int((c_W - o_W) / 2.0) + blurry_gap:int((c_W - o_W) / 2.0) + o_W - blurry_gap, :] = 0 # noqa elif vertical_expansion_ratio != 1 and horizontal_expansion_ratio != 1: expand_mask[int((c_H - o_H) / 2.0) + blurry_gap:int((c_H - o_H) / 2.0) + o_H - blurry_gap, int((c_W - o_W) / 2.0) + blurry_gap:int((c_W - o_W) / 2.0) + o_W - blurry_gap, :] = 0 # noqa elif vertical_expansion_ratio != 1 and horizontal_expansion_ratio == 1: expand_mask[int((c_H - o_H) / 2.0) + blurry_gap:int((c_H - o_H) / 2.0) + o_H - blurry_gap, int((c_W - o_W) / 2.0):int((c_W - o_W) / 2.0) + o_W, :] = 0 # noqa input_image['image'] = Image.fromarray(expand_img) input_image['mask'] = Image.fromarray(expand_mask) promptA, promptB, negative_promptA, negative_promptB = add_task( prompt, negative_prompt, task) print(promptA, promptB, negative_promptA, negative_promptB) img = np.array(input_image['image'].convert('RGB')) W = int(np.shape(img)[0] - np.shape(img)[0] % 8) H = int(np.shape(img)[1] - np.shape(img)[1] % 8) input_image['image'] = input_image['image'].resize((H, W)) input_image['mask'] = input_image['mask'].resize((H, W)) set_seed(seed) global pipe result = pipe( promptA=promptA, promptB=promptB, tradoff=fitting_degree, tradoff_nag=fitting_degree, negative_promptA=negative_promptA, negative_promptB=negative_promptB, image=input_image['image'].convert('RGB'), mask_image=input_image['mask'].convert('RGB'), width=H, height=W, guidance_scale=scale, num_inference_steps=ddim_steps).images[0] mask_np = np.array(input_image['mask'].convert('RGB')) red = np.array(result).astype('float') * 1 red[:, :, 0] = 180.0 red[:, :, 2] = 0 red[:, :, 1] = 0 result_m = np.array(result) result_m = Image.fromarray( (result_m.astype('float') * (1 - mask_np.astype('float') / 512.0) + mask_np.astype('float') / 512.0 * red).astype('uint8')) m_img = input_image['mask'].convert('RGB').filter( ImageFilter.GaussianBlur(radius=3)) m_img = np.asarray(m_img) / 255.0 img_np = np.asarray(input_image['image'].convert('RGB')) / 255.0 ours_np = np.asarray(result) / 255.0 ours_np = ours_np * m_img + (1 - m_img) * img_np result_paste = Image.fromarray(np.uint8(ours_np * 255)) dict_res = [input_image['mask'].convert('RGB'), result_m] dict_out = [input_image['image'].convert('RGB'), result_paste] return dict_out, dict_res def predict_controlnet(input_image, input_control_image, control_type, prompt, ddim_steps, scale, seed, negative_prompt, controlnet_conditioning_scale): promptA = prompt + ' P_obj' promptB = prompt + ' P_obj' negative_promptA = negative_prompt negative_promptB = negative_prompt size1, size2 = input_image['image'].convert('RGB').size if size1 < size2: input_image['image'] = input_image['image'].convert('RGB').resize( (640, int(size2 / size1 * 640))) else: input_image['image'] = input_image['image'].convert('RGB').resize( (int(size1 / size2 * 640), 640)) img = np.array(input_image['image'].convert('RGB')) W = int(np.shape(img)[0] - np.shape(img)[0] % 8) H = int(np.shape(img)[1] - np.shape(img)[1] % 8) input_image['image'] = input_image['image'].resize((H, W)) input_image['mask'] = input_image['mask'].resize((H, W)) global current_control global pipe base_control = ControlNetModel.from_pretrained( 'lllyasviel/sd-controlnet-canny', torch_dtype=weight_dtype) control_pipe = controlnetPipeline(pipe.vae, pipe.text_encoder, pipe.tokenizer, pipe.unet, base_control, pipe.scheduler, None, None, False) control_pipe = control_pipe.to('cuda') current_control = 'canny' if current_control != control_type: if control_type == 'canny' or control_type is None: control_pipe.controlnet = ControlNetModel.from_pretrained( 'lllyasviel/sd-controlnet-canny', torch_dtype=weight_dtype) elif control_type == 'pose': control_pipe.controlnet = ControlNetModel.from_pretrained( 'lllyasviel/sd-controlnet-openpose', torch_dtype=weight_dtype) elif control_type == 'depth': control_pipe.controlnet = ControlNetModel.from_pretrained( 'lllyasviel/sd-controlnet-depth', torch_dtype=weight_dtype) else: control_pipe.controlnet = ControlNetModel.from_pretrained( 'lllyasviel/sd-controlnet-hed', torch_dtype=weight_dtype) control_pipe = control_pipe.to('cuda') current_control = control_type controlnet_image = input_control_image if current_control == 'canny': controlnet_image = controlnet_image.resize((H, W)) controlnet_image = np.array(controlnet_image) controlnet_image = cv2.Canny(controlnet_image, 100, 200) controlnet_image = controlnet_image[:, :, None] controlnet_image = np.concatenate( [controlnet_image, controlnet_image, controlnet_image], axis=2) controlnet_image = Image.fromarray(controlnet_image) elif current_control == 'pose': controlnet_image = openpose(controlnet_image) elif current_control == 'depth': controlnet_image = controlnet_image.resize((H, W)) controlnet_image = get_depth_map(controlnet_image) else: controlnet_image = hed(controlnet_image) mask_np = np.array(input_image['mask'].convert('RGB')) controlnet_image = controlnet_image.resize((H, W)) set_seed(seed) result = control_pipe( promptA=promptB, promptB=promptA, tradoff=1.0, tradoff_nag=1.0, negative_promptA=negative_promptA, negative_promptB=negative_promptB, image=input_image['image'].convert('RGB'), mask_image=input_image['mask'].convert('RGB'), control_image=controlnet_image, width=H, height=W, guidance_scale=scale, controlnet_conditioning_scale=controlnet_conditioning_scale, num_inference_steps=ddim_steps).images[0] red = np.array(result).astype('float') * 1 red[:, :, 0] = 180.0 red[:, :, 2] = 0 red[:, :, 1] = 0 result_m = np.array(result) result_m = Image.fromarray( (result_m.astype('float') * (1 - mask_np.astype('float') / 512.0) + mask_np.astype('float') / 512.0 * red).astype('uint8')) mask_np = np.array(input_image['mask'].convert('RGB')) m_img = input_image['mask'].convert('RGB').filter( ImageFilter.GaussianBlur(radius=4)) m_img = np.asarray(m_img) / 255.0 img_np = np.asarray(input_image['image'].convert('RGB')) / 255.0 ours_np = np.asarray(result) / 255.0 ours_np = ours_np * m_img + (1 - m_img) * img_np result_paste = Image.fromarray(np.uint8(ours_np * 255)) return [input_image['image'].convert('RGB'), result_paste], [controlnet_image, result_m] def infer(input_image, text_guided_prompt, text_guided_negative_prompt, shape_guided_prompt, shape_guided_negative_prompt, fitting_degree, ddim_steps, scale, seed, task, enable_control, input_control_image, control_type, vertical_expansion_ratio, horizontal_expansion_ratio, outpaint_prompt, outpaint_negative_prompt, controlnet_conditioning_scale, removal_prompt, removal_negative_prompt): if task == 'text-guided': prompt = text_guided_prompt negative_prompt = text_guided_negative_prompt elif task == 'shape-guided': prompt = shape_guided_prompt negative_prompt = shape_guided_negative_prompt elif task == 'object-removal': prompt = removal_prompt negative_prompt = removal_negative_prompt elif task == 'image-outpainting': prompt = outpaint_prompt negative_prompt = outpaint_negative_prompt return predict(input_image, prompt, fitting_degree, ddim_steps, scale, seed, negative_prompt, task, vertical_expansion_ratio, horizontal_expansion_ratio) else: task = 'text-guided' prompt = text_guided_prompt negative_prompt = text_guided_negative_prompt if enable_control and task == 'text-guided': return predict_controlnet(input_image, input_control_image, control_type, prompt, ddim_steps, scale, seed, negative_prompt, controlnet_conditioning_scale) else: return predict(input_image, prompt, fitting_degree, ddim_steps, scale, seed, negative_prompt, task, None, None) def select_tab_text_guided(): return 'text-guided' def select_tab_object_removal(): return 'object-removal' def select_tab_image_outpainting(): return 'image-outpainting' def select_tab_shape_guided(): return 'shape-guided' with gr.Blocks(css='style.css') as demo: with gr.Row(): gr.Markdown( "
PowerPaint: High-Quality Versatile Image Inpainting
" # noqa ) with gr.Row(): gr.Markdown( "
Project Page  " # noqa "Paper  " "Code
" # noqa ) with gr.Row(): gr.Markdown( '**Note:** Due to network-related factors, the page may experience occasional bugs! If the inpainting results deviate significantly from expectations, consider toggling between task options to refresh the content.' # noqa ) with gr.Row(): with gr.Column(): gr.Markdown('### Input image and draw mask') input_image = gr.Image(source='upload', tool='sketch', type='pil') task = gr.Radio([ 'text-guided', 'object-removal', 'shape-guided', 'image-outpainting' ], show_label=False, visible=False) # Text-guided object inpainting with gr.Tab('Text-guided object inpainting') as tab_text_guided: enable_text_guided = gr.Checkbox( label='Enable text-guided object inpainting', value=True, interactive=False) text_guided_prompt = gr.Textbox(label='Prompt') text_guided_negative_prompt = gr.Textbox( label='negative_prompt') gr.Markdown('### Controlnet setting') enable_control = gr.Checkbox( label='Enable controlnet', info='Enable this if you want to use controlnet') controlnet_conditioning_scale = gr.Slider( label='controlnet conditioning scale', minimum=0, maximum=1, step=0.05, value=0.5, ) control_type = gr.Radio(['canny', 'pose', 'depth', 'hed'], label='Control type') input_control_image = gr.Image(source='upload', type='pil') tab_text_guided.select( fn=select_tab_text_guided, inputs=None, outputs=task) # Object removal inpainting with gr.Tab('Object removal inpainting') as tab_object_removal: enable_object_removal = gr.Checkbox( label='Enable object removal inpainting', value=True, info='The recommended configuration for ' 'the Guidance Scale is 10 or higher.' 'If undesired objects appear in the masked area, ' 'you can address this by specifically increasing ' 'the Guidance Scale.', interactive=False) removal_prompt = gr.Textbox(label='Prompt') removal_negative_prompt = gr.Textbox(label='negative_prompt') tab_object_removal.select( fn=select_tab_object_removal, inputs=None, outputs=task) # Object image outpainting with gr.Tab('Image outpainting') as tab_image_outpainting: enable_object_removal = gr.Checkbox( label='Enable image outpainting', value=True, info='The recommended configuration for the Guidance ' 'Scale is 10 or higher. ' 'If unwanted random objects appear in ' 'the extended image region, ' 'you can enhance the cleanliness of the extension ' 'area by increasing the Guidance Scale.', interactive=False) outpaint_prompt = gr.Textbox(label='Outpainting_prompt') outpaint_negative_prompt = gr.Textbox( label='Outpainting_negative_prompt') horizontal_expansion_ratio = gr.Slider( label='horizontal expansion ratio', minimum=1, maximum=4, step=0.05, value=1, ) vertical_expansion_ratio = gr.Slider( label='vertical expansion ratio', minimum=1, maximum=4, step=0.05, value=1, ) tab_image_outpainting.select( fn=select_tab_image_outpainting, inputs=None, outputs=task) # Shape-guided object inpainting with gr.Tab('Shape-guided object inpainting') as tab_shape_guided: enable_shape_guided = gr.Checkbox( label='Enable shape-guided object inpainting', value=True, interactive=False) shape_guided_prompt = gr.Textbox(label='shape_guided_prompt') shape_guided_negative_prompt = gr.Textbox( label='shape_guided_negative_prompt') fitting_degree = gr.Slider( label='fitting degree', minimum=0, maximum=1, step=0.05, value=1, ) tab_shape_guided.select( fn=select_tab_shape_guided, inputs=None, outputs=task) run_button = gr.Button(label='Run') with gr.Accordion('Advanced options', open=False): ddim_steps = gr.Slider( label='Steps', minimum=1, maximum=50, value=45, step=1) scale = gr.Slider( label='Guidance Scale', info='For object removal and image outpainting, ' 'it is recommended to set the value at 10 or above.', minimum=0.1, maximum=30.0, value=7.5, step=0.1) seed = gr.Slider( label='Seed', minimum=0, maximum=2147483647, step=1, randomize=True, ) with gr.Column(): gr.Markdown('### Inpainting result') inpaint_result = gr.Gallery( label='Generated images', show_label=False, columns=2) gr.Markdown('### Mask') gallery = gr.Gallery( label='Generated masks', show_label=False, columns=2) run_button.click( fn=infer, inputs=[ input_image, text_guided_prompt, text_guided_negative_prompt, shape_guided_prompt, shape_guided_negative_prompt, fitting_degree, ddim_steps, scale, seed, task, enable_control, input_control_image, control_type, vertical_expansion_ratio, horizontal_expansion_ratio, outpaint_prompt, outpaint_negative_prompt, controlnet_conditioning_scale, removal_prompt, removal_negative_prompt ], outputs=[inpaint_result, gallery]) demo.queue() demo.launch(share=False, server_name='0.0.0.0', server_port=7860) ================================================ FILE: projects/powerpaint/pipeline/pipeline_PowerPaint.py ================================================ # Copyright 2023 The HuggingFace Team. 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 inspect from typing import Any, Callable, Dict, List, Optional, Union import numpy as np import PIL import torch from diffusers.configuration_utils import FrozenDict from diffusers.image_processor import VaeImageProcessor from diffusers.loaders import (FromSingleFileMixin, LoraLoaderMixin, TextualInversionLoaderMixin) from diffusers.models import (AsymmetricAutoencoderKL, AutoencoderKL, UNet2DConditionModel) from diffusers.pipelines.pipeline_utils import DiffusionPipeline from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput from diffusers.pipelines.stable_diffusion.safety_checker import \ StableDiffusionSafetyChecker from diffusers.schedulers import KarrasDiffusionSchedulers from diffusers.utils import (deprecate, is_accelerate_available, is_accelerate_version, logging) from diffusers.utils.torch_utils import randn_tensor from packaging import version from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer logger = logging.get_logger(__name__) # pylint: disable=invalid-name def prepare_mask_and_masked_image(image, mask, height, width, return_image: bool = False): """Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the ``image`` and ``1`` for the ``mask``. The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be binarized (``mask > 0.5``) and cast to ``torch.float32`` too. Args: image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint. It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width`` ``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``. mask (_type_): The mask to apply to the image, i.e. regions to inpaint. It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width`` ``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``. Raises: ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions. TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not (or the other way around). Returns: tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 4 dimensions: ``batch x channels x height x width``. """ if image is None: raise ValueError('`image` input cannot be undefined.') if mask is None: raise ValueError('`mask_image` input cannot be undefined.') if isinstance(image, torch.Tensor): if not isinstance(mask, torch.Tensor): raise TypeError('`image` is a torch.Tensor but ' f'`mask` (type: {type(mask)} is not') # Batch single image if image.ndim == 3: assert image.shape[ 0] == 3, 'Image outside a batch should be of shape (3, H, W)' image = image.unsqueeze(0) # Batch and add channel dim for single mask if mask.ndim == 2: mask = mask.unsqueeze(0).unsqueeze(0) # Batch single mask or add channel dim if mask.ndim == 3: # Single batched mask, no channel dim or single mask # not batched but channel dim if mask.shape[0] == 1: mask = mask.unsqueeze(0) # Batched masks no channel dim else: mask = mask.unsqueeze(1) assert image.ndim == 4 and mask.ndim == 4, \ 'Image and Mask must have 4 dimensions' assert image.shape[-2:] == mask.shape[ -2:], 'Image and Mask must have the same spatial dimensions' assert image.shape[0] == mask.shape[ 0], 'Image and Mask must have the same batch size' # Check image is in [-1, 1] if image.min() < -1 or image.max() > 1: raise ValueError('Image should be in [-1, 1] range') # Check mask is in [0, 1] if mask.min() < 0 or mask.max() > 1: raise ValueError('Mask should be in [0, 1] range') # Binarize mask mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 # Image as float32 image = image.to(dtype=torch.float32) elif isinstance(mask, torch.Tensor): raise TypeError( f'`mask` is a torch.Tensor but `image` (type: {type(image)} is not' ) else: # preprocess image if isinstance(image, (PIL.Image.Image, np.ndarray)): image = [image] if isinstance(image, list) and isinstance(image[0], PIL.Image.Image): # resize all images w.r.t passed height an width image = [ i.resize((width, height), resample=PIL.Image.LANCZOS) for i in image ] image = [np.array(i.convert('RGB'))[None, :] for i in image] image = np.concatenate(image, axis=0) elif isinstance(image, list) and isinstance(image[0], np.ndarray): image = np.concatenate([i[None, :] for i in image], axis=0) image = image.transpose(0, 3, 1, 2) image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0 # preprocess mask if isinstance(mask, (PIL.Image.Image, np.ndarray)): mask = [mask] if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image): mask = [ i.resize((width, height), resample=PIL.Image.LANCZOS) for i in mask ] mask = np.concatenate( [np.array(m.convert('L'))[None, None, :] for m in mask], axis=0) mask = mask.astype(np.float32) / 255.0 elif isinstance(mask, list) and isinstance(mask[0], np.ndarray): mask = np.concatenate([m[None, None, :] for m in mask], axis=0) mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 mask = torch.from_numpy(mask) masked_image = image * (mask < 0.5) # n.b. ensure backwards compatibility as old function does not return image if return_image: return mask, masked_image, image return mask, masked_image class StableDiffusionInpaintPipeline(DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin, FromSingleFileMixin): r""" Pipeline for text-guided image inpainting using Stable Diffusion. This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods implemented for all pipelines (downloading, saving, running on a particular device, etc.). The pipeline also inherits the following loading methods: - [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings - [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights - [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights Args: vae ([`AutoencoderKL`, `AsymmetricAutoencoderKL`]): Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations. text_encoder ([`CLIPTextModel`]): Frozen text-encoder ([clip-vit-large-patch14] (https://huggingface.co/openai/clip-vit-large-patch14)). tokenizer ([`~transformers.CLIPTokenizer`]): A `CLIPTokenizer` to tokenize text. unet ([`UNet2DConditionModel`]): A `UNet2DConditionModel` to denoise the encoded image latents. scheduler ([`SchedulerMixin`]): A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`]. safety_checker ([`StableDiffusionSafetyChecker`]): Classification module that estimates whether generated images could be considered offensive or harmful. Please refer to the [model card] (https://huggingface.co/runwayml/stable-diffusion-v1-5) for more details about a model's potential harms. feature_extractor ([`~transformers.CLIPImageProcessor`]): A `CLIPImageProcessor` to extract features from generated images; used as inputs to the `safety_checker`. """ _optional_components = ['safety_checker', 'feature_extractor'] def __init__( self, vae: Union[AutoencoderKL, AsymmetricAutoencoderKL], text_encoder: CLIPTextModel, tokenizer: CLIPTokenizer, unet: UNet2DConditionModel, scheduler: KarrasDiffusionSchedulers, safety_checker: StableDiffusionSafetyChecker, feature_extractor: CLIPImageProcessor, requires_safety_checker: bool = True, ): super().__init__() if hasattr(scheduler.config, 'steps_offset') and scheduler.config.steps_offset != 1: deprecation_message = ( f'The configuration file of this scheduler: {scheduler} is ' ' outdated. `steps_offset`' ' should be set to 1 instead of ' f' {scheduler.config.steps_offset}. Please make sure ' 'to update the config accordingly as leaving `steps_offset` ' ' might led to incorrect results' ' in future versions. If you have downloaded this checkpoint ' ' from the Hugging Face Hub,' ' it would be very nice if you could open a Pull request for ' ' the `scheduler/scheduler_config.json`' ' file') deprecate( 'steps_offset!=1', '1.0.0', deprecation_message, standard_warn=False) new_config = dict(scheduler.config) new_config['steps_offset'] = 1 scheduler._internal_dict = FrozenDict(new_config) if hasattr( scheduler.config, 'skip_prk_steps') and scheduler.config.skip_prk_steps is False: deprecation_message = ( f'The configuration file of this scheduler: {scheduler} has ' ' not set the configuration' ' `skip_prk_steps`. `skip_prk_steps` should be set to True in ' ' the configuration file. Please make' ' sure to update the config accordingly as not setting ' ' `skip_prk_steps` in the config might lead to' ' incorrect results in future versions. ' ' If you have downloaded ' ' this checkpoint from the Hugging Face' ' Hub, it would be very nice if you could open a Pull ' ' request for the' ' `scheduler/scheduler_config.json` file') deprecate( 'skip_prk_steps not set', '1.0.0', deprecation_message, standard_warn=False) new_config = dict(scheduler.config) new_config['skip_prk_steps'] = True scheduler._internal_dict = FrozenDict(new_config) if safety_checker is None and requires_safety_checker: logger.warning( f'You have disabled the safety checker for {self.__class__} ' ' by passing `safety_checker=None`. Ensure' ' that you abide to the conditions of the Stable Diffusion ' ' license and do not expose unfiltered' ' results in services or applications open to the public. ' ' Both the diffusers team and Hugging Face' ' strongly recommend to keep the safety filter enabled in ' ' all public facing circumstances, disabling' ' it only for use-cases that involve analyzing network ' ' behavior or auditing its results. For more' ' information, please have a look at' ' https://github.com/huggingface/diffusers/pull/254 .') if safety_checker is not None and feature_extractor is None: raise ValueError( 'Make sure to define a feature extractor when ' 'loading {self.__class__} if you want to use the safety' ' checker. If you do not want to use the safety checker, ' "you can pass `'safety_checker=None'` instead.") is_unet_version_less_0_9_0 = hasattr( unet.config, '_diffusers_version') and version.parse( version.parse(unet.config._diffusers_version).base_version ) < version.parse('0.9.0.dev0') is_unet_sample_size_less_64 = hasattr( unet.config, 'sample_size') and unet.config.sample_size < 64 if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64: deprecation_message = ( 'The configuration file of the unet has set the default ' '`sample_size` to smaller than' " 64 which seems highly unlikely .If you're checkpoint is " ' a fine-tuned version of any of the' ' following: \n- CompVis/stable-diffusion-v1-4 \n- ' ' CompVis/stable-diffusion-v1-3 \n-' ' CompVis/stable-diffusion-v1-2 \n- ' ' CompVis/stable-diffusion-v1-1 \n- ' ' runwayml/stable-diffusion-v1-5' ' \n- runwayml/stable-diffusion-inpainting \n you should ' " change 'sample_size' to 64 in the" ' configuration file. Please make sure to update the config ' ' accordingly as leaving `sample_size=32`' ' in the config might lead to incorrect results in future ' ' versions. If you have downloaded this' ' checkpoint from the Hugging Face Hub, it would be very nice ' ' if you could open a Pull request for' ' the `unet/config.json` file') deprecate( 'sample_size<64', '1.0.0', deprecation_message, standard_warn=False) new_config = dict(unet.config) new_config['sample_size'] = 64 unet._internal_dict = FrozenDict(new_config) # Check shapes, assume num_channels_latents == 4, # num_channels_mask == 1, num_channels_masked == 4 if unet.config.in_channels != 9: logger.info( f'You have loaded a UNet with {unet.config.in_channels} ' 'input channels which.') self.register_modules( vae=vae, text_encoder=text_encoder, tokenizer=tokenizer, unet=unet, scheduler=scheduler, safety_checker=safety_checker, feature_extractor=feature_extractor, ) self.vae_scale_factor = 2**( len(self.vae.config.block_out_channels) - 1) self.image_processor = VaeImageProcessor( vae_scale_factor=self.vae_scale_factor) self.register_to_config( requires_safety_checker=requires_safety_checker) # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion. # StableDiffusionPipeline.enable_model_cpu_offload def enable_model_cpu_offload(self, gpu_id=0): r""" Offload all models to CPU to reduce memory usage with a low impact on performance. Moves one whole model at a time to the GPU when its `forward` method is called, and the model remains in GPU until the next model runs. Memory savings are lower than using `enable_sequential_cpu_offload`, but performance is much better due to the iterative execution of the `unet`. """ if is_accelerate_available() and is_accelerate_version( '>=', '0.17.0.dev0'): from accelerate import cpu_offload_with_hook else: raise ImportError( '`enable_model_cpu_offload` requires `accelerate v0.17.0` ' 'or higher.') device = torch.device(f'cuda:{gpu_id}') if self.device.type != 'cpu': self.to('cpu', silence_dtype_warnings=True) torch.cuda.empty_cache() # otherwise we don't see the memory savings # (but they probably exist) hook = None for cpu_offloaded_model in [self.text_encoder, self.unet, self.vae]: _, hook = cpu_offload_with_hook( cpu_offloaded_model, device, prev_module_hook=hook) if self.safety_checker is not None: _, hook = cpu_offload_with_hook( self.safety_checker, device, prev_module_hook=hook) # We'll offload the last model manually. self.final_offload_hook = hook # Copied from diffusers.pipelines.stable_diffusion.pipeline_ # stable_diffusion.StableDiffusionPipeline._encode_prompt def _encode_prompt( self, promptA, promptB, t, device, num_images_per_prompt, do_classifier_free_guidance, negative_promptA=None, negative_promptB=None, t_nag=None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, lora_scale: Optional[float] = None, ): r""" Encodes the prompt into text encoder hidden states. Args: prompt (`str` or `List[str]`, *optional*): prompt to be encoded device: (`torch.device`): torch device num_images_per_prompt (`int`): number of images that should be generated per prompt do_classifier_free_guidance (`bool`): whether to use classifier free guidance or not negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. If not defined, one has to pass `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, text embeddings will be generated from `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input argument. lora_scale (`float`, *optional*): A lora scale that will be applied to all LoRA layers of the text encoder if LoRA layers are loaded. """ # set lora scale so that monkey patched LoRA # function of text encoder can correctly access it if lora_scale is not None and isinstance(self, LoraLoaderMixin): self._lora_scale = lora_scale prompt = promptA negative_prompt = negative_promptA if promptA is not None and isinstance(promptA, str): batch_size = 1 elif promptA is not None and isinstance(promptA, list): batch_size = len(promptA) else: batch_size = prompt_embeds.shape[0] if prompt_embeds is None: # textual inversion: procecss multi-vector tokens if necessary if isinstance(self, TextualInversionLoaderMixin): promptA = self.maybe_convert_prompt(promptA, self.tokenizer) text_inputsA = self.tokenizer( promptA, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_inputsB = self.tokenizer( promptB, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_input_idsA = text_inputsA.input_ids text_input_idsB = text_inputsB.input_ids untruncated_ids = self.tokenizer( promptA, padding='longest', return_tensors='pt').input_ids if untruncated_ids.shape[-1] >= text_input_idsA.shape[ -1] and not torch.equal(text_input_idsA, untruncated_ids): removed_text = self.tokenizer.batch_decode( untruncated_ids[:, self.tokenizer.model_max_length - 1:-1]) logger.warning( 'The following part of your input was truncated because ' 'CLIP can only handle sequences up to' f' {self.tokenizer.model_max_length} ' f'tokens: {removed_text}') if hasattr(self.text_encoder.config, 'use_attention_mask' ) and self.text_encoder.config.use_attention_mask: attention_mask = text_inputsA.attention_mask.to(device) else: attention_mask = None # print("text_input_idsA: ",text_input_idsA) # print("text_input_idsB: ",text_input_idsB) # print('t: ',t) prompt_embedsA = self.text_encoder( text_input_idsA.to(device), attention_mask=attention_mask, ) prompt_embedsA = prompt_embedsA[0] prompt_embedsB = self.text_encoder( text_input_idsB.to(device), attention_mask=attention_mask, ) prompt_embedsB = prompt_embedsB[0] prompt_embeds = prompt_embedsA * (t) + (1 - t) * prompt_embedsB # print("prompt_embeds: ",prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype elif self.unet is not None: prompt_embeds_dtype = self.unet.dtype else: prompt_embeds_dtype = prompt_embeds.dtype prompt_embeds = prompt_embeds.to( dtype=prompt_embeds_dtype, device=device) bs_embed, seq_len, _ = prompt_embeds.shape # duplicate text embeddings for each generation per prompt, # using mps friendly method prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) # get unconditional embeddings for classifier free guidance if do_classifier_free_guidance and negative_prompt_embeds is None: uncond_tokensA: List[str] uncond_tokensB: List[str] if negative_prompt is None: uncond_tokensA = [''] * batch_size uncond_tokensB = [''] * batch_size elif prompt is not None and type(prompt) is not type( negative_prompt): raise TypeError( f'`negative_prompt` should be the same type to `prompt`, ' ' but got {type(negative_prompt)} !=' f' {type(prompt)}.') elif isinstance(negative_prompt, str): uncond_tokensA = [negative_promptA] uncond_tokensB = [negative_promptB] elif batch_size != len(negative_prompt): raise ValueError( f'`negative_prompt`: {negative_prompt} has batch ' f' size {len(negative_prompt)}, but `prompt`:' f' {prompt} has batch size {batch_size}. Please make ' ' sure that passed `negative_prompt` matches' ' the batch size of `prompt`.') else: uncond_tokensA = negative_promptA uncond_tokensB = negative_promptB # textual inversion: procecss multi-vector tokens if necessary if isinstance(self, TextualInversionLoaderMixin): uncond_tokensA = self.maybe_convert_prompt( uncond_tokensA, self.tokenizer) uncond_tokensB = self.maybe_convert_prompt( uncond_tokensB, self.tokenizer) max_length = prompt_embeds.shape[1] uncond_inputA = self.tokenizer( uncond_tokensA, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) uncond_inputB = self.tokenizer( uncond_tokensB, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) if hasattr(self.text_encoder.config, 'use_attention_mask' ) and self.text_encoder.config.use_attention_mask: attention_mask = uncond_inputA.attention_mask.to(device) else: attention_mask = None negative_prompt_embedsA = self.text_encoder( uncond_inputA.input_ids.to(device), attention_mask=attention_mask, ) negative_prompt_embedsB = self.text_encoder( uncond_inputB.input_ids.to(device), attention_mask=attention_mask, ) negative_prompt_embeds = negative_prompt_embedsA[0] * (t_nag) + ( 1 - t_nag) * negative_prompt_embedsB[0] # negative_prompt_embeds = negative_prompt_embeds[0] if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation per # prompt, using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.to( dtype=prompt_embeds_dtype, device=device) negative_prompt_embeds = negative_prompt_embeds.repeat( 1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view( batch_size * num_images_per_prompt, seq_len, -1) # For classifier free guidance, we need to do two forward passes. # Here we concatenate the unconditional and text embeddings # into a single batch # to avoid doing two forward passes # print("prompt_embeds: ",prompt_embeds) prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds]) return prompt_embeds # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion. # StableDiffusionPipeline.run_safety_checker def run_safety_checker(self, image, device, dtype): if self.safety_checker is None: has_nsfw_concept = None else: if torch.is_tensor(image): feature_extractor_input = self.image_processor.postprocess( image, output_type='pil') else: feature_extractor_input = self.image_processor.numpy_to_pil( image) safety_checker_input = self.feature_extractor( feature_extractor_input, return_tensors='pt').to(device) image, has_nsfw_concept = self.safety_checker( images=image, clip_input=safety_checker_input.pixel_values.to(dtype)) return image, has_nsfw_concept # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion. # StableDiffusionPipeline.prepare_extra_step_kwargs def prepare_extra_step_kwargs(self, generator, eta): # prepare extra kwargs for the scheduler step, since not all # schedulers have the same signature # eta (η) is only used with the DDIMScheduler, it will be # ignored for other schedulers. # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 # and should be between [0, 1] accepts_eta = 'eta' in set( inspect.signature(self.scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs def check_inputs( self, prompt, height, width, strength, callback_steps, negative_prompt=None, prompt_embeds=None, negative_prompt_embeds=None, ): if strength < 0 or strength > 1: raise ValueError( f'The value of strength should in [0.0, 1.0] but is {strength}' ) if height % 8 != 0 or width % 8 != 0: raise ValueError(f'`height` and `width` have to be divisible by 8 ' f' but are {height} and {width}.') if (callback_steps is None) or (callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)): raise ValueError( f'`callback_steps` has to be a positive integer but ' f' is {callback_steps} of type' f' {type(callback_steps)}.') if prompt is not None and prompt_embeds is not None: raise ValueError( f'Cannot forward both `prompt`: {prompt} and `prompt_embeds`: ' ' {prompt_embeds}. Please make sure to' ' only forward one of the two.') elif prompt is None and prompt_embeds is None: raise ValueError('Provide either `prompt` or `prompt_embeds`. ' ' Cannot leave both ' ' `prompt` and `prompt_embeds` undefined.') elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)): raise ValueError(f'`prompt` has to be of type `str` or ' f' `list` but is {type(prompt)}') if negative_prompt is not None and negative_prompt_embeds is not None: raise ValueError( f'Cannot forward both `negative_prompt`: {negative_prompt} ' 'and `negative_prompt_embeds`:' f' {negative_prompt_embeds}. Please make sure to only ' ' forward one of the two.') if prompt_embeds is not None and negative_prompt_embeds is not None: if prompt_embeds.shape != negative_prompt_embeds.shape: raise ValueError( '`prompt_embeds` and `negative_prompt_embeds` ' 'must have the same shape when passed directly, but' f' got: `prompt_embeds` {prompt_embeds.shape} != ' ' `negative_prompt_embeds`' f' {negative_prompt_embeds.shape}.') def prepare_latents( self, batch_size, num_channels_latents, height, width, dtype, device, generator, latents=None, image=None, timestep=None, is_strength_max=True, return_noise=False, return_image_latents=False, ): shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) if isinstance(generator, list) and len(generator) != batch_size: raise ValueError( f'You have passed a list of generators of ' f' length {len(generator)},' ' but requested an effective batch' f' size of {batch_size}. Make sure the batch size ' ' matches the length of the generators.') if (image is None or timestep is None) and not is_strength_max: raise ValueError( 'Since strength < 1. initial latents are to be initialised' ' as a combination of Image + Noise.' 'However, either the image or the noise timestep ' 'has not been provided.') if return_image_latents or (latents is None and not is_strength_max): image = image.to(device=device, dtype=dtype) image_latents = self._encode_vae_image( image=image, generator=generator) if latents is None: noise = randn_tensor( shape, generator=generator, device=device, dtype=dtype) # if strength is 1. then initialise the latents to noise, # else initial to image + noise latents = noise if is_strength_max else self.scheduler.add_noise( image_latents, noise, timestep) # if pure noise then scale the initial latents by the # Scheduler's init sigma latents = latents * self.scheduler.init_noise_sigma \ if is_strength_max else latents else: noise = latents.to(device) latents = noise * self.scheduler.init_noise_sigma outputs = (latents, ) if return_noise: outputs += (noise, ) if return_image_latents: outputs += (image_latents, ) return outputs def _encode_vae_image(self, image: torch.Tensor, generator: torch.Generator): if isinstance(generator, list): image_latents = [ self.vae.encode(image[i:i + 1]).latent_dist.sample( generator=generator[i]) for i in range(image.shape[0]) ] image_latents = torch.cat(image_latents, dim=0) else: image_latents = self.vae.encode(image).latent_dist.sample( generator=generator) image_latents = self.vae.config.scaling_factor * image_latents return image_latents def prepare_mask_latents(self, mask, masked_image, batch_size, height, width, dtype, device, generator, do_classifier_free_guidance): # resize the mask to latents shape as we concatenate the # mask to the latents # we do that before converting to dtype to avoid breaking in # case we're using cpu_offload # and half precision mask = torch.nn.functional.interpolate( mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)) mask = mask.to(device=device, dtype=dtype) masked_image = masked_image.to(device=device, dtype=dtype) masked_image_latents = self._encode_vae_image( masked_image, generator=generator) # duplicate mask and masked_image_latents for each generation per # prompt, using mps friendly method if mask.shape[0] < batch_size: if not batch_size % mask.shape[0] == 0: raise ValueError( "The passed mask and the required batch size don't match. " ' Masks are supposed to be duplicated to' f' a total batch size of {batch_size}, ' f' but {mask.shape[0]} ' ' masks were passed. Make sure the number' ' of masks that you pass is divisible by the ' ' total requested batch size.') mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1) if masked_image_latents.shape[0] < batch_size: if not batch_size % masked_image_latents.shape[0] == 0: raise ValueError( "The passed images and the required batch size don't " ' match. Images are supposed to be duplicated' f' to a total batch size of {batch_size}, ' f' but {masked_image_latents.shape[0]} images were passed.' ' Make sure the number of images that you pass is ' ' divisible by the total requested batch size.') masked_image_latents = masked_image_latents.repeat( batch_size // masked_image_latents.shape[0], 1, 1, 1) mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask masked_image_latents = ( torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents) # aligning device to prevent device errors when concatenating it # with the latent model input masked_image_latents = masked_image_latents.to( device=device, dtype=dtype) return mask, masked_image_latents # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion_img2img. # StableDiffusionImg2ImgPipeline.get_timesteps def get_timesteps(self, num_inference_steps, strength, device): # get the original timestep using init_timestep init_timestep = min( int(num_inference_steps * strength), num_inference_steps) t_start = max(num_inference_steps - init_timestep, 0) timesteps = self.scheduler.timesteps[t_start * self.scheduler.order:] return timesteps, num_inference_steps - t_start @torch.no_grad() def __call__( self, promptA: Union[str, List[str]] = None, promptB: Union[str, List[str]] = None, image: Union[torch.FloatTensor, PIL.Image.Image] = None, mask_image: Union[torch.FloatTensor, PIL.Image.Image] = None, height: Optional[int] = None, width: Optional[int] = None, strength: float = 1.0, tradoff: float = 1.0, tradoff_nag: float = 1.0, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_promptA: Optional[Union[str, List[str]]] = None, negative_promptB: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, latents: Optional[torch.FloatTensor] = None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, output_type: Optional[str] = 'pil', return_dict: bool = True, callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None, callback_steps: int = 1, cross_attention_kwargs: Optional[Dict[str, Any]] = None, task_class: Union[torch.Tensor, float, int] = None, ): r""" The call function to the pipeline for generation. Args: prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`. image (`PIL.Image.Image`): `Image` or tensor representing an image batch to be inpainted (which parts of the image to be masked out with `mask_image` and repainted according to `prompt`). mask_image (`PIL.Image.Image`): `Image` or tensor representing an image batch to mask `image`. White pixels in the mask are repainted while black pixels are preserved. If `mask_image` is a PIL image, it is converted to a single channel (luminance) before use. If it's a tensor, it should contain one color channel (L) instead of 3, so the expected shape would be `(B, H, W, 1)`. height (`int`, *optional*, defaults to `self.unet.config. sample_size * self.vae_scale_factor`): The height in pixels of the generated image. width (`int`, *optional*, defaults to `self.unet.config. sample_size * self.vae_scale_factor`): The width in pixels of the generated image. strength (`float`, *optional*, defaults to 1.0): Indicates extent to transform the reference `image`. Must be between 0 and 1. `image` is used as a starting point and more noise is added the higher the `strength`. The number of denoising steps depends on the amount of noise initially added. When `strength` is 1, added noise is maximum and the denoising process runs for the full number of iterations specified in `num_inference_steps`. A value of 1 essentially ignores `image`. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. This parameter is modulated by `strength`. guidance_scale (`float`, *optional*, defaults to 7.5): A higher guidance scale value encourages the model to generate images closely linked to the text `prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`. negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide what to not include in image generation. If not defined, you need to pass `negative_prompt_embeds` instead. Ignored when not using guidance (`guidance_scale < 1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) from the [DDIM] (https://arxiv.org/abs/2010.02502) paper. Only applies to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers. generator (`torch.Generator` or `List[torch.Generator]`, *optional*): A [`torch.Generator`](https://pytorch.org/docs/stable /generated/torch.Generator.html) to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor is generated by sampling using the supplied random `generator`. prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not provided, text embeddings are generated from the `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not provided, `negative_prompt_embeds` are generated from the `negative_prompt` input argument. output_type (`str`, *optional*, defaults to `"pil"`): The output format of the generated image. Choose between `PIL.Image` or `np.array`. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`~pipelines.stable_diffusion. StableDiffusionPipelineOutput`] instead of a plain tuple. callback (`Callable`, *optional*): A function that calls every `callback_steps` steps during inference. The function is called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`. callback_steps (`int`, *optional*, defaults to 1): The frequency at which the `callback` function is called. If not specified, the callback is called at every step. cross_attention_kwargs (`dict`, *optional*): A kwargs dictionary that if specified is passed along to the [`AttentionProcessor`] as defined in [`self.processor`](https://github.com/huggingface/diffusers /blob/main/src/diffusers/models/attention_processor.py). Examples: ```py >>> import PIL >>> import requests >>> import torch >>> from io import BytesIO >>> from diffusers import StableDiffusionInpaintPipeline >>> def download_image(url): ... response = requests.get(url) ... return PIL.Image.open(BytesIO(response.content)).convert("RGB") >>> img_url = "https://raw.githubusercontent.com/CompVis/ latent-diffusion/main/data/inpainting_examples /overture-creations-5sI6fQgYIuo.png" >>> mask_url = "https://raw.githubusercontent.com/CompVis/ latent-diffusion/main/data/inpainting_examples/ overture-creations-5sI6fQgYIuo_mask.png" >>> init_image = download_image(img_url).resize((512, 512)) >>> mask_image = download_image(mask_url).resize((512, 512)) >>> pipe = StableDiffusionInpaintPipeline.from_pretrained( ... "runwayml/stable-diffusion-inpainting", torch_dtype=torch.float16 ... ) >>> pipe = pipe.to("cuda") >>> prompt = "Face of a yellow cat, high resolution, sitting on a park bench" >>> image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0] ``` Returns: [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`: If `return_dict` is `True`, [`~pipelines.stable_diffusion. StableDiffusionPipelineOutput`] is returned, otherwise a `tuple` is returned where the first element is a list with the generated images and the second element is a list of `bool`s indicating whether the corresponding generated image contains "not-safe-for-work" (nsfw) content. """ # 0. Default height and width to unet height = height or self.unet.config.sample_size * self.vae_scale_factor width = width or self.unet.config.sample_size * self.vae_scale_factor prompt = promptA negative_prompt = negative_promptA # 1. Check inputs self.check_inputs( prompt, height, width, strength, callback_steps, negative_prompt, prompt_embeds, negative_prompt_embeds, ) # 2. Define call parameters if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] device = self._execution_device # here `guidance_scale` is defined analog to the guidance # weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt text_encoder_lora_scale = ( cross_attention_kwargs.get('scale', None) if cross_attention_kwargs is not None else None) prompt_embeds = self._encode_prompt( promptA, promptB, tradoff, device, num_images_per_prompt, do_classifier_free_guidance, negative_promptA, negative_promptB, tradoff_nag, prompt_embeds=prompt_embeds, negative_prompt_embeds=negative_prompt_embeds, lora_scale=text_encoder_lora_scale, ) # 4. set timesteps self.scheduler.set_timesteps(num_inference_steps, device=device) timesteps, num_inference_steps = self.get_timesteps( num_inference_steps=num_inference_steps, strength=strength, device=device) # check that number of inference steps is not < 1 - # as this doesn't make sense if num_inference_steps < 1: raise ValueError( f'After adjusting the num_inference_steps by strength ' f' parameter: {strength}, the number of pipeline' f'steps is {num_inference_steps} which is < 1 and not ' 'appropriate for this pipeline.') # at which timestep to set the initial noise (n.b. 50% if # strength is 0.5) latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt) # create a boolean to check if the strength is set to 1. # if so then initialise the latents with pure noise is_strength_max = strength == 1.0 # 5. Preprocess mask and image mask, masked_image, init_image = prepare_mask_and_masked_image( image, mask_image, height, width, return_image=True) mask_condition = mask.clone() # 6. Prepare latent variables num_channels_latents = self.vae.config.latent_channels num_channels_unet = self.unet.config.in_channels return_image_latents = num_channels_unet == 4 latents_outputs = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, prompt_embeds.dtype, device, generator, latents, image=init_image, timestep=latent_timestep, is_strength_max=is_strength_max, return_noise=True, return_image_latents=return_image_latents, ) if return_image_latents: latents, noise, image_latents = latents_outputs else: latents, noise = latents_outputs # 7. Prepare mask latent variables mask, masked_image_latents = self.prepare_mask_latents( mask, masked_image, batch_size * num_images_per_prompt, height, width, prompt_embeds.dtype, device, generator, do_classifier_free_guidance, ) # 8. Check that sizes of mask, masked image and latents match if num_channels_unet == 9: # default case for runwayml/stable-diffusion-inpainting num_channels_mask = mask.shape[1] num_channels_masked_image = masked_image_latents.shape[1] if num_channels_latents + num_channels_mask + \ num_channels_masked_image != self.unet.config.in_channels: raise ValueError( 'Incorrect configuration settings! The ' f' config of `pipeline.unet`: {self.unet.config} expects' f' {self.unet.config.in_channels} but received ' f' `num_channels_latents`: {num_channels_latents} +' f' `num_channels_mask`: {num_channels_mask} + ' ' `num_channels_masked_image`:' f' {num_channels_masked_image}' f' = {num_channels_latents+num_channels_masked_image+ num_channels_mask}. Please verify the config of' # noqa ' `pipeline.unet` or your `mask_image` or `image` input.') elif num_channels_unet != 4: raise ValueError( f'The unet {self.unet.__class__} should have either 4 or 9 ' f'input channels, not {self.unet.config.in_channels}.') # 9. Prepare extra step kwargs. TODO: Logic should ideally just # be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 10. Denoising loop num_warmup_steps = len( timesteps) - num_inference_steps * self.scheduler.order with self.progress_bar(total=num_inference_steps) as progress_bar: for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents # concat latents, mask, masked_image_latents # in the channel dimension latent_model_input = self.scheduler.scale_model_input( latent_model_input, t) if num_channels_unet == 9: latent_model_input = torch.cat( [latent_model_input, mask, masked_image_latents], dim=1) # predict the noise residual if task_class is not None: noise_pred = self.unet( sample=latent_model_input, timestep=t, encoder_hidden_states=prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, return_dict=False, task_class=task_class, )[0] else: noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, return_dict=False, )[0] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.scheduler.step( noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0] if num_channels_unet == 4: init_latents_proper = image_latents[:1] init_mask = mask[:1] if i < len(timesteps) - 1: noise_timestep = timesteps[i + 1] init_latents_proper = self.scheduler.add_noise( init_latents_proper, noise, torch.tensor([noise_timestep])) latents = (1 - init_mask ) * init_latents_proper + init_mask * latents # call the callback, if provided if i == len(timesteps) - 1 or ( (i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0): # noqa progress_bar.update() if callback is not None and i % callback_steps == 0: callback(i, t, latents) if not output_type == 'latent': condition_kwargs = {} if isinstance(self.vae, AsymmetricAutoencoderKL): init_image = init_image.to( device=device, dtype=masked_image_latents.dtype) init_image_condition = init_image.clone() init_image = self._encode_vae_image( init_image, generator=generator) mask_condition = mask_condition.to( device=device, dtype=masked_image_latents.dtype) condition_kwargs = { 'image': init_image_condition, 'mask': mask_condition } image = self.vae.decode( latents / self.vae.config.scaling_factor, return_dict=False, **condition_kwargs)[0] image, has_nsfw_concept = self.run_safety_checker( image, device, prompt_embeds.dtype) else: image = latents has_nsfw_concept = None if has_nsfw_concept is None: do_denormalize = [True] * image.shape[0] else: do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept] image = self.image_processor.postprocess( image, output_type=output_type, do_denormalize=do_denormalize) # Offload last model to CPU if hasattr( self, 'final_offload_hook') and self.final_offload_hook is not None: self.final_offload_hook.offload() if not return_dict: return (image, has_nsfw_concept) return StableDiffusionPipelineOutput( images=image, nsfw_content_detected=has_nsfw_concept) ================================================ FILE: projects/powerpaint/pipeline/pipeline_PowerPaint_ControlNet.py ================================================ # Copyright 2023 The HuggingFace Team. 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. # This model implementation is heavily inspired by https://github.com/haofanwang/ControlNet-for-Diffusers/ # noqa import inspect import warnings from typing import Any, Callable, Dict, List, Optional, Tuple, Union import numpy as np import PIL.Image import torch import torch.nn.functional as F from diffusers.image_processor import VaeImageProcessor from diffusers.loaders import (FromSingleFileMixin, LoraLoaderMixin, TextualInversionLoaderMixin) from diffusers.models import (AsymmetricAutoencoderKL, AutoencoderKL, ControlNetModel, UNet2DConditionModel) from diffusers.pipelines.controlnet import MultiControlNetModel from diffusers.pipelines.pipeline_utils import DiffusionPipeline from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput from diffusers.pipelines.stable_diffusion.safety_checker import \ StableDiffusionSafetyChecker from diffusers.schedulers import KarrasDiffusionSchedulers from diffusers.utils import (is_accelerate_available, is_accelerate_version, logging, replace_example_docstring) from diffusers.utils.torch_utils import is_compiled_module, randn_tensor from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer logger = logging.get_logger(__name__) # pylint: disable=invalid-name EXAMPLE_DOC_STRING = """ Examples: ```py >>> # !pip install transformers accelerate >>> from diffusers import (StableDiffusionControlNetInpaintPipeline, ControlNetModel, DDIMScheduler) >>> from diffusers.utils import load_image >>> import numpy as np >>> import torch >>> init_image = load_image( ... "https://huggingface.co/datasets/diffusers/" + "test-arrays/resolve/main/stable_diffusion_inpaint/boy.png") >>> init_image = init_image.resize((512, 512)) >>> generator = torch.Generator(device="cpu").manual_seed(1) >>> mask_image = load_image( ... "https://huggingface.co/datasets/diffusers/" + "test-arrays/resolve/main/stable_diffusion_inpaint/boy_mask.png") >>> mask_image = mask_image.resize((512, 512)) >>> def make_inpaint_condition(image, image_mask): ... image = np.array( image.convert("RGB")).astype(np.float32) / 255.0 ... image_mask = np.array( image_mask.convert("L")).astype(np.float32) / 255.0 ... assert image.shape[0:1] == image_mask.shape[0:1], \ "image and image_mask must have the same image size" ... image[image_mask > 0.5] = -1.0 # set as masked pixel ... image = np.expand_dims(image, 0).transpose(0, 3, 1, 2) ... image = torch.from_numpy(image) ... return image >>> control_image = make_inpaint_condition(init_image, mask_image) >>> controlnet = ControlNetModel.from_pretrained( ... "lllyasviel/control_v11p_sd15_inpaint", ... torch_dtype=torch.float16 ... ) >>> pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained( ... "runwayml/stable-diffusion-v1-5", controlnet=controlnet, ... torch_dtype=torch.float16 ... ) >>> pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config) >>> pipe.enable_model_cpu_offload() >>> # generate image >>> image = pipe( ... "a handsome man with ray-ban sunglasses", ... num_inference_steps=20, ... generator=generator, ... eta=1.0, ... image=init_image, ... mask_image=mask_image, ... control_image=control_image, ... ).images[0] ``` """ # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_inpaint.prepare_mask_and_masked_image # noqa def prepare_mask_and_masked_image(image, mask, height, width, return_image=False): """Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the ``image`` and ``1`` for the ``mask``. The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be binarized (``mask > 0.5``) and cast to ``torch.float32`` too. Args: image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint. It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width`` ``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``. mask (_type_): The mask to apply to the image, i.e. regions to inpaint. It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width`` ``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``. Raises: ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions. TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not (or the other way around). Returns: tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 4 dimensions: ``batch x channels x height x width``. """ if image is None: raise ValueError('`image` input cannot be undefined.') if mask is None: raise ValueError('`mask_image` input cannot be undefined.') if isinstance(image, torch.Tensor): if not isinstance(mask, torch.Tensor): raise TypeError('`image` is a torch.Tensor ' f'but `mask` (type: {type(mask)} is not') # Batch single image if image.ndim == 3: assert image.shape[ 0] == 3, 'Image outside a batch should be of shape (3, H, W)' image = image.unsqueeze(0) # Batch and add channel dim for single mask if mask.ndim == 2: mask = mask.unsqueeze(0).unsqueeze(0) # Batch single mask or add channel dim if mask.ndim == 3: # Single batched mask, no channel dim or single mask not # batched but channel dim if mask.shape[0] == 1: mask = mask.unsqueeze(0) # Batched masks no channel dim else: mask = mask.unsqueeze(1) assert image.ndim == 4 and mask.ndim == 4, \ 'Image and Mask must have 4 dimensions' assert image.shape[-2:] == mask.shape[ -2:], 'Image and Mask must have the same spatial dimensions' assert image.shape[0] == mask.shape[ 0], 'Image and Mask must have the same batch size' # Check image is in [-1, 1] if image.min() < -1 or image.max() > 1: raise ValueError('Image should be in [-1, 1] range') # Check mask is in [0, 1] if mask.min() < 0 or mask.max() > 1: raise ValueError('Mask should be in [0, 1] range') # Binarize mask mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 # Image as float32 image = image.to(dtype=torch.float32) elif isinstance(mask, torch.Tensor): raise TypeError( f'`mask` is a torch.Tensor but `image` (type: {type(image)} is not' ) else: # preprocess image if isinstance(image, (PIL.Image.Image, np.ndarray)): image = [image] if isinstance(image, list) and isinstance(image[0], PIL.Image.Image): # resize all images w.r.t passed height an width image = [ i.resize((width, height), resample=PIL.Image.LANCZOS) for i in image ] image = [np.array(i.convert('RGB'))[None, :] for i in image] image = np.concatenate(image, axis=0) elif isinstance(image, list) and isinstance(image[0], np.ndarray): image = np.concatenate([i[None, :] for i in image], axis=0) image = image.transpose(0, 3, 1, 2) image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0 # preprocess mask if isinstance(mask, (PIL.Image.Image, np.ndarray)): mask = [mask] if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image): mask = [ i.resize((width, height), resample=PIL.Image.LANCZOS) for i in mask ] mask = np.concatenate( [np.array(m.convert('L'))[None, None, :] for m in mask], axis=0) mask = mask.astype(np.float32) / 255.0 elif isinstance(mask, list) and isinstance(mask[0], np.ndarray): mask = np.concatenate([m[None, None, :] for m in mask], axis=0) mask[mask < 0.5] = 0 mask[mask >= 0.5] = 1 mask = torch.from_numpy(mask) masked_image = image * (mask < 0.5) # n.b. ensure backwards compatibility as old function does not return image if return_image: return mask, masked_image, image return mask, masked_image class StableDiffusionControlNetInpaintPipeline(DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin, FromSingleFileMixin): r""" Pipeline for text-to-image generation using Stable Diffusion with ControlNet guidance. This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.) In addition the pipeline inherits the following loading methods: - *Textual-Inversion*: [ `loaders.TextualInversionLoaderMixin.load_textual_inversion`] This pipeline can be used both with checkpoints that have been specifically fine-tuned for inpainting, such as [runwayml/stable-diffusion-inpainting] (https://huggingface.co/runwayml/stable-diffusion-inpainting) as well as default text-to-image stable diffusion checkpoints, such as [runwayml/stable-diffusion-v1-5] (https://huggingface.co/runwayml/stable-diffusion-v1-5). Default text-to-image stable diffusion checkpoints might be preferable for controlnets that have been fine-tuned on those, such as [lllyasviel/control_v11p_sd15_inpaint] (https://huggingface.co/lllyasviel/control_v11p_sd15_inpaint). Args: vae ([`AutoencoderKL`]): Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations. text_encoder ([`CLIPTextModel`]): Frozen text-encoder. Stable Diffusion uses the text portion of [CLIP](https://huggingface.co/docs/transformers/model_doc/clip# transformers.CLIPTextModel), specifically the [clip-vit-large-patch14](https://huggingface.co/openai/ clip-vit-large-patch14) variant. tokenizer (`CLIPTokenizer`): Tokenizer of class [CLIPTokenizer](https://huggingface.co/docs/transformers/v4.21.0/ en/model_doc/clip#transformers.CLIPTokenizer). unet ([`UNet2DConditionModel`]): Conditional U-Net architecture to denoise the encoded image latents. controlnet ([`ControlNetModel`] or `List[ControlNetModel]`): Provides additional conditioning to the unet during the denoising process. If you set multiple ControlNets as a list, the outputs from each ControlNet are added together to create one combined additional conditioning. scheduler ([`SchedulerMixin`]): A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`]. safety_checker ([`StableDiffusionSafetyChecker`]): Classification module that estimates whether generated images could be considered offensive or harmful. Please, refer to the [model card](https://huggingface.co/ runwayml/stable-diffusion-v1-5) for details. feature_extractor ([`CLIPImageProcessor`]): Model that extracts features from generated images to be used as inputs for the `safety_checker`. """ _optional_components = ['safety_checker', 'feature_extractor'] def __init__( self, vae: AutoencoderKL, text_encoder: CLIPTextModel, tokenizer: CLIPTokenizer, unet: UNet2DConditionModel, controlnet: Union[ControlNetModel, List[ControlNetModel], Tuple[ControlNetModel], MultiControlNetModel], scheduler: KarrasDiffusionSchedulers, safety_checker: StableDiffusionSafetyChecker, feature_extractor: CLIPImageProcessor, requires_safety_checker: bool = True, ): super().__init__() if safety_checker is None and requires_safety_checker: logger.warning( f'You have disabled the safety checker for {self.__class__} by' ' passing `safety_checker=None`. Ensure' ' that you abide to the conditions of the Stable Diffusion' ' license and do not expose unfiltered' ' results in services or applications open to the public.' ' Both the diffusers team and Hugging Face' ' strongly recommend to keep the safety filter enabled' ' in all public facing circumstances, disabling' ' it only for use-cases that involve analyzing network' ' behavior or auditing its results. For more' ' information, please have a look at' ' https://github.com/huggingface/diffusers/pull/254 .') if safety_checker is not None and feature_extractor is None: raise ValueError( 'Make sure to define a feature extractor when ' 'loading {self.__class__} if you want to use the safety' ' checker. If you do not want to use the safety checker,' " you can pass `'safety_checker=None'` instead.") if isinstance(controlnet, (list, tuple)): controlnet = MultiControlNetModel(controlnet) self.register_modules( vae=vae, text_encoder=text_encoder, tokenizer=tokenizer, unet=unet, controlnet=controlnet, scheduler=scheduler, safety_checker=safety_checker, feature_extractor=feature_extractor, ) self.vae_scale_factor = 2**( len(self.vae.config.block_out_channels) - 1) self.image_processor = VaeImageProcessor( vae_scale_factor=self.vae_scale_factor) self.control_image_processor = VaeImageProcessor( vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True, do_normalize=False) self.register_to_config( requires_safety_checker=requires_safety_checker) # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_slicing def enable_vae_slicing(self): r""" Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to compute decoding in several steps. This is useful to save some memory and allow larger batch sizes. """ self.vae.enable_slicing() # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.disable_vae_slicing def disable_vae_slicing(self): r""" Disable sliced VAE decoding. If `enable_vae_slicing` was previously enabled, this method will go back to computing decoding in one step. """ self.vae.disable_slicing() # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_tiling def enable_vae_tiling(self): r""" Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to compute decoding and encoding in several steps. This is useful for saving a large amount of memory and to allow processing larger images. """ self.vae.enable_tiling() # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.disable_vae_tiling def disable_vae_tiling(self): r""" Disable tiled VAE decoding. If `enable_vae_tiling` was previously enabled, this method will go back to computing decoding in one step. """ self.vae.disable_tiling() def enable_model_cpu_offload(self, gpu_id=0): r""" Offloads all models to CPU using accelerate, reducing memory usage with a low impact on performance. Compared to `enable_sequential_cpu_offload`, this method moves one whole model at a time to the GPU when its `forward` method is called, and the model remains in GPU until the next model runs. Memory savings are lower than with `enable_sequential_cpu_offload`, but performance is much better due to the iterative execution of the `unet`. """ if is_accelerate_available() and is_accelerate_version( '>=', '0.17.0.dev0'): from accelerate import cpu_offload_with_hook else: raise ImportError('`enable_model_cpu_offload` ' 'requires `accelerate v0.17.0` or higher.') device = torch.device(f'cuda:{gpu_id}') hook = None for cpu_offloaded_model in [self.text_encoder, self.unet, self.vae]: _, hook = cpu_offload_with_hook( cpu_offloaded_model, device, prev_module_hook=hook) if self.safety_checker is not None: # the safety checker can offload the vae again _, hook = cpu_offload_with_hook( self.safety_checker, device, prev_module_hook=hook) # control net hook has be manually offloaded as it alternates with unet cpu_offload_with_hook(self.controlnet, device) # We'll offload the last model manually. self.final_offload_hook = hook # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline._encode_prompt def _encode_prompt( self, promptA, promptB, t, device, num_images_per_prompt, do_classifier_free_guidance, negative_promptA=None, negative_promptB=None, t_nag=None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, lora_scale: Optional[float] = None, ): r""" Encodes the prompt into text encoder hidden states. Args: prompt (`str` or `List[str]`, *optional*): prompt to be encoded device: (`torch.device`): torch device num_images_per_prompt (`int`): number of images that should be generated per prompt do_classifier_free_guidance (`bool`): whether to use classifier free guidance or not negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. If not defined, one has to pass `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, text embeddings will be generated from `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input argument. lora_scale (`float`, *optional*): A lora scale that will be applied to all LoRA layers of the text encoder if LoRA layers are loaded. """ # set lora scale so that monkey patched LoRA # function of text encoder can correctly access it if lora_scale is not None and isinstance(self, LoraLoaderMixin): self._lora_scale = lora_scale prompt = promptA negative_prompt = negative_promptA if promptA is not None and isinstance(promptA, str): batch_size = 1 elif promptA is not None and isinstance(promptA, list): batch_size = len(promptA) else: batch_size = prompt_embeds.shape[0] if prompt_embeds is None: # textual inversion: procecss multi-vector tokens if necessary if isinstance(self, TextualInversionLoaderMixin): promptA = self.maybe_convert_prompt(promptA, self.tokenizer) text_inputsA = self.tokenizer( promptA, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_inputsB = self.tokenizer( promptB, padding='max_length', max_length=self.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_input_idsA = text_inputsA.input_ids text_input_idsB = text_inputsB.input_ids untruncated_ids = self.tokenizer( promptA, padding='longest', return_tensors='pt').input_ids if untruncated_ids.shape[-1] >= text_input_idsA.shape[ -1] and not torch.equal(text_input_idsA, untruncated_ids): removed_text = self.tokenizer.batch_decode( untruncated_ids[:, self.tokenizer.model_max_length - 1:-1]) logger.warning( 'The following part of your input was truncated because' 'CLIP can only handle sequences up to' f' {self.tokenizer.model_max_length} ' f' tokens: {removed_text}') if hasattr(self.text_encoder.config, 'use_attention_mask' ) and self.text_encoder.config.use_attention_mask: attention_mask = text_inputsA.attention_mask.to(device) else: attention_mask = None # print("text_input_idsA: ",text_input_idsA) # print("text_input_idsB: ",text_input_idsB) # print('t: ',t) prompt_embedsA = self.text_encoder( text_input_idsA.to(device), attention_mask=attention_mask, ) prompt_embedsA = prompt_embedsA[0] prompt_embedsB = self.text_encoder( text_input_idsB.to(device), attention_mask=attention_mask, ) prompt_embedsB = prompt_embedsB[0] prompt_embeds = prompt_embedsA * (t) + (1 - t) * prompt_embedsB # print("prompt_embeds: ",prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype elif self.unet is not None: prompt_embeds_dtype = self.unet.dtype else: prompt_embeds_dtype = prompt_embeds.dtype prompt_embeds = prompt_embeds.to( dtype=prompt_embeds_dtype, device=device) bs_embed, seq_len, _ = prompt_embeds.shape # duplicate text embeddings for each generation per prompt, # using mps friendly method prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1) prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1) # get unconditional embeddings for classifier free guidance if do_classifier_free_guidance and negative_prompt_embeds is None: uncond_tokensA: List[str] uncond_tokensB: List[str] if negative_prompt is None: uncond_tokensA = [''] * batch_size uncond_tokensB = [''] * batch_size elif prompt is not None and type(prompt) is not type( negative_prompt): raise TypeError( f'`negative_prompt` should be the same type to `prompt`, ' f'but got {type(negative_prompt)} !=' f' {type(prompt)}.') elif isinstance(negative_prompt, str): uncond_tokensA = [negative_promptA] uncond_tokensB = [negative_promptB] elif batch_size != len(negative_prompt): raise ValueError( f'`negative_prompt`: {negative_prompt} has ' f'batch size {len(negative_prompt)}, but `prompt`:' f' {prompt} has batch size {batch_size}. Please make' ' sure that passed `negative_prompt` matches' ' the batch size of `prompt`.') else: uncond_tokensA = negative_promptA uncond_tokensB = negative_promptB # textual inversion: procecss multi-vector tokens if necessary if isinstance(self, TextualInversionLoaderMixin): uncond_tokensA = self.maybe_convert_prompt( uncond_tokensA, self.tokenizer) uncond_tokensB = self.maybe_convert_prompt( uncond_tokensB, self.tokenizer) max_length = prompt_embeds.shape[1] uncond_inputA = self.tokenizer( uncond_tokensA, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) uncond_inputB = self.tokenizer( uncond_tokensB, padding='max_length', max_length=max_length, truncation=True, return_tensors='pt', ) if hasattr(self.text_encoder.config, 'use_attention_mask' ) and self.text_encoder.config.use_attention_mask: attention_mask = uncond_inputA.attention_mask.to(device) else: attention_mask = None negative_prompt_embedsA = self.text_encoder( uncond_inputA.input_ids.to(device), attention_mask=attention_mask, ) negative_prompt_embedsB = self.text_encoder( uncond_inputB.input_ids.to(device), attention_mask=attention_mask, ) negative_prompt_embeds = negative_prompt_embedsA[0] * (t_nag) + ( 1 - t_nag) * negative_prompt_embedsB[0] # negative_prompt_embeds = negative_prompt_embeds[0] if do_classifier_free_guidance: # duplicate unconditional embeddings for each generation # per prompt, using mps friendly method seq_len = negative_prompt_embeds.shape[1] negative_prompt_embeds = negative_prompt_embeds.to( dtype=prompt_embeds_dtype, device=device) negative_prompt_embeds = negative_prompt_embeds.repeat( 1, num_images_per_prompt, 1) negative_prompt_embeds = negative_prompt_embeds.view( batch_size * num_images_per_prompt, seq_len, -1) # For classifier free guidance, we need to do two forward passes. # Here we concatenate the unconditional and text embeddings # into a single batch # to avoid doing two forward passes # print("prompt_embeds: ",prompt_embeds) prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds]) return prompt_embeds # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker def run_safety_checker(self, image, device, dtype): if self.safety_checker is None: has_nsfw_concept = None else: if torch.is_tensor(image): feature_extractor_input = self.image_processor.postprocess( image, output_type='pil') else: feature_extractor_input = self.image_processor.numpy_to_pil( image) safety_checker_input = self.feature_extractor( feature_extractor_input, return_tensors='pt').to(device) image, has_nsfw_concept = self.safety_checker( images=image, clip_input=safety_checker_input.pixel_values.to(dtype)) return image, has_nsfw_concept # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents def decode_latents(self, latents): warnings.warn( 'The decode_latents method is deprecated and will ' 'be removed in a future version. Please' ' use VaeImageProcessor instead', FutureWarning, ) latents = 1 / self.vae.config.scaling_factor * latents image = self.vae.decode(latents, return_dict=False)[0] image = (image / 2 + 0.5).clamp(0, 1) # we always cast to float32 as this does not cause significant # overhead and is compatible with bfloat16 image = image.cpu().permute(0, 2, 3, 1).float().numpy() return image # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion.StableDiffusionPipeline. # prepare_extra_step_kwargs def prepare_extra_step_kwargs(self, generator, eta): # prepare extra kwargs for the scheduler step, since not # all schedulers have the same signature # eta (η) is only used with the DDIMScheduler, it # will be ignored for other schedulers. # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 # and should be between [0, 1] accepts_eta = 'eta' in set( inspect.signature(self.scheduler.step).parameters.keys()) extra_step_kwargs = {} if accepts_eta: extra_step_kwargs['eta'] = eta # check if the scheduler accepts generator accepts_generator = 'generator' in set( inspect.signature(self.scheduler.step).parameters.keys()) if accepts_generator: extra_step_kwargs['generator'] = generator return extra_step_kwargs # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion_img2img. # StableDiffusionImg2ImgPipeline.get_timesteps def get_timesteps(self, num_inference_steps, strength, device): # get the original timestep using init_timestep init_timestep = min( int(num_inference_steps * strength), num_inference_steps) t_start = max(num_inference_steps - init_timestep, 0) timesteps = self.scheduler.timesteps[t_start * self.scheduler.order:] return timesteps, num_inference_steps - t_start def check_inputs( self, prompt, image, height, width, callback_steps, negative_prompt=None, prompt_embeds=None, negative_prompt_embeds=None, controlnet_conditioning_scale=1.0, control_guidance_start=0.0, control_guidance_end=1.0, ): if height % 8 != 0 or width % 8 != 0: raise ValueError('`height` and `width` have to be divisible ' f' by 8 but are {height} and {width}.') if (callback_steps is None) or (callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)): raise ValueError(f'`callback_steps` has to be a positive ' f' integer but is {callback_steps} of type' f' {type(callback_steps)}.') if prompt is not None and prompt_embeds is not None: raise ValueError( f'Cannot forward both `prompt`: {prompt} and ' f'`prompt_embeds`: {prompt_embeds}. Please make sure to' ' only forward one of the two.') elif prompt is None and prompt_embeds is None: raise ValueError( 'Provide either `prompt` or `prompt_embeds`.' 'Cannot leave both `prompt` and `prompt_embeds` undefined.') elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)): raise ValueError(f'`prompt` has to be of ' f'type `str` or `list` but is {type(prompt)}') if negative_prompt is not None and negative_prompt_embeds is not None: raise ValueError( f'Cannot forward both `negative_prompt`: {negative_prompt} ' f'and `negative_prompt_embeds`:' f' {negative_prompt_embeds}. Please make' f' sure to only forward one of the two.') if prompt_embeds is not None and negative_prompt_embeds is not None: if prompt_embeds.shape != negative_prompt_embeds.shape: raise ValueError( '`prompt_embeds` and `negative_prompt_embeds` must' f' have the same shape when passed directly, but' f' got: `prompt_embeds` {prompt_embeds.shape} != ' '`negative_prompt_embeds`' f' {negative_prompt_embeds.shape}.') # `prompt` needs more sophisticated handling when there are multiple # conditionings. if isinstance(self.controlnet, MultiControlNetModel): if isinstance(prompt, list): logger.warning( f'You have {len(self.controlnet.nets)} ControlNets ' ' and you have passed {len(prompt)}' ' prompts. The conditionings will be ' ' fixed across the prompts.') # Check `image` is_compiled = hasattr( F, 'scaled_dot_product_attention') and isinstance( self.controlnet, torch._dynamo.eval_frame.OptimizedModule) if (isinstance(self.controlnet, ControlNetModel) or is_compiled and isinstance(self.controlnet._orig_mod, ControlNetModel)): self.check_image(image, prompt, prompt_embeds) elif (isinstance(self.controlnet, MultiControlNetModel) or is_compiled and isinstance(self.controlnet._orig_mod, MultiControlNetModel)): if not isinstance(image, list): raise TypeError( 'For multiple controlnets: `image` must be type `list`') # When `image` is a nested list: # (e.g. [[canny_image_1, pose_image_1], # [canny_image_2, pose_image_2]]) elif any(isinstance(i, list) for i in image): raise ValueError('A single batch of multiple conditionings ' 'are supported at the moment.') elif len(image) != len(self.controlnet.nets): raise ValueError( 'For multiple controlnets: `image` must have the ' 'same length as the number of controlnets, but got' f' {len(image)} images ' f' and {len(self.controlnet.nets)} ControlNets.') for image_ in image: self.check_image(image_, prompt, prompt_embeds) else: assert False # Check `controlnet_conditioning_scale` if (isinstance(self.controlnet, ControlNetModel) or is_compiled and isinstance(self.controlnet._orig_mod, ControlNetModel)): if not isinstance(controlnet_conditioning_scale, float): raise TypeError( 'For single controlnet: ' '`controlnet_conditioning_scale` must be type `float`.') elif (isinstance(self.controlnet, MultiControlNetModel) or is_compiled and isinstance(self.controlnet._orig_mod, MultiControlNetModel)): if isinstance(controlnet_conditioning_scale, list): if any( isinstance(i, list) for i in controlnet_conditioning_scale): raise ValueError( 'A single batch of ' 'multiple conditionings are supported at the moment.') elif isinstance( controlnet_conditioning_scale, list) and len(controlnet_conditioning_scale) != len( self.controlnet.nets): raise ValueError( 'For multiple controlnets: When ' '`controlnet_conditioning_scale` is specified as ' '`list`, it must have' ' the same length as the number of controlnets') else: assert False if len(control_guidance_start) != len(control_guidance_end): raise ValueError( f'`control_guidance_start` has {len(control_guidance_start)} ' ' elements, but `control_guidance_end` has' f' {len(control_guidance_end)} elements. Make sure to' f' provide the same number of elements to each list.') if isinstance(self.controlnet, MultiControlNetModel): if len(control_guidance_start) != len(self.controlnet.nets): raise ValueError( f'`control_guidance_start`: {control_guidance_start} has' f' {len(control_guidance_start)} elements but there ' f' are {len(self.controlnet.nets)} controlnets available. ' f' Make sure to provide {len(self.controlnet.nets)}.') for start, end in zip(control_guidance_start, control_guidance_end): if start >= end: raise ValueError( f'control guidance start: {start} cannot be larger or ' f'equal to control guidance end: {end}.') if start < 0.0: raise ValueError( f"control guidance start: {start} can't be smaller than 0." ) if end > 1.0: raise ValueError( f"control guidance end: {end} can't be larger than 1.0.") # Copied from diffusers.pipelines.controlnet.pipeline_controlnet. # StableDiffusionControlNetPipeline.check_image def check_image(self, image, prompt, prompt_embeds): image_is_pil = isinstance(image, PIL.Image.Image) image_is_tensor = isinstance(image, torch.Tensor) image_is_np = isinstance(image, np.ndarray) image_is_pil_list = isinstance(image, list) and isinstance( image[0], PIL.Image.Image) image_is_tensor_list = isinstance(image, list) and isinstance( image[0], torch.Tensor) image_is_np_list = isinstance(image, list) and isinstance( image[0], np.ndarray) if (not image_is_pil and not image_is_tensor and not image_is_np and not image_is_pil_list and not image_is_tensor_list and not image_is_np_list): raise TypeError( 'image must be passed and be one of PIL image, numpy array,' f' torch tensor, list of PIL images, list of numpy arrays or' f'list of torch tensors, but is {type(image)}') if image_is_pil: image_batch_size = 1 else: image_batch_size = len(image) if prompt is not None and isinstance(prompt, str): prompt_batch_size = 1 elif prompt is not None and isinstance(prompt, list): prompt_batch_size = len(prompt) elif prompt_embeds is not None: prompt_batch_size = prompt_embeds.shape[0] if image_batch_size != 1 and image_batch_size != prompt_batch_size: raise ValueError( 'If image batch size is not 1, image batch size must be ' 'same as prompt batch size. ' f' image batch size: {image_batch_size}, ' f' prompt batch size: {prompt_batch_size}') # Copied from diffusers.pipelines.controlnet.pipeline_controlnet. # StableDiffusionControlNetPipeline.prepare_image def prepare_control_image( self, image, width, height, batch_size, num_images_per_prompt, device, dtype, do_classifier_free_guidance=False, guess_mode=False, ): image = self.control_image_processor.preprocess( image, height=height, width=width).to(dtype=torch.float32) image_batch_size = image.shape[0] if image_batch_size == 1: repeat_by = batch_size else: # image batch size is the same as prompt batch size repeat_by = num_images_per_prompt image = image.repeat_interleave(repeat_by, dim=0) image = image.to(device=device, dtype=dtype) if do_classifier_free_guidance and not guess_mode: image = torch.cat([image] * 2) return image # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion_inpaint. # StableDiffusionInpaintPipeline.prepare_latents def prepare_latents( self, batch_size, num_channels_latents, height, width, dtype, device, generator, latents=None, image=None, timestep=None, is_strength_max=True, return_noise=False, return_image_latents=False, ): shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) if isinstance(generator, list) and len(generator) != batch_size: raise ValueError( 'You have passed a list of generators of ' f'length {len(generator)}, but requested an effective batch' f' size of {batch_size}. Make sure the batch size ' 'matches the length of the generators.') if (image is None or timestep is None) and not is_strength_max: raise ValueError( 'Since strength < 1. initial latents are to be initialised' ' as a combination of Image + Noise.' 'However, either the image or the noise timestep has ' ' not been provided.') if return_image_latents or (latents is None and not is_strength_max): image = image.to(device=device, dtype=dtype) image_latents = self._encode_vae_image( image=image, generator=generator) if latents is None: noise = randn_tensor( shape, generator=generator, device=device, dtype=dtype) # if strength is 1. then initialise the latents to noise, # else initial to image + noise latents = noise if is_strength_max else self.scheduler.add_noise( image_latents, noise, timestep) # if pure noise then scale the initial latents by the # Scheduler's init sigma latents = latents * self.scheduler.init_noise_sigma \ if is_strength_max else latents else: noise = latents.to(device) latents = noise * self.scheduler.init_noise_sigma outputs = (latents, ) if return_noise: outputs += (noise, ) if return_image_latents: outputs += (image_latents, ) return outputs def _default_height_width(self, height, width, image): # NOTE: It is possible that a list of images have different # dimensions for each image, so just checking the first image # is not _exactly_ correct, but it is simple. while isinstance(image, list): image = image[0] if height is None: if isinstance(image, PIL.Image.Image): height = image.height elif isinstance(image, torch.Tensor): height = image.shape[2] height = (height // 8) * 8 # round down to nearest multiple of 8 if width is None: if isinstance(image, PIL.Image.Image): width = image.width elif isinstance(image, torch.Tensor): width = image.shape[3] width = (width // 8) * 8 # round down to nearest multiple of 8 return height, width # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion_inpaint. # StableDiffusionInpaintPipeline.prepare_mask_latents def prepare_mask_latents(self, mask, masked_image, batch_size, height, width, dtype, device, generator, do_classifier_free_guidance): # resize the mask to latents shape as we # concatenate the mask to the latents # we do that before converting to dtype to # avoid breaking in case we're using cpu_offload # and half precision mask = torch.nn.functional.interpolate( mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)) mask = mask.to(device=device, dtype=dtype) masked_image = masked_image.to(device=device, dtype=dtype) masked_image_latents = self._encode_vae_image( masked_image, generator=generator) # duplicate mask and masked_image_latents for each generation per # prompt, using mps friendly method if mask.shape[0] < batch_size: if not batch_size % mask.shape[0] == 0: raise ValueError( "The passed mask and required batch size don't match.'" ' Masks are supposed to be duplicated to' f' total batch size of {batch_size}, but {mask.shape[0]} ' ' masks were passed. Make sure the number' ' of masks that you pass is divisible by the total ' ' requested batch size.') mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1) if masked_image_latents.shape[0] < batch_size: if not batch_size % masked_image_latents.shape[0] == 0: raise ValueError( 'The passed images and the required batch size ' " don't match. Images are supposed to be duplicated" f' to a total batch size of {batch_size}, but ' f' {masked_image_latents.shape[0]} images were passed.' ' Make sure the number of images that you pass is ' ' divisible by the total requested batch size.') masked_image_latents = masked_image_latents.repeat( batch_size // masked_image_latents.shape[0], 1, 1, 1) mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask masked_image_latents = ( torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents) # aligning device to prevent device errors when # concatenating it with the latent model input masked_image_latents = masked_image_latents.to( device=device, dtype=dtype) return mask, masked_image_latents # Copied from diffusers.pipelines.stable_diffusion. # pipeline_stable_diffusion_inpaint. # StableDiffusionInpaintPipeline._encode_vae_image def _encode_vae_image(self, image: torch.Tensor, generator: torch.Generator): if isinstance(generator, list): image_latents = [ self.vae.encode(image[i:i + 1]).latent_dist.sample( generator=generator[i]) for i in range(image.shape[0]) ] image_latents = torch.cat(image_latents, dim=0) else: image_latents = self.vae.encode(image).latent_dist.sample( generator=generator) image_latents = self.vae.config.scaling_factor * image_latents return image_latents @torch.no_grad() def predict_woControl( self, promptA: Union[str, List[str]] = None, promptB: Union[str, List[str]] = None, image: Union[torch.FloatTensor, PIL.Image.Image] = None, mask_image: Union[torch.FloatTensor, PIL.Image.Image] = None, height: Optional[int] = None, width: Optional[int] = None, strength: float = 1.0, tradoff: float = 1.0, tradoff_nag: float = 1.0, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_promptA: Optional[Union[str, List[str]]] = None, negative_promptB: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, latents: Optional[torch.FloatTensor] = None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, output_type: Optional[str] = 'pil', return_dict: bool = True, callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None, callback_steps: int = 1, cross_attention_kwargs: Optional[Dict[str, Any]] = None, task_class: Union[torch.Tensor, float, int] = None, ): r""" The call function to the pipeline for generation. Args: prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`. image (`PIL.Image.Image`): `Image` or tensor representing an image batch to be inpainted (which parts of the image to be masked out with `mask_image` and repainted according to `prompt`). mask_image (`PIL.Image.Image`): `Image` or tensor representing an image batch to mask `image`. White pixels in the mask are repainted while black pixels are preserved. If `mask_image` is a PIL image, it is converted to a single channel (luminance) before use. If it's a tensor, it should contain one color channel (L) instead of 3, so the expected shape would be `(B, H, W, 1)`. height (`int`, *optional*, defaults to `self.unet.config. sample_size * self.vae_scale_factor`): The height in pixels of the generated image. width (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`): The width in pixels of the generated image. strength (`float`, *optional*, defaults to 1.0): Indicates extent to transform the reference `image`. Must be between 0 and 1. `image` is used as a starting point and more noise is added the higher the `strength`. The number of denoising steps depends on the amount of noise initially added. When `strength` is 1, added noise is maximum and the denoising process runs for the full number of iterations specified in `num_inference_steps`. A value of 1 essentially ignores `image`. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. This parameter is modulated by `strength`. guidance_scale (`float`, *optional*, defaults to 7.5): A higher guidance scale value encourages the model to generate images closely linked to the text `prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`. negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide what to not include in image generation. If not defined, you need to pass `negative_prompt_embeds` instead. Ignored when not using guidance (`guidance_scale < 1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) from the [DDIM] (https://arxiv.org/abs/2010.02502) paper. Only applies to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers. generator (`torch.Generator` or `List[torch.Generator]`, *optional*): A [`torch.Generator`](https://pytorch.org/docs/stable/ generated/torch.Generator.html) to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor is generated by sampling using the supplied random `generator`. prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not provided, text embeddings are generated from the `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not provided, `negative_prompt_embeds` are generated from the `negative_prompt` input argument. output_type (`str`, *optional*, defaults to `"pil"`): The output format of the generated image. Choose between `PIL.Image` or `np.array`. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`~pipelines.stable_diffusion. StableDiffusionPipelineOutput`] instead of a plain tuple. callback (`Callable`, *optional*): A function that calls every `callback_steps` steps during inference. The function is called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`. callback_steps (`int`, *optional*, defaults to 1): The frequency at which the `callback` function is called. If not specified, the callback is called at every step. cross_attention_kwargs (`dict`, *optional*): A kwargs dictionary that if specified is passed along to the [`AttentionProcessor`] as defined in [`self.processor`](https://github.com/huggingface/diffusers/ blob/main/src/diffusers/models/attention_processor.py). Examples: ```py >>> import PIL >>> import requests >>> import torch >>> from io import BytesIO >>> from diffusers import StableDiffusionInpaintPipeline >>> def download_image(url): ... response = requests.get(url) ... return PIL.Image.open(BytesIO(response.content)).convert("RGB") >>> img_url = "https://raw.githubusercontent.com/CompVis/ latent-diffusion/main/data/inpainting_examples/ overture-creations-5sI6fQgYIuo.png" >>> mask_url = "https://raw.githubusercontent.com/CompVis/ latent-diffusion/main/data/inpainting_examples/ overture-creations-5sI6fQgYIuo_mask.png" >>> init_image = download_image(img_url).resize((512, 512)) >>> mask_image = download_image(mask_url).resize((512, 512)) >>> pipe = StableDiffusionInpaintPipeline.from_pretrained( ... "runwayml/stable-diffusion-inpainting", torch_dtype=torch.float16 ... ) >>> pipe = pipe.to("cuda") >>> prompt = "Face of a yellow cat, high resolution, sitting on a park bench" >>> image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0] ``` Returns: [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`: If `return_dict` is `True`, [`~pipelines.stable_diffusion. StableDiffusionPipelineOutput`] is returned, otherwise a `tuple` is returned where the first element is a list with the generated images and the second element is a list of `bool`s indicating whether the corresponding generated image contains "not-safe-for-work" (nsfw) content. """ # 0. Default height and width to unet height = height or self.unet.config.sample_size * self.vae_scale_factor width = width or self.unet.config.sample_size * self.vae_scale_factor prompt = promptA negative_prompt = negative_promptA # 1. Check inputs self.check_inputs( prompt, height, width, strength, callback_steps, negative_prompt, prompt_embeds, negative_prompt_embeds, ) # 2. Define call parameters if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] device = self._execution_device # here `guidance_scale` is defined analog to the guidance # weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 # 3. Encode input prompt text_encoder_lora_scale = ( cross_attention_kwargs.get('scale', None) if cross_attention_kwargs is not None else None) prompt_embeds = self._encode_prompt( promptA, promptB, tradoff, device, num_images_per_prompt, do_classifier_free_guidance, negative_promptA, negative_promptB, tradoff_nag, prompt_embeds=prompt_embeds, negative_prompt_embeds=negative_prompt_embeds, lora_scale=text_encoder_lora_scale, ) # 4. set timesteps self.scheduler.set_timesteps(num_inference_steps, device=device) timesteps, num_inference_steps = self.get_timesteps( num_inference_steps=num_inference_steps, strength=strength, device=device) # check that number of inference steps is not < 1 - # as this doesn't make sense if num_inference_steps < 1: raise ValueError( 'After adjusting the num_inference_steps by strength ' f'parameter: {strength}, the number of pipeline' f'steps is {num_inference_steps} which is < 1 and ' f'not appropriate for this pipeline.') # at which timestep to set the initial noise # (n.b. 50% if strength is 0.5) latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt) # create a boolean to check if the strength # is set to 1. if so then initialise the latents with pure noise is_strength_max = strength == 1.0 # 5. Preprocess mask and image mask, masked_image, init_image = prepare_mask_and_masked_image( image, mask_image, height, width, return_image=True) mask_condition = mask.clone() # 6. Prepare latent variables num_channels_latents = self.vae.config.latent_channels num_channels_unet = self.unet.config.in_channels return_image_latents = num_channels_unet == 4 latents_outputs = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, prompt_embeds.dtype, device, generator, latents, image=init_image, timestep=latent_timestep, is_strength_max=is_strength_max, return_noise=True, return_image_latents=return_image_latents, ) if return_image_latents: latents, noise, image_latents = latents_outputs else: latents, noise = latents_outputs # 7. Prepare mask latent variables mask, masked_image_latents = self.prepare_mask_latents( mask, masked_image, batch_size * num_images_per_prompt, height, width, prompt_embeds.dtype, device, generator, do_classifier_free_guidance, ) # 8. Check that sizes of mask, masked image and latents match if num_channels_unet == 9: # default case for runwayml/stable-diffusion-inpainting num_channels_mask = mask.shape[1] num_channels_masked_image = masked_image_latents.shape[1] if (num_channels_latents + num_channels_mask + num_channels_masked_image) != self.unet.config.in_channels: raise ValueError( 'Incorrect configuration settings! The config ' f'of `pipeline.unet`: {self.unet.config} expects' f' {self.unet.config.in_channels} but received ' f'`num_channels_latents`: {num_channels_latents} +' f' `num_channels_mask`: {num_channels_mask} + ' f'`num_channels_masked_image`: {num_channels_masked_image}' f' = {num_channels_latents+num_channels_masked_image+num_channels_mask}. Please verify the config of' # noqa ' `pipeline.unet` or your `mask_image` or `image` input.') elif num_channels_unet != 4: raise ValueError( f'The unet {self.unet.__class__} should have either 4 ' f'or 9 input channels, not {self.unet.config.in_channels}.') # 9. Prepare extra step kwargs. TODO: Logic should ideally # just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 10. Denoising loop num_warmup_steps = len( timesteps) - num_inference_steps * self.scheduler.order with self.progress_bar(total=num_inference_steps) as progress_bar: for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents # concat latents, mask, masked_image_latents # in the channel dimension latent_model_input = self.scheduler.scale_model_input( latent_model_input, t) if num_channels_unet == 9: latent_model_input = torch.cat( [latent_model_input, mask, masked_image_latents], dim=1) # predict the noise residual if task_class is not None: noise_pred = self.unet( sample=latent_model_input, timestep=t, encoder_hidden_states=prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, return_dict=False, task_class=task_class, )[0] else: noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, return_dict=False, )[0] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.scheduler.step( noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0] if num_channels_unet == 4: init_latents_proper = image_latents[:1] init_mask = mask[:1] if i < len(timesteps) - 1: noise_timestep = timesteps[i + 1] init_latents_proper = self.scheduler.add_noise( init_latents_proper, noise, torch.tensor([noise_timestep])) latents = (1 - init_mask ) * init_latents_proper + init_mask * latents # call the callback, if provided if i == len(timesteps) - 1 or ( (i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0): # noqa progress_bar.update() if callback is not None and i % callback_steps == 0: callback(i, t, latents) if not output_type == 'latent': condition_kwargs = {} if isinstance(self.vae, AsymmetricAutoencoderKL): init_image = init_image.to( device=device, dtype=masked_image_latents.dtype) init_image_condition = init_image.clone() init_image = self._encode_vae_image( init_image, generator=generator) mask_condition = mask_condition.to( device=device, dtype=masked_image_latents.dtype) condition_kwargs = { 'image': init_image_condition, 'mask': mask_condition } image = self.vae.decode( latents / self.vae.config.scaling_factor, return_dict=False, **condition_kwargs)[0] image, has_nsfw_concept = self.run_safety_checker( image, device, prompt_embeds.dtype) else: image = latents has_nsfw_concept = None if has_nsfw_concept is None: do_denormalize = [True] * image.shape[0] else: do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept] image = self.image_processor.postprocess( image, output_type=output_type, do_denormalize=do_denormalize) # Offload last model to CPU if hasattr( self, 'final_offload_hook') and self.final_offload_hook is not None: self.final_offload_hook.offload() if not return_dict: return (image, has_nsfw_concept) return StableDiffusionPipelineOutput( images=image, nsfw_content_detected=has_nsfw_concept) @torch.no_grad() @replace_example_docstring(EXAMPLE_DOC_STRING) def __call__( self, promptA: Union[str, List[str]] = None, promptB: Union[str, List[str]] = None, image: Union[torch.Tensor, PIL.Image.Image] = None, mask_image: Union[torch.Tensor, PIL.Image.Image] = None, control_image: Union[torch.FloatTensor, PIL.Image.Image, np.ndarray, List[torch.FloatTensor], List[PIL.Image.Image], List[np.ndarray], ] = None, height: Optional[int] = None, width: Optional[int] = None, strength: float = 1.0, tradoff: float = 1.0, tradoff_nag: float = 1.0, num_inference_steps: int = 50, guidance_scale: float = 7.5, negative_promptA: Optional[Union[str, List[str]]] = None, negative_promptB: Optional[Union[str, List[str]]] = None, num_images_per_prompt: Optional[int] = 1, eta: float = 0.0, generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, latents: Optional[torch.FloatTensor] = None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, output_type: Optional[str] = 'pil', return_dict: bool = True, callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None, callback_steps: int = 1, cross_attention_kwargs: Optional[Dict[str, Any]] = None, controlnet_conditioning_scale: Union[float, List[float]] = 0.5, guess_mode: bool = False, control_guidance_start: Union[float, List[float]] = 0.0, control_guidance_end: Union[float, List[float]] = 1.0, ): r""" Function invoked when calling the pipeline for generation. Args: prompt (`str` or `List[str]`, *optional*): The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`. instead. image (`torch.FloatTensor`, `PIL.Image.Image`, `List[torch.FloatTensor]`, `List[PIL.Image.Image]`, `List[List[torch.FloatTensor]]`, or `List[List[PIL.Image.Image]]`): The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If the type is specified as `Torch.FloatTensor`, it is passed to ControlNet as is. `PIL.Image.Image` can also be accepted as an image. The dimensions of the output image defaults to `image`'s dimensions. If height and/or width are passed, `image` is resized according to them. If multiple ControlNets are specified in init, images must be passed as a list such that each element of the list can be correctly batched for input to a single controlnet. height (`int`, *optional*, defaults to self.unet.config. sample_size * self.vae_scale_factor): The height in pixels of the generated image. width (`int`, *optional*, defaults to self.unet.config. sample_size * self.vae_scale_factor): The width in pixels of the generated image. strength (`float`, *optional*, defaults to 1.): Conceptually, indicates how much to transform the masked portion of the reference `image`. Must be between 0 and 1. `image` will be used as a starting point, adding more noise to it the larger the `strength`. The number of denoising steps depends on the amount of noise initially added. When `strength` is 1, added noise will be maximum and the denoising process will run for the full number of iterations specified in `num_inference_steps`. A value of 1, therefore, essentially ignores the masked portion of the reference `image`. num_inference_steps (`int`, *optional*, defaults to 50): The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference. guidance_scale (`float`, *optional*, defaults to 7.5): Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598). `guidance_scale` is defined as `w` of equation 2. of [Imagen Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale > 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`, usually at the expense of lower image quality. negative_prompt (`str` or `List[str]`, *optional*): The prompt or prompts not to guide the image generation. If not defined, one has to pass `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`). num_images_per_prompt (`int`, *optional*, defaults to 1): The number of images to generate per prompt. eta (`float`, *optional*, defaults to 0.0): Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to [`schedulers.DDIMScheduler`], will be ignored for others. generator (`torch.Generator` or `List[torch.Generator]`, *optional*): One or a list of [torch generator(s)] (https://pytorch.org/docs/stable/generated/torch.Generator.html) to make generation deterministic. latents (`torch.FloatTensor`, *optional*): Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image generation. Can be used to tweak the same generation with different prompts. If not provided, a latents tensor will ge generated by sampling using the supplied random `generator`. prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, text embeddings will be generated from `prompt` input argument. negative_prompt_embeds (`torch.FloatTensor`, *optional*): Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input argument. output_type (`str`, *optional*, defaults to `"pil"`): The output format of the generate image. Choose between [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`. return_dict (`bool`, *optional*, defaults to `True`): Whether or not to return a [`~pipelines.stable_diffusion. StableDiffusionPipelineOutput`] instead of a plain tuple. callback (`Callable`, *optional*): A function that will be called every `callback_steps` steps during inference. The function will be called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`. callback_steps (`int`, *optional*, defaults to 1): The frequency at which the `callback` function will be called. If not specified, the callback will be called at every step. cross_attention_kwargs (`dict`, *optional*): A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under `self.processor` in [diffusers.models.attention_processor] (https://github.com/huggingface/diffusers/blob/main/src /diffusers/models/attention_processor.py). controlnet_conditioning_scale (`float` or `List[float]`, *optional*, defaults to 0.5): The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added to the residual in the original unet. If multiple ControlNets are specified in init, you can set the corresponding scale as a list. Note that by default, we use a smaller conditioning scale for inpainting than for [`~StableDiffusionControlNetPipeline.__call__`]. guess_mode (`bool`, *optional*, defaults to `False`): In this mode, the ControlNet encoder will try best to recognize the content of the input image even if you remove all prompts. The `guidance_scale` between 3.0 and 5.0 is recommended. control_guidance_start (`float` or `List[float]`, *optional*, defaults to 0.0): The percentage of total steps at which the controlnet starts applying. control_guidance_end (`float` or `List[float]`, *optional*, defaults to 1.0): The percentage of total steps at which the controlnet stops applying. Examples: Returns: [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`: [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple. When returning a tuple, the first element is a list with the generated images, and the second element is a list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work" (nsfw) content, according to the `safety_checker`. """ controlnet = self.controlnet._orig_mod if is_compiled_module( self.controlnet) else self.controlnet # 0. Default height and width to unet height, width = self._default_height_width(height, width, image) prompt = promptA negative_prompt = negative_promptA # align format for control guidance if not isinstance(control_guidance_start, list) and isinstance( control_guidance_end, list): control_guidance_start = len(control_guidance_end) * [ control_guidance_start ] elif not isinstance(control_guidance_end, list) and isinstance( control_guidance_start, list): control_guidance_end = len(control_guidance_start) * [ control_guidance_end ] elif not isinstance(control_guidance_start, list) and not isinstance( control_guidance_end, list): mult = len(controlnet.nets) if isinstance( controlnet, MultiControlNetModel) else 1 control_guidance_start, control_guidance_end = mult * [ control_guidance_start ], mult * [control_guidance_end] # 1. Check inputs. Raise error if not correct self.check_inputs( prompt, control_image, height, width, callback_steps, negative_prompt, prompt_embeds, negative_prompt_embeds, controlnet_conditioning_scale, control_guidance_start, control_guidance_end, ) # 2. Define call parameters if prompt is not None and isinstance(prompt, str): batch_size = 1 elif prompt is not None and isinstance(prompt, list): batch_size = len(prompt) else: batch_size = prompt_embeds.shape[0] device = self._execution_device # here `guidance_scale` is defined analog to the guidance # weight `w` of equation (2) # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . # `guidance_scale = 1` # corresponds to doing no classifier free guidance. do_classifier_free_guidance = guidance_scale > 1.0 if isinstance(controlnet, MultiControlNetModel) and isinstance( controlnet_conditioning_scale, float): controlnet_conditioning_scale = [controlnet_conditioning_scale ] * len(controlnet.nets) global_pool_conditions = ( controlnet.config.global_pool_conditions if isinstance( controlnet, ControlNetModel) else controlnet.nets[0].config.global_pool_conditions) guess_mode = guess_mode or global_pool_conditions # 3. Encode input prompt text_encoder_lora_scale = ( cross_attention_kwargs.get('scale', None) if cross_attention_kwargs is not None else None) prompt_embeds = self._encode_prompt( promptA, promptB, tradoff, device, num_images_per_prompt, do_classifier_free_guidance, negative_promptA, negative_promptB, tradoff_nag, prompt_embeds=prompt_embeds, negative_prompt_embeds=negative_prompt_embeds, lora_scale=text_encoder_lora_scale, ) # 4. Prepare image if isinstance(controlnet, ControlNetModel): control_image = self.prepare_control_image( image=control_image, width=width, height=height, batch_size=batch_size * num_images_per_prompt, num_images_per_prompt=num_images_per_prompt, device=device, dtype=controlnet.dtype, do_classifier_free_guidance=do_classifier_free_guidance, guess_mode=guess_mode, ) elif isinstance(controlnet, MultiControlNetModel): control_images = [] for control_image_ in control_image: control_image_ = self.prepare_control_image( image=control_image_, width=width, height=height, batch_size=batch_size * num_images_per_prompt, num_images_per_prompt=num_images_per_prompt, device=device, dtype=controlnet.dtype, do_classifier_free_guidance=do_classifier_free_guidance, guess_mode=guess_mode, ) control_images.append(control_image_) control_image = control_images else: assert False # 4. Preprocess mask and image - resizes image and # mask w.r.t height and width mask, masked_image, init_image = prepare_mask_and_masked_image( image, mask_image, height, width, return_image=True) # 5. Prepare timesteps self.scheduler.set_timesteps(num_inference_steps, device=device) timesteps, num_inference_steps = self.get_timesteps( num_inference_steps=num_inference_steps, strength=strength, device=device) # at which timestep to set the initial noise (n.b. # 50% if strength is 0.5) latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt) # create a boolean to check if the strength is set to 1. if so # then initialise the latents with pure noise is_strength_max = strength == 1.0 # 6. Prepare latent variables num_channels_latents = self.vae.config.latent_channels num_channels_unet = self.unet.config.in_channels return_image_latents = num_channels_unet == 4 latents_outputs = self.prepare_latents( batch_size * num_images_per_prompt, num_channels_latents, height, width, prompt_embeds.dtype, device, generator, latents, image=init_image, timestep=latent_timestep, is_strength_max=is_strength_max, return_noise=True, return_image_latents=return_image_latents, ) if return_image_latents: latents, noise, image_latents = latents_outputs else: latents, noise = latents_outputs # 7. Prepare mask latent variables mask, masked_image_latents = self.prepare_mask_latents( mask, masked_image, batch_size * num_images_per_prompt, height, width, prompt_embeds.dtype, device, generator, do_classifier_free_guidance, ) # 7. Prepare extra step kwargs. TODO: Logic should ideally # just be moved out of the pipeline extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) # 7.1 Create tensor stating which controlnets to keep controlnet_keep = [] for i in range(len(timesteps)): keeps = [ 1.0 - float(i / len(timesteps) < s or (i + 1) / len(timesteps) > e) for s, e in zip(control_guidance_start, control_guidance_end) ] controlnet_keep.append( keeps[0] if isinstance(controlnet, ControlNetModel) else keeps) # 8. Denoising loop num_warmup_steps = len( timesteps) - num_inference_steps * self.scheduler.order with self.progress_bar(total=num_inference_steps) as progress_bar: for i, t in enumerate(timesteps): # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents latent_model_input = self.scheduler.scale_model_input( latent_model_input, t) # controlnet(s) inference if guess_mode and do_classifier_free_guidance: # Infer ControlNet only for the conditional batch. control_model_input = latents control_model_input = self.scheduler.scale_model_input( control_model_input, t) controlnet_prompt_embeds = prompt_embeds.chunk(2)[1] else: control_model_input = latent_model_input controlnet_prompt_embeds = prompt_embeds if isinstance(controlnet_keep[i], list): cond_scale = [ c * s for c, s in zip(controlnet_conditioning_scale, controlnet_keep[i]) ] else: controlnet_cond_scale = controlnet_conditioning_scale if isinstance(controlnet_cond_scale, list): controlnet_cond_scale = controlnet_cond_scale[0] cond_scale = controlnet_cond_scale * controlnet_keep[i] down_block_res_samples, mid_block_res_sample = self.controlnet( control_model_input, t, encoder_hidden_states=controlnet_prompt_embeds, controlnet_cond=control_image, conditioning_scale=cond_scale, guess_mode=guess_mode, return_dict=False, ) if guess_mode and do_classifier_free_guidance: # Inferred ControlNet only for the conditional batch. # To apply the output of ControlNet to both the # unconditional and conditional batches, # add 0 to the unconditional batch to keep it unchanged. down_block_res_samples = [ torch.cat([torch.zeros_like(d), d]) for d in down_block_res_samples ] mid_block_res_sample = torch.cat([ torch.zeros_like(mid_block_res_sample), mid_block_res_sample ]) # predict the noise residual if num_channels_unet == 9: latent_model_input = torch.cat( [latent_model_input, mask, masked_image_latents], dim=1) noise_pred = self.unet( latent_model_input, t, encoder_hidden_states=prompt_embeds, cross_attention_kwargs=cross_attention_kwargs, down_block_additional_residuals=down_block_res_samples, mid_block_additional_residual=mid_block_res_sample, return_dict=False, )[0] # perform guidance if do_classifier_free_guidance: noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_pred_text - noise_pred_uncond) # compute the previous noisy sample x_t -> x_t-1 latents = self.scheduler.step( noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0] if num_channels_unet == 4: init_latents_proper = image_latents[:1] init_mask = mask[:1] if i < len(timesteps) - 1: noise_timestep = timesteps[i + 1] init_latents_proper = self.scheduler.add_noise( init_latents_proper, noise, torch.tensor([noise_timestep])) latents = (1 - init_mask ) * init_latents_proper + init_mask * latents # call the callback, if provided if i == len(timesteps) - 1 or ( (i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0): # noqa progress_bar.update() if callback is not None and i % callback_steps == 0: callback(i, t, latents) # If we do sequential model offloading, let's # offload unet and controlnet # manually for max memory savings if hasattr( self, 'final_offload_hook') and self.final_offload_hook is not None: self.unet.to('cpu') self.controlnet.to('cpu') torch.cuda.empty_cache() if not output_type == 'latent': image = self.vae.decode( latents / self.vae.config.scaling_factor, return_dict=False)[0] image, has_nsfw_concept = self.run_safety_checker( image, device, prompt_embeds.dtype) else: image = latents has_nsfw_concept = None if has_nsfw_concept is None: do_denormalize = [True] * image.shape[0] else: do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept] image = self.image_processor.postprocess( image, output_type=output_type, do_denormalize=do_denormalize) # Offload last model to CPU if hasattr( self, 'final_offload_hook') and self.final_offload_hook is not None: self.final_offload_hook.offload() if not return_dict: return (image, has_nsfw_concept) return StableDiffusionPipelineOutput( images=image, nsfw_content_detected=has_nsfw_concept) ================================================ FILE: projects/powerpaint/requirements.txt ================================================ controlnet-aux==0.0.3 diffusers==0.23.1 gradio==3.41.0 mmengine opencv-python torch torchvision transformers ================================================ FILE: projects/powerpaint/utils/utils.py ================================================ import copy import importlib import os import random from logging import WARNING from typing import Any, List, Optional, Union import torch import torch.nn as nn from mmengine import print_log def try_import(name: str): """Try to import a module. Args: name (str): Specifies what module to import in absolute or relative terms (e.g. either pkg.mod or ..mod). Returns: ModuleType or None: If importing successfully, returns the imported module, otherwise returns None. """ try: return importlib.import_module(name) except ImportError: return None class TokenizerWrapper: """Tokenizer wrapper for CLIPTokenizer. Only support CLIPTokenizer currently. This wrapper is modified from https://github.com/huggingface/dif fusers/blob/e51f19aee82c8dd874b715a09dbc521d88835d68/src/diffusers/loaders. py#L358 # noqa. Args: from_pretrained (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Defaults to None. from_config (Union[str, os.PathLike], optional): The *model id* of a pretrained model or a path to a *directory* containing model weights and config. Defaults to None. *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs will be passed to `from_pretrained` function. Otherwise, *args and **kwargs will be used to initialize the model by `self._module_cls(*args, **kwargs)`. """ def __init__(self, from_pretrained: Optional[Union[str, os.PathLike]] = None, from_config: Optional[Union[str, os.PathLike]] = None, *args, **kwargs): transformers = try_import('transformers') module_cls = transformers.CLIPTokenizer assert not (from_pretrained and from_config), ( '\'from_pretrained\' and \'from_config\' should not be passed ' 'at the same time.') if from_config: print_log( 'Tokenizers from Huggingface transformers do not support ' '\'from_config\'. Will call \'from_pretrained\' instead ' 'with the same argument.', 'current', WARNING) from_pretrained = from_config if from_pretrained: self.wrapped = module_cls.from_pretrained(from_pretrained, *args, **kwargs) else: self.wrapper = module_cls(*args, **kwargs) self._from_pretrained = from_pretrained self.token_map = {} def __getattr__(self, name: str) -> Any: if name == 'wrapped': return super().__getattr__('wrapped') try: return getattr(self.wrapped, name) except AttributeError: try: return super().__getattr__(name) except AttributeError: raise AttributeError( '\'name\' cannot be found in both ' f'\'{self.__class__.__name__}\' and ' f'\'{self.__class__.__name__}.tokenizer\'.') def try_adding_tokens(self, tokens: Union[str, List[str]], *args, **kwargs): """Attempt to add tokens to the tokenizer. Args: tokens (Union[str, List[str]]): The tokens to be added. """ num_added_tokens = self.wrapped.add_tokens(tokens, *args, **kwargs) assert num_added_tokens != 0, ( f'The tokenizer already contains the token {tokens}. Please pass ' 'a different `placeholder_token` that is not already in the ' 'tokenizer.') def get_token_info(self, token: str) -> dict: """Get the information of a token, including its start and end index in the current tokenizer. Args: token (str): The token to be queried. Returns: dict: The information of the token, including its start and end index in current tokenizer. """ token_ids = self.__call__(token).input_ids start, end = token_ids[1], token_ids[-2] + 1 return {'name': token, 'start': start, 'end': end} def add_placeholder_token(self, placeholder_token: str, *args, num_vec_per_token: int = 1, **kwargs): """Add placeholder tokens to the tokenizer. Args: placeholder_token (str): The placeholder token to be added. num_vec_per_token (int, optional): The number of vectors of the added placeholder token. *args, **kwargs: The arguments for `self.wrapped.add_tokens`. """ output = [] if num_vec_per_token == 1: self.try_adding_tokens(placeholder_token, *args, **kwargs) output.append(placeholder_token) else: output = [] for i in range(num_vec_per_token): ith_token = placeholder_token + f'_{i}' self.try_adding_tokens(ith_token, *args, **kwargs) output.append(ith_token) for token in self.token_map: if token in placeholder_token: raise ValueError( f'The tokenizer already has placeholder token {token} ' f'that can get confused with {placeholder_token} ' 'keep placeholder tokens independent') self.token_map[placeholder_token] = output def replace_placeholder_tokens_in_text(self, text: Union[str, List[str]], vector_shuffle: bool = False, prop_tokens_to_load: float = 1.0 ) -> Union[str, List[str]]: """Replace the keywords in text with placeholder tokens. This function will be called in `self.__call__` and `self.encode`. Args: text (Union[str, List[str]]): The text to be processed. vector_shuffle (bool, optional): Whether to shuffle the vectors. Defaults to False. prop_tokens_to_load (float, optional): The proportion of tokens to be loaded. If 1.0, all tokens will be loaded. Defaults to 1.0. Returns: Union[str, List[str]]: The processed text. """ if isinstance(text, list): output = [] for i in range(len(text)): output.append( self.replace_placeholder_tokens_in_text( text[i], vector_shuffle=vector_shuffle)) return output for placeholder_token in self.token_map: if placeholder_token in text: tokens = self.token_map[placeholder_token] tokens = tokens[:1 + int(len(tokens) * prop_tokens_to_load)] if vector_shuffle: tokens = copy.copy(tokens) random.shuffle(tokens) text = text.replace(placeholder_token, ' '.join(tokens)) return text def replace_text_with_placeholder_tokens(self, text: Union[str, List[str]] ) -> Union[str, List[str]]: """Replace the placeholder tokens in text with the original keywords. This function will be called in `self.decode`. Args: text (Union[str, List[str]]): The text to be processed. Returns: Union[str, List[str]]: The processed text. """ if isinstance(text, list): output = [] for i in range(len(text)): output.append( self.replace_text_with_placeholder_tokens(text[i])) return output for placeholder_token, tokens in self.token_map.items(): merged_tokens = ' '.join(tokens) if merged_tokens in text: text = text.replace(merged_tokens, placeholder_token) return text def __call__(self, text: Union[str, List[str]], *args, vector_shuffle: bool = False, prop_tokens_to_load: float = 1.0, **kwargs): """The call function of the wrapper. Args: text (Union[str, List[str]]): The text to be tokenized. vector_shuffle (bool, optional): Whether to shuffle the vectors. Defaults to False. prop_tokens_to_load (float, optional): The proportion of tokens to be loaded. If 1.0, all tokens will be loaded. Defaults to 1.0 *args, **kwargs: The arguments for `self.wrapped.__call__`. """ replaced_text = self.replace_placeholder_tokens_in_text( text, vector_shuffle=vector_shuffle, prop_tokens_to_load=prop_tokens_to_load) return self.wrapped.__call__(replaced_text, *args, **kwargs) def encode(self, text: Union[str, List[str]], *args, **kwargs): """Encode the passed text to token index. Args: text (Union[str, List[str]]): The text to be encode. *args, **kwargs: The arguments for `self.wrapped.__call__`. """ replaced_text = self.replace_placeholder_tokens_in_text(text) return self.wrapped(replaced_text, *args, **kwargs) def decode(self, token_ids, return_raw: bool = False, *args, **kwargs) -> Union[str, List[str]]: """Decode the token index to text. Args: token_ids: The token index to be decoded. return_raw: Whether keep the placeholder token in the text. Defaults to False. *args, **kwargs: The arguments for `self.wrapped.decode`. Returns: Union[str, List[str]]: The decoded text. """ text = self.wrapped.decode(token_ids, *args, **kwargs) if return_raw: return text replaced_text = self.replace_text_with_placeholder_tokens(text) return replaced_text def __repr__(self): """The representation of the wrapper.""" s = super().__repr__() prefix = f'Wrapped Module Class: {self._module_cls}\n' prefix += f'Wrapped Module Name: {self._module_name}\n' if self._from_pretrained: prefix += f'From Pretrained: {self._from_pretrained}\n' s = prefix + s return s class EmbeddingLayerWithFixes(nn.Module): """The revised embedding layer to support external embeddings. This design of this class is inspired by https://github.com/AUTOMATIC1111/stable- diffusion-webui/blob/22bcc7be428c94e9408f589966c2040187245d81/modules/sd_hi jack.py#L224 # noqa. Args: wrapped (nn.Emebdding): The embedding layer to be wrapped. external_embeddings (Union[dict, List[dict]], optional): The external embeddings added to this layer. Defaults to None. """ def __init__(self, wrapped: nn.Embedding, external_embeddings: Optional[Union[dict, List[dict]]] = None): super().__init__() self.wrapped = wrapped self.num_embeddings = wrapped.weight.shape[0] self.external_embeddings = [] if external_embeddings: self.add_embeddings(external_embeddings) self.trainable_embeddings = nn.ParameterDict() @property def weight(self): """Get the weight of wrapped embedding layer.""" return self.wrapped.weight def check_duplicate_names(self, embeddings: List[dict]): """Check whether duplicate names exist in list of 'external embeddings'. Args: embeddings (List[dict]): A list of embedding to be check. """ names = [emb['name'] for emb in embeddings] assert len(names) == len(set(names)), ( 'Found duplicated names in \'external_embeddings\'. Name list: ' f'\'{names}\'') def check_ids_overlap(self, embeddings): """Check whether overlap exist in token ids of 'external_embeddings'. Args: embeddings (List[dict]): A list of embedding to be check. """ ids_range = [[emb['start'], emb['end'], emb['name']] for emb in embeddings] ids_range.sort() # sort by 'start' # check if 'end' has overlapping for idx in range(len(ids_range) - 1): name1, name2 = ids_range[idx][-1], ids_range[idx + 1][-1] assert ids_range[idx][1] <= ids_range[idx + 1][0], ( f'Found ids overlapping between embeddings \'{name1}\' ' f'and \'{name2}\'.') def add_embeddings(self, embeddings: Optional[Union[dict, List[dict]]]): """Add external embeddings to this layer. Use case: >>> 1. Add token to tokenizer and get the token id. >>> tokenizer = TokenizerWrapper('openai/clip-vit-base-patch32') >>> # 'how much' in kiswahili >>> tokenizer.add_placeholder_tokens('ngapi', num_vec_per_token=4) >>> >>> 2. Add external embeddings to the model. >>> new_embedding = { >>> 'name': 'ngapi', # 'how much' in kiswahili >>> 'embedding': torch.ones(1, 15) * 4, >>> 'start': tokenizer.get_token_info('kwaheri')['start'], >>> 'end': tokenizer.get_token_info('kwaheri')['end'], >>> 'trainable': False # if True, will registry as a parameter >>> } >>> embedding_layer = nn.Embedding(10, 15) >>> embedding_layer_wrapper = EmbeddingLayerWithFixes(embedding_layer) >>> embedding_layer_wrapper.add_embeddings(new_embedding) >>> >>> 3. Forward tokenizer and embedding layer! >>> input_text = ['hello, ngapi!', 'hello my friend, ngapi?'] >>> input_ids = tokenizer( >>> input_text, padding='max_length', truncation=True, >>> return_tensors='pt')['input_ids'] >>> out_feat = embedding_layer_wrapper(input_ids) >>> >>> 4. Let's validate the result! >>> assert (out_feat[0, 3: 7] == 2.3).all() >>> assert (out_feat[2, 5: 9] == 2.3).all() Args: embeddings (Union[dict, list[dict]]): The external embeddings to be added. Each dict must contain the following 4 fields: 'name' (the name of this embedding), 'embedding' (the embedding tensor), 'start' (the start token id of this embedding), 'end' (the end token id of this embedding). For example: `{name: NAME, start: START, end: END, embedding: torch.Tensor}` """ if isinstance(embeddings, dict): embeddings = [embeddings] self.external_embeddings += embeddings self.check_duplicate_names(self.external_embeddings) self.check_ids_overlap(self.external_embeddings) # set for trainable added_trainable_emb_info = [] for embedding in embeddings: trainable = embedding.get('trainable', False) if trainable: name = embedding['name'] embedding['embedding'] = torch.nn.Parameter( embedding['embedding']) self.trainable_embeddings[name] = embedding['embedding'] added_trainable_emb_info.append(name) added_emb_info = [emb['name'] for emb in embeddings] added_emb_info = ', '.join(added_emb_info) print_log(f'Successfully add external embeddings: {added_emb_info}.', 'current') if added_trainable_emb_info: added_trainable_emb_info = ', '.join(added_trainable_emb_info) print_log( 'Successfully add trainable external embeddings: ' f'{added_trainable_emb_info}', 'current') def replace_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor: """Replace external input ids to 0. Args: input_ids (torch.Tensor): The input ids to be replaced. Returns: torch.Tensor: The replaced input ids. """ input_ids_fwd = input_ids.clone() input_ids_fwd[input_ids_fwd >= self.num_embeddings] = 0 return input_ids_fwd def replace_embeddings(self, input_ids: torch.Tensor, embedding: torch.Tensor, external_embedding: dict) -> torch.Tensor: """Replace external embedding to the embedding layer. Noted that, in this function we use `torch.cat` to avoid inplace modification. Args: input_ids (torch.Tensor): The original token ids. Shape like [LENGTH, ]. embedding (torch.Tensor): The embedding of token ids after `replace_input_ids` function. external_embedding (dict): The external embedding to be replaced. Returns: torch.Tensor: The replaced embedding. """ new_embedding = [] name = external_embedding['name'] start = external_embedding['start'] end = external_embedding['end'] target_ids_to_replace = [i for i in range(start, end)] ext_emb = external_embedding['embedding'] # do not need to replace if not (input_ids == start).any(): return embedding # start replace s_idx, e_idx = 0, 0 while e_idx < len(input_ids): if input_ids[e_idx] == start: if e_idx != 0: # add embedding do not need to replace new_embedding.append(embedding[s_idx:e_idx]) # check if the next embedding need to replace is valid actually_ids_to_replace = [ int(i) for i in input_ids[e_idx:e_idx + end - start] ] assert actually_ids_to_replace == target_ids_to_replace, ( f'Invalid \'input_ids\' in position: {s_idx} to {e_idx}. ' f'Expect \'{target_ids_to_replace}\' for embedding ' f'\'{name}\' but found \'{actually_ids_to_replace}\'.') new_embedding.append(ext_emb) s_idx = e_idx + end - start e_idx = s_idx + 1 else: e_idx += 1 if e_idx == len(input_ids): new_embedding.append(embedding[s_idx:e_idx]) return torch.cat(new_embedding, dim=0) def forward(self, input_ids: torch.Tensor, external_embeddings: Optional[List[dict]] = None): """The forward function. Args: input_ids (torch.Tensor): The token ids shape like [bz, LENGTH] or [LENGTH, ]. external_embeddings (Optional[List[dict]]): The external embeddings. If not passed, only `self.external_embeddings` will be used. Defaults to None. input_ids: shape like [bz, LENGTH] or [LENGTH]. """ assert input_ids.ndim in [1, 2] if input_ids.ndim == 1: input_ids = input_ids.unsqueeze(0) if external_embeddings is None and not self.external_embeddings: return self.wrapped(input_ids) input_ids_fwd = self.replace_input_ids(input_ids) inputs_embeds = self.wrapped(input_ids_fwd) vecs = [] if external_embeddings is None: external_embeddings = [] elif isinstance(external_embeddings, dict): external_embeddings = [external_embeddings] embeddings = self.external_embeddings + external_embeddings for input_id, embedding in zip(input_ids, inputs_embeds): new_embedding = embedding for external_embedding in embeddings: new_embedding = self.replace_embeddings( input_id, new_embedding, external_embedding) vecs.append(new_embedding) return torch.stack(vecs) def add_tokens(tokenizer, text_encoder, placeholder_tokens: list, initialize_tokens: list = None, num_vectors_per_token: int = 1): """Add token for training. # TODO: support add tokens as dict, then we can load pretrained tokens. """ if initialize_tokens is not None: assert len(initialize_tokens) == len(placeholder_tokens), ( 'placeholder_token should be the same length as initialize_token') for ii in range(len(placeholder_tokens)): tokenizer.add_placeholder_token( placeholder_tokens[ii], num_vec_per_token=num_vectors_per_token) # text_encoder.set_embedding_layer() embedding_layer = text_encoder.text_model.embeddings.token_embedding text_encoder.text_model.embeddings.token_embedding = \ EmbeddingLayerWithFixes(embedding_layer) embedding_layer = text_encoder.text_model.embeddings.token_embedding assert embedding_layer is not None, ( 'Do not support get embedding layer for current text encoder. ' 'Please check your configuration.') initialize_embedding = [] if initialize_tokens is not None: for ii in range(len(placeholder_tokens)): init_id = tokenizer(initialize_tokens[ii]).input_ids[1] temp_embedding = embedding_layer.weight[init_id] initialize_embedding.append(temp_embedding[None, ...].repeat( num_vectors_per_token, 1)) else: for ii in range(len(placeholder_tokens)): init_id = tokenizer('a').input_ids[1] temp_embedding = embedding_layer.weight[init_id] len_emb = temp_embedding.shape[0] init_weight = (torch.rand(num_vectors_per_token, len_emb) - 0.5) / 2.0 initialize_embedding.append(init_weight) # initialize_embedding = torch.cat(initialize_embedding,dim=0) token_info_all = [] for ii in range(len(placeholder_tokens)): token_info = tokenizer.get_token_info(placeholder_tokens[ii]) token_info['embedding'] = initialize_embedding[ii] token_info['trainable'] = True token_info_all.append(token_info) embedding_layer.add_embeddings(token_info_all) ================================================ FILE: projects/prompt_to_prompt/README.md ================================================ # Inversions & Editing (DDIM Inversion & Null-Text Inversion & Prompt-to-Prompt Editing) ``` Author: @FerryHuang This is an implementation of the papers: ``` > [PROMPT-TO-PROMPT IMAGE EDITING > WITH CROSS-ATTENTION CONTROL](https://prompt-to-prompt.github.io/ptp_files/Prompt-to-Prompt_preprint.pdf) > [Null-text Inversion for Editing Real Images using Guided Diffusion Models](https://arxiv.org/pdf/2211.09794.pdf) > **Task**: Text2Image, diffusion, inversion, editing ## Abstract Diffusion's inversion basically means you put an image (with or without a prompt) into a method and it will return a latent code which can be later turned back to a image with high simmilarity as the original one. Of course we want this latent code for an editing purpose, that's also why we always implement inversion methods together with the editing methods. This project contains **Two inversion methods** and **One editing method**. ## From right to left: origin image, DDIM inversion, Null-text inversion
## Prompt-to-prompt Editing
cat -> dog
spider man -> iron man(attention replace)
Effel tower -> Effel tower at night (attention refine)
blossom sakura tree -> blossom(-3) sakura tree (attention reweight)
## Quick Start A walkthrough of the project is provided [here](visualize.ipynb) or you can just run the following scripts to get the results: ```python # load the mmagic SD1.5 from mmengine import MODELS, Config from mmengine.registry import init_default_scope init_default_scope('mmagic') config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py' config = Config.fromfile(config).copy() StableDiffuser = MODELS.build(config.model) StableDiffuser = StableDiffuser.to('cuda') ``` ```python # inversion image_path = 'projects/prompt_to_prompt/assets/gnochi_mirror.jpeg' prompt = "a cat sitting next to a mirror" image_tensor = ptp_utils.load_512(image_path).to('cuda') from inversions.null_text_inversion import NullTextInversion from models.ptp import EmptyControl from models import ptp_utils null_inverter = NullTextInversion(StableDiffuser) null_inverter.init_prompt(prompt) ddim_latents = null_inverter.ddim_inversion(image_tensor) x_t = ddim_latents[-1] uncond_embeddings = null_inverter.null_optimization(ddim_latents, num_inner_steps=10, epsilon=1e-5) null_text_rec, _ = ptp_utils.text2image_ldm_stable(StableDiffuser, [prompt], EmptyControl(), latent=x_t, uncond_embeddings=uncond_embeddings) ptp_utils.view_images(null_text_rec) ``` ```python # prompt-to-prompt editing prompts = ["A cartoon of spiderman", "A cartoon of ironman"] import torch from models.ptp import LocalBlend, AttentionReplace from models.ptp_utils import text2image_ldm_stable g = torch.Generator().manual_seed(2023616) lb = LocalBlend(prompts, ("spiderman", "ironman"), model=StableDiffuser) controller = AttentionReplace(prompts, 50, cross_replace_steps={"default_": 1., "ironman": .2}, self_replace_steps=0.4, local_blend=lb, model=StableDiffuser) images, x_t = text2image_ldm_stable(StableDiffuser, prompts, controller, latent=None, num_inference_steps=50, guidance_scale=7.5, uncond_embeddings=None, generator=g) ``` ## Citation ```bibtex @article{hertz2022prompt, title = {Prompt-to-Prompt Image Editing with Cross Attention Control}, author = {Hertz, Amir and Mokady, Ron and Tenenbaum, Jay and Aberman, Kfir and Pritch, Yael and Cohen-Or, Daniel}, journal = {arXiv preprint arXiv:2208.01626}, year = {2022}, } @article{mokady2022null, title={Null-text Inversion for Editing Real Images using Guided Diffusion Models}, author={Mokady, Ron and Hertz, Amir and Aberman, Kfir and Pritch, Yael and Cohen-Or, Daniel}, journal={arXiv preprint arXiv:2211.09794}, year={2022} } ``` ================================================ FILE: projects/prompt_to_prompt/inversions/__init__.py ================================================ ================================================ FILE: projects/prompt_to_prompt/inversions/ddim_inversion.py ================================================ """This code was originally taken from https://github.com/google/prompt-to- prompt and modified by Ferry.""" # Copyright 2022 Google LLC # # 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. from typing import Union import numpy as np import torch from PIL import Image from mmagic.models.diffusion_schedulers import EditDDIMScheduler class DDIMInversion: def __init__(self, model, **kwargs): scheduler = EditDDIMScheduler( beta_start=0.00085, beta_end=0.012, beta_schedule='scaled_linear', clip_sample=False, set_alpha_to_one=False) self.model = model self.num_ddim_steps = kwargs.pop('num_ddim_steps', 50) self.guidance_scale = kwargs.pop('guidance_scale', 7.5) self.tokenizer = self.model.tokenizer self.model.scheduler = scheduler self.model.scheduler.set_timesteps(self.num_ddim_steps) self.prompt = None self.context = None def prev_step(self, model_output: Union[torch.FloatTensor, np.ndarray], timestep: int, sample: Union[torch.FloatTensor, np.ndarray]): prev_timestep = timestep - ( self.scheduler.num_train_timesteps // self.scheduler.num_inference_steps) alpha_prod_t = self.scheduler.alphas_cumprod[timestep] alpha_prod_t_prev = ( self.scheduler.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.scheduler.final_alpha_cumprod) beta_prod_t = 1 - alpha_prod_t pred_original_sample = ( sample - beta_prod_t**0.5 * model_output) / alpha_prod_t**0.5 pred_sample_direction = (1 - alpha_prod_t_prev)**0.5 * model_output prev_sample = alpha_prod_t_prev**0.5 * pred_original_sample \ + pred_sample_direction return prev_sample def next_step(self, model_output: Union[torch.FloatTensor, np.ndarray], timestep: int, sample: Union[torch.FloatTensor, np.ndarray]): timestep, next_timestep = min( timestep - self.scheduler.num_train_timesteps // self.scheduler.num_inference_steps, 999), timestep alpha_prod_t = self.scheduler.alphas_cumprod[ timestep] if timestep >= 0 else self.scheduler.final_alpha_cumprod alpha_prod_t_next = self.scheduler.alphas_cumprod[next_timestep] beta_prod_t = 1 - alpha_prod_t next_original_sample = ( sample - beta_prod_t**0.5 * model_output) / alpha_prod_t**0.5 next_sample_direction = (1 - alpha_prod_t_next)**0.5 * model_output next_sample = alpha_prod_t_next**0.5 * next_original_sample \ + next_sample_direction return next_sample def get_noise_pred_single(self, latents, t, context): noise_pred = self.model.unet( latents, t, encoder_hidden_states=context)['sample'] return noise_pred def get_noise_pred(self, latents, t, is_forward=True, context=None): latents_input = torch.cat([latents] * 2) if context is None: context = self.context guidance_scale = 1 if is_forward else self.guidance_scale noise_pred = self.model.unet( latents_input, t, encoder_hidden_states=context)['sample'] noise_pred_uncond, noise_prediction_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_prediction_text - noise_pred_uncond) if is_forward: latents = self.next_step(noise_pred, t, latents) else: latents = self.prev_step(noise_pred, t, latents) return latents @torch.no_grad() def latent2image(self, latents, return_type='np'): latents = 1 / 0.18215 * latents.detach() image = self.model.vae.decode(latents, return_dict=False)[0] if return_type == 'np': image = (image / 2 + 0.5).clamp(0, 1) image = image.cpu().permute(0, 2, 3, 1).numpy()[0] image = (image * 255).astype(np.uint8) return image @torch.no_grad() def image2latent(self, image): with torch.no_grad(): if type(image) is Image: image = np.array(image) if type(image) is torch.Tensor and image.dim() == 4: latents = image else: image = torch.from_numpy(image).float() / 127.5 - 1 image = image.permute(2, 0, 1).unsqueeze(0).to(self.model.device) latents = self.model.vae.encode(image)['latent_dist'].mean latents = latents * 0.18215 return latents @torch.no_grad() def init_prompt(self, prompt: str): uncond_input = self.model.tokenizer( [''], padding='max_length', max_length=self.model.tokenizer.model_max_length, return_tensors='pt') uncond_embeddings = self.model.text_encoder( uncond_input.input_ids.to(self.model.device))[0] text_input = self.model.tokenizer( [prompt], padding='max_length', max_length=self.model.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_embeddings = self.model.text_encoder( text_input.input_ids.to(self.model.device))[0] self.context = torch.cat([uncond_embeddings, text_embeddings]) self.prompt = prompt @torch.no_grad() def ddim_loop(self, latent): uncond_embeddings, cond_embeddings = self.context.chunk(2) all_latent = [latent] latent = latent.clone().detach() for i in range(self.num_ddim_steps): t = self.model.scheduler.timesteps[ len(self.model.scheduler.timesteps) - i - 1] noise_pred = self.get_noise_pred_single(latent, t, cond_embeddings) latent = self.next_step(noise_pred, t, latent) all_latent.append(latent) return all_latent @property def scheduler(self): return self.model.scheduler @torch.no_grad() def ddim_inversion(self, image): latent = self.model.vae.encode(image)['latent_dist'].mean latent = latent * 0.18215 # image_rec = self.latent2image(latent) ddim_latents = self.ddim_loop(latent) return ddim_latents ================================================ FILE: projects/prompt_to_prompt/inversions/null_text_inversion.py ================================================ import torch import torch.nn.functional as F from inversions.ddim_inversion import DDIMInversion from torch.optim import Adam from tqdm import tqdm class NullTextInversion(DDIMInversion): # basically the only thing null_text_inversion does is # to add a null_text_optimization method over ddim inversion def null_optimization(self, latents, num_inner_steps, epsilon): uncond_embeddings, cond_embeddings = self.context.chunk(2) uncond_embeddings_list = [] latent_cur = latents[-1] bar = tqdm(total=num_inner_steps * self.num_ddim_steps) for i in range(self.num_ddim_steps): uncond_embeddings = uncond_embeddings.clone().detach() uncond_embeddings.requires_grad = True optimizer = Adam([uncond_embeddings], lr=1e-2 * (1. - i / 100.)) latent_prev = latents[len(latents) - i - 2] t = self.model.scheduler.timesteps[i] with torch.no_grad(): noise_pred_cond = self.get_noise_pred_single( latent_cur, t, cond_embeddings) for j in range(num_inner_steps): noise_pred_uncond = self.get_noise_pred_single( latent_cur, t, uncond_embeddings) noise_pred = noise_pred_uncond + self.guidance_scale * ( noise_pred_cond - noise_pred_uncond) latents_prev_rec = self.prev_step(noise_pred, t, latent_cur) loss = F.mse_loss(latents_prev_rec, latent_prev) optimizer.zero_grad() loss.backward() optimizer.step() loss_item = loss.item() bar.update() if loss_item < epsilon + i * 2e-5: break for j in range(j + 1, num_inner_steps): bar.update() uncond_embeddings_list.append(uncond_embeddings[:1].detach()) with torch.no_grad(): context = torch.cat([uncond_embeddings, cond_embeddings]) latent_cur = self.get_noise_pred(latent_cur, t, False, context) bar.close() return uncond_embeddings_list ================================================ FILE: projects/prompt_to_prompt/models/ptp.py ================================================ """This code was originally taken from https://github.com/google/prompt-to- prompt.""" import abc from typing import Dict, List, Optional, Tuple, Union import numpy as np import torch import torch.nn.functional as nnf from PIL import Image import projects.prompt_to_prompt.models.ptp_utils as ptp_utils import projects.prompt_to_prompt.models.seq_aligner as seq_aligner LOW_RESOURCE = False MAX_NUM_WORDS = 77 def make_controller(prompts: List[str], is_replace_controller: bool, cross_replace_steps: Dict[str, float], self_replace_steps: float, blend_words=None, equilizer_params=None, model=None): num_ddim_steps = 50 if blend_words is None: lb = None else: lb = LocalBlend(prompts, blend_words, model=model) if is_replace_controller: controller = AttentionReplace( prompts, num_ddim_steps, cross_replace_steps=cross_replace_steps, self_replace_steps=self_replace_steps, local_blend=lb, model=model) else: controller = AttentionRefine( prompts, num_ddim_steps, cross_replace_steps=cross_replace_steps, self_replace_steps=self_replace_steps, local_blend=lb, model=model) if equilizer_params is not None: eq = get_equalizer(prompts[1], equilizer_params['words'], equilizer_params['values']) controller = AttentionReweight( prompts, num_ddim_steps, cross_replace_steps=cross_replace_steps, self_replace_steps=self_replace_steps, equalizer=eq, local_blend=lb, controller=controller) return controller class LocalBlend: def __call__(self, x_t, attention_store): k = 1 maps = attention_store['down_cross'][2:4] + attention_store[ 'up_cross'][:3] maps = [ item.reshape(self.alpha_layers.shape[0], -1, 1, 16, 16, MAX_NUM_WORDS) for item in maps ] maps = torch.cat(maps, dim=1) maps = (maps * self.alpha_layers).sum(-1).mean(1) mask = nnf.max_pool2d( maps, (k * 2 + 1, k * 2 + 1), (1, 1), padding=(k, k)) mask = nnf.interpolate(mask, size=(x_t.shape[2:])) mask = mask / mask.max(2, keepdims=True)[0].max(3, keepdims=True)[0] mask = mask.gt(self.threshold) mask = (mask[:1] + mask[1:]).float() x_t = x_t[:1] + mask * (x_t - x_t[:1]) return x_t def __init__(self, prompts: List[str], words, threshold=.3, model=None): device, tokenizer = model.device, model.tokenizer alpha_layers = torch.zeros(len(prompts), 1, 1, 1, 1, MAX_NUM_WORDS) for i, (prompt, words_) in enumerate(zip(prompts, words)): if type(words_) is str: words_ = [words_] for word in words_: ind = ptp_utils.get_word_inds(prompt, word, tokenizer) alpha_layers[i, :, :, :, :, ind] = 1 self.alpha_layers = alpha_layers.to(device) self.threshold = threshold class AttentionControl(abc.ABC): def step_callback(self, x_t): return x_t def between_steps(self): return @property def num_uncond_att_layers(self): return self.num_att_layers if LOW_RESOURCE else 0 @abc.abstractmethod def forward(self, attn, is_cross: bool, place_in_unet: str): raise NotImplementedError def __call__(self, attn, is_cross: bool, place_in_unet: str): if self.cur_att_layer >= self.num_uncond_att_layers: if LOW_RESOURCE: attn = self.forward(attn, is_cross, place_in_unet) else: h = attn.shape[0] attn[h // 2:] = self.forward(attn[h // 2:], is_cross, place_in_unet) self.cur_att_layer += 1 if self.cur_att_layer == (self.num_att_layers + self.num_uncond_att_layers): self.cur_att_layer = 0 self.cur_step += 1 self.between_steps() return attn def reset(self): self.cur_step = 0 self.cur_att_layer = 0 def __init__(self): self.cur_step = 0 self.num_att_layers = -1 self.cur_att_layer = 0 class EmptyControl: def step_callback(self, x_t): return x_t def between_steps(self): return def __call__(self, attn, is_cross: bool, place_in_unet: str): return attn class AttentionStore(AttentionControl): @staticmethod def get_empty_store(): return { 'down_cross': [], 'mid_cross': [], 'up_cross': [], 'down_self': [], 'mid_self': [], 'up_self': [] } def forward(self, attn, is_cross: bool, place_in_unet: str): key = f"{place_in_unet}_{'cross' if is_cross else 'self'}" if attn.shape[1] <= 32**2: # avoid memory overhead self.step_store[key].append(attn) return attn def between_steps(self): if len(self.attention_store) == 0: self.attention_store = self.step_store else: for key in self.attention_store: for i in range(len(self.attention_store[key])): self.attention_store[key][i] += self.step_store[key][i] self.step_store = self.get_empty_store() def get_average_attention(self): average_attention = { key: [item / self.cur_step for item in self.attention_store[key]] for key in self.attention_store } return average_attention def reset(self): super(AttentionStore, self).reset() self.step_store = self.get_empty_store() self.attention_store = {} def __init__(self): super(AttentionStore, self).__init__() self.step_store = self.get_empty_store() self.attention_store = {} class AttentionControlEdit(AttentionStore, abc.ABC): def step_callback(self, x_t): if self.local_blend is not None: x_t = self.local_blend(x_t, self.attention_store) return x_t def replace_self_attention(self, attn_base, att_replace): if att_replace.shape[2] <= 16**2: return attn_base.unsqueeze(0).expand(att_replace.shape[0], *attn_base.shape) else: return att_replace @abc.abstractmethod def replace_cross_attention(self, attn_base, att_replace): raise NotImplementedError def forward(self, attn, is_cross: bool, place_in_unet: str): super(AttentionControlEdit, self).forward(attn, is_cross, place_in_unet) if is_cross or (self.num_self_replace[0] <= self.cur_step < self.num_self_replace[1]): h = attn.shape[0] // (self.batch_size) attn = attn.reshape(self.batch_size, h, *attn.shape[1:]) attn_base, attn_repalce = attn[0], attn[1:] if is_cross: alpha_words = self.cross_replace_alpha[self.cur_step] attn_repalce_new = self.replace_cross_attention( attn_base, attn_repalce) * alpha_words + ( 1 - alpha_words) * attn_repalce attn[1:] = attn_repalce_new else: attn[1:] = self.replace_self_attention(attn_base, attn_repalce) attn = attn.reshape(self.batch_size * h, *attn.shape[2:]) return attn def __init__(self, prompts, num_steps: int, cross_replace_steps: Union[float, Tuple[float, float], Dict[str, Tuple[float, float]]], self_replace_steps: Union[float, Tuple[float, float]], local_blend: Optional[LocalBlend], model): super(AttentionControlEdit, self).__init__() self.batch_size = len(prompts) self.cross_replace_alpha = ptp_utils.get_time_words_attention_alpha( prompts, num_steps, cross_replace_steps, model.tokenizer).to(model.device) if type(self_replace_steps) is float: self_replace_steps = 0, self_replace_steps self.num_self_replace = int(num_steps * self_replace_steps[0]), int( num_steps * self_replace_steps[1]) self.local_blend = local_blend class AttentionReplace(AttentionControlEdit): def replace_cross_attention(self, attn_base, att_replace): return torch.einsum('hpw,bwn->bhpn', attn_base, self.mapper) def __init__(self, prompts, num_steps: int, cross_replace_steps: float, self_replace_steps: float, local_blend: Optional[LocalBlend] = None, model=None): super(AttentionReplace, self).__init__( prompts, num_steps, cross_replace_steps, self_replace_steps, local_blend, model=model) self.mapper = seq_aligner.get_replacement_mapper( prompts, model.tokenizer).to(model.device) class AttentionRefine(AttentionControlEdit): def replace_cross_attention(self, attn_base, att_replace): attn_base_replace = attn_base[:, :, self.mapper].permute(2, 0, 1, 3) attn_replace = attn_base_replace * self.alphas + att_replace * ( 1 - self.alphas) return attn_replace def __init__(self, prompts, num_steps: int, cross_replace_steps: float, self_replace_steps: float, local_blend: Optional[LocalBlend] = None, model=None): super(AttentionRefine, self).__init__( prompts, num_steps, cross_replace_steps, self_replace_steps, local_blend, model=model) self.mapper, alphas = seq_aligner.get_refinement_mapper( prompts, model.tokenizer) self.mapper, alphas = self.mapper.to(model.device), alphas.to( model.device) self.alphas = alphas.reshape(alphas.shape[0], 1, 1, alphas.shape[1]) class AttentionReweight(AttentionControlEdit): def replace_cross_attention(self, attn_base, att_replace): if self.prev_controller is not None: attn_base = self.prev_controller.replace_cross_attention( attn_base, att_replace) attn_replace = attn_base[None, :, :, :] * self.equalizer[:, None, None, :] return attn_replace def __init__(self, prompts, num_steps: int, cross_replace_steps: float, self_replace_steps: float, equalizer, local_blend: Optional[LocalBlend] = None, controller: Optional[AttentionControlEdit] = None, model=None): super(AttentionReweight, self).__init__( prompts, num_steps, cross_replace_steps, self_replace_steps, local_blend, model=model) self.equalizer = equalizer.to(model.device) self.prev_controller = controller def get_equalizer(text: str, word_select: Union[int, Tuple[int, ...]], values: Union[List[float], Tuple[float, ...]], tokenizer=None): if type(word_select) is int or type(word_select) is str: word_select = (word_select, ) equalizer = torch.ones(len(values), 77) values = torch.tensor(values, dtype=torch.float32) for word in word_select: inds = ptp_utils.get_word_inds(text, word, tokenizer) equalizer[:, inds] = values return equalizer def aggregate_attention(attention_store: AttentionStore, res: int, from_where: List[str], is_cross: bool, select: int, prompts=None): out = [] attention_maps = attention_store.get_average_attention() num_pixels = res**2 for location in from_where: for item in attention_maps[ f"{location}_{'cross' if is_cross else 'self'}"]: if item.shape[1] == num_pixels: cross_maps = item.reshape( len(prompts), -1, res, res, item.shape[-1])[select] out.append(cross_maps) out = torch.cat(out, dim=0) out = out.sum(0) / out.shape[0] return out.cpu() def show_cross_attention(attention_store: AttentionStore, res: int, from_where: List[str], select: int = 0, prompts=None, tokenizer=None): tokens = tokenizer.encode(prompts[select]) decoder = tokenizer.decode attention_maps = aggregate_attention(attention_store, res, from_where, True, select, prompts) images = [] for i in range(len(tokens)): image = attention_maps[:, :, i] image = 255 * image / image.max() image = image.unsqueeze(-1).expand(*image.shape, 3) image = image.numpy().astype(np.uint8) image = np.array(Image.fromarray(image).resize((256, 256))) image = ptp_utils.text_under_image(image, decoder(int(tokens[i]))) images.append(image) return (ptp_utils.view_images(np.stack(images, axis=0))) def show_self_attention_comp(attention_store: AttentionStore, res: int, from_where: List[str], max_com=10, select: int = 0): attention_maps = aggregate_attention(attention_store, res, from_where, False, select).numpy().reshape( (res**2, res**2)) u, s, vh = np.linalg.svd(attention_maps - np.mean(attention_maps, axis=1, keepdims=True)) images = [] for i in range(max_com): image = vh[i].reshape(res, res) image = image - image.min() image = 255 * image / image.max() image = np.repeat( np.expand_dims(image, axis=2), 3, axis=2).astype(np.uint8) image = Image.fromarray(image).resize((256, 256)) image = np.array(image) images.append(image) ptp_utils.view_images(np.concatenate(images, axis=1)) def run_and_display(model, prompts, controller, latent=None, run_baseline=False, generator=None): if run_baseline: print('w.o. prompt-to-prompt') images, latent = run_and_display( model, prompts, EmptyControl(), latent=latent, run_baseline=False, generator=generator) print('with prompt-to-prompt') images, x_t = ptp_utils.text2image_ld ================================================ FILE: projects/prompt_to_prompt/models/ptp_utils.py ================================================ """This code was originally taken from https://github.com/google/prompt-to- prompt.""" # Copyright 2022 Google LLC # # 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. from typing import Dict, List, Optional, Tuple, Union import cv2 import numpy as np import torch from IPython.display import display from PIL import Image from tqdm import tqdm def tensor_to_nparray(image: torch.Tensor): image = (image / 2 + 0.5).clamp(0, 1) image = image.detach().cpu().permute(0, 2, 3, 1).numpy()[0] image = (image * 255).astype(np.uint8) return image def text_under_image(image: np.ndarray, text: str, text_color: Tuple[int, int, int] = (0, 0, 0)): h, w, c = image.shape offset = int(h * .2) img = np.ones((h + offset, w, c), dtype=np.uint8) * 255 font = cv2.FONT_HERSHEY_SIMPLEX img[:h] = image textsize = cv2.getTextSize(text, font, 1, 2)[0] text_x, text_y = (w - textsize[0]) // 2, h + offset - textsize[1] // 2 cv2.putText(img, text, (text_x, text_y), font, 1, text_color, 2) return img def view_images(images, num_rows=1, offset_ratio=0.02): if type(images) is list: num_empty = len(images) % num_rows elif images.ndim == 4: num_empty = images.shape[0] % num_rows else: images = [images] num_empty = 0 empty_images = np.ones(images[0].shape, dtype=np.uint8) * 255 images = [image.astype(np.uint8) for image in images] + [empty_images] * num_empty num_items = len(images) h, w, c = images[0].shape offset = int(h * offset_ratio) num_cols = num_items // num_rows image_ = np.ones( (h * num_rows + offset * (num_rows - 1), w * num_cols + offset * (num_cols - 1), 3), dtype=np.uint8) * 255 for i in range(num_rows): for j in range(num_cols): image_[i * (h + offset):i * (h + offset) + h:, j * (w + offset):j * (w + offset) + w] = images[i * num_cols + j] pil_img = Image.fromarray(image_) display(pil_img) # return pil_img def diffusion_step(model, controller, latents, context, t, guidance_scale, low_resource=False): if low_resource: noise_pred_uncond = model.unet( latents, t, encoder_hidden_states=context[0])['sample'] noise_prediction_text = model.unet( latents, t, encoder_hidden_states=context[1])['sample'] else: latents_input = torch.cat([latents] * 2) noise_pred = model.unet( latents_input, t, encoder_hidden_states=context)['sample'] noise_pred_uncond, noise_prediction_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + guidance_scale * ( noise_prediction_text - noise_pred_uncond) latents = model.scheduler.step(noise_pred, t, latents)['prev_sample'] latents = controller.step_callback(latents) return latents def latent2image(vae, latents): latents = 1 / 0.18215 * latents image = vae.decode(latents)['sample'] image = (image / 2 + 0.5).clamp(0, 1) image = image.cpu().permute(0, 2, 3, 1).numpy() image = (image * 255).astype(np.uint8) return image def init_latent(latent, model, height, width, generator, batch_size): if latent is None: latent = torch.randn( (1, model.unet.in_channels, height // 8, width // 8), generator=generator, ) latents = latent.expand(batch_size, model.unet.in_channels, height // 8, width // 8).to(model.device) return latent, latents @torch.no_grad() def text2image_ldm_stable(model, prompt: List[str], controller, num_inference_steps: int = 50, guidance_scale: Optional[float] = 7.5, generator: Optional[torch.Generator] = None, latent: Optional[torch.FloatTensor] = None, uncond_embeddings=None, start_time=50, return_type='image'): batch_size = len(prompt) register_attention_control(model, controller) height = width = 512 text_input = model.tokenizer( prompt, padding='max_length', max_length=model.tokenizer.model_max_length, truncation=True, return_tensors='pt', ) text_embeddings = model.text_encoder( text_input.input_ids.to(model.device))[0] max_length = text_input.input_ids.shape[-1] if uncond_embeddings is None: uncond_input = model.tokenizer( [''] * batch_size, padding='max_length', max_length=max_length, return_tensors='pt') uncond_embeddings_ = model.text_encoder( uncond_input.input_ids.to(model.device))[0] else: uncond_embeddings_ = None latent, latents = init_latent(latent, model, height, width, generator, batch_size) model.scheduler.set_timesteps(num_inference_steps) for i, t in enumerate(tqdm(model.scheduler.timesteps[-start_time:])): if uncond_embeddings_ is None: context = torch.cat([ uncond_embeddings[i].expand(*text_embeddings.shape), text_embeddings ]) else: context = torch.cat([uncond_embeddings_, text_embeddings]) latents = diffusion_step( model, controller, latents, context, t, guidance_scale, low_resource=False) if return_type == 'image': image = latent2image(model.vae, latents) else: image = latents return image, latent def register_attention_control(model, controller): def ca_forward(self, place_in_unet): to_out = self.to_out if type(to_out) is torch.nn.modules.container.ModuleList: to_out = self.to_out[0] else: to_out = self.to_out def forward(x, encoder_hidden_states=None, attention_mask=None): batch_size, sequence_length, dim = x.shape h = self.heads q = self.to_q(x) is_cross = encoder_hidden_states is not None encoder_hidden_states = encoder_hidden_states if is_cross else x k = self.to_k(encoder_hidden_states) v = self.to_v(encoder_hidden_states) q = self.head_to_batch_dim(q) k = self.head_to_batch_dim(k) v = self.head_to_batch_dim(v) sim = torch.einsum('b i d, b j d -> b i j', q, k) * self.scale if attention_mask is not None: attention_mask = attention_mask.reshape(batch_size, -1) max_neg_value = -torch.finfo(sim.dtype).max attention_mask = attention_mask[:, None, :].repeat(h, 1, 1) sim.masked_fill_(~attention_mask, max_neg_value) # attention, what we cannot get enough of attn = sim.softmax(dim=-1) attn = controller(attn, is_cross, place_in_unet) out = torch.einsum('b i j, b j d -> b i d', attn, v) out = self.batch_to_head_dim(out) return to_out(out) return forward class DummyController: def __call__(self, *args): return args[0] def __init__(self): self.num_att_layers = 0 if controller is None: controller = DummyController() # def register_recr(net_, count, place_in_unet): # if net_.__class__.__name__ == 'CrossAttention': # net_.forward = ca_forward(net_, place_in_unet) # return count + 1 # elif hasattr(net_, 'children'): # for net__ in net_.children(): # count = register_recr(net__, count, place_in_unet) # return count # cross_att_count = 0 # sub_nets = model.unet.named_children() # for net in sub_nets: # if "down" in net[0]: # cross_att_count += register_recr(net[1], 0, "down") # elif "up" in net[0]: # cross_att_count += register_recr(net[1], 0, "up") # elif "mid" in net[0]: # cross_att_count += register_recr(net[1], 0, "mid") # controller.num_att_layers = cross_att_count def register_recr(net_name: str, net_, count, place_in_unet): if net_name.endswith('attn2') or net_name.endswith('attn1'): net_.forward = ca_forward(net_, place_in_unet) return count + 1 return count cross_att_count = 0 sub_nets = model.unet.named_modules() for net in sub_nets: if 'down' in net[0]: cross_att_count += register_recr(net[0], net[1], 0, 'down') elif 'up' in net[0]: cross_att_count += register_recr(net[0], net[1], 0, 'up') elif 'mid' in net[0]: cross_att_count += register_recr(net[0], net[1], 0, 'mid') controller.num_att_layers = cross_att_count def get_word_inds(text: str, word_place: int, tokenizer): split_text = text.split(' ') if type(word_place) is str: word_place = [ i for i, word in enumerate(split_text) if word_place == word ] elif type(word_place) is int: word_place = [word_place] out = [] if len(word_place) > 0: words_encode = [ tokenizer.decode([item]).strip('#') for item in tokenizer.encode(text)['input_ids'] ][1:-1] cur_len, ptr = 0, 0 for i in range(len(words_encode)): cur_len += len(words_encode[i]) if ptr in word_place: out.append(i + 1) if cur_len >= len(split_text[ptr]): ptr += 1 cur_len = 0 return np.array(out) def update_alpha_time_word(alpha, bounds: Union[float, Tuple[float, float]], prompt_ind: int, word_inds: Optional[torch.Tensor] = None): if type(bounds) is float: bounds = 0, bounds start, end = int(bounds[0] * alpha.shape[0]), int(bounds[1] * alpha.shape[0]) if word_inds is None: word_inds = torch.arange(alpha.shape[2]) alpha[:start, prompt_ind, word_inds] = 0 alpha[start:end, prompt_ind, word_inds] = 1 alpha[end:, prompt_ind, word_inds] = 0 return alpha def get_time_words_attention_alpha( prompts, num_steps, cross_replace_steps: Union[float, Dict[str, Tuple[float, float]]], tokenizer, max_num_words=77): if type(cross_replace_steps) is not dict: cross_replace_steps = {'default_': cross_replace_steps} if 'default_' not in cross_replace_steps: cross_replace_steps['default_'] = (0., 1.) alpha_time_words = torch.zeros(num_steps + 1, len(prompts) - 1, max_num_words) for i in range(len(prompts) - 1): alpha_time_words = update_alpha_time_word( alpha_time_words, cross_replace_steps['default_'], i) for key, item in cross_replace_steps.items(): if key != 'default_': inds = [ get_word_inds(prompts[i], key, tokenizer) for i in range(1, len(prompts)) ] for i, ind in enumerate(inds): if len(ind) > 0: alpha_time_words = update_alpha_time_word( alpha_time_words, item, i, ind) alpha_time_words = alpha_time_words.reshape(num_steps + 1, len(prompts) - 1, 1, 1, max_num_words) return alpha_time_words def load_512(image_path, left=0, right=0, top=0, bottom=0, device=None): if type(image_path) is str: image = np.array(Image.open(image_path).convert('RGB'))[:, :, :3] else: image = image_path h, w, c = image.shape left = min(left, w - 1) right = min(right, w - left - 1) top = min(top, h - left - 1) bottom = min(bottom, h - top - 1) image = image[top:h - bottom, left:w - right] h, w, c = image.shape if h < w: offset = (w - h) // 2 image = image[:, offset:offset + h] elif w < h: offset = (h - w) // 2 image = image[offset:offset + w] image = np.array(Image.fromarray(image).resize((512, 512))) image = torch.from_numpy(image).float() / 127.5 - 1 image = image.permute(2, 0, 1).unsqueeze(0).to(device) return image ================================================ FILE: projects/prompt_to_prompt/models/seq_aligner.py ================================================ """This code was originally taken from https://github.com/google/prompt-to- prompt.""" import numpy as np # Copyright 2022 Google LLC # # 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 torch class ScoreParams: def __init__(self, gap, match, mismatch): self.gap = gap self.match = match self.mismatch = mismatch def mis_match_char(self, x, y): if x != y: return self.mismatch else: return self.match def get_matrix(size_x, size_y, gap): matrix = [] for i in range(size_x + 1): sub_matrix = [] for j in range(size_y + 1): sub_matrix.append(0) matrix.append(sub_matrix) for j in range(1, size_y + 1): matrix[0][j] = j * gap for i in range(1, size_x + 1): matrix[i][0] = i * gap return np.array(matrix) # def get_matrix(size_x, size_y, gap): # matrix = np.zeros((size_x + 1, size_y + 1), dtype=np.int32) # matrix[0, 1:] = (np.arange(size_y) + 1) * gap # matrix[1:, 0] = (np.arange(size_x) + 1) * gap # return matrix def get_traceback_matrix(size_x, size_y): matrix = np.zeros((size_x + 1, size_y + 1), dtype=np.int32) matrix[0, 1:] = 1 matrix[1:, 0] = 2 matrix[0, 0] = 4 return matrix def global_align(x, y, score): matrix = get_matrix(len(x), len(y), score.gap) trace_back = get_traceback_matrix(len(x), len(y)) for i in range(1, len(x) + 1): for j in range(1, len(y) + 1): left = matrix[i, j - 1] + score.gap up = matrix[i - 1, j] + score.gap diag = matrix[i - 1, j - 1] + score.mis_match_char( x[i - 1], y[j - 1]) matrix[i, j] = max(left, up, diag) if matrix[i, j] == left: trace_back[i, j] = 1 elif matrix[i, j] == up: trace_back[i, j] = 2 else: trace_back[i, j] = 3 return matrix, trace_back def get_aligned_sequences(x, y, trace_back): x_seq = [] y_seq = [] i = len(x) j = len(y) mapper_y_to_x = [] while i > 0 or j > 0: if trace_back[i, j] == 3: x_seq.append(x[i - 1]) y_seq.append(y[j - 1]) i = i - 1 j = j - 1 mapper_y_to_x.append((j, i)) elif trace_back[i][j] == 1: x_seq.append('-') y_seq.append(y[j - 1]) j = j - 1 mapper_y_to_x.append((j, -1)) elif trace_back[i][j] == 2: x_seq.append(x[i - 1]) y_seq.append('-') i = i - 1 elif trace_back[i][j] == 4: break mapper_y_to_x.reverse() return x_seq, y_seq, torch.tensor(mapper_y_to_x, dtype=torch.int64) def get_mapper(x: str, y: str, tokenizer, max_len=77): x_seq = tokenizer.encode(x)['input_ids'] y_seq = tokenizer.encode(y)['input_ids'] score = ScoreParams(0, 1, -1) matrix, trace_back = global_align(x_seq, y_seq, score) mapper_base = get_aligned_sequences(x_seq, y_seq, trace_back)[-1] alphas = torch.ones(max_len) alphas[:mapper_base.shape[0]] = mapper_base[:, 1].ne(-1).float() mapper = torch.zeros(max_len, dtype=torch.int64) mapper[:mapper_base.shape[0]] = mapper_base[:, 1] mapper[mapper_base.shape[0]:] = len(y_seq) + torch.arange(max_len - len(y_seq)) return mapper, alphas def get_refinement_mapper(prompts, tokenizer, max_len=77): x_seq = prompts[0] mappers, alphas = [], [] for i in range(1, len(prompts)): mapper, alpha = get_mapper(x_seq, prompts[i], tokenizer, max_len) mappers.append(mapper) alphas.append(alpha) return torch.stack(mappers), torch.stack(alphas) def get_word_inds(text: str, word_place: int, tokenizer): split_text = text.split(' ') if type(word_place) is str: word_place = [ i for i, word in enumerate(split_text) if word_place == word ] elif type(word_place) is int: word_place = [word_place] out = [] if len(word_place) > 0: words_encode = [ tokenizer.decode([item]).strip('#') for item in tokenizer.encode(text)['input_ids'] ][1:-1] cur_len, ptr = 0, 0 for i in range(len(words_encode)): cur_len += len(words_encode[i]) if ptr in word_place: out.append(i + 1) if cur_len >= len(split_text[ptr]): ptr += 1 cur_len = 0 return np.array(out) def get_replacement_mapper_(x: str, y: str, tokenizer, max_len=77): words_x = x.split(' ') words_y = y.split(' ') if len(words_x) != len(words_y): raise ValueError() inds_replace = [i for i in range(len(words_y)) if words_y[i] != words_x[i]] inds_source = [get_word_inds(x, i, tokenizer) for i in inds_replace] inds_target = [get_word_inds(y, i, tokenizer) for i in inds_replace] mapper = np.zeros((max_len, max_len)) i = j = 0 cur_inds = 0 while i < max_len and j < max_len: if cur_inds < len(inds_source) and inds_source[cur_inds][0] == i: inds_source_, inds_target_ = inds_source[cur_inds], inds_target[ cur_inds] if len(inds_source_) == len(inds_target_): mapper[inds_source_, inds_target_] = 1 else: ratio = 1 / len(inds_target_) for i_t in inds_target_: mapper[inds_source_, i_t] = ratio cur_inds += 1 i += len(inds_source_) j += len(inds_target_) elif cur_inds < len(inds_source): mapper[i, j] = 1 i += 1 j += 1 else: mapper[j, j] = 1 i += 1 j += 1 return torch.from_numpy(mapper).float() def get_replacement_mapper(prompts, tokenizer, max_len=77): x_seq = prompts[0] mappers = [] for i in range(1, len(prompts)): mapper = get_replacement_mapper_(x_seq, prompts[i], tokenizer, max_len) mappers.append(mapper) return torch.stack(mappers) ================================================ FILE: projects/prompt_to_prompt/visualize.ipynb ================================================ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### A Walkthrough of DDIM inversion and Null-text inversion and Prompt-to-Prompt editing" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/mnt/wsl/PHYSICALDRIVE4/htr/mmagic\n" ] } ], "source": [ "# cd into the mmagic directory to make sure mmagic models work fine!!\n", "%cd ../.." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Load Stable Diffusion from MMagic" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/ssd2/priv/miniconda3/envs/mmagic/lib/python3.8/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n", "Cannot initialize model with low cpu memory usage because `accelerate` was not found in the environment. Defaulting to `low_cpu_mem_usage=False`. It is strongly recommended to install `accelerate` for faster and less memory-intense model loading. You can do so with: \n", "```\n", "pip install accelerate\n", "```\n", ".\n", "Cannot initialize model with low cpu memory usage because `accelerate` was not found in the environment. Defaulting to `low_cpu_mem_usage=False`. It is strongly recommended to install `accelerate` for faster and less memory-intense model loading. You can do so with: \n", "```\n", "pip install accelerate\n", "```\n", ".\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "06/17 13:45:38 - mmengine - INFO - Creating runwayml/stable-diffusion-v1-5 by 'HuggingFace'\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/mnt/wsl/PHYSICALDRIVE4/htr/mmagic/mmagic/models/archs/wrapper.py:149: FutureWarning: Accessing config attribute `block_out_channels` directly via 'AutoencoderKL' object attribute is deprecated. Please access 'block_out_channels' over 'AutoencoderKL's config object instead, e.g. 'unet.config.block_out_channels'.\n", " return getattr(self.model, name)\n" ] } ], "source": [ "from mmengine import MODELS, Config\n", "from mmengine.registry import init_default_scope\n", "\n", "init_default_scope('mmagic')\n", "\n", "config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py'\n", "config = Config.fromfile(config).copy()\n", "# change the 'pretrained_model_path' if you have downloaded the weights manually\n", "# config.model.unet.from_pretrained = '/path/to/your/stable-diffusion-v1-5'\n", "# config.model.vae.from_pretrained = '/path/to/your/stable-diffusion-v1-5'\n", "\n", "StableDiffuser = MODELS.build(config.model)\n", "StableDiffuser = StableDiffuser.to('cuda')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### VAE vs DDIM Inversion vs Null-Text Inversion\n", "Diffusion's inversion basically means you put an image (with or without a prompt) into a method and it will return a latent code which can be later turned back to a image with high simmilarity as the original one. Of course we want this latent code for an editing purpose, that's also why we always implement inversion methods together with the editing methods.\n", "\n", "Let's first see how ddim inversion and null-text inversion works on the same image and prompt. Note here we put the result of vae as the upper bound of the inversion result. (For further knowledge please read the original paper of null-text inversion proposed by google :))" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "#### 1. VAE reconstruction as the standard result\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from models import ptp_utils\n", "import torch\n", "import mmcv\n", "\n", "image = mmcv.imread('https://github.com/open-mmlab/mmagic/assets/12782558/c851dcf8-bcfa-424f-9eeb-d01a48ea7127', channel_order='rgb')\n", "prompt = \"a cat sitting next to a mirror\"\n", "# using vae to reconstruct the image\n", "image_tensor = ptp_utils.load_512(image).to('cuda')\n", "vae = StableDiffuser.vae\n", "with torch.no_grad():\n", " vae_rec = vae(image_tensor, return_dict=False)[0]\n", "ptp_utils.view_images(ptp_utils.tensor_to_nparray(vae_rec))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2. Use ddim inversion to invert the image" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/mnt/wsl/PHYSICALDRIVE4/htr/mmagic/mmagic/models/archs/wrapper.py:149: FutureWarning: Accessing config attribute `in_channels` directly via 'UNet2DConditionModel' object attribute is deprecated. Please access 'in_channels' over 'UNet2DConditionModel's config object instead, e.g. 'unet.config.in_channels'.\n", " return getattr(self.model, name)\n", "100%|██████████| 50/50 [00:07<00:00, 6.57it/s]\n" ] }, { "data": { "image/png": "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IlIgsceY2TDyNkuM+xvskzU6yRbcqb4FfDMyOdj7ACuI1u7CJEb87a/KwH7DCTh9X2HbVeP1rclRkXbvtZ92tt80uM+mR2bJMuIHSu+drKgPDLIbd0MjHDoANmECojYAM2ATZiRqNHQce2cQYO6IjUcGQO4dEcdxu15vNuv1bru9v71drzf3t9f36/thPgjAejMCC4rsdtvZMNuuRxBss+H49PTo9OTm9vrll1999qc/vb68nwv1DkfPnggMl69fy2Z7fXX99u7y7s0bWMzu1tv79fju9h3NhpurN0jD9fXbETs2/st/928uLh6z4PLo5Prq7Xe/+8NPHn/3r/76r69vrw6u312+ej2shgHberf9/LPPduPm/MnZu5dv1uv1uN1SHw/Ozl9/8+785GYA3G7Gr796w7M5DFsAFqd34BNpAOYvatpa34BIjjPvBdECh6+dS909UGm4B4C2UKAz43wWAEsFypahTImVxGdn7d4/JBHGhvqgY3SfAhSbefSHb1nBg9lhgBBB8wfxyRGAKVopLlmF0Hf/9xKmH4aguyoJcOJqzudBA+kwoD1jdxpwjA8ll0MLXNNihfXJazETp4sESotDCJk2od7n4vTc2Jc+t9EF6zesoS/mcSxBjBgDFhV09TCJRA0jlhSILrXUnEDEdmARM7jIKtCNTQRE8qHbwrrRnZAAszMOAQCj5ylzDwvxIWhGKShKzAz51TE2hIjCv3fbL8ZlCtljj0StOZirWKAE150KLFl7RNNCV5IoedwyWpIOFkAt5d8834RWWFHgfWFO4IQqQ1z4EPzm13tx+X2hKOT//gOj83tu7JQksrnf0BeLox5MXDA2qYJxFMMWdrO20nRXH+09dsbtblg07kwD8ThS05U+hNCo+xNDdHsWYem83WyEeRzH9fp+vd5ut/e77a6P43a722y2s9n83bub80fns8Xq5t3l5fXVwdHBarm8u7ufzeazYf746dPjg5O7t2+/+ptfvHnxZiObNszOLp790X/4Tw7nh69fvzqC4e7m8vbyzfruenu1W4/jzXrbZo3vd4R9sVq8fvN2OD54/eWLk9OzL375q6Ozk6vbm3HXX719/c3XXw6L1fHpyW/94LdevX7+8vmrF7vnvBu3m+1yNR+v7o9Xi+99+ukc6fOvvtiNcHp2/OTxRWfufff63WXHeac5wlpXdhAiSNxw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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from models.ptp import EmptyControl\n", "from inversions.ddim_inversion import DDIMInversion\n", "\n", "ddim_inverter = DDIMInversion(StableDiffuser)\n", "ddim_inverter.init_prompt(prompt)\n", "ddim_latents = ddim_inverter.ddim_inversion(image_tensor)\n", "x_t = ddim_latents[-1]\n", "ddim_rec, _ = ptp_utils.text2image_ldm_stable(StableDiffuser, [prompt], EmptyControl(), latent=x_t)\n", "ptp_utils.view_images(ddim_rec)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2. Use null-text inversion to invert the image\n", "Note null-text inversion uses the same inversion process as ddim inversion but additionally optimizes the **unconditional embedding** to make the result more similar to the original image." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/500 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from inversions.null_text_inversion import NullTextInversion\n", "null_inverter = NullTextInversion(StableDiffuser)\n", "null_inverter.init_prompt(prompt)\n", "uncond_embeddings = null_inverter.null_optimization(ddim_latents, num_inner_steps=10, epsilon=1e-5)\n", "null_text_rec, _ = ptp_utils.text2image_ldm_stable(StableDiffuser, [prompt], EmptyControl(), latent=x_t, uncond_embeddings=uncond_embeddings)\n", "ptp_utils.view_images(null_text_rec)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 4. Conclusion\n", "Let's put all these results together and it's obvious to see that null-text inversion is better than ddim inversion." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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39OhPzz6J0jls+We8Q6ef1uMLyTbcO99rK0FDt5prbWM4kEbDri2OZAlanaKJJBADsP07raISluubl++evOLu3e/uXz8RmkSBNwAIFWAUD7Unmw/3HZduUKS3HafO7pDJIfkp6dIT+HOJ03yiEra+FQ7EvXVLqJoF+P6+S+++sWf3Hz5+f1fffObX//N5en+tODmasWr1198/bVcvXDKzc3tzc3tq5cvn+71m+++AfX6dm1L62N8eP/hdD3ubt/96z/9f//z/+X/8s//r/+3f/P/+L/z6YNLhztmTHWsH5sbFLZx9rwcZetQO7H7gyHjRzg5rfGEWlCoC7C3kR5CwWdyN7EkKxGspSt2zoMIlv/qVvqGnpobJIQIpr4Z0s6QOHRPjY3Ieyl1d/QacmtrJabjAQcoxIioqCphmfudPqElf6v/lI569oqvYjDamTKHxjE5j1B8f9G4pREI2cxokqISXoyqIChTHdG1DbgxSikSx3VA3F1cqDnzgTN76QCoEYPJMM82ADLjvTz4uXIB0GhiQ4i2snCEInWM5PWbYQuILACMCoi4gVxrIamMXmkPSnVrrcXKR+wQaTBRmkU3mDr8crls2waHNm2tLeuynq5IqjRViQhiWHCHi5mBRtKGReww92G4M4p93EblmsIuCorpryodvKQinERKTKaLDU2EtNQLgD3FEwg1LLvhEj8gDQNAuEl1HvZ6nGznr4RoGGKR5IqUWbcSZTIheCH8B1OUZ893P34+Q+qrsAVzTXYdsau9ONGZtXIcK7SmAiwHxkHNg3tYnDpFNjNY9TXZf1OuAXcPIM5v4AEzhigl5J7hn1cMMr2cuHycrPn+1F6eDpa5zYjIkyQrYybn8QHzbsob8RnsIUrRowEkooWDvczFCMbcjvpR+Kh79noPxxhVNhbZERud8L5d3NnW0+u3P7u6vt3648P7z87nu3459/OjwAUulLW1qPHvw0Rk693gNkzgS2veh9kAOdy3vqlKFPddLo/RE4TI444okgpv3UFx8QaaQSgjJxUiiwGys9LXpfURjoWpSrfukZukjzG8Q1S6B5eo+3ARhSNIoc0cbpqURAwGCRGx3mNUMzV63SqerloixoneSULTNtdJMcBVeLF5CG135qr7andL0w9HH92NAUIxUXYADskOUgc9uG6jNjobtV3IER1qwS9FAR1moFbhPpty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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "vae reconstruction -> ddim reconstruction -> null text reconstruction\n" ] } ], "source": [ "ptp_utils.view_images([ptp_utils.tensor_to_nparray(vae_rec), ddim_rec, null_text_rec])\n", "print(\"vae reconstruction -> ddim reconstruction -> null text reconstruction\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Prompt-to-prompt Editing\n", "prompt-to-prompt controls the attention map in diffusion process to edit a user-provided image or generated image. Let's use the example above to see how it works." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Same process as above, we get the noise latent x_t and use new prompt to edit the cat into a dog **while keeping the orther features unchanged**." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import torch\n", "import gc\n", "gc.collect()\n", "torch.cuda.empty_cache()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/50 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ptp_utils.view_images(images)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course ptp can also be used to edit a generated image(no inversion needed).\n", "Three types of attention controller are provided here:\n", "1. AttentionReplace: replace the attention map of the original word with that of new inserted word. (above example)\n", "2. AttentionRefine: extend the prompt with adjective words or something.\n", "3. AttentionReweighting: strengthen or weaken some features' presence in an image" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/50 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ptp_utils.view_images(images)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 50/50 [00:13<00:00, 3.84it/s]\n" ] }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "prompts = [\"a photo of Eiffel Tower\",\n", " \"a photo of Eiffel Tower at night\"]\n", "from models.ptp import AttentionRefine\n", "controller = AttentionRefine(prompts, 50, cross_replace_steps=1.0,\n", " self_replace_steps=.4, model=StableDiffuser)\n", "images, _ = text2image_ldm_stable(StableDiffuser, prompts, controller, latent=None)\n", "ptp_utils.view_images(images)" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " 0%| | 0/50 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "prompts = [\"a blossom sakura tree\"] * 2\n", "\n", "from models.ptp import AttentionReweight, get_equalizer\n", "### pay 3 times more attention to the word \"roses\"\n", "equalizer = get_equalizer(prompts[1], (\"blossom\",), (-3,), StableDiffuser.tokenizer)\n", "controller = AttentionReweight(prompts, 50, cross_replace_steps=.8,\n", " self_replace_steps=.4,\n", " equalizer=equalizer, model=StableDiffuser)\n", "images, _ = text2image_ldm_stable(StableDiffuser, prompts, controller, latent=None)\n", "ptp_utils.view_images(images)" ] } ], "metadata": { "kernelspec": { "display_name": "mmagic", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.16" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: requirements/docs.txt ================================================ docutils==0.16.0 modelindex myst_parser -e git+https://github.com/open-mmlab/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme requests<=2.29.0 sphinx==4.5.0 sphinx-autoapi sphinx-copybutton sphinx-notfound-page sphinx-tabs sphinx_markdown_tables ================================================ FILE: requirements/mminstall.txt ================================================ mmcv>=2.0.0 mmengine>=0.4.0 ================================================ FILE: requirements/optional.txt ================================================ albumentations -e git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1#egg=clip imageio-ffmpeg==0.4.4 mmdet >= 3.0.0 open_clip_torch PyQt5 ================================================ FILE: requirements/readthedocs.txt ================================================ lmdb lpips mmcv >= 2.0.0rc1 mmdet >= 3.0.0 mmengine prettytable Pygments regex scikit-image tabulate titlecase torch torchvision tqdm ================================================ FILE: requirements/runtime.txt ================================================ av av==8.0.3; python_version < '3.7' click # required by mmagic/utils/io_utils.py controlnet_aux diffusers>=0.23.0 einops face-alignment<=1.3.4 facexlib lmdb lpips mediapipe numpy # MMCV depends opencv-python instead of headless, thus we install opencv-python # Due to a bug from upstream, we skip this two version # https://github.com/opencv/opencv-python/issues/602 # https://github.com/opencv/opencv/issues/21366 # It seems to be fixed in https://github.com/opencv/opencv/pull/21382 opencv-python!=4.5.5.62,!=4.5.5.64 pandas # required by mmagic/models/editors/disco_diffusion/guider.py Pillow resize_right tensorboard transformers>=4.27.4 ================================================ FILE: requirements/tests.txt ================================================ albumentations -e git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1#egg=clip controlnet_aux # codecov # flake8 # isort==5.10.1 # onnxruntime # pytest # pytest-runner # yapf coverage < 7.0.0 imageio-ffmpeg==0.4.4 interrogate mmdet >= 3.0.0 pytest transformers>=4.27.4 ================================================ FILE: requirements.txt ================================================ -r requirements/runtime.txt -r requirements/tests.txt -r requirements/optional.txt ================================================ FILE: setup.cfg ================================================ [bdist_wheel] universal=1 [aliases] test=pytest [tool:pytest] testpaths = tests/ [yapf] based_on_style = pep8 blank_line_before_nested_class_or_def = true split_before_expression_after_opening_paren = true split_penalty_import_names=0 SPLIT_PENALTY_AFTER_OPENING_BRACKET=888 [isort] line_length = 79 multi_line_output = 0 extra_standard_library = setuptools known_first_party = mmagic known_third_party = PIL,cv2,lmdb,mmcv,numpy,onnx,onnxruntime,packaging,pymatting,pytest,pytorch_sphinx_theme,requests,scipy,titlecase,torch,torchvision,ts no_lines_before = STDLIB,LOCALFOLDER default_section = THIRDPARTY [flake8] # The E251 check is conflict with yapf in some situation. # See https://github.com/google/yapf/issues/393 extend-ignore = E251 # The F401 check is wrong if the `__all__` variable is modified # in `__init__.py` per-file-ignores = */__init__.py: F401 mmagic/configs/*: F401,F403,F405,E501 ================================================ FILE: setup.py ================================================ import os import os.path as osp import shutil import subprocess import sys import warnings from setuptools import find_packages, setup import torch from torch.utils.cpp_extension import (BuildExtension, CppExtension, CUDAExtension) def readme(): with open('README.md', encoding='utf-8') as f: content = f.read() return content version_file = 'mmagic/version.py' def get_git_hash(): def _minimal_ext_cmd(cmd): # construct minimal environment env = {} for k in ['SYSTEMROOT', 'PATH', 'HOME']: v = os.environ.get(k) if v is not None: env[k] = v # LANGUAGE is used on win32 env['LANGUAGE'] = 'C' env['LANG'] = 'C' env['LC_ALL'] = 'C' out = subprocess.Popen( cmd, stdout=subprocess.PIPE, env=env).communicate()[0] return out try: out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD']) sha = out.strip().decode('ascii') except OSError: sha = 'unknown' return sha def get_hash(): if os.path.exists('.git'): sha = get_git_hash()[:7] elif os.path.exists(version_file): try: from mmagic.version import __version__ sha = __version__.split('+')[-1] except ImportError: raise ImportError('Unable to get git version') else: sha = 'unknown' return sha def get_version(): with open(version_file, 'r') as f: exec(compile(f.read(), version_file, 'exec')) return locals()['__version__'] def parse_requirements(fname='requirements.txt', with_version=True): """Parse the package dependencies listed in a requirements file but strips specific versioning information. Args: fname (str): path to requirements file with_version (bool, default=False): if True include version specs Returns: List[str]: list of requirements items CommandLine: python -c "import setup; print(setup.parse_requirements())" """ import re import sys from os.path import exists require_fpath = fname def parse_line(line): """Parse information from a line in a requirements text file.""" if line.startswith('-r '): # Allow specifying requirements in other files target = line.split(' ')[1] for info in parse_require_file(target): yield info else: info = {'line': line} if line.startswith('-e '): info['package'] = line.split('#egg=')[1] elif '@git+' in line: info['package'] = line else: # Remove versioning from the package pat = '(' + '|'.join(['>=', '<=', '==', '>', '<']) + ')' parts = re.split(pat, line, maxsplit=1) parts = [p.strip() for p in parts] info['package'] = parts[0] if len(parts) > 1: op, rest = parts[1:] if ';' in rest: # Handle platform specific dependencies # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies version, platform_deps = map(str.strip, rest.split(';')) info['platform_deps'] = platform_deps else: version = rest # NOQA info['version'] = (op, version) yield info def parse_require_file(fpath): with open(fpath, 'r') as f: for line in f.readlines(): line = line.strip() if line and not line.startswith('#'): for info in parse_line(line): yield info def gen_packages_items(): if exists(require_fpath): for info in parse_require_file(require_fpath): parts = [info['package']] if with_version and 'version' in info: parts.extend(info['version']) if not sys.version.startswith('3.4'): # apparently package_deps are broken in 3.4 platform_deps = info.get('platform_deps') if platform_deps is not None: parts.append(';' + platform_deps) item = ''.join(parts) yield item packages = list(gen_packages_items()) return packages def make_cuda_ext(name, module, sources, sources_cuda=[]): define_macros = [] extra_compile_args = {'cxx': []} if torch.cuda.is_available() or os.getenv('FORCE_CUDA', '0') == '1': define_macros += [('WITH_CUDA', None)] extension = CUDAExtension extra_compile_args['nvcc'] = [ '-D__CUDA_NO_HALF_OPERATORS__', '-D__CUDA_NO_HALF_CONVERSIONS__', '-D__CUDA_NO_HALF2_OPERATORS__', ] sources += sources_cuda else: print(f'Compiling {name} without CUDA') extension = CppExtension return extension( name=f'{module}.{name}', sources=[os.path.join(*module.split('.'), p) for p in sources], define_macros=define_macros, extra_compile_args=extra_compile_args) def add_mim_extension(): """Add extra files that are required to support MIM into the package. These files will be added by creating a symlink to the originals if the package is installed in `editable` mode (e.g. pip install -e .), or by copying from the originals otherwise. """ # parse installment mode if 'develop' in sys.argv: # installed by `pip install -e .` mode = 'symlink' elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: # installed by `pip install .` # or create source distribution by `python setup.py sdist` mode = 'copy' else: return filenames = ['tools', 'configs', 'demo', 'model-index.yml'] repo_path = osp.dirname(__file__) mim_path = osp.join(repo_path, 'mmagic', '.mim') os.makedirs(mim_path, exist_ok=True) for filename in filenames: if osp.exists(filename): src_path = osp.join(repo_path, filename) tar_path = osp.join(mim_path, filename) if osp.isfile(tar_path) or osp.islink(tar_path): os.remove(tar_path) elif osp.isdir(tar_path): shutil.rmtree(tar_path) if mode == 'symlink': src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) try: os.symlink(src_relpath, tar_path) except OSError: # Creating a symbolic link on windows may raise an # `OSError: [WinError 1314]` due to privilege. If # the error happens, the src file will be copied mode = 'copy' warnings.warn( f'Failed to create a symbolic link for {src_relpath}, ' f'and it will be copied to {tar_path}') else: continue if mode == 'copy': if osp.isfile(src_path): shutil.copyfile(src_path, tar_path) elif osp.isdir(src_path): shutil.copytree(src_path, tar_path) else: warnings.warn(f'Cannot copy file {src_path}.') else: raise ValueError(f'Invalid mode {mode}') if __name__ == '__main__': add_mim_extension() setup( name='mmagic', version=get_version(), description='OpenMMLab Multimodal Advanced, Generative, and ' 'Intelligent Creation Toolbox', long_description=readme(), long_description_content_type='text/markdown', maintainer='MMagic Contributors', maintainer_email='openmmlab@gmail.com', keywords='computer vision, super resolution, video interpolation, ' 'inpainting, matting, SISR, RefSR, VSR, GAN, VFI', url='https://github.com/open-mmlab/mmagic', packages=find_packages(exclude=('configs', 'tools', 'demo')), include_package_data=True, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Education', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Topic :: Scientific/Engineering :: Artificial Intelligence', 'Topic :: Scientific/Engineering :: Image Processing', ], license='Apache License 2.0', install_requires=parse_requirements('requirements/runtime.txt'), cmdclass={'build_ext': BuildExtension}, extras_require={ 'all': parse_requirements('requirements.txt'), 'tests': parse_requirements('requirements/tests.txt'), 'mim': parse_requirements('requirements/mminstall.txt'), }, zip_safe=False) ================================================ FILE: tests/configs/aot_test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='AOTInpaintor', train_cfg=dict( disc_step=1, start_iter=0, ), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='AOTEncoderDecoder', encoder=dict(type='AOTEncoder'), decoder=dict(type='AOTDecoder'), dilation_neck=dict( type='AOTBlockNeck', dilation_rates=(1, 2, 4, 8), num_aotblock=8)), disc=dict( type='SoftMaskPatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, with_spectral_norm=True, ), loss_gan=dict( type='GANLoss', gan_type='smgan', loss_weight=0.01, ), loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg19', layer_weights={ '1': 1., '6': 1., '11': 1., '20': 1., '29': 1., }, layer_weights_style={ '8': 1., '17': 1., '26': 1., '31': 1., }, perceptual_weight=0.1, style_weight=250), loss_out_percep=True, loss_l1_valid=dict( type='L1Loss', loss_weight=1., ), loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001), ) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/configs/deepfillv1_test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='DeepFillv1Inpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict(type='DeepFillEncoderDecoder'), disc=dict( type='DeepFillv1Discriminators', global_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=256, fc_in_channels=256 * 16 * 16, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), local_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=512, fc_in_channels=512 * 8 * 8, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2))), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep', 'loss_tv'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type='GANLoss', gan_type='hinge', loss_weight=1, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, ), loss_l1_valid=dict( type='L1Loss', loss_weight=1.0, ), loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg16', layer_weights={ '4': 1., '9': 1., '16': 1., }, perceptual_weight=0.05, style_weight=120, pretrained=('torchvision://vgg16')), loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1, ), loss_gp=dict(type='GradientPenaltyLoss', loss_weight=10.), loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001), train_cfg=dict(disc_step=2, start_iter=0, local_size=(128, 128)), ) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/configs/diffuser_wrapper_cfg/config.json ================================================ { "_class_name": "ControlNetModel", "_diffusers_version": "0.14.0", "act_fn": "silu", "attention_head_dim": 2, "block_out_channels": [ 32 ], "class_embed_type": null, "conditioning_embedding_out_channels": [ 16 ], "controlnet_conditioning_channel_order": "rgb", "cross_attention_dim": 16, "down_block_types": [ "DownBlock2D" ], "downsample_padding": 1, "flip_sin_to_cos": true, "freq_shift": 0, "in_channels": 4, "layers_per_block": 2, "mid_block_scale_factor": 1, "norm_eps": 1e-05, "norm_num_groups": 32, "num_class_embeds": null, "only_cross_attention": false, "projection_class_embeddings_input_dim": null, "resnet_time_scale_shift": "default", "upcast_attention": false, "use_linear_projection": false } ================================================ FILE: tests/configs/gl_test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. input_shape = (256, 256) global_disc_cfg = dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='BN')) local_disc_cfg = dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=5, norm_cfg=dict(type='BN')) model = dict( type='GLInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='GLEncoderDecoder', encoder=dict(type='GLEncoder'), decoder=dict(type='GLDecoder'), dilation_neck=dict(type='GLDilationNeck')), disc=dict( type='GLDiscs', global_disc_cfg=global_disc_cfg, local_disc_cfg=local_disc_cfg), loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ), loss_l1_hole=dict(type='L1Loss', loss_weight=1.0), loss_l1_valid=dict(type='L1Loss', loss_weight=1.0), train_cfg=dict( disc_step=1, start_iter=0, iter_tc=2, iter_td=3, local_size=(128, 128))) model_dirty = dict( type='GLInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='GLEncoderDecoder', encoder=dict(type='GLEncoder'), decoder=dict(type='GLDecoder'), dilation_neck=dict(type='GLDilationNeck')), disc=dict( type='GLDiscs', global_disc_cfg=global_disc_cfg, local_disc_cfg=local_disc_cfg), loss_gan=None, loss_l1_hole=None, loss_l1_valid=None) model_inference = dict( type='GLInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='GLEncoderDecoder', encoder=dict(type='GLEncoder'), decoder=dict(type='GLDecoder'), dilation_neck=dict(type='GLDilationNeck')), disc=dict( type='GLDiscs', global_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='SyncBN'), ), local_disc_cfg=dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=5, norm_cfg=dict(type='SyncBN'), ), ), loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, )) test_pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict( type='LoadMask', mask_mode='bbox', mask_config=dict( max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20, img_shape=input_shape)), dict( type='Crop', keys=['gt'], crop_size=(384, 384), random_crop=True, ), dict( type='Resize', keys=['gt'], scale=input_shape, keep_ratio=False, ), dict(type='GetMaskedImage'), dict(type='PackInputs'), ] def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/configs/one_stage_gl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='OneStageInpaintor', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='GLEncoderDecoder', encoder=dict(type='GLEncoder'), decoder=dict(type='GLDecoder'), dilation_neck=dict(type='GLDilationNeck')), disc=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='BN'), ), loss_gan=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.001, ), loss_gp=dict( type='GradientPenaltyLoss', loss_weight=1., ), loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001), loss_composed_percep=dict( type='PerceptualLoss', layer_weights={'0': 1.}, perceptual_weight=0.1, style_weight=0, ), loss_out_percep=True, loss_l1_hole=dict(type='L1Loss', loss_weight=1.0), loss_l1_valid=dict(type='L1Loss', loss_weight=1.0), loss_tv=dict(type='MaskedTVLoss', loss_weight=0.01), train_cfg=dict(disc_step=1)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/configs/pconv_test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='PConvInpaintor', train_cfg=dict( disc_step=0, start_iter=0, ), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='PConvEncoderDecoder', encoder=dict( type='PConvEncoder', norm_cfg=dict(type='BN', requires_grad=False), norm_eval=True), decoder=dict(type='PConvDecoder', norm_cfg=dict(type='BN'))), disc=None, loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg16', layer_weights={ '4': 1., '9': 1., '16': 1., }, perceptual_weight=0.05, style_weight=120, pretrained=('torchvision://vgg16')), loss_out_percep=True, loss_l1_hole=dict( type='L1Loss', loss_weight=6., ), loss_l1_valid=dict( type='L1Loss', loss_weight=1., ), loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1, )) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/configs/two_stage_test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. model = dict( type='TwoStageInpaintor', disc_input_with_mask=True, train_cfg=dict(disc_step=1, start_iter=0), data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), encdec=dict( type='DeepFillEncoderDecoder', stage1=dict( type='GLEncoderDecoder', encoder=dict( type='DeepFillEncoder', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', conv_type='gated_conv', in_channels=96, channel_factor=0.75, out_act_cfg=dict(type='Tanh'), padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect')), stage2=dict( type='DeepFillRefiner', encoder_attention=dict( type='DeepFillEncoder', encoder_type='stage2_attention', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), encoder_conv=dict( type='DeepFillEncoder', encoder_type='stage2_conv', conv_type='gated_conv', channel_factor=0.75, padding_mode='reflect'), dilation_neck=dict( type='GLDilationNeck', in_channels=96, conv_type='gated_conv', act_cfg=dict(type='ELU'), padding_mode='reflect'), contextual_attention=dict( type='ContextualAttentionNeck', in_channels=96, conv_type='gated_conv', padding_mode='reflect'), decoder=dict( type='DeepFillDecoder', in_channels=192, conv_type='gated_conv', out_act_cfg=dict(type='Tanh'), padding_mode='reflect'))), disc=dict( type='MultiLayerDiscriminator', in_channels=4, max_channels=256, fc_in_channels=None, num_convs=6, norm_cfg=None, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2), with_spectral_norm=True, ), stage1_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep', 'loss_tv'), stage2_loss_type=('loss_l1_hole', 'loss_l1_valid', 'loss_gan'), loss_gan=dict( type='GANLoss', gan_type='hinge', loss_weight=0.1, ), loss_l1_hole=dict( type='L1Loss', loss_weight=1.0, ), loss_l1_valid=dict( type='L1Loss', loss_weight=1.0, ), loss_composed_percep=dict( type='PerceptualLoss', vgg_type='vgg16', layer_weights={ '4': 1., '9': 1., '16': 1., }, perceptual_weight=0.05, style_weight=120, pretrained=('torchvision://vgg16')), loss_tv=dict( type='MaskedTVLoss', loss_weight=0.1, ), loss_disc_shift=dict(type='DiscShiftLoss', loss_weight=0.001), ) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/data/coco/annotations/captions_train2014.json ================================================ { "annotations": [{"image_id": 9, "caption": "a good meal"}] } ================================================ FILE: tests/data/coco/annotations/captions_val2014.json ================================================ { "annotations": [{"image_id": 42, "caption": "a pair of slippers"}] } ================================================ FILE: tests/data/controlnet/prompt.json ================================================ {"source": "source/0.png", "target": "target/0.png", "prompt": "pale golden rod circle with old lace background"} {"source": "source/1.png", "target": "target/1.png", "prompt": "light coral circle with white background"} ================================================ FILE: tests/data/dataset/anno.json ================================================ { "a/1.JPG": [ 1, 2, 3, 4 ], "b/2.jpeg": [ 1, 4, 5, 3 ] } ================================================ FILE: tests/data/dataset/anno.txt ================================================ a/1.JPG 0 b/2.jpeg 1 b/subb/3.jpg 1 ================================================ FILE: tests/data/dataset/c/c.not_support_type ================================================ ================================================ FILE: tests/data/dataset/classes.txt ================================================ bus car ================================================ FILE: tests/data/dataset/wrong.yml ================================================ ================================================ FILE: tests/data/frames/ann1.txt ================================================ sequence_1 sequence_2 ================================================ FILE: tests/data/frames/ann2.txt ================================================ sequence_1/00000000.png sequence_1/00000001.png sequence_2/00000000.png ================================================ FILE: tests/data/frames/ann3.txt ================================================ gt/sequence_1 gt/sequence_2 ================================================ FILE: tests/data/image/train.txt ================================================ baboon.png (480,500,3) /baboon.png (480,500,3) ================================================ FILE: tests/data/inpainting/mask_list.txt ================================================ mask/test.png ================================================ FILE: tests/data/inpainting/mask_list_single_ch.txt ================================================ mask/test_single_ch.png ================================================ FILE: tests/data/lq.lmdb/meta_info.txt ================================================ baboon.png (120,125,3) 1 ================================================ FILE: tests/data/matting_dataset/ann.json ================================================ { "metainfo": { "dataset_type": "test_dataset", "task_name": "test_task" }, "data_list": [ { "alpha_path": "alpha/GT05.jpg", "trimap_path": "trimap/GT05.jpg", "bg_path": "bg/GT26r.jpg", "fg_path": "fg/GT05.jpg", "merged_path": "merged/GT05.jpg" }, { "alpha_path": "alpha/GT05.jpg", "bg_path": "bg/GT26r.jpg", "fg_path": "fg/GT05.jpg" } ] } ================================================ FILE: tests/data/matting_dataset/ann_old.json ================================================ [ { "alpha_path": "alpha/GT05.jpg", "trimap_path": "trimap/GT05.jpg", "bg_path": "bg/GT26r.jpg", "fg_path": "fg/GT05.jpg", "merged_path": "merged/GT05.jpg" }, { "alpha_path": "alpha/GT05.jpg", "bg_path": "bg/GT26r.jpg", "fg_path": "fg/GT05.jpg" } ] ================================================ FILE: tests/data/textual_inversion/imagenet_templates_small.txt ================================================ a photo of a {} a rendering of a {} a cropped photo of the {} the photo of a {} a photo of a clean {} a photo of a dirty {} a dark photo of the {} a photo of my {} a photo of the cool {} a close-up photo of a {} a bright photo of the {} a cropped photo of a {} a photo of the {} a good photo of the {} a photo of one {} a close-up photo of the {} a rendition of the {} a photo of the clean {} a rendition of a {} a photo of a nice {} a good photo of a {} a photo of the nice {} a photo of the small {} a photo of the weird {} a photo of the large {} a photo of a cool {} a photo of a small {} ================================================ FILE: tests/test_apis/test_inferencers/test_base_mmagic_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import pytest from mmagic.apis.inferencers.base_mmagic_inferencer import BaseMMagicInferencer from mmagic.utils import register_all_modules register_all_modules() def test_base_mmagic_inferencer(): with pytest.raises(Exception): BaseMMagicInferencer(1, None) cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'sngan_proj', 'sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py') with pytest.raises(Exception): BaseMMagicInferencer(cfg, 'test') inferencer_instance = BaseMMagicInferencer(cfg, None) extra_parameters = inferencer_instance.get_extra_parameters() assert len(extra_parameters) == 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_colorization_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import unittest import torch from mmagic.apis.inferencers.colorization_inferencer import \ ColorizationInferencer from mmagic.utils import register_all_modules register_all_modules() def test_colorization_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'inst_colorization', 'inst-colorizatioon_full_official_cocostuff-256x256.py') data_path = osp.join( osp.dirname(__file__), '..', '..', 'data', 'unpaired', 'trainA', '1.jpg') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'inst_colorization_result.jpg') inferencer_instance = \ ColorizationInferencer(cfg, None) del inferencer_instance.model.cfg.test_pipeline[1] inferencer_instance.preprocess(img=data_path) preds = torch.rand((1, 3, 256, 256)) result_img = inferencer_instance.visualize(preds=preds) result_img = inferencer_instance.visualize( preds=preds, result_out_dir=result_out_dir) if not torch.cuda.is_available(): # RoI pooling only support in GPU return unittest.skip('test requires GPU and torch+cuda') inferencer_instance(img=data_path) inference_result = inferencer_instance( img=data_path, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.shape == (256, 256, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_conditional_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.conditional_inferencer import \ ConditionalInferencer from mmagic.utils import register_all_modules register_all_modules() def test_conditional_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'sngan_proj', 'sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'conditional_result.png') inferencer_instance = \ ConditionalInferencer(cfg, None, extra_parameters={'sample_model': 'orig'}) inference_result = inferencer_instance(label=1) inference_result = inferencer_instance( label=1, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.shape == (4, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_diffusers_pipeline_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.apis.inferencers.diffusers_pipeline_inferencer import \ DiffusersPipelineInferencer from mmagic.utils import register_all_modules register_all_modules() @pytest.mark.skipif( 'win' in platform.system().lower() or digit_version(TORCH_VERSION) <= digit_version('1.8.1'), reason='skip on windows due to limited RAM' 'and get_submodule requires torch >= 1.9.0') def test_diffusers_pipeline_inferencer(): cfg = dict( model=dict( type='DiffusionPipeline', from_pretrained='google/ddpm-cat-256')) inferencer_instance = DiffusersPipelineInferencer(cfg, None) result = inferencer_instance() assert result[1][0].size == (256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_eg3d_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import shutil import numpy as np import pytest from mmengine import Config from mmagic.apis.inferencers.eg3d_inferencer import EG3DInferencer from mmagic.utils import register_all_modules register_all_modules() config = dict( model=dict( type='EG3D', generator=dict( type='TriplaneGenerator', out_size=32, noise_size=8, style_channels=8, num_mlps=1, triplane_size=8, triplane_channels=4, sr_in_size=8, sr_in_channels=8, neural_rendering_resolution=5, cond_scale=1, renderer_cfg=dict( ray_start=0.1, ray_end=2.6, box_warp=1.6, depth_resolution=4, white_back=True, depth_resolution_importance=4, ), rgb2bgr=True), camera=dict( type='UniformCamera', horizontal_mean=3.141, horizontal_std=3.141, vertical_mean=3.141 / 2, vertical_std=3.141 / 2, focal=1.025390625, up=[0, 0, 1], radius=1.2), data_preprocessor=dict(type='DataPreprocessor'))) def test_eg3d_inferencer(): cfg = Config(config) result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'eg3d_output') inferencer_instance = EG3DInferencer(cfg, None) output = inferencer_instance( vis_mode='both', save_img=False, save_video=True, interpolation='camera', num_images=10, result_out_dir=result_out_dir) # contrust target file list target_file_list = [ 'fake_img_seed2022.mp4', 'depth_seed2022.mp4', 'combine_seed2022.mp4' ] assert set(target_file_list) == set(os.listdir(result_out_dir)) assert isinstance(output, dict) shutil.rmtree(result_out_dir) output = inferencer_instance( vis_mode='both', save_img=True, save_video=False, interpolation='camera', num_images=10, result_out_dir=result_out_dir) # contrust target file list target_file_list = [ f'fake_img_frame{idx}_seed2022.png' for idx in range(10) ] target_file_list += [f'depth_frame{idx}_seed2022.png' for idx in range(10)] target_file_list += [ f'combine_frame{idx}_seed2022.png' for idx in range(10) ] assert set(target_file_list) == set(os.listdir(result_out_dir)) assert isinstance(output, dict) shutil.rmtree(result_out_dir) output = inferencer_instance( vis_mode='depth', save_img=False, interpolation='camera', num_images=2, result_out_dir=result_out_dir) # contrust target file list target_file_list = ['depth_seed2022.mp4'] assert set(target_file_list) == set(os.listdir(result_out_dir)) assert isinstance(output, dict) shutil.rmtree(result_out_dir) output = inferencer_instance( vis_mode='depth', save_video=False, save_img=False, interpolation='camera', sample_model='orig', num_images=2, result_out_dir=result_out_dir) assert len(os.listdir(result_out_dir)) == 0 # test cond input inferencer_instance = EG3DInferencer( cfg, None, extra_parameters=dict(sample_model='orig')) cond_input = [np.random.randn(25) for _ in range(2)] output = inferencer_instance( inputs=cond_input, vis_mode='both', save_video=True, save_img=False, interpolation='camera', num_images=2, result_out_dir=result_out_dir) # contrust target file list target_file_list = [ 'fake_img_seed2022.png', 'depth_seed2022.png', 'combine_seed2022.png', ] assert set(target_file_list) == set(os.listdir(result_out_dir)) assert isinstance(output, dict) shutil.rmtree(result_out_dir) cond_input = [[0.111 for _ in range(25)] for _ in range(2)] output = inferencer_instance( inputs=cond_input, vis_mode='depth', save_video=False, save_img=True, interpolation='camera', num_images=2, result_out_dir=result_out_dir) target_file_list = ['depth_seed2022.png'] assert set(target_file_list) == set(os.listdir(result_out_dir)) assert isinstance(output, dict) shutil.rmtree(result_out_dir) cond_input = [['wrong'], ['input']] with pytest.raises(AssertionError): inferencer_instance( inputs=cond_input, vis_mode='depth', save_video=False, save_img=False, interpolation='camera', num_images=2, result_out_dir=result_out_dir) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_image_super_resolution_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import platform import pytest import torch from mmagic.apis.inferencers.image_super_resolution_inferencer import \ ImageSuperResolutionInferencer from mmagic.utils import register_all_modules register_all_modules() @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_image_super_resolution_inferencer(): data_root = osp.join(osp.dirname(__file__), '../../../') config = data_root + 'configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py' # noqa img_path = data_root + 'tests/data/image/lq/baboon_x4.png' result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'image_super_resolution_result.png') inferencer_instance = \ ImageSuperResolutionInferencer(config, None) inferencer_instance(img=img_path) inference_result = inferencer_instance( img=img_path, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.shape == (480, 500, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_inference_functions.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest from mmagic.apis.inferencers.inference_functions import (calculate_grid_size, init_model, set_random_seed) def test_init_model(): set_random_seed(1) with pytest.raises(TypeError): init_model(['dog']) def test_calculate_grid_size(): inp_batch_size = (10, 13, 20, 1, 4) target_nrow = (4, 4, 5, 1, 2) for bz, tar in zip(inp_batch_size, target_nrow): assert calculate_grid_size(bz) == tar # test aspect_ratio is not None inp_batch_size = (10, 13, 20, 1, 4) aspect_ratio = (2, 3, 3, 4, 3) target_nrow = (3, 3, 3, 1, 2) for bz, ratio, tar in zip(inp_batch_size, aspect_ratio, target_nrow): assert calculate_grid_size(bz, ratio) == tar def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_inpainting_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.inpainting_inferencer import InpaintingInferencer from mmagic.utils import register_all_modules register_all_modules() def test_inpainting_inferencer(): data_root = osp.join(osp.dirname(__file__), '../../') masked_img_path = data_root + 'data/inpainting/celeba_test.png' mask_path = data_root + 'data/inpainting/bbox_mask.png' cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'aot_gan', 'aot-gan_smpgan_4xb4_places-512x512.py', ) result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'inpainting_result.png') inferencer_instance = \ InpaintingInferencer(cfg, None) inferencer_instance(img=masked_img_path, mask=mask_path) inference_result = inferencer_instance( img=masked_img_path, mask=mask_path, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.shape == (256, 256, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_matting_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.matting_inferencer import MattingInferencer from mmagic.utils import register_all_modules register_all_modules() def test_matting_inferencer(): data_root = osp.join(osp.dirname(__file__), '../../../') config = data_root + 'configs/dim/dim_stage3-v16-pln_1xb1-1000k_comp1k.py' img_path = data_root + 'tests/data/matting_dataset/merged/GT05.jpg' trimap_path = data_root + 'tests/data/matting_dataset/trimap/GT05.png' result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'matting_result.png') inferencer_instance = \ MattingInferencer(config, None) inferencer_instance(img=img_path, trimap=trimap_path) inference_result = inferencer_instance( img=img_path, trimap=trimap_path, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.numpy().shape == (552, 800) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_mmedit_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import pytest from mmagic.apis.inferencers import Inferencers from mmagic.utils import register_all_modules register_all_modules() def test_mmagic_inferencer(): with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('colorization', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('unconditional', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('matting', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('inpainting', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('translation', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('restoration', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('video_restoration', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('video_interpolation', ['error_type'], None) with pytest.raises(Exception) as e_info: inferencer_instance = Inferencers('dog', ['error_type'], None) print(e_info) cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'sngan_proj', 'sngan-proj_woReLUinplace_lr2e-4-ndisc5-1xb64_cifar10-32x32.py') inferencer_instance = \ Inferencers('conditional', cfg, None, extra_parameters={'sample_model': 'orig'}) inference_result = inferencer_instance(label=1) result_img = inference_result[1] assert result_img.shape == (4, 3, 32, 32) extra_parameters = inferencer_instance.get_extra_parameters() assert len(extra_parameters) == 2 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_text2image_inferencers.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import unittest from unittest import TestCase from unittest.mock import patch import torch import torch.nn as nn from mmengine.utils import digit_version from torchvision.version import __version__ as TV_VERSION from mmagic.apis.inferencers.text2image_inferencer import Text2ImageInferencer from mmagic.models import DenoisingUnet, DiscoDiffusion from mmagic.models.diffusion_schedulers import EditDDIMScheduler from mmagic.utils import register_all_modules register_all_modules() class clip_mock(nn.Module): def __init__(self, device='cuda'): super().__init__() self.register_buffer('tensor', torch.randn([1, 512])) def encode_image(self, inputs): return inputs.mean() * self.tensor.repeat(inputs.shape[0], 1).to( inputs.device) def encode_text(self, inputs): return self.tensor.repeat(inputs.shape[0], 1).to(inputs.device) def forward(self, x): return x class clip_mock_wrapper(nn.Module): def __init__(self): super().__init__() self.model = clip_mock() def forward(self, x): return x class TestTranslationInferencer(TestCase): def setUp(self): self.unet32 = DenoisingUnet( image_size=32, in_channels=3, base_channels=8, resblocks_per_downsample=2, attention_res=(8, ), norm_cfg=dict(type='GN32', num_groups=8), dropout=0.0, num_classes=0, use_fp16=True, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=2, num_head_channels=8, use_new_attention_order=False), use_scale_shift_norm=True) # mock clip self.clip_models = [clip_mock_wrapper(), clip_mock_wrapper()] # diffusion_scheduler self.diffusion_scheduler = EditDDIMScheduler( variance_type='learned_range', beta_schedule='linear', clip_sample=False) unet32 = self.unet32 diffusion_scheduler = self.diffusion_scheduler clip_models = self.clip_models self.disco_diffusion = DiscoDiffusion( unet=unet32, diffusion_scheduler=diffusion_scheduler, secondary_model=None, clip_models=clip_models, use_fp16=True).cuda() @unittest.skipIf( digit_version(TV_VERSION) <= digit_version('0.7.0'), reason='torchvision version limiation') @unittest.skipIf(not torch.cuda.is_available(), reason='requires cuda') def test_translation(self): cfg_root = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'disco_diffusion') cfg = osp.join(cfg_root, 'disco-diffusion_adm-u-finetuned_imagenet-512x512.py') text = {0: ['sad']} result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'disco_result.png') with patch.object(Text2ImageInferencer, '_init_model'): inferencer_instance = Text2ImageInferencer( cfg, None, extra_parameters={'num_inference_steps': 2}) # mock model inferencer_instance.model = self.disco_diffusion inferencer_instance(text=text) inference_result = inferencer_instance( text=text, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img[0].cpu().numpy().shape == (3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_translation_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.translation_inferencer import \ TranslationInferencer from mmagic.utils import register_all_modules register_all_modules() def test_translation_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'pix2pix', 'pix2pix_vanilla-unet-bn_1xb1-80kiters_facades.py') data_path = osp.join( osp.dirname(__file__), '..', '..', 'data', 'unpaired', 'trainA', '1.jpg') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'translation_result.png') inferencer_instance = \ TranslationInferencer(cfg, None) inferencer_instance(img=data_path) inference_result = inferencer_instance( img=data_path, result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img[0].cpu().numpy().shape == (3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_unconditional_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import torch from mmagic.apis.inferencers.unconditional_inferencer import \ UnconditionalInferencer from mmagic.utils import register_all_modules register_all_modules() def test_unconditional_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'styleganv1', 'styleganv1_ffhq-256x256_8xb4-25Mimgs.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'unconditional_result.png') inferencer_instance = \ UnconditionalInferencer(cfg, None, extra_parameters={ 'num_batches': 1, 'sample_model': 'orig'}) # test no result_out_dir inferencer_instance() inference_result = inferencer_instance(result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.detach().numpy().shape == (1, 3, 256, 256) # test additional input for extra parameters noise = torch.randn(1, 512) sample_kwargs = sample_kwargs = { 'return_noise': True, 'input_is_latent': False } inferencer_instance = \ UnconditionalInferencer(cfg, None, extra_parameters={ 'num_batches': 1, 'sample_model': 'orig', 'noise': noise, 'sample_kwargs': sample_kwargs}) # test no result_out_dir inferencer_instance() inference_result = inferencer_instance(result_out_dir=result_out_dir) result_img = inference_result[1] assert result_img.detach().numpy().shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_video_interpolation_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.video_interpolation_inferencer import \ VideoInterpolationInferencer from mmagic.utils import register_all_modules register_all_modules() def test_video_interpolation_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'flavr', 'flavr_in4out1_8xb4_vimeo90k-septuplet.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'video_interpolation_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') video_path = data_root + 'tests/data/frames/test_inference.mp4' inferencer_instance = \ VideoInterpolationInferencer(cfg, None) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def test_video_interpolation_inferencer_input_dir(): data_root = osp.join(osp.dirname(__file__), '../../../') config = data_root + 'configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py' video_path = data_root + 'tests/data/frames/sequence/gt/sequence_1' result_out_dir = data_root + 'tests/data/out' inferencer_instance = \ VideoInterpolationInferencer(config, None, extra_parameters={'fps': 60}) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def test_video_interpolation_inferencer_fps_multiplier(): result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data', 'video_interpolation_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') cfg = data_root + 'configs/cain/cain_g1b32_1xb5_vimeo90k-triplet.py' video_path = data_root + 'tests/data/frames/test_inference.mp4' inferencer_instance = \ VideoInterpolationInferencer(cfg, None, extra_parameters={'fps_multiplier': 2}) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_inferencers/test_video_restoration_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.apis.inferencers.video_restoration_inferencer import \ VideoRestorationInferencer from mmagic.utils import register_all_modules register_all_modules() def test_video_restoration_inferencer(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'basicvsr', 'basicvsr_2xb4_reds4.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'video_restoration_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') video_path = data_root + 'tests/data/frames/test_inference.mp4' inferencer_instance = \ VideoRestorationInferencer( cfg, None) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def test_video_restoration_inferencer_input_dir(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'basicvsr', 'basicvsr_2xb4_reds4.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'video_restoration_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') input_dir = osp.join(data_root, 'tests/data/frames/sequence/gt/sequence_1') result_out_dir = data_root + 'tests/data/out' inferencer_instance = \ VideoRestorationInferencer( cfg, None) inference_result = inferencer_instance( video=input_dir, result_out_dir=result_out_dir) assert inference_result is None def test_video_restoration_inferencer_window_size(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'basicvsr', 'basicvsr_2xb4_reds4.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'video_restoration_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') video_path = data_root + 'tests/data/frames/test_inference.mp4' extra_parameters = {'window_size': 3} inferencer_instance = \ VideoRestorationInferencer( cfg, None, extra_parameters=extra_parameters) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def test_video_restoration_inferencer_max_seq_len(): cfg = osp.join( osp.dirname(__file__), '..', '..', '..', 'configs', 'basicvsr', 'basicvsr_2xb4_reds4.py') result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', 'video_restoration_result.mp4') data_root = osp.join(osp.dirname(__file__), '../../../') video_path = data_root + 'tests/data/frames/test_inference.mp4' extra_parameters = {'max_seq_len': 3} inferencer_instance = \ VideoRestorationInferencer( cfg, None, extra_parameters=extra_parameters) inference_result = inferencer_instance( video=video_path, result_out_dir=result_out_dir) assert inference_result is None def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_apis/test_mmagic_inferencer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import pytest from mmagic.apis import MMagicInferencer from mmagic.utils import register_all_modules register_all_modules() def test_edit(): with pytest.raises(Exception): MMagicInferencer('dog', ['error_type'], None) with pytest.raises(Exception): MMagicInferencer() with pytest.raises(Exception): MMagicInferencer(model_setting=1) supported_models = MMagicInferencer.get_inference_supported_models() MMagicInferencer.inference_supported_models_cfg_inited = False supported_models = MMagicInferencer.get_inference_supported_models() supported_tasks = MMagicInferencer.get_inference_supported_tasks() MMagicInferencer.inference_supported_models_cfg_inited = False supported_tasks = MMagicInferencer.get_inference_supported_tasks() task_supported_models = \ MMagicInferencer.get_task_supported_models('Image2Image Translation') MMagicInferencer.inference_supported_models_cfg_inited = False task_supported_models = \ MMagicInferencer.get_task_supported_models('Image2Image Translation') print(supported_models) print(supported_tasks) print(task_supported_models) cfg = osp.join( osp.dirname(__file__), '..', '..', 'configs', 'biggan', 'biggan_2xb25-500kiters_cifar10-32x32.py') mmagic_instance = MMagicInferencer( 'biggan', model_ckpt='', model_config=cfg, extra_parameters={'sample_model': 'ema'}) mmagic_instance.print_extra_parameters() inference_result = mmagic_instance.infer(label=1) result_img = inference_result[1] assert result_img.shape == (4, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_basic_conditional_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. # import os import os.path as osp from unittest import TestCase import numpy as np from mmagic.datasets import BasicConditionalDataset from mmagic.utils import register_all_modules register_all_modules() DATA_DIR = osp.abspath(osp.join(osp.dirname(__file__), '../data/dataset/')) class TestBasicConditonalDataset(TestCase): def test_init(self): ann_file = osp.abspath(osp.join(DATA_DIR, 'anno.txt')) dataset = BasicConditionalDataset( data_root=DATA_DIR, ann_file=ann_file, metainfo={'classes': ('bus', 'car')}) self.assertEqual(dataset.CLASSES, ('bus', 'car')) self.assertFalse(dataset.test_mode) self.assertNotIn('With transforms:', repr(dataset)) classes_file = osp.abspath(osp.join(DATA_DIR, 'classes.txt')) dataset = BasicConditionalDataset( data_root=DATA_DIR, ann_file=ann_file, classes=classes_file) self.assertEqual(dataset.CLASSES, ('bus', 'car')) self.assertEqual(dataset.class_to_idx, {'bus': 0, 'car': 1}) ann_file = osp.abspath(osp.join(DATA_DIR, 'wrong.yml')) with self.assertRaises(TypeError): BasicConditionalDataset(data_root=DATA_DIR, ann_file=ann_file) gt_labels = dataset.get_gt_labels() print(type(gt_labels)) self.assertTrue((gt_labels == np.array([0, 1, 1])).all()) for idx, tar_ids in enumerate([0, 1, 1]): cat_ids = dataset.get_cat_ids(idx) self.assertEqual(cat_ids, [tar_ids]) data = dataset[0] self.assertEqual(data['sample_idx'], 0) self.assertEqual(data['gt_label'], 0) self.assertIn('a/1.JPG', data['gt_path']) # test data prefix --> b/subb dataset = BasicConditionalDataset(data_root=DATA_DIR, data_prefix='b') self.assertIn('subb', dataset.CLASSES) dataset = BasicConditionalDataset( data_root=DATA_DIR, data_prefix={'gt_path': 'b'}) self.assertIn('subb', dataset.CLASSES) # test runtime error --> no samples with self.assertRaises(RuntimeError): dataset = BasicConditionalDataset(data_root=osp.dirname(__file__)) # test assert error --> class list is not same with self.assertRaises(AssertionError): dataset = BasicConditionalDataset( data_root=DATA_DIR, classes=['1', '2', '3', '4']) # test Value error --> wrong classes type input with self.assertRaises(ValueError): dataset = BasicConditionalDataset( data_root=DATA_DIR, classes=dict(a=1)) # test raise warning --> find empty classes --> # TODO: how to get logger's output? dataset = BasicConditionalDataset(data_root=DATA_DIR) # test lazy init dataset = BasicConditionalDataset( data_root=DATA_DIR, lazy_init=True, pipeline=[dict(type='PackInputs')]) self.assertFalse(dataset._fully_initialized) self.assertIn("Haven't been initialized", repr(dataset)) self.assertIn('With transforms:', repr(dataset)) # test load label from json file ann_file = osp.abspath(osp.join(DATA_DIR, 'anno.json')) dataset = BasicConditionalDataset( data_root=DATA_DIR, ann_file=ann_file, lazy_init=True, pipeline=[dict(type='PackInputs')]) self.assertEqual(dataset[0]['data_samples'].gt_label.label.tolist(), [1, 2, 3, 4]) self.assertEqual(dataset[1]['data_samples'].gt_label.label.tolist(), [1, 4, 5, 3]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_basic_frames_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from pathlib import Path from mmagic.datasets import BasicFramesDataset class TestFramesDatasets: # TODO add a param for depth of file (for sequence_length). @classmethod def setup_class(cls): cls.data_root = Path(__file__).parent.parent / 'data' / 'frames' def test_version_1_method(self): # test SRREDSDataset and SRREDSMultipleGTDataset # need to split the data set ahead of schedule dataset = BasicFramesDataset( ann_file='ann2.txt', metainfo=dict(dataset_type='SRREDSDataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), backend_args=dict(backend='local'), pipeline=[], depth=1, num_input_frames=5, fixed_seq_len=100) assert dataset[0] == dict( key='sequence_1', num_input_frames=5, num_output_frames=None, sequence_length=100, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) # test SRVimeo90KDataset and SRVimeo90KMultipleGTDataset # Each clip of Vimeo90K has 7 frames starting from 1. # So we use 9 for generating frame_index_list in Version 1.0: # N | frame_index_list # 1 | 4 # 3 | 3,4,5 # 5 | 2,3,4,5,6 # 7 | 1,2,3,4,5,6,7 # In Version 2.0, we load the list of frames directly dataset = BasicFramesDataset( ann_file='ann3.txt', metainfo=dict(dataset_type='SRVimeo90KDataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict(img='sequence', gt='sequence'), pipeline=[], depth=2, load_frames_list=dict( img=['all'], gt=['00000000.png', '00000001.png'])) assert dataset[0] == dict( key=f'gt{os.sep}sequence_1', num_input_frames=2, num_output_frames=2, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], sample_idx=0) # test SRVid4Dataset dataset = BasicFramesDataset( ann_file='ann1.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) # test SRTestMultipleGTDataset and SRFolderMultipleGTDataset dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), pipeline=[], num_input_frames=1, depth=1) assert dataset[0] == dict( key='sequence_1', num_input_frames=1, num_output_frames=None, sequence_length=2, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) dataset = BasicFramesDataset( ann_file='ann1.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), pipeline=[], num_input_frames=1, depth=1) assert dataset[0] == dict( key='sequence_1', num_input_frames=1, num_output_frames=None, sequence_length=2, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) # test SRFolderVideoDataset dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), pipeline=[], num_input_frames=5, depth=2) assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=5, num_output_frames=None, sequence_length=2, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) dataset = BasicFramesDataset( ann_file='ann2.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), pipeline=[], num_input_frames=5, depth=2) assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=5, num_output_frames=None, sequence_length=2, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) # test VFIVimeo90KDataset dataset = BasicFramesDataset( ann_file='ann3.txt', metainfo=dict(dataset_type='vfi_folder_dataset', task_name='vfi'), data_root=self.data_root, data_prefix=dict(img='sequence', gt='sequence'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3, load_frames_list=dict( img=['00000000.png', '00000001.png'], gt=['00000000.png'])) assert dataset[0] == dict( key=f'gt{os.sep}sequence_1', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png') ], sample_idx=0) def test_vsr_folder_dataset(self): # case 1: deep_path dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key=f'sequence_1{os.sep}00000001', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) assert dataset[2] == dict( key=f'sequence_2{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=2) # case 2: not deep_path dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) # case 3: no fixed_seq_len dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=None) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=2, sequence_length=2, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) # case 4: not deep_path, load_frames_list dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=3, load_frames_list=dict(img=['all'], gt=['00000000.png'])) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png') ], sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=3, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000001.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000002.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png') ], sample_idx=1) # case 5: deep_path, load_frames_list dataset = BasicFramesDataset( ann_file='', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict(img='sequence', gt='sequence'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3, load_frames_list=dict(img=['00000000.png'], gt=['all'])) assert dataset.data_prefix == dict( img=str(self.data_root / 'sequence'), gt=str(self.data_root / 'sequence')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key=f'gt{os.sep}sequence_1', num_input_frames=1, num_output_frames=2, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], sample_idx=0) assert dataset[1] == dict( key=f'gt{os.sep}sequence_2', num_input_frames=1, num_output_frames=3, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000001.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000002.png') ], sample_idx=1) def test_vsr_ann_dataset(self): # case 1: deep_path, not deep_ann dataset = BasicFramesDataset( ann_file='ann1.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) assert dataset.ann_file == str(self.data_root / 'ann1.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key=f'sequence_1{os.sep}00000001', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) assert dataset[2] == dict( key=f'sequence_2{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=2) # case 2: deep_path, deep_ann dataset = BasicFramesDataset( ann_file='ann2.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) assert dataset.ann_file == str(self.data_root / 'ann2.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key=f'sequence_1{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key=f'sequence_1{os.sep}00000001', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) assert dataset[2] == dict( key=f'sequence_2{os.sep}00000000', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=2) # case 3: not deep_path, not deep_ann dataset = BasicFramesDataset( ann_file='ann1.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) assert dataset.ann_file == str(self.data_root / 'ann1.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) # case 4: not deep_path, deep_ann dataset = BasicFramesDataset( ann_file='ann2.txt', metainfo=dict(dataset_type='vsr_folder_dataset', task_name='vsr'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=3) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) assert dataset.ann_file == str(self.data_root / 'ann2.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=2, num_output_frames=2, sequence_length=3, img_path=str(self.data_root / f'sequence{os.sep}gt'), gt_path=str(self.data_root / f'sequence{os.sep}gt'), sample_idx=1) def test_vfi_ann_dataset(self): # case 1: not deep_path dataset = BasicFramesDataset( ann_file='ann1.txt', metainfo=dict(dataset_type='vfi_folder_dataset', task_name='vfi'), data_root=self.data_root, data_prefix=dict( img=f'sequence{os.sep}gt', gt=f'sequence{os.sep}gt'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=1, num_input_frames=2, num_output_frames=2, fixed_seq_len=3, load_frames_list=dict( img=['00000000.png', '00000001.png'], gt=['00000000.png'])) assert dataset.data_prefix == dict( img=str(self.data_root / f'sequence{os.sep}gt'), gt=str(self.data_root / f'sequence{os.sep}gt')) assert dataset.ann_file == str(self.data_root / 'ann1.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='sequence_1', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png') ], sample_idx=0) assert dataset[1] == dict( key='sequence_2', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png') ], sample_idx=1) # case 2: deep_path dataset = BasicFramesDataset( ann_file='ann3.txt', metainfo=dict(dataset_type='vfi_folder_dataset', task_name='vfi'), data_root=self.data_root, data_prefix=dict(img='sequence', gt='sequence'), filename_tmpl=dict(img='{}', gt='{}'), pipeline=[], depth=2, num_input_frames=2, num_output_frames=2, fixed_seq_len=3, load_frames_list=dict( img=['00000000.png', '00000001.png'], gt=['00000000.png'])) assert dataset.data_prefix == dict( img=str(self.data_root / 'sequence'), gt=str(self.data_root / 'sequence')) assert dataset.ann_file == str(self.data_root / 'ann3.txt') # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key=f'gt{os.sep}sequence_1', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_1' / '00000000.png') ], sample_idx=0) assert dataset[1] == dict( key=f'gt{os.sep}sequence_2', num_input_frames=2, num_output_frames=1, sequence_length=None, img_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png'), str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000001.png') ], gt_path=[ str(self.data_root / f'sequence{os.sep}gt' / 'sequence_2' / '00000000.png') ], sample_idx=1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_basic_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from pathlib import Path import mmcv from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import LoadImageFromFile class TestImageDatasets: @classmethod def setup_class(cls): cls.data_root = Path(__file__).parent.parent / 'data' / 'image' def test_version_1_method(self): # test SRAnnotationDataset dataset = BasicImageDataset( ann_file='train.txt', metainfo=dict( dataset_type='sr_annotation_dataset', task_name='sisr'), data_root=self.data_root, data_prefix=dict(img='lq', gt='gt'), filename_tmpl=dict(img='{}_x4'), backend_args=dict(backend='local'), pipeline=[]) assert dataset[0] == dict( key='baboon', img_path=str(self.data_root / 'lq' / 'baboon_x4.png'), gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) # test SRFolderDataset dataset = BasicImageDataset( metainfo=dict(dataset_type='sr_folder_dataset', task_name='sisr'), data_root=self.data_root, data_prefix=dict(img='lq', gt='gt'), filename_tmpl=dict(img='{}_x4'), pipeline=[]) assert dataset[0] == dict( key='baboon', img_path=str(self.data_root / 'lq' / 'baboon_x4.png'), gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) # test SRFolderGTDataset dataset = BasicImageDataset( metainfo=dict(dataset_type='sr_folder_dataset', task_name='sisr'), data_root=self.data_root, data_prefix=dict(gt='gt'), filename_tmpl=dict(), pipeline=[]) assert dataset[0] == dict( key='baboon', gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) # test SRLmdbDataset # The reconstructed LoadImageFromFile supports process images in LMDB # backend, which require similar img_path as that of disk backend. # Thus SRLmdbDataset is useless. # We can build the dataset in the same way with SRAnnotationDataset: pipeline = [ LoadImageFromFile( key='img', backend_args=dict( backend='lmdb', db_path=Path(__file__).parent.parent / 'data' / 'lq.lmdb')) ] dataset = BasicImageDataset( ann_file=f'lq.lmdb{os.sep}meta_info.txt', metainfo=dict( dataset_type='sr_annotation_dataset', task_name='sisr'), data_prefix=dict(gt='', img=''), data_root=self.data_root.parent, pipeline=pipeline) assert dataset.ann_file == str(self.data_root.parent / 'lq.lmdb' / 'meta_info.txt') path_baboon_x4 = Path( __file__).parent.parent / 'data' / 'image' / 'lq' / 'baboon_x4.png' img_baboon_x4 = mmcv.imread(str(path_baboon_x4), flag='color') h, w, _ = img_baboon_x4.shape assert dataset[0]['img'].shape == (h, w, 3) assert dataset[0]['ori_img_shape'] == (h, w, 3) dataset[0]['img_path'] == str(self.data_root.parent / 'baboon.png') dataset[0]['gt_path'] == str(self.data_root.parent / 'baboon.png') # test ImgInpaintingDataset # test SRFacialLandmarkDataset i.e. SRAnnGTDataset dataset = BasicImageDataset( ann_file='train.txt', metainfo=dict( dataset_type='ImgInpaintingDataset', task_name='inpainting'), data_root=self.data_root, data_prefix=dict(gt='gt'), filename_tmpl=dict(), pipeline=[]) assert dataset[0] == dict( key='baboon', gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) assert dataset[1] == dict( key='baboon', gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=1) def test_sisr_annotation_dataset(self): # setup dataset = BasicImageDataset( ann_file='train.txt', metainfo=dict( dataset_type='sisr_annotation_dataset', task_name='sisr'), data_root=self.data_root, data_prefix=dict(img='lq', gt='gt'), filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=[]) assert dataset.ann_file == str(self.data_root / 'train.txt') assert dataset.data_prefix == dict( img=str(self.data_root / 'lq'), gt=str(self.data_root / 'gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='baboon', img_path=str(self.data_root / 'lq' / 'baboon_x4.png'), gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0), dataset[0] def test_sisr_folder_dataset(self): # setup dataset = BasicImageDataset( metainfo=dict( dataset_type='sisr_folder_dataset', task_name='sisr'), data_root=self.data_root, data_prefix=dict(img='lq', gt='gt'), filename_tmpl=dict(img='{}_x4', gt='{}'), pipeline=[]) assert dataset.data_prefix == dict( img=str(self.data_root / 'lq'), gt=str(self.data_root / 'gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='baboon', img_path=str(self.data_root / 'lq' / 'baboon_x4.png'), gt_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) def test_refsr_folder_dataset(self): # setup dataset = BasicImageDataset( metainfo=dict( dataset_type='refsr_folder_dataset', task_name='refsr'), data_root=self.data_root, data_prefix=dict(img='lq', gt='gt', ref='gt'), filename_tmpl=dict(img='{}_x4', gt='{}', ref='{}'), pipeline=[]) assert dataset.data_prefix == dict( img=str(self.data_root / 'lq'), gt=str(self.data_root / 'gt'), ref=str(self.data_root / 'gt')) # Serialize ``self.data_list`` to save memory assert dataset.data_list == [] assert dataset[0] == dict( key='baboon', img_path=str(self.data_root / 'lq' / 'baboon_x4.png'), gt_path=str(self.data_root / 'gt' / 'baboon.png'), ref_path=str(self.data_root / 'gt' / 'baboon.png'), sample_idx=0) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_categories.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.datasets.categories import CIFAR10_CATEGORIES, IMAGENET_CATEGORIES def test_cifar10_categories(): assert len(CIFAR10_CATEGORIES) == 10 def test_imagenet_categories(): assert len(IMAGENET_CATEGORIES) == 1000 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_cifar10_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import pickle import tempfile from unittest import TestCase from unittest.mock import MagicMock, patch import numpy as np from mmagic.registry import DATASETS from mmagic.utils import register_all_modules DATA_DIR = osp.abspath(osp.join(osp.dirname(__file__), '../data/dataset/')) register_all_modules() class TestCIFAR10(TestCase): DATASET_TYPE = 'CIFAR10' @classmethod def setUpClass(cls) -> None: super().setUpClass() tmpdir = tempfile.TemporaryDirectory() cls.tmpdir = tmpdir data_prefix = tmpdir.name cls.DEFAULT_ARGS = dict( data_prefix=data_prefix, pipeline=[], test_mode=False) dataset_class = DATASETS.get(cls.DATASET_TYPE) base_folder = osp.join(data_prefix, dataset_class.base_folder) os.mkdir(base_folder) cls.fake_imgs = np.random.randint( 0, 255, size=(6, 3 * 32 * 32), dtype=np.uint8) cls.fake_labels = np.random.randint(0, 10, size=(6, )) cls.fake_classes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] batch1 = dict( data=cls.fake_imgs[:2], labels=cls.fake_labels[:2].tolist()) with open(osp.join(base_folder, 'data_batch_1'), 'wb') as f: f.write(pickle.dumps(batch1)) batch2 = dict( data=cls.fake_imgs[2:4], labels=cls.fake_labels[2:4].tolist()) with open(osp.join(base_folder, 'data_batch_2'), 'wb') as f: f.write(pickle.dumps(batch2)) test_batch = dict( data=cls.fake_imgs[4:], fine_labels=cls.fake_labels[4:].tolist()) with open(osp.join(base_folder, 'test_batch'), 'wb') as f: f.write(pickle.dumps(test_batch)) meta = {dataset_class.meta['key']: cls.fake_classes} meta_filename = dataset_class.meta['filename'] with open(osp.join(base_folder, meta_filename), 'wb') as f: f.write(pickle.dumps(meta)) dataset_class.train_list = [['data_batch_1', None], ['data_batch_2', None]] dataset_class.test_list = [['test_batch', None]] dataset_class.meta['md5'] = None def test_initialize(self): dataset_class = DATASETS.get(self.DATASET_TYPE) # Test overriding metainfo by `metainfo` argument cfg = {**self.DEFAULT_ARGS, 'metainfo': {'classes': ('bus', 'car')}} dataset = dataset_class(**cfg) self.assertEqual(dataset.CLASSES, ('bus', 'car')) # Test overriding metainfo by `classes` argument cfg = {**self.DEFAULT_ARGS, 'classes': ['bus', 'car']} dataset = dataset_class(**cfg) self.assertEqual(dataset.CLASSES, ('bus', 'car')) classes_file = osp.join(DATA_DIR, 'classes.txt') cfg = {**self.DEFAULT_ARGS, 'classes': classes_file} dataset = dataset_class(**cfg) self.assertEqual(dataset.CLASSES, ('bus', 'car')) self.assertEqual(dataset.class_to_idx, {'bus': 0, 'car': 1}) # Test invalid classes cfg = {**self.DEFAULT_ARGS, 'classes': dict(classes=1)} with self.assertRaisesRegex(ValueError, "type "): dataset_class(**cfg) def test_load_data_list(self): dataset_class = DATASETS.get(self.DATASET_TYPE) # Test default behavior dataset = dataset_class(**self.DEFAULT_ARGS) self.assertEqual(len(dataset), 4) self.assertEqual(dataset.CLASSES, dataset_class.METAINFO['classes']) data_info = dataset[0] fake_img = self.fake_imgs[0].reshape(3, 32, 32).transpose(1, 2, 0) np.testing.assert_equal(data_info['gt'], fake_img) np.testing.assert_equal(data_info['gt_label'], self.fake_labels[0]) assert data_info['gt_channel_order'] == 'RGB' # Test with test_mode=True cfg = {**self.DEFAULT_ARGS, 'test_mode': True} dataset = dataset_class(**cfg) self.assertEqual(len(dataset), 2) data_info = dataset[0] fake_img = self.fake_imgs[4].reshape(3, 32, 32).transpose(1, 2, 0) np.testing.assert_equal(data_info['gt'], fake_img) np.testing.assert_equal(data_info['gt_label'], self.fake_labels[4]) assert data_info['gt_channel_order'] == 'RGB' # Test load meta cfg = {**self.DEFAULT_ARGS, 'lazy_init': True} dataset = dataset_class(**cfg) dataset._metainfo = {} dataset.full_init() self.assertEqual(dataset.CLASSES, self.fake_classes) cfg = {**self.DEFAULT_ARGS, 'lazy_init': True} dataset = dataset_class(**cfg) dataset._metainfo = {} dataset.meta['filename'] = 'invalid' with self.assertRaisesRegex(RuntimeError, 'not found or corrupted'): dataset.full_init() # Test automatically download with patch( 'mmagic.datasets.cifar10_dataset.download_and_extract_archive' ) as mock: cfg = {**self.DEFAULT_ARGS, 'lazy_init': True, 'test_mode': True} dataset = dataset_class(**cfg) dataset.test_list = [['invalid_batch', None]] with self.assertRaisesRegex(AssertionError, 'Download failed'): dataset.full_init() mock.assert_called_once_with( dataset.url, dataset.data_prefix['root'], filename=dataset.filename, md5=dataset.tgz_md5) with self.assertRaisesRegex(RuntimeError, '`download=True`'): cfg = { **self.DEFAULT_ARGS, 'lazy_init': True, 'test_mode': True, 'download': False } dataset = dataset_class(**cfg) dataset.test_list = [['test_batch', 'invalid_md5']] dataset.full_init() # Test different backend cfg = { **self.DEFAULT_ARGS, 'lazy_init': True, 'data_prefix': 'http://openmmlab/cifar' } dataset = dataset_class(**cfg) dataset._check_integrity = MagicMock(return_value=False) with self.assertRaisesRegex(RuntimeError, 'http://openmmlab/cifar'): dataset.full_init() def test_extra_repr(self): dataset_class = DATASETS.get(self.DATASET_TYPE) cfg = {**self.DEFAULT_ARGS, 'lazy_init': True} dataset = dataset_class(**cfg) self.assertIn(f'Prefix of data: \t{dataset.data_prefix["root"]}', repr(dataset)) @classmethod def tearDownClass(cls): cls.tmpdir.cleanup() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_comp1k_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from pathlib import Path from mmagic.datasets import AdobeComp1kDataset class TestMattingDatasets: # path to a minimal test dataset under 'tests/data' DATA_ROOT = Path(__file__).parent.parent / 'data' / 'matting_dataset' # cls.pipeline = [ # dict(type='LoadImageFromFile', key='alpha', flag='grayscale') # ] def test_comp1k_dataset(self): """Verify AdobeComp1kDataset reads dataset correctly. AdobeComp1kDataset should support both new and old annotation formats. """ ann_new = 'ann.json' ann_old = 'ann_old.json' for ann in ann_new, ann_old: # TODO: we may add an actual pipeline later ds = AdobeComp1kDataset(ann, data_root=self.DATA_ROOT, pipeline=[]) assert len(ds) == 2 assert ds.metainfo == dict( dataset_type='matting_dataset', task_name='matting') data0 = ds[0] data1 = ds[1] assert osp.isfile(data0['alpha_path']) assert osp.isfile(data1['alpha_path']) is_correct_ntpath = data0 == { 'alpha_path': f'{self.DATA_ROOT}\\alpha/GT05.jpg', 'trimap_path': f'{self.DATA_ROOT}\\trimap/GT05.jpg', 'bg_path': f'{self.DATA_ROOT}\\bg/GT26r.jpg', 'fg_path': f'{self.DATA_ROOT}\\fg/GT05.jpg', 'merged_path': f'{self.DATA_ROOT}\\merged/GT05.jpg', 'sample_idx': 0, } is_correct_posixpath = data0 == { 'alpha_path': f'{self.DATA_ROOT}/alpha/GT05.jpg', 'trimap_path': f'{self.DATA_ROOT}/trimap/GT05.jpg', 'bg_path': f'{self.DATA_ROOT}/bg/GT26r.jpg', 'fg_path': f'{self.DATA_ROOT}/fg/GT05.jpg', 'merged_path': f'{self.DATA_ROOT}/merged/GT05.jpg', 'sample_idx': 0, } assert is_correct_ntpath or is_correct_posixpath is_correct_ntpath = data1 == { 'alpha_path': f'{self.DATA_ROOT}\\alpha/GT05.jpg', 'bg_path': f'{self.DATA_ROOT}\\bg/GT26r.jpg', 'fg_path': f'{self.DATA_ROOT}\\fg/GT05.jpg', 'sample_idx': 1, } is_correct_posixpath = data1 == { 'alpha_path': f'{self.DATA_ROOT}/alpha/GT05.jpg', 'bg_path': f'{self.DATA_ROOT}/bg/GT26r.jpg', 'fg_path': f'{self.DATA_ROOT}/fg/GT05.jpg', 'sample_idx': 1, } assert is_correct_ntpath or is_correct_posixpath # TODO: after mmcv.transform becomes ready in CI # assert 'alpha' in first_data # assert isinstance(first_data['alpha'], np.ndarray) # assert first_data['alpha'].shape == (552, 800) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_controlnet_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from mmagic.datasets import ControlNetDataset data_dir = os.path.join(__file__, '../', '../', 'data', 'controlnet') data_dir = os.path.abspath(data_dir) anno_path = os.path.join(data_dir, 'prompt.json') source_path = os.path.join(data_dir, 'source') target_path = os.path.join(data_dir, 'target') def test_controlnet_dataset(): print(os.path.abspath(data_dir)) dataset = ControlNetDataset(data_root=data_dir) assert len(dataset) == 2 prompts = [ 'pale golden rod circle with old lace background', 'light coral circle with white background' ] for idx, data in enumerate(dataset): assert 'source_path' in data assert 'target_path' in data assert data['prompt'] == prompts[idx] def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_data_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.datasets.data_utils import infer_io_backend def test_infer_io_backend(): path = 'http://openmmlab/xxx' assert infer_io_backend(path) == 'http' path = 'https://torchvision/xxx' assert infer_io_backend(path) == 'http' path = 'MYCLUSTER:s3://openmmlab/datasets/mmediting/lsun/' assert infer_io_backend(path) == 'petrel' path = 's3://work_dirs/' assert infer_io_backend(path) == 'petrel' path = 'this/is/a/test' assert infer_io_backend(path) == 'local' # TODO: add more uts def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_dreambooth_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from mmagic.datasets import DreamBoothDataset # we use controlnet's dataset to test data_dir = os.path.join(__file__, '../', '../', 'data', 'controlnet') concept_dir = os.path.join(data_dir, 'source') def test_dreambooth_dataset(): print(os.path.abspath(data_dir)) dataset = DreamBoothDataset( data_root=data_dir, concept_dir=concept_dir, prompt='a sks ball', ) assert len(dataset) == 2 for data in dataset: assert data['prompt'] == 'a sks ball' def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_grow_scale_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import pytest from mmagic.datasets import GrowScaleImgDataset from mmagic.utils import register_all_modules register_all_modules() class TestGrowScaleImgDataset: @classmethod def setup_class(cls): cls.imgs_root = osp.join(osp.dirname(__file__), '..', 'data/image') cls.imgs_roots = { '4': cls.imgs_root, '8': osp.join(cls.imgs_root, 'img_root'), '32': osp.join(cls.imgs_root, 'img_root', 'grass') } cls.default_pipeline = [dict(type='LoadImageFromFile', key='gt')] cls.len_per_stage = 10 cls.gpu_samples_base = 2 def test_dynamic_unconditional_img_dataset(self): dataset = GrowScaleImgDataset( self.imgs_roots, self.default_pipeline, self.len_per_stage, io_backend='local', gpu_samples_base=self.gpu_samples_base) assert len(dataset) == 10 img = dataset[2]['gt'] assert img.ndim == 3 assert repr(dataset) == ( f'dataset_name: {dataset.__class__}, ' f'total {10} images in imgs_root: {self.imgs_root}') assert dataset.samples_per_gpu == 2 dataset.update_annotations(8) assert len(dataset) == 10 img = dataset[2]['gt'] assert img.ndim == 3 assert repr(dataset) == (f'dataset_name: {dataset.__class__}, ' f'total {10} images in imgs_root:' f' {osp.join(self.imgs_root, "img_root")}') assert dataset.samples_per_gpu == 2 dataset = GrowScaleImgDataset( self.imgs_roots, self.default_pipeline, 20, gpu_samples_base=self.gpu_samples_base, gpu_samples_per_scale={ '4': 10, '16': 13 }) assert len(dataset) == 20 img = dataset[2]['gt'] assert img.ndim == 3 assert repr(dataset) == ( f'dataset_name: {dataset.__class__}, ' f'total {20} images in imgs_root: {self.imgs_root}') assert dataset.samples_per_gpu == 10 dataset.update_annotations(8) assert len(dataset) == 20 img = dataset[2]['gt'] assert img.ndim == 3 assert repr(dataset) == (f'dataset_name: {dataset.__class__}, ' f'total {20} images in imgs_root:' f' {osp.join(self.imgs_root, "img_root")}') assert dataset.samples_per_gpu == 2 dataset = GrowScaleImgDataset( self.imgs_roots, self.default_pipeline, 5, test_mode=True) assert len(dataset) == 5 img = dataset[2]['gt'] assert img.ndim == 3 assert repr(dataset) == ( f'dataset_name: {dataset.__class__}, ' f'total {5} images in imgs_root: {self.imgs_root}') dataset.update_annotations(24) assert len(dataset) == 5 img = dataset[2]['gt'] assert img.ndim == 3 _path_str = osp.join(self.imgs_root, 'img_root', 'grass') assert repr(dataset) == (f'dataset_name: {dataset.__class__}, ' f'total {5} images in imgs_root: {_path_str}') with pytest.raises(AssertionError): _ = GrowScaleImgDataset( self.imgs_root, self.default_pipeline, 10, gpu_samples_per_scale=10) with pytest.raises(AssertionError): _ = GrowScaleImgDataset(10, self.default_pipeline, 10.) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_imagenet_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from unittest import TestCase from mmagic.datasets import ImageNet DATA_DIR = osp.abspath(osp.join(osp.dirname(__file__), '../data/dataset/')) class TestImageNetDataset(TestCase): def test_load_data_list(self): with self.assertRaisesRegex( AssertionError, r"\(3\) doesn't match .* classes \(1000\)"): ImageNet(data_root=DATA_DIR, data_prefix=DATA_DIR) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_mscoco_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from pathlib import Path from mmagic.datasets import MSCoCoDataset class TestMSCoCoDatasets: @classmethod def setup_class(cls): cls.data_root = Path(__file__).parent.parent / 'data' / 'coco' def test_mscoco(self): # test basic usage dataset = MSCoCoDataset(data_root=self.data_root, pipeline=[]) assert dataset[0] == dict( gt_prompt='a good meal', img_path=os.path.join(self.data_root, 'train2014', 'COCO_train2014_000000000009.jpg'), sample_idx=0) # test with different phase dataset = MSCoCoDataset( data_root=self.data_root, phase='val', pipeline=[]) assert dataset[0] == dict( gt_prompt='a pair of slippers', img_path=os.path.join(self.data_root, 'val2014', 'COCO_val2014_000000000042.jpg'), sample_idx=0) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_paired_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.datasets import PairedImageDataset from mmagic.utils import register_all_modules register_all_modules() class TestPairedImageDataset(object): @classmethod def setup_class(cls): cls.imgs_root = osp.join( osp.dirname(osp.dirname(__file__)), 'data/paired') cls.default_pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='a', domain_b='b'), dict( type='TransformBroadcaster', mapping={'img': ['img_a', 'img_b']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='Resize', scale=(286, 286), interpolation='bicubic'), dict(type='FixedCrop', keys=['img'], crop_size=(256, 256)) ]), dict(type='Flip', direction='horizontal', keys=['img_a', 'img_b']), dict(type='PackInputs', keys=['img_a', 'img_b']) ] def test_paired_image_dataset(self): dataset = PairedImageDataset( self.imgs_root, pipeline=self.default_pipeline) assert len(dataset) == 2 img = dataset[0]['inputs']['img_a'] assert img.ndim == 3 img = dataset[0]['inputs']['img_b'] assert img.ndim == 3 dataset = PairedImageDataset( self.imgs_root, pipeline=self.default_pipeline, io_backend='local') assert len(dataset) == 2 img = dataset[0]['inputs']['img_a'] assert img.ndim == 3 img = dataset[0]['inputs']['img_b'] assert img.ndim == 3 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_singan_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.datasets import SinGANDataset from mmagic.utils import register_all_modules register_all_modules() class TestSinGANDataset(object): @classmethod def setup_class(cls): cls.imgs_root = osp.join( osp.dirname(osp.dirname(__file__)), 'data/image/gt/baboon.png') cls.min_size = 25 cls.max_size = 250 cls.num_scales = 10 cls.scale_factor_init = 0.75 cls.pipeline = [ dict( type='PackInputs', keys=[f'real_scale{i}' for i in range(cls.num_scales)]) ] def test_singan_dataset(self): dataset = SinGANDataset( self.imgs_root, min_size=self.min_size, max_size=self.max_size, scale_factor_init=self.scale_factor_init, pipeline=self.pipeline) assert len(dataset) == 1000000 data_dict = dataset[0]['inputs'] assert all( [f'real_scale{i}' in data_dict for i in range(self.num_scales)]) a = TestSinGANDataset() a.setup_class() a.test_singan_dataset() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_textual_inversion_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os from mmagic.datasets import TextualInversionDataset data_dir = os.path.join(__file__, '../', '../', 'data', 'controlnet') concept_dir = os.path.join(data_dir, 'source') placeholder = 'S*' template = os.path.join(__file__, '../', '../', 'data', 'textual_inversion', 'imagenet_templates_small.txt') with_image_reference = True def test_textual_inversion_dataset(): print(os.path.abspath(data_dir)) dataset = TextualInversionDataset( data_root=data_dir, concept_dir=concept_dir, placeholder=placeholder, template=template, with_image_reference=with_image_reference) assert len(dataset) == 2 ================================================ FILE: tests/test_datasets/test_transforms/test_albumentations.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np from mmagic.datasets.transforms import Albumentations def test_albumentations(): results = {} results['img'] = np.ones((8, 8, 3)).astype(np.uint8) model = Albumentations( keys=['img'], transforms=[ dict(type='Resize', height=4, width=4), ]) results = model(results) assert results['img'].shape == (4, 4, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_alpha.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import GenerateSeg, GenerateSoftSeg def assert_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" assert set(target_keys).issubset(set(result_keys)) def test_generate_seg(): with pytest.raises(ValueError): # crop area should not exceed the image size img = np.random.rand(32, 32, 3) GenerateSeg._crop_hole(img, (0, 0), (64, 64)) target_keys = ['alpha', 'trimap', 'seg', 'num_holes'] alpha = np.random.randint(0, 255, (64, 64)) # previously this is 32 by 32, but default hole size contains 45 trimap = np.zeros_like(alpha) trimap[(alpha > 0) & (alpha < 255)] = 128 trimap[alpha == 255] = 255 results = dict(alpha=alpha, trimap=trimap) for _ in range(3): # test multiple times as it contain some random operations generate_seg = GenerateSeg(num_holes_range=(1, 3)) generate_seg_results = generate_seg(results) assert_keys_contain(generate_seg_results.keys(), target_keys) assert generate_seg_results['seg'].shape == alpha.shape assert isinstance(generate_seg_results['num_holes'], int) assert generate_seg_results['num_holes'] < 3 # check repr string and the default setting assert repr(generate_seg) == generate_seg.__class__.__name__ + ( '(kernel_size=5, erode_iter_range=(10, 20), ' 'dilate_iter_range=(15, 30), num_holes_range=(1, 3), ' 'hole_sizes=[(15, 15), (25, 25), (35, 35), (45, 45)], ' 'blur_ksizes=[(21, 21), (31, 31), (41, 41)]') def test_generate_soft_seg(): with pytest.raises(TypeError): # fg_thr must be a float GenerateSoftSeg(fg_thr=[0.2]) with pytest.raises(TypeError): # border_width must be an int GenerateSoftSeg(border_width=25.) with pytest.raises(TypeError): # erode_ksize must be an int GenerateSoftSeg(erode_ksize=5.) with pytest.raises(TypeError): # dilate_ksize must be an int GenerateSoftSeg(dilate_ksize=5.) with pytest.raises(TypeError): # erode_iter_range must be a tuple of 2 int GenerateSoftSeg(erode_iter_range=(3, 5, 7)) with pytest.raises(TypeError): # dilate_iter_range must be a tuple of 2 int GenerateSoftSeg(dilate_iter_range=(3, 5, 7)) with pytest.raises(TypeError): # blur_ksizes must be a list of tuple GenerateSoftSeg(blur_ksizes=[21, 21]) target_keys = ['seg', 'soft_seg'] seg = np.random.randint(0, 255, (512, 512)) results = dict(seg=seg) generate_soft_seg = GenerateSoftSeg( erode_ksize=3, dilate_ksize=3, erode_iter_range=(1, 2), dilate_iter_range=(1, 2), blur_ksizes=[(11, 11)]) generate_soft_seg_results = generate_soft_seg(results) assert_keys_contain(generate_soft_seg_results.keys(), target_keys) assert generate_soft_seg_results['soft_seg'].shape == seg.shape repr_str = generate_soft_seg.__class__.__name__ + ( '(fg_thr=0.2, border_width=25, erode_ksize=3, dilate_ksize=3, ' 'erode_iter_range=(1, 2), dilate_iter_range=(1, 2), ' 'blur_ksizes=[(11, 11)])') assert repr(generate_soft_seg) == repr_str def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_aug_frames.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import MirrorSequence, TemporalReverse class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.gt = np.random.randint(0, 256, (256, 128, 3), dtype=np.uint8) cls.img = np.random.randint(0, 256, (64, 32, 3), dtype=np.uint8) cls.results = dict( img=cls.img, gt=cls.gt, scale=4, img_path='fake_img_path', gt_path='fake_gt_path') cls.results['ori_img'] = np.random.randint( 0, 256, (256, 256, 3), dtype=np.uint8) cls.results['mask'] = np.random.randint( 0, 256, (256, 256, 1), dtype=np.uint8) # cls.results['img_tensor'] = torch.rand((3, 256, 256)) # cls.results['mask_tensor'] = torch.zeros((1, 256, 256)) # cls.results['mask_tensor'][:, 50:150, 40:140] = 1. @staticmethod def assert_img_equal(img, ref_img, ratio_thr=0.999): """Check if img and ref_img are matched approximately.""" assert img.shape == ref_img.shape assert img.dtype == ref_img.dtype area = ref_img.shape[-1] * ref_img.shape[-2] diff = np.abs(img.astype('int32') - ref_img.astype('int32')) assert np.sum(diff <= 1) / float(area) > ratio_thr @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) def test_mirror_sequence(self): imgs = [np.random.rand(4, 4, 3) for _ in range(0, 5)] gts = [np.random.rand(16, 16, 3) for _ in range(0, 5)] target_keys = ['img', 'gt'] mirror_sequence = MirrorSequence(keys=['img', 'gt']) results = dict(img=imgs, gt=gts) results = mirror_sequence(results) assert self.check_keys_contain(results.keys(), target_keys) for i in range(0, 5): np.testing.assert_almost_equal(results['img'][i], results['img'][-i - 1]) np.testing.assert_almost_equal(results['gt'][i], results['gt'][-i - 1]) assert repr(mirror_sequence) == mirror_sequence.__class__.__name__ + ( "(keys=['img', 'gt'])") # each key should contain a list of nparray with pytest.raises(TypeError): results = dict(img=0, gt=gts) mirror_sequence(results) def test_temporal_reverse(self): img_lq1 = np.random.rand(4, 4, 3).astype(np.float32) img_lq2 = np.random.rand(4, 4, 3).astype(np.float32) img_gt = np.random.rand(8, 8, 3).astype(np.float32) results = dict(lq=[img_lq1, img_lq2], gt=[img_gt]) target_keys = ['lq', 'gt', 'reverse'] temporal_reverse = TemporalReverse(keys=['lq', 'gt'], reverse_ratio=1) results = temporal_reverse(results) assert self.check_keys_contain(results.keys(), target_keys) np.testing.assert_almost_equal(results['lq'][0], img_lq2) np.testing.assert_almost_equal(results['lq'][1], img_lq1) np.testing.assert_almost_equal(results['gt'][0], img_gt) assert repr( temporal_reverse) == temporal_reverse.__class__.__name__ + ( f"(keys={['lq', 'gt']}, reverse_ratio=1)") results = dict(lq=[img_lq1, img_lq2], gt=[img_gt]) temporal_reverse = TemporalReverse(keys=['lq', 'gt'], reverse_ratio=0) results = temporal_reverse(results) assert self.check_keys_contain(results.keys(), target_keys) np.testing.assert_almost_equal(results['lq'][0], img_lq1) np.testing.assert_almost_equal(results['lq'][1], img_lq2) np.testing.assert_almost_equal(results['gt'][0], img_gt) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_aug_pixel.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import numpy as np import pytest from mmagic.datasets.transforms import (BinarizeImage, Clip, ColorJitter, RandomAffine, RandomMaskDilation, UnsharpMasking) class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.gt = np.random.randint(0, 256, (256, 128, 3), dtype=np.uint8) cls.img = np.random.randint(0, 256, (64, 32, 3), dtype=np.uint8) cls.results = dict( img=cls.img, gt=cls.gt, scale=4, img_path='fake_img_path', gt_path='fake_gt_path') cls.results['ori_img'] = np.random.randint( 0, 256, (256, 256, 3), dtype=np.uint8) cls.results['mask'] = np.random.randint( 0, 256, (256, 256, 1), dtype=np.uint8) # cls.results['img_tensor'] = torch.rand((3, 256, 256)) # cls.results['mask_tensor'] = torch.zeros((1, 256, 256)) # cls.results['mask_tensor'][:, 50:150, 40:140] = 1. @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) def test_binarize(self): mask_ = np.zeros((5, 5, 1)) mask_[2, 2, :] = 0.6 gt_mask = mask_.copy() gt_mask[2, 2, :] = 1. results = dict(mask=mask_.copy()) binarize = BinarizeImage(['mask'], 0.5, dtype=np.float32) results = binarize(results) assert np.array_equal(results['mask'], gt_mask.astype(np.float32)) results = dict(mask=mask_.copy()) binarize = BinarizeImage(['mask'], 0.5) results = binarize(results) assert np.array_equal(results['mask'], gt_mask.astype(np.uint8)) assert repr(binarize) == ( binarize.__class__.__name__ + f"(keys={['mask']}, binary_thr=0.5, " f'a_min=0, a_max=1, dtype={np.uint8})') results = dict(mask=mask_.copy()) binarize = BinarizeImage(['mask'], 0.5, a_max=3, a_min=1) results = binarize(results) assert np.array_equal(results['mask'], gt_mask.astype(np.uint8) * 2 + 1) assert repr(binarize) == ( binarize.__class__.__name__ + f"(keys={['mask']}, binary_thr=0.5, " f'a_min=1, a_max=3, dtype={np.uint8})') def test_clip(self): results = {} # clip results['gt'] = (1.2 - 0.1) * self.results['gt'] model = Clip(keys=['gt']) assert np.array_equal(model(results)['gt'], results['gt'].clip(0, 255)) def test_color_jitter(self): results = copy.deepcopy(self.results) results['gt'] = (results['gt'] * 255).astype(np.uint8) results['img'] = [results['gt'], results['gt']] target_keys = ['gt', 'img'] color_jitter = ColorJitter( keys=['gt', 'img'], brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5) color_jitter_results = color_jitter(results) assert self.check_keys_contain(color_jitter_results.keys(), target_keys) assert color_jitter_results['gt'].shape == self.gt.shape color_jitter = ColorJitter( keys=['gt', 'img'], channel_order='bgr', brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5) color_jitter_results = color_jitter(results) assert self.check_keys_contain(color_jitter_results.keys(), target_keys) assert color_jitter_results['gt'].shape == self.gt.shape assert np.abs(color_jitter_results['gt'] - self.gt.shape).mean() > 0 assert repr(color_jitter) == color_jitter.__class__.__name__ + ( f'(keys={color_jitter.keys}, ' f'channel_order={color_jitter.channel_order}, ' f'brightness={color_jitter._transform.brightness}, ' f'contrast={color_jitter._transform.contrast}, ' f'saturation={color_jitter._transform.saturation}, ' f'hue={color_jitter._transform.hue})') with pytest.raises(AssertionError): color_jitter = ColorJitter( keys=['gt', 'img'], channel_order='bgr', to_rgb=True, brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5) def test_random_affine(self): with pytest.raises(AssertionError): RandomAffine(None, -1) with pytest.raises(AssertionError): RandomAffine(None, 0, translate='Not a tuple') with pytest.raises(AssertionError): RandomAffine(None, 0, translate=(0, 0, 0)) with pytest.raises(AssertionError): RandomAffine(None, 0, translate=(0, 2)) with pytest.raises(AssertionError): RandomAffine(None, 0, scale='Not a tuple') with pytest.raises(AssertionError): RandomAffine(None, 0, scale=(0.8, 1., 1.2)) with pytest.raises(AssertionError): RandomAffine(None, 0, scale=(-0.8, 1.)) with pytest.raises(AssertionError): RandomAffine(None, 0, shear=-1) with pytest.raises(AssertionError): RandomAffine(None, 0, shear=(0, 1, 2)) with pytest.raises(AssertionError): RandomAffine(None, 0, flip_ratio='Not a float') target_keys = ['fg', 'alpha'] # Test identical transformation alpha = np.random.rand(4, 4).astype(np.float32) fg = np.random.rand(4, 4).astype(np.float32) results = dict(alpha=alpha, fg=fg) random_affine = RandomAffine(['fg', 'alpha'], degrees=0, flip_ratio=0.0) random_affine_results = random_affine(results) assert np.allclose(alpha, random_affine_results['alpha']) assert np.allclose(fg, random_affine_results['fg']) # Test flip in both direction fg = np.random.rand(4, 4).astype(np.float32) alpha = np.random.rand(4, 4).astype(np.float32) results = dict(alpha=alpha, fg=fg) random_affine = RandomAffine(['fg', 'alpha'], degrees=0, flip_ratio=1.0) random_affine_results = random_affine(results) assert np.allclose(alpha[::-1, ::-1], random_affine_results['alpha']) assert np.allclose(fg[::-1, ::-1], random_affine_results['fg']) # test random affine with different valid setting combinations # only shape are tested alpha = np.random.rand(240, 320, 1).astype(np.float32) fg = np.random.rand(240, 320, 3).astype(np.float32) results = dict(alpha=alpha, fg=fg) random_affine = RandomAffine(['fg', 'alpha'], degrees=30, translate=(0, 1), shear=(10, 20), flip_ratio=0.5) random_affine_results = random_affine(results) assert self.check_keys_contain(random_affine_results.keys(), target_keys) assert random_affine_results['fg'].shape == (240, 320, 3) assert random_affine_results['alpha'].shape == (240, 320, 1) alpha = np.random.rand(240, 320, 1).astype(np.float32) fg = np.random.rand(240, 320, 3).astype(np.float32) results = dict(alpha=alpha, fg=fg) random_affine = RandomAffine(['fg', 'alpha'], degrees=(-30, 30), scale=(0.8, 1.25), shear=10, flip_ratio=0.5) random_affine_results = random_affine(results) assert self.check_keys_contain(random_affine_results.keys(), target_keys) assert random_affine_results['fg'].shape == (240, 320, 3) assert random_affine_results['alpha'].shape == (240, 320, 1) alpha = np.random.rand(240, 320, 1).astype(np.float32) fg = np.random.rand(240, 320, 3).astype(np.float32) results = dict(alpha=alpha, fg=fg) random_affine = RandomAffine(['fg', 'alpha'], degrees=30) random_affine_results = random_affine(results) assert self.check_keys_contain(random_affine_results.keys(), target_keys) assert random_affine_results['fg'].shape == (240, 320, 3) assert random_affine_results['alpha'].shape == (240, 320, 1) assert repr(random_affine) == random_affine.__class__.__name__ + ( f'(keys={target_keys}, degrees={(-30, 30)}, ' f'translate={None}, scale={None}, ' f'shear={None}, flip_ratio={0})') def test_random_dilation(self): mask = np.zeros((3, 3, 1), dtype=np.float32) mask[1, 1] = 1 gt_mask = np.ones_like(mask) results = dict(mask=mask.copy()) dilation = RandomMaskDilation(['mask'], binary_thr=0.5, kernel_min=3, kernel_max=3) results = dilation(results) assert np.array_equal(results['mask'], gt_mask) assert results['mask_dilate_kernel_size'] == 3 assert str(dilation) == ( dilation.__class__.__name__ + f"(keys={['mask']}, kernel_min=3, kernel_max=3)") def test_unsharp_masking(self): results = {} unsharp_masking = UnsharpMasking( kernel_size=15, sigma=0, weight=0.5, threshold=10, keys=['gt']) # single image results['gt'] = np.zeros((8, 8, 3)).astype(np.float32) results = unsharp_masking(results) assert isinstance(results['gt_unsharp'], np.ndarray) # sequence of images results['gt'] = [np.zeros((8, 8, 3)).astype(np.float32)] * 2 results = unsharp_masking(results) assert isinstance(results['gt_unsharp'], list) assert repr(unsharp_masking) == unsharp_masking.__class__.__name__ + ( "(keys=['gt'], kernel_size=15, sigma=0, weight=0.5, threshold=10)") # kernel_size must be odd with pytest.raises(ValueError): unsharp_masking = UnsharpMasking( kernel_size=10, sigma=0, weight=0.5, threshold=10, keys=['gt']) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_aug_shape.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import numpy as np import pytest from mmagic.datasets.transforms import (CenterCropLongEdge, Flip, NumpyPad, RandomCropLongEdge, RandomRotation, RandomTransposeHW, Resize) class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.gt = np.random.randint(0, 256, (256, 128, 3), dtype=np.uint8) cls.img = np.random.randint(0, 256, (64, 32, 3), dtype=np.uint8) cls.results = dict( img=cls.img, gt=cls.gt, scale=4, img_path='fake_img_path', gt_path='fake_gt_path') cls.results['ori_img'] = np.random.randint( 0, 256, (256, 256, 3), dtype=np.uint8) cls.results['mask'] = np.random.randint( 0, 256, (256, 256, 1), dtype=np.uint8) # cls.results['img_tensor'] = torch.rand((3, 256, 256)) # cls.results['mask_tensor'] = torch.zeros((1, 256, 256)) # cls.results['mask_tensor'][:, 50:150, 40:140] = 1. @staticmethod def check_flip(origin_img, result_img, flip_direction): """Check if the origin_img are flipped correctly into result_img in different flip_directions. Args: origin_img (np.ndarray): Original image. result_img (np.ndarray): Result image. flip_direction (str): Direction of flip. Returns: bool: Whether origin_img == result_img. """ if flip_direction == 'horizontal': diff = result_img[:, ::-1] - origin_img else: diff = result_img[::-1, :] - origin_img return diff.max() < 1e-8 @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) @staticmethod def check_transposehw(origin_img, result_img): """Check if the origin_imgs are transposed correctly.""" h, w, c = origin_img.shape for i in range(c): for j in range(h): for k in range(w): if result_img[k, j, i] != origin_img[j, k, i]: # noqa:E501 return False return True def test_flip(self): results = copy.deepcopy(self.results) trans = Flip(keys='img', flip_ratio=0) assert trans.keys == ['img'] with pytest.raises(ValueError): Flip(keys=['img', 'gt'], direction='vertically') # horizontal np.random.seed(1) target_keys = ['img', 'gt', 'flip_infos'] flip = Flip(keys=['img', 'gt'], flip_ratio=1, direction='horizontal') assert 'flip_infos' not in results results = flip(results) assert results['flip_infos'] == [ dict( keys=['img', 'gt'], direction='horizontal', ratio=1, flip=True) ] assert self.check_keys_contain(results.keys(), target_keys) assert results['img'].shape == self.img.shape assert results['gt'].shape == self.gt.shape assert self.check_flip(self.img, results['img'], results['flip_infos'][-1]['direction']) assert self.check_flip(self.gt, results['gt'], results['flip_infos'][-1]['direction']) results = flip(results) assert results['flip_infos'] == [ dict( keys=['img', 'gt'], direction='horizontal', ratio=1, flip=True), dict( keys=['img', 'gt'], direction='horizontal', ratio=1, flip=True), ] # vertical results = copy.deepcopy(self.results) flip = Flip(keys=['img', 'gt'], flip_ratio=1, direction='vertical') results = flip(results) assert self.check_keys_contain(results.keys(), target_keys) assert results['img'].shape == self.img.shape assert results['gt'].shape == self.gt.shape assert self.check_flip(self.img, results['img'], results['flip_infos'][-1]['direction']) assert self.check_flip(self.gt, results['gt'], results['flip_infos'][-1]['direction']) assert repr(flip) == flip.__class__.__name__ + ( f"(keys={['img', 'gt']}, flip_ratio=1, " f"direction={results['flip_infos'][-1]['direction']})") # flip a list # horizontal flip = Flip(keys=['img', 'gt'], flip_ratio=1, direction='horizontal') results = dict( img=[self.img, np.copy(self.img)], gt=[self.gt, np.copy(self.gt)], scale=4, img_path='fake_img_path', gt_path='fake_gt_path') flip_rlt = flip(copy.deepcopy(results)) assert self.check_keys_contain(flip_rlt.keys(), target_keys) assert self.check_flip(self.img, flip_rlt['img'][0], flip_rlt['flip_infos'][-1]['direction']) assert self.check_flip(self.gt, flip_rlt['gt'][0], flip_rlt['flip_infos'][-1]['direction']) np.testing.assert_almost_equal(flip_rlt['gt'][0], flip_rlt['gt'][1]) np.testing.assert_almost_equal(flip_rlt['img'][0], flip_rlt['img'][1]) # vertical flip = Flip(keys=['img', 'gt'], flip_ratio=1, direction='vertical') flip_rlt = flip(copy.deepcopy(results)) assert self.check_keys_contain(flip_rlt.keys(), target_keys) assert self.check_flip(self.img, flip_rlt['img'][0], flip_rlt['flip_infos'][-1]['direction']) assert self.check_flip(self.gt, flip_rlt['gt'][0], flip_rlt['flip_infos'][-1]['direction']) np.testing.assert_almost_equal(flip_rlt['gt'][0], flip_rlt['gt'][1]) np.testing.assert_almost_equal(flip_rlt['img'][0], flip_rlt['img'][1]) # no flip flip = Flip(keys=['img', 'gt'], flip_ratio=0, direction='vertical') results = flip(copy.deepcopy(results)) assert self.check_keys_contain(results.keys(), target_keys) np.testing.assert_almost_equal(results['gt'][0], self.gt) np.testing.assert_almost_equal(results['img'][0], self.img) np.testing.assert_almost_equal(results['gt'][0], results['gt'][1]) np.testing.assert_almost_equal(results['img'][0], results['img'][1]) def test_random_rotation(self): with pytest.raises(ValueError): RandomRotation(None, degrees=-10.0) with pytest.raises(TypeError): RandomRotation(None, degrees=('0.0', '45.0')) target_keys = ['degrees'] results = copy.deepcopy(self.results) random_rotation = RandomRotation(['ori_img'], degrees=(0, 45)) random_rotation_results = random_rotation(results) assert self.check_keys_contain(random_rotation_results.keys(), target_keys) assert random_rotation_results['ori_img'].shape == (256, 256, 3) assert random_rotation_results['degrees'] == (0, 45) assert repr(random_rotation) == random_rotation.__class__.__name__ + ( "(keys=['ori_img'], degrees=(0, 45))") # test single degree integer random_rotation = RandomRotation(['ori_img'], degrees=45) random_rotation_results = random_rotation(results) assert self.check_keys_contain(random_rotation_results.keys(), target_keys) assert random_rotation_results['ori_img'].shape == (256, 256, 3) assert random_rotation_results['degrees'] == (-45, 45) # test image dim == 2 grey_scale_ori_img = np.random.rand(256, 256).astype(np.float32) results = dict(ori_img=grey_scale_ori_img.copy()) random_rotation = RandomRotation(['ori_img'], degrees=(0, 45)) random_rotation_results = random_rotation(results) assert self.check_keys_contain(random_rotation_results.keys(), target_keys) assert random_rotation_results['ori_img'].shape == (256, 256, 1) def test_random_transposehw(self): trans = RandomTransposeHW(keys='img', transpose_ratio=1) assert trans.keys == ['img'] results = self.results.copy() target_keys = ['img', 'gt', 'transpose'] transposehw = RandomTransposeHW(keys=['img', 'gt'], transpose_ratio=1) results = transposehw(results) assert self.check_keys_contain(results.keys(), target_keys) assert self.check_transposehw(self.img, results['img']) assert self.check_transposehw(self.gt, results['gt']) assert results['img'].shape == (32, 64, 3) assert results['gt'].shape == (128, 256, 3) assert repr(transposehw) == transposehw.__class__.__name__ + ( f"(keys={['img', 'gt']}, transpose_ratio=1)") # for image list ori_results = dict( img=[self.img, np.copy(self.img)], gt=[self.gt, np.copy(self.gt)], scale=4, img_path='fake_img_path', gt_path='fake_gt_path') target_keys = ['img', 'gt', 'transpose'] transposehw = RandomTransposeHW(keys=['img', 'gt'], transpose_ratio=1) results = transposehw(ori_results.copy()) assert self.check_keys_contain(results.keys(), target_keys) assert self.check_transposehw(self.img, results['img'][0]) assert self.check_transposehw(self.gt, results['gt'][1]) np.testing.assert_almost_equal(results['gt'][0], results['gt'][1]) np.testing.assert_almost_equal(results['img'][0], results['img'][1]) # no transpose target_keys = ['img', 'gt', 'transpose'] transposehw = RandomTransposeHW(keys=['img', 'gt'], transpose_ratio=0) results = transposehw(ori_results.copy()) assert self.check_keys_contain(results.keys(), target_keys) np.testing.assert_almost_equal(results['gt'][0], self.gt) np.testing.assert_almost_equal(results['img'][0], self.img) np.testing.assert_almost_equal(results['gt'][0], results['gt'][1]) np.testing.assert_almost_equal(results['img'][0], results['img'][1]) def test_resize(self): with pytest.raises(AssertionError): Resize([], scale=0.5) with pytest.raises(AssertionError): Resize(['gt_img'], size_factor=32, scale=0.5) with pytest.raises(AssertionError): Resize(['gt_img'], size_factor=32, keep_ratio=True) with pytest.raises(AssertionError): Resize(['gt_img'], max_size=32, size_factor=None) with pytest.raises(ValueError): Resize(['gt_img'], scale=-0.5) with pytest.raises(TypeError): Resize(['gt_img'], (0.4, 0.2)) with pytest.raises(TypeError): Resize(['gt_img'], dict(test=None)) target_keys = ['alpha'] alpha = np.random.rand(240, 320).astype(np.float32) results = dict(alpha=alpha) resize = Resize(keys=['alpha'], size_factor=32, max_size=None) resize_results = resize(results) assert self.check_keys_contain(resize_results.keys(), target_keys) assert resize_results['alpha'].shape == (224, 320, 1) resize = Resize(keys=['alpha'], size_factor=32, max_size=320) resize_results = resize(results) assert self.check_keys_contain(resize_results.keys(), target_keys) assert resize_results['alpha'].shape == (224, 320, 1) resize = Resize(keys=['alpha'], size_factor=32, max_size=200) resize_results = resize(results) assert self.check_keys_contain(resize_results.keys(), target_keys) assert resize_results['alpha'].shape == (192, 192, 1) resize = Resize(['gt_img'], (-1, 200)) assert resize.scale == (np.inf, 200) results = dict(gt_img=self.results['ori_img'].copy()) resize_keep_ratio = Resize(['gt_img'], scale=0.5, keep_ratio=True) results = resize_keep_ratio(results) assert results['gt_img'].shape[:2] == (128, 128) assert results['scale_factor'] == 0.5 results = dict(gt_img=self.results['ori_img'].copy()) resize_keep_ratio = Resize(['gt_img'], scale=(128, 128), keep_ratio=False) results = resize_keep_ratio(results) assert results['gt_img'].shape[:2] == (128, 128) # test input with shape (256, 256) results = dict( gt_img=self.results['ori_img'][..., 0].copy(), alpha=alpha) resize = Resize(['gt_img', 'alpha'], scale=(128, 128), keep_ratio=False, output_keys=['img', 'beta']) results = resize(results) assert results['gt_img'].shape == (256, 256) assert results['img'].shape == (128, 128, 1) assert results['alpha'].shape == (240, 320) assert results['beta'].shape == (128, 128, 1) name_ = str(resize_keep_ratio) assert name_ == resize_keep_ratio.__class__.__name__ + ( "(keys=['gt_img'], output_keys=['gt_img'], " 'scale=(128, 128), ' f'keep_ratio={False}, size_factor=None, ' 'max_size=None, interpolation=bilinear)') # test input with shape (256, 256) + out keys and metainfo copy results = dict( gt_img=self.results['ori_img'][..., 0].copy(), alpha=alpha, ori_alpha_shape=[3, 3], gt_img_channel_order='rgb', alpha_color_type='grayscale') resize = Resize(['gt_img', 'alpha'], scale=(128, 128), keep_ratio=False, output_keys=['img', 'beta']) results = resize(results) assert results['gt_img'].shape == (256, 256) assert results['img'].shape == (128, 128, 1) assert results['alpha'].shape == (240, 320) assert results['beta'].shape == (128, 128, 1) assert results['ori_beta_shape'] == [3, 3] assert results['img_channel_order'] == 'rgb' assert results['beta_color_type'] == 'grayscale' name_ = str(resize_keep_ratio) assert name_ == resize_keep_ratio.__class__.__name__ + ( "(keys=['gt_img'], output_keys=['gt_img'], " 'scale=(128, 128), ' f'keep_ratio={False}, size_factor=None, ' 'max_size=None, interpolation=bilinear)') def test_random_long_edge_crop(): results = dict(img=np.random.rand(256, 128, 3).astype(np.float32)) crop = RandomCropLongEdge(['img']) results = crop(results) assert results['img'].shape == (128, 128, 3) repr_str = crop.__class__.__name__ repr_str += (f'(keys={crop.keys})') assert str(crop) == repr_str def test_center_long_edge_crop(): results = dict(img=np.random.rand(256, 128, 3).astype(np.float32)) crop = CenterCropLongEdge(['img']) results = crop(results) assert results['img'].shape == (128, 128, 3) def test_numpy_pad(): results = dict(img=np.zeros((5, 5, 1))) pad = NumpyPad(['img'], ((2, 2), (0, 0), (0, 0))) results = pad(results) assert results['img'].shape == (9, 5, 1) repr_str = pad.__class__.__name__ repr_str += ( f'(keys={pad.keys}, padding={pad.padding}, kwargs={pad.kwargs})') assert str(pad) == repr_str def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_blur_kernels.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.datasets.transforms import blur_kernels def test_blur_kernels(): kernels = [ 'iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso', 'sinc' ] for kernel_type in kernels: kernel = blur_kernels.random_mixed_kernels([kernel_type], [1], 5) assert kernel.shape == (5, 5) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_crop.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import os.path as osp import unittest import cv2 import numpy as np import pytest import torch from mmagic.datasets.transforms import (Crop, CropLike, FixedCrop, InstanceCrop, ModCrop, PairedRandomCrop, RandomResizedCrop) class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.img_gt = np.random.rand(256, 128, 3).astype(np.float32) cls.img_lq = np.random.rand(64, 32, 3).astype(np.float32) cls.results = dict( img=cls.img_lq, gt=cls.img_gt, scale=4, lq_path='fake_lq_path', gt_path='fake_gt_path') cls.results['img'] = np.random.rand(256, 256, 3).astype(np.float32) cls.results['img_a'] = np.random.rand(286, 286, 3).astype(np.float32) cls.results['img_b'] = np.random.rand(286, 286, 3).astype(np.float32) def test_crop(self): with pytest.raises(TypeError): Crop(['img'], (0.23, 0.1)) # test center crop results = copy.deepcopy(self.results) center_crop = Crop(['img'], crop_size=(128, 128), random_crop=False) results = center_crop(results) assert results['img_crop_bbox'] == [64, 64, 128, 128] assert np.array_equal(self.results['img'][64:192, 64:192, :], results['img']) # test random crop results = copy.deepcopy(self.results) random_crop = Crop(['img'], crop_size=(128, 128), random_crop=True) results = random_crop(results) assert 0 <= results['img_crop_bbox'][0] <= 128 assert 0 <= results['img_crop_bbox'][1] <= 128 assert results['img_crop_bbox'][2] == 128 assert results['img_crop_bbox'][3] == 128 # test random crop for larger size than the original shape results = copy.deepcopy(self.results) random_crop = Crop(['img'], crop_size=(512, 512), random_crop=True) results = random_crop(results) assert np.array_equal(self.results['img'], results['img']) assert str(random_crop) == ( random_crop.__class__.__name__ + "keys=['img'], crop_size=(512, 512), random_crop=True") # test center crop for size larger than original shape results = copy.deepcopy(self.results) center_crop = Crop(['img'], crop_size=(512, 512), random_crop=False, is_pad_zeros=True) gt_pad = np.pad( copy.deepcopy(self.results)['img'], ((128, 128), (128, 128), (0, 0)), mode='constant', constant_values=0) results = center_crop(results) assert results['img_crop_bbox'] == [128, 128, 512, 512] assert np.array_equal(gt_pad, results['img']) def test_random_resized_crop(self): with pytest.raises(TypeError): RandomResizedCrop(['img'], crop_size=(0.23, 0.1)) with pytest.raises(TypeError): RandomResizedCrop(['img'], crop_size=(128, 128), scale=(1, 1)) with pytest.raises(TypeError): RandomResizedCrop(['img'], crop_size=(128, 128), scale=(0.5, 0.5), ratio=(1, 2)) # test random crop results = copy.deepcopy(self.results) random_resized_crop = RandomResizedCrop(['img'], crop_size=(128, 128)) results = random_resized_crop(results) assert 0 <= results['img_crop_bbox'][0] <= 256 assert 0 <= results['img_crop_bbox'][1] <= 256 assert results['img_crop_bbox'][2] <= 256 assert results['img_crop_bbox'][3] <= 256 assert results['img'].shape == (128, 128, 3) # test random crop with integer crop size results = copy.deepcopy(self.results) random_resized_crop = RandomResizedCrop(['img'], crop_size=128) results = random_resized_crop(results) assert 0 <= results['img_crop_bbox'][0] <= 256 assert 0 <= results['img_crop_bbox'][1] <= 256 assert results['img_crop_bbox'][2] <= 256 assert results['img_crop_bbox'][3] <= 256 assert results['img'].shape == (128, 128, 3) assert str(random_resized_crop) == ( random_resized_crop.__class__.__name__ + "(keys=['img'], crop_size=(128, 128), scale=(0.08, 1.0), " f'ratio={(3. / 4., 4. / 3.)}, interpolation=bilinear)') # test random crop for larger size than the original shape results = copy.deepcopy(self.results) random_resized_crop = RandomResizedCrop(['img'], crop_size=(512, 512)) results = random_resized_crop(results) assert results['img'].shape == (512, 512, 3) assert str(random_resized_crop) == ( random_resized_crop.__class__.__name__ + "(keys=['img'], crop_size=(512, 512), scale=(0.08, 1.0), " f'ratio={(3. / 4., 4. / 3.)}, interpolation=bilinear)') # test center crop for in_ratio < min(self.ratio) results = copy.deepcopy(self.results) center_crop = RandomResizedCrop(['img'], crop_size=(128, 128), ratio=(100.0, 200.0)) results = center_crop(results) assert results['img_crop_bbox'] == [126, 0, 256, 3] assert results['img'].shape == (128, 128, 3) # test center crop for in_ratio > max(self.ratio) results = copy.deepcopy(self.results) center_crop = RandomResizedCrop(['img'], crop_size=(128, 128), ratio=(0.01, 0.02)) results = center_crop(results) assert results['img_crop_bbox'] == [0, 125, 5, 256] assert results['img'].shape == (128, 128, 3) def test_fixed_crop(self): with pytest.raises(TypeError): FixedCrop(['img_a', 'img_b'], (0.23, 0.1)) with pytest.raises(TypeError): FixedCrop(['img_a', 'img_b'], (256, 256), (0, 0.1)) # test shape consistency results = copy.deepcopy(self.results) fixed_crop = FixedCrop(['img_a', 'img'], crop_size=(128, 128)) with pytest.raises(ValueError): results = fixed_crop(results) # test sequence results = copy.deepcopy(self.results) results['img_a'] = [results['img_a'], results['img_a']] results['img_b'] = [results['img_b'], results['img_b']] fixed_crop = FixedCrop(['img_a', 'img_b'], crop_size=(128, 128)) results = fixed_crop(results) for img in results['img_a']: assert img.shape == (128, 128, 3) for img in results['img_b']: assert img.shape == (128, 128, 3) # test given pos crop results = copy.deepcopy(self.results) given_pos_crop = FixedCrop(['img_a', 'img_b'], crop_size=(256, 256), crop_pos=(1, 1)) results = given_pos_crop(results) assert results['img_a_crop_bbox'] == [1, 1, 256, 256] assert results['img_b_crop_bbox'] == [1, 1, 256, 256] assert np.array_equal(self.results['img_a'][1:257, 1:257, :], results['img_a']) assert np.array_equal(self.results['img_b'][1:257, 1:257, :], results['img_b']) # test given pos crop if pos > suitable pos results = copy.deepcopy(self.results) given_pos_crop = FixedCrop(['img_a', 'img_b'], crop_size=(256, 256), crop_pos=(280, 280)) results = given_pos_crop(results) assert results['img_a_crop_bbox'] == [280, 280, 6, 6] assert results['img_b_crop_bbox'] == [280, 280, 6, 6] assert np.array_equal(self.results['img_a'][280:, 280:, :], results['img_a']) assert np.array_equal(self.results['img_b'][280:, 280:, :], results['img_b']) assert str(given_pos_crop) == ( given_pos_crop.__class__.__name__ + "keys=['img_a', 'img_b'], crop_size=(256, 256), " + 'crop_pos=(280, 280)') # test random initialized fixed crop results = copy.deepcopy(self.results) random_fixed_crop = FixedCrop(['img_a', 'img_b'], crop_size=(256, 256), crop_pos=None) results = random_fixed_crop(results) assert 0 <= results['img_a_crop_bbox'][0] <= 30 assert 0 <= results['img_a_crop_bbox'][1] <= 30 assert results['img_a_crop_bbox'][2] == 256 assert results['img_a_crop_bbox'][3] == 256 x_offset, y_offset, crop_w, crop_h = results['img_a_crop_bbox'] assert x_offset == results['img_b_crop_bbox'][0] assert y_offset == results['img_b_crop_bbox'][1] assert crop_w == results['img_b_crop_bbox'][2] assert crop_h == results['img_b_crop_bbox'][3] assert np.array_equal( self.results['img_a'][y_offset:y_offset + crop_h, x_offset:x_offset + crop_w, :], results['img_a']) assert np.array_equal( self.results['img_b'][y_offset:y_offset + crop_h, x_offset:x_offset + crop_w, :], results['img_b']) # test given pos crop for lager size than the original shape results = copy.deepcopy(self.results) given_pos_crop = FixedCrop(['img_a', 'img_b'], crop_size=(512, 512), crop_pos=(1, 1)) results = given_pos_crop(results) assert results['img_a_crop_bbox'] == [1, 1, 285, 285] assert results['img_b_crop_bbox'] == [1, 1, 285, 285] assert np.array_equal(self.results['img_a'][1:, 1:, :], results['img_a']) assert np.array_equal(self.results['img_b'][1:, 1:, :], results['img_b']) assert str(given_pos_crop) == ( given_pos_crop.__class__.__name__ + "keys=['img_a', 'img_b'], crop_size=(512, 512), crop_pos=(1, 1)") # test random initialized fixed crop for lager size # than the original shape results = copy.deepcopy(self.results) random_fixed_crop = FixedCrop(['img_a', 'img_b'], crop_size=(512, 512), crop_pos=None) results = random_fixed_crop(results) assert results['img_a_crop_bbox'] == [0, 0, 286, 286] assert results['img_b_crop_bbox'] == [0, 0, 286, 286] assert np.array_equal(self.results['img_a'], results['img_a']) assert np.array_equal(self.results['img_b'], results['img_b']) assert str(random_fixed_crop) == ( random_fixed_crop.__class__.__name__ + "keys=['img_a', 'img_b'], crop_size=(512, 512), crop_pos=None") def test_modcrop(self): # color image results = dict(gt=np.random.randn(257, 258, 3), scale=4) modcrop = ModCrop() results = modcrop(results) assert results['gt'].shape == (256, 256, 3) # gray image results = dict(gt=np.random.randn(257, 258), scale=4) results = modcrop(results) assert results['gt'].shape == (256, 256) # Wrong img ndim with pytest.raises(ValueError): results = dict(gt=np.random.randn(1, 257, 258, 3), scale=4) results = modcrop(results) assert repr(modcrop) == ( modcrop.__class__.__name__ + f'(key={modcrop.key})') def test_paired_random_crop(self): results = dict( gt=np.random.randn(256, 128, 3), img=np.random.randn(64, 32, 3), scale=4, gt_path='fake_gt_path', img_path='fake_lq_path') pairedrandomcrop = PairedRandomCrop(128) results = pairedrandomcrop(results) assert results['gt'].shape == (128, 128, 3) assert results['img'].shape == (32, 32, 3) # Scale mismatches. GT (h, w) is not {scale} multiplication of LQ's. with pytest.raises(ValueError): results = dict( gt=np.random.randn(128, 128, 3), img=np.random.randn(64, 64, 3), scale=4, gt_path='fake_gt_path', img_path='fake_lq_path') results = pairedrandomcrop(results) # LQ (h, w) is smaller than patch size. with pytest.raises(ValueError): results = dict( gt=np.random.randn(32, 32, 3), img=np.random.randn(8, 8, 3), scale=4, gt_path='fake_gt_path', img_path='fake_lq_path') results = pairedrandomcrop(results) assert repr(pairedrandomcrop) == ( pairedrandomcrop.__class__.__name__ + (f'(gt_patch_size={pairedrandomcrop.gt_patch_size}, ' f'lq_key={pairedrandomcrop.lq_key}, ' f'gt_key={pairedrandomcrop.gt_key})')) # for image list results = dict( img=[self.img_lq, self.img_lq], gt=[self.img_gt, self.img_gt], scale=4, img_path='fake_lq_path', gt_path='fake_gt_path') pairedrandomcrop = PairedRandomCrop(128) results = pairedrandomcrop(results) for v in results['gt']: assert v.shape == (128, 128, 3) for v in results['img']: assert v.shape == (32, 32, 3) np.testing.assert_almost_equal(results['gt'][0], results['gt'][1]) np.testing.assert_almost_equal(results['img'][0], results['img'][1]) def test_crop_like(): img = np.uint8(np.random.randn(480, 640, 3) * 255) img_ref = np.uint8(np.random.randn(512, 512, 3) * 255) inputs = dict(gt=img, ref=img_ref) crop_like = CropLike(target_key='gt', reference_key='ref') results = crop_like(inputs) assert set(list(results.keys())) == set(['gt', 'ref']) assert repr(crop_like) == ( crop_like.__class__.__name__ + f' target_key={crop_like.target_key}, ' + f'reference_key={crop_like.reference_key}') assert results['gt'].shape == (512, 512, 3) sum_diff = np.sum(abs(results['gt'][:480, :512] - img[:480, :512])) assert sum_diff < 1e-6 inputs = dict(gt=img, ref=img_ref[:, :, 0]) crop_like = CropLike(target_key='gt', reference_key='ref') results = crop_like(inputs) assert set(list(results.keys())) == set(['gt', 'ref']) assert results['gt'].shape == (512, 512, 3) sum_diff = np.sum(abs(results['gt'][:480, :512] - img[:480, :512])) assert sum_diff < 1e-6 inputs = dict(gt=img[:, :, 0], ref=img_ref) crop_like = CropLike(target_key='gt', reference_key='ref') results = crop_like(inputs) assert set(list(results.keys())) == set(['gt', 'ref']) assert results['gt'].shape == (512, 512) sum_diff = np.sum(abs(results['gt'][:480, :512] - img[:480, :512, 0])) assert sum_diff < 1e-6 def test_instance_crop(): if not torch.cuda.is_available(): # RoI pooling only support in GPU return unittest.skip('test requires GPU and torch+cuda') croper = InstanceCrop( key='img', finesize=256, box_num_upbound=2, config_file='mmdet::mask_rcnn/' 'mask-rcnn_x101-32x8d_fpn_ms-poly-3x_coco.py') # noqa img_path = osp.join( osp.dirname(__file__), '..', '..', 'data/image/img_root/horse/horse.jpeg') img = cv2.imread(img_path) data = dict(img=img, ori_img_shape=img.shape, img_channel_order='rgb') results = croper(data) assert 'empty_box' in results if results['empty_box']: cropped_img = results['cropped_img'] assert len(cropped_img) == 0 assert len(cropped_img) <= 2 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_fgbg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from pathlib import Path import numpy as np import pytest from mmengine.fileio import load from mmagic.datasets.transforms import (CompositeFg, MergeFgAndBg, PerturbBg, RandomJitter, RandomLoadResizeBg) test_root = Path(__file__).parent.parent.parent data_root = test_root / 'data' / 'matting_dataset' def assert_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" assert set(target_keys).issubset(set(result_keys)) def test_composite_fg(): target_keys = ['alpha', 'fg', 'bg'] fg = np.random.rand(32, 32, 3).astype(np.float32) bg = np.random.rand(32, 32, 3).astype(np.float32) alpha = np.random.rand(32, 32, 1).astype(np.float32) results = dict(alpha=alpha, fg=fg, bg=bg) # use merged dir as fake fg dir, trimap dir as fake alpha dir for unittest composite_fg = CompositeFg( [str(data_root / 'fg'), str(data_root / 'merged')], [str(data_root / 'alpha'), str(data_root / 'trimap')]) correct_fg_list = [ str(data_root / 'fg' / 'GT05.jpg'), str(data_root / 'merged' / 'GT05.jpg') ] correct_alpha_list = [ str(data_root / 'alpha' / 'GT05.jpg'), str(data_root / 'trimap' / 'GT05.png') ] assert composite_fg.fg_list == correct_fg_list assert composite_fg.alpha_list == correct_alpha_list for _ in range(3): # to test randomness composite_fg_results = composite_fg(results) assert_keys_contain(composite_fg_results.keys(), target_keys) assert composite_fg_results['fg'].shape == (32, 32, 3) assert composite_fg_results['alpha'].shape == (32, 32, 1) fg = np.random.rand(32, 32, 3).astype(np.float32) bg = np.random.rand(32, 32, 3).astype(np.float32) alpha = np.random.rand(32, 32, 1).astype(np.float32) results = dict(alpha=alpha, fg=fg, bg=bg) composite_fg = CompositeFg( str(data_root / 'fg'), str(data_root / 'alpha'), interpolation='bilinear') for _ in range(3): # to test randomness composite_fg_results = composite_fg(results) assert_keys_contain(composite_fg_results.keys(), target_keys) assert composite_fg_results['fg'].shape == (32, 32, 3) assert composite_fg_results['alpha'].shape == (32, 32, 1) _fg_dirs = str(data_root / 'fg') _alpha_dirs = str(data_root / 'alpha') strs = (f"(fg_dirs=['{_fg_dirs}'], " f"alpha_dirs=['{_alpha_dirs}'], " "interpolation='bilinear')") assert repr(composite_fg) == 'CompositeFg' + strs.replace('\\', '\\\\') def test_merge_fg_and_bg(): target_keys = ['fg', 'bg', 'alpha', 'merged'] fg = np.random.randn(32, 32, 3) bg = np.random.randn(32, 32, 3) alpha = np.random.randn(32, 32, 1) results = dict(fg=fg, bg=bg, alpha=alpha) merge_fg_and_bg = MergeFgAndBg() merge_fg_and_bg_results = merge_fg_and_bg(results) assert_keys_contain(merge_fg_and_bg_results.keys(), target_keys) assert merge_fg_and_bg_results['merged'].shape == fg.shape assert merge_fg_and_bg_results['alpha'].shape == (32, 32, 1) def test_perturb_bg(): with pytest.raises(ValueError): # gammma_ratio must be a float between [0, 1] PerturbBg(-0.5) with pytest.raises(ValueError): # gammma_ratio must be a float between [0, 1] PerturbBg(1.1) target_keys = ['bg', 'noisy_bg'] # set a random seed to make sure the test goes through every branch np.random.seed(123) img_shape = (32, 32, 3) results = dict(bg=np.random.randint(0, 255, img_shape)) perturb_bg = PerturbBg(0.6) perturb_bg_results = perturb_bg(results) assert_keys_contain(perturb_bg_results.keys(), target_keys) assert perturb_bg_results['noisy_bg'].shape == img_shape img_shape = (32, 32, 3) results = dict(bg=np.random.randint(0, 255, img_shape)) perturb_bg = PerturbBg(0.6) perturb_bg_results = perturb_bg(results) assert_keys_contain(perturb_bg_results.keys(), target_keys) assert perturb_bg_results['noisy_bg'].shape == img_shape repr_str = perturb_bg.__class__.__name__ + '(gamma_ratio=0.6)' assert repr(perturb_bg) == repr_str def test_random_jitter(): with pytest.raises(AssertionError): RandomJitter(-40) with pytest.raises(AssertionError): RandomJitter((-40, 40, 40)) target_keys = ['fg'] fg = np.random.rand(240, 320, 3).astype(np.float32) alpha = np.random.rand(240, 320, 1).astype(np.float32) results = dict(fg=fg.copy(), alpha=alpha) random_jitter = RandomJitter(40) random_jitter_results = random_jitter(results) assert_keys_contain(random_jitter_results.keys(), target_keys) assert random_jitter_results['fg'].shape == (240, 320, 3) fg = np.random.rand(240, 320, 3).astype(np.float32) alpha = np.random.rand(240, 320, 1).astype(np.float32) results = dict(fg=fg.copy(), alpha=alpha) random_jitter = RandomJitter((-50, 50)) random_jitter_results = random_jitter(results) assert_keys_contain(random_jitter_results.keys(), target_keys) assert random_jitter_results['fg'].shape == (240, 320, 3) assert repr(random_jitter) == random_jitter.__class__.__name__ + ( 'hue_range=(-50, 50)') def test_random_load_resize_bg(): ann_file = data_root / 'ann_old.json' bg_dir = data_root / 'bg' data_infos = load(ann_file) results = dict() for data_info in data_infos: for key in data_info: results[key] = str(data_root / data_info[key]) target_keys = ['bg'] results = dict(fg=np.random.rand(128, 128)) random_load_bg = RandomLoadResizeBg(bg_dir=bg_dir) for _ in range(2): random_load_bg_results = random_load_bg(results) """Check if all elements in target_keys is in result_keys.""" assert set(target_keys).issubset(set(random_load_bg_results.keys())) assert isinstance(random_load_bg_results['bg'], np.ndarray) assert random_load_bg_results['bg'].shape == (128, 128, 3) assert repr( random_load_bg) == f"RandomLoadResizeBg(bg_dir='{str(bg_dir)}')" def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_formatting.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmcv.transforms import to_tensor from mmagic.datasets.transforms import PackInputs from mmagic.structures.data_sample import DataSample def assert_tensor_equal(img, ref_img, ratio_thr=0.999): """Check if img and ref_img are matched approximately.""" assert img.shape == ref_img.shape assert img.dtype == ref_img.dtype area = ref_img.shape[-1] * ref_img.shape[-2] diff = torch.abs(img - ref_img) assert torch.sum(diff <= 1) / float(area) > ratio_thr def test_pack_inputs(): pack_inputs = PackInputs(meta_keys='a', data_keys='numpy') assert repr(pack_inputs) == 'PackInputs' ori_results = dict( img=np.random.rand(64, 64, 3), gt=[np.random.rand(64, 61, 3), np.random.rand(64, 61, 3)], img_lq=np.random.rand(64, 64, 3), ref=np.random.rand(64, 62, 3), ref_lq=np.random.rand(64, 62, 3), mask=np.random.rand(64, 63, 3), gt_heatmap=np.random.rand(64, 65, 3), gt_unsharp=np.random.rand(64, 65, 3), merged=np.random.rand(64, 64, 3), trimap=np.random.rand(64, 66, 3), alpha=np.random.rand(64, 67, 3), fg=np.random.rand(64, 68, 3), bg=np.random.rand(64, 69, 3), img_shape=(64, 64), a='b', numpy=np.random.rand(48, 48, 3)) results = ori_results.copy() packed_results = pack_inputs(results) target_keys = ['inputs', 'data_samples'] assert set(target_keys).issubset(set(packed_results.keys())) data_sample = packed_results['data_samples'] assert isinstance(data_sample, DataSample) assert data_sample.img_shape == (64, 64) assert data_sample.a == 'b' numpy_tensor = to_tensor(ori_results['numpy']) numpy_tensor = numpy_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.numpy, numpy_tensor) gt_tensors = [to_tensor(v) for v in ori_results['gt']] gt_tensors = [v.permute(2, 0, 1) for v in gt_tensors] gt_tensor = torch.stack(gt_tensors, dim=0) assert_tensor_equal(data_sample.gt_img, gt_tensor) img_lq_tensor = to_tensor(ori_results['ref']) img_lq_tensor = img_lq_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.ref_img, img_lq_tensor) ref_lq_tensor = to_tensor(ori_results['ref']) ref_lq_tensor = ref_lq_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.ref_img, ref_lq_tensor) ref_tensor = to_tensor(ori_results['ref']) ref_tensor = ref_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.ref_img, ref_tensor) mask_tensor = to_tensor(ori_results['mask']) mask_tensor = mask_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.mask, mask_tensor) gt_heatmap_tensor = to_tensor(ori_results['gt_heatmap']) gt_heatmap_tensor = gt_heatmap_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_heatmap, gt_heatmap_tensor) gt_unsharp_tensor = to_tensor(ori_results['gt_heatmap']) gt_unsharp_tensor = gt_unsharp_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_heatmap, gt_unsharp_tensor) gt_merged_tensor = to_tensor(ori_results['merged']) gt_merged_tensor = gt_merged_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_merged, gt_merged_tensor) trimap_tensor = to_tensor(ori_results['trimap']) trimap_tensor = trimap_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.trimap, trimap_tensor) gt_alpha_tensor = to_tensor(ori_results['alpha']) gt_alpha_tensor = gt_alpha_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_alpha, gt_alpha_tensor) gt_fg_tensor = to_tensor(ori_results['fg']) gt_fg_tensor = gt_fg_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_fg, gt_fg_tensor) gt_bg_tensor = to_tensor(ori_results['bg']) gt_bg_tensor = gt_bg_tensor.permute(2, 0, 1) assert_tensor_equal(data_sample.gt_bg, gt_bg_tensor) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_generate_assistant.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.datasets.transforms import (GenerateCoordinateAndCell, GenerateFacialHeatmap, LoadImageFromFile) def test_generate_coordinate_and_cell(): tensor1 = torch.randn((3, 64, 48)) inputs1 = dict(lq=tensor1) coordinate1 = GenerateCoordinateAndCell(scale=3.1, target_size=(128, 96)) results1 = coordinate1(inputs1) assert set(list(results1.keys())) == set(['lq', 'coord', 'cell']) assert repr(coordinate1) == ( coordinate1.__class__.__name__ + f'(sample_quantity={coordinate1.sample_quantity}, ' + f'scale={coordinate1.scale}, ' + f'target_size={coordinate1.target_size}, ' + f'reshape_gt={coordinate1.reshape_gt})') tensor2 = torch.randn((3, 64, 48)) inputs2 = dict(gt=tensor2) coordinate2 = GenerateCoordinateAndCell( sample_quantity=64 * 48, scale=3.1, target_size=(128, 96)) results2 = coordinate2(inputs2) assert set(list(results2.keys())) == set(['gt', 'coord', 'cell']) assert results2['gt'].shape == (64 * 48, 3) inputs3 = dict() coordinate3 = GenerateCoordinateAndCell( sample_quantity=64 * 48, scale=3.1, target_size=(128, 96)) results3 = coordinate3(inputs3) assert set(list(results3.keys())) == set(['coord', 'cell']) def test_generate_facial_heatmap(): results = dict(gt_path='tests/data/image/face/000001.png', key='000001') loader = LoadImageFromFile(key='gt', channel_order='rgb') results = loader(results) generate_heatmap = GenerateFacialHeatmap('gt', 256, 32) results1 = generate_heatmap(results) results1 = generate_heatmap(results) assert set(list(results1.keys())) == set([ 'gt_path', 'gt', 'ori_gt_shape', 'gt_heatmap', 'key', 'gt_channel_order', 'gt_color_type' ]) assert results1['gt_heatmap'].shape == (32, 32, 68) generate_heatmap = GenerateFacialHeatmap('gt', (256, 256), (32, 64)) results2 = generate_heatmap(results) assert set(list(results2.keys())) == set([ 'gt_path', 'gt', 'ori_gt_shape', 'gt_heatmap', 'key', 'gt_channel_order', 'gt_color_type' ]) assert results2['gt_heatmap'].shape == (32, 64, 68) generate_heatmap = GenerateFacialHeatmap( 'gt', (256, 256), (32, 64), use_cache=False) results2 = generate_heatmap(results) assert set(list(results2.keys())) == set([ 'gt_path', 'gt', 'ori_gt_shape', 'gt_heatmap', 'key', 'gt_channel_order', 'gt_color_type' ]) assert results2['gt_heatmap'].shape == (32, 64, 68) assert repr(generate_heatmap) == ( generate_heatmap.__class__.__name__ + f'(image_key={generate_heatmap.image_key}, ' + f'ori_size={generate_heatmap.ori_size}, ' + f'target_size={generate_heatmap.target_size}, ' + f'sigma={generate_heatmap.sigma}, ' f'use_cache={generate_heatmap.use_cache})') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_generate_frame_indices.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import os.path as osp import numpy as np import pytest from mmagic.datasets.transforms import (GenerateFrameIndices, GenerateFrameIndiceswithPadding, GenerateSegmentIndices) class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.gt = np.random.randint(0, 256, (256, 128, 3), dtype=np.uint8) cls.img = np.random.randint(0, 256, (64, 32, 3), dtype=np.uint8) cls.results = dict( img=cls.img, gt=cls.gt, scale=4, img_path='fake_img_path', gt_path='fake_gt_path') cls.results['ori_img'] = np.random.randint( 0, 256, (256, 256, 3), dtype=np.uint8) cls.results['mask'] = np.random.randint( 0, 256, (256, 256, 1), dtype=np.uint8) # cls.results['img_tensor'] = torch.rand((3, 256, 256)) # cls.results['mask_tensor'] = torch.zeros((1, 256, 256)) # cls.results['mask_tensor'][:, 50:150, 40:140] = 1. @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) def test_frame_index_generator(self): results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key=osp.join('000', '00000010'), num_input_frames=3) target_keys = ['img_path', 'gt_path', 'key', 'interval'] frame_index_generator = GenerateFrameIndices( interval_list=[1], frames_per_clip=99) rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) name_ = repr(frame_index_generator) assert name_ == frame_index_generator.__class__.__name__ + ( '(interval_list=[1], frames_per_clip=99)') # index out of range frame_index_generator = GenerateFrameIndices(interval_list=[10]) rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) # index out of range results['key'] = osp.join('000', '00000099') frame_index_generator = GenerateFrameIndices(interval_list=[2, 3]) rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) def test_frame_index_generation_with_padding(self): with pytest.raises(ValueError): # Wrong padding mode GenerateFrameIndiceswithPadding(padding='fake') results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key=osp.join('000', '00000000'), sequence_length=100, num_input_frames=5) target_keys = ['img_path', 'gt_path', 'key'] replicate_idx = [0, 0, 0, 1, 2] reflection_idx = [2, 1, 0, 1, 2] reflection_circle_idx = [4, 3, 0, 1, 2] circle_idx = [3, 4, 0, 1, 2] # replicate img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in replicate_idx ] gt_paths = [osp.join('fake_gt_root', '000', '00000000.png')] frame_index_generator = GenerateFrameIndiceswithPadding( padding='replicate') rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # reflection img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in reflection_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='reflection') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # reflection_circle img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in reflection_circle_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='reflection_circle') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # circle img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in circle_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='circle') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key=osp.join('000', '00000099'), sequence_length=100, num_input_frames=5) target_keys = ['img_path', 'gt_path', 'key'] replicate_idx = [97, 98, 99, 99, 99] reflection_idx = [97, 98, 99, 98, 97] reflection_circle_idx = [97, 98, 99, 96, 95] circle_idx = [97, 98, 99, 95, 96] # replicate img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in replicate_idx ] gt_paths = [osp.join('fake_gt_root', '000', '00000099.png')] frame_index_generator = GenerateFrameIndiceswithPadding( padding='replicate') rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # reflection img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in reflection_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='reflection') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # reflection_circle img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in reflection_circle_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='reflection_circle') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths # circle img_paths = [ osp.join('fake_img_root', '000', f'{v:08d}.png') for v in circle_idx ] frame_index_generator = GenerateFrameIndiceswithPadding( padding='circle') rlt = frame_index_generator(copy.deepcopy(results)) assert rlt['img_path'] == img_paths assert rlt['gt_path'] == gt_paths name_ = repr(frame_index_generator) assert name_ == frame_index_generator.__class__.__name__ + ( "(padding='circle')") def test_frame_index_generation_for_recurrent(self): results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key='000', num_input_frames=10, sequence_length=100) target_keys = [ 'img_path', 'gt_path', 'key', 'interval', 'num_input_frames', 'sequence_length', ] frame_index_generator = GenerateSegmentIndices(interval_list=[1, 5, 9]) rlt = frame_index_generator(copy.deepcopy(results)) assert self.check_keys_contain(rlt.keys(), target_keys) name_ = repr(frame_index_generator) assert name_ == frame_index_generator.__class__.__name__ + ( '(interval_list=[1, 5, 9])') # interval too large results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key='000', num_input_frames=11, sequence_length=100) frame_index_generator = GenerateSegmentIndices(interval_list=[10]) with pytest.raises(ValueError): frame_index_generator(copy.deepcopy(results)) # num_input_frames is None results = dict( img_path='fake_img_root', gt_path='fake_gt_root', key='000', num_input_frames=None, sequence_length=100) frame_index_generator = GenerateSegmentIndices(interval_list=[1]) rlt = frame_index_generator(copy.deepcopy(results)) assert len(rlt['img_path']) == 100 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_get_masked_image.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np from mmagic.datasets.transforms import GetMaskedImage def test_masked_img(): img = np.random.rand(4, 4, 3).astype(np.float32) mask = np.zeros((4, 4, 1), dtype=np.float32) mask[1, 1] = 1 results = dict(gt=img, mask=mask) get_masked_img = GetMaskedImage(zero_value=0) results = get_masked_img(results) masked_img = img * (1. - mask) assert np.array_equal(results['img'], masked_img) name_ = repr(get_masked_img) class_name = get_masked_img.__class__.__name__ assert name_ == class_name + ("(img_key='gt', mask_key='mask'" ", out_key='img', zero_value=0)") # test copy meta info results = dict( gt=img, mask=mask, ori_gt_shape=img.shape, gt_channel_order='rgb', gt_color_type='color') get_masked_img = GetMaskedImage(zero_value=0) results = get_masked_img(results) assert results['ori_img_shape'] == img.shape assert results['img_channel_order'] == 'rgb' assert results['img_color_type'] == 'color' def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_loading.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from pathlib import Path import mmcv import numpy as np import pytest from mmengine.fileio.backends import LocalBackend from mmagic.datasets.transforms import (GetSpatialDiscountMask, LoadImageFromFile, LoadMask) def test_load_image_from_file(): path_baboon = Path( __file__).parent.parent.parent / 'data' / 'image' / 'gt' / 'baboon.png' img_baboon = mmcv.imread(str(path_baboon), flag='color') h, w, _ = img_baboon.shape path_baboon_x4 = Path( __file__ ).parent.parent.parent / 'data' / 'image' / 'lq' / 'baboon_x4.png' img_baboon_x4 = mmcv.imread(str(path_baboon_x4), flag='color') # read gt image # input path is Path object results = dict(gt_path=path_baboon) config = dict(key='gt') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['gt'].shape == (h, w, 3) assert results['ori_gt_shape'] == (h, w, 3) np.testing.assert_almost_equal(results['gt'], img_baboon) assert results['gt_path'] == path_baboon # input path is str results = dict(gt_path=str(path_baboon)) results = image_loader(results) assert results['gt'].shape == (h, w, 3) assert results['ori_gt_shape'] == (h, w, 3) np.testing.assert_almost_equal(results['gt'], img_baboon) assert results['gt_path'] == str(path_baboon) assert results['gt_channel_order'] == 'bgr' assert results['gt_color_type'] == 'color' # read input image # input path is Path object results = dict(img_path=path_baboon_x4) config = dict(key='img') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['img'].shape == (h // 4, w // 4, 3) np.testing.assert_almost_equal(results['img'], img_baboon_x4) assert results['img_path'] == path_baboon_x4 # input path is str results = dict(img_path=str(path_baboon_x4)) results = image_loader(results) assert results['img'].shape == (h // 4, w // 4, 3) np.testing.assert_almost_equal(results['img'], img_baboon_x4) assert results['img_path'] == str(path_baboon_x4) assert repr(image_loader) == ( image_loader.__class__.__name__ + ('(key=img, color_type=color, channel_order=bgr, ' 'imdecode_backend=None, use_cache=False, to_float32=False, ' 'to_y_channel=False, save_original_img=False, ' 'backend_args=None)')) assert isinstance(image_loader.file_backend, LocalBackend) # test save_original_img results = dict(img_path=path_baboon) config = dict(key='img', color_type='grayscale', save_original_img=True) image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['img'].shape == (h, w, 1) assert results['ori_img_shape'] == (h, w, 1) np.testing.assert_almost_equal(results['ori_img'], results['img']) assert id(results['ori_img']) != id(results['img']) assert results['img_channel_order'] == 'bgr' assert results['img_color_type'] == 'grayscale' # test: use_cache results = dict(gt_path=path_baboon) config = dict(key='gt', use_cache=True) image_loader = LoadImageFromFile(**config) assert image_loader.cache == dict() assert repr(image_loader) == ( image_loader.__class__.__name__ + ('(key=gt, color_type=color, channel_order=bgr, ' 'imdecode_backend=None, use_cache=True, to_float32=False, ' 'to_y_channel=False, save_original_img=False, ' 'backend_args=None)')) results = image_loader(results) assert image_loader.cache is not None assert str(path_baboon) in image_loader.cache assert results['gt'].shape == (h, w, 3) assert results['gt_path'] == path_baboon np.testing.assert_almost_equal(results['gt'], img_baboon) assert isinstance(image_loader.file_backend, LocalBackend) assert results['gt_channel_order'] == 'bgr' assert results['gt_color_type'] == 'color' # convert to y-channel (bgr2y) results = dict(gt_path=path_baboon) config = dict(key='gt', to_y_channel=True, to_float32=True) image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['gt'].shape == (h, w, 1) img_baboon_y = mmcv.bgr2ycbcr(img_baboon, y_only=True) img_baboon_y = np.expand_dims(img_baboon_y, axis=2) np.testing.assert_almost_equal(results['gt'], img_baboon_y) assert results['gt_path'] == path_baboon assert results['gt_channel_order'] == 'bgr' assert results['gt_color_type'] == 'color' # convert to y-channel (rgb2y) results = dict(gt_path=path_baboon) config = dict( key='gt', channel_order='rgb', to_y_channel=True, to_float32=True) image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['gt'].shape == (h, w, 1) img_baboon_y = mmcv.bgr2ycbcr(img_baboon, y_only=True) img_baboon_y = np.expand_dims(img_baboon_y, axis=2) np.testing.assert_almost_equal(results['gt'], img_baboon_y) # test frames # input path is Path object results = dict(gt_path=[path_baboon]) config = dict(key='gt', save_original_img=True) image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['gt'][0].shape == (h, w, 3) assert results['ori_gt_shape'] == [(h, w, 3)] np.testing.assert_almost_equal(results['gt'][0], img_baboon) assert results['gt_path'] == [path_baboon] # input path is str results = dict(gt_path=[str(path_baboon)]) results = image_loader(results) assert results['gt'][0].shape == (h, w, 3) assert results['ori_gt_shape'] == [(h, w, 3)] np.testing.assert_almost_equal(results['gt'][0], img_baboon) assert results['gt_path'] == [str(path_baboon)] # test lmdb results = dict(img_path=path_baboon) config = dict( key='img', backend_args=dict( backend='lmdb', db_path=Path(__file__).parent.parent.parent / 'data' / 'lq.lmdb')) image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['img'].shape == (h // 4, w // 4, 3) assert results['ori_img_shape'] == (h // 4, w // 4, 3) assert results['img_path'] == path_baboon # convert to y-channel (ValueError) results = dict(gt_path=path_baboon) config = dict(key='gt', to_y_channel=True, channel_order='gg') image_loader = LoadImageFromFile(**config) with pytest.raises(ValueError): results = image_loader(results) # test infer from s3 from mmengine.fileio import PetrelBackend PetrelBackend.get = lambda self, filepath: filepath results = dict(img_path='openmmlab:s3://abcd/efg/') config = dict(key='img') image_loader = LoadImageFromFile(**config) try: import petrel_client # noqa: F401 except ImportError: with pytest.raises(ImportError) as excinfo: results = image_loader(results) assert 'Please install petrel_client to enable PetrelBackend.' in str( excinfo.value) else: results = image_loader(results) assert results['img'] == 'openmmlab:s3://abcd/efg/' def test_dct_mask(): mask = np.zeros((64, 64, 1)) mask[20:40, 20:40] = 1. mask_bbox = [20, 20, 20, 20] results = dict(mask=mask, mask_bbox=mask_bbox) dct_mask = GetSpatialDiscountMask() results = dct_mask(results) assert 'discount_mask' in results assert results['discount_mask'].shape == (64, 64, 1) mask_height = mask_width = 20 gamma = 0.99 beta = 1.5 mask_values = np.ones((mask_width, mask_height, 1)) for i in range(mask_width): for j in range(mask_height): mask_values[i, j] = max(gamma**(min(i, mask_width - i - 1) * beta), gamma**(min(j, mask_height - j - 1) * beta)) dct_mask_test = np.zeros_like(mask) dct_mask_test[20:40, 20:40, ...] = mask_values np.testing.assert_almost_equal(dct_mask_test, results['discount_mask']) repr_str = dct_mask.__class__.__name__ + (f'(gamma={dct_mask.gamma}, ' f'beta={dct_mask.beta})') assert repr_str == repr(dct_mask) class TestInpaintLoading: @classmethod def setup_class(cls): cls.img_path = Path(__file__).parent.parent.parent.joinpath( 'data/image/test.png') cls.results = dict(img_info=dict(filename=cls.img_path)) def test_load_mask(self): # test mask mode: set mask_config = dict( mask_list_file='tests/data/inpainting/mask_list.txt', prefix='tests/data/inpainting/', io_backend='local', color_type='unchanged', file_client_kwargs=dict()) set_loader = LoadMask('set', mask_config) class_name = set_loader.__class__.__name__ assert repr(set_loader) == class_name + "(mask_mode='set')" for _ in range(2): results = dict() results = set_loader(results) gt_mask = mmcv.imread( 'tests/data/inpainting/mask/test.png', flag='unchanged') assert np.array_equal(results['mask'], gt_mask[..., 0:1] / 255.) mask_config = dict( mask_list_file='tests/data/inpainting/mask_list_single_ch.txt', prefix='tests/data/inpainting/', io_backend='local', color_type='unchanged', file_client_kwargs=dict()) # test mask mode: set with input as single channel image set_loader = LoadMask('set', mask_config) results = dict() results = set_loader(results) gt_mask = mmcv.imread( 'tests/data/inpainting/mask/test_single_ch.png', flag='unchanged') gt_mask = np.expand_dims(gt_mask, axis=2) assert np.array_equal(results['mask'], gt_mask[..., 0:1] / 255.) # test mask mode: ff mask_config = dict( img_shape=(256, 256), num_vertices=(4, 12), mean_angle=1.2, angle_range=0.4, brush_width=(12, 40)) ff_loader = LoadMask('ff', mask_config) results = dict() results = ff_loader(results) assert results['mask'].shape == (256, 256, 1) # test mask mode: irregular holes mask_config = dict( img_shape=(256, 256), num_vertices=(4, 12), max_angle=4., length_range=(10, 100), brush_width=(10, 40), area_ratio_range=(0.15, 0.5)) irregular_loader = LoadMask('irregular', mask_config) results = dict() results = irregular_loader(results) assert results['mask'].shape == (256, 256, 1) # test mask mode: bbox mask_config = dict(img_shape=(256, 256), max_bbox_shape=128) bbox_loader = LoadMask('bbox', mask_config) results = dict() results = bbox_loader(results) assert results['mask'].shape == (256, 256, 1) # test mask mode: file mask_loader = LoadMask('file') mask = mask_loader( dict(mask_path='tests/data/inpainting/mask/test_single_ch.png')) assert mask['mask'].shape == (256, 256, 1) with pytest.raises(NotImplementedError): loader = LoadMask('xxxx', mask_config) results = loader(results) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_matlab_like_resize.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import MATLABLikeResize def test_matlab_like_resize(): results = {} # give scale results['lq'] = np.ones((16, 16, 3)) imresize = MATLABLikeResize(keys=['lq'], scale=0.25) results = imresize(results) assert results['lq'].shape == (4, 4, 3) # give scale results['lq'] = np.ones((16, 16, 3)) imresize = MATLABLikeResize(keys=['lq'], output_shape=(6, 6)) results = imresize(results) assert results['lq'].shape == (6, 6, 3) # kernel must equal 'bicubic' with pytest.raises(ValueError): MATLABLikeResize(keys=['lq'], kernel='abc') # kernel_width must equal 4.0 with pytest.raises(ValueError): MATLABLikeResize(keys=['lq'], kernel_width=10) # scale and output_shape cannot be both None with pytest.raises(ValueError): MATLABLikeResize(keys=['lq']) assert repr(imresize) == imresize.__class__.__name__ \ + "(keys=['lq'], scale=None, output_shape=(6, 6), " \ + 'kernel=bicubic, kernel_width=4.0)' def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_normalization.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import Normalize, RescaleToZeroOne class TestAugmentations: @staticmethod def assert_img_equal(img, ref_img, ratio_thr=0.999): """Check if img and ref_img are matched approximately.""" assert img.shape == ref_img.shape assert img.dtype == ref_img.dtype area = ref_img.shape[-1] * ref_img.shape[-2] diff = np.abs(img.astype('int32') - ref_img.astype('int32')) assert np.sum(diff <= 1) / float(area) > ratio_thr @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) def check_normalize(self, origin_img, result_img, norm_cfg): """Check if the origin_img are normalized correctly into result_img in a given norm_cfg.""" target_img = result_img.copy() target_img *= norm_cfg['std'][None, None, :] target_img += norm_cfg['mean'][None, None, :] if norm_cfg['to_rgb']: target_img = target_img[:, ::-1, ...].copy() self.assert_img_equal(origin_img, target_img) def test_normalize(self): with pytest.raises(TypeError): Normalize(['alpha'], dict(mean=[123.675, 116.28, 103.53]), [58.395, 57.12, 57.375]) with pytest.raises(TypeError): Normalize(['alpha'], [123.675, 116.28, 103.53], dict(std=[58.395, 57.12, 57.375])) target_keys = ['merged', 'img_norm_cfg'] merged = np.random.rand(240, 320, 3).astype(np.float32) results = dict(merged=merged) config = dict( keys=['merged'], mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=False) normalize = Normalize(**config) normalize_results = normalize(results) assert self.check_keys_contain(normalize_results.keys(), target_keys) self.check_normalize(merged, normalize_results['merged'], normalize_results['img_norm_cfg']) merged = np.random.rand(240, 320, 3).astype(np.float32) results = dict(merged=merged) config = dict( keys=['merged'], mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) normalize = Normalize(**config) normalize_results = normalize(results) assert self.check_keys_contain(normalize_results.keys(), target_keys) self.check_normalize(merged, normalize_results['merged'], normalize_results['img_norm_cfg']) assert normalize.__repr__() == ( normalize.__class__.__name__ + f"(keys={ ['merged']}, mean={np.array([123.675, 116.28, 103.53])}," f' std={np.array([58.395, 57.12, 57.375])}, to_rgb=True)') # input is an image list merged = np.random.rand(240, 320, 3).astype(np.float32) merged_2 = np.random.rand(240, 320, 3).astype(np.float32) results = dict(merged=[merged, merged_2]) config = dict( keys=['merged'], mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=False) normalize = Normalize(**config) normalize_results = normalize(results) assert self.check_keys_contain(normalize_results.keys(), target_keys) self.check_normalize(merged, normalize_results['merged'][0], normalize_results['img_norm_cfg']) self.check_normalize(merged_2, normalize_results['merged'][1], normalize_results['img_norm_cfg']) merged = np.random.rand(240, 320, 3).astype(np.float32) merged_2 = np.random.rand(240, 320, 3).astype(np.float32) results = dict(merged=[merged, merged_2]) config = dict( keys=['merged'], mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) normalize = Normalize(**config) normalize_results = normalize(results) assert self.check_keys_contain(normalize_results.keys(), target_keys) self.check_normalize(merged, normalize_results['merged'][0], normalize_results['img_norm_cfg']) self.check_normalize(merged_2, normalize_results['merged'][1], normalize_results['img_norm_cfg']) def test_rescale_to_zero_one(self): target_keys = ['alpha'] alpha = np.random.rand(240, 320).astype(np.float32) results = dict(alpha=alpha) rescale_to_zero_one = RescaleToZeroOne(keys=['alpha']) rescale_to_zero_one_results = rescale_to_zero_one(results) assert self.check_keys_contain(rescale_to_zero_one_results.keys(), target_keys) assert rescale_to_zero_one_results['alpha'].shape == (240, 320) np.testing.assert_almost_equal(rescale_to_zero_one_results['alpha'], alpha / 255.) assert repr(rescale_to_zero_one) == ( rescale_to_zero_one.__class__.__name__ + f"(keys={['alpha']})") # input is image list alpha = np.random.rand(240, 320).astype(np.float32) alpha_2 = np.random.rand(240, 320).astype(np.float32) results = dict(alpha=[alpha, alpha_2]) rescale_to_zero_one = RescaleToZeroOne(keys=['alpha']) rescale_to_zero_one_results = rescale_to_zero_one(results) assert rescale_to_zero_one_results['alpha'][0].shape == (240, 320) assert rescale_to_zero_one_results['alpha'][1].shape == (240, 320) np.testing.assert_almost_equal(rescale_to_zero_one_results['alpha'][0], alpha / 255.) np.testing.assert_almost_equal(rescale_to_zero_one_results['alpha'][1], alpha_2 / 255.) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_random_degradations.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import (DegradationsWithShuffle, RandomBlur, RandomJPEGCompression, RandomNoise, RandomResize, RandomVideoCompression) def test_random_noise(): results = {} results['lq'] = np.ones((8, 8, 3)).astype(np.uint8) # Gaussian noise model = RandomNoise( params=dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[0, 50], gaussian_gray_noise_prob=1), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # Poisson noise model = RandomNoise( params=dict( noise_type=['poisson'], noise_prob=[1], poisson_scale=[0, 1], poisson_gray_noise_prob=1), keys=['lq']) results = model(results) shape, dtype = results['lq'].shape, results['lq'].dtype assert {'shape': shape, 'dtype': dtype} == \ {'shape': (8, 8, 3), 'dtype': np.float32} # skip degradations with prob < 1 params = dict( noise_type=['gaussian'], noise_prob=[1], gaussian_sigma=[0, 50], gaussian_gray_noise_prob=1, prob=0) model = RandomNoise(params=params, keys=['lq']) assert model(results) == results assert repr(model) == model.__class__.__name__ + f'(params={params}, ' \ + "keys=['lq'])" def test_random_jpeg_compression(): results = {} results['lq'] = np.ones((8, 8, 3)).astype(np.uint8) model = RandomJPEGCompression( params=dict(quality=[5, 50], color_type='color'), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # skip degradations with prob < 1 params = dict(quality=[5, 50], color_type='color', prob=0) model = RandomJPEGCompression(params=params, keys=['lq']) assert model(results) == results model = RandomJPEGCompression(params=params, keys=['lq'], bgr2rgb=True) assert model(results)['lq'].shape == results['lq'].shape assert repr(model) == model.__class__.__name__ + f'(params={params}, ' \ + "keys=['lq'])" def test_random_video_compression(): results = {} results['lq'] = [np.ones((8, 8, 3)).astype(np.float32)] * 5 model = RandomVideoCompression( params=dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5]), keys=['lq']) results = model(results) assert results['lq'][0].shape == (8, 8, 3) assert len(results['lq']) == 5 # skip degradations with prob < 1 params = dict( codec=['libx264', 'h264', 'mpeg4'], codec_prob=[1 / 3., 1 / 3., 1 / 3.], bitrate=[1e4, 1e5], prob=0) model = RandomVideoCompression(params=params, keys=['lq']) assert model(results) == results assert repr(model) == model.__class__.__name__ + f'(params={params}, ' \ + "keys=['lq'])" def test_random_resize(): results = {} results['lq'] = np.ones((8, 8, 3)).astype(np.float32) # upscale model = RandomResize( params=dict( resize_mode_prob=[1, 0, 0], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), keys=['lq']) results = model(results) assert results['lq'].shape[0] >= 8 and results['lq'].shape[1] >= 8 # downscale results['lq'] = np.ones((8, 8, 3)).astype(np.float32) model = RandomResize( params=dict( resize_mode_prob=[0, 1, 0], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), keys=['lq']) results = model(results) assert results['lq'].shape[0] <= 8 and results['lq'].shape[1] <= 8 # keep size results['lq'] = np.ones((8, 8, 3)).astype(np.float32) model = RandomResize( params=dict( resize_mode_prob=[0, 0, 1], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.]), keys=['lq']) results = model(results) assert results['lq'].shape[0] == 8 and results['lq'].shape[1] == 8 # given target_size results['lq'] = np.ones((8, 8, 3)).astype(np.float32) model = RandomResize( params=dict( resize_mode_prob=[0, 0, 1], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], target_size=(16, 32)), keys=['lq']) results = model(results) assert results['lq'].shape == (16, 32, 3) # step_size > 0 results['lq'] = np.ones((8, 8, 3)).astype(np.float32) model = RandomResize( params=dict( resize_mode_prob=[0, 0, 1], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], resize_step=0.05), keys=['lq']) results = model(results) # is_size_even is True results['lq'] = np.ones((8, 8, 3)).astype(np.float32) model = RandomResize( params=dict( resize_mode_prob=[0, 1, 0], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], resize_step=0.05, is_size_even=True), keys=['lq']) results = model(results) assert results['lq'].shape[0] % 2 == 0 assert results['lq'].shape[1] % 2 == 0 # skip degradation model = RandomResize( params=dict( resize_mode_prob=[1, 0, 0], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], prob=0), keys=['lq']) assert model(results) == results with pytest.raises(NotImplementedError): params = dict( resize_mode_prob=[1], resize_scale=[1], resize_opt=['abc'], resize_prob=[1]) model = RandomResize(params=params, keys=['lq']) results = model(results) assert repr(model) == model.__class__.__name__ + f'(params={params}, ' \ + "keys=['lq'])" def test_random_blur(): results = {} results['lq'] = np.ones((8, 8, 3)).astype(np.float32) # isotropic Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['iso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # anisotropic Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['aniso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # isotropic generalized Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['generalized_iso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # anisotropic generalized Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['generalized_aniso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # isotropic plateau Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['plateau_iso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # anisotropic plateau Gaussian model = RandomBlur( params=dict( kernel_size=[41], kernel_list=['plateau_aniso'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # sinc (kernel size < 13) model = RandomBlur( params=dict( kernel_size=[11], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # sinc (kernel size >= 13) model = RandomBlur( params=dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # sinc (given omega) model = RandomBlur( params=dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], omega=[0.1, 0.1]), keys=['lq']) results = model(results) assert results['lq'].shape == (8, 8, 3) # skip degradation params = dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], prob=0) model = RandomBlur(params=params, keys=['lq']) assert model(results) == results assert repr(model) == model.__class__.__name__ + f'(params={params}, ' \ + "keys=['lq'])" def test_degradations_with_shuffle(): results = {} results['lq'] = np.ones((8, 8, 3)).astype(np.uint8) # shuffle all model = DegradationsWithShuffle( degradations=[ dict( type='RandomBlur', params=dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], omega=[0.1, 0.1])), dict( type='RandomResize', params=dict( resize_mode_prob=[0, 0, 1], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], target_size=(16, 16))), [ dict( type='RandomJPEGCompression', params=dict(quality=[5, 10], color_type='color')), dict( type='RandomJPEGCompression', params=dict(quality=[15, 20], color_type='color')) ] ], keys=['lq'], shuffle_idx=None) model(results) # shuffle last 2 degradations = [ dict( type='RandomBlur', params=dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], omega=[0.1, 0.1])), dict( type='RandomResize', params=dict( resize_mode_prob=[0, 0, 1], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], target_size=(16, 16))), [ dict( type='RandomJPEGCompression', params=dict(quality=[5, 10], color_type='color')), dict( type='RandomJPEGCompression', params=dict(quality=[15, 20], color_type='color')) ] ] model = DegradationsWithShuffle( degradations=degradations, keys=['lq'], shuffle_idx=(1, 2)) model(results) assert repr(model) == model.__class__.__name__ \ + f'(degradations={degradations}, ' \ + "keys=['lq'], " \ + 'shuffle_idx=(1, 2))' # shuffle all image degradations multiple times degradations = [ dict( type='RandomBlur', params=dict( kernel_size=[15], kernel_list=['sinc'], kernel_prob=[1], sigma_x=[0.2, 10], sigma_y=[0.2, 10], rotate_angle=[-3.1416, 3.1416], omega=[0.1, 0.1])), dict( type='RandomResize', params=dict( resize_mode_prob=[0.4, 0.4, 0.2], resize_scale=[0.5, 1.5], resize_opt=['bilinear', 'area', 'bicubic'], resize_prob=[1 / 3., 1 / 3., 1 / 3.], resize_step=0.05)), dict( type='RandomNoise', params=dict( noise_type=['gaussian', 'poisson'], noise_prob=[0.4, 0.6], gaussian_sigma=[0, 20], gaussian_gray_noise_prob=1., gaussian_sigma_step=0.05, poisson_scale=[0., 1.], poisson_gray_noise_prob=1., scale_step=0.05)), dict( type='RandomJPEGCompression', params=dict(quality=[5, 10], color_type='color')) ] * 10 model = DegradationsWithShuffle(degradations=degradations, keys=['lq']) model(results) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_random_down_sampling.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np from mmagic.datasets.transforms import RandomDownSampling def test_random_down_sampling(): img1 = np.uint8(np.random.randn(480, 640, 3) * 255) inputs1 = dict(gt=img1) down_sampling1 = RandomDownSampling( scale_min=1, scale_max=4, patch_size=None) results1 = down_sampling1(inputs1) assert set(list(results1.keys())) == set(['gt', 'img', 'scale']) assert repr(down_sampling1) == ( down_sampling1.__class__.__name__ + f' scale_min={down_sampling1.scale_min}, ' + f'scale_max={down_sampling1.scale_max}, ' + f'patch_size={down_sampling1.patch_size}, ' + f'interpolation={down_sampling1.interpolation}, ' + f'backend={down_sampling1.backend}') img2 = np.uint8(np.random.randn(480, 640, 3) * 255) inputs2 = dict(gt=img2) down_sampling2 = RandomDownSampling( scale_min=1, scale_max=4, patch_size=48) results2 = down_sampling2(inputs2) assert set(list(results2.keys())) == set(['gt', 'img', 'scale']) assert repr(down_sampling2) == ( down_sampling2.__class__.__name__ + f' scale_min={down_sampling2.scale_min}, ' + f'scale_max={down_sampling2.scale_max}, ' + f'patch_size={down_sampling2.patch_size}, ' + f'interpolation={down_sampling2.interpolation}, ' + f'backend={down_sampling2.backend}') # test copy meta info img3 = np.uint8(np.random.randn(480, 640, 3) * 255) inputs3 = dict(gt=img3, gt_channel_order='rgb', gt_color_type='color') down_sampling3 = RandomDownSampling( scale_min=1, scale_max=4, patch_size=48) results3 = down_sampling3(inputs3) assert results3['img_channel_order'] == 'rgb' assert results3['img_color_type'] == 'color' def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_trimap.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import cv2 import numpy as np import pytest from mmagic.datasets.transforms import (FormatTrimap, GenerateTrimap, GenerateTrimapWithDistTransform, TransformTrimap) def assert_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" assert set(target_keys).issubset(set(result_keys)) def generate_ref_trimap(alpha, kernel_size, iterations, random): """Check if a trimap's value is correct.""" if isinstance(kernel_size, int): kernel_size = kernel_size, kernel_size + 1 if isinstance(iterations, int): iterations = iterations, iterations + 1 if random: min_kernel, max_kernel = kernel_size kernel_num = max_kernel - min_kernel erode_ksize = min_kernel + np.random.randint(kernel_num) erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (erode_ksize, erode_ksize)) dilate_ksize = min_kernel + np.random.randint(kernel_num) dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate_ksize, dilate_ksize)) min_iteration, max_iteration = iterations erode_iter = np.random.randint(min_iteration, max_iteration) dilate_iter = np.random.randint(min_iteration, max_iteration) else: erode_ksize, dilate_ksize = kernel_size erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (erode_ksize, erode_ksize)) dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate_ksize, dilate_ksize)) erode_iter, dilate_iter = iterations h, w = alpha.shape # erode erode_kh = erode_kw = erode_ksize eroded = np.zeros_like(alpha) src = alpha pad = ((erode_kh // 2, (erode_kh - 1) // 2), (erode_kw // 2, (erode_kw - 1) // 2)) for _ in range(erode_iter): src = np.pad(src, pad, 'constant', constant_values=np.max(src)) for i in range(h): for j in range(w): target = src[i:i + erode_kh, j:j + erode_kw] eroded[i, j] = np.min( (target * erode_kernel)[erode_kernel == 1]) src = eroded # dilate dilate_kh = dilate_kw = dilate_ksize dilated = np.zeros_like(alpha) src = alpha pad = ((dilate_kh // 2, (dilate_kh - 1) // 2), (dilate_kw // 2, (dilate_kw - 1) // 2)) for _ in range(dilate_iter): src = np.pad(src, pad, constant_values=np.min(src)) for i in range(h): for j in range(w): target = src[i:i + dilate_kh, j:j + dilate_kw] dilated[i, j] = np.max( (target * dilate_kernel)[dilate_kernel == 1]) src = dilated ref_trimap = np.zeros_like(alpha) ref_trimap.fill(128) ref_trimap[eroded >= 255] = 255 ref_trimap[dilated <= 0] = 0 return ref_trimap def test_format_trimap(): ori_trimap = np.random.randint(3, size=(64, 64)) ori_trimap[ori_trimap == 1] = 128 ori_trimap[ori_trimap == 2] = 255 results = dict(trimap=ori_trimap.copy()) format_trimap = FormatTrimap(to_onehot=False) results = format_trimap(results) result_trimap = results['trimap'] assert repr(format_trimap) == format_trimap.__class__.__name__ + ( '(to_onehot=False)') assert result_trimap.shape == (64, 64) assert ((result_trimap == 0) == (ori_trimap == 0)).all() assert ((result_trimap == 1) == (ori_trimap == 128)).all() assert ((result_trimap == 2) == (ori_trimap == 255)).all() assert results['format_trimap_to_onehot'] is False results = dict(trimap=ori_trimap.copy()) format_trimap = FormatTrimap(to_onehot=True) results = format_trimap(results) result_trimap = results['trimap'] assert repr(format_trimap) == format_trimap.__class__.__name__ + ( '(to_onehot=True)') assert result_trimap.shape == (64, 64, 3) assert ((result_trimap[..., 0] == 1) == (ori_trimap == 0)).all() assert ((result_trimap[..., 1] == 1) == (ori_trimap == 128)).all() assert ((result_trimap[..., 2] == 1) == (ori_trimap == 255)).all() assert results['format_trimap_to_onehot'] is True def test_generate_trimap(): with pytest.raises(ValueError): # kernel_size must be an int or a tuple of 2 int GenerateTrimap(1.5) with pytest.raises(ValueError): # kernel_size must be an int or a tuple of 2 int GenerateTrimap((3, 3, 3)) with pytest.raises(ValueError): # iterations must be an int or a tuple of 2 int GenerateTrimap(3, iterations=1.5) with pytest.raises(ValueError): # iterations must be an int or a tuple of 2 int GenerateTrimap(3, iterations=(3, 3, 3)) target_keys = ['alpha', 'trimap'] # check random mode kernel_size = (3, 5) iterations = (3, 5) random = True alpha = np.random.randn(32, 32) results = dict(alpha=alpha) generate_trimap = GenerateTrimap(kernel_size, iterations, random) np.random.seed(123) generate_trimap_results = generate_trimap(results) trimap = generate_trimap_results['trimap'] assert_keys_contain(generate_trimap_results.keys(), target_keys) assert trimap.shape == alpha.shape np.random.seed(123) ref_trimap = generate_ref_trimap(alpha, kernel_size, iterations, random) assert (trimap == ref_trimap).all() # check non-random mode kernel_size = (3, 5) iterations = (5, 3) random = False generate_trimap = GenerateTrimap(kernel_size, iterations, random) generate_trimap_results = generate_trimap(results) trimap = generate_trimap_results['trimap'] assert_keys_contain(generate_trimap_results.keys(), target_keys) assert trimap.shape == alpha.shape ref_trimap = generate_ref_trimap(alpha, kernel_size, iterations, random) assert (trimap == ref_trimap).all() # check repr string kernel_size = 1 iterations = 1 generate_trimap = GenerateTrimap(kernel_size, iterations) kernels = [ cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size)) ] assert repr(generate_trimap) == ( generate_trimap.__class__.__name__ + f'(kernels={kernels}, iterations={(iterations, iterations + 1)}, ' f'random=True)') def test_generate_trimap_with_dist_transform(): with pytest.raises(ValueError): # dist_thr must be an float that is greater than 1 GenerateTrimapWithDistTransform(dist_thr=-1) target_keys = ['alpha', 'trimap'] alpha = np.random.randint(0, 256, (32, 32)) alpha[:8, :8] = 0 alpha[-8:, -8:] = 255 results = dict(alpha=alpha) generate_trimap = GenerateTrimapWithDistTransform(dist_thr=3, random=False) generate_trimap_results = generate_trimap(results) trimap = generate_trimap_results['trimap'] assert_keys_contain(generate_trimap_results.keys(), target_keys) assert trimap.shape == alpha.shape alpha = np.random.randint(0, 256, (32, 32)) results = dict(alpha=alpha) generate_trimap = GenerateTrimapWithDistTransform(dist_thr=3, random=True) generate_trimap_results = generate_trimap(results) trimap = generate_trimap_results['trimap'] assert_keys_contain(generate_trimap_results.keys(), target_keys) assert trimap.shape == alpha.shape assert repr(generate_trimap) == ( generate_trimap.__class__.__name__ + '(dist_thr=3, random=True)') def test_transform_trimap(): results = dict() transform = TransformTrimap() target_keys = ['trimap', 'transformed_trimap'] with pytest.raises(KeyError): results_transformed = transform(results) with pytest.raises(AssertionError): dummy_trimap = np.zeros((100, 100, 1), dtype=np.uint8) results['trimap'] = dummy_trimap results_transformed = transform(results) results = dict() # generate dummy trimap with shape (100,100) dummy_trimap = np.zeros((100, 100), dtype=np.uint8) dummy_trimap[:50, :50] = 255 results['trimap'] = dummy_trimap results_transformed = transform(results) assert_keys_contain(results_transformed.keys(), target_keys) assert results_transformed['trimap'].shape == dummy_trimap.shape assert results_transformed[ 'transformed_trimap'].shape[:2] == dummy_trimap.shape repr_str = transform.__class__.__name__ assert repr(transform) == repr_str def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_transforms/test_values.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.datasets.transforms import CopyValues, SetValues class TestAugmentations: @classmethod def setup_class(cls): cls.results = dict() cls.gt = np.random.randint(0, 256, (256, 128, 3), dtype=np.uint8) cls.img = np.random.randint(0, 256, (64, 32, 3), dtype=np.uint8) cls.results = dict( img=cls.img, gt=cls.gt, scale=4, img_path='fake_img_path', gt_path='fake_gt_path') cls.results['ori_img'] = np.random.randint( 0, 256, (256, 256, 3), dtype=np.uint8) cls.results['mask'] = np.random.randint( 0, 256, (256, 256, 1), dtype=np.uint8) # cls.results['img_tensor'] = torch.rand((3, 256, 256)) # cls.results['mask_tensor'] = torch.zeros((1, 256, 256)) # cls.results['mask_tensor'][:, 50:150, 40:140] = 1. def test_copy_value(self): with pytest.raises(AssertionError): CopyValues(src_keys='gt', dst_keys='img') with pytest.raises(ValueError): CopyValues(src_keys=['gt', 'gt'], dst_keys=['img']) results = {} results['gt'] = np.zeros((1)).astype(np.float32) copy_ = CopyValues(src_keys=['gt'], dst_keys=['img']) assert np.array_equal(copy_(results)['img'], results['gt']) assert repr(copy_) == copy_.__class__.__name__ + ("(src_keys=['gt'])" "(dst_keys=['img'])") def test_set_value(self): with pytest.raises(AssertionError): CopyValues(src_keys='gt', dst_keys='img') with pytest.raises(ValueError): CopyValues(src_keys=['gt', 'gt'], dst_keys=['img']) results = {} results['gt'] = np.zeros((1)).astype(np.float32) dictionary = dict(a='b') set_values = SetValues(dictionary=dictionary) new_results = set_values(results) for key in dictionary.keys(): assert new_results[key] == dictionary[key] assert repr(set_values) == ( set_values.__class__.__name__ + f'(dictionary={dictionary})') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_datasets/test_unpaired_image_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from mmagic.datasets import UnpairedImageDataset from mmagic.utils import register_all_modules register_all_modules() class TestUnpairedImageDataset(object): @classmethod def setup_class(cls): cls.imgs_root = osp.join( osp.dirname(osp.dirname(__file__)), 'data/unpaired') cls.default_pipeline = [ dict(type='LoadImageFromFile', key='img_a', color_type='color'), dict(type='LoadImageFromFile', key='img_b', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_a', 'img_b']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='Resize', scale=(286, 286), interpolation='bicubic') ]), dict( type='Crop', keys=['img_a', 'img_b'], crop_size=(256, 256), random_crop=True), dict(type='Flip', direction='horizontal', keys=['img_a', 'img_b']), dict(type='PackInputs', keys=['img_a', 'img_b']), ] def test_unpaired_image_dataset(self): dataset = UnpairedImageDataset( self.imgs_root, pipeline=self.default_pipeline, domain_a='a', domain_b='b') assert len(dataset) == 2 img = dataset[0]['inputs']['img_a'] assert img.ndim == 3 img = dataset[0]['inputs']['img_b'] assert img.ndim == 3 dataset = UnpairedImageDataset( self.imgs_root, pipeline=self.default_pipeline, io_backend='local', domain_a='a', domain_b='b') assert len(dataset) == 2 img = dataset[0]['inputs']['img_a'] assert img.ndim == 3 img = dataset[0]['inputs']['img_b'] assert img.ndim == 3 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_ema.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest.mock import MagicMock import pytest import torch import torch.nn as nn from mmengine.model import MMDistributedDataParallel from packaging import version from mmagic.engine import ExponentialMovingAverageHook class SimpleModule(nn.Module): def __init__(self): super().__init__() self.a = nn.Parameter(torch.tensor([1., 2.])) if version.parse(torch.__version__) >= version.parse('1.7.0'): self.register_buffer('b', torch.tensor([2., 3.]), persistent=True) self.register_buffer('c', torch.tensor([0., 1.]), persistent=False) else: self.register_buffer('b', torch.tensor([2., 3.])) self.c = torch.tensor([0., 1.]) class SimpleModel(nn.Module): def __init__(self) -> None: super().__init__() self.module_a = SimpleModule() self.module_b = SimpleModule() self.module_a_ema = SimpleModule() self.module_b_ema = SimpleModule() class SimpleModelNoEMA(nn.Module): def __init__(self) -> None: super().__init__() self.module_a = SimpleModule() self.module_b = SimpleModule() class SimpleRunner: def __init__(self): self.model = SimpleModel() self.iter = 0 class TestEMA: @classmethod def setup_class(cls): cls.default_config = dict( module_keys=('module_a_ema', 'module_b_ema'), interval=1, interp_cfg=dict(momentum=0.5)) cls.runner = SimpleRunner() @torch.no_grad() def test_ema_hook(self): cfg_ = deepcopy(self.default_config) cfg_['interval'] = -1 ema = ExponentialMovingAverageHook(**cfg_) ema.before_run(self.runner) ema.after_train_iter(self.runner, 1) module_a = self.runner.model.module_a module_a_ema = self.runner.model.module_a_ema ema_states = module_a_ema.state_dict() assert torch.equal(ema_states['a'], torch.tensor([1., 2.])) ema = ExponentialMovingAverageHook(**self.default_config) ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(ema_states['a'], torch.tensor([1., 2.])) module_a.b /= 2. module_a.a.data /= 2. module_a.c /= 2. self.runner.iter += 1 ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(self.runner.model.module_a.a, torch.tensor([0.5, 1.])) assert torch.equal(ema_states['a'], torch.tensor([0.75, 1.5])) assert torch.equal(ema_states['b'], torch.tensor([1., 1.5])) assert 'c' not in ema_states # check for the validity of args with pytest.raises(AssertionError): _ = ExponentialMovingAverageHook(module_keys=['a']) with pytest.raises(AssertionError): _ = ExponentialMovingAverageHook(module_keys=('a')) with pytest.raises(AssertionError): _ = ExponentialMovingAverageHook( module_keys=('module_a_ema'), interp_mode='xxx') # test before run ema = ExponentialMovingAverageHook(**self.default_config) self.runner.model = SimpleModelNoEMA() self.runner.iter = 0 ema.before_run(self.runner) assert hasattr(self.runner.model, 'module_a_ema') module_a = self.runner.model.module_a module_a_ema = self.runner.model.module_a_ema ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(ema_states['a'], torch.tensor([1., 2.])) module_a.b /= 2. module_a.a.data /= 2. module_a.c /= 2. self.runner.iter += 1 ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(self.runner.model.module_a.a, torch.tensor([0.5, 1.])) assert torch.equal(ema_states['a'], torch.tensor([0.75, 1.5])) assert torch.equal(ema_states['b'], torch.tensor([1., 1.5])) assert 'c' not in ema_states # test ema with simple warm up runner = SimpleRunner() cfg_ = deepcopy(self.default_config) cfg_.update(dict(start_iter=3, interval=1)) ema = ExponentialMovingAverageHook(**cfg_) ema.before_run(runner) module_a = runner.model.module_a module_a_ema = runner.model.module_a_ema module_a.a.data /= 2. runner.iter += 1 ema.after_train_iter(runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(runner.model.module_a.a, torch.tensor([0.5, 1.])) assert torch.equal(ema_states['a'], torch.tensor([0.5, 1.])) module_a.a.data /= 2 runner.iter += 2 ema.after_train_iter(runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(runner.model.module_a.a, torch.tensor([0.25, 0.5])) assert torch.equal(ema_states['a'], torch.tensor([0.375, 0.75])) # test warning with pytest.warns(UserWarning): default_config = dict( module_keys=('module_a_ema', 'module_b_ema'), interval=1, interp_cfg=dict(momentum=0.6)) cfg_ = deepcopy(default_config) ema = ExponentialMovingAverageHook(**cfg_) ema.lerp( torch.tensor([0.25, 0.5]), torch.tensor([0.25, 0.5]), momentum=0.6) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_ema_hook_cuda(self): ema = ExponentialMovingAverageHook(**self.default_config) cuda_runner = SimpleRunner() cuda_runner.model = cuda_runner.model.cuda() ema.after_train_iter(cuda_runner, 1) module_a = cuda_runner.model.module_a module_a_ema = cuda_runner.model.module_a_ema ema_states = module_a_ema.state_dict() assert torch.equal(ema_states['a'], torch.tensor([1., 2.]).cuda()) module_a.b /= 2. module_a.a.data /= 2. module_a.c /= 2. cuda_runner.iter += 1 ema.after_train_iter(cuda_runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(cuda_runner.model.module_a.a, torch.tensor([0.5, 1.]).cuda()) assert torch.equal(ema_states['a'], torch.tensor([0.75, 1.5]).cuda()) assert torch.equal(ema_states['b'], torch.tensor([1., 1.5]).cuda()) assert 'c' not in ema_states # test before run ema = ExponentialMovingAverageHook(**self.default_config) model_ = SimpleModelNoEMA().cuda() self.runner.model = MagicMock(spec=MMDistributedDataParallel) self.runner.model.module = model_ self.runner.iter = 0 ema.before_run(self.runner) assert hasattr(self.runner.model.module, 'module_a_ema') module_a = self.runner.model.module.module_a module_a_ema = self.runner.model.module.module_a_ema ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(ema_states['a'], torch.tensor([1., 2.]).cuda()) module_a.b /= 2. module_a.a.data /= 2. module_a.c /= 2. self.runner.iter += 1 ema.after_train_iter(self.runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(self.runner.model.module.module_a.a, torch.tensor([0.5, 1.]).cuda()) assert torch.equal(ema_states['a'], torch.tensor([0.75, 1.5]).cuda()) assert torch.equal(ema_states['b'], torch.tensor([1., 1.5]).cuda()) assert 'c' not in ema_states # test ema with simple warm up runner = SimpleRunner() runner.model = runner.model.cuda() cfg_ = deepcopy(self.default_config) cfg_.update(dict(start_iter=3, interval=1)) ema = ExponentialMovingAverageHook(**cfg_) ema.before_run(runner) module_a = runner.model.module_a module_a_ema = runner.model.module_a_ema module_a.a.data /= 2. runner.iter += 1 ema.after_train_iter(runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(runner.model.module_a.a, torch.tensor([0.5, 1.]).cuda()) assert torch.equal(ema_states['a'], torch.tensor([0.5, 1.]).cuda()) module_a.a.data /= 2 runner.iter += 2 ema.after_train_iter(runner, 1) ema_states = module_a_ema.state_dict() assert torch.equal(runner.model.module_a.a, torch.tensor([0.25, 0.5]).cuda()) assert torch.equal(ema_states['a'], torch.tensor([0.375, 0.75]).cuda()) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_iter_time_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock, Mock, patch from mmengine.logging import MessageHub from mmagic.engine import IterTimerHook def time_patch(): if not hasattr(time_patch, 'time'): time_patch.time = 0 else: time_patch.time += 1 return time_patch.time class TestIterTimerHook(TestCase): def setUp(self) -> None: self.hook = IterTimerHook() def test_init(self): assert self.hook.time_sec_tot == 0 assert self.hook.start_iter == 0 def test_before_train(self): runner = MagicMock() runner.iter = 1 self.hook.before_train(runner) assert self.hook.start_iter == 1 def test_before_epoch(self): runner = Mock() self.hook._before_epoch(runner) assert isinstance(self.hook.t, float) @patch('time.time', MagicMock(return_value=1)) def test_before_iter(self): runner = MagicMock() runner.log_buffer = dict() self.hook._before_epoch(runner) for mode in ('train', 'val', 'test'): self.hook._before_iter(runner, batch_idx=1, mode=mode) runner.message_hub.update_scalar.assert_called_with( f'{mode}/data_time', 0) @patch('time.time', time_patch) def test_after_iter(self): runner = MagicMock() runner.log_buffer = dict() runner.log_processor.window_size = 10 runner.max_iters = 100 runner.iter = 0 runner.test_loop.total_length = 20 runner.val_loop.total_length = 20 self.hook._before_epoch(runner) self.hook.before_run(runner) self.hook._after_iter(runner, batch_idx=1) runner.message_hub.update_scalar.assert_called() runner.message_hub.get_log.assert_not_called() runner.message_hub.update_info.assert_not_called() runner.message_hub = MessageHub.get_instance('test_iter_timer_hook') runner.iter = 9 # eta = (100 - 10) / 1 self.hook._after_iter(runner, batch_idx=89) assert runner.message_hub.get_info('eta') == 90 self.hook._after_iter(runner, batch_idx=9, mode='val') assert runner.message_hub.get_info('eta') == 10 self.hook._after_iter(runner, batch_idx=19, mode='test') assert runner.message_hub.get_info('eta') == 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_pggan_fetch_data_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from unittest import TestCase from unittest.mock import MagicMock import torch from mmengine.dataset import DefaultSampler, InfiniteSampler, pseudo_collate from mmengine.runner import IterBasedTrainLoop from torch.utils.data.dataloader import DataLoader from mmagic.engine import PGGANFetchDataHook from mmagic.registry import DATASETS, MODELS from mmagic.utils import register_all_modules register_all_modules() class TestPGGANFetchDataHook(TestCase): pggan_cfg = dict( type='ProgressiveGrowingGAN', data_preprocessor=dict(type='DataPreprocessor'), noise_size=512, generator=dict(type='PGGANGenerator', out_scale=8), discriminator=dict(type='PGGANDiscriminator', in_scale=8), nkimgs_per_scale={ '4': 600, '8': 1200, '16': 1200, '32': 1200, '64': 1200, '128': 12000 }, transition_kimgs=600, ema_config=dict(interval=1)) imgs_root = osp.join(osp.dirname(__file__), '..', '..', 'data/image') grow_scale_dataset_cfg = dict( type='GrowScaleImgDataset', data_roots={ '4': imgs_root, '8': osp.join(imgs_root, 'img_root'), '32': osp.join(imgs_root, 'img_root', 'grass') }, gpu_samples_base=4, gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4 }, len_per_stage=10, pipeline=[dict(type='LoadImageFromFile', key='img')]) def test_before_train_iter(self): runner = MagicMock() model = MODELS.build(self.pggan_cfg) dataset = DATASETS.build(self.grow_scale_dataset_cfg) # test default sampler default_sampler = DefaultSampler(dataset) dataloader = DataLoader( batch_size=64, dataset=dataset, sampler=default_sampler, collate_fn=pseudo_collate) runner.train_loop = MagicMock(spec=IterBasedTrainLoop) runner.train_loop.dataloader = dataloader runner.model = model hooks = PGGANFetchDataHook() hooks.before_train_iter(runner, 0, None) for scale, target_bz in self.grow_scale_dataset_cfg[ 'gpu_samples_per_scale'].items(): model._next_scale_int = torch.tensor(int(scale), dtype=torch.int32) hooks.before_train_iter(runner, 0, None) self.assertEqual(runner.train_loop.dataloader.batch_size, target_bz) # check attribute of default sampler sampler = runner.train_loop.dataloader.sampler self.assertEqual(sampler.seed, default_sampler.seed) self.assertEqual(sampler.shuffle, default_sampler.shuffle) self.assertEqual(sampler.round_up, default_sampler.round_up) # set `_next_scale_int` as int delattr(model, '_next_scale_int') setattr(model, '_next_scale_int', 128) hooks.before_train_iter(runner, 0, None) self.assertEqual(runner.train_loop.dataloader.batch_size, 4) # test InfinitySampler infinite_sampler = InfiniteSampler(dataset) dataloader = DataLoader( batch_size=64, dataset=dataset, sampler=infinite_sampler, collate_fn=pseudo_collate) runner.train_loop.dataloader = dataloader for scale, target_bz in self.grow_scale_dataset_cfg[ 'gpu_samples_per_scale'].items(): model._next_scale_int = torch.tensor(int(scale), dtype=torch.int32) hooks.before_train_iter(runner, 0, None) self.assertEqual(runner.train_loop.dataloader.batch_size, target_bz) # check attribute of infinite sampler sampler = runner.train_loop.dataloader.sampler self.assertEqual(sampler.seed, infinite_sampler.seed) self.assertEqual(sampler.shuffle, infinite_sampler.shuffle) # test do not update + `IterBasedTrainLoop` hooks.before_train_iter(runner, 1, None) # test not `IterBasedTrainLoop` runner.train_loop = MagicMock() runner.train_loop.dataloader = dataloader runner.model = model model._next_scale_int = 8 # test update hooks.before_train_iter(runner, 0, None) # test do not update hooks.before_train_iter(runner, 1, None) # test invalid sampler type dataloader = DataLoader( batch_size=64, dataset=dataset, collate_fn=pseudo_collate) runner.train_loop.dataloader = dataloader model._next_scale_int = 4 self.assertRaises(ValueError, hooks.before_train_iter, runner, 0, None) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_pickle_data_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock import numpy as np import torch import torch.nn as nn from mmagic.engine.hooks import PickleDataHook class ToyModel(nn.Module): def __init__(self): super().__init__() self.a = torch.randn(10, 10) self.b = np.random.random((10, 10)) def test_PickleDataHook(): hook = PickleDataHook( output_dir='./', data_name_list=['a', 'b', 'c'], interval=3) runner = MagicMock() runner.work_dir = './test/data' runner.iter = 0 runner.model = ToyModel() # test after train iter hook.after_train_iter(runner, 0, None, None) hook.data_name_list = ['a', 'b'] hook.after_train_iter(runner, 0, None, None) runner.model = MagicMock() runner.model.module = ToyModel() hook._pickle_data(runner) runner.iter = 2 hook.after_train_iter(runner, 0, None, None) # test after run hook.after_run(runner) # test before run hook.before_run(runner) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_reduce_lr_scheduler_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import Mock import pytest import torch import torch.nn.functional as F from mmengine import MessageHub from mmagic.engine.hooks import ReduceLRSchedulerHook class ToyModel(torch.nn.Module): def __init__(self): super().__init__() self.conv1 = torch.nn.Conv2d(1, 1, 1) self.conv2 = torch.nn.Conv2d(1, 1, 1) def forward(self, x): return self.conv2(F.relu(self.conv1(x))) def test_reduce_lr_scheduler_hook(): scheduler = [Mock()] scheduler[0].step = Mock() runner = Mock() runner.epoch = 0 runner.iter = 0 runner.param_schedulers = scheduler runner.message_hub = MessageHub.get_instance('test-reduce-lr-scheduler') runner.message_hub.update_scalar('train/loss', 0.1) hook = ReduceLRSchedulerHook(val_metric=None, by_epoch=True, interval=2) scheduler[0].by_epoch = True hook.after_train_iter(runner, 0, data_batch=[dict(a=1)] * 3) runner.message_hub.update_scalar('train/loss', 0.2) hook.after_train_iter(runner, 0, data_batch=[dict(a=1)] * 2) assert abs(hook.sum_value - 0.7) < 1e-8 assert hook.count == 5 hook.after_train_epoch(runner) runner.epoch += 1 assert abs(hook.sum_value - 0.7) < 1e-8 assert hook.count == 5 hook.after_train_epoch(runner) scheduler[0].step.assert_called() assert abs(hook.sum_value - 0) < 1e-8 assert hook.count == 0 value = hook.message_hub.get_scalar('value').current() assert abs(value - 0.14) < 1e-8 hook.after_val_iter(runner, 0, data_batch=[dict(a=1)] * 2) hook.after_val_epoch(runner) hook = ReduceLRSchedulerHook(val_metric=None, by_epoch=False, interval=2) scheduler[0].by_epoch = False runner.message_hub.update_scalar('train/loss', 0.1) hook.after_train_iter(runner, 0, data_batch=[dict(a=1)] * 3) runner.iter += 1 assert abs(hook.sum_value - 0.3) < 1e-8 assert hook.count == 3 runner.message_hub.update_scalar('train/loss', 0.3) hook.after_train_iter(runner, 0, data_batch=[dict(a=1)] * 2) scheduler[0].step.assert_called() value = hook.message_hub.get_scalar('value').current() assert abs(value - 0.18) < 1e-8 assert abs(hook.sum_value - 0) < 1e-8 assert hook.count == 0 hook.after_train_epoch(runner) hook.after_val_iter(runner, 0, data_batch=[dict(a=1)] * 2) hook.after_val_epoch(runner) hook = ReduceLRSchedulerHook(val_metric='PSNR', by_epoch=True, interval=2) scheduler[0].by_epoch = False hook.after_train_iter(runner, 0) hook.after_train_epoch(runner) runner.epoch = 0 hook.after_val_epoch(runner, metrics=dict(PSNR=40)) assert abs(hook.sum_value - 40) < 1e-8, hook.sum_value assert hook.count == 1 runner.epoch = 1 hook.after_val_epoch(runner, metrics=dict(PSNR=50)) scheduler[0].step.assert_called() value = hook.message_hub.get_scalar('value').current() assert abs(value - 45) < 1e-8 assert abs(hook.sum_value - 0) < 1e-8, hook.sum_value assert hook.count == 0 hook = ReduceLRSchedulerHook(val_metric='PSNR', by_epoch=False, interval=2) scheduler[0].by_epoch = False hook.after_train_iter(runner, 0) hook.after_train_epoch(runner) runner.epoch = 0 hook.after_val_epoch(runner, metrics=dict(PSNR=40)) scheduler[0].step.assert_called() value = hook.message_hub.get_scalar('value').current() assert abs(value - 40) < 1e-8 assert abs(hook.sum_value - 0) < 1e-8, hook.sum_value assert hook.count == 0 runner.epoch = 1 runner.param_schedulers = dict(scheduler=scheduler) hook.after_val_epoch(runner, metrics=dict(PSNR=50)) scheduler[0].step.assert_called() value = hook.message_hub.get_scalar('value').current() assert abs(value - 50) < 1e-8 assert abs(hook.sum_value - 0) < 1e-8, hook.sum_value assert hook.count == 0 with pytest.raises(AssertionError): runner.param_schedulers = dict(a='') hook.after_val_epoch(runner, metrics=dict(PSNR=50)) with pytest.raises(TypeError): runner.param_schedulers = '' hook.after_val_epoch(runner, metrics=dict(PSNR=50)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_hooks/test_visualization_hook.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from unittest import TestCase from unittest.mock import MagicMock, Mock import mmcv import numpy as np import torch from mmengine import MessageHub from mmengine.testing import assert_allclose from mmengine.visualization import Visualizer from torch.utils.data.dataset import Dataset from mmagic.engine import VisualizationHook from mmagic.engine.hooks import BasicVisualizationHook from mmagic.structures import DataSample from mmagic.utils import register_all_modules from mmagic.visualization import ConcatImageVisualizer from mmagic.registry import MODELS # isort:skip # noqa register_all_modules() class TestBasicVisualizationHook(TestCase): def setUp(self) -> None: input = torch.rand(2, 3, 32, 32) data_sample = DataSample( path_rgb='rgb.png', tensor3d=torch.ones(3, 32, 32) * torch.tensor([[[0.1]], [[0.2]], [[0.3]]]), array3d=np.ones(shape=(32, 32, 3)) * [0.4, 0.5, 0.6], tensor4d=torch.ones(2, 3, 32, 32) * torch.tensor( [[[[0.1]], [[0.2]], [[0.3]]], [[[0.4]], [[0.5]], [[0.6]]]]), pixdata=torch.ones(1, 32, 32) * 0.6) self.data_batch = {'inputs': input, 'data_samples': [data_sample] * 2} output = copy.deepcopy(data_sample) output.outpixdata = np.ones(shape=(32, 32)) * 0.8 self.outputs = [output] * 2 self.vis = ConcatImageVisualizer( fn_key='path_rgb', img_keys=[ 'tensor3d', 'array3d', 'pixdata', 'tensor4d', 'outpixdata', ], vis_backends=[dict(type='LocalVisBackend')], save_dir='work_dirs') def test_after_iter(self): runner = Mock() runner.iter = 1 runner.visualizer = self.vis hook = BasicVisualizationHook() hook._after_iter(runner, 1, self.data_batch, self.outputs) img = mmcv.imread('work_dirs/vis_data/vis_image/rgb_1.png') assert img.shape == (64, 160, 3) hook._on_train = hook._on_test = hook._on_val = True runner.visualizer = Mock() runner.visualizer.add_datasample = Mock() hook._after_iter( runner, 1, self.data_batch, self.outputs, mode='train') runner.visualizer.add_datasample.assert_called hook._after_iter(runner, 1, self.data_batch, self.outputs, mode='val') runner.visualizer.add_datasample.assert_called hook._after_iter(runner, 1, self.data_batch, self.outputs, mode='test') assert runner.visualizer.assert_called hook._on_train = hook._on_test = hook._on_val = False hook._after_iter( runner, 1, self.data_batch, self.outputs, mode='train') assert runner.visualizer.assert_not_called hook._after_iter(runner, 1, self.data_batch, self.outputs, mode='val') assert runner.visualizer.assert_not_called hook._after_iter(runner, 1, self.data_batch, self.outputs, mode='test') assert runner.visualizer.assert_not_called class TestVisualizationHook(TestCase): Visualizer.get_instance('test-gen-visualizer') MessageHub.get_instance('test-gen-visualizer') def test_init(self): hook = VisualizationHook( interval=10, vis_kwargs_list=dict(type='Noise')) self.assertEqual(hook.interval, 10) self.assertEqual(hook.vis_kwargs_list, [dict(type='Noise')]) self.assertEqual(hook.n_samples, 64) self.assertFalse(hook.show) hook = VisualizationHook( interval=10, vis_kwargs_list=[dict(type='Noise'), dict(type='Translation')]) self.assertEqual(len(hook.vis_kwargs_list), 2) hook = VisualizationHook( interval=10, vis_kwargs_list=dict(type='GAN'), show=True) self.assertEqual(hook._visualizer._vis_backends, {}) def test_vis_sample_with_gan_alias(self): gan_model_cfg = dict( type='DCGAN', noise_size=10, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='DCGANGenerator', output_scale=32, base_channels=32)) model = MODELS.build(gan_model_cfg) runner = MagicMock() runner.model = model runner.train_dataloader = MagicMock() runner.train_dataloader.batch_size = 10 hook = VisualizationHook( interval=10, vis_kwargs_list=dict(type='GAN'), n_samples=9) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer # build a empty data sample data_batch = [ dict(inputs=None, data_samples=DataSample()) for idx in range(10) ] hook.vis_sample(runner, 0, data_batch, None) _, called_kwargs = mock_visualuzer.add_datasample.call_args self.assertEqual(called_kwargs['name'], 'gan') self.assertEqual(called_kwargs['target_keys'], None) self.assertEqual(called_kwargs['vis_mode'], None) gen_batches = called_kwargs['gen_samples'] self.assertEqual(len(gen_batches), 9) noise_in_gen_batches = torch.stack( [gen_batches[idx].noise for idx in range(9)], 0) noise_in_buffer = torch.cat([ buffer['inputs']['noise'] for buffer in hook.inputs_buffer['GAN'] ], dim=0)[:9] self.assertTrue((noise_in_gen_batches == noise_in_buffer).all()) hook.vis_sample(runner, 1, data_batch, None) _, called_kwargs = mock_visualuzer.add_datasample.call_args gen_batches = called_kwargs['gen_samples'] noise_in_gen_batches_new = torch.stack( [gen_batches[idx].noise for idx in range(9)], 0) self.assertTrue((noise_in_gen_batches_new == noise_in_buffer).all()) def test_vis_sample_with_translation_alias(self): translation_cfg = dict( type='CycleGAN', data_preprocessor=dict( type='DataPreprocessor', data_keys=['img_photo', 'img_mask']), generator=dict( type='ResnetGenerator', in_channels=3, out_channels=3, base_channels=8, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=4, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=3, base_channels=8, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02)), default_domain='photo', reachable_domains=['photo', 'mask'], related_domains=['photo', 'mask']) model = MODELS.build(translation_cfg) class naive_dataset(Dataset): def __init__(self, max_len, train=False): self.max_len = max_len self.train = train def __len__(self): return self.max_len def __getitem__(self, index): weight = index if self.train else -index img_photo = torch.ones(3, 32, 32) * weight img_mask = torch.ones(3, 32, 32) * (weight + 1) return dict( inputs=dict(img_photo=img_photo, img_mask=img_mask), data_samples=DataSample( img_photo=img_photo, img_mask=img_mask)) train_dataloader = MagicMock() train_dataloader.batch_size = 4 train_dataloader.dataset = naive_dataset(max_len=15, train=True) val_dataloader = MagicMock() val_dataloader.batch_size = 4 val_dataloader.dataset = naive_dataset(max_len=17) runner = MagicMock() runner.model = model runner.train_dataloader = train_dataloader runner.val_loop = MagicMock() runner.val_loop.dataloader = val_dataloader hook = VisualizationHook( interval=10, vis_kwargs_list=[ dict(type='Translation'), dict(type='TranslationVal', name='cyclegan_val') ], n_samples=9) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer # build a empty data sample data_batch = [ dict(inputs=None, data_samples=DataSample()) for idx in range(4) ] hook.vis_sample(runner, 0, data_batch, None) called_kwargs_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual(len(called_kwargs_list), 2) # trans_called_kwargs, trans_val_called_kwargs = called_kwargs_list _, trans_called_kwargs = called_kwargs_list[0] _, trans_val_called_kwargs = called_kwargs_list[1] self.assertEqual(trans_called_kwargs['name'], 'translation') self.assertEqual(trans_val_called_kwargs['name'], 'cyclegan_val') # test train gen samples trans_gen_sample = trans_called_kwargs['gen_samples'] print(trans_gen_sample[0].keys()) trans_gt_mask_list = [samp.img_mask for samp in trans_gen_sample] trans_gt_photo_list = [samp.img_photo for samp in trans_gen_sample] self.assertEqual(len(trans_gen_sample), 9) for idx, (mask, photo) in enumerate( zip(trans_gt_mask_list, trans_gt_photo_list)): sample_from_dataset = train_dataloader.dataset[idx]['inputs'] # data sample in test mode --> do not normed assert_allclose(mask, sample_from_dataset['img_mask']) assert_allclose(photo, sample_from_dataset['img_photo']) # test val gen samples trans_gen_sample = trans_val_called_kwargs['gen_samples'] trans_gt_mask_list = [samp.img_mask for samp in trans_gen_sample] trans_gt_photo_list = [samp.img_photo for samp in trans_gen_sample] self.assertEqual(len(trans_gen_sample), 9) for idx, (mask, photo) in enumerate( zip(trans_gt_mask_list, trans_gt_photo_list)): sample_from_dataset = val_dataloader.dataset[idx]['inputs'] assert_allclose(mask, sample_from_dataset['img_mask']) assert_allclose(photo, sample_from_dataset['img_photo']) # check input buffer input_buffer = hook.inputs_buffer input_buffer['translation'] # TODO: uncomment after support DDPM # def test_vis_ddpm_alias_with_user_defined_args(self): # ddpm_cfg = dict( # type='BasicGaussianDiffusion', # num_timesteps=4, # data_preprocessor=dict(type='DataPreprocessor'), # betas_cfg=dict(type='cosine'), # denoising=dict( # type='DenoisingUnet', # image_size=32, # in_channels=3, # base_channels=128, # resblocks_per_downsample=3, # attention_res=[16, 8], # use_scale_shift_norm=True, # dropout=0.3, # num_heads=4, # use_rescale_timesteps=True, # output_cfg=dict(mean='eps', var='learned_range')), # timestep_sampler=dict(type='UniformTimeStepSampler')) # model = MODELS.build(ddpm_cfg) # runner = MagicMock() # runner.model = model # runner.train_dataloader = MagicMock() # runner.train_dataloader.batch_size = 10 # hook = VisualizationHook( # interval=10, # n_samples=2, # vis_kwargs_list=dict( # type='DDPMDenoising', vis_mode='gif', name='ddpm', # n_samples=3)) # mock_visualuzer = MagicMock() # mock_visualuzer.add_datasample = MagicMock() # hook._visualizer = mock_visualuzer # # build a empty data sample # data_batch = [ # dict(inputs=None, data_sample=DataSample()) # for idx in range(10) # ] # hook.vis_sample(runner, 0, data_batch, None) # _, called_kwargs = mock_visualuzer.add_datasample.call_args # gen_samples = called_kwargs['gen_samples'] # self.assertEqual(len(gen_samples), 3) # self.assertEqual(called_kwargs['n_row'], min(hook.n_row, 3)) # # test user defined vis kwargs # hook.vis_kwargs_list = [ # dict( # type='Arguments', # forward_mode='sampling', # name='ddpm_sample', # n_samples=2, # n_row=4, # vis_mode='gif', # n_skip=1, # forward_kwargs=dict( # forward_mode='sampling', # sample_kwargs=dict(show_pbar=True, save_intermedia=True))) # noqa # ] # mock_visualuzer = MagicMock() # mock_visualuzer.add_datasample = MagicMock() # hook._visualizer = mock_visualuzer # # build a empty data sample # data_batch = [ # dict(inputs=None, data_sample=DataSample()) # for idx in range(10) # ] # hook.vis_sample(runner, 0, data_batch, None) # _, called_kwargs = mock_visualuzer.add_datasample.call_args # gen_samples = called_kwargs['gen_samples'] # self.assertEqual(len(gen_samples), 2) # self.assertEqual(called_kwargs['n_row'], min(hook.n_row, 2)) def test_after_val_iter(self): model = MagicMock() hook = VisualizationHook( interval=10, n_samples=2, vis_kwargs_list=dict(type='GAN')) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer runner = MagicMock() runner.model = model hook.after_val_iter(runner, 0, [dict()], [DataSample()]) mock_visualuzer.assert_not_called() def test_after_train_iter(self): gan_model_cfg = dict( type='DCGAN', noise_size=10, data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='DCGANGenerator', output_scale=32, base_channels=32)) model = MODELS.build(gan_model_cfg) runner = MagicMock() runner.model = model runner.train_dataloader = MagicMock() runner.train_dataloader.batch_size = 10 hook = VisualizationHook( interval=2, vis_kwargs_list=dict(type='GAN'), n_samples=9) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer # build a empty data sample data_batch = [ dict(inputs=None, data_samples=DataSample()) for idx in range(10) ] for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) self.assertEqual(mock_visualuzer.add_datasample.call_count, 1) # test vis with messagehub info --> str mock_visualuzer.add_datasample.reset_mock() message_hub = MessageHub.get_current_instance() feat_map = torch.randn(4, 16, 4, 4) vis_results = dict(feat_map=feat_map) message_hub.update_info('vis_results', vis_results) hook.message_vis_kwargs = 'feat_map' for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) called_args_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual(len(called_args_list), 2) # outputs + messageHub _, messageHub_vis_args = called_args_list[1] self.assertEqual(messageHub_vis_args['name'], 'train_feat_map') self.assertEqual(len(messageHub_vis_args['gen_samples']), 4) self.assertEqual(messageHub_vis_args['vis_mode'], None) self.assertEqual(messageHub_vis_args['n_row'], None) # test vis with messagehub info --> list[str] mock_visualuzer.add_datasample.reset_mock() hook.message_vis_kwargs = ['feat_map'] for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) called_args_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual(len(called_args_list), 2) # outputs + messageHub _, messageHub_vis_args = called_args_list[1] self.assertEqual(messageHub_vis_args['name'], 'train_feat_map') self.assertEqual(len(messageHub_vis_args['gen_samples']), 4) self.assertEqual(messageHub_vis_args['vis_mode'], None) self.assertEqual(messageHub_vis_args['n_row'], None) # test vis with messagehub info --> dict mock_visualuzer.add_datasample.reset_mock() hook.message_vis_kwargs = dict(key='feat_map', vis_mode='feature_map') for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) called_args_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual(len(called_args_list), 2) # outputs + messageHub _, messageHub_vis_args = called_args_list[1] self.assertEqual(messageHub_vis_args['name'], 'train_feat_map') self.assertEqual(len(messageHub_vis_args['gen_samples']), 4) self.assertEqual(messageHub_vis_args['vis_mode'], 'feature_map') self.assertEqual(messageHub_vis_args['n_row'], None) # test vis with messagehub info --> list[dict] mock_visualuzer.add_datasample.reset_mock() feat_map = torch.randn(4, 16, 4, 4) x_t = [DataSample(info='x_t')] vis_results = dict(feat_map=feat_map, x_t=x_t) message_hub.update_info('vis_results', vis_results) hook.message_vis_kwargs = [ dict(key='feat_map', vis_mode='feature_map'), dict(key='x_t') ] for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) called_args_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual(len(called_args_list), 3) # outputs + messageHub # output_vis_args = called_args_list[0].kwargs _, feat_map_vis_args = called_args_list[1] self.assertEqual(feat_map_vis_args['name'], 'train_feat_map') self.assertEqual(len(feat_map_vis_args['gen_samples']), 4) self.assertEqual(feat_map_vis_args['vis_mode'], 'feature_map') self.assertEqual(feat_map_vis_args['n_row'], None) _, x_t_vis_args = called_args_list[2] self.assertEqual(x_t_vis_args['name'], 'train_x_t') self.assertEqual(len(x_t_vis_args['gen_samples']), 1) self.assertEqual(x_t_vis_args['vis_mode'], None) self.assertEqual(x_t_vis_args['n_row'], None) # test vis messageHub info --> errors hook.message_vis_kwargs = 'error' with self.assertRaises(RuntimeError): hook.after_train_iter(runner, 1, data_batch, None) message_hub.runtime_info.clear() with self.assertRaises(RuntimeError): hook.after_train_iter(runner, 1, data_batch, None) hook.message_vis_kwargs = dict(key='feat_map', vis_mode='feature_map') message_hub.update_info('vis_results', dict(feat_map='feat_map')) with self.assertRaises(TypeError): hook.after_train_iter(runner, 1, data_batch, None) def test_after_train_iter_contain_mul_elements(self): # test contain_mul_elements + n_row != None # n_row = 8, n_samples = 3, batch_size = 2, model_n_samples = 4 # run math.ceil(3 / 2) = 2 times, visualize 2 * 4 = 8 samples, class MockModel: def __init__(self, n_samples): self.n_samples = n_samples def noise_fn(self, *args, **kwargs): return torch.randn(2, 2) def val_step(self, *args, **kwargs): return [DataSample() for _ in range(self.n_samples)] def eval(self): return self def train(self): return self runner = MagicMock() runner.model = MockModel(n_samples=4) runner.train_dataloader = MagicMock() runner.train_dataloader.batch_size = 2 hook = VisualizationHook( interval=2, vis_kwargs_list=dict(type='GAN'), n_samples=3, n_row=8) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer # build a empty data sample data_batch = [ dict(inputs=None, data_samples=DataSample()) for idx in range(10) ] for idx in range(3): hook.after_train_iter(runner, idx, data_batch, None) self.assertEqual(mock_visualuzer.add_datasample.call_count, 1) called_args_list = mock_visualuzer.add_datasample.call_args_list[0] self.assertEqual(len(called_args_list[1]['gen_samples']), 8) def test_after_test_iter(self): model = MagicMock() hook = VisualizationHook( interval=10, n_samples=2, max_save_at_test=None, test_vis_keys=['ema', 'orig', 'new_model.x_t', 'gt_img'], vis_kwargs_list=dict(type='GAN')) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer runner = MagicMock() runner.model = model gt_list = [torch.randn(3, 6, 6) for _ in range(4)] ema_list = [torch.randn(3, 6, 6) for _ in range(4)] orig_list = [torch.randn(3, 6, 6) for _ in range(4)] x_t_list = [torch.randn(3, 6, 6) for _ in range(4)] outputs = [] for gt, ema, orig, x_t in zip(gt_list, ema_list, orig_list, x_t_list): gen_sample = DataSample( gt_img=gt, ema=DataSample(fake_img=ema), orig=DataSample(fake_img=orig), new_model=DataSample(x_t=x_t)) outputs.append(gen_sample) hook.after_test_iter(runner, 42, [], outputs) args_list = mock_visualuzer.add_datasample.call_args_list self.assertEqual( len(args_list), len(hook.test_vis_keys_list) * len(gt_list)) # check target consistency for idx, args in enumerate(args_list): _, called_kwargs = args gen_samples = called_kwargs['gen_samples'] name = called_kwargs['name'] batch_idx = called_kwargs['step'] target_keys = called_kwargs['target_keys'] self.assertEqual(len(gen_samples), 1) idx_in_outputs = idx // 4 self.assertEqual(batch_idx, idx_in_outputs + 42 * len(outputs)) self.assertEqual(outputs[idx_in_outputs], gen_samples[0]) # check ema if idx % 4 == 0: self.assertEqual(target_keys, 'ema') self.assertEqual(name, 'test_ema') # check orig elif idx % 4 == 1: self.assertEqual(target_keys, 'orig') self.assertEqual(name, 'test_orig') # check x_t elif idx % 4 == 2: self.assertEqual(target_keys, 'new_model.x_t') self.assertEqual(name, 'test_new_model_x_t') # check gt else: self.assertEqual(target_keys, 'gt_img') self.assertEqual(name, 'test_gt_img') # test get target key automatically hook.test_vis_keys_list = None mock_visualuzer.add_datasample.reset_mock() hook.after_test_iter(runner, 42, [], outputs) kwargs_list = [ args[1] for args in mock_visualuzer.add_datasample.call_args_list ] self.assertTrue(all([kwargs['target_keys'] for kwargs in kwargs_list])) # test get target key automatically with error outputs = [DataSample(ema=DataSample(fake_img=torch.randn(3, 6, 6)))] with self.assertRaises(AssertionError): hook.after_test_iter(runner, 42, [], outputs) # test max save time hook = VisualizationHook( interval=10, n_samples=2, test_vis_keys='ema', vis_kwargs_list=dict(type='GAN'), max_save_at_test=3) mock_visualuzer = MagicMock() mock_visualuzer.add_datasample = MagicMock() hook._visualizer = mock_visualuzer runner = MagicMock() runner.model = model ema_list = [torch.randn(3, 6, 6) for _ in range(4)] outputs = [ DataSample(ema=DataSample(fake_img=ema)) for ema in ema_list ] hook.after_test_iter(runner, 42, [], outputs) mock_visualuzer.add_datasample.assert_not_called() hook.after_test_iter(runner, 0, [], outputs) assert mock_visualuzer.add_datasample.call_count == 3 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_optimizers/test_multi_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch.nn as nn from mmengine import MMLogger from mmengine.optim import OptimWrapper from mmagic.engine.optimizers import MultiOptimWrapperConstructor logger = MMLogger.get_instance('test_multi_optimizer_constructor') class ToyModel(nn.Module): def __init__(self) -> None: super().__init__() self.generator = nn.Conv2d(3, 3, 1) self.discriminator = nn.Conv2d(3, 3, 1) class TextEncoder(nn.Module): def __init__(self): super().__init__() self.embedding = nn.Embedding(100, 100) class ToyModel2(nn.Module): def __init__(self) -> None: super().__init__() self.m1 = ToyModel() self.m2 = nn.Conv2d(3, 3, 1) self.m3 = nn.Linear(2, 2) self.text_encoder = TextEncoder() def test_optimizer_constructor(): # test optimizer wrapper cfg is a dict optim_wrapper_constructor = MultiOptimWrapperConstructor( optim_wrapper_cfg=dict( generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='SGD', lr=0.1)))) model = ToyModel() optim_wrapper_dict = optim_wrapper_constructor(model) assert optim_wrapper_dict.__class__.__name__ == 'OptimWrapperDict' assert set(optim_wrapper_dict.optim_wrappers) == set( ['generator', 'discriminator']) # test optimizer wrapper is dict of **modules** optim_wrapper = { '.*embedding': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-4, 'betas': (0.9, 0.99) } }, 'm1.generator': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-5, 'betas': (0.9, 0.99) } }, 'm2': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-5, } } } optim_wrapper_constructor = MultiOptimWrapperConstructor( optim_wrapper_cfg=dict( generator=dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99))), discriminator=dict( type='OptimWrapper', optimizer=dict(type='SGD', lr=0.1)))) optim_wrapper_cfg = { '.*embedding': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-4, 'betas': (0.9, 0.99) } }, 'm1.generator': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-5, 'betas': (0.9, 0.99) } }, 'm2': { 'type': 'OptimWrapper', 'optimizer': { 'type': 'Adam', 'lr': 1e-5, } } } optim_wrapper_constructor = MultiOptimWrapperConstructor(optim_wrapper_cfg) model = ToyModel2() optim_wrapper_dict = optim_wrapper_constructor(model) # optim_wrapper_cfg should be a dict with pytest.raises(TypeError): MultiOptimWrapperConstructor(1) # parawise_cfg should be set in each optimizer separately with pytest.raises(AssertionError): MultiOptimWrapperConstructor(dict(), dict()) # test optimizer wrapper with multi param groups optim_wrapper_constructor = MultiOptimWrapperConstructor( optim_wrapper_cfg=dict( modules=['.*text_encoder', '.*generator', 'm2'], optimizer=dict( type='Adam', lr=1e-4, betas=(0.9, 0.99), ), accumulative_counts=4)) model = ToyModel2() optim_wrapper = optim_wrapper_constructor(model) assert isinstance(optim_wrapper, OptimWrapper) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_optimizers/test_pggan_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import MagicMock from mmengine.model import MMSeparateDistributedDataParallel from mmagic.engine import PGGANOptimWrapperConstructor from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() class TestPGGANOptimWrapperConstructor(TestCase): pggan_cfg = dict( type='ProgressiveGrowingGAN', data_preprocessor=dict(type='DataPreprocessor'), noise_size=512, generator=dict(type='PGGANGenerator', out_scale=8), discriminator=dict(type='PGGANDiscriminator', in_scale=8), nkimgs_per_scale={ '4': 600, '8': 1200 }, transition_kimgs=600, ema_config=dict(interval=1)) base_lr = 0.001 lr_schedule = dict(generator={'8': 0.0015}, discriminator={'8': 0.0015}) optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=lr_schedule) def test(self): pggan = MODELS.build(self.pggan_cfg) optim_wrapper_dict_builder = PGGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(pggan) optim_keys = set(optim_wrapper_dict.keys()) scales = self.pggan_cfg['nkimgs_per_scale'].keys() self.assertEqual( optim_keys, set([ f'{model}_{scale}' for model in ['generator', 'discriminator'] for scale in scales ])) # check lr for scale in scales: gen_optim = optim_wrapper_dict[f'generator_{scale}'] gen_lr = gen_optim.optimizer.param_groups[0]['lr'] disc_optim = optim_wrapper_dict[f'discriminator_{scale}'] disc_lr = disc_optim.optimizer.param_groups[0]['lr'] self.assertEqual( gen_lr, self.lr_schedule['generator'].get(str(scale), self.base_lr)) self.assertEqual( disc_lr, self.lr_schedule['discriminator'].get( str(scale), self.base_lr)) # test pggan is Wrapper pggan_with_wrapper = MagicMock( module=pggan, spec=MMSeparateDistributedDataParallel) optim_wrapper_dict = optim_wrapper_dict_builder(pggan_with_wrapper) # test raise error with self.assertRaises(TypeError): optim_wrapper_dict_builder = PGGANOptimWrapperConstructor( 'optim_wrapper') # test same optimizer optim_wrapper_cfg = deepcopy(self.optim_wrapper_cfg) optim_wrapper_cfg['reset_optim_for_new_scale'] = False optim_wrapper_dict_builder = PGGANOptimWrapperConstructor( optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(pggan) # check id are same gen_optims = [optim_wrapper_dict[k] for k in optim_keys if 'gen' in k] disc_optims = [ optim_wrapper_dict[k] for k in optim_keys if 'disc' in k ] self.assertTrue(all([id(gen_optims[0]) == id(o) for o in gen_optims])) self.assertTrue( all([id(disc_optims[0]) == id(o) for o in disc_optims])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_optimizers/test_singan_optimizer_constructor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock from mmagic.engine import SinGANOptimWrapperConstructor from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() class TestSinGANOptimWrapperConstructor(TestCase): singan_cfg = dict( type='SinGAN', num_scales=2, data_preprocessor=dict( type='DataPreprocessor', non_image_keys=['input_sample']), generator=dict( type='SinGANMultiScaleGenerator', in_channels=3, out_channels=3, num_scales=2), discriminator=dict( type='SinGANMultiScaleDiscriminator', in_channels=3, num_scales=2), noise_weight_init=0.1, iters_per_scale=20, test_pkl_data=None) optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999)))) def test(self): singan = MODELS.build(self.singan_cfg) optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(singan) optim_keys = set(optim_wrapper_dict.keys()) self.assertEqual( optim_keys, set([ f'{model}_{scale}' for model in ['generator', 'discriminator'] for scale in range(2 + 1) ])) # test singan is Wrapper singan_with_wrapper = MagicMock( module=singan, generator=MagicMock(module=singan.generator), discriminator=MagicMock(module=singan.discriminator)) optim_wrapper_dict = optim_wrapper_dict_builder(singan_with_wrapper) # test raise error with self.assertRaises(TypeError): optim_wrapper_dict_builder = SinGANOptimWrapperConstructor('test') with self.assertRaises(AssertionError): optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg, 'test') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_runner/test_log_processor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock from mmagic.engine import LogProcessor as LogProcessor class TestLogProcessor: def setup(self): runner = MagicMock() runner.epoch = 1 runner.iter = 10 runner.max_epochs = 10 runner.max_iters = 50 runner.train_dataloader = [0] * 20 runner.val_dataloader = [0] * 10 runner.test_dataloader = [0] * 5 runner.train_loop.dataloader = [0] * 20 runner.val_loop.total_length = 10 runner.test_loop.total_length = 5 self.runner = runner def test_get_dataloader_size(self): log_processor = LogProcessor(by_epoch=True) del self.runner.train_loop.total_length assert log_processor._get_dataloader_size(self.runner, 'train') == 20 assert log_processor._get_dataloader_size(self.runner, 'val') == 10 assert log_processor._get_dataloader_size(self.runner, 'test') == 5 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_runner/test_loop_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock import pytest from mmengine.evaluator import Evaluator as BaseEvaluator from mmagic.engine.runner.loop_utils import (is_evaluator, update_and_check_evaluator) from mmagic.evaluation import Evaluator def test_is_evaluator(): evaluator = dict(type='Evaluator', metrics=[dict(type='PSNR')]) assert is_evaluator(evaluator) evaluator = [dict(type='PSNR'), dict(type='SSIM')] assert is_evaluator(evaluator) evaluator = MagicMock(spec=BaseEvaluator) assert is_evaluator(evaluator) evaluator = 'SSIM' assert not is_evaluator(evaluator) evaluator = [dict(metrics='PSNR'), dict(metrics='SSIM')] assert not is_evaluator(evaluator) evaluator = dict(type='PSNR') assert not is_evaluator(evaluator) def test_update_and_check_evaluator(): evaluator = MagicMock(spec=BaseEvaluator) assert evaluator == update_and_check_evaluator(evaluator) evaluator = MagicMock(spec=Evaluator) assert evaluator == update_and_check_evaluator(evaluator) evaluator = [dict(type='PSNR'), dict(type='SSIM')] evaluator = update_and_check_evaluator(evaluator) assert isinstance(evaluator, dict) assert evaluator['type'] == 'Evaluator' evaluator = 'this is wrong' with pytest.raises(AssertionError): update_and_check_evaluator(evaluator) evaluator = dict(metrics=[dict(type='PSNR')]) evaluator = update_and_check_evaluator(evaluator) assert 'type' in evaluator assert evaluator['type'] == 'Evaluator' evaluator = dict(type='Evaluator', metrics=[dict(type='PSNR')]) evaluator = update_and_check_evaluator(evaluator) assert evaluator['type'] == 'Evaluator' evaluator = dict(type='Evaluator', metrics=[dict(type='PSNR')]) evaluator = update_and_check_evaluator(evaluator) assert evaluator['type'] == 'Evaluator' evaluator = dict(type='Evaluator') evaluator = update_and_check_evaluator(evaluator) assert evaluator['metrics'] is None def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_runner/test_multi_loops.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock from mmengine.evaluator import Evaluator as BaseEvaluator from mmagic.engine import MultiTestLoop, MultiValLoop from mmagic.evaluation import Evaluator def build_dataloader(loader, **kwargs): if isinstance(loader, dict): dataset = MagicMock() dataloader = MagicMock() dataloader.dataset = dataset return dataloader else: return loader def build_metrics(metrics): if isinstance(metrics, dict): return [MagicMock(**metrics)] elif isinstance(metrics, list): return [MagicMock(**metric) for metric in metrics] else: raise ValueError('Unsupported metrics type in MockRunner.') def build_evaluator(evaluator): if isinstance(evaluator, BaseEvaluator): return evaluator if isinstance(evaluator, dict): # a dirty way to check Evaluator type if 'type' in evaluator and evaluator['type'] == 'Evaluator': spec = Evaluator else: spec = BaseEvaluator # if `metrics` in dict keys, it means to build customized evalutor if 'metrics' in evaluator: evaluator_ = MagicMock(spec=spec) evaluator_.metrics = build_metrics(evaluator['metrics']) return evaluator_ # otherwise, default evalutor will be built else: evaluator_ = MagicMock(spec=spec) evaluator_.metrics = build_metrics(evaluator) return evaluator_ elif isinstance(evaluator, list): # use the default `Evaluator` evaluator_ = MagicMock(spec=Evaluator) evaluator_.metrics = build_metrics(evaluator) return evaluator_ else: raise TypeError( 'evaluator should be one of dict, list of dict, and Evaluator' f', but got {evaluator}') def build_mock_runner(): runner = MagicMock() runner.build_evaluator = build_evaluator runner.build_dataloader = build_dataloader return runner class TestLoop(TestCase): def _test_init(self, is_val): LOOP_CLS = MultiValLoop if is_val else MultiTestLoop # test init with single evaluator runner = build_mock_runner() dataloaders = MagicMock() evaluators = [dict(prefix='m1'), dict(prefix='m2')] loop = LOOP_CLS(runner, dataloaders, evaluators) self.assertEqual(len(loop.evaluators), 1) self.assertIsInstance(loop.evaluators[0], Evaluator) self.assertEqual(loop.evaluators[0].metrics[0].prefix, 'm1') self.assertEqual(loop.evaluators[0].metrics[1].prefix, 'm2') # test init with single evaluator and dataloader is list runner = build_mock_runner() dataloaders = [MagicMock()] evaluators = dict( type='Evaluator', metrics=[dict(prefix='m1'), dict(prefix='m2')]) loop = LOOP_CLS(runner, dataloaders, evaluators) self.assertEqual(len(loop.evaluators), 1) self.assertIsInstance(loop.evaluators[0], BaseEvaluator) self.assertEqual(loop.evaluators[0].metrics[0].prefix, 'm1') self.assertEqual(loop.evaluators[0].metrics[1].prefix, 'm2') # test init with multi evaluators runner = build_mock_runner() dataloaders = [MagicMock(), MagicMock()] evaluators = [ dict( type='Evaluator', metrics=[dict(prefix='m1'), dict(prefix='m2')]), dict(metrics=dict(prefix='m3')) ] loop = LOOP_CLS(runner, dataloaders, evaluators) self.assertEqual(len(loop.evaluators), 2) self.assertIsInstance(loop.evaluators[0], BaseEvaluator) self.assertIsInstance(loop.evaluators[1], Evaluator) self.assertEqual(loop.evaluators[0].metrics[0].prefix, 'm1') self.assertEqual(loop.evaluators[0].metrics[1].prefix, 'm2') self.assertEqual(loop.evaluators[1].metrics[0].prefix, 'm3') # test call total length before self.run self.assertEqual(loop.total_length, 0) def test_init(self): self._test_init(True) # val self._test_init(False) # test def _test_run(self, is_val): # since we have tested init, we direct use predefined mock object to # test run function LOOP_CLS = MultiValLoop if is_val else MultiTestLoop # test single evaluator runner = build_mock_runner() dataloader = MagicMock() dataloader.batch_size = 3 metric1, metric2, metric3 = MagicMock(), MagicMock(), MagicMock() evaluator = MagicMock(spec=Evaluator) evaluator.prepare_metrics = MagicMock() evaluator.prepare_samplers = MagicMock( return_value=[[[metric1, metric2], [dict(inputs=1), dict( inputs=2)]], [[metric3], [dict(inputs=4)]]]) loop = LOOP_CLS( runner=runner, dataloader=dataloader, evaluator=evaluator) assert len(loop.evaluators) == 1 assert loop.evaluators[0] == evaluator # test run loop.run() assert loop.total_length == 3 call_args_list = evaluator.call_args_list for idx, call_args in enumerate(call_args_list): if idx == 0: inputs = dict(inputs=1) elif idx == 1: inputs = dict(inputs=2) else: inputs = dict(inputs=4) assert call_args[1] == inputs # test multi evaluator runner = build_mock_runner() dataloader = MagicMock() dataloader.batch_size = 3 metric11, metric12, metric13 = MagicMock(), MagicMock(), MagicMock() metric21 = MagicMock() evaluator1 = MagicMock(spec=Evaluator) evaluator1.prepare_metrics = MagicMock() evaluator1.prepare_samplers = MagicMock( return_value=[[[metric11, metric12], [dict(inputs=1), dict( inputs=2)]], [[metric13], [dict(inputs=4)]]]) evaluator2 = MagicMock(spec=Evaluator) evaluator2.prepare_metrics = MagicMock() evaluator2.prepare_samplers = MagicMock( return_value=[[[metric21], [dict(inputs=3)]]]) loop = LOOP_CLS( runner=runner, dataloader=[dataloader, dataloader], evaluator=[evaluator1, evaluator2]) assert len(loop.evaluators) == 2 assert loop.evaluators[0] == evaluator1 assert loop.evaluators[1] == evaluator2 loop.run() assert loop.total_length == 4 call_args_list = evaluator1.call_args_list for idx, call_args in enumerate(call_args_list): if idx == 0: inputs = dict(inputs=1) elif idx == 1: inputs = dict(inputs=2) else: inputs = dict(inputs=4) assert call_args[1] == inputs call_args_list = evaluator2.call_args_list for idx, call_args in enumerate(call_args_list): if idx == 0: inputs = dict(inputs=3) assert call_args[1] == inputs def test_run(self): self._test_run(True) # val self._test_run(False) # test def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_schedulers/test_linear_lr_scheduler_with_interval.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import numpy as np import torch import torch.nn.functional as F import torch.optim as optim from mmengine import MessageHub from mmagic.engine.schedulers import LinearLrInterval class ToyModel(torch.nn.Module): def __init__(self): super().__init__() self.conv1 = torch.nn.Conv2d(1, 1, 1) self.conv2 = torch.nn.Conv2d(1, 1, 1) def forward(self, x): return self.conv2(F.relu(self.conv1(x))) class TestLinearLrInterval(TestCase): def setUp(self): """Setup the model and optimizer which are used in every test method. TestCase calls functions in this order: setUp() -> testMethod() -> tearDown() -> cleanUp() """ self.model = ToyModel() lr = 1 self.optimizer = optim.SGD([{ 'params': self.model.conv1.parameters() }], lr=lr, momentum=0.01, weight_decay=5e-4) def test_step(self): targets = torch.linspace(1., 0., 11) param_scheduler = LinearLrInterval( self.optimizer, interval=1, by_epoch=False, start_factor=1.0, end_factor=0, begin=0, end=10) messageHub = MessageHub.get_current_instance() for step in range(10): messageHub.update_info('iter', step) param_scheduler.step() np.testing.assert_almost_equal(param_scheduler._get_value(), targets[step].item()) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_engine/test_schedulers/test_reduce_lr_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import pytest import torch import torch.nn.functional as F import torch.optim as optim from mmengine import MessageHub from mmagic.engine.schedulers import ReduceLR class ToyModel(torch.nn.Module): def __init__(self): super().__init__() self.conv1 = torch.nn.Conv2d(1, 1, 1) self.conv2 = torch.nn.Conv2d(1, 1, 1) def forward(self, x): return self.conv2(F.relu(self.conv1(x))) class TestLRScheduler(TestCase): def setUp(self): """Setup the model and optimizer which are used in every test method. TestCase calls functions in this order: setUp() -> testMethod() -> tearDown() -> cleanUp() """ self.model = ToyModel() self.optimizer = optim.SGD( self.model.parameters(), lr=0.05, momentum=0.01, weight_decay=5e-4) def test_reduce_lr_scheduler(self): message_hub = MessageHub.get_instance('reduce_lr') scheduler = ReduceLR(self.optimizer, patience=1) scheduler.last_step = 0 results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 scheduler.last_step = 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert abs(results[0] - 0.005) < 1e-8 assert scheduler.num_bad_epochs == 0 scheduler = ReduceLR(self.optimizer, patience=1, mode='max') scheduler.last_step = 0 results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 scheduler.last_step = 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert abs(results[0] - 0.005) < 1e-8 assert scheduler.num_bad_epochs == 0 scheduler = ReduceLR( self.optimizer, patience=1, mode='max', threshold_mode='abs') scheduler.last_step = 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 1 scheduler = ReduceLR( self.optimizer, patience=1, mode='min', threshold_mode='abs') scheduler.last_step = 1 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 0 message_hub.update_scalar('value', 1) results = scheduler._get_value() assert results == [0.05] assert scheduler.num_bad_epochs == 1 with pytest.raises(ValueError): ReduceLR(self.optimizer, mode='ysli') with pytest.raises(ValueError): ReduceLR(self.optimizer, threshold_mode='ysli') with pytest.raises(ValueError): ReduceLR(self.optimizer, factor=1.5) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_evaluator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import MagicMock, patch from mmagic.evaluation import (Evaluator, FrechetInceptionDistance, InceptionScore) from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() fid_loading_str = 'mmagic.evaluation.metrics.fid.FrechetInceptionDistance._load_inception' # noqa is_loading_str = 'mmagic.evaluation.metrics.inception_score.InceptionScore._load_inception' # noqa loading_mock = MagicMock(return_value=(MagicMock(), 'StyleGAN')) class TestEvaluator(TestCase): @classmethod def setUpClass(cls): cls.metrics = [ dict( type='InceptionScore', fake_nums=10, inception_style='pytorch', sample_model='orig'), dict( type='FrechetInceptionDistance', fake_nums=11, inception_style='pytorch', sample_model='orig'), dict(type='TransFID', fake_nums=10), ] @patch(is_loading_str, loading_mock) @patch(fid_loading_str, loading_mock) def test_init(self): evaluator = Evaluator(self.metrics) self.assertFalse(evaluator.is_ready) @patch(is_loading_str, loading_mock) @patch(fid_loading_str, loading_mock) def test_prepare_metric(self): evaluator = Evaluator(self.metrics) model = MagicMock() model.data_preprocessor.device = 'cpu' dataloader = MagicMock() with patch('mmagic.evaluation.metrics.fid.prepare_inception_feat'): evaluator.prepare_metrics(model, dataloader) self.assertTrue(evaluator.is_ready) evaluator = Evaluator(self.metrics) evaluator.metrics = [MagicMock()] evaluator.is_ready = True evaluator.prepare_metrics(model, dataloader) evaluator.metrics[0].assert_not_called() @patch(is_loading_str, loading_mock) @patch(fid_loading_str, loading_mock) def test_prepare_samplers(self): evaluator = Evaluator(self.metrics) model = MagicMock() model.data_preprocessor.device = 'cpu' dataloader = MagicMock() dataloader.batch_size = 2 metric_sampler_list = evaluator.prepare_samplers(model, dataloader) self.assertEqual(len(metric_sampler_list), 2) for metric_cls in [FrechetInceptionDistance, InceptionScore]: self.assertTrue( any([ isinstance(m, metric_cls) for m in metric_sampler_list[0][0] ])) self.assertEqual(metric_sampler_list[0][1].max_length, 11) self.assertEqual(len(metric_sampler_list[0][1]), 6) # test prepare metrics with different `sample_model` cfg = deepcopy(self.metrics) cfg.append( dict( type='FrechetInceptionDistance', fake_nums=12, inception_style='pytorch', sample_model='ema')) evaluator = Evaluator(cfg) # mock metrics model = MagicMock() model.data_preprocessor.device = 'cpu' dataloader = MagicMock() dataloader.batch_size = 2 metric_sampler_list = evaluator.prepare_samplers(model, dataloader) self.assertEqual(len(metric_sampler_list), 3) # test prepare sampler with metric.need_cond_input = True cfg = deepcopy(self.metrics) cfg += [ dict( type='FrechetInceptionDistance', fake_nums=12, inception_style='pytorch', sample_model='ema'), dict( type='FrechetInceptionDistance', fake_nums=12, inception_style='pytorch', sample_model='ema', need_cond_input=True), dict( type='InceptionScore', fake_nums=10, inception_style='pytorch', sample_model='ema', need_cond_input=True), dict( type='InceptionScore', fake_nums=10, inception_style='pytorch', sample_model='orig', need_cond_input=True), ] # all metrics (5 groups): [[IS-orig, FID-orig], [TransFID-orig], # [FID-ema], [FID-cond-ema, IS-cond-ema], # [IS-cond-orig]] evaluator = Evaluator(cfg) # mock metrics model = MagicMock() model.data_preprocessor.device = 'cpu' dataloader = MagicMock() dataloader.batch_size = 2 metric_sampler_list = evaluator.prepare_samplers(model, dataloader) self.assertEqual(len(metric_sampler_list), 5) @patch(is_loading_str, loading_mock) @patch(fid_loading_str, loading_mock) def test_process(self): evaluator = Evaluator(self.metrics) metrics_mock = [MagicMock(), MagicMock()] data_samples = [DataSample(a=1, b=2), dict(c=3, d=4)] # NOTE: data_batch is not used in evaluation evaluator.process( data_batch=None, data_samples=data_samples, metrics=metrics_mock) for metric in metrics_mock: metric.process.assert_called_with(None, [{ 'a': 1, 'b': 2 }, { 'c': 3, 'd': 4 }]) @patch(is_loading_str, loading_mock) @patch(fid_loading_str, loading_mock) def test_evaluate(self): evaluator = Evaluator(self.metrics) # mock metrics metric_mock1, metric_mock2 = MagicMock(), MagicMock() metric_mock1.evaluate = MagicMock(return_value=dict(m1=233)) metric_mock2.evaluate = MagicMock(return_value=dict(m2=42)) evaluator.metrics = [metric_mock1, metric_mock2] res = evaluator.evaluate() self.assertEqual(res, dict(m1=233, m2=42)) # test raise value error with duplicate keys metric_mock3, metric_mock4 = MagicMock(), MagicMock() metric_mock3.evaluate = MagicMock(return_value=dict(m=3)) metric_mock4.evaluate = MagicMock(return_value=dict(m=4)) evaluator.metrics = [metric_mock3, metric_mock4] with self.assertRaises(ValueError): evaluator.evaluate() class TestNonMetricEvaluator(TestCase): def test_init(self): evaluator = Evaluator(None) self.assertIsNone(evaluator.metrics) def test_prepare_metrics(self): evaluator = Evaluator(None) evaluator.prepare_metrics(None, None) self.assertTrue(evaluator.is_ready) def test_prepare_samplers(self): evaluator = Evaluator(None) metric_sampler_list = evaluator.prepare_samplers(None, None) self.assertEqual(metric_sampler_list, [[[None], []]]) def test_process(self): evaluator = Evaluator(None) evaluator.process(None, None, None) def test_evalute(self): evaluator = Evaluator(None) output = evaluator.evaluate() self.assertEqual(output, {'No Metric': 'Nan'}) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_functional/test_fid_inception.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.evaluation.functional.fid_inception import (InceptionV3, fid_inception_v3) class TestFIDInception: @classmethod def setup_class(cls): cls.load_fid_inception = False def test_fid_inception(self): inception = InceptionV3(load_fid_inception=self.load_fid_inception) imgs = torch.randn((2, 3, 256, 256)) out = inception(imgs)[0] assert out.shape == (2, 2048, 1, 1) imgs = torch.randn((2, 3, 512, 512)) out = inception(imgs)[0] assert out.shape == (2, 2048, 1, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_fid_inception_cuda(self): inception = InceptionV3( load_fid_inception=self.load_fid_inception).cuda() imgs = torch.randn((2, 3, 256, 256)).cuda() out = inception(imgs)[0] assert out.shape == (2, 2048, 1, 1) imgs = torch.randn((2, 3, 512, 512)).cuda() out = inception(imgs)[0] assert out.shape == (2, 2048, 1, 1) def test_load_fid_inception(): fid_net = fid_inception_v3(load_ckpt=False) inputs = torch.randn(1, 3, 299, 299) outputs = fid_net(inputs) assert outputs.shape == (1, 1008) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_functional/test_gaussian_funcs.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np from mmagic.evaluation.functional import gauss_gradient def test_gauss_gradient(): img = np.random.randint(0, 255, size=(8, 8, 3)) grad = gauss_gradient(img, 1.4) assert grad.shape == (8, 8, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_functional/test_inception_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock from torch.utils.data import Dataset from mmagic.datasets.transforms import LoadImageFromFile from mmagic.evaluation.functional.inception_utils import ( get_inception_feat_cache_name_and_args, get_vgg_feat_cache_name_and_args) def test_inception_feat_cache_name_args(): dataloader = MagicMock() dataloader.dataset = MagicMock(spec=Dataset) dataloader.dataset.data_root = 'test_root' dataloader.dataset.data_prefix = 'test_prefix' dataloader.dataset.metainfo = dict(meta_info='test_meta') dataloader.dataset.pipeline = LoadImageFromFile(key='img') metric = MagicMock() metric.inception_style = 'test_style' metric.real_key = 'test_key' metric.inception_args = dict(args='test_args') cache_tag_1, args_1 = get_inception_feat_cache_name_and_args( dataloader, metric, 10, True, True) dataloader = MagicMock() dataloader.dataset = MagicMock(spec=Dataset) dataloader.dataset.data_root = 'test_root' dataloader.dataset.data_prefix = 'test_prefix' dataloader.dataset.metainfo = dict(meta_info='test_meta') dataloader.dataset.pipeline = LoadImageFromFile(key='img') metric = MagicMock() metric.inception_style = 'test_style' metric.real_key = 'test_key' metric.inception_args = dict(args='test_args') cache_tag_2, args_2 = get_inception_feat_cache_name_and_args( dataloader, metric, 10, True, True) # check whether cache name are same with the same inputs assert cache_tag_1 == cache_tag_2 assert args_1 == args_2 def test_vgg_feat_cache_name_args(): dataloader = MagicMock() dataloader.dataset = MagicMock(spec=Dataset) dataloader.dataset.data_root = 'test_root' dataloader.dataset.data_prefix = 'test_prefix' dataloader.dataset.metainfo = dict(meta_info='test_meta') dataloader.dataset.pipeline = LoadImageFromFile(key='img') metric = MagicMock() metric.inception_style = 'test_style' cache_tag_1, args_1 = get_vgg_feat_cache_name_and_args(dataloader, metric) dataloader = MagicMock() dataloader.dataset = MagicMock(spec=Dataset) dataloader.dataset.data_root = 'test_root' dataloader.dataset.data_prefix = 'test_prefix' dataloader.dataset.metainfo = dict(meta_info='test_meta') dataloader.dataset.pipeline = LoadImageFromFile(key='img') cache_tag_2, args_2 = get_vgg_feat_cache_name_and_args(dataloader, metric) # check whether cache name are same with the same inputs assert cache_tag_1 == cache_tag_2 assert args_1 == args_2 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_base_gen_metric.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock, patch import pytest import torch from mmengine.model import MMDistributedDataParallel from mmagic.evaluation.metrics.base_gen_metric import (GenerativeMetric, GenMetric) def mock_collect_fn(results, *args, **kwargs): return results[0] @patch('mmagic.evaluation.metrics.base_gen_metric.collect_results', mock_collect_fn) class ToyMetric(GenMetric): def process(self, data_batch, data_samples): return def compute_metrics(self, results): return dict(score=1) @patch('mmagic.evaluation.metrics.base_gen_metric.collect_results', mock_collect_fn) class ToyGenerativeMetric(GenerativeMetric): def process(self, data_batch, data_samples): return def compute_metrics(self, results): return dict(score=1) def test_GenMetric(): metric = ToyMetric(10, 10) assert metric.real_nums_per_device == 10 metric.real_results = [] # test get_metric_sampler model = MagicMock() dataset = MagicMock() dataset.__len__.return_value = 10 dataloader = MagicMock() dataloader.batch_size = 4 dataloader.dataset = dataset sampler = metric.get_metric_sampler(model, dataloader, [metric]) assert sampler.dataset == dataset # test prepare model = MagicMock(spec=MMDistributedDataParallel) preprocessor = MagicMock() model.module = MagicMock() model.module.data_preprocessor = preprocessor metric.prepare(model, dataloader) assert metric.data_preprocessor == preprocessor # test raise error with dataset is length than real_nums dataset.__len__.return_value = 5 with pytest.raises(AssertionError): metric.get_metric_sampler(model, dataloader, [metric]) def test_GenerativeMetric(): metric = ToyGenerativeMetric(11, need_cond_input=True) assert metric.need_cond_input assert metric.real_nums == 0 assert metric.fake_nums == 11 # NOTE: only test whether returned sampler is correct in this UT def side_effect(index): return {'gt_label': [i for i in range(index, index + 3)]} dataset = MagicMock() dataset.__len__ = MagicMock(return_value=2) dataset.get_data_info.side_effect = side_effect dataloader = MagicMock() dataloader.batch_size = 10 dataloader.dataset = dataset model = MagicMock() sampler = metric.get_metric_sampler(model, dataloader, [metric]) assert sampler.dataset == dataset assert sampler.batch_size == 10 assert sampler.max_length == 11 assert sampler.sample_model == 'ema' # index passed to `side_effect` can only be 0 or 1 assert len(sampler) == 2 iterator = iter(sampler) output = next(iterator) assert output['inputs'] == dict( sample_model='ema', num_batches=10, sample_kwargs={}) assert len(output['data_samples']) == 10 target_label_list = [ torch.FloatTensor([0, 1, 2]), torch.FloatTensor([1, 2, 3]) ] # check if all cond in target label list for data in output['data_samples']: label = data.gt_label.label assert any([(label == tar).all() for tar in target_label_list]) # test with sample kwargs sample_kwargs = dict( num_inference_steps=250, show_progress=True, classifier_scale=1.) metric = ToyGenerativeMetric( 11, need_cond_input=True, sample_kwargs=sample_kwargs) sampler = metric.get_metric_sampler(model, dataloader, [metric]) iterator = iter(sampler) output = next(iterator) assert output['inputs'] == dict( sample_model='ema', num_batches=10, sample_kwargs=sample_kwargs) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_base_sample_wise_metric.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest.mock import MagicMock import numpy as np import torch from torch.utils.data.dataloader import DataLoader from mmagic.datasets import BasicImageDataset from mmagic.evaluation.metrics.base_sample_wise_metric import \ BaseSampleWiseMetric class BaseSampleWiseMetricMock(BaseSampleWiseMetric): metric = 'metric' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def process_image(self, *args, **kwargs): return 0 def test_compute_metrics(): metric = BaseSampleWiseMetricMock() results = [] key = 'metric' total = 0 n = 0 for i in range(10): results.append({'batch_size': i, key: i}) total += i * i n += i average = metric.compute_metrics(results) assert average[key] == total / n def test_process(): metric = BaseSampleWiseMetricMock() mask = np.ones((32, 32, 3)) * 2 mask[:16] *= 0 gt = np.ones((32, 32, 3)) * 2 data_sample = dict(gt_img=gt, mask=mask) data_batch = [dict(data_samples=data_sample)] predictions = [dict(pred_img=np.ones((32, 32, 3)))] data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt), mask=torch.from_numpy(mask)))) predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in predictions[0].items() }) for d, p in zip(data_batch, predictions): d['output'] = p predictions = data_batch metric.process(data_batch, predictions) assert len(metric.results) == 2 assert metric.results[0]['metric'] == 0 def test_prepare(): data_root = 'tests/data/image/' dataset = BasicImageDataset( metainfo=dict(dataset_type='sr_annotation_dataset', task_name='sisr'), data_root=data_root, data_prefix=dict(img='lq', gt='gt'), filename_tmpl=dict(img='{}_x4'), pipeline=[]) dataloader = DataLoader(dataset) metric = BaseSampleWiseMetricMock() model = MagicMock() model.data_preprocessor = MagicMock() metric.prepare(model, dataloader) assert metric.SAMPLER_MODE == 'normal' assert metric.sample_model == 'orig' assert metric.size == 1 assert metric.data_preprocessor == model.data_preprocessor metric.get_metric_sampler(None, dataloader, []) assert dataloader == dataloader def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_connectivity_error.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from pathlib import Path import numpy as np import pytest import torch from mmagic.datasets.transforms import LoadImageFromFile from mmagic.evaluation.metrics import ConnectivityError class TestMattingMetrics: @classmethod def setup_class(cls): # Make sure these values are immutable across different test cases. # This test depends on the interface of loading # if loading is changed, data should be change accordingly. test_path = Path(__file__).parent.parent.parent alpha_path = ( test_path / 'data' / 'matting_dataset' / 'alpha' / 'GT05.jpg') results = dict(alpha_path=alpha_path) config = dict(key='alpha') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['alpha'].ndim == 3 gt_alpha = np.ones((32, 32), dtype=np.uint8) * 255 trimap = np.zeros((32, 32), dtype=np.uint8) trimap[:16, :16] = 128 trimap[16:, 16:] = 255 # non-masked pred_alpha pred_alpha = torch.zeros((32, 32), dtype=torch.uint8) # masked pred_alpha masked_pred_alpha = pred_alpha.clone() masked_pred_alpha[trimap == 0] = 0 masked_pred_alpha[trimap == 255] = 255 gt_alpha = gt_alpha[None, ...] trimap = trimap[None, ...] cls.data_batch = [{ 'inputs': [], 'data_samples': { 'ori_trimap': torch.from_numpy(trimap), 'ori_alpha': torch.from_numpy(gt_alpha), }, }] cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p def test_connectivity_error(self): """Test connectivity error for evaluating predicted alpha matte.""" data_batch, bad_pred1, bad_pred2, good_pred = ( self.data_batch, self.bad_preds1, self.bad_preds2, self.good_preds, ) conn_err = ConnectivityError() with pytest.raises(ValueError): conn_err.process(data_batch, bad_pred1) with pytest.raises(ValueError): conn_err.process(data_batch, bad_pred2) # process 2 batches conn_err.process(data_batch, good_pred) conn_err.process(data_batch, good_pred) assert conn_err.results == [ { 'conn_err': 0.256, }, { 'conn_err': 0.256, }, ] res = conn_err.compute_metrics(conn_err.results) assert list(res.keys()) == ['ConnectivityError'] assert np.allclose(res['ConnectivityError'], 0.256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_equivariance.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmengine.runner import Runner from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import PackInputs from mmagic.evaluation import Equivariance from mmagic.models import DataPreprocessor, StyleGAN3 from mmagic.models.editors.stylegan3 import StyleGAN3Generator from mmagic.utils import register_all_modules register_all_modules() def process_fn(data_batch, predictions): _predictions = [] for pred in predictions: _predictions.append(pred.to_dict()) return data_batch, _predictions @pytest.mark.skipif( digit_version(TORCH_VERSION) < digit_version('1.8.0'), reason='version limitation') class TestEquivariance: @classmethod def setup_class(cls): pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(64, 64)), PackInputs() ] dataset = BasicImageDataset( data_root='./tests/data/image/img_root', pipeline=pipeline, test_mode=True) cls.dataloader = Runner.build_dataloader( dict( batch_size=2, dataset=dataset, sampler=dict(type='DefaultSampler'))) gan_data_preprocessor = DataPreprocessor() generator = StyleGAN3Generator(64, 8, 3, noise_size=8) cls.module = StyleGAN3( generator, data_preprocessor=gan_data_preprocessor) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') @torch.no_grad() def test_eq_cuda(self): eq = Equivariance( 2, eq_cfg=dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True), sample_mode='orig') self.module.cuda() sampler = eq.get_metric_sampler(self.module, self.dataloader, [eq]) eq.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) eq.process(_data_batch, _predictions) eq_res = eq.compute_metrics(eq.fake_results) isinstance(eq_res['eqt_int'], float) and isinstance( eq_res['eqt_frac'], float) and isinstance(eq_res['eqr'], float) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_fid.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import pickle from unittest import TestCase from unittest.mock import MagicMock, patch import numpy as np import pytest import torch import torch.nn as nn from mmengine.runner import Runner from mmagic.datasets import PairedImageDataset from mmagic.evaluation import FrechetInceptionDistance, TransFID from mmagic.models import DataPreprocessor, Pix2Pix from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() def process_fn(data_batch, predictions): _predictions = [] for pred in predictions: _predictions.append(pred.to_dict()) return data_batch, _predictions def construct_inception_pkl(inception_path): data_root = osp.dirname(inception_path) os.makedirs(data_root, exist_ok=True) with open(inception_path, 'wb') as file: feat = np.random.rand(10, 2048) mean = np.mean(feat, 0) cov = np.cov(feat, rowvar=False) inception_feat = dict(raw_feature=feat, real_mean=mean, real_cov=cov) pickle.dump(inception_feat, file) class inception_mock(nn.Module): def __init__(self, style): super().__init__() self.style = style def forward(self, x, *args, **kwargs): mock_feat = torch.randn(x.shape[0], 2048) if self.style.upper() in ['STYLEGAN', 'IS']: return mock_feat else: return [mock_feat] class TestFID(TestCase): inception_pkl = osp.join( osp.dirname(__file__), '..', '..', 'data/inception_pkl/inception_feat.pkl') mock_inception_stylegan = MagicMock( return_value=(inception_mock('StyleGAN'), 'StyleGAN')) mock_inception_pytorch = MagicMock( return_value=(inception_mock('PyTorch'), 'PyTorch')) def test_init(self): construct_inception_pkl(self.inception_pkl) with patch.object(FrechetInceptionDistance, '_load_inception', self.mock_inception_stylegan): fid = FrechetInceptionDistance( fake_nums=2, real_key='real', fake_key='fake', inception_pkl=self.inception_pkl) self.assertFalse(fid.need_cond_input) self.assertIsNone(fid.real_mean) self.assertIsNone(fid.real_cov) module = MagicMock() module.data_preprocessor = MagicMock() module.data_preprocessor.device = 'cpu' dataloader = MagicMock() fid.prepare(module, dataloader) self.assertIsNotNone(fid.real_mean) self.assertIsNotNone(fid.real_cov) def test_prepare(self): module = MagicMock() module.data_preprocessor = MagicMock() module.data_preprocessor.device = 'cpu' dataloader = MagicMock() with patch.object(FrechetInceptionDistance, '_load_inception', self.mock_inception_stylegan): fid = FrechetInceptionDistance( fake_nums=2, real_nums=2, real_key='real', fake_key='fake', inception_pkl=self.inception_pkl) fid.prepare(module, dataloader) # NOTE: do not test load inception network to save time # def test_load_inception(self): # fid = FrechetInceptionDistance( # fake_nums=2, # real_nums=2, # real_key='real', # fake_key='fake', # inception_style='PyTorch', # inception_pkl=self.inception_pkl) # self.assertEqual(fid.inception_style.upper(), 'PYTORCH') def test_process_and_compute(self): with patch.object(FrechetInceptionDistance, '_load_inception', self.mock_inception_stylegan): fid = FrechetInceptionDistance( fake_nums=2, real_nums=2, real_key='real', fake_key='fake', inception_pkl=self.inception_pkl) gen_images = torch.randn(4, 3, 2, 2) gen_samples = [ DataSample(fake=(gen_images[i])).to_dict() for i in range(4) ] fid.process(None, gen_samples) fid.process(None, gen_samples) fid.fake_results.clear() gen_sample = [ DataSample(orig=DataSample(fake=torch.randn(3, 2, 2))).to_dict() ] fid.process(None, gen_sample) gen_sample = [ DataSample(orig=DataSample( fake_img=torch.randn(3, 2, 2))).to_dict() ] fid.process(None, gen_sample) with patch.object(FrechetInceptionDistance, '_load_inception', self.mock_inception_pytorch): fid = FrechetInceptionDistance( fake_nums=2, real_nums=2, real_key='real', fake_key='fake', inception_style='PyTorch', inception_pkl=self.inception_pkl) module = MagicMock() module.data_preprocessor = MagicMock() module.data_preprocessor.device = 'cpu' dataloader = MagicMock() fid.prepare(module, dataloader) gen_samples = [ DataSample(fake_img=torch.randn(3, 2, 2)).to_dict() for _ in range(4) ] fid.process(None, gen_samples) metric = fid.evaluate() self.assertIsInstance(metric, dict) self.assertTrue('fid' in metric) self.assertTrue('mean' in metric) self.assertTrue('cov' in metric) class TestTransFID: inception_pkl = osp.join( osp.dirname(__file__), '..', '..', 'data/inception_pkl/inception_feat.pkl') mock_inception_stylegan = MagicMock( return_value=(inception_mock('StyleGAN'), 'StyleGAN')) mock_inception_pytorch = MagicMock( return_value=(inception_mock('PyTorch'), 'PyTorch')) @classmethod def setup_class(cls): pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='edge', domain_b='shoe', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_edge', 'img_shoe']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='Resize', scale=(256, 256), interpolation='bicubic'), dict(type='FixedCrop', keys=['img'], crop_size=(256, 256)) ]), dict(type='PackInputs', keys=['img_edge', 'img_shoe', 'pair']) ] dataset = PairedImageDataset( data_root='tests/data/paired', pipeline=pipeline, test_mode=True) cls.dataloader = Runner.build_dataloader( dict( batch_size=2, dataset=dataset, sampler=dict(type='DefaultSampler'))) gan_data_preprocessor = DataPreprocessor() generator = dict( type='UnetGenerator', in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)) discriminator = dict( type='PatchDiscriminator', in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)) cls.module = Pix2Pix( generator, discriminator, data_preprocessor=gan_data_preprocessor, default_domain='shoe', reachable_domains=['shoe'], related_domains=['shoe', 'edge']) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_trans_fid_cuda(self): return with patch.object(TransFID, '_load_inception', self.mock_inception_stylegan): fid = TransFID( prefix='FID-Full', fake_nums=2, real_key='img_shoe', fake_key='fake_shoe', inception_style='PyTorch') self.module.cuda() sampler = fid.get_metric_sampler(self.module, self.dataloader, [fid]) fid.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) fid.process(_data_batch, _predictions) fid_res = fid.compute_metrics(fid.fake_results) assert fid_res['fid'] >= 0 and fid_res['mean'] >= 0 and fid_res[ 'cov'] >= 0 def test_trans_fid_cpu(self): return with patch.object(TransFID, '_load_inception', self.mock_inception_stylegan): fid = TransFID( prefix='FID-Full', fake_nums=2, real_key='img_shoe', fake_key='fake_shoe', inception_style='PyTorch') sampler = fid.get_metric_sampler(self.module, self.dataloader, [fid]) fid.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) fid.process(_data_batch, _predictions) fid_res = fid.compute_metrics(fid.fake_results) assert fid_res['fid'] >= 0 and fid_res['mean'] >= 0 and fid_res[ 'cov'] >= 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_gradient_error.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from pathlib import Path import numpy as np import pytest import torch from mmagic.datasets.transforms import LoadImageFromFile from mmagic.evaluation.metrics import GradientError class TestMattingMetrics: @classmethod def setup_class(cls): # Make sure these values are immutable across different test cases. # This test depends on the interface of loading # if loading is changed, data should be change accordingly. test_path = Path(__file__).parent.parent.parent alpha_path = ( test_path / 'data' / 'matting_dataset' / 'alpha' / 'GT05.jpg') results = dict(alpha_path=alpha_path) config = dict(key='alpha') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['alpha'].ndim == 3 gt_alpha = np.ones((32, 32), dtype=np.uint8) * 255 trimap = np.zeros((32, 32), dtype=np.uint8) trimap[:16, :16] = 128 trimap[16:, 16:] = 255 # non-masked pred_alpha pred_alpha = torch.zeros((32, 32), dtype=torch.uint8) # masked pred_alpha masked_pred_alpha = pred_alpha.clone() masked_pred_alpha[trimap == 0] = 0 masked_pred_alpha[trimap == 255] = 255 gt_alpha = gt_alpha[None, ...] trimap = trimap[None, ...] cls.data_batch = [{ 'inputs': [], 'data_samples': { 'ori_trimap': torch.from_numpy(trimap), 'ori_alpha': torch.from_numpy(gt_alpha), }, }] cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p def test_gradient_error(self): """Test gradient error for evaluating predicted alpha matte.""" data_batch, bad_pred1, bad_pred2, good_pred = ( self.data_batch, self.bad_preds1, self.bad_preds2, self.good_preds, ) grad_err = GradientError() with pytest.raises(ValueError): grad_err.process(data_batch, bad_pred1) with pytest.raises(ValueError): grad_err.process(data_batch, bad_pred2) # process 2 batches grad_err.process(data_batch, good_pred) grad_err.process(data_batch, good_pred) assert len(grad_err.results) == 2 for el in grad_err.results: assert list(el.keys()) == ['grad_err'] np.testing.assert_almost_equal(el['grad_err'], 0.0028887) res = grad_err.compute_metrics(grad_err.results) assert list(res.keys()) == ['GradientError'] np.testing.assert_almost_equal(el['grad_err'], 0.0028887) # assert np.allclose(res['GradientError'], 0.0028887) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_inception_score.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from unittest import TestCase from unittest.mock import MagicMock, patch import pytest import torch import torch.nn as nn from mmengine.runner import Runner from mmagic.datasets import PairedImageDataset from mmagic.evaluation import InceptionScore, TransIS from mmagic.models import DataPreprocessor, Pix2Pix from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() def process_fn(data_batch, predictions): _predictions = [] for pred in predictions: _predictions.append(pred.to_dict()) return data_batch, _predictions class inception_mock(nn.Module): def __init__(self, style): super().__init__() self.style = style def forward(self, x, *args, **kwargs): mock_feat = torch.randn(x.shape[0], 2048) if self.style.upper() in ['STYLEGAN', 'IS']: return mock_feat else: return [mock_feat] class TestIS(TestCase): mock_inception_stylegan = MagicMock( return_value=(inception_mock('IS'), 'StyleGAN')) mock_inception_pytorch = MagicMock( return_value=(inception_mock('IS'), 'PyTorch')) def test_init(self): with patch.object(InceptionScore, '_load_inception', self.mock_inception_stylegan): IS = InceptionScore(fake_nums=2, fake_key='fake') from PIL import Image self.assertEqual(IS.resize, True) self.assertEqual(IS.splits, 10) self.assertEqual(IS.resize_method, Image.BICUBIC) with patch.object(InceptionScore, '_load_inception', self.mock_inception_stylegan): IS = InceptionScore( fake_nums=2, fake_key='fake', use_pillow_resize=False) self.assertEqual(IS.use_pillow_resize, False) self.assertEqual(IS.resize_method, 'bicubic') module = MagicMock() module.data_preprocessor = MagicMock() module.data_preprocessor.device = 'cpu' dataloader = MagicMock() IS.prepare(module, dataloader) # NOTE: do not test load inception network to save time # def test_load_inception(self): # IS = InceptionScore(fake_nums=2, inception_style='PyTorch') # self.assertEqual(IS.inception_style.upper(), 'PYTORCH') def test_process_and_compute(self): with patch.object(InceptionScore, '_load_inception', self.mock_inception_stylegan): IS = InceptionScore(fake_nums=2, fake_key='fake') gen_images = torch.randn(4, 3, 2, 2) gen_samples = [ DataSample(fake_img=img).to_dict() for img in gen_images ] IS.process(None, gen_samples) IS.process(None, gen_samples) with patch.object(InceptionScore, '_load_inception', self.mock_inception_pytorch): IS = InceptionScore( fake_nums=2, fake_key='fake', inception_style='PyTorch') gen_images = torch.randn(4, 3, 2, 2) gen_samples = [ DataSample(fake_img=img).to_dict() for img in gen_images ] IS.process(None, gen_samples) with patch.object(InceptionScore, '_load_inception', self.mock_inception_stylegan): IS = InceptionScore( fake_nums=2, fake_key='fake', sample_model='orig') gen_samples = [ DataSample( ema=DataSample(fake_img=torch.randn(3, 2, 2)), orig=DataSample(fake_img=torch.randn(3, 2, 2))).to_dict() ] IS.process(None, gen_samples) gen_samples = [ DataSample(orig=DataSample(fake=torch.randn(3, 2, 2))).to_dict() ] IS.process(None, gen_samples) with patch.object(InceptionScore, '_load_inception', self.mock_inception_stylegan): IS = InceptionScore( fake_nums=2, fake_key='fake', sample_model='orig') gen_samples = [ DataSample(fake_img=torch.randn(3, 2, 2)).to_dict() for _ in range(4) ] IS.process(None, gen_samples) metric = IS.evaluate() self.assertIsInstance(metric, dict) self.assertTrue('is' in metric) self.assertTrue('is_std' in metric) class TestTransIS: inception_pkl = osp.join( osp.dirname(__file__), '..', '..', 'data/inception_pkl/inception_feat.pkl') mock_inception_stylegan = MagicMock( return_value=(inception_mock('StyleGAN'), 'StyleGAN')) mock_inception_pytorch = MagicMock( return_value=(inception_mock('PyTorch'), 'PyTorch')) @classmethod def setup_class(cls): pipeline = [ dict( type='LoadPairedImageFromFile', key='pair', domain_a='edge', domain_b='shoe', color_type='color'), dict( type='TransformBroadcaster', mapping={'img': ['img_edge', 'img_shoe']}, auto_remap=True, share_random_params=True, transforms=[ dict( type='Resize', scale=(286, 286), interpolation='bicubic'), dict(type='FixedCrop', keys=['img'], crop_size=(256, 256)) ]), dict(type='PackInputs', keys=['img_edge', 'img_shoe', 'pair']) ] dataset = PairedImageDataset( data_root='tests/data/paired', pipeline=pipeline, test_mode=True) cls.dataloader = Runner.build_dataloader( dict( batch_size=2, dataset=dataset, sampler=dict(type='DefaultSampler'))) gan_data_preprocessor = DataPreprocessor() generator = dict( type='UnetGenerator', in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)) discriminator = dict( type='PatchDiscriminator', in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)) cls.module = Pix2Pix( generator, discriminator, data_preprocessor=gan_data_preprocessor, default_domain='shoe', reachable_domains=['shoe'], related_domains=['shoe', 'edge']) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_trans_is_cuda(self): return with patch.object(TransIS, '_load_inception', self.mock_inception_stylegan): IS = TransIS( prefix='IS-Full', fake_nums=2, inception_style='PyTorch', fake_key='fake_shoe', sample_model='orig') self.module.cuda() sampler = IS.get_metric_sampler(self.module, self.dataloader, [IS]) IS.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) IS.process(_data_batch, _predictions) IS_res = IS.compute_metrics(IS.fake_results) assert 'is' in IS_res and 'is_std' in IS_res def test_trans_is_cpu(self): return with patch.object(TransIS, '_load_inception', self.mock_inception_stylegan): IS = TransIS( prefix='IS-Full', fake_nums=2, inception_style='PyTorch', fake_key='fake_shoe', sample_model='orig') sampler = IS.get_metric_sampler(self.module, self.dataloader, [IS]) IS.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) IS.process(_data_batch, _predictions) IS_res = IS.compute_metrics(IS.fake_results) assert 'is' in IS_res and 'is_std' in IS_res def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_mae.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch from mmagic.evaluation.metrics import MAE class TestPixelMetrics: @classmethod def setup_class(cls): mask = np.ones((32, 32, 3)) * 2 mask[:16] *= 0 gt = np.ones((32, 32, 3)) * 2 data_sample = dict(gt_img=gt, mask=mask, gt_channel_order='bgr') cls.data_batch = [dict(data_samples=data_sample)] cls.predictions = [dict(pred_img=np.ones((32, 32, 3)))] cls.data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt), mask=torch.from_numpy(mask), img_channel_order='bgr'))) cls.predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in cls.predictions[0].items() }) for d, p in zip(cls.data_batch, cls.predictions): d['output'] = p cls.predictions = cls.data_batch def test_mae(self): # Single MAE mae = MAE() mae.process(self.data_batch, self.predictions) result = mae.compute_metrics(mae.results) assert 'MAE' in result np.testing.assert_almost_equal(result['MAE'], 0.003921568627) # Masked MAE mae = MAE(mask_key='mask', prefix='MAE') mae.process(self.data_batch, self.predictions) result = mae.compute_metrics(mae.results) assert 'MAE' in result np.testing.assert_almost_equal(result['MAE'], 0.003921568627) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_matting_mse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from pathlib import Path import numpy as np import pytest import torch from mmagic.datasets.transforms import LoadImageFromFile from mmagic.evaluation.metrics import MattingMSE class TestMattingMetrics: @classmethod def setup_class(cls): # Make sure these values are immutable across different test cases. # This test depends on the interface of loading # if loading is changed, data should be change accordingly. test_path = Path(__file__).parent.parent.parent alpha_path = ( test_path / 'data' / 'matting_dataset' / 'alpha' / 'GT05.jpg') results = dict(alpha_path=alpha_path) config = dict(key='alpha') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['alpha'].ndim == 3 gt_alpha = np.ones((32, 32), dtype=np.uint8) * 255 trimap = np.zeros((32, 32), dtype=np.uint8) trimap[:16, :16] = 128 trimap[16:, 16:] = 255 # non-masked pred_alpha pred_alpha = torch.zeros((32, 32), dtype=torch.uint8) # masked pred_alpha masked_pred_alpha = pred_alpha.clone() masked_pred_alpha[trimap == 0] = 0 masked_pred_alpha[trimap == 255] = 255 gt_alpha = gt_alpha[None, ...] trimap = trimap[None, ...] cls.data_batch = [{ 'inputs': [], 'data_samples': { 'ori_trimap': torch.from_numpy(trimap), 'ori_alpha': torch.from_numpy(gt_alpha), }, }] cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p def test_mse(self): """Test MattingMSE for evaluating predicted alpha matte.""" data_batch, bad_pred1, bad_pred2, good_pred = ( self.data_batch, self.bad_preds1, self.bad_preds2, self.good_preds, ) mse = MattingMSE() with pytest.raises(ValueError): mse.process(data_batch, bad_pred1) with pytest.raises(ValueError): mse.process(data_batch, bad_pred2) # process 2 batches mse.process(data_batch, good_pred) mse.process(data_batch, good_pred) assert mse.results == [ { 'mse': 3.0, }, { 'mse': 3.0, }, ] res = mse.compute_metrics(mse.results) assert list(res.keys()) == ['MattingMSE'] np.testing.assert_almost_equal(res['MattingMSE'], 3.0) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_metrics_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest from mmagic.evaluation.metrics import metrics_utils from mmagic.evaluation.metrics.metrics_utils import reorder_image def test_average(): results = [] key = 'data' total = 0 n = 0 for i in range(10): results.append({'batch_size': i, key: i}) total += i * i n += i average = metrics_utils.average(results, key) assert average == total / n def test_img_transform(): img = np.random.randint(0, 255, size=(4, 4, 3)) new_img = metrics_utils.img_transform(img, 0, 'HWC', None, 'rgb') assert new_img.shape == (4, 4, 3) def test_obtain_data(): img = np.random.randint(0, 255, size=(4, 4, 3)) key = 'img' data_sample = {'data_samples': {key: img}} result = metrics_utils.obtain_data(data_sample, key) assert not (result - img).any() def test_reorder_image(): img_hw = np.ones((32, 32)) img_hwc = np.ones((32, 32, 3)) img_chw = np.ones((3, 32, 32)) with pytest.raises(ValueError): reorder_image(img_hw, 'HH') output = reorder_image(img_hw) assert output.shape == (32, 32, 1) output = reorder_image(img_hwc) assert output.shape == (32, 32, 3) output = reorder_image(img_chw, input_order='CHW') assert output.shape == (32, 32, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_ms_ssim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import torch from mmagic.evaluation import MultiScaleStructureSimilarity from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestMS_SSIM(TestCase): def test_init(self): MS_SSIM = MultiScaleStructureSimilarity( fake_nums=10, fake_key='fake', sample_model='ema') self.assertEqual(MS_SSIM.num_pairs, 5) with self.assertRaises(AssertionError): MultiScaleStructureSimilarity(fake_nums=9) def test_process_and_evaluate(self): MS_SSIM = MultiScaleStructureSimilarity( fake_nums=4, fake_key='fake', sample_model='ema') input_batch_size = 6 input_pairs = 6 // 2 gen_images = torch.randint(0, 255, (input_batch_size, 3, 32, 32)) gen_samples = [ DataSample(fake_img=img).to_dict() for img in gen_images ] MS_SSIM.process(None, gen_samples) MS_SSIM.process(None, gen_samples) self.assertEqual(len(MS_SSIM.fake_results), input_pairs) metric_1 = MS_SSIM.evaluate() self.assertTrue('avg' in metric_1) MS_SSIM.fake_results.clear() MS_SSIM.process(None, gen_samples[:4]) self.assertEqual(len(MS_SSIM.fake_results), 4 // 2) metric_2 = MS_SSIM.evaluate() self.assertTrue('avg' in metric_2) MS_SSIM.fake_results.clear() gen_samples = [ DataSample( ema=DataSample(fake_img=torch.randint(0, 255, (3, 32, 32))), orig=DataSample( fake_img=torch.randint(0, 255, (3, 32, 32)))).to_dict() ] * 2 MS_SSIM.process(None, gen_samples) gen_samples = [ DataSample( ema=DataSample( fake=torch.randint(0, 255, (3, 32, 32)))).to_dict() ] * 2 MS_SSIM.process(None, gen_samples) # test prefix MS_SSIM = MultiScaleStructureSimilarity( fake_nums=4, fake_key='fake', sample_model='ema', prefix='ms-ssim') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_mse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import torch from mmagic.evaluation.metrics import MSE class TestPixelMetrics: @classmethod def setup_class(cls): mask = np.ones((32, 32, 3)) * 2 mask[:16] *= 0 gt = np.ones((32, 32, 3)) * 2 data_sample = dict(gt_img=gt, mask=mask, gt_channel_order='bgr') cls.data_batch = [dict(data_samples=data_sample)] cls.predictions = [dict(pred_img=np.ones((32, 32, 3)))] cls.data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt), mask=torch.from_numpy(mask), img_channel_order='bgr'))) cls.predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in cls.predictions[0].items() }) for d, p in zip(cls.data_batch, cls.predictions): d['output'] = p cls.predictions = cls.data_batch def test_mse(self): # Single MSE mae = MSE() mae.process(self.data_batch, self.predictions) result = mae.compute_metrics(mae.results) assert 'MSE' in result np.testing.assert_almost_equal(result['MSE'], 0.000015378700496) # Masked MSE mae = MSE(mask_key='mask', prefix='MSE') mae.process(self.data_batch, self.predictions) result = mae.compute_metrics(mae.results) assert 'MSE' in result np.testing.assert_almost_equal(result['MSE'], 0.000015378700496) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_niqe.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import mmcv import numpy as np import pytest import torch from mmagic.evaluation.metrics import NIQE, niqe def test_niqe(): img = mmcv.imread('tests/data/image/gt/baboon.png') predictions = [dict(pred_img=img)] predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in predictions[0].items() }) data_batch = [ dict( data_samples=dict( gt_img=torch.from_numpy(img), gt_channel_order='bgr')) ] data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(img), img_channel_order='bgr'))) data_samples = [d_['data_samples'] for d_ in data_batch] for d, p in zip(data_samples, predictions): d['output'] = p niqe_ = NIQE() niqe_.process(data_batch, data_samples) result = niqe_.compute_metrics(niqe_.results) assert 'NIQE' in result np.testing.assert_almost_equal(result['NIQE'], 5.731541051885604) niqe_ = NIQE(key='gt_img', is_predicted=False) niqe_.process(data_batch, data_samples) result = niqe_.compute_metrics(niqe_.results) assert 'NIQE' in result np.testing.assert_almost_equal(result['NIQE'], 5.731541051885604) with pytest.raises(AssertionError): niqe_ = NIQE(convert_to='a') def test_calculate_niqe(): img = mmcv.imread('tests/data/image/gt/baboon.png') result = niqe(img[:, :, 0], crop_border=0, input_order='HW') np.testing.assert_almost_equal(result, 5.62525, decimal=5) result = niqe(img, crop_border=0, input_order='HWC', convert_to='y') np.testing.assert_almost_equal(result, 5.72957, decimal=5) result = niqe(img, crop_border=0, input_order='HWC', convert_to='gray') np.testing.assert_almost_equal(result, 5.73154, decimal=5) result = niqe( img.transpose(2, 0, 1), crop_border=0, input_order='CHW', convert_to='y') np.testing.assert_almost_equal(result, 5.72957, decimal=5) result = niqe( img.transpose(2, 0, 1), crop_border=0, input_order='CHW', convert_to='gray') np.testing.assert_almost_equal(result, 5.73154, decimal=5) result = niqe(img[:, :, 0], crop_border=6, input_order='HW') np.testing.assert_almost_equal(result, 5.82981, decimal=5) result = niqe(img, crop_border=6, input_order='HWC', convert_to='y') np.testing.assert_almost_equal(result, 6.10074, decimal=5) result = niqe( img.transpose(2, 0, 1), crop_border=6, input_order='CHW', convert_to='y') np.testing.assert_almost_equal(result, 6.10074, decimal=5) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_ppl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest.mock import patch import pytest import torch from mmengine.runner import Runner from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import PackInputs from mmagic.evaluation import PerceptualPathLength from mmagic.models import LSGAN, DataPreprocessor from mmagic.models.editors.stylegan2 import StyleGAN2Generator from mmagic.utils import register_all_modules register_all_modules() def process_fn(data_batch, predictions): _predictions = [] for pred in predictions: _predictions.append(pred.to_dict()) return data_batch, _predictions class LPIPS_mock: def __init__(self, *args, **kwargs): pass def to(self, *args, **kwargs): return self def __call__(self, x1, x2, *args, **kwargs): num_batche = x1.shape[0] return torch.rand(num_batche, 1, 1, 1) class TestPPL: @classmethod def setup_class(cls): pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Resize', scale=(64, 64)), PackInputs() ] dataset = BasicImageDataset( data_root='tests/data/image/img_root', pipeline=pipeline, test_mode=True) cls.dataloader = Runner.build_dataloader( dict( batch_size=2, dataset=dataset, sampler=dict(type='DefaultSampler'))) gan_data_preprocessor = DataPreprocessor() generator = StyleGAN2Generator(64, 8) cls.module = LSGAN(generator, data_preprocessor=gan_data_preprocessor) @patch('lpips.LPIPS', LPIPS_mock) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_ppl_cuda(self): ppl = PerceptualPathLength( fake_nums=2, prefix='ppl-z', space='Z', sample_model='orig', latent_dim=8) self.module.cuda() sampler = ppl.get_metric_sampler(self.module, self.dataloader, [ppl]) ppl.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) ppl.process(_data_batch, _predictions) ppl_res = ppl.compute_metrics(ppl.fake_results) assert ppl_res['ppl_score'] >= 0 ppl = PerceptualPathLength( fake_nums=2, prefix='ppl-w', space='W', sample_model='orig', latent_dim=8) sampler = ppl.get_metric_sampler(self.module, self.dataloader, [ppl]) ppl.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) ppl.process(_data_batch, _predictions) ppl_res = ppl.compute_metrics(ppl.fake_results) assert ppl_res['ppl_score'] >= 0 @patch('lpips.LPIPS', LPIPS_mock) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_ppl_cpu(self): ppl = PerceptualPathLength( fake_nums=2, prefix='ppl-z', space='Z', sample_model='orig', latent_dim=8) sampler = ppl.get_metric_sampler(self.module, self.dataloader, [ppl]) ppl.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) ppl.process(_data_batch, _predictions) ppl_res = ppl.compute_metrics(ppl.fake_results) assert ppl_res['ppl_score'] >= 0 ppl = PerceptualPathLength( fake_nums=2, prefix='ppl-w', space='W', sample_model='orig', latent_dim=8) sampler = ppl.get_metric_sampler(self.module, self.dataloader, [ppl]) ppl.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) _data_batch, _predictions = process_fn(data_batch, predictions) ppl.process(_data_batch, _predictions) ppl_res = ppl.compute_metrics(ppl.fake_results) assert ppl_res['ppl_score'] >= 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_precision_and_recall.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock, patch import pytest import torch import torch.nn as nn from mmengine.runner import Runner from mmagic.datasets import BasicImageDataset from mmagic.datasets.transforms import PackInputs from mmagic.evaluation import PrecisionAndRecall from mmagic.models import LSGAN, DataPreprocessor from mmagic.models.editors.dcgan import DCGANGenerator from mmagic.utils import register_all_modules register_all_modules() class vgg_pytorch_classifier(nn.Module): def __init__(self): super().__init__() def forward(self, x): return torch.randn(x.shape[0], 4096) class vgg_mock(nn.Module): def __init__(self, style): super().__init__() self.classifier = nn.Sequential(nn.Identity(), nn.Identity(), nn.Identity(), vgg_pytorch_classifier()) self.style = style def forward(self, x, *args, **kwargs): if self.style.upper() == 'STYLEGAN': return torch.randn(x.shape[0], 4096) else: # torch return torch.randn(x.shape[0], 7 * 7 * 512) class TestPR: @classmethod def setup_class(cls): pipeline = [ dict(type='LoadImageFromFile', key='gt'), dict(type='Resize', keys='gt', scale=(128, 128)), PackInputs() ] dataset = BasicImageDataset( data_root='tests/data/image/img_root', pipeline=pipeline, data_prefix=dict(gt=''), test_mode=True, recursive=True) cls.dataloader = Runner.build_dataloader( dict( batch_size=2, dataset=dataset, sampler=dict(type='DefaultSampler'))) gan_data_preprocessor = DataPreprocessor() generator = DCGANGenerator(128, noise_size=10, base_channels=20) cls.module = LSGAN( generator, data_preprocessor=gan_data_preprocessor) # noqa cls.mock_vgg_pytorch = MagicMock( return_value=(vgg_mock('PyTorch'), 'False')) @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires cuda') # noqa def test_pr_cuda(self): pr = PrecisionAndRecall(10, sample_model='orig', auto_save=False) self.module.cuda() sampler = pr.get_metric_sampler(self.module, self.dataloader, [pr]) pr.prepare(self.module, self.dataloader) for data_batch in sampler: predictions = self.module.test_step(data_batch) predictions = [pred.to_dict() for pred in predictions] pr.process(data_batch, predictions) pr_score = pr.compute_metrics(pr.fake_results) print(pr_score) assert pr_score['precision'] >= 0 and pr_score['recall'] >= 0 def test_pr_cpu(self): with patch.object(PrecisionAndRecall, '_load_vgg', self.mock_vgg_pytorch): pr = PrecisionAndRecall(10, sample_model='orig', auto_save=False) sampler = pr.get_metric_sampler(self.module, self.dataloader, [pr]) pr.prepare(self.module, self.dataloader) for data_batch in sampler: data_samples = self.module.test_step(data_batch) data_samples = [pred.to_dict() for pred in data_samples] pr.process(data_batch, data_samples) pr_score = pr.evaluate() print(pr_score) assert pr_score['precision'] >= 0 and pr_score['recall'] >= 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_psnr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import pytest import torch from mmagic.evaluation.metrics import PSNR, psnr class TestPixelMetrics: @classmethod def setup_class(cls): mask = np.ones((32, 32, 3)) * 2 mask[:16] *= 0 gt = np.ones((32, 32, 3)) * 2 data_sample = dict(gt_img=gt, mask=mask, gt_channel_order='bgr') cls.data_batch = [dict(data_samples=data_sample)] cls.predictions = [dict(pred_img=np.ones((32, 32, 3)))] cls.data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt), mask=torch.from_numpy(mask), img_channel_order='bgr'))) cls.predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in cls.predictions[0].items() }) for d, p in zip(cls.data_batch, cls.predictions): d['output'] = p cls.predictions = cls.data_batch def test_psnr(self): psnr_ = PSNR() psnr_.process(self.data_batch, self.predictions) result = psnr_.compute_metrics(psnr_.results) assert 'PSNR' in result np.testing.assert_almost_equal(result['PSNR'], 48.1308036) def test_psnr(): img_hw_1 = np.ones((32, 32)) img_hwc_1 = np.ones((32, 32, 3)) img_chw_1 = np.ones((3, 32, 32)) img_hw_2 = np.ones((32, 32)) * 2 img_hwc_2 = np.ones((32, 32, 3)) * 2 img_chw_2 = np.ones((3, 32, 32)) * 2 with pytest.raises(ValueError): psnr(img_hw_1, img_hw_2, crop_border=0, input_order='HH') with pytest.raises(ValueError): psnr(img_hw_1, img_hw_2, crop_border=0, convert_to='ABC') psnr_result = psnr(img_hw_1, img_hw_2, crop_border=0) np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_hwc_1, img_hwc_2, crop_border=0, input_order='HWC') np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_chw_1, img_chw_2, crop_border=0, input_order='CHW') np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_hw_1, img_hw_2, crop_border=2) np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_hwc_1, img_hwc_2, crop_border=3, input_order='HWC') np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_chw_1, img_chw_2, crop_border=4, input_order='CHW') np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_hwc_1, img_hwc_2, crop_border=0, convert_to=None) np.testing.assert_almost_equal(psnr_result, 48.1308036) psnr_result = psnr(img_hwc_1, img_hwc_2, crop_border=0, convert_to='Y') np.testing.assert_almost_equal(psnr_result, 49.4527218) # test float inf psnr_result = psnr(img_hw_1, img_hw_1, crop_border=0) assert psnr_result == float('inf') # test uint8 img_hw_1 = np.zeros((32, 32), dtype=np.uint8) img_hw_2 = np.ones((32, 32), dtype=np.uint8) * 255 psnr_result = psnr(img_hw_1, img_hw_2, crop_border=0) assert psnr_result == 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_sad.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from pathlib import Path import numpy as np import pytest import torch from mmagic.datasets.transforms import LoadImageFromFile from mmagic.evaluation.metrics import SAD class TestMattingMetrics: @classmethod def setup_class(cls): # Make sure these values are immutable across different test cases. # This test depends on the interface of loading # if loading is changed, data should be change accordingly. test_path = Path(__file__).parent.parent.parent alpha_path = ( test_path / 'data' / 'matting_dataset' / 'alpha' / 'GT05.jpg') results = dict(alpha_path=alpha_path) config = dict(key='alpha') image_loader = LoadImageFromFile(**config) results = image_loader(results) assert results['alpha'].ndim == 3 gt_alpha = np.ones((32, 32), dtype=np.uint8) * 255 trimap = np.zeros((32, 32), dtype=np.uint8) trimap[:16, :16] = 128 trimap[16:, 16:] = 255 # non-masked pred_alpha pred_alpha = torch.zeros((32, 32), dtype=torch.uint8) # masked pred_alpha masked_pred_alpha = pred_alpha.clone() masked_pred_alpha[trimap == 0] = 0 masked_pred_alpha[trimap == 255] = 255 gt_alpha = gt_alpha[None, ...] trimap = trimap[None, ...] cls.data_batch = [{ 'inputs': [], 'data_samples': { 'ori_trimap': torch.from_numpy(trimap), 'ori_alpha': torch.from_numpy(gt_alpha), }, }] cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p def test_sad(self): """Test SAD for evaluating predicted alpha matte.""" data_batch, bad_pred1, bad_pred2, good_pred = ( self.data_batch, self.bad_preds1, self.bad_preds2, self.good_preds, ) sad = SAD() with pytest.raises(ValueError): sad.process(data_batch, bad_pred1) with pytest.raises(ValueError): sad.process(data_batch, bad_pred2) # process 2 batches sad.process(data_batch, good_pred) sad.process(data_batch, good_pred) assert sad.results == [ { 'sad': 0.768, }, { 'sad': 0.768, }, ] res = sad.compute_metrics(sad.results) assert list(res.keys()) == ['SAD'] np.testing.assert_almost_equal(res['SAD'], 0.768) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_snr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import pytest import torch from mmagic.evaluation.metrics import SNR, snr class TestPixelMetrics: @classmethod def setup_class(cls): mask = np.ones((32, 32, 3)) * 2 mask[:16] *= 0 gt = np.ones((32, 32, 3)) * 2 data_sample = dict(gt_img=gt, mask=mask, gt_channel_order='bgr') cls.data_batch = [dict(data_samples=data_sample)] cls.predictions = [dict(pred_img=np.ones((32, 32, 3)))] cls.data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt), mask=torch.from_numpy(mask), img_channel_order='bgr'))) cls.predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in cls.predictions[0].items() }) for d, p in zip(cls.data_batch, cls.predictions): d['output'] = p cls.predictions = cls.data_batch def test_snr(self): snr_ = SNR() snr_.process(self.data_batch, self.predictions) result = snr_.compute_metrics(snr_.results) assert 'SNR' in result np.testing.assert_almost_equal(result['SNR'], 6.0206001996994) def test_snr(): img_hw_1 = np.ones((32, 32)) * 2 img_hwc_1 = np.ones((32, 32, 3)) * 2 img_chw_1 = np.ones((3, 32, 32)) * 2 img_hw_2 = np.ones((32, 32)) img_hwc_2 = np.ones((32, 32, 3)) img_chw_2 = np.ones((3, 32, 32)) with pytest.raises(ValueError): snr(img_hw_1, img_hw_2, crop_border=0, input_order='HH') with pytest.raises(ValueError): snr(img_hw_1, img_hw_2, crop_border=0, convert_to='ABC') snr_result = snr(img_hw_1, img_hw_2, crop_border=0) np.testing.assert_almost_equal(snr_result, 6.020600199699402) snr_result = snr(img_hwc_1, img_hwc_2, crop_border=0, input_order='HWC') np.testing.assert_almost_equal(snr_result, 6.020600199699402) print(snr_result) snr_result = snr(img_chw_1, img_chw_2, crop_border=0, input_order='CHW') np.testing.assert_almost_equal(snr_result, 6.020600199699402) print(snr_result) snr_result = snr(img_hw_1, img_hw_2, crop_border=2) np.testing.assert_almost_equal(snr_result, 6.020600199699402) snr_result = snr(img_hwc_1, img_hwc_2, crop_border=3, input_order='HWC') np.testing.assert_almost_equal(snr_result, 6.020600199699402) snr_result = snr(img_chw_1, img_chw_2, crop_border=4, input_order='CHW') np.testing.assert_almost_equal(snr_result, 6.020600199699402) snr_result = snr(img_hwc_1, img_hwc_2, crop_border=0, convert_to=None) np.testing.assert_almost_equal(snr_result, 6.020600199699402) snr_result = snr(img_hwc_1, img_hwc_2, crop_border=0, convert_to='Y') np.testing.assert_almost_equal(snr_result, 26.290040016174316) # test float inf snr_result = snr(img_hw_1, img_hw_1, crop_border=0) assert snr_result == float('inf') # test uint8 img_hw_1 = np.ones((32, 32), dtype=np.uint8) img_hw_2 = np.zeros((32, 32), dtype=np.uint8) snr_result = snr(img_hw_1, img_hw_2, crop_border=0) assert snr_result == 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_ssim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import numpy as np import pytest import torch from mmagic.evaluation.metrics import SSIM, ssim def test_ssim(): mask = np.ones((3, 32, 32)) * 2 mask[:16] *= 0 gt_img = np.ones((3, 32, 32)) * 2 predictions = [dict(pred_img=np.ones((3, 32, 32)))] data_batch = [ dict( data_samples=dict( gt_img=gt_img, mask=mask, gt_channel_order='bgr')) ] data_batch.append( dict( data_samples=dict( gt_img=torch.from_numpy(gt_img), mask=torch.from_numpy(mask), img_channel_order='bgr'))) predictions.append({ k: torch.from_numpy(deepcopy(v)) for (k, v) in predictions[0].items() }) data_samples = [d_['data_samples'] for d_ in data_batch] for d, p in zip(data_samples, predictions): d['output'] = p ssim_ = SSIM() ssim_.process(data_batch, data_samples) result = ssim_.compute_metrics(ssim_.results) assert 'SSIM' in result np.testing.assert_almost_equal(result['SSIM'], 0.913062377743969) def test_calculate_ssim(): img_hw_1 = np.ones((32, 32)) img_hwc_1 = np.ones((32, 32, 3)) img_chw_1 = np.ones((3, 32, 32)) img_hw_2 = np.ones((32, 32)) * 2 img_hwc_2 = np.ones((32, 32, 3)) * 2 img_chw_2 = np.ones((3, 32, 32)) * 2 with pytest.raises(ValueError): ssim(img_hw_1, img_hw_2, crop_border=0, input_order='HH') with pytest.raises(ValueError): ssim(img_hw_1, img_hw_2, crop_border=0, input_order='ABC') ssim_result = ssim(img_hw_1, img_hw_2, crop_border=0) np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_hwc_1, img_hwc_2, crop_border=0, input_order='HWC') np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_chw_1, img_chw_2, crop_border=0, input_order='CHW') np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_hw_1, img_hw_2, crop_border=2) np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_hwc_1, img_hwc_2, crop_border=3, input_order='HWC') np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_chw_1, img_chw_2, crop_border=4, input_order='CHW') np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_hwc_1, img_hwc_2, crop_border=0, convert_to=None) np.testing.assert_almost_equal(ssim_result, 0.9130623) ssim_result = ssim(img_hwc_1, img_hwc_2, crop_border=0, convert_to='Y') np.testing.assert_almost_equal(ssim_result, 0.9987801) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_evaluation/test_metrics/test_swd.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock import numpy as np import torch from mmagic.evaluation import SlicedWassersteinDistance from mmagic.models import DataPreprocessor from mmagic.structures import DataSample class TestSWD(TestCase): def test_init(self): swd = SlicedWassersteinDistance(fake_nums=10, image_shape=(3, 32, 32)) self.assertEqual(len(swd.real_results), 2) def test_prosess(self): model = MagicMock() model.data_preprocessor = DataPreprocessor() swd = SlicedWassersteinDistance(fake_nums=100, image_shape=(3, 32, 32)) swd.prepare(model, None) torch.random.manual_seed(42) real_samples = [ dict(inputs=torch.rand(3, 32, 32) * 255.) for _ in range(100) ] fake_samples = [ DataSample( fake_img=(torch.rand(3, 32, 32) * 255), gt_img=(torch.rand(3, 32, 32) * 255)).to_dict() for _ in range(100) ] swd.process(real_samples, fake_samples) # 100 samples are passed in 1 batch, _num_processed should be 100 self.assertEqual(swd._num_processed, 100) # _num_processed(100) > fake_nums(4), _num_processed should be # unchanged swd.process(real_samples, fake_samples) self.assertEqual(swd._num_processed, 100) output = swd.evaluate() result = [16.495922580361366, 24.15413036942482, 20.325026474893093] output = [item / 100 for item in output.values()] result = [item / 100 for item in result] np.testing.assert_almost_equal(output, result, decimal=1) swd = SlicedWassersteinDistance( fake_nums=4, fake_key='fake', real_key='img', sample_model='orig', image_shape=(3, 32, 32)) swd.prepare(model, None) # test gray scale input swd.image_shape = (1, 32, 32) real_samples = [ dict(inputs=torch.rand(1, 32, 32) * 255.) for _ in range(100) ] fake_samples = [ DataSample( fake_img=torch.rand(1, 32, 32) * 255, gt_img=torch.rand(1, 32, 32) * 255).to_dict() for _ in range(100) ] swd.process(real_samples, fake_samples) # test fake_nums is -1 swd = SlicedWassersteinDistance( fake_nums=-1, fake_key='fake', real_key='img', sample_model='orig', image_shape=(3, 32, 32)) fake_samples = [ DataSample( fake_img=torch.rand(3, 32, 32) * 255, gt_img=torch.rand(3, 32, 32) * 255).to_dict() for _ in range(10) ] for _ in range(3): swd.process(None, fake_samples) # fake_nums is -1, all samples (10 * 3 = 30) is processed self.assertEqual(swd._num_processed, 30) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_aspp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import ASPP def test_aspp(): # test aspp with normal conv aspp = ASPP(128, out_channels=512, mid_channels=128, dilations=(6, 12, 18)) assert aspp.convs[0].activate.__class__.__name__ == 'ReLU' assert aspp.convs[0].conv.out_channels == 128 assert aspp.convs[1].__class__.__name__ == 'ConvModule' for conv_idx in range(1, 4): assert aspp.convs[conv_idx].conv.dilation[0] == 6 * conv_idx x = torch.rand(2, 128, 8, 8) output = aspp(x) assert output.shape == (2, 512, 8, 8) # test aspp with separable conv aspp = ASPP(128, separable_conv=True) assert aspp.convs[1].__class__.__name__ == 'DepthwiseSeparableConvModule' x = torch.rand(2, 128, 8, 8) output = aspp(x) assert output.shape == (2, 256, 8, 8) # test aspp with ReLU6 aspp = ASPP(128, dilations=(12, 24, 36), act_cfg=dict(type='ReLU6')) assert aspp.convs[0].activate.__class__.__name__ == 'ReLU6' for conv_idx in range(1, 4): assert aspp.convs[conv_idx].conv.dilation[0] == 12 * conv_idx x = torch.rand(2, 128, 8, 8) output = aspp(x) assert output.shape == (2, 256, 8, 8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_conv.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.models.archs import conv def test_conv(): assert 'Deconv' in conv.MODELS.module_dict def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_downsample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.archs import pixel_unshuffle def test_pixel_unshuffle(): # test on cpu x = torch.rand(1, 3, 20, 20) y = pixel_unshuffle(x, scale=2) assert y.shape == (1, 12, 10, 10) with pytest.raises(AssertionError): y = pixel_unshuffle(x, scale=3) # test on gpu if torch.cuda.is_available(): x = x.cuda() y = pixel_unshuffle(x, scale=2) assert y.shape == (1, 12, 10, 10) with pytest.raises(AssertionError): y = pixel_unshuffle(x, scale=3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_ensemble.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch import torch.nn as nn from mmagic.models.archs import SpatialTemporalEnsemble def test_ensemble_cpu(): model = nn.Identity() # spatial ensemble of an image ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=False) inputs = torch.rand(1, 3, 4, 4) outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.numpy(), outputs.numpy()) # spatial ensemble of a sequence ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=False) inputs = torch.rand(1, 2, 3, 4, 4) outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.numpy(), outputs.numpy()) # spatial and temporal ensemble of a sequence ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=True) inputs = torch.rand(1, 2, 3, 4, 4) outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.numpy(), outputs.numpy()) # spatial and temporal ensemble of an image with pytest.raises(ValueError): ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=True) inputs = torch.rand(1, 3, 4, 4) outputs = ensemble(inputs, model) def test_ensemble_cuda(): if torch.cuda.is_available(): model = nn.Identity().cuda() # spatial ensemble of an image ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=False) inputs = torch.rand(1, 3, 4, 4).cuda() outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.cpu().numpy(), outputs.cpu().numpy()) # spatial ensemble of a sequence ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=False) inputs = torch.rand(1, 2, 3, 4, 4).cuda() outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.cpu().numpy(), outputs.cpu().numpy()) # spatial and temporal ensemble of a sequence ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=True) inputs = torch.rand(1, 2, 3, 4, 4).cuda() outputs = ensemble(inputs, model) np.testing.assert_almost_equal(inputs.cpu().numpy(), outputs.cpu().numpy()) # spatial and temporal ensemble of an image with pytest.raises(ValueError): ensemble = SpatialTemporalEnsemble(is_temporal_ensemble=True) inputs = torch.rand(1, 3, 4, 4).cuda() outputs = ensemble(inputs, model) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_gated_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch import torch.nn as nn from mmagic.models.archs import SimpleGatedConvModule def test_gated_conv(): conv = SimpleGatedConvModule(3, 10, 3, padding=1) x = torch.rand((2, 3, 10, 10)) assert not conv.conv.with_activation assert conv.with_feat_act assert conv.with_gate_act assert isinstance(conv.feat_act, nn.ELU) assert isinstance(conv.gate_act, nn.Sigmoid) assert conv.conv.out_channels == 20 out = conv(x) assert out.shape == (2, 10, 10, 10) conv = SimpleGatedConvModule( 3, 10, 3, padding=1, feat_act_cfg=None, gate_act_cfg=None) assert not conv.with_gate_act out = conv(x) assert out.shape == (2, 10, 10, 10) with pytest.raises(AssertionError): conv = SimpleGatedConvModule( 3, 1, 3, padding=1, order=('linear', 'act', 'norm')) conv = SimpleGatedConvModule(3, out_channels=10, kernel_size=3, padding=1) assert conv.conv.out_channels == 20 out = conv(x) assert out.shape == (2, 10, 10, 10) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_img_normalize.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import ImgNormalize def test_normalize_layer(): rgb_mean = (1, 2, 3) rgb_std = (1, 0.5, 0.25) layer = ImgNormalize(1, rgb_mean, rgb_std) x = torch.randn((2, 3, 64, 64)) y = layer(x) x = x.permute((1, 0, 2, 3)).reshape((3, -1)) y = y.permute((1, 0, 2, 3)).reshape((3, -1)) rgb_mean = torch.tensor(rgb_mean) rgb_std = torch.tensor(rgb_std) mean_x = x.mean(dim=1) mean_y = y.mean(dim=1) std_x = x.std(dim=1) std_y = y.std(dim=1) assert sum(torch.div(std_x, std_y) - rgb_std) < 1e-5 assert sum(torch.div(mean_x - rgb_mean, rgb_std) - mean_y) < 1e-5 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_linear_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmagic.models.archs import LinearModule def test_linear_module(): linear = LinearModule(10, 20) linear.init_weights() x = torch.rand((3, 10)) assert linear.with_bias assert not linear.with_spectral_norm assert linear.out_features == 20 assert linear.in_features == 10 assert isinstance(linear.activate, nn.ReLU) y = linear(x) assert y.shape == (3, 20) linear = LinearModule(10, 20, act_cfg=None, with_spectral_norm=True) assert hasattr(linear.linear, 'weight_orig') assert not linear.with_activation y = linear(x) assert y.shape == (3, 20) linear = LinearModule( 10, 20, act_cfg=dict(type='LeakyReLU'), with_spectral_norm=True) y = linear(x) assert y.shape == (3, 20) assert isinstance(linear.activate, nn.LeakyReLU) linear = LinearModule( 10, 20, bias=False, act_cfg=None, with_spectral_norm=True) y = linear(x) assert y.shape == (3, 20) assert not linear.with_bias linear = LinearModule( 10, 20, bias=False, act_cfg=None, with_spectral_norm=True, order=('act', 'linear')) assert linear.order == ('act', 'linear') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_lora.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch import torch.nn as nn from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.archs import (LoRAWrapper, set_lora, set_lora_disable, set_lora_enable, set_only_lora_trainable) class ToyAttn(nn.Module): def __init__(self, in_dim, context_dim): super().__init__() self.to_q = nn.Linear(in_dim, in_dim) self.to_k = nn.Linear(context_dim, in_dim) self.to_v = nn.Linear(context_dim, in_dim) def forward(self, x, context=None): b, c, h, w = x.shape x = x.view(b, c, h * w).permute(0, 2, 1) if context is None: context = x q = self.to_q(x) k = self.to_k(context) v = self.to_v(context) attn_mask = torch.softmax(q @ k.transpose(-2, -1), dim=-1) out = attn_mask @ v return out.view(b, h, w, c).permute(0, 3, 1, 2) class ToySubModule(nn.Module): def __init__(self): super().__init__() self.net = nn.Identity() self.attn1 = ToyAttn(4, 3) def forward(self, x, context=None): x = self.net(x) x = self.attn1(x, context) return x class ToyModel(nn.Module): def __init__(self): super().__init__() self.n1 = ToySubModule() self.attn2 = ToyAttn(4, 4) def forward(self, x, context=None): out = self.n1(x, context) out = self.attn2(out) return out @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.8.1'), reason='get_submodule requires torch >= 1.9.0') def test_set_lora(): model = ToyModel() img = torch.randn(2, 4, 3, 3) context = torch.randn(2, 11, 3) config = dict(rank=2, scale=1, target_modules='to_q') model: ToyModel = set_lora(model, config, True) isinstance(model.attn2.to_q, LoRAWrapper) isinstance(model.n1.attn1.to_q, LoRAWrapper) out = model(img, context) assert out.shape == (2, 4, 3, 3) model = ToyModel() config = dict( rank=2, scale=1, target_modules=[ 'to_q', dict(target_module='.*attn1.to_v', rank=1), dict(target_module='to_k', scale=2.5) ]) out_wo_lora = model(img, context) set_lora(model, config) assert isinstance(model.attn2.to_q, LoRAWrapper) assert model.attn2.to_q.scale == 1 assert model.attn2.to_q.rank == 2 assert isinstance(model.attn2.to_k, LoRAWrapper) assert model.attn2.to_k.scale == 2.5 assert model.attn2.to_k.rank == 2 assert isinstance(model.attn2.to_v, nn.Linear) assert isinstance(model.n1.attn1.to_q, LoRAWrapper) assert model.n1.attn1.to_q.scale == 1 assert model.n1.attn1.to_q.rank == 2 assert isinstance(model.n1.attn1.to_k, LoRAWrapper) assert model.n1.attn1.to_k.scale == 2.5 assert model.n1.attn1.to_k.rank == 2 assert isinstance(model.n1.attn1.to_v, LoRAWrapper) assert model.n1.attn1.to_v.scale == 1 assert model.n1.attn1.to_v.rank == 1 out_w_lora = model(img, context) assert out_w_lora.shape == (2, 4, 3, 3) model.n1.attn1.to_v.set_scale(10) assert model.n1.attn1.to_v.scale == 10 # test set onlyu lora trainable set_only_lora_trainable(model) for n, m in model.named_parameters(): if 'lora_' in n: assert m.requires_grad else: assert not m.requires_grad # test enable and disable set_lora_disable(model) out_lora_disable = model(img, context) assert (out_lora_disable == out_wo_lora).all() set_lora_enable(model) out_lora_enable = model(img, context) assert (out_lora_enable == out_w_lora).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_multi_layer_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch import torch.nn as nn from mmagic.models.archs import MultiLayerDiscriminator def test_multi_layer_disc(): with pytest.raises(AssertionError): # fc_in_channels must be greater than 0 multi_disc = MultiLayerDiscriminator( 3, 236, fc_in_channels=-100, out_act_cfg=None) with pytest.raises(TypeError): # stride_list must be a tuple of int with length of 1 or # length of num_conv multi_disc = MultiLayerDiscriminator( 3, 256, num_convs=3, stride_list=(1, 2)) input_g = torch.randn(1, 3, 256, 256) # test multi-layer discriminators without fc layer multi_disc = MultiLayerDiscriminator( in_channels=3, max_channels=256, fc_in_channels=None) multi_disc.init_weights() disc_pred = multi_disc(input_g) assert disc_pred.shape == (1, 256, 8, 8) multi_disc = MultiLayerDiscriminator( in_channels=3, max_channels=256, fc_in_channels=100) assert isinstance(multi_disc.fc.activate, nn.ReLU) multi_disc = MultiLayerDiscriminator(3, 236, fc_in_channels=None) assert multi_disc.with_out_act assert not multi_disc.with_fc assert isinstance(multi_disc.conv5.activate, nn.ReLU) multi_disc = MultiLayerDiscriminator( 3, 236, fc_in_channels=None, out_act_cfg=None) assert not multi_disc.conv5.with_activation with pytest.raises(TypeError): multi_disc.init_weights(pretrained=dict(igccc=4396)) input_g = torch.randn(1, 3, 16, 16) multi_disc = MultiLayerDiscriminator( in_channels=3, max_channels=256, num_convs=2, fc_in_channels=4 * 4 * 128, fc_out_channels=10, with_spectral_norm=True) multi_disc.init_weights() disc_pred = multi_disc(input_g) assert disc_pred.shape == (1, 10) assert multi_disc.conv1.with_spectral_norm assert multi_disc.conv2.with_spectral_norm assert hasattr(multi_disc.fc.linear, 'weight_orig') num_convs = 3 multi_disc = MultiLayerDiscriminator( in_channels=64, max_channels=512, num_convs=num_convs, kernel_size=4, norm_cfg=dict(type='BN'), act_cfg=dict(type='LeakyReLU', negative_slope=0.2), out_act_cfg=dict(type='ReLU'), with_input_norm=False, with_out_convs=True) # check input conv assert not multi_disc.conv1.with_norm assert isinstance(multi_disc.conv1.activate, nn.LeakyReLU) assert multi_disc.conv1.stride == (2, 2) # check intermediate conv for i in range(1, num_convs): assert getattr(multi_disc, f'conv{i + 1}').with_norm assert isinstance( getattr(multi_disc, f'conv{i + 1}').activate, nn.LeakyReLU) assert getattr(multi_disc, f'conv{i + 1}').stride == (2, 2) # check out_conv assert multi_disc.conv4.with_norm assert multi_disc.conv4.with_activation assert multi_disc.conv4.stride == (1, 1) assert not multi_disc.conv5.with_norm assert not multi_disc.conv5.with_activation assert multi_disc.conv5.stride == (1, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_patch_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import pytest import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_patch_discriminator(): # color, BN cfg = dict( type='PatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)) net = MODELS.build(cfg) # cpu input_shape = (1, 3, 64, 64) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 1, 6, 6) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 1, 6, 6) # gray, IN cfg = dict( type='PatchDiscriminator', in_channels=1, base_channels=64, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02)) net = MODELS.build(cfg) # cpu input_shape = (1, 1, 64, 64) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 1, 6, 6) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 1, 6, 6) # test norm_cfg assertions bad_cfg = copy.deepcopy(cfg) bad_cfg['norm_cfg'] = None with pytest.raises(AssertionError): _ = MODELS.build(bad_cfg) bad_cfg['norm_cfg'] = dict(tp='BN') with pytest.raises(AssertionError): _ = MODELS.build(bad_cfg) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_resnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import ResNet def test_resnet(): resnet = ResNet(18, 3, 16, 16) resnet.init_weights() input = torch.rand((2, 3, 128, 128)) output = resnet(input) assert output[0].detach().numpy().shape == (2, 3, 128, 128) resnet = ResNet(50, 3, 16, 16) resnet.init_weights() input = torch.rand((2, 3, 128, 128)) output = resnet(input) assert output[0].detach().numpy().shape == (2, 3, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_separable_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch import torch.nn as nn from mmagic.models.archs import DepthwiseSeparableConvModule def test_depthwise_separable_conv(): with pytest.raises(AssertionError): # conv_cfg must be a dict or None DepthwiseSeparableConvModule(4, 8, 2, groups=2) # test default config conv = DepthwiseSeparableConvModule(3, 8, 2) assert conv.depthwise_conv.conv.groups == 3 assert conv.pointwise_conv.conv.kernel_size == (1, 1) assert not conv.depthwise_conv.with_norm assert not conv.pointwise_conv.with_norm assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU' assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU' x = torch.rand(1, 3, 256, 256) output = conv(x) assert output.shape == (1, 8, 255, 255) # test conv = DepthwiseSeparableConvModule(3, 8, 2, dw_norm_cfg=dict(type='BN')) assert conv.depthwise_conv.norm_name == 'bn' assert not conv.pointwise_conv.with_norm x = torch.rand(1, 3, 256, 256) output = conv(x) assert output.shape == (1, 8, 255, 255) conv = DepthwiseSeparableConvModule(3, 8, 2, pw_norm_cfg=dict(type='BN')) assert not conv.depthwise_conv.with_norm assert conv.pointwise_conv.norm_name == 'bn' x = torch.rand(1, 3, 256, 256) output = conv(x) assert output.shape == (1, 8, 255, 255) # add test for ['norm', 'conv', 'act'] conv = DepthwiseSeparableConvModule(3, 8, 2, order=('norm', 'conv', 'act')) x = torch.rand(1, 3, 256, 256) output = conv(x) assert output.shape == (1, 8, 255, 255) conv = DepthwiseSeparableConvModule( 3, 8, 3, padding=1, with_spectral_norm=True) assert hasattr(conv.depthwise_conv.conv, 'weight_orig') assert hasattr(conv.pointwise_conv.conv, 'weight_orig') output = conv(x) assert output.shape == (1, 8, 256, 256) conv = DepthwiseSeparableConvModule( 3, 8, 3, padding=1, padding_mode='reflect') assert isinstance(conv.depthwise_conv.padding_layer, nn.ReflectionPad2d) output = conv(x) assert output.shape == (1, 8, 256, 256) conv = DepthwiseSeparableConvModule( 3, 8, 3, padding=1, dw_act_cfg=dict(type='LeakyReLU')) assert conv.depthwise_conv.activate.__class__.__name__ == 'LeakyReLU' assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU' output = conv(x) assert output.shape == (1, 8, 256, 256) conv = DepthwiseSeparableConvModule( 3, 8, 3, padding=1, pw_act_cfg=dict(type='LeakyReLU')) assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU' assert conv.pointwise_conv.activate.__class__.__name__ == 'LeakyReLU' output = conv(x) assert output.shape == (1, 8, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_simple_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmagic.models.archs import SimpleEncoderDecoder def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def test_encoder_decoder(): """Test SimpleEncoderDecoder.""" # check DIM with only alpha loss encoder = dict(type='VGG16', in_channels=4) decoder = dict(type='PlainDecoder') model = SimpleEncoderDecoder(encoder, decoder) model.init_weights() model.train() fg, bg, merged, alpha, trimap = _demo_inputs_pair() prediction = model(torch.cat([merged, trimap], 1)) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # check DIM with only composition loss encoder = dict(type='VGG16', in_channels=4) decoder = dict(type='PlainDecoder') model = SimpleEncoderDecoder(encoder, decoder) model.init_weights() model.train() fg, bg, merged, alpha, trimap = _demo_inputs_pair() prediction = model(torch.cat([merged, trimap], 1)) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # check DIM with both alpha and composition loss encoder = dict(type='VGG16', in_channels=4) decoder = dict(type='PlainDecoder') model = SimpleEncoderDecoder(encoder, decoder) model.init_weights() model.train() fg, bg, merged, alpha, trimap = _demo_inputs_pair() prediction = model(torch.cat([merged, trimap], 1)) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # test forward with gpu if torch.cuda.is_available(): encoder = dict(type='VGG16', in_channels=4) decoder = dict(type='PlainDecoder') model = SimpleEncoderDecoder(encoder, decoder) model.init_weights() model.train() fg, bg, merged, alpha, trimap = _demo_inputs_pair(cuda=True) model.cuda() prediction = model(torch.cat([merged, trimap], 1)) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) def _demo_inputs_pair(img_shape=(64, 64), batch_size=1, cuda=False): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) fg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) bg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) alpha = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) trimap = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) if cuda: fg = fg.cuda() bg = bg.cuda() merged = merged.cuda() alpha = alpha.cuda() trimap = trimap.cuda() return fg, bg, merged, alpha, trimap def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_smpatch_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_smpatch_discriminator(): # color, BN cfg = dict( type='SoftMaskPatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, with_spectral_norm=True) net = MODELS.build(cfg) # cpu input_shape = (1, 3, 64, 64) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 1, 6, 6) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 1, 6, 6) # gray, IN cfg = dict( type='SoftMaskPatchDiscriminator', in_channels=1, base_channels=64, num_conv=3, with_spectral_norm=True) net = MODELS.build(cfg) # cpu input_shape = (1, 1, 64, 64) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 1, 6, 6) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 1, 6, 6) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_sr_backbone.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import ResidualBlockNoBN from mmagic.models.utils import make_layer def test_sr_backbone_utils(): block = make_layer(ResidualBlockNoBN, 3) input = torch.rand((2, 64, 128, 128)) output = block(input) assert output.detach().numpy().shape == (2, 64, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_tokenizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from mmagic.models.archs import TokenizerWrapper PREFIX = '<|startoftext|>' SUFFIX = ' <|endoftext|>' class TestTokenizerWrapper(TestCase): def setUp(self): """Test add placeholder tokens in this function.""" tokenizer = TokenizerWrapper('openai/clip-vit-base-patch32') # 'Goodbye' in kiswahili tokenizer.add_placeholder_token('kwaheri', num_vec_per_token=1) # 'how much' in kiswahili tokenizer.add_placeholder_token('ngapi', num_vec_per_token=4) with self.assertRaises(AssertionError): tokenizer.add_placeholder_token('hello', num_vec_per_token=1) self.tokenizer = tokenizer def test_encode_and_decode_and_call(self): # test single token text = 'Nice bro, kwaheri!' input_ids = self.tokenizer.encode(text).input_ids self.assertEqual(input_ids[-3:-2], self.tokenizer.encode('kwaheri').input_ids[1:-1]) text_recon = self.tokenizer.decode(input_ids) text_recon_raw = self.tokenizer.decode(input_ids, return_raw=True) self.assertEqual(text_recon, f'{PREFIX}{text}{SUFFIX}'.lower()) self.assertEqual(text_recon_raw, f'{PREFIX}{text}{SUFFIX}'.lower()) self.assertEqual(input_ids, self.tokenizer(text).input_ids) # test multi token text = 'This apple seems delicious, ngapi?' input_ids = self.tokenizer.encode(text).input_ids self.assertEqual(input_ids[6:-2], self.tokenizer.encode('ngapi').input_ids[1:-1]) text_recon = self.tokenizer.decode(input_ids) text_recon_raw = self.tokenizer.decode(input_ids, return_raw=True) self.assertEqual(text_recon, f'{PREFIX}{text}{SUFFIX}'.lower()) for idx in range(4): self.assertIn(f'ngapi_{idx}', text_recon_raw) self.assertEqual(input_ids, self.tokenizer(text).input_ids) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_upsample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import PixelShufflePack def test_pixel_shuffle(): # test on cpu model = PixelShufflePack(3, 3, 2, 3) model.init_weights() x = torch.rand(1, 3, 16, 16) y = model(x) assert y.shape == (1, 3, 32, 32) # test on gpu if torch.cuda.is_available(): model = model.cuda() x = x.cuda() y = model(x) assert y.shape == (1, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_vgg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import numpy as np import pytest import torch from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.models.archs import VGG16 def check_norm_state(modules, train_state): """Check if norm layer is in correct train state.""" for mod in modules: if isinstance(mod, _BatchNorm): if mod.training != train_state: return False return True def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def assert_mid_feat_shape(mid_feat, target_shape): assert len(mid_feat) == 5 for i in range(5): assert_tensor_with_shape(mid_feat[i], torch.Size(target_shape[i])) def _demo_inputs(input_shape=(2, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_vgg16_encoder(): """Test VGG16 encoder.""" target_shape = [(2, 64, 32, 32), (2, 128, 16, 16), (2, 256, 8, 8), (2, 512, 4, 4), (2, 512, 2, 2)] model = VGG16(4) model.init_weights() model.train() img = _demo_inputs() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) model = VGG16(4, batch_norm=True) model.init_weights() model.train() img = _demo_inputs() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) model = VGG16(4, aspp=True, dilations=[6, 12, 18]) model.init_weights() model.train() img = _demo_inputs() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 256, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) assert check_norm_state(model.modules(), True) # test forward with gpu if torch.cuda.is_available(): model = VGG16(4) model.init_weights() model.train() model.cuda() img = _demo_inputs().cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) model = VGG16(4, batch_norm=True) model.init_weights() model.train() model.cuda() img = _demo_inputs().cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) model = VGG16(4, aspp=True, dilations=[6, 12, 18]) model.init_weights() model.train() model.cuda() img = _demo_inputs().cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 256, 2, 2)) assert_tensor_with_shape(outputs['max_idx_1'], target_shape[0]) assert_tensor_with_shape(outputs['max_idx_2'], target_shape[1]) assert_tensor_with_shape(outputs['max_idx_3'], target_shape[2]) assert_tensor_with_shape(outputs['max_idx_4'], target_shape[3]) assert_tensor_with_shape(outputs['max_idx_5'], target_shape[4]) assert check_norm_state(model.modules(), True) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_archs/test_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp import platform import shutil from unittest import TestCase from unittest.mock import MagicMock import torch from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.registry import MODELS from mmagic.utils import register_all_modules test_dir = osp.join(osp.dirname(__file__), '..', '..', '..', 'tests') config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') model_path = osp.join(test_dir, 'configs', 'tmp_weight') ckpt_path = osp.join(test_dir, 'configs', 'ckpt') register_all_modules() class TestWrapper(TestCase): def test_build(self): # mock SiLU if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): from mmagic.models.editors.ddpm.denoising_unet import SiLU torch.nn.SiLU = SiLU # 1. test from config model = MODELS.build( dict(type='ControlNetModel', from_config=config_path)) model.init_weights() # test init_weights without warning model_str = repr(model) self.assertIn( 'Wrapped Module Class: ', model_str) self.assertIn('Wrapped Module Name: ControlNetModel', model_str) self.assertIn(f'From Config: {config_path}', model_str) # 2. test save as diffuser os.makedirs(model_path, exist_ok=True) if digit_version(TORCH_VERSION) < digit_version('2.0.1'): model.save_pretrained(model_path, safe_serialization=False) else: model.save_pretrained(model_path) # 3. test from_pretrained model = MODELS.build( dict( type='ControlNetModel', from_pretrained=model_path, torch_dtype=torch.float16)) assert all([p.dtype == torch.float16 for p in model.parameters()]) model_str = repr(model) self.assertIn(f'From Pretrained: {model_path}', model_str) # save ckpt to test init_weights os.makedirs(ckpt_path, exist_ok=True) torch.save(model.state_dict(), osp.join(ckpt_path, 'model.pth')) # test raise warning when init_cfg is passed model = MODELS.build( dict( type='ControlNetModel', from_pretrained=model_path, torch_dtype=torch.float16, init_cfg=dict( type='Pretrained', checkpoint=osp.join(ckpt_path, 'model.pth')))) model.init_weights() # delete saved model to save space if 'win' not in platform.system().lower(): shutil.rmtree(model_path) shutil.rmtree(ckpt_path) # 4. test loading without repo_id model = MODELS.build( dict( type='ControlNetModel', in_channels=3, down_block_types=['DownBlock2D'], block_out_channels=(32, ), cross_attention_dim=16, attention_head_dim=2, conditioning_embedding_out_channels=(16, )), ) model_str = repr(model) self.assertNotIn('From Config:', model_str) self.assertNotIn('From Pretrained:', model_str) # 5. test attribute error for a unknown attribute with self.assertRaises(AttributeError): model.unkonwn_attr('what\'s this?') # 6. test init_weights model.init_weights() # 7. test forward function forward_mock = MagicMock() model.model.forward = forward_mock model(**dict(t='t', control='control')) _, called_kwargs = forward_mock.call_args self.assertEqual(called_kwargs['t'], 't') self.assertEqual(called_kwargs['control'], 'control') # 8. test other attribute share with BaseModule and model register_buffer_mock = MagicMock() model.model.registrer_buffer = register_buffer_mock model.registrer_buffer('buffer', 123) called_args, _ = register_buffer_mock.call_args self.assertEqual(called_args, ('buffer', 123)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_average_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import pytest import torch import torch.nn as nn from mmengine.model import BaseModel from mmengine.testing import assert_allclose from mmagic.models.base_models import ExponentialMovingAverage, RampUpEMA class ToyModule(nn.Module): def __init__(self): super().__init__() self.conv = nn.Conv2d(1, 1, 3) self.register_buffer('buffer', torch.randn(2, 2)) def update_buffer(self): for buffer in self.buffers(): buffer.add_(torch.randn(*buffer.size())) def update_params(self): for param in self.parameters(): param.add(torch.randn(*param.size())) def update(self): self.update_params() self.update_buffer() def forward(self, x): return self.conv(x) class ToyModel_old(BaseModel): def __init__(self): super().__init__() self.ema = ToyModule() self.module = ToyModule() def forward(self, x): return class ToyEMAModel(nn.Module): def __init__(self): super().__init__() self.module = ToyModule() def forward(self, x): return self.module(x) class ToyModel(BaseModel): def __init__(self): super().__init__() self.ema = ToyEMAModel() self.module = ToyModule() def forward(self, x): return class TestExponentialMovingAverage(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( interval=1, momentum=0.0001, update_buffers=True) def test_init(self): cfg = deepcopy(self.default_cfg) model = ToyModule() average_model = ExponentialMovingAverage(model=model, **cfg) self.assertEqual(average_model.momentum, 0.0001) self.assertTrue( (average_model.module.conv.weight == model.conv.weight).all()) cfg['momentum'] = 10 with self.assertRaises(AssertionError): average_model = ExponentialMovingAverage(model, **cfg) cfg['momentum'] = -2 with self.assertRaises(AssertionError): average_model = ExponentialMovingAverage(model, **cfg) # test warning with pytest.warns(UserWarning): cfg = deepcopy(self.default_cfg) cfg['momentum'] = 0.6 model = ToyModule() average_model = ExponentialMovingAverage(model=model, **cfg) self.assertEqual(average_model.momentum, 0.6) def test_avg_func(self): cfg = deepcopy(self.default_cfg) model = ToyModule() average_model = ExponentialMovingAverage(model, **cfg) src_tensor = torch.randn(1, 3, 2, 2) tar_tensor = torch.randn(1, 3, 2, 2) tar_tensor_backup = tar_tensor.clone() average_model.avg_func(tar_tensor, src_tensor, steps=42) assert_allclose(tar_tensor, tar_tensor_backup * 0.9999 + src_tensor * 0.0001) def test_sync_buffer_and_parameters(self): cfg = deepcopy(self.default_cfg) model = ToyModule() average_model = ExponentialMovingAverage(model, **cfg) model.update() average_model.sync_parameters(model) assert_allclose(model.conv.weight, average_model.module.conv.weight) assert_allclose(model.conv.bias, average_model.module.conv.bias) assert_allclose(model.buffer, average_model.module.buffer) model.update() average_model.sync_buffers(model) assert_allclose(model.buffer, average_model.module.buffer) cfg['update_buffers'] = True average_model = ExponentialMovingAverage(model, **cfg) with self.assertWarns(Warning): average_model.sync_buffers(model) def test_load_from_state_dict(self): cfg = deepcopy(self.default_cfg) model = ToyModel() average_model = ExponentialMovingAverage(model, **cfg) old_state_dict = ToyModel_old().state_dict() average_model._load_from_state_dict( old_state_dict, 'ema.', local_metadata={}, strict=True, missing_keys=[], unexpected_keys=[], error_msgs=[]) class TestRamUpEMA(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=32, eps=1e-8) def test_init(self): cfg = deepcopy(self.default_cfg) model = ToyModule() RampUpEMA(model, **cfg) def test_avg_func(self): cfg = deepcopy(self.default_cfg) model = ToyModule() average_model = RampUpEMA(model, **cfg) src_tensor = torch.randn(1, 3, 2, 2) tar_tensor = torch.randn(1, 3, 2, 2) average_model.avg_func(tar_tensor, src_tensor, steps=42) # model = ToyModule() cfg['ema_rampup'] = None average_model = RampUpEMA(model, **cfg) src_tensor = torch.randn(1, 3, 2, 2) tar_tensor = torch.randn(1, 3, 2, 2) average_model.avg_func(tar_tensor, src_tensor, steps=42) # test warning with pytest.warns(UserWarning): cfg = deepcopy(self.default_cfg) cfg['batch_size'] = 0 model = ToyModule() average_model = RampUpEMA(model, **cfg) src_tensor = torch.randn(1, 3, 2, 2) tar_tensor = torch.randn(1, 3, 2, 2) average_model.avg_func(tar_tensor, src_tensor, steps=42) def test_sync_buffer_and_parameters(self): cfg = deepcopy(self.default_cfg) model = ToyModule() average_model = RampUpEMA(model, **cfg) model.update() average_model.sync_parameters(model) assert_allclose(model.conv.weight, average_model.module.conv.weight) assert_allclose(model.conv.bias, average_model.module.conv.bias) assert_allclose(model.buffer, average_model.module.buffer) model.update() average_model.sync_buffers(model) assert_allclose(model.buffer, average_model.module.buffer) cfg['update_buffers'] = True average_model = RampUpEMA(model, **cfg) with self.assertWarns(Warning): average_model.sync_buffers(model) def test_load_from_state_dict(self): cfg = deepcopy(self.default_cfg) model = ToyModel() average_model = RampUpEMA(model, **cfg) old_state_dict = ToyModel_old().state_dict() average_model._load_from_state_dict( old_state_dict, 'ema.', local_metadata={}, strict=True, missing_keys=[], unexpected_keys=[], error_msgs=[]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_base_conditional_gan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import MagicMock import torch from mmengine import MessageHub from mmengine.structures import LabelData from mmengine.testing import assert_allclose from torch.nn import ModuleList from mmagic.models import BaseConditionalGAN, DataPreprocessor from mmagic.models.losses import (DiscShiftLossComps, GANLossComps, GeneratorPathRegularizerComps, GradientPenaltyLossComps) from mmagic.structures import DataSample generator = dict( type='SAGANGenerator', output_scale=32, base_channels=32, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=2, with_spectral_norm=True) discriminator = dict( type='ProjDiscriminator', input_scale=32, base_channels=32, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=1, with_spectral_norm=True) class ToyCGAN(BaseConditionalGAN): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def train_generator(self, inputs, data_samples, optimizer_wrapper): return dict(loss_gen=1) def train_discriminator(self, inputs, data_samples, optimizer_wrapper): return dict(loss_disc=2) class TestBaseGAN(TestCase): def test_val_step_and_test_step(self): gan = ToyCGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor()) gan.eval() # no mode inputs = dict(inputs=dict(num_batches=3)) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 3) self.assertEqual(len(outputs_test), 3) for out_val, out_test in zip(outputs_val, outputs_test): self.assertEqual(out_val.fake_img.shape, (3, 32, 32)) self.assertEqual(out_test.fake_img.shape, (3, 32, 32)) # set mode inputs = dict(inputs=dict(num_batches=4, sample_model='orig')) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 4) self.assertEqual(len(outputs_test), 4) for out_val, out_test in zip(outputs_val, outputs_test): self.assertEqual(out_val.sample_model, 'orig') self.assertEqual(out_test.sample_model, 'orig') self.assertEqual(out_val.fake_img.shape, (3, 32, 32)) self.assertEqual(out_test.fake_img.shape, (3, 32, 32)) inputs = dict(inputs=dict(num_batches=4, sample_model='orig/ema')) self.assertRaises(AssertionError, gan.val_step, inputs) inputs = dict(inputs=dict(num_batches=4, sample_model='ema')) self.assertRaises(AssertionError, gan.val_step, inputs) # set noise and label input gt_label = torch.randint(0, 10, (1, )) inputs = dict( inputs=dict(noise=torch.randn(1, 10)), data_samples=[DataSample(gt_label=LabelData(label=gt_label))]) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 1) self.assertEqual(len(outputs_val), 1) for idx in range(1): test_fake_img = outputs_test[idx].fake_img val_fake_img = outputs_val[idx].fake_img test_label = outputs_test[idx].gt_label.label val_label = outputs_val[idx].gt_label.label self.assertEqual(test_label, gt_label) self.assertEqual(val_label, gt_label) assert_allclose(test_fake_img, val_fake_img) def test_forward(self): # set a gan w/o EMA gan = ToyCGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor()) gan.eval() inputs = dict(num_batches=3) outputs = gan(inputs, None) self.assertEqual(len(outputs), 3) for out in outputs: self.assertEqual(out.fake_img.shape, (3, 32, 32)) outputs = gan(inputs) self.assertEqual(len(outputs), 3) for out in outputs: self.assertEqual(out.fake_img.shape, (3, 32, 32)) outputs = gan(torch.randn(3, 10)) self.assertEqual(len(outputs), 3) for out in outputs: self.assertEqual(out.fake_img.shape, (3, 32, 32)) # set a gan w EMA gan = ToyCGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor(), ema_config=dict(interval=1)) gan.eval() # inputs = dict(inputs=dict(num_batches=3)) inputs = dict(num_batches=3) outputs = gan(inputs) self.assertEqual(len(outputs), 3) for out in outputs: self.assertEqual(out.fake_img.shape, (3, 32, 32)) # inputs = dict(inputs=dict(num_batches=3, sample_model='ema/orig')) inputs = dict(num_batches=3, sample_model='ema/orig') outputs = gan(inputs) self.assertEqual(len(outputs), 3) for out in outputs: ema_img = out.ema orig_img = out.orig self.assertEqual(ema_img.fake_img.shape, orig_img.fake_img.shape) self.assertTrue(out.sample_model, 'ema/orig') # inputs = dict(inputs=dict(noise=torch.randn(4, 10))) inputs = dict(noise=torch.randn(4, 10)) outputs = gan(inputs) self.assertEqual(len(outputs), 4) for out in outputs: self.assertEqual(out.fake_img.shape, (3, 32, 32)) # test data sample input # inputs = dict(inputs=dict(noise=torch.randn(3, 10))) inputs = dict(noise=torch.randn(3, 10)) label = [torch.randint(0, 10, (1, )) for _ in range(3)] data_sample = [DataSample() for _ in range(3)] for idx, sample in enumerate(data_sample): sample.set_gt_label(label[idx]) print(DataSample.stack(data_sample)) outputs = gan(inputs, DataSample.stack(data_sample)) self.assertEqual(len(outputs), 3) for idx, output in enumerate(outputs): self.assertEqual(output.gt_label.label, label[idx]) def test_custom_loss(self): message_hub = MessageHub.get_instance('basegan-test-custom-loss') message_hub.update_info('iter', 10) gan_loss = dict(type='GANLossComps', gan_type='vanilla') # test loss config is dict() gan = BaseConditionalGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=dict()) self.assertIsNone(gan.gan_loss) self.assertIsNone(gan.disc_auxiliary_losses) self.assertIsNone(gan.gen_auxiliary_losses) # test loss config is list disc_auxiliary_loss_list = [ dict(type='DiscShiftLossComps'), dict(type='GradientPenaltyLossComps') ] gen_auxiliary_loss_list = [dict(type='GeneratorPathRegularizerComps')] loss_config = dict( gan_loss=gan_loss, disc_auxiliary_loss=disc_auxiliary_loss_list, gen_auxiliary_loss=gen_auxiliary_loss_list) gan = BaseConditionalGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) self.assertIsInstance(gan.disc_auxiliary_losses, ModuleList) self.assertIsInstance(gan.disc_auxiliary_losses[0], DiscShiftLossComps) self.assertIsInstance(gan.disc_auxiliary_losses[1], GradientPenaltyLossComps) self.assertIsInstance(gan.gen_auxiliary_losses, ModuleList) self.assertIsInstance(gan.gen_auxiliary_losses[0], GeneratorPathRegularizerComps) # test loss config is single dict disc_auxiliary_loss = dict( type='DiscShiftLossComps', data_info=dict(pred='disc_pred_fake')) gen_auxiliary_loss = dict( type='GeneratorPathRegularizerComps', data_info=dict(generator='gen', num_batches='batch_size')) loss_config = dict( gan_loss=gan_loss, disc_auxiliary_loss=disc_auxiliary_loss, gen_auxiliary_loss=gen_auxiliary_loss) gan = BaseConditionalGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) self.assertIsInstance(gan.gan_loss, GANLossComps) self.assertIsInstance(gan.disc_auxiliary_losses, ModuleList) self.assertIsInstance(gan.disc_auxiliary_losses[0], DiscShiftLossComps) self.assertIsInstance(gan.gen_auxiliary_losses, ModuleList) self.assertIsInstance(gan.gen_auxiliary_losses[0], GeneratorPathRegularizerComps) # test forward custom loss terms gan = BaseConditionalGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) # mock gen aux loss to avoid build styleGAN Generator gen_aux_loss_mock = MagicMock(return_value=torch.Tensor([1.])) gen_aux_loss_mock.loss_name = MagicMock(return_value='loss_gen_aux') gan._modules['gen_auxiliary_losses'] = [gen_aux_loss_mock] # mock optim wrapper optimizer_wrapper = { 'discriminator': MagicMock(), 'generator': MagicMock() } optimizer_wrapper['discriminator']._accumulative_counts = 1 optimizer_wrapper['generator']._accumulative_counts = 1 inputs = dict(img=torch.randn(3, 3, 32, 32)) label = [torch.randint(0, 10, (1, )) for _ in range(3)] data_sample = [DataSample() for _ in range(3)] for idx, sample in enumerate(data_sample): sample.set_gt_label(label[idx]) data = dict(inputs=inputs, data_samples=data_sample) log_vars = gan.train_step(data, optim_wrapper=optimizer_wrapper) self.assertIn('loss', log_vars) self.assertIn('loss_disc_fake', log_vars) self.assertIn('loss_disc_real', log_vars) self.assertIn('loss_disc_fake_g', log_vars) self.assertIn('loss_gen_aux', log_vars) self.assertIn('loss_disc_shift', log_vars) # test forward with only gan loss loss_config = dict(gan_loss=gan_loss) gan = BaseConditionalGAN( noise_size=10, num_classes=10, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) log_vars = gan.train_step(data, optim_wrapper=optimizer_wrapper) self.assertIn('loss', log_vars) self.assertIn('loss_disc_fake', log_vars) self.assertIn('loss_disc_real', log_vars) self.assertIn('loss_disc_fake_g', log_vars) self.assertNotIn('loss_gen_aux', log_vars) self.assertNotIn('loss_disc_shift', log_vars) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_base_edit_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine.optim import OptimWrapper from torch import nn from torch.optim import Adam from mmagic.models import BaseEditModel, DataPreprocessor from mmagic.models.losses import L1Loss from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() @MODELS.register_module() class ToyBaseModel(nn.Module): """An example of interpolate network for testing BasicInterpolator.""" def __init__(self): super().__init__() self.layer = nn.Conv2d(3, 3, 3, 1, 1) def forward(self, x): return self.layer(x) def init_weights(self, pretrained=None): pass def test_base_edit_model(): model = BaseEditModel( generator=dict(type='ToyBaseModel'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=DataPreprocessor()) assert model.__class__.__name__ == 'BaseEditModel' assert isinstance(model.generator, ToyBaseModel) assert isinstance(model.pixel_loss, L1Loss) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # prepare data inputs = torch.rand(1, 3, 20, 20) target = torch.rand(3, 20, 20) data_sample = DataSample(gt_img=target) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars['loss'], torch.Tensor) save_loss = log_vars['loss'] log_vars = model.train_step(data, optim_wrapper) log_vars = model.train_step(data, optim_wrapper) assert save_loss > log_vars['loss'] # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 20, 20) # feat output = model(torch.rand(1, 3, 20, 20), mode='tensor') assert output.shape == (1, 3, 20, 20) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_base_gan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import MagicMock import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmengine.testing import assert_allclose from torch.nn import ModuleList from torch.optim import SGD from mmagic.models import BaseGAN, DataPreprocessor from mmagic.models.losses import (DiscShiftLossComps, GANLossComps, GeneratorPathRegularizerComps, GradientPenaltyLossComps) from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict(type='DCGANGenerator', output_scale=8, base_channels=8) discriminator = dict( type='DCGANDiscriminator', base_channels=8, input_scale=8, output_scale=4, out_channels=1) class ToyGAN(BaseGAN): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def train_generator(self, inputs, data_samples, optimizer_wrapper): return dict(loss_gen=1) def train_discriminator(self, inputs, data_samples, optimizer_wrapper): return dict(loss_disc=2) class TestBaseGAN(TestCase): def test_init(self): gan = ToyGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor()) self.assertIsInstance(gan, BaseGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = ToyGAN( generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = ToyGAN( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = ToyGAN(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) self.assertIsNone(gan.gan_loss) self.assertIsNone(gan.gen_auxiliary_losses) self.assertIsNone(gan.disc_auxiliary_losses) self.assertEqual(gan.loss_config, dict()) def test_train_step(self): # prepare model accu_iter = 2 n_disc = 2 message_hub = MessageHub.get_instance('basegan-test') gan = ToyGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) ToyGAN.train_discriminator = MagicMock( return_value=dict(loss_disc=torch.Tensor(1), loss=torch.Tensor(1))) ToyGAN.train_generator = MagicMock( return_value=dict(loss_gen=torch.Tensor(2), loss=torch.Tensor(2))) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs inputs = torch.randn(1, 3, 4, 4) data = dict(inputs=inputs) # simulate train_loop here disc_update_times = 0 for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual(ToyGAN.train_generator.call_count, accu_iter) self.assertEqual( set(log.keys()), set(['loss', 'loss_disc', 'loss_gen'])) else: # should not update when discriminator's updating is unfinished self.assertEqual(ToyGAN.train_generator.call_count, 0) self.assertEqual(log.keys(), set(['loss', 'loss_disc'])) # disc should update once for each iteration disc_update_times += 1 self.assertEqual(ToyGAN.train_discriminator.call_count, disc_update_times) def test_update_ema(self): # prepare model n_gen = 4 n_disc = 2 accu_iter = 2 ema_interval = 3 message_hub = MessageHub.get_instance('basegan-test-ema') gan = ToyGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc, generator_steps=n_gen, ema_config=dict(interval=ema_interval)) gan.train_discriminator = MagicMock( return_value=dict(loss_disc=torch.Tensor(1), loss=torch.Tensor(1))) gan.train_generator = MagicMock( return_value=dict(loss_gen=torch.Tensor(2), loss=torch.Tensor(2))) self.assertTrue(gan.with_ema_gen) # mock generator_ema with MagicMock del gan.generator_ema setattr(gan, 'generator_ema', MagicMock()) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs inputs = torch.randn(1, 3, 4, 4) data = dict(inputs=inputs) # simulate train_loop here ema_times = 0 gen_update_times = 0 disc_update_times = 0 for idx in range(n_disc * accu_iter * ema_interval): message_hub.update_info('iter', idx) gan.train_step(data, optim_wrapper_dict) if (idx + 1) % (n_disc * accu_iter) == 0: ema_times += 1 gen_update_times += accu_iter * n_gen disc_update_times += 1 self.assertEqual(gan.generator_ema.update_parameters.call_count, ema_times) self.assertEqual(gan.train_generator.call_count, gen_update_times) # disc should update once for each iteration self.assertEqual(gan.train_discriminator.call_count, disc_update_times) def test_val_step_and_test_step(self): gan = ToyGAN( noise_size=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor()) # no mode inputs = dict(inputs=dict(num_batches=3)) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 3) self.assertEqual(len(outputs_test), 3) for idx in range(3): self.assertEqual(outputs_val[idx].fake_img.shape, (3, 8, 8)) self.assertEqual(outputs_test[idx].fake_img.shape, (3, 8, 8)) # set mode inputs = dict(inputs=dict(num_batches=4, sample_model='orig')) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 4) self.assertEqual(len(outputs_test), 4) for idx in range(4): self.assertEqual(outputs_val[idx].sample_model, 'orig') self.assertEqual(outputs_test[idx].sample_model, 'orig') self.assertEqual(outputs_val[idx].fake_img.shape, (3, 8, 8)) self.assertEqual(outputs_test[idx].fake_img.shape, (3, 8, 8)) inputs = dict(inputs=dict(num_batches=4, sample_model='orig/ema')) self.assertRaises(AssertionError, gan.val_step, inputs) inputs = dict(inputs=dict(num_batches=4, sample_model='ema')) self.assertRaises(AssertionError, gan.val_step, inputs) # set noise input inputs = dict(inputs=dict(noise=torch.randn(4, 10))) outputs_val = gan.val_step(inputs) outputs_test = gan.test_step(inputs) self.assertEqual(len(outputs_val), 4) self.assertEqual(len(outputs_val), 4) for idx in range(4): test_fake_img = outputs_test[idx].fake_img val_fake_img = outputs_val[idx].fake_img assert_allclose(test_fake_img, val_fake_img) def test_forward(self): # set a gan w/o EMA gan = ToyGAN( noise_size=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor()) inputs = dict(num_batches=3) outputs = gan(inputs, None) self.assertEqual(len(outputs), 3) for idx in range(3): self.assertTrue(outputs[idx].fake_img.shape == (3, 8, 8)) outputs = gan(inputs) self.assertEqual(len(outputs), 3) for idx in range(3): self.assertEqual(outputs[idx].fake_img.shape, (3, 8, 8)) outputs = gan(torch.randn(3, 10)) self.assertEqual(len(outputs), 3) for idx in range(3): self.assertEqual(outputs[idx].fake_img.shape, (3, 8, 8)) # set a gan w EMA gan = ToyGAN( noise_size=10, generator=deepcopy(generator), data_preprocessor=DataPreprocessor(), ema_config=dict(interval=1)) inputs = dict(num_batches=3) outputs = gan(inputs) self.assertEqual(len(outputs), 3) for idx in range(3): self.assertEqual(outputs[idx].fake_img.shape, (3, 8, 8)) inputs = dict(num_batches=3, sample_model='ema/orig') outputs = gan(inputs) self.assertEqual(len(outputs), 3) for idx in range(3): ema_img = outputs[idx].ema orig_img = outputs[idx].orig self.assertEqual(ema_img.fake_img.shape, orig_img.fake_img.shape) self.assertTrue(outputs[idx].sample_model, 'ema/orig') inputs = dict(noise=torch.randn(4, 10)) outputs = gan(inputs) self.assertEqual(len(outputs), 4) for idx in range(4): self.assertEqual(outputs[idx].fake_img.shape, (3, 8, 8)) # test additional sample kwargs sample_kwargs = dict(return_noise=True) inputs = dict(noise=torch.randn(4, 10), sample_kwargs=sample_kwargs) outputs = gan(inputs) self.assertEqual(len(outputs), 4) for idx in range(4): self.assertEqual(outputs[idx].fake_img.shape, (3, 8, 8)) # test when data samples is not None inputs = dict(num_batches=3, sample_model='ema/orig') data_samples = [DataSample(id=1), DataSample(id=2), DataSample(id=3)] outputs = gan(inputs, DataSample.stack(data_samples)) self.assertEqual(len(outputs), 3) for idx, output in enumerate(outputs): self.assertEqual(output.id, idx + 1) def test_custom_loss(self): message_hub = MessageHub.get_instance('basegan-test-custom-loss') message_hub.update_info('iter', 10) gan_loss = dict(type='GANLossComps', gan_type='vanilla') # test loss config is dict() gan = BaseGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=dict()) self.assertIsNone(gan.gan_loss) self.assertIsNone(gan.disc_auxiliary_losses) self.assertIsNone(gan.gen_auxiliary_losses) # test loss config is list disc_auxiliary_loss_list = [ dict(type='DiscShiftLossComps'), dict(type='GradientPenaltyLossComps') ] gen_auxiliary_loss_list = [dict(type='GeneratorPathRegularizerComps')] loss_config = dict( gan_loss=gan_loss, disc_auxiliary_loss=disc_auxiliary_loss_list, gen_auxiliary_loss=gen_auxiliary_loss_list) gan = BaseGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) self.assertIsInstance(gan.disc_auxiliary_losses, ModuleList) self.assertIsInstance(gan.disc_auxiliary_losses[0], DiscShiftLossComps) self.assertIsInstance(gan.disc_auxiliary_losses[1], GradientPenaltyLossComps) self.assertIsInstance(gan.gen_auxiliary_losses, ModuleList) self.assertIsInstance(gan.gen_auxiliary_losses[0], GeneratorPathRegularizerComps) # test loss config is single dict disc_auxiliary_loss = dict( type='DiscShiftLossComps', data_info=dict(pred='disc_pred_fake')) gen_auxiliary_loss = dict( type='GeneratorPathRegularizerComps', data_info=dict(generator='gen', num_batches='batch_size')) loss_config = dict( gan_loss=gan_loss, disc_auxiliary_loss=disc_auxiliary_loss, gen_auxiliary_loss=gen_auxiliary_loss) gan = BaseGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) self.assertIsInstance(gan.gan_loss, GANLossComps) self.assertIsInstance(gan.disc_auxiliary_losses, ModuleList) self.assertIsInstance(gan.disc_auxiliary_losses[0], DiscShiftLossComps) self.assertIsInstance(gan.gen_auxiliary_losses, ModuleList) self.assertIsInstance(gan.gen_auxiliary_losses[0], GeneratorPathRegularizerComps) # test forward custom loss terms gan = BaseGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) # mock gen aux loss to avoid build styleGAN Generator gen_aux_loss_mock = MagicMock(return_value=torch.Tensor([1.])) gen_aux_loss_mock.loss_name = MagicMock(return_value='loss_gen_aux') gan._modules['gen_auxiliary_losses'] = [gen_aux_loss_mock] # mock optim wrapper optimizer_wrapper = { 'discriminator': MagicMock(), 'generator': MagicMock() } optimizer_wrapper['discriminator']._accumulative_counts = 1 optimizer_wrapper['generator']._accumulative_counts = 1 data = dict(inputs=dict(img=torch.randn(2, 3, 32, 32))) log_vars = gan.train_step(data, optim_wrapper=optimizer_wrapper) self.assertIn('loss', log_vars) self.assertIn('loss_disc_fake', log_vars) self.assertIn('loss_disc_real', log_vars) self.assertIn('loss_disc_fake_g', log_vars) self.assertIn('loss_gen_aux', log_vars) self.assertIn('loss_disc_shift', log_vars) # test forward with only gan loss loss_config = dict(gan_loss=gan_loss) gan = BaseGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor(), loss_config=loss_config) data = dict(inputs=dict(img=torch.randn(2, 3, 32, 32))) log_vars = gan.train_step(data, optim_wrapper=optimizer_wrapper) self.assertIn('loss', log_vars) self.assertIn('loss_disc_fake', log_vars) self.assertIn('loss_disc_real', log_vars) self.assertIn('loss_disc_fake_g', log_vars) self.assertNotIn('loss_gen_aux', log_vars) self.assertNotIn('loss_disc_shift', log_vars) def test_gather_log_vars(self): gan = ToyGAN( noise_size=5, generator=deepcopy(generator), discriminator=deepcopy(discriminator), data_preprocessor=DataPreprocessor()) log_dict_list = [ dict(loss=torch.Tensor([2.33]), loss_disc=torch.Tensor([1.14514])) ] self.assertDictEqual(log_dict_list[0], gan.gather_log_vars(log_dict_list)) log_dict_list = [ dict(loss=torch.Tensor([2]), loss_disc=torch.Tensor([2])), dict(loss=torch.Tensor([3]), loss_disc=torch.Tensor([5])) ] self.assertDictEqual( dict(loss=torch.Tensor([2.5]), loss_disc=torch.Tensor([3.5])), gan.gather_log_vars(log_dict_list)) # test raise error with self.assertRaises(AssertionError): gan.gather_log_vars([dict(a=1), dict(b=2)]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_base_mattor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp from unittest.mock import patch import mmcv import numpy as np import torch from mmengine.config import ConfigDict from mmagic.datasets.transforms import PackInputs from mmagic.models.base_models import BaseMattor from mmagic.models.editors import DIM from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() def _get_model_cfg(fname): """Grab configs necessary to create a model. These are deep copied to allow for safe modification of parameters without influencing other tests. """ config_dpath = 'configs' config_fpath = osp.join(config_dpath, fname) if not osp.exists(config_dpath): raise Exception('Cannot find config path') config = mmcv.Config.fromfile(config_fpath) return config.model def _demo_input_train(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) inputs = torch.cat((merged, trimap), dim=1) if cuda: inputs = inputs.cuda() results = dict( alpha=np.random.random( (img_shape[0], img_shape[1], 1)).astype(np.float32), merged=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32), fg=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32), bg=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32)) data_samples = [] packinputs = PackInputs() for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def _demo_input_test(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. test_trans (str): what test transformation is used in data pipeline. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) ori_shape = (img_shape[0], img_shape[1], 1) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) inputs = torch.cat((merged, trimap), dim=1) if cuda: inputs = inputs.cuda() results = dict( ori_alpha=np.random.random(ori_shape).astype(np.float32), ori_trimap=np.random.randint(256, size=ori_shape).astype(np.float32), ori_merged_shape=img_shape) data_samples = [] packinputs = PackInputs() for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def assert_pred_alpha(predictions, batch_size): assert isinstance(predictions, list) assert isinstance(predictions[0], DataSample) pred_alpha = predictions[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == batch_size def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) @patch.multiple(BaseMattor, __abstractmethods__=set()) def test_base_mattor(): """Test resize and restore size.""" data_preprocessor = dict(type='MattorPreprocessor') backbone = dict( type='SimpleEncoderDecoder', encoder=dict(type='VGG16', in_channels=4), decoder=dict(type='PlainDecoder')) test_cfgs = [ dict(resize_method='pad', resize_mode='reflect', size_divisor=32), dict(resize_method='interp', resize_mode='bilinear', size_divisor=32), ] out_shapes = (64, 64), (32, 32) inputs = torch.rand((1, 4, 48, 48)) for test_cfg, out_shape in zip(test_cfgs, out_shapes): mattor = BaseMattor( data_preprocessor=data_preprocessor, backbone=backbone, test_cfg=test_cfg, ) out = mattor.resize_inputs(inputs) assert out.shape[-2:] == out_shape out = mattor.restore_size(out[0], ConfigDict(ori_merged_shape=(48, 48))) assert out.shape[-2:] == (48, 48) def test_dim_config(): data_preprocessor = dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], # bgr_to_rgb=True, # proc_inputs='normalize', proc_trimap='rescale_to_zero_one', # proc_gt='rescale_to_zero_one', ) backbone = dict( type='SimpleEncoderDecoder', encoder=dict(type='VGG16', in_channels=4), decoder=dict(type='PlainDecoder')) refiner = dict(type='PlainRefiner') train_cfg = dict(train_backbone=True, train_refiner=True) test_cfg = dict(refine=True) loss_alpha = dict(type='L1Loss') # build mattor without refiner mattor = DIM( data_preprocessor, backbone, refiner=None, loss_alpha=loss_alpha, train_cfg=train_cfg, test_cfg=test_cfg.copy()) assert not mattor.with_refiner assert not mattor.test_cfg.refine # only train the refiner, this will freeze the backbone mattor = DIM( data_preprocessor, backbone, refiner, loss_alpha=loss_alpha, train_cfg=dict(train_backbone=False, train_refiner=True), test_cfg=test_cfg.copy()) assert not mattor.train_cfg.train_backbone assert mattor.train_cfg.train_refiner assert mattor.test_cfg.refine # only train the backbone while the refiner is used for inference but not # trained, this behavior is allowed currently but will cause a warning. mattor = DIM( data_preprocessor, backbone, refiner, loss_alpha=loss_alpha, train_cfg=dict(train_backbone=True, train_refiner=False), test_cfg=test_cfg.copy()) assert mattor.train_cfg.train_backbone assert not mattor.train_cfg.train_refiner assert mattor.test_cfg.refine def test_dim(): model_cfg = ConfigDict( type='DIM', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], # bgr_to_rgb=True, # proc_inputs='normalize', proc_trimap='rescale_to_zero_one', # proc_gt='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict(type='VGG16', in_channels=4), decoder=dict(type='PlainDecoder')), refiner=dict(type='PlainRefiner'), loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5), loss_comp=dict(type='CharbonnierCompLoss', loss_weight=0.5), loss_refine=dict(type='CharbonnierLoss'), train_cfg=dict(train_backbone=True, train_refiner=True), test_cfg=dict( refine=False, resize_method='pad', resize_mode='reflect', size_divisor=32, ), ) # 1. test dim model with refiner model_cfg.train_cfg.train_refiner = True model_cfg.test_cfg.refine = True # test model forward in train mode model = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64)) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp', 'loss_refine']) # test model forward in train mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_train = _demo_input_train((64, 64), cuda=True) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp', 'loss_refine']) # test model forward in test mode with torch.no_grad(): model = MODELS.build(model_cfg) input_test = _demo_input_test((48, 48)) output_test = model(*input_test, mode='predict') assert isinstance(output_test, list) assert isinstance(output_test[0], DataSample) pred_alpha = output_test[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == (48, 48) # test model forward in test mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_test = _demo_input_test((48, 48), cuda=True) output_test = model(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # 2. test dim model without refiner model_cfg.refiner = None model_cfg.test_cfg.refine = True # test model forward in train mode model = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64)) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp']) # test model forward in train mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_train = _demo_input_train((64, 64), cuda=True) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp']) # test model forward in test mode with torch.no_grad(): model = MODELS.build(model_cfg) input_test = _demo_input_test((48, 48)) output_test = model(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # check test with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_test = _demo_input_test((48, 48), cuda=True) output_test = model(*input_test, mode='predict') # test forward_raw model.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) model.forward(inputs) def test_indexnet(): model_cfg = ConfigDict( type='IndexNet', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], # bgr_to_rgb=True, # proc_inputs='normalize', proc_trimap='rescale_to_zero_one', # proc_gt='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='IndexNetEncoder', in_channels=4, freeze_bn=True, ), decoder=dict(type='IndexNetDecoder')), loss_alpha=dict( type='CharbonnierLoss', loss_weight=0.5, sample_wise=True), loss_comp=dict( type='CharbonnierCompLoss', loss_weight=1.5, sample_wise=True), test_cfg=dict( resize_method='interp', resize_mode='bicubic', size_divisor=32, ), ) model_cfg.backbone.encoder.init_cfg = None # test indexnet inference with torch.no_grad(): indexnet = MODELS.build(model_cfg) indexnet.eval() input_test = _demo_input_test((48, 48)) output_test = indexnet(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # test inference with gpu if torch.cuda.is_available(): indexnet = MODELS.build(model_cfg).cuda() indexnet.eval() input_test = _demo_input_test((48, 48), cuda=True) output_test = indexnet(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # test forward train though we do not guarantee the training for present model_cfg.loss_alpha = None model_cfg.loss_comp = dict(type='L1CompositionLoss') indexnet = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64), batch_size=2) output_train = indexnet(*input_train, mode='loss') # assert output_train['num_samples'] == 2 assert_dict_keys_equal(output_train, ['loss_comp']) if torch.cuda.is_available(): model_cfg.loss_alpha = dict(type='L1Loss') model_cfg.loss_comp = None indexnet = MODELS.build(model_cfg).cuda() input_train = _demo_input_train((64, 64), batch_size=2, cuda=True) output_train = indexnet(*input_train, mode='loss') # assert output_train['num_samples'] == 2 assert_dict_keys_equal(output_train, ['loss_alpha']) # test forward indexnet.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) indexnet.forward(inputs) def test_gca(): model_cfg = ConfigDict( type='GCA', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], # bgr_to_rgb=True, # proc_inputs='normalize', proc_trimap='as_is', # proc_gt='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='ResGCAEncoder', block='BasicBlock', layers=[3, 4, 4, 2], in_channels=6, with_spectral_norm=True, ), decoder=dict( type='ResGCADecoder', block='BasicBlockDec', layers=[2, 3, 3, 2], with_spectral_norm=True)), loss_alpha=dict(type='L1Loss'), test_cfg=dict( resize_method='pad', resize_mode='reflect', size_divisor=32, )) # test model forward in train mode model = MODELS.build(model_cfg) meta = {'format_trimap_to_onehot': True} inputs, data_samples = _demo_input_train((64, 64), batch_size=2, meta=meta) inputs6 = torch.cat((inputs, inputs[:, 3:, :, :], inputs[:, 3:, :, :]), dim=1) outputs = model(inputs6, data_samples, mode='loss') assert_dict_keys_equal(outputs, ['loss']) if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() inputs, data_samples = _demo_input_train((64, 64), batch_size=2, cuda=True, meta=meta) inputs6 = torch.cat((inputs, inputs[:, 3:, :, :], inputs[:, 3:, :, :]), dim=1) outputs = model(inputs6, data_samples, mode='loss') assert_dict_keys_equal(outputs, ['loss']) # test model forward in test mode with torch.no_grad(): model_cfg.backbone.encoder.in_channels = 4 model = MODELS.build(model_cfg) inputs = _demo_input_test((48, 48), meta=meta) outputs = model(*inputs, mode='predict') assert_pred_alpha(outputs, (48, 48)) if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() inputs = _demo_input_test((48, 48), cuda=True, meta=meta) outputs = model(*inputs, mode='predict') assert_pred_alpha(outputs, (48, 48)) # test forward_dummy model.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) model.forward(inputs) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_base_translation_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock import torch from mmengine.model import MMDistributedDataParallel from mmagic.models import BaseTranslationModel class ToyTranslationModel(BaseTranslationModel): def __init__(self, generator, discriminator=None): super().__init__( generator=generator, discriminator=discriminator, default_domain='A', reachable_domains=['A'], related_domains=['A', 'B'], data_preprocessor=None) class TestBaseTranslationModel(TestCase): @classmethod def setUpClass(cls): cls.generator = dict( type='ResnetGenerator', in_channels=3, out_channels=3, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)) cls.discriminator = dict( type='PatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02)) def test_init(self): # test disc is None model = ToyTranslationModel( generator=self.generator, discriminator=None) self.assertIsNone(model.discriminators) # test disc is not None model = ToyTranslationModel( generator=self.generator, discriminator=self.discriminator) self.assertIsNotNone(model.discriminators) def test_get_module(self): generator_mock = MagicMock(spec=MMDistributedDataParallel) generator_mock_module = MagicMock() generator_mock.module = generator_mock_module model = ToyTranslationModel( generator=self.generator, discriminator=None) module = model.get_module(generator_mock) self.assertEqual(module, generator_mock_module) def test_forward(self): model = ToyTranslationModel( generator=self.generator, discriminator=None) res = model.forward_test( img=torch.randn(1, 3, 64, 64), target_domain=None) self.assertEqual(res['target'].shape, (1, 3, 64, 64)) self.assertEqual(res['source'].shape, (1, 3, 64, 64)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_basic_interpolator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from torch import nn from mmagic.models import BasicInterpolator from mmagic.models.losses import L1Loss from mmagic.registry import MODELS @MODELS.register_module() class InterpolateExample(nn.Module): """An example of interpolate network for testing BasicInterpolator.""" def __init__(self): super().__init__() self.layer = nn.Conv2d(3, 3, 3, 1, 1) def forward(self, x): return self.layer(x[:, 0]) def init_weights(self, pretrained=None): pass def test_basic_interpolator(): model = BasicInterpolator( generator=dict(type='InterpolateExample'), pixel_loss=dict(type='L1Loss')) assert model.__class__.__name__ == 'BasicInterpolator' assert isinstance(model.generator, InterpolateExample) assert isinstance(model.pixel_loss, L1Loss) input_tensors = torch.rand((1, 9, 3, 16, 16)) input_tensors = model.split_frames(input_tensors) assert input_tensors.shape == (8, 2, 3, 16, 16) output_tensors = torch.rand((8, 1, 3, 16, 16)) result = model.merge_frames(input_tensors, output_tensors) assert len(result) == 17 assert result[0].shape == (16, 16, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_one_stage.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from os.path import dirname, join from unittest.mock import patch import pytest import torch from mmengine import Config from mmagic.models import GLEncoderDecoder from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules def test_one_stage_inpaintor(): register_all_modules() device = 'cuda' if torch.cuda.is_available() else 'cpu' config_file = join( dirname(__file__), '..', '..', 'configs', 'one_stage_gl.py') cfg = Config.fromfile(config_file) # mock perceptual loss for test speed cfg.model.loss_composed_percep = None inpaintor = MODELS.build(cfg.model) # modify attributes for mocking inpaintor.with_composed_percep_loss = True inpaintor.loss_percep = None # test attributes assert inpaintor.__class__.__name__ == 'OneStageInpaintor' assert isinstance(inpaintor.generator, GLEncoderDecoder) assert inpaintor.with_l1_hole_loss assert inpaintor.with_l1_valid_loss assert inpaintor.with_tv_loss assert inpaintor.with_composed_percep_loss assert inpaintor.with_out_percep_loss assert inpaintor.with_gan assert inpaintor.with_gp_loss assert inpaintor.with_disc_shift_loss assert inpaintor.is_train assert inpaintor.train_cfg['disc_step'] == 1 assert inpaintor.disc_step_count == 0 with patch.object( inpaintor, 'loss_percep', return_value=(torch.tensor(1.0), None)): input_x = torch.randn(1, 3, 256, 256) with pytest.raises(NotImplementedError): inpaintor.forward_train(input_x) inpaintor.to(device=device) # construct inputs gt_img = torch.randn(3, 256, 256).to(device=device) mask = torch.zeros_like(gt_img)[0:1, ...] mask[..., 20:100, 100:120] = 1. masked_img = gt_img * (1. - mask) mask_bbox = [100, 100, 110, 110] inputs = masked_img.unsqueeze(0) data_sample = DataSample( mask=mask, mask_bbox=mask_bbox, gt_img=gt_img, ) data_samples = DataSample.stack([data_sample]) data_batch = {'inputs': inputs, 'data_samples': [data_sample]} # test forward_tensor fake_reses, fake_imgs = inpaintor.forward_tensor(inputs, data_samples) assert fake_reses.shape == fake_imgs.shape == (1, 3, 256, 256) # test forward test predictions = inpaintor.forward_test(inputs, data_samples) assert predictions.fake_img.shape == (1, 3, 256, 256) # test train_step optim_g = torch.optim.SGD(inpaintor.generator.parameters(), lr=0.1) optim_d = torch.optim.SGD(inpaintor.disc.parameters(), lr=0.1) optim_dict = dict(generator=optim_g, disc=optim_d) log_vars = inpaintor.train_step(data_batch, optim_dict) assert 'loss_l1_hole' in log_vars assert 'loss_l1_valid' in log_vars assert 'loss_composed_percep' in log_vars assert 'loss_composed_style' not in log_vars assert 'loss_out_percep' in log_vars assert 'loss_out_style' not in log_vars assert 'loss_tv' in log_vars assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_g_fake' in log_vars # Another test cfg_ = copy.deepcopy(cfg) cfg_.model.train_cfg.disc_step = 2 inpaintor = MODELS.build(cfg_.model) inpaintor.to(device=device) assert inpaintor.train_cfg.disc_step == 2 log_vars = inpaintor.train_step(data_batch, optim_dict) assert 'loss_l1_hole' not in log_vars def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_base_models/test_two_stage.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import platform from os.path import dirname, join from unittest.mock import MagicMock import pytest import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules # TODO: this test is same as `test_two_stage_encoder_decoder.py` @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_two_stage_inpaintor(): register_all_modules() config_file = join(dirname(__file__), '../../configs', 'two_stage_test.py') cfg = Config.fromfile(config_file) inpaintor = MODELS.build(cfg.model) assert inpaintor.__class__.__name__ == 'TwoStageInpaintor' if torch.cuda.is_available(): inpaintor.cuda() # check architecture assert inpaintor.stage1_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep', 'loss_tv') assert inpaintor.stage2_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_gan') assert inpaintor.with_l1_hole_loss assert inpaintor.with_l1_valid_loss assert inpaintor.with_composed_percep_loss assert not inpaintor.with_out_percep_loss assert inpaintor.with_gan inpaintor._modules['loss_percep'] = MagicMock( return_value=(torch.Tensor([1]), torch.Tensor([2]))) # prepare data gt_img = torch.rand((3, 256, 256)) mask = torch.zeros((1, 256, 256)) mask[..., 50:180, 60:170] = 1. masked_img = gt_img.unsqueeze(0) * (1. - mask) mask_bbox = [100, 100, 110, 110] data_batch = { 'inputs': masked_img, 'data_samples': [DataSample( mask=mask, mask_bbox=mask_bbox, gt_img=gt_img, )] } optim_g = torch.optim.Adam(inpaintor.generator.parameters(), lr=0.0001) optim_d = torch.optim.Adam(inpaintor.disc.parameters(), lr=0.0001) optims = dict(generator=OptimWrapper(optim_g), disc=OptimWrapper(optim_d)) # check train_step with standard two_stage model for i in range(5): log_vars = inpaintor.train_step(data_batch, optims) if i % 2 == 0: assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_disc_shift' in log_vars assert 'loss' in log_vars else: assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_disc_shift' in log_vars assert 'loss' in log_vars assert 'stage1_loss_l1_hole' in log_vars assert 'stage1_loss_l1_valid' in log_vars assert 'stage2_loss_l1_hole' in log_vars assert 'stage2_loss_l1_valid' in log_vars # check for forward_test data = inpaintor.data_preprocessor(data_batch, True) data_inputs, data_sample = data['inputs'], data['data_samples'] output = inpaintor.forward_test(data_inputs, data_sample) prediction = output assert 'fake_res' in prediction assert 'fake_img' in prediction assert 'pred_img' in prediction assert prediction.pred_img.shape == (1, 3, 256, 256) # check for gp_loss cfg_copy = copy.deepcopy(cfg) cfg_copy.model.disc_input_with_mask = False cfg_copy.model.disc.in_channels = 3 cfg_copy.model.loss_gp = dict(type='GradientPenaltyLoss', loss_weight=10.) inpaintor = MODELS.build(cfg_copy.model) assert inpaintor.with_gp_loss log_vars = inpaintor.train_step(data_batch, optims) assert 'real_loss' in log_vars assert 'stage1_loss_l1_hole' in log_vars assert 'stage1_loss_l1_valid' in log_vars assert 'stage2_loss_l1_hole' in log_vars assert 'stage2_loss_l1_valid' in log_vars def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_data_preprocessors/test_data_preprocessor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import torch import torch.nn.functional as F from mmengine.testing import assert_allclose from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.structures import DataSample class TestBaseDataPreprocessor(TestCase): def test_init(self): data_preprocessor = DataPreprocessor( mean=[0, 0, 0], std=[255, 255, 255], pad_size_divisor=16, pad_value=10) self.assertEqual(data_preprocessor._device.type, 'cpu') assert_allclose(data_preprocessor.mean, torch.tensor([0, 0, 0]).view(-1, 1, 1)) assert_allclose(data_preprocessor.std, torch.tensor([255, 255, 255]).view(-1, 1, 1)) assert_allclose(data_preprocessor.pad_value, torch.tensor(10)) self.assertEqual(data_preprocessor.pad_size_divisor, 16) self.assertEqual(data_preprocessor.pad_mode, 'constant') # test non-image-keys data_preprocessor = DataPreprocessor(non_image_keys='feature') self.assertIn('feature', data_preprocessor._NON_IMAGE_KEYS) data_preprocessor = DataPreprocessor(non_image_keys=['feature']) self.assertIn('feature', data_preprocessor._NON_IMAGE_KEYS) # test non-concentate-keys data_preprocessor = DataPreprocessor(non_concentate_keys='n_imgs') self.assertIn('n_imgs', data_preprocessor._NON_CONCATENATE_KEYS) data_preprocessor = DataPreprocessor(non_concentate_keys=['n_imgs']) self.assertIn('n_imgs', data_preprocessor._NON_CONCATENATE_KEYS) def test_parse_channel_index(self): data_preprocessor = DataPreprocessor() self.assertEqual( data_preprocessor._parse_channel_index(torch.rand(3, 5, 5)), 0) self.assertEqual( data_preprocessor._parse_channel_index(torch.rand(2, 3, 5, 5)), 1) self.assertEqual( data_preprocessor._parse_channel_index(torch.rand(2, 10, 3, 5, 5)), 2) self.assertEqual( data_preprocessor._parse_channel_index(torch.rand(5, 5)), 1) with self.assertRaises(AssertionError): data_preprocessor._parse_channel_index( torch.rand(1, 2, 10, 3, 5, 5, 5)) # test dict input inputs = dict(fake_img=torch.rand(2, 3, 5, 5)) self.assertEqual(data_preprocessor._parse_channel_index(inputs), 1) def test_parse_channel_order(self): data_preprocessor = DataPreprocessor() parse_fn = data_preprocessor._parse_channel_order # test no data sample self.assertEqual(parse_fn('img', torch.rand(3, 5, 5)), 'BGR') self.assertEqual(parse_fn('img', torch.rand(1, 3, 3, 4)), 'BGR') self.assertEqual(parse_fn('img', torch.rand(1, 1, 3, 4)), 'single') # test dict input inputs = dict(fake_img=torch.rand(1, 3, 3, 4)) self.assertEqual(parse_fn('img', inputs), 'BGR') # test data sample is not None data_sample = DataSample() # test gt_img key # - RGB in channel order --> RGB data_sample.set_metainfo({'gt_channel_order': 'RGB'}) self.assertEqual( parse_fn('gt_img', torch.rand(3, 5, 5), data_sample), 'RGB') # - BGR in channel order --> BGR data_sample.set_metainfo({'gt_channel_order': 'BGR'}) self.assertEqual( parse_fn('gt_img', torch.rand(3, 5, 5), data_sample), 'BGR') # - grayscale in color_type --> single data_sample.set_metainfo({'gt_color_type': 'grayscale'}) self.assertEqual( parse_fn('gt_img', torch.rand(1, 5, 5), data_sample), 'single') with self.assertRaises(AssertionError): parse_fn('gt_img', torch.rand(3, 5, 5), data_sample) # - unchanged in color_type --> BGR / single data_sample.set_metainfo({'gt_color_type': 'unchanged'}) self.assertEqual( parse_fn('gt_img', torch.rand(1, 5, 5), data_sample), 'single') self.assertEqual( parse_fn('gt_img', torch.rand(3, 5, 5), data_sample), 'BGR') # test non-gt keys # - RGB in channel order --> RGB data_sample.set_metainfo({'AAA_channel_order': 'RGB'}) self.assertEqual( parse_fn('AAA', torch.rand(3, 5, 5), data_sample), 'RGB') # - BGR in channel order --> BGR data_sample.set_metainfo({'BBC_channel_order': 'BGR'}) self.assertEqual( parse_fn('BBC', torch.rand(3, 5, 5), data_sample), 'BGR') # - grayscale in color_type --> single data_sample.set_metainfo({'mm_img_color_type': 'grayscale'}) data_sample.set_metainfo({'mm_img_channel_order': 'RGB'}) self.assertEqual( parse_fn('mm_img', torch.rand(1, 5, 5), data_sample), 'single') with self.assertRaises(AssertionError): parse_fn('mm_img', torch.rand(3, 5, 5), data_sample) # - unchanged in color_type --> BGR / single data_sample.set_metainfo({'mm_img_color_type': 'unchanged'}) self.assertEqual( parse_fn('mm_img', torch.rand(1, 5, 5), data_sample), 'single') self.assertEqual( parse_fn('mm_img', torch.rand(3, 5, 5), data_sample), 'BGR') # - color_type and channel_order both None --> BGR / single self.assertEqual( parse_fn('dk', torch.rand(1, 5, 5), data_sample), 'single') self.assertEqual( parse_fn('dk', torch.rand(3, 5, 5), data_sample), 'BGR') # test parse channel order for a stacked data sample stacked_data_sample = DataSample.stack([data_sample, data_sample]) self.assertEqual( parse_fn('mm_img', torch.rand(1, 5, 5), stacked_data_sample), 'single') self.assertEqual( parse_fn('AAA', torch.rand(3, 5, 5), data_sample), 'RGB') def test_parse_batch_channel_order(self): data_preprocessor = DataPreprocessor() parse_fn = data_preprocessor._parse_batch_channel_order with self.assertRaises(AssertionError): parse_fn('img', torch.rand(1, 3, 5, 5), [DataSample()] * 2) inputs_batch = torch.randn(2, 3, 5, 5) data_sample_batch = [ DataSample(metainfo=dict(gt_channel_order='RGB')), DataSample(metainfo=dict(gt_channel_order='RGB')) ] self.assertTrue(parse_fn('gt', inputs_batch, data_sample_batch)) data_sample_batch = [ DataSample(metainfo=dict(mm_img_channel_order='RGB')), DataSample(metainfo=dict(mm_img_channel_order='BGR')) ] with self.assertRaises(AssertionError): parse_fn(parse_fn('mm_img', inputs_batch, data_sample_batch)) def test_do_conversion(self): data_preprocessor = DataPreprocessor() cov_fn = data_preprocessor._do_conversion # RGB -> BGR inputs = torch.rand(2, 3, 5, 5) target_outputs = inputs[:, [2, 1, 0], ...] outputs, order = cov_fn(inputs, 'RGB', 'BGR') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'BGR') # BGR -> RGB outputs, order = cov_fn(inputs, 'BGR', 'RGB') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'RGB') # RGB -> None target_outputs = inputs.clone() outputs, order = cov_fn(inputs, 'RGB', None) self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'RGB') # BGR -> None target_outputs = inputs.clone() outputs, order = cov_fn(inputs, 'BGR', None) self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'BGR') # single inputs -> None inputs = torch.rand(1, 10, 1, 5, 5) target_outputs = inputs.clone() outputs, order = cov_fn(inputs, 'single', None) self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'single') # single inputs -> BGR / RGB outputs, order = cov_fn(inputs, 'single', None) self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'single') outputs, order = cov_fn(inputs, 'single', 'RGB') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'single') outputs, order = cov_fn(inputs, 'single', 'BGR') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'single') with self.assertRaises(ValueError): cov_fn(inputs, 'RGBA', 'RGB') # RGBA inputs -> BGR / RGB inputs = torch.rand(2, 4, 5, 5) target_outputs = inputs.clone() outputs, order = cov_fn(inputs, 'RGB', 'RGB') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'RGB') target_outputs = inputs[:, [2, 1, 0, 3], ...] outputs, order = cov_fn(inputs, 'RGB', 'BGR') self.assertTrue((outputs == target_outputs).all()) self.assertEqual(order, 'BGR') def test_update_metainfo(self): data_preprocessor = DataPreprocessor() update_fn = data_preprocessor._update_metainfo with self.assertRaises(AssertionError): padding_info = torch.randint(0, 10, (3, 2)) data_samples = [DataSample() for _ in range(2)] update_fn(padding_info, None, data_samples) padding_info = torch.randint(0, 10, (3, 2)) channel_order = dict(aaa='RGB', BBB='single') output = update_fn(padding_info, channel_order) self.assertEqual(len(output), 3) for data, padding_tar in zip(output, padding_info): self.assertTrue( (data.metainfo['padding_size'] == padding_tar).all()) self.assertEqual(data.metainfo['aaa_output_channel_order'], 'RGB') self.assertEqual(data.metainfo['BBB_output_channel_order'], 'single') # channel_order is None + data_sample is not None (use last output) padding_info = torch.randint(0, 10, (3, 2)) output = update_fn(padding_info, None, output) self.assertEqual(len(output), 3) for data, padding_tar in zip(output, padding_info): self.assertTrue( (data.metainfo['padding_size'] == padding_tar).all()) # channel order in last output remains self.assertEqual(data.metainfo['aaa_output_channel_order'], 'RGB') self.assertEqual(data.metainfo['BBB_output_channel_order'], 'single') def test_preprocess_image_tensor(self): """We test five cases: 1. raise error when input is not 4D tensor 2. no metainfo + output channel order is None: no conversion 3. no metainfo + output channel order is RGB: do conversion to RGB 4. metainfo (BGR) + output channel order is RGB: do conversion to RGB 5. metainfo (single) + output channel order is RGB: no conversion 6. datasample is None: return new data sample with metainfo """ data_preprocessor = DataPreprocessor() process_fn = data_preprocessor._preprocess_image_tensor # 1. raise error with self.assertRaises(AssertionError): process_fn(torch.rand(2, 25), None) # [0, 0, 0] for all time target_padding_info = torch.FloatTensor([0, 0, 0]) # 2. no metainfo + output channel order is None inputs = torch.randint(0, 255, (4, 3, 5, 5)) targets = (inputs - 127.5) / 127.5 data_samples = [ DataSample(metainfo=dict(mm_img_channel_order='RGB')) for _ in range(4) ] outputs, data_samples = process_fn(inputs, data_samples) assert_allclose(outputs, targets) for data in data_samples: self.assertEqual(data.metainfo['img_output_channel_order'], 'BGR') padding_size = data.metainfo['padding_size'] self.assertEqual(padding_size.shape, (3, )) self.assertTrue((padding_size == target_padding_info).all()) # 3. no metainfo + output channel order is RGB -> do conversion data_preprocessor = DataPreprocessor(output_channel_order='RGB') process_fn = data_preprocessor._preprocess_image_tensor inputs = torch.randint(0, 255, (4, 3, 5, 5)) targets = ((inputs - 127.5) / 127.5)[:, [2, 1, 0]] data_samples = [DataSample() for _ in range(4)] outputs, data_samples = process_fn(inputs, data_samples) assert_allclose(outputs, targets) for data in data_samples: self.assertEqual(data.metainfo['img_output_channel_order'], 'RGB') padding_size = data.metainfo['padding_size'] self.assertEqual(padding_size.shape, (3, )) self.assertTrue((padding_size == target_padding_info).all()) # 4. metainfo (BGR) + output channel order is RGB -> do conversion data_preprocessor = DataPreprocessor(output_channel_order='RGB') process_fn = data_preprocessor._preprocess_image_tensor inputs = torch.randint(0, 255, (4, 3, 5, 5)) targets = ((inputs - 127.5) / 127.5)[:, [2, 1, 0]] data_samples = [ DataSample(metainfo=dict(gt_channel_order='BGR')) for _ in range(4) ] outputs, data_samples = process_fn(inputs, data_samples, 'gt_img') assert_allclose(outputs, targets) for data in data_samples: self.assertEqual(data.metainfo['gt_img_output_channel_order'], 'RGB') padding_size = data.metainfo['padding_size'] self.assertEqual(padding_size.shape, (3, )) self.assertTrue((padding_size == target_padding_info).all()) # 5. metainfo (single) + output channel order is RGB -> no conversion data_preprocessor = DataPreprocessor(output_channel_order='RGB') process_fn = data_preprocessor._preprocess_image_tensor inputs = torch.randint(0, 255, (4, 1, 5, 5)) targets = ((inputs - 127.5) / 127.5) data_samples = [ DataSample(metainfo=dict(sin_channel_order='single')) for _ in range(4) ] outputs, data_samples = process_fn(inputs, data_samples, 'sin') assert_allclose(outputs, targets) for data in data_samples: self.assertEqual(data.metainfo['sin_output_channel_order'], 'single') padding_size = data.metainfo['padding_size'] self.assertEqual(padding_size.shape, (3, )) self.assertTrue((padding_size == target_padding_info).all()) # 6. data sample is None + video inputs data_preprocessor = DataPreprocessor(output_channel_order='RGB') inputs = torch.randint(0, 255, (4, 5, 3, 5, 5)) targets = ((inputs - 127.5) / 127.5)[:, :, [2, 1, 0]] outputs, data_samples = process_fn(inputs, None, 'sin') for data in data_samples: self.assertEqual(data.metainfo['sin_output_channel_order'], 'RGB') self.assertTrue( (data.metainfo['padding_size'] == target_padding_info).all()) def test_preprocess_image_list(self): """We test four cases: 1. no metainfo + output channel order is None: no conversion 2. no metainfo + output channel order is RGB + padding: do conversion to RGB 3. metainfo (RGB) + output channel order is RGB + padding: no conversion 4. metainfo (single) + output channel order is RGB: no conversion 5. data_sample is None """ # no metainfo + output channel order is None data_preprocessor = DataPreprocessor() process_fn = data_preprocessor._preprocess_image_list input1 = torch.randint(0, 255, (3, 3, 5)) input2 = torch.randint(0, 255, (3, 3, 5)) inputs = [input1, input2] data_samples = [DataSample() for _ in range(2)] target = torch.stack([(input1 - 127.5) / 127.5, (input2 - 127.5) / 127.5], dim=0) target_padding_info = torch.FloatTensor([0, 0, 0]) outputs, data_samples = process_fn(inputs, data_samples) assert_allclose(outputs, target) for data in data_samples: self.assertEqual(data.metainfo['img_output_channel_order'], 'BGR') self.assertTrue( (data.metainfo['padding_size'] == target_padding_info).all()) # no metainfo + output channel order is RGB data_preprocessor = DataPreprocessor( output_channel_order='RGB', pad_value=42) process_fn = data_preprocessor._preprocess_image_list input1 = torch.randint(0, 255, (3, 3, 5)) input2 = torch.randint(0, 255, (3, 5, 5)) inputs = [input1, input2] data_samples = [DataSample() for _ in range(2)] target1 = F.pad(input1.clone(), (0, 0, 0, 2), value=42) # pad H target2 = input2.clone() target = torch.stack([target1, target2], dim=0)[:, [2, 1, 0]] target = (target - 127.5) / 127.5 target_padding_info = [ torch.FloatTensor([0, 2, 0]), torch.FloatTensor([0, 0, 0]) ] outputs, data_samples = process_fn(inputs, data_samples) assert_allclose(outputs, target) for data, pad in zip(data_samples, target_padding_info): self.assertEqual(data.metainfo['img_output_channel_order'], 'RGB') self.assertTrue((data.metainfo['padding_size'] == pad).all()) # meta info + output channel order is RGB data_preprocessor = DataPreprocessor( output_channel_order='RGB', pad_value=42) process_fn = data_preprocessor._preprocess_image_list input1 = torch.randint(0, 255, (3, 3, 5)) input2 = torch.randint(0, 255, (3, 5, 3)) inputs = [input1, input2] data_samples = [ DataSample(metainfo=dict(gt_channel_order='RGB')) for _ in range(2) ] target1 = F.pad(input1.clone(), (0, 0, 0, 2), value=42) # pad H target2 = F.pad(input2.clone(), (0, 2, 0, 0), value=42) # pad W target = torch.stack([target1, target2], dim=0) target = (target - 127.5) / 127.5 target_padding_info = [ torch.FloatTensor([0, 2, 0]), torch.FloatTensor([0, 0, 2]) ] outputs, data_samples = process_fn(inputs, data_samples, 'gt_img') assert_allclose(outputs, target) for data, pad in zip(data_samples, target_padding_info): self.assertEqual(data.metainfo['gt_img_output_channel_order'], 'RGB') self.assertTrue((data.metainfo['padding_size'] == pad).all()) # meta info (single) + output channel order is RGB data_preprocessor = DataPreprocessor( output_channel_order='RGB', pad_value=42) process_fn = data_preprocessor._preprocess_image_list input1 = torch.randint(0, 255, (1, 3, 5)) input2 = torch.randint(0, 255, (1, 5, 3)) inputs = [input1, input2] data_samples = [ DataSample(metainfo=dict(AA_channel_order='single')) for _ in range(2) ] target1 = F.pad(input1.clone(), (0, 0, 0, 2), value=42) # pad H target2 = F.pad(input2.clone(), (0, 2, 0, 0), value=42) # pad W target = torch.stack([target1, target2], dim=0) target = (target - 127.5) / 127.5 target_padding_info = [ torch.FloatTensor([0, 2, 0]), torch.FloatTensor([0, 0, 2]) ] outputs, data_samples = process_fn(inputs, data_samples, 'AA') assert_allclose(outputs, target) for data, pad in zip(data_samples, target_padding_info): self.assertEqual(data.metainfo['AA_output_channel_order'], 'single') self.assertTrue((data.metainfo['padding_size'] == pad).all()) # test data sample is None data_preprocessor = DataPreprocessor( output_channel_order='RGB', pad_value=42) process_fn = data_preprocessor._preprocess_image_list input1 = torch.randint(0, 255, (1, 3, 5)) input2 = torch.randint(0, 255, (1, 5, 3)) inputs = [input1, input2] target1 = F.pad(input1.clone(), (0, 0, 0, 2), value=42) # pad H target2 = F.pad(input2.clone(), (0, 2, 0, 0), value=42) # pad W target = torch.stack([target1, target2], dim=0) target = (target - 127.5) / 127.5 target_padding_info = [ torch.FloatTensor([0, 2, 0]), torch.FloatTensor([0, 0, 2]) ] outputs, data_samples = process_fn(inputs, None, 'test') assert_allclose(outputs, target) for data, pad in zip(data_samples, target_padding_info): self.assertEqual(data.metainfo['test_output_channel_order'], 'single') self.assertTrue((data.metainfo['padding_size'] == pad).all()) def test_preprocess_dict_inputs(self): """Since preprocess of dict inputs are based on `_preprocess_image_list` and `_preprocess_image_tensor`, we just test a simple case for translation model and padding behavior.""" data_preprocessor = DataPreprocessor(output_channel_order='RGB') process_fn = data_preprocessor._preprocess_dict_inputs inputs = dict( img_A=[torch.randint(0, 255, (3, 5, 5)) for _ in range(3)], img_B=[torch.randint(0, 255, (3, 5, 5)) for _ in range(3)], noise=[torch.randn(16) for _ in range(3)], num_batches=3, tensor=torch.randint(0, 255, (3, 4, 5, 5)), mode=['ema', 'ema', 'ema'], ) data_samples = [ DataSample( metainfo=dict( img_A_channel_order='RGB', img_B_channel_order='BGR')) for _ in range(3) ] target_A = (torch.stack(inputs['img_A']) - 127.5) / 127.5 target_B = (torch.stack(inputs['img_B']) - 127.5) / 127.5 target_B = target_B[:, [2, 1, 0]] target_noise = torch.stack(inputs['noise']) # no metainfo, parse as BGR, do conversion target_tensor = ((inputs['tensor'] - 127.5) / 127.5)[:, [2, 1, 0, 3]] outputs, data_samples = process_fn(inputs, data_samples) assert_allclose(outputs['img_A'], target_A) assert_allclose(outputs['img_B'], target_B) assert_allclose(outputs['noise'], target_noise) assert_allclose(outputs['tensor'], target_tensor) self.assertEqual(outputs['mode'], 'ema') self.assertEqual(outputs['num_batches'], 3) # test no padding checking --> no tensor inputs inputs = dict(num_batches=3, mode=['ema', 'ema', 'ema']) outputs, data_samples = process_fn(inputs, data_samples) self.assertEqual(outputs['mode'], 'ema') self.assertEqual(outputs['num_batches'], 3) # test error in padding checking data_samples = [DataSample() for _ in range(2)] inputs = dict( img_A=[ torch.randint(0, 255, (3, 3, 5)), torch.randint(0, 255, (3, 5, 5)) ], img_B=[ torch.randint(0, 255, (3, 5, 5)), torch.randint(0, 255, (3, 5, 5)) ], ) with self.assertRaises(ValueError): process_fn(inputs, data_samples) def test_prerprocess_data_sample(self): """Only test training and testint mode in this test case.""" data_preprocessor = DataPreprocessor( data_keys=['gt_img', 'AA', 'dk'], output_channel_order='RGB') cov_fn = data_preprocessor._preprocess_data_sample # test training is True metainfo = dict(gt_channel_order='RGB', tar_channel_order='BGR') data_samples = [ DataSample( gt_img=torch.randint(0, 255, (3, 5, 5)), AA=torch.randint(0, 255, (3, 5, 5)), metainfo=metainfo, ) for _ in range(3) ] tar_AA = torch.stack([data.AA for data in data_samples]) tar_AA = ((tar_AA - 127.5) / 127.5)[:, [2, 1, 0]] tar_gt = torch.stack([data.gt_img for data in data_samples]) tar_gt = (tar_gt - 127.5) / 127.5 outputs = cov_fn(data_samples, True) assert_allclose(outputs.gt_img, tar_gt) assert_allclose(outputs.AA, tar_AA) # test training is False data_samples = [ DataSample( gt_img=torch.randint(0, 255, (3, 5, 5)), AA=torch.randint(0, 255, (3, 5, 5)), metainfo=metainfo, ) for _ in range(3) ] tar_AA = torch.stack([data.AA for data in data_samples]) tar_AA = tar_AA # BGR, no conversion tar_gt = torch.stack([data.gt_img for data in data_samples]) tar_gt = tar_gt[:, [2, 1, 0]] # RGB -> BGR outputs = cov_fn(data_samples, False) assert_allclose(outputs.gt_img, tar_gt) assert_allclose(outputs.AA, tar_AA) # test no stack data_preprocessor.stack_data_sample = False data_samples = [ DataSample( gt_img=torch.randint(0, 255, (3, 5, 5)), AA=torch.randint(0, 255, (3, 5, 5)), metainfo=metainfo, ) for _ in range(3) ] tar_AA = torch.stack([data.AA for data in data_samples]) tar_AA = tar_AA # BGR, no conversion tar_gt = torch.stack([data.gt_img for data in data_samples]) tar_gt = tar_gt[:, [2, 1, 0]] # RGB -> BGR outputs = cov_fn(data_samples, False) output_gt = torch.stack([out.gt_img for out in outputs]) output_AA = torch.stack([out.AA for out in outputs]) assert_allclose(output_gt, tar_gt) assert_allclose(output_AA, tar_AA) def test_destruct_tensor_norm_and_conversion(self): """Test batch inputs, single input and batch inputs + no norm in this unit test.""" data_preprocessor = DataPreprocessor() cov_fn = data_preprocessor._destruct_norm_and_conversion # test batch metainfo = dict( img_output_channel_order='RGB', aaa_output_channel_order='single', bbb_output_channel_order='BGR', ) img = torch.randn([3, 3, 5, 5]) aaa = torch.randn([3, 1, 5, 5]) bbb = torch.randn([3, 3, 5, 5]) ccc = torch.randn([3, 3, 5, 5]) data_samples = [DataSample(metainfo=metainfo) for _ in range(3)] tar_img = ((img * 127.5) + 127.5)[:, [2, 1, 0]] tar_aaa = (aaa * 127.5) + 127.5 tar_bbb = (bbb * 127.5) + 127.5 tar_ccc = (ccc * 127.5) + 127.5 assert_allclose(cov_fn(img, data_samples, 'img'), tar_img) assert_allclose(cov_fn(aaa, data_samples, 'aaa'), tar_aaa) assert_allclose(cov_fn(bbb, data_samples, 'bbb'), tar_bbb) assert_allclose(cov_fn(ccc, data_samples, 'bbb'), tar_ccc) # test single sample img = torch.randn([3, 5, 5]) aaa = torch.randn([1, 5, 5]) bbb = torch.randn([3, 5, 5]) ccc = torch.randn([3, 5, 5]) data_samples = DataSample(metainfo=metainfo) tar_img = ((img * 127.5) + 127.5)[[2, 1, 0], ...] tar_aaa = (aaa * 127.5) + 127.5 tar_bbb = (bbb * 127.5) + 127.5 tar_ccc = (ccc * 127.5) + 127.5 assert_allclose(cov_fn(img, data_samples, 'img'), tar_img) assert_allclose(cov_fn(aaa, data_samples, 'aaa'), tar_aaa) assert_allclose(cov_fn(bbb, data_samples, 'bbb'), tar_bbb) assert_allclose(cov_fn(ccc, data_samples, 'bbb'), tar_ccc) # test no norm data_preprocessor._enable_normalize = False metainfo = dict(img_output_channel_order='RGB', ) img = torch.randn([3, 3, 5, 5]) data_samples = [DataSample(metainfo=metainfo) for _ in range(3)] tar_img = img[:, [2, 1, 0]] assert_allclose(cov_fn(img, data_samples, 'img'), tar_img) def test_destruct_tensor_padding(self): """Test five cases in this unit test. 1. batch inputs + same padidng = True 2. batch inputs + same padding = False 3. single inputs 4. data_samples is None 5. padding_size is not found in metainfo 6. one data sample + padding size is not found in metainfo 7. list of sample + padding size is not found in metainfo 8. data sample is stacked 9. data sample is stacked + padding size not found in metainfo """ data_preprocessor = DataPreprocessor() cov_fn = data_preprocessor._destruct_padding # data sample is None, no un-padding batch_tensor = torch.randint(0, 255, (2, 3, 3, 3)) tar_output = batch_tensor.clone() output = cov_fn(batch_tensor, None) assert_allclose(tar_output, output) # batch inputs + same_padding is True batch_tensor = torch.randint(0, 255, (2, 3, 5, 5)) metainfo_1 = dict(padding_size=torch.FloatTensor([2, 0])) metainfo_2 = dict(padding_size=torch.FloatTensor([0, 2])) data_samples = [ DataSample(metainfo=metainfo_1), DataSample(metainfo=metainfo_2) ] output = cov_fn(batch_tensor, data_samples) self.assertEqual(output.shape, (2, 3, 3, 5)) # batch inputs + same padding is False batch_tensor = torch.randint(0, 255, (2, 3, 5, 5)) metainfo_1 = dict(padding_size=torch.FloatTensor([2, 0])) metainfo_2 = dict(padding_size=torch.FloatTensor([0, 2])) data_samples = [ DataSample(metainfo=metainfo_1), DataSample(metainfo=metainfo_2) ] output = cov_fn(batch_tensor, data_samples, False) self.assertIsInstance(output, list) self.assertEqual(output[0].shape, (3, 3, 5)) self.assertEqual(output[1].shape, (3, 5, 3)) # single inputs batch_tensor = torch.randint(0, 255, (3, 5, 5)) data_samples = DataSample(metainfo=metainfo_1) output = cov_fn(batch_tensor, data_samples, False) self.assertEqual(output.shape, (3, 3, 5)) # single data sample + test metainfo not found batch_tensor = torch.randint(0, 255, (3, 5, 5)) data_preprocessor._done_padding = False output = cov_fn(batch_tensor, DataSample(), False) assert_allclose(output, batch_tensor) # list of data sample + test metainfo not found batch_tensor = torch.randint(0, 255, (2, 3, 5, 5)) output = cov_fn(batch_tensor, [DataSample()] * 2, False) assert_allclose(output, batch_tensor) data_preprocessor._done_padding = True output = cov_fn(batch_tensor, DataSample(), False) assert_allclose(output, batch_tensor) # test stacked data sample data_samples = [ DataSample(metainfo=metainfo_1), DataSample(metainfo=metainfo_2) ] stacked_data_sample = DataSample.stack(data_samples) batch_tensor = torch.randint(0, 255, (2, 3, 5, 5)) output = cov_fn(batch_tensor, stacked_data_sample, False) self.assertIsInstance(output, list) self.assertEqual(output[0].shape, (3, 3, 5)) self.assertEqual(output[1].shape, (3, 5, 3)) # test stacked data sample + metainfo is None stacked_data_sample = DataSample() batch_tensor = torch.randint(0, 255, (2, 3, 5, 5)) output = cov_fn(batch_tensor, stacked_data_sample, True) self.assertEqual(output.shape, (2, 3, 5, 5)) def test_forward(self): """Test five cases in this unit test. We do not cover all possible cases, as we test them in test cases for other functions. 1. Input is tensor. 2. Input is list of tensors. 3. Input is a list of dict. 4. Input is dict. 5. Input is tensor + no norm 6. data samples behavior in training = False / True 7. Input is wrong type. """ data_preprocessor = DataPreprocessor() # 1. input is tensor inputs = torch.randint(0, 255, (2, 3, 5, 5)) data = dict(inputs=inputs) tar_output = (inputs.clone() - 127.5) / 127.5 data_preprocessor = DataPreprocessor() data = data_preprocessor(data) assert_allclose(data['inputs'], tar_output) # 2. input is list of tensor input1 = torch.randn(3, 3, 5) input2 = torch.randn(3, 3, 5) data = dict(inputs=[input1, input2]) data = data_preprocessor(data) self.assertEqual(data['inputs'].shape, (2, 3, 3, 5)) target_input1 = (input1.clone() - 127.5) / 127.5 target_input2 = (input2.clone() - 127.5) / 127.5 assert_allclose(target_input1, data['inputs'][0]) assert_allclose(target_input2, data['inputs'][1]) # 3. input is list of dict imgA1 = torch.randn(3, 3, 5) imgA2 = torch.randn(3, 3, 5) imgB1 = torch.randn(3, 3, 5) imgB2 = torch.randn(3, 3, 5) data = dict(inputs=[ dict(imgA=imgA1, imgB=imgB1), dict(imgA=imgA2, imgB=imgB2) ]) data = data_preprocessor(data) self.assertEqual(list(data['inputs'].keys()), ['imgA', 'imgB']) img1 = torch.randn(3, 4, 4) img2 = torch.randn(3, 4, 4) noise1 = torch.randn(3, 4, 4) noise2 = torch.randn(3, 4, 4) target_input1 = (img1[[2, 1, 0], ...].clone() - 127.5) / 127.5 target_input2 = (img2[[2, 1, 0], ...].clone() - 127.5) / 127.5 data = dict(inputs=[ dict(noise=noise1, img=img1, num_batches=2, mode='ema'), dict(noise=noise2, img=img2, num_batches=2, mode='ema'), ]) data_preprocessor = DataPreprocessor(output_channel_order='RGB') data = data_preprocessor(data) self.assertEqual( list(data['inputs'].keys()), ['noise', 'img', 'num_batches', 'mode']) assert_allclose(data['inputs']['noise'][0], noise1) assert_allclose(data['inputs']['noise'][1], noise2) assert_allclose(data['inputs']['img'][0], target_input1) assert_allclose(data['inputs']['img'][1], target_input2) self.assertEqual(data['inputs']['num_batches'], 2) self.assertEqual(data['inputs']['mode'], 'ema') # 4. nput is dict sampler_results = dict(inputs=dict(num_batches=2, mode='ema')) data = data_preprocessor(sampler_results) self.assertEqual(data['inputs'], sampler_results['inputs']) self.assertIsNone(data['data_samples']) # test dict input with tensor sampler_results = dict(inputs=dict(fake_img=torch.randn(2, 3, 10, 10))) data = data_preprocessor(sampler_results) # # 5. input is tensor + no norm data_preprocessor = DataPreprocessor(mean=None, std=None) input1 = torch.randn(3, 3, 5) input2 = torch.randn(3, 3, 5) data = dict(inputs=torch.stack([input1, input2], dim=0)) data = data_preprocessor(data) self.assertEqual(data['inputs'].shape, (2, 3, 3, 5)) self.assertTrue((data['inputs'] == torch.stack([input1, input2], dim=0)).all()) # 6. data samples behavior in training = False / True data_preprocessor = DataPreprocessor() gt_inp1 = torch.randint(0, 255, (3, 5, 5)) gt_inp2 = torch.randint(0, 255, (3, 5, 5)) data_samples = [DataSample(gt_img=gt_inp1), DataSample(gt_img=gt_inp2)] data = dict(inputs=[input1, input2], data_samples=data_samples) data = data_preprocessor(data, training=False) assert_allclose(data['data_samples'].gt_img, torch.stack([gt_inp1, gt_inp2])) data = dict(inputs=[input1, input2], data_samples=data_samples) data = data_preprocessor(data, training=True) self.assertTrue((data['data_samples'].gt_img <= 1).all()) # 7. Input is wrong type data = dict(inputs='wrong type') with self.assertRaises(ValueError): data = data_preprocessor(data) def test_destruct(self): """We test the following cases in this unit test: 1. test un-padding 2. test un-norm + no un-padding 3. test no un-norm + no un-padding """ # 1. test un-padding data_preprocessor = DataPreprocessor() input1 = torch.randn(3, 3, 5) input2 = torch.randn(3, 5, 3) data = dict(inputs=[input1, input2]) data = data_preprocessor(data) self.assertEqual(data['inputs'].shape, (2, 3, 5, 5)) tar_pad_size = torch.FloatTensor([[0, 2, 0], [0, 0, 2]]) padding_sizes = data['data_samples'].metainfo['padding_size'] for padding_size, tar in zip(padding_sizes, tar_pad_size): assert_allclose(padding_size, tar) destruct_batch = data_preprocessor.destruct(data['inputs'], data['data_samples']) self.assertEqual(destruct_batch.shape, (2, 3, 3, 5)) # 2. test no un-padding + un-norm data_preprocessor = DataPreprocessor() input1 = torch.randint(0, 255, (3, 5, 5)) input2 = torch.randint(0, 255, (3, 5, 5)) data = dict(inputs=[input1, input2]) data = data_preprocessor(data) self.assertEqual(data['inputs'].shape, (2, 3, 5, 5)) tar_pad_size = torch.FloatTensor([[0, 0, 0], [0, 0, 0]]) padding_sizes = data['data_samples'].metainfo['padding_size'] for padding_size, tar in zip(padding_sizes, tar_pad_size): assert_allclose(padding_size, tar) destruct_batch = data_preprocessor.destruct(data['inputs'], data['data_samples']) self.assertEqual(destruct_batch.shape, (2, 3, 5, 5)) assert_allclose(destruct_batch, torch.stack([input1, input2], dim=0).float()) # 3. test no un-norm data_preprocessor = DataPreprocessor(std=None, mean=None) input1 = torch.randint(0, 255, (1, 5, 5)) input2 = torch.randint(0, 255, (1, 5, 5)) inputs = torch.stack([input1, input2], dim=0) destruct_batch = data_preprocessor.destruct(inputs) self.assertEqual(destruct_batch.shape, (2, 1, 5, 5)) assert_allclose(destruct_batch.float(), inputs.float()) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_data_preprocessors/test_mattor_preprocessor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmengine.testing import assert_allclose from mmagic.models.data_preprocessors import MattorPreprocessor from mmagic.structures import DataSample def test_mattor_preprocessor(): processor = MattorPreprocessor() # prepare data inputs = torch.rand(1, 3, 20, 20) target = torch.rand(3, 20, 20) gt_fg = torch.rand(3, 20, 20) gt_bg = torch.rand(3, 20, 20) data_sample = DataSample(trimap=target, gt_fg=gt_fg, gt_bg=gt_bg) data = dict(inputs=inputs, data_samples=[data_sample]) # process data = processor(data, True) batch_inputs, batch_data_samples = data['inputs'], data['data_samples'] assert isinstance(batch_inputs, torch.Tensor) assert batch_inputs.shape == (1, 6, 20, 20) assert isinstance(batch_data_samples, DataSample) assert batch_data_samples.trimap.shape == (1, 3, 20, 20) # test proc_batch_trimap processor = MattorPreprocessor(proc_trimap='as_is') inputs = torch.rand(1, 3, 20, 20) target = torch.rand(3, 20, 20) data_sample = DataSample(trimap=target) data = dict(inputs=inputs, data_samples=[data_sample]) data = processor(data, True) batch_inputs, batch_data_samples = data['inputs'], data['data_samples'] assert isinstance(batch_inputs, torch.Tensor) assert batch_inputs.shape == (1, 6, 20, 20) assert isinstance(batch_data_samples, DataSample) assert batch_data_samples.trimap.shape == (1, 3, 20, 20) assert_allclose(batch_data_samples.trimap[0], target) # test error in proc_batch_trimap processor = MattorPreprocessor(proc_trimap='wrong_method') with pytest.raises(ValueError): processor(dict(inputs=inputs, data_samples=[data_sample])) # test training is False processor = MattorPreprocessor(proc_trimap='as_is') inputs = torch.rand(1, 3, 20, 20) target = torch.rand(3, 20, 20) gt_fg = torch.rand(3, 20, 20) gt_bg = torch.rand(3, 20, 20) data_sample = DataSample(trimap=target) data = dict(inputs=inputs, data_samples=[data_sample]) data = processor(data, training=False) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.diffusion_schedulers.ddim_scheduler import EditDDIMScheduler def test_ddim(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) ddim = EditDDIMScheduler( num_train_timesteps=1000, variance_type='learned_range') ddim.set_timesteps(10) result = ddim.step(modelout, 980, sample) assert result['prev_sample'].shape == (1, 4, 32, 32) noise = torch.rand((1, 4, 32, 32)) result = ddim.add_noise(sample, noise, 10) assert result.shape == (1, 4, 32, 32) assert len(ddim) == 1000 def test_ddim_init(): ddim = EditDDIMScheduler( num_train_timesteps=1000, beta_schedule='scaled_linear') ddim = EditDDIMScheduler( num_train_timesteps=1000, beta_schedule='squaredcos_cap_v2') assert isinstance(ddim, EditDDIMScheduler) with pytest.raises(Exception): EditDDIMScheduler(num_train_timesteps=1000, beta_schedule='fake') def test_ddim_step(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) ddim = EditDDIMScheduler( num_train_timesteps=1000, variance_type='learned_range') with pytest.raises(Exception): ddim.step(modelout, 980, sample) ddim.set_timesteps(10) result = ddim.step( modelout, 980, sample, eta=1, use_clipped_model_output=True) assert result['prev_sample'].shape == (1, 4, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_diffusion_schedulers/test_init.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import shutil from unittest import TestCase from mmagic.registry import DIFFUSION_SCHEDULERS test_dir = osp.join(osp.dirname(__file__), '../../..', 'tests') config_path = osp.join(test_dir, 'configs', 'scheduler_cfg') class TestWrapper(TestCase): def test_build(self): # 1. test init by args config = dict( type='EulerDiscreteScheduler', num_train_timesteps=2000, beta_schedule='scaled_linear') scheduler = DIFFUSION_SCHEDULERS.build(config) self.assertEqual(len(scheduler.timesteps), 2000) # self.assertEqual(scheduler.beta_schedule, 'scaled_linear') scheduler_str = repr(scheduler) self.assertIn( 'Wrapped Scheduler Class: ' '', scheduler_str) self.assertIn('Wrapped Scheduler Name: EulerDiscreteScheduler', scheduler_str) self.assertNotIn('From Pretrained: ', scheduler_str) # 2. test save as diffuser scheduler.save_pretrained(config_path) # 3. test from_pretrained config = dict( type='EulerDiscreteScheduler', from_pretrained=config_path) scheduler = DIFFUSION_SCHEDULERS.build(config) scheduler_str = repr(scheduler) self.assertIn('From Pretrained: ', scheduler_str) # 4. test attribute error with self.assertRaises(AttributeError): scheduler.unsupported_attr('do not support') # tear down shutil.rmtree(config_path) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_animatediff.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest import TestCase import pytest from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.registry import MODELS from mmagic.utils import register_all_modules # from mmengine.utils import digit_version # from mmengine.utils.dl_utils import TORCH_VERSION register_all_modules() stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' diffusion_scheduler = dict( type='DDIMScheduler', beta_end=0.012, beta_schedule='linear', beta_start=0.00085, num_train_timesteps=1000, prediction_type='epsilon', set_alpha_to_one=True, clip_sample=False, thresholding=False, steps_offset=1) model = dict( type='AnimateDiff', vae=dict( type='AutoencoderKL', from_pretrained=stable_diffusion_v15_url, subfolder='vae'), unet=dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1)), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_v15_url, subfolder='text_encoder'), tokenizer=stable_diffusion_v15_url, scheduler=diffusion_scheduler, test_scheduler=diffusion_scheduler, data_preprocessor=dict(type='DataPreprocessor'), dream_booth_lora_cfg=dict(type='ToonYou', steps=25, guidance_scale=7.5)) @pytest.mark.skipif( 'win' in platform.system().lower() or digit_version(TORCH_VERSION) <= digit_version('1.9.2'), reason='skip on windows due to limited RAM' 'and torch >= 1.10.0') class TestAnimateDiff(TestCase): def setUp(self): animatediff = MODELS.build(model) assert not any([p.requires_grad for p in animatediff.vae.parameters()]) assert not any( [p.requires_grad for p in animatediff.text_encoder.parameters()]) assert not any( [p.requires_grad for p in animatediff.unet.parameters()]) self.animatediff = animatediff @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_infer(self): videos = self.animatediff.infer( 'best quality, masterpiece, 1girl, cloudy sky, \ dandelion, contrapposto, alternate hairstyle', negative_prompt='', video_length=16, height=32, width=32)['samples'] assert videos.shape == (1, 3, 16, 32, 32) ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_attention3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.animatediff.attention_3d import (CrossAttention, Transformer3DModel) def test_crossattention(): input = torch.rand((2, 64, 64)) crossattention = CrossAttention(64) crossattention.set_attention_slice(2) output = crossattention.forward(input) assert output.shape == (2, 64, 64) with pytest.raises(Exception): crossattention.set_attention_slice(10) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_Transformer3DModel_init(): with pytest.raises(Exception): Transformer3DModel( in_channels=32, num_vector_embeds=4, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False) with pytest.raises(Exception): Transformer3DModel() Transformer3DModel( in_channels=32, use_linear_projection=True, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False) # if __name__ == '__main__': # test_crossattention() # test_Transformer3DModel_init() ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_motion_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.animatediff.motion_module import ( FeedForward, VanillaTemporalModule) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_VanillaTemporalModule(): # This also test TemporalTransformerBlock input = torch.rand((1, 64, 16, 32, 32)) text_feat = torch.rand([1, 77, 768]) transformer = VanillaTemporalModule(in_channels=64) output = transformer.forward(input, 10, text_feat) assert output.shape == (1, 64, 16, 32, 32) def test_FeedForward(): input = torch.rand((2, 64, 64)) feed_forward = FeedForward(64, 64, activation_fn='geglu') output = feed_forward.forward(input) assert output.shape == (2, 64, 64) # if __name__ == '__main__': # test_VanillaTemporalModule() # test_FeedForward() ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_res_blocks3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.animatediff.unet_block import (Downsample3D, ResnetBlock3D, Upsample3D) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_resnetblock3d(): input = torch.rand((1, 64, 16, 16, 16)) resblock = ResnetBlock3D(in_channels=64) output = resblock.forward(input, None) assert output.shape == (1, 64, 16, 16, 16) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_Downsample3D(): input = torch.rand((1, 64, 16, 16, 16)) downsample = Downsample3D(channels=64, use_conv=True, padding=1) output = downsample.forward(input) assert output.shape == (1, 64, 16, 8, 8) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_Upsample3D(): input = torch.rand((1, 64, 16, 16, 16)) upsample = Upsample3D(channels=64, use_conv_transpose=False, use_conv=True) output = upsample.forward(input) assert output.shape == (1, 64, 16, 32, 32) # if __name__ == '__main__': # test_Downsample3D() # test_Upsample3D() # test_resnetblock3d() ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_unet3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.utils import build_module from mmagic.registry import MODELS stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' unet_cfg = dict( type='UNet3DConditionMotionModel', unet_use_cross_frame_attention=False, unet_use_temporal_attention=False, use_motion_module=True, motion_module_resolutions=[1, 2, 4, 8], motion_module_mid_block=False, motion_module_decoder_only=False, motion_module_type='Vanilla', motion_module_kwargs=dict( num_attention_heads=8, num_transformer_block=1, attention_block_types=['Temporal_Self', 'Temporal_Self'], temporal_position_encoding=True, temporal_position_encoding_max_len=24, temporal_attention_dim_div=1), subfolder='unet') @pytest.mark.skipif( 'win' in platform.system().lower() or digit_version(TORCH_VERSION) <= digit_version('1.9.2'), reason='skip on windows due to limited RAM' 'and torch >= 1.10.0') def test_Unet3D(): input = torch.rand((1, 4, 16, 8, 8)) text_feat = torch.rand([1, 20, 768]) unet = build_module(unet_cfg, MODELS) output = unet.forward(input, 10, text_feat) assert output['sample'].shape == (1, 4, 16, 8, 8) if __name__ == '__main__': test_Unet3D() ================================================ FILE: tests/test_models/test_editors/test_animatediff/test_unet_blocks3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.animatediff.unet_block import ( CrossAttnDownBlock3D, CrossAttnUpBlock3D, UNetMidBlock3DCrossAttn, get_down_block, get_up_block) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_UNetMidBlock3DCrossAttn(): input = torch.rand((1, 64, 16, 8, 8)) midblock = UNetMidBlock3DCrossAttn( 64, 64, cross_attention_dim=64, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False) output = midblock.forward(input) assert output.shape == (1, 64, 16, 8, 8) def test_CrossAttnDownBlock3D(): input = torch.rand((1, 64, 16, 8, 8)) downblock = CrossAttnDownBlock3D( 64, 64, 64, cross_attention_dim=64, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False) output, _ = downblock.forward(input) assert output.shape == (1, 64, 16, 4, 4) def test_CrossAttnUpBlock3D(): input = torch.rand((1, 64, 16, 8, 8)) upblock = CrossAttnUpBlock3D( 64, 64, 64, 64, cross_attention_dim=64, unet_use_cross_frame_attention=False, unet_use_temporal_attention=False) output = upblock.forward(input, [input]) assert output.shape == (1, 64, 16, 16, 16) def test_get_down_block(): with pytest.raises(Exception): get_down_block('tem', 1, 1, 1, 1, True, 'silu', 1) def test_get_up_block(): with pytest.raises(Exception): get_up_block('tem', 1, 1, 1, 1, 1, True, 'silu', 1) # if __name__ == '__main__': # test_CrossAttnDownBlock3D() # test_CrossAttnUpBlock3D() # test_get_down_block() # test_get_up_block() ================================================ FILE: tests/test_models/test_editors/test_aotgan/test_aot_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_gl_dec(): input_x = torch.randn(1, 4, 256, 256) template_cfg = dict(type='AOTEncoderDecoder') cfg_ = template_cfg.copy() cfg_['decoder'] = dict(type='AOTDecoder') aot_encdec = MODELS.build(cfg_) output = aot_encdec(input_x) assert output.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_aotgan/test_aot_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_gl_enc(): input_x = torch.randn(1, 4, 256, 256) template_cfg = dict(type='AOTEncoderDecoder') cfg_ = template_cfg.copy() cfg_['encoder'] = dict(type='AOTEncoder') aot_encdec = MODELS.build(cfg_) output = aot_encdec(input_x) assert output.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_aotgan/test_aot_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_gl_encdec(): input_x = torch.randn(1, 4, 64, 64) template_cfg = dict(type='AOTEncoderDecoder') aot_encdec = MODELS.build(template_cfg) aot_encdec.init_weights() output = aot_encdec(input_x) assert output.shape == (1, 3, 64, 64) cfg_ = template_cfg.copy() cfg_['encoder'] = dict(type='AOTEncoder') aot_encdec = MODELS.build(cfg_) output = aot_encdec(input_x) assert output.shape == (1, 3, 64, 64) cfg_ = template_cfg.copy() cfg_['decoder'] = dict(type='AOTDecoder') aot_encdec = MODELS.build(cfg_) output = aot_encdec(input_x) assert output.shape == (1, 3, 64, 64) if torch.cuda.is_available(): aot_encdec = MODELS.build(template_cfg) aot_encdec.init_weights() aot_encdec = aot_encdec.cuda() output = aot_encdec(input_x.cuda()) assert output.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_aotgan/test_aot_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from os.path import dirname, join import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.models import AOTEncoderDecoder from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules def test_aot_inpaintor(): register_all_modules() config_file = join(dirname(__file__), '../../..', 'configs', 'aot_test.py') cfg = Config.fromfile(config_file) inpaintor = MODELS.build(cfg.model) # optimizer optim_g = torch.optim.Adam( inpaintor.generator.parameters(), lr=0.0001, betas=(0.0, 0.9)) optim_d = torch.optim.Adam( inpaintor.disc.parameters(), lr=0.0001, betas=(0.0, 0.9)) optims = dict(generator=OptimWrapper(optim_g), disc=OptimWrapper(optim_d)) # test attributes assert inpaintor.__class__.__name__ == 'AOTInpaintor' assert isinstance(inpaintor.generator, AOTEncoderDecoder) assert inpaintor.with_l1_valid_loss assert inpaintor.with_composed_percep_loss assert inpaintor.with_out_percep_loss assert inpaintor.with_gan assert inpaintor.is_train assert inpaintor.train_cfg['disc_step'] == 1 assert inpaintor.disc_step_count == 0 if torch.cuda.is_available(): inpaintor = inpaintor.cuda() gt_img = torch.randn(3, 64, 64) mask = torch.zeros((1, 64, 64)) mask[..., 12:45, 14:42] = 1. masked_img = gt_img.unsqueeze(0) * (1. - mask) + mask mask_bbox = [25, 25, 27, 27] data_batch = { 'inputs': masked_img, 'data_samples': [DataSample( mask=mask, mask_bbox=mask_bbox, gt_img=gt_img, )] } # check train_step for i in range(5): log_vars = inpaintor.train_step(data_batch, optims) assert 'loss_l1_valid' in log_vars assert 'loss_out_percep' in log_vars assert 'disc_losses' in log_vars assert 'loss_g_fake' in log_vars # # check forward_test data = inpaintor.data_preprocessor(data_batch, True) data_inputs, data_sample = data['inputs'], data['data_samples'] output = inpaintor.forward_test(data_inputs, data_sample) prediction = output assert 'fake_res' in prediction assert 'fake_img' in prediction assert 'pred_img' in prediction assert prediction.pred_img.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_aotgan/test_aot_neck.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import AOTBlockNeck def test_aot_dilation_neck(): neck = AOTBlockNeck( in_channels=32, dilation_rates=(1, 2, 4, 8), num_aotblock=4) x = torch.rand((2, 32, 64, 64)) res = neck(x) assert res.shape == (2, 32, 64, 64) if torch.cuda.is_available(): neck = AOTBlockNeck( in_channels=32, dilation_rates=(1, 2, 4, 8), num_aotblock=4).cuda() x = torch.rand((2, 32, 64, 64)).cuda() res = neck(x) assert res.shape == (2, 32, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_arcface/test_arcface_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.arcface.arcface_modules import get_blocks @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_get_blocks(): blocks = get_blocks(num_layers=100) assert len(blocks) == 4 blocks = get_blocks(num_layers=152) assert len(blocks) == 4 with pytest.raises(ValueError): get_blocks(num_layers=1000) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_arcface/test_id_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models import IDLossModel class TestArcFace: @classmethod def setup_class(cls): cls.default_cfg = dict( input_size=224, num_layers=50, mode='ir', drop_ratio=0.4, affine=True) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_arcface_cpu(self): # test loss model id_loss_model = IDLossModel() x1 = torch.randn((2, 3, 224, 224)) x2 = torch.randn((2, 3, 224, 224)) y, _ = id_loss_model(pred=x1, gt=x2) assert y >= 0 @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_arcface_cuda(self): # test loss model id_loss_model = IDLossModel().cuda() x1 = torch.randn((2, 3, 224, 224)).cuda() x2 = torch.randn((2, 3, 224, 224)).cuda() y, _ = id_loss_model(pred=x1, gt=x2) assert y >= 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_arcface/test_model_irse.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.arcface.model_irse import Backbone class TestIRSEModel: @classmethod def setup_class(cls): cls.default_cfg = dict( input_size=224, num_layers=50, mode='ir', drop_ratio=0.4, affine=True) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_arcface_cpu(self): model = Backbone(**self.default_cfg) x = torch.randn((2, 3, 224, 224)) y = model(x) assert y.shape == (2, 512) # test different input size cfg = deepcopy(self.default_cfg) cfg.update(dict(input_size=112)) model = Backbone(**cfg) x = torch.randn((2, 3, 112, 112)) y = model(x) assert y.shape == (2, 512) # test different num_layers cfg = deepcopy(self.default_cfg) cfg.update(dict(num_layers=50)) model = Backbone(**cfg) x = torch.randn((2, 3, 224, 224)) y = model(x) assert y.shape == (2, 512) # test different mode cfg = deepcopy(self.default_cfg) cfg.update(dict(mode='ir_se')) model = Backbone(**cfg) x = torch.randn((2, 3, 224, 224)) y = model(x) assert y.shape == (2, 512) # test different drop ratio cfg = deepcopy(self.default_cfg) cfg.update(dict(drop_ratio=0.8)) model = Backbone(**cfg) x = torch.randn((2, 3, 224, 224)) y = model(x) assert y.shape == (2, 512) # test affine=False cfg = deepcopy(self.default_cfg) cfg.update(dict(affine=False)) model = Backbone(**cfg) x = torch.randn((2, 3, 224, 224)) y = model(x) assert y.shape == (2, 512) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_arcface_cuda(self): model = Backbone(**self.default_cfg).cuda() x = torch.randn((2, 3, 224, 224)).cuda() y = model(x) assert y.shape == (2, 512) # test different input size cfg = deepcopy(self.default_cfg) cfg.update(dict(input_size=112)) model = Backbone(**cfg).cuda() x = torch.randn((2, 3, 112, 112)).cuda() y = model(x) assert y.shape == (2, 512) # test different num_layers cfg = deepcopy(self.default_cfg) cfg.update(dict(num_layers=50)) model = Backbone(**cfg).cuda() x = torch.randn((2, 3, 224, 224)).cuda() y = model(x) assert y.shape == (2, 512) # test different mode cfg = deepcopy(self.default_cfg) cfg.update(dict(mode='ir_se')) model = Backbone(**cfg).cuda() x = torch.randn((2, 3, 224, 224)).cuda() y = model(x) assert y.shape == (2, 512) # test different drop ratio cfg = deepcopy(self.default_cfg) cfg.update(dict(drop_ratio=0.8)) model = Backbone(**cfg).cuda() x = torch.randn((2, 3, 224, 224)).cuda() y = model(x) assert y.shape == (2, 512) # test affine=False cfg = deepcopy(self.default_cfg) cfg.update(dict(affine=False)) model = Backbone(**cfg).cuda() x = torch.randn((2, 3, 224, 224)).cuda() y = model(x) assert y.shape == (2, 512) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_basicvsr/test_basicvsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import BasicVSR, BasicVSRNet, DataPreprocessor from mmagic.models.losses import CharbonnierLoss from mmagic.structures import DataSample def test_basicvsr(): model = BasicVSR( generator=dict( type='BasicVSRNet', mid_channels=8, num_blocks=1, spynet_pretrained=None), pixel_loss=dict( type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=1), ensemble=None, data_preprocessor=DataPreprocessor()) assert isinstance(model, BasicVSR) assert isinstance(model.generator, BasicVSRNet) assert isinstance(model.pixel_loss, CharbonnierLoss) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # prepare data inputs = torch.rand(5, 3, 16, 16) target = torch.rand(5, 3, 64, 64) data_sample = DataSample(gt_img=target) data = dict(inputs=[inputs], data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert model.generator.spynet.basic_module[0].basic_module[ 0].conv.weight.requires_grad is False assert isinstance(log_vars, dict) log_vars = model.train_step(data, optim_wrapper) assert model.generator.spynet.basic_module[0].basic_module[ 0].conv.weight.requires_grad is True assert isinstance(log_vars, dict) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (5, 3, 64, 64) data['data_samples'][0].gt_img.data = torch.rand(3, 64, 64) output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 64, 64) model = BasicVSR( generator=dict( type='BasicVSRNet', mid_channels=8, num_blocks=1, spynet_pretrained=None), pixel_loss=dict( type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=1), ensemble=dict(type='SpatialTemporalEnsemble'), data_preprocessor=DataPreprocessor()) with pytest.raises(NotImplementedError): model = BasicVSR( generator=dict( type='BasicVSRNet', mid_channels=8, num_blocks=1, spynet_pretrained=None), pixel_loss=dict( type='CharbonnierLoss', loss_weight=1.0, reduction='mean'), train_cfg=dict(fix_iter=1), ensemble=dict(type=''), data_preprocessor=DataPreprocessor()) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_basicvsr/test_basicvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import BasicVSRNet def test_basicvsr_net(): """Test BasicVSR.""" # cpu basicvsr = BasicVSRNet( mid_channels=8, num_blocks=1, spynet_pretrained=None) input_tensor = torch.rand(1, 5, 3, 64, 64) basicvsr(input_tensor) assert not basicvsr._raised_warning input_tensor = torch.rand(1, 5, 3, 16, 16) output = basicvsr(input_tensor) assert output.shape == (1, 5, 3, 64, 64) assert basicvsr._raised_warning # gpu if torch.cuda.is_available(): basicvsr = BasicVSRNet( mid_channels=8, num_blocks=1, spynet_pretrained=None).cuda() input_tensor = torch.rand(1, 5, 3, 16, 16).cuda() output = basicvsr(input_tensor) assert output.shape == (1, 5, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_basicvsr_plusplus_net/test_basicvsr_plusplus_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import BasicVSRPlusPlusNet @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_basicvsr_plusplus_cpu(): """Test BasicVSR++.""" # cpu model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained=None, cpu_cache_length=100) input_tensor = torch.rand(1, 5, 3, 64, 64) output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) # with cpu_cache (no effect on cpu) model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained=None, cpu_cache_length=3) output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) with pytest.raises(AssertionError): # The height and width of inputs should be at least 64 input_tensor = torch.rand(1, 5, 3, 61, 61) model(input_tensor) # output has the same size as input model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=False, spynet_pretrained=None, cpu_cache_length=100) input_tensor = torch.rand(1, 5, 3, 256, 256) output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_basicvsr_plusplus_cuda(): # gpu if torch.cuda.is_available(): model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained=None, cpu_cache_length=100).cuda() input_tensor = torch.rand(1, 5, 3, 64, 64).cuda() output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) # with cpu_cache model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=True, spynet_pretrained=None, cpu_cache_length=3).cuda() output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) with pytest.raises(AssertionError): # The height and width of inputs should be at least 64 input_tensor = torch.rand(1, 5, 3, 61, 61).cuda() model(input_tensor) # output has the same size as input model = BasicVSRPlusPlusNet( mid_channels=64, num_blocks=7, is_low_res_input=False, spynet_pretrained=None, cpu_cache_length=100).cuda() input_tensor = torch.rand(1, 5, 3, 256, 256).cuda() output = model(input_tensor) assert output.shape == (1, 5, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import BigGAN, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='BigGANGenerator', output_scale=32, noise_size=128, num_classes=10, base_channels=64, with_shared_embedding=False, sn_eps=1e-8, sn_style='torch', # init_type='N02', split_noise=False, auto_sync_bn=False, init_cfg=dict(type='N02')) discriminator = dict( type='BigGANDiscriminator', input_scale=32, num_classes=10, base_channels=64, sn_eps=1e-8, sn_style='torch', # init_type='N02', with_spectral_norm=True, init_cfg=dict(type='N02')) class TestBigGAN(TestCase): def test_init(self): gan = BigGAN( num_classes=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator, generator_steps=1, discriminator_steps=4) gan.init_weights() self.assertIsInstance(gan, BigGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = BigGAN( noise_size=10, generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = BigGAN( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = BigGAN(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) # test init with different num_classes gan = BigGAN( num_classes=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator, generator_steps=1, discriminator_steps=4) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('mmgen') gan = BigGAN( generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) gan.init_weights() # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) label = torch.randint(0, 10, (3, 1)) data_sample = DataSample(gt_img=img) data_sample.set_gt_label(label) data = dict(inputs=dict(), data_samples=[data_sample]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_deep_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch from mmagic.models.editors.biggan import BigGANDeepDiscriminator from mmagic.registry import MODELS class TestBigGANDeepDiscriminator(object): @classmethod def setup_class(cls): num_classes = 1000 cls.default_config = dict( type='BigGANDeepDiscriminator', input_scale=128, num_classes=num_classes, base_channels=8) cls.x = torch.randn((2, 3, 128, 128)) cls.label = torch.randint(0, num_classes, (2, )) def test_biggan_deep_discriminator(self): # test default settings d = MODELS.build(self.default_config) assert isinstance(d, BigGANDeepDiscriminator) y = d(self.x, self.label) assert y.shape == (2, 1) # test different init types cfg = deepcopy(self.default_config) cfg.update(dict(init_type='N02')) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_type='xavier')) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0)) d = MODELS.build(cfg) y = d(self.x, None) assert y.shape == (2, 1) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_deep_discriminator_cuda(self): # test default settings d = MODELS.build(self.default_config).cuda() assert isinstance(d, BigGANDeepDiscriminator) y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) # test different init types cfg = deepcopy(self.default_config) cfg.update(dict(init_type='N02')) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_type='xavier')) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0)) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), None) assert y.shape == (2, 1) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_deep_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from functools import partial import pytest import torch # yapf:disable from mmagic.models.editors.biggan import BigGANDeepGenerator from mmagic.registry import MODELS # yapf:enable class TestBigGANDeepGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((3, 120)) num_classes = 1000 cls.label = torch.randint(0, num_classes, (3, )) cls.default_config = dict( type='BigGANDeepGenerator', output_scale=128, num_classes=num_classes, base_channels=4) def test_biggan_deep_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, BigGANDeepGenerator) res = g(self.noise, self.label) assert res.shape == (3, 3, 128, 128) # test 'return_noise' res = g(self.noise, self.label, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) res = g(None, None, num_batches=3, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) # test callable noise = torch.randn label = partial(torch.randint, 0, 1000) res = g(noise, label, num_batches=2) assert res.shape == (2, 3, 128, 128) # test different output scale cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=256)) g = MODELS.build(cfg) noise = torch.randn((3, 120)) res = g(noise, self.label) assert res.shape == (3, 3, 256, 256) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 256, 256) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=512)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 512, 512) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=64)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 64, 64) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=32)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 32, 32) # test with `concat_noise=False` cfg = deepcopy(self.default_config) cfg.update(dict(concat_noise=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test different num_classes cfg = deepcopy(self.default_config) cfg.update( dict( num_classes=0, with_shared_embedding=False, concat_noise=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test no shared embedding cfg = deepcopy(self.default_config) cfg.update(dict(with_shared_embedding=False, concat_noise=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) g = MODELS.build(cfg) res = g(self.noise, self.label) assert res.shape == (3, 3, 128, 128) # test init --> N02 cfg = deepcopy(self.default_config) cfg.update(init_type='N02') g = MODELS.build(cfg) # test init --> xavier cfg = deepcopy(self.default_config) cfg.update(init_type='xavier') g = MODELS.build(cfg) # test init --> raise error cfg = deepcopy(self.default_config) cfg.update(init_type='dont know') with pytest.raises(NotImplementedError): g = MODELS.build(cfg) cfg = deepcopy(self.default_config) cfg.update(pretrained=1234) with pytest.raises(TypeError): g = MODELS.build(cfg) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_deep_generator_cuda(self): # test default setting with builder g = MODELS.build(self.default_config).cuda() assert isinstance(g, BigGANDeepGenerator) res = g(self.noise.cuda(), self.label.cuda()) assert res.shape == (3, 3, 128, 128) # test 'return_noise' res = g(self.noise.cuda(), self.label.cuda(), return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) res = g(None, None, num_batches=3, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) # test callable noise = torch.randn label = partial(torch.randint, 0, 1000) res = g(noise, label, num_batches=2) assert res.shape == (2, 3, 128, 128) # test different output scale cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=256)) g = MODELS.build(cfg).cuda() noise = torch.randn((3, 120)) res = g(noise.cuda(), self.label.cuda()) assert res.shape == (3, 3, 256, 256) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 256, 256) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=512)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 512, 512) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=64)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 64, 64) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=32)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 32, 32) # test with `concat_noise=False` cfg = deepcopy(self.default_config) cfg.update(dict(concat_noise=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test different num_classes cfg = deepcopy(self.default_config) cfg.update( dict( num_classes=0, with_shared_embedding=False, concat_noise=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test no shared embedding cfg = deepcopy(self.default_config) cfg.update(dict(with_shared_embedding=False, concat_noise=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch from mmagic.models.editors.biggan import BigGANDiscriminator from mmagic.registry import MODELS class TestBigGANDiscriminator(object): @classmethod def setup_class(cls): num_classes = 1000 cls.default_config = dict( type='BigGANDiscriminator', input_scale=128, num_classes=num_classes, base_channels=8) cls.x = torch.randn((2, 3, 128, 128)) cls.label = torch.randint(0, num_classes, (2, )) def test_biggan_discriminator(self): # test default settings d = MODELS.build(self.default_config) assert isinstance(d, BigGANDiscriminator) y = d(self.x, self.label) assert y.shape == (2, 1) # test different init types cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='N02'))) d = MODELS.build(cfg) d.init_weights() y = d(self.x, self.label) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='xavier'))) d = MODELS.build(cfg) d.init_weights() y = d(self.x, self.label) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='ortho'))) g = MODELS.build(cfg) g.init_weights() y = d(self.x, self.label) assert y.shape == (2, 1) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0)) d = MODELS.build(cfg) y = d(self.x, None) assert y.shape == (2, 1) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) d = MODELS.build(cfg) y = d(self.x, self.label) assert y.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_discriminator_cuda(self): # test default settings d = MODELS.build(self.default_config).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) # test different init types cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='N02'))) d = MODELS.build(cfg).cuda() d.init_weights() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='xavier'))) d = MODELS.build(cfg).cuda() d.init_weights() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='ortho'))) g = MODELS.build(cfg) g.init_weights() y = d(self.x, self.label) assert y.shape == (2, 1) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0)) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), None) assert y.shape == (2, 1) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) d = MODELS.build(cfg).cuda() y = d(self.x.cuda(), self.label.cuda()) assert y.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from functools import partial import pytest import torch # yapf:disable from mmagic.models.editors.biggan import BigGANGenerator from mmagic.registry import MODELS # yapf:enable class TestBigGANGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((3, 120)) num_classes = 1000 cls.label = torch.randint(0, num_classes, (3, )) cls.default_config = dict( type='BigGANGenerator', output_scale=128, num_classes=num_classes, base_channels=4) def test_biggan_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, BigGANGenerator) res = g(self.noise, self.label) assert res.shape == (3, 3, 128, 128) # test 'return_noise' res = g(self.noise, self.label, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) res = g(None, None, num_batches=3, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) # test callable noise = torch.randn label = partial(torch.randint, 0, 1000) res = g(noise, label, num_batches=2) assert res.shape == (2, 3, 128, 128) # test different output scale cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=256)) g = MODELS.build(cfg) noise = torch.randn((3, 119)) res = g(noise, self.label) assert res.shape == (3, 3, 256, 256) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 256, 256) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=512)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 512, 512) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=64)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 64, 64) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=32)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 32, 32) # test with `split_noise=False` cfg = deepcopy(self.default_config) cfg.update(dict(split_noise=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0, with_shared_embedding=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test no shared embedding cfg = deepcopy(self.default_config) cfg.update(dict(with_shared_embedding=False, split_noise=False)) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test init --> ortho cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='ortho'))) g = MODELS.build(cfg) g.init_weights() # test init --> N02 cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='N02'))) g = MODELS.build(cfg) g.init_weights() # test init --> xavier cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='xavier'))) g = MODELS.build(cfg) g.init_weights() # test init --> raise error cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='dont know'))) with pytest.raises(NotImplementedError): g = MODELS.build(cfg) g.init_weights() @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_generator_cuda(self): # test default setting with builder g = MODELS.build(self.default_config).cuda() assert isinstance(g, BigGANGenerator) res = g(self.noise.cuda(), self.label.cuda()) assert res.shape == (3, 3, 128, 128) # test 'return_noise' res = g(self.noise.cuda(), self.label.cuda(), return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) res = g(None, None, num_batches=3, return_noise=True) assert res['fake_img'].shape == (3, 3, 128, 128) assert res['noise_batch'].shape == (3, 120) assert res['label'].shape == (3, ) # test callable noise = torch.randn label = partial(torch.randint, 0, 1000) res = g(noise, label, num_batches=2) assert res.shape == (2, 3, 128, 128) # test different output scale cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=256)) g = MODELS.build(cfg).cuda() noise = torch.randn((3, 119)).cuda() res = g(noise, self.label.cuda()) assert res.shape == (3, 3, 256, 256) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 256, 256) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=512)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 512, 512) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=64)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 64, 64) cfg = deepcopy(self.default_config) cfg.update(dict(output_scale=32)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 32, 32) # test with `split_noise=False` cfg = deepcopy(self.default_config) cfg.update(dict(split_noise=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test with `with_spectral_norm=False` cfg = deepcopy(self.default_config) cfg.update(dict(with_spectral_norm=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test different num_classes cfg = deepcopy(self.default_config) cfg.update(dict(num_classes=0, with_shared_embedding=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test no shared embedding cfg = deepcopy(self.default_config) cfg.update(dict(with_shared_embedding=False, split_noise=False)) g = MODELS.build(cfg).cuda() res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test torch-sn cfg = deepcopy(self.default_config) cfg.update(dict(sn_style='torch')) g = MODELS.build(cfg) res = g(None, None, num_batches=3) assert res.shape == (3, 3, 128, 128) # test init --> ortho cfg = deepcopy(self.default_config) cfg.update(dict(init_cfg=dict(type='ortho'))) g = MODELS.build(cfg) g.init_weights() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch # yapf:disable from mmagic.models.editors.biggan import (BigGANConditionBN, BigGANDeepDiscResBlock, BigGANDeepGenResBlock, BigGANDiscResBlock, BigGANGenResBlock, SelfAttentionBlock) from mmagic.registry import MODELS # yapf:enable class TestBigGANDeepGenResBlock: @classmethod def setup_class(cls): cls.default_cfg = dict( type='BigGANDeepGenResBlock', in_channels=32, out_channels=16, dim_after_concat=100, act_cfg=dict(type='ReLU'), upsample_cfg=dict(type='nearest', scale_factor=2), sn_eps=1e-6, bn_eps=1e-5, with_spectral_norm=True, input_is_label=False, auto_sync_bn=True, channel_ratio=4) cls.x = torch.randn(2, 32, 8, 8) cls.y = torch.randn(2, 100) cls.label = torch.randint(0, 100, (2, )) def test_biggan_deep_gen_res_block(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, BigGANDeepGenResBlock) out = module(self.x, self.y) assert out.shape == (2, 16, 16, 16) # test without upsample cfg = deepcopy(self.default_cfg) cfg.update(dict(upsample_cfg=None)) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 16, 8, 8) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg) out = module(self.x, self.label) assert out.shape == (2, 16, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 16, 16, 16) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_deep_gen_res_block_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, BigGANDeepGenResBlock) out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 16, 16) # test without upsample cfg = deepcopy(self.default_cfg) cfg.update(dict(upsample_cfg=None)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 8, 8) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.label.cuda()) assert out.shape == (2, 16, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 16, 16) class TestBigGANDeepDiscResBlock: @classmethod def setup_class(cls): cls.default_cfg = dict( type='BigGANDeepDiscResBlock', in_channels=32, out_channels=64, channel_ratio=4, act_cfg=dict(type='ReLU', inplace=False), sn_eps=1e-6, with_downsample=True, with_spectral_norm=True) cls.x = torch.randn(2, 32, 16, 16) def test_biggan_deep_disc_res_block(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, BigGANDeepDiscResBlock) out = module(self.x) assert out.shape == (2, 64, 8, 8) # test with_downsample cfg = deepcopy(self.default_cfg) cfg.update(dict(with_downsample=False)) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 16, 16) # test different channel_ratio cfg = deepcopy(self.default_cfg) cfg.update(dict(channel_ratio=8)) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 8, 8) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 8, 8) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_deep_disc_res_block_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, BigGANDeepDiscResBlock) out = module(self.x.cuda()) assert out.shape == (2, 64, 8, 8) # test with_downsample cfg = deepcopy(self.default_cfg) cfg.update(dict(with_downsample=False)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda()) assert out.shape == (2, 64, 16, 16) # test different channel_ratio cfg = deepcopy(self.default_cfg) cfg.update(dict(channel_ratio=8)) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 8, 8) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda()) assert out.shape == (2, 64, 8, 8) class TestBigGANConditionBN: @classmethod def setup_class(cls): cls.default_cfg = dict( type='BigGANConditionBN', num_features=64, linear_input_channels=80) cls.x = torch.randn(2, 64, 32, 32) cls.y = torch.randn(2, 80) cls.label = torch.randint(0, 80, (2, )) def test_biggan_condition_bn(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, BigGANConditionBN) out = module(self.x, self.y) assert out.shape == (2, 64, 32, 32) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg) out = module(self.x, self.label) assert out.shape == (2, 64, 32, 32) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 64, 32, 32) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 64, 32, 32) # test not-implemented sn-style with pytest.raises(NotImplementedError): cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='tero')) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 64, 32, 32) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_condition_bn_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, BigGANConditionBN) out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 64, 32, 32) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.label.cuda()) assert out.shape == (2, 64, 32, 32) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 64, 32, 32) # test not-implemented sn-style with pytest.raises(NotImplementedError): cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='tero')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 64, 32, 32) class TestSelfAttentionBlock: @classmethod def setup_class(cls): cls.default_cfg = dict(type='SelfAttentionBlock', in_channels=16) cls.x = torch.randn(2, 16, 8, 8) def test_self_attention_block(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, SelfAttentionBlock) out = module(self.x) assert out.shape == (2, 16, 8, 8) # test different in_channels cfg = deepcopy(self.default_cfg) cfg.update(dict(in_channels=10)) module = MODELS.build(cfg) x = torch.randn(2, 10, 8, 8) out = module(x) assert out.shape == (2, 10, 8, 8) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 16, 8, 8) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_self_attention_block_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, SelfAttentionBlock) out = module(self.x.cuda()) assert out.shape == (2, 16, 8, 8) # test different in_channels cfg = deepcopy(self.default_cfg) cfg.update(dict(in_channels=10)) module = MODELS.build(cfg).cuda() x = torch.randn(2, 10, 8, 8).cuda() out = module(x) assert out.shape == (2, 10, 8, 8) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda()) assert out.shape == (2, 16, 8, 8) class TestBigGANGenResBlock: @classmethod def setup_class(cls): cls.default_cfg = dict( type='BigGANGenResBlock', in_channels=32, out_channels=16, dim_after_concat=100, act_cfg=dict(type='ReLU'), upsample_cfg=dict(type='nearest', scale_factor=2), sn_eps=1e-6, with_spectral_norm=True, input_is_label=False, auto_sync_bn=True) cls.x = torch.randn(2, 32, 8, 8) cls.y = torch.randn(2, 100) cls.label = torch.randint(0, 100, (2, )) def test_biggan_gen_res_block(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, BigGANGenResBlock) out = module(self.x, self.y) assert out.shape == (2, 16, 16, 16) # test without upsample cfg = deepcopy(self.default_cfg) cfg.update(dict(upsample_cfg=None)) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 16, 8, 8) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg) out = module(self.x, self.label) assert out.shape == (2, 16, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x, self.y) assert out.shape == (2, 16, 16, 16) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_gen_res_block_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, BigGANGenResBlock) out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 16, 16) # test without upsample cfg = deepcopy(self.default_cfg) cfg.update(dict(upsample_cfg=None)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 8, 8) # test input_is_label cfg = deepcopy(self.default_cfg) cfg.update(dict(input_is_label=True)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.label.cuda()) assert out.shape == (2, 16, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda(), self.y.cuda()) assert out.shape == (2, 16, 16, 16) class TestBigGANDiscResBlock: @classmethod def setup_class(cls): cls.default_cfg = dict( type='BigGANDiscResBlock', in_channels=32, out_channels=64, act_cfg=dict(type='ReLU', inplace=False), sn_eps=1e-6, with_downsample=True, with_spectral_norm=True, is_head_block=False) cls.x = torch.randn(2, 32, 16, 16) def test_biggan_disc_res_block(self): # test default setting module = MODELS.build(self.default_cfg) assert isinstance(module, BigGANDiscResBlock) out = module(self.x) assert out.shape == (2, 64, 8, 8) # test with_downsample cfg = deepcopy(self.default_cfg) cfg.update(dict(with_downsample=False)) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg) out = module(self.x) assert out.shape == (2, 64, 8, 8) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_biggan_disc_res_block_cuda(self): # test default setting module = MODELS.build(self.default_cfg).cuda() assert isinstance(module, BigGANDiscResBlock) out = module(self.x.cuda()) assert out.shape == (2, 64, 8, 8) # test with_downsample cfg = deepcopy(self.default_cfg) cfg.update(dict(with_downsample=False)) module = MODELS.build(cfg).cuda() out = module(self.x.cuda()) assert out.shape == (2, 64, 16, 16) # test torch-sn cfg = deepcopy(self.default_cfg) cfg.update(dict(sn_style='torch')) module = MODELS.build(cfg).cuda() out = module(self.x.cuda()) assert out.shape == (2, 64, 8, 8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_biggan/test_biggan_snmodule.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch import torch.nn as nn from mmagic.models.editors.biggan.biggan_snmodule import SpectralNorm class MyBlock(nn.Module): def __init__(self, num_channels): super().__init__() self.weight = nn.Parameter(torch.randn(num_channels)) def forward(self, x): return x + self.weight class MySNBlock(MyBlock, SpectralNorm): def __init__(self, num_channels): MyBlock.__init__(self, num_channels) SpectralNorm.__init__( self, num_svs=2, num_iters=2, num_outputs=num_channels) def forward(self, x): return x + self.sn_weight() # test Spectral Norm with my own layer def test_SpectralNorm(): sn_block = MySNBlock(num_channels=4) x = torch.randn(1, 4) out = sn_block(x) assert out.shape == (1, 4) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_cain/test_cain.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import DataPreprocessor from mmagic.models.editors import CAIN, CAINNet from mmagic.models.losses import L1Loss from mmagic.registry import MODELS from mmagic.structures import DataSample @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_cain_net_cpu(): model_cfg = dict(type='CAINNet') # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'CAINNet' # prepare data inputs0 = torch.rand(1, 2, 3, 5, 5) inputs = torch.rand(1, 2, 3, 256, 248) target = torch.rand(1, 3, 256, 248) # test on cpu output = model(inputs) output = model(inputs, padding_flag=True) model(inputs0, padding_flag=True) assert torch.is_tensor(output) assert output.shape == target.shape with pytest.raises(AssertionError): output = model(inputs[:, :1]) model_cfg = dict(type='CAINNet', norm='in') model = MODELS.build(model_cfg) model(inputs) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg) model(inputs) with pytest.raises(ValueError): model_cfg = dict(type='CAINNet', norm='lys') MODELS.build(model_cfg) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_cain_net_cuda(): # prepare data inputs0 = torch.rand(1, 2, 3, 5, 5) target0 = torch.rand(1, 3, 5, 5) inputs = torch.rand(1, 2, 3, 256, 248) target = torch.rand(1, 3, 256, 248) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg) # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() target = target.cuda() output = model(inputs) output = model(inputs, True) assert torch.is_tensor(output) assert output.shape == target.shape inputs0 = inputs0.cuda() target0 = target0.cuda() model(inputs0, padding_flag=True) model_cfg = dict(type='CAINNet', norm='in') model = MODELS.build(model_cfg).cuda() model(inputs) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg).cuda() model(inputs) with pytest.raises(ValueError): model_cfg = dict(type='CAINNet', norm='lys') MODELS.build(model_cfg).cuda() @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_cain(): # build model model = CAIN( generator=dict(type='CAINNet'), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=DataPreprocessor(pad_mode='reflect')) # test attributes assert isinstance(model, CAIN) assert isinstance(model.data_preprocessor, DataPreprocessor) assert isinstance(model.generator, CAINNet) assert isinstance(model.pixel_loss, L1Loss) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # prepare data inputs = torch.rand(2, 3, 32, 32) target = torch.rand(3, 32, 32) data_sample = DataSample(gt_img=target) data = dict(inputs=[inputs], data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars['loss'], torch.Tensor) # val output = model.val_step(data) assert output[0].output.pred_img.data.shape == (3, 32, 32) # feat output = model(torch.rand(1, 2, 3, 32, 32), mode='tensor') assert output.shape == (1, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_cain/test_cain_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_cain_net_cpu(): model_cfg = dict(type='CAINNet') # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'CAINNet' # prepare data inputs0 = torch.rand(1, 2, 3, 5, 5) inputs = torch.rand(1, 2, 3, 256, 248) target = torch.rand(1, 3, 256, 248) # test on cpu output = model(inputs) output = model(inputs, padding_flag=True) model(inputs0, padding_flag=True) assert torch.is_tensor(output) assert output.shape == target.shape with pytest.raises(AssertionError): output = model(inputs[:, :1]) model_cfg = dict(type='CAINNet', norm='in') model = MODELS.build(model_cfg) model(inputs) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg) model(inputs) with pytest.raises(ValueError): model_cfg = dict(type='CAINNet', norm='lys') MODELS.build(model_cfg) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_cain_net_cuda(): # prepare data inputs0 = torch.rand(1, 2, 3, 5, 5) target0 = torch.rand(1, 3, 5, 5) inputs = torch.rand(1, 2, 3, 256, 248) target = torch.rand(1, 3, 256, 248) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg) # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() target = target.cuda() output = model(inputs) output = model(inputs, True) assert torch.is_tensor(output) assert output.shape == target.shape inputs0 = inputs0.cuda() target0 = target0.cuda() model(inputs0, padding_flag=True) model_cfg = dict(type='CAINNet', norm='in') model = MODELS.build(model_cfg).cuda() model(inputs) model_cfg = dict(type='CAINNet', norm='bn') model = MODELS.build(model_cfg).cuda() model(inputs) with pytest.raises(ValueError): model_cfg = dict(type='CAINNet', norm='lys') MODELS.build(model_cfg).cuda() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_controlnet/test_controlnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import platform from unittest import TestCase from unittest.mock import MagicMock import pytest import torch import torch.nn as nn from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules test_dir = osp.join(osp.dirname(__file__), '../../../..', 'tests') config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') model_path = osp.join(test_dir, 'configs', 'tmp_weight') ckpt_path = osp.join(test_dir, 'configs', 'ckpt') register_all_modules() stable_diffusion_tiny_url = 'hf-internal-testing/tiny-stable-diffusion-pipe' config = dict( type='ControlStableDiffusion', vae=dict(type='AutoencoderKL', sample_size=64), unet=dict( sample_size=64, type='UNet2DConditionModel', down_block_types=('DownBlock2D', ), up_block_types=('UpBlock2D', ), block_out_channels=(32, ), cross_attention_dim=16, ), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_tiny_url, subfolder='text_encoder'), tokenizer=stable_diffusion_tiny_url, controlnet=dict( type='ControlNetModel', # from_pretrained=controlnet_canny_rul from_config=config_path # train from scratch ), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), data_preprocessor=dict(type='DataPreprocessor'), enable_xformers=False, init_cfg=dict(type='init_from_unet')) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestControlStableDiffusion(TestCase): def setUp(self): # mock SiLU if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): from mmagic.models.editors.ddpm.denoising_unet import SiLU torch.nn.SiLU = SiLU control_sd = MODELS.build(config) assert not any([p.requires_grad for p in control_sd.vae.parameters()]) assert not any( [p.requires_grad for p in control_sd.text_encoder.parameters()]) assert not any([p.requires_grad for p in control_sd.unet.parameters()]) self.control_sd = control_sd def test_init_weights(self): control_sd = self.control_sd # test init_from_unet control_sd.init_weights() # test init_convert_from_unet unet = dict( type='UNet2DConditionModel', down_block_types=('DownBlock2D', ), up_block_types=('UpBlock2D', ), block_out_channels=(32, ), cross_attention_dim=16) control_sd.init_cfg = dict(type='convert_from_unet', base_model=unet) control_sd.init_weights() def test_infer(self): control_sd = self.control_sd def mock_encode_prompt(prompt, do_classifier_free_guidance, num_images_per_prompt, *args, **kwargs): batch_size = len(prompt) if isinstance(prompt, list) else 1 batch_size *= num_images_per_prompt if do_classifier_free_guidance: batch_size *= 2 return torch.randn(batch_size, 5, 16) # 2 for cfg encode_prompt = control_sd._encode_prompt control_sd._encode_prompt = mock_encode_prompt # one prompt, one control, repeat 1 time self._test_infer(control_sd, 1, 1, 1, 1) # two prompt, two control, repeat 1 time # NOTE: skip this due to memory limit # self._test_infer(control_sd, 2, 2, 1, 2) # one prompt, one control, repeat 2 times # NOTE: skip this due to memory limit # self._test_infer(control_sd, 1, 1, 2, 2) # two prompt, two control, repeat 2 times # NOTE: skip this due to memory limit # self._test_infer(control_sd, 2, 2, 2, 4) control_sd._encode_prompt = encode_prompt def _test_infer(self, control_sd, num_prompt, num_control, num_repeat, tar_shape): prompt = '' control = torch.ones([1, 3, 64, 64]) result = control_sd.infer( [prompt] * num_prompt, control=[control] * num_control, height=64, width=64, num_images_per_prompt=num_repeat, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (tar_shape, 3, 64, 64) def test_val_step(self): control_sd = self.control_sd data = dict( inputs=[ dict( target=torch.ones([3, 64, 64]), source=torch.ones([3, 64, 64])) ], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(*args, **kwargs): return dict(samples=torch.randn(2, 3, 64, 64)) encode_prompt = control_sd._encode_prompt control_sd._encode_prompt = mock_encode_prompt infer = control_sd.infer control_sd.infer = mock_infer # control_sd.text_encoder = mock_text_encoder() output = control_sd.val_step(data) assert len(output) == 1 control_sd._encode_prompt = encode_prompt control_sd.infer = infer def test_test_step(self): control_sd = self.control_sd data = dict( inputs=[ dict( target=torch.ones([3, 64, 64]), source=torch.ones([3, 64, 64])) ], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(*args, **kwargs): return dict(samples=torch.randn(2, 3, 64, 64)) encode_prompt = control_sd._encode_prompt control_sd._encode_prompt = mock_encode_prompt infer = control_sd.infer control_sd.infer = mock_infer # control_sd.text_encoder = mock_text_encoder() output = control_sd.test_step(data) assert len(output) == 1 control_sd._encode_prompt = encode_prompt control_sd.infer = infer def test_train_step(self): control_sd = self.control_sd data = dict( inputs=[ dict( target=torch.ones([3, 64, 64]), source=torch.ones([3, 64, 64])) ], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) optimizer = MagicMock() update_params = MagicMock() optimizer.update_params = update_params optim_wrapper = {'controlnet': optimizer} class mock_text_encoder(nn.Module): def __init__(self): super().__init__() def forward(self, *args, **kwargs): return [torch.randn(1, 5, 16)] control_sd.text_encoder = mock_text_encoder() control_sd.train_step(data, optim_wrapper) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import os.path as osp from unittest.mock import MagicMock import pytest import torch from mmagic.models.editors.controlnet.controlnet_utils import change_base_model def make_state_dict(d): new_d = dict() for k, v in d.items(): new_d[k] = torch.FloatTensor([v]) return new_d def check_state_dict(s1, s2): # s1, s2 = m1.state_dict(), m2.state_dict() assert s1.keys() == s2.keys() for k in s1.keys(): assert (s1[k] == s2[k]).all() def parameters(model): state_dict = model.state_dict() for v in state_dict.values(): yield v def test_change_base_model(): control_state_dict = make_state_dict(dict(k1=1, k2=2, k3=3)) target_control_state_dict = make_state_dict(dict(k1=1.5, k2=2.5, k3=3)) base_state_dict = make_state_dict(dict(k1=2, k2=3)) curr_state_dict = make_state_dict(dict(k1=2.5, k2=3.5)) controlnet = MagicMock() basemodel = MagicMock() currmodel = MagicMock() controlnet.parameters = MagicMock(return_value=parameters(controlnet)) basemodel.parameters = MagicMock(return_value=parameters(basemodel)) currmodel.parameters = MagicMock(return_value=parameters(currmodel)) controlnet.state_dict = MagicMock(return_value=control_state_dict) basemodel.state_dict = MagicMock(return_value=base_state_dict) currmodel.state_dict = MagicMock(return_value=curr_state_dict) change_base_model(controlnet, currmodel, basemodel) check_state_dict(controlnet.state_dict(), target_control_state_dict) # test save control_state_dict = make_state_dict(dict(k1=1, k2=2, k3=3)) controlnet.state_dict = MagicMock(return_value=control_state_dict) save_path = osp.abspath( osp.join(__file__, '../../../../data/out', 'test.pth')) change_base_model(controlnet, currmodel, basemodel, save_path=save_path) assert os.path.isfile(save_path) control_state_dict_loaded = torch.load(save_path) check_state_dict(control_state_dict_loaded, target_control_state_dict) os.remove(save_path) # test error wrong_base_state_dict = make_state_dict(dict(k1=2, k2=[3, 5])) wrong_model = MagicMock() wrong_model.state_dict = MagicMock(return_value=wrong_base_state_dict) with pytest.raises(Exception): change_base_model(controlnet, currmodel, wrong_model) # change_base_model(controlnet, currmodel, wrong_base_state_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_cyclegan/test_cyclegan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import sys import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmagic.models import CycleGAN, DataPreprocessor from mmagic.models.archs import PatchDiscriminator from mmagic.models.editors.cyclegan import ResnetGenerator from mmagic.structures import DataSample def obj_from_dict(info: dict, parent=None, default_args=None): """Initialize an object from dict. The dict must contain the key "type", which indicates the object type, it can be either a string or type, such as "list" or ``list``. Remaining fields are treated as the arguments for constructing the object. Args: info (dict): Object types and arguments. parent (:class:`module`): Module which may containing expected object classes. default_args (dict, optional): Default arguments for initializing the object. Returns: any type: Object built from the dict. """ assert isinstance(info, dict) and 'type' in info assert isinstance(default_args, dict) or default_args is None args = info.copy() obj_type = args.pop('type') # if mmcv.is_str(obj_type): if isinstance(obj_type, str): if parent is not None: obj_type = getattr(parent, obj_type) else: obj_type = sys.modules[obj_type] elif not isinstance(obj_type, type): raise TypeError('type must be a str or valid type, but ' f'got {type(obj_type)}') if default_args is not None: for name, value in default_args.items(): args.setdefault(name, value) return obj_type(**args) def test_cyclegan(): model_cfg = dict( default_domain='photo', reachable_domains=['photo', 'mask'], related_domains=['photo', 'mask'], generator=dict( type='ResnetGenerator', in_channels=3, out_channels=3, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=3, base_channels=64, num_conv=3, norm_cfg=dict(type='IN'), init_cfg=dict(type='normal', gain=0.02))) train_settings = None # build synthesizer synthesizer = CycleGAN(**model_cfg, data_preprocessor=DataPreprocessor()) # test attributes assert synthesizer.__class__.__name__ == 'CycleGAN' assert isinstance(synthesizer.generators['photo'], ResnetGenerator) assert isinstance(synthesizer.generators['mask'], ResnetGenerator) assert isinstance(synthesizer.discriminators['photo'], PatchDiscriminator) assert isinstance(synthesizer.discriminators['mask'], PatchDiscriminator) # prepare data inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) data_batch = {'img_mask': inputs, 'img_photo': targets} # prepare optimizer optim_cfg = dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)) optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict(params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) # test forward_test with torch.no_grad(): outputs = synthesizer(inputs, target_domain='photo', test_mode=True) assert torch.equal(outputs['source'], data_batch['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) with torch.no_grad(): outputs = synthesizer(targets, target_domain='mask', test_mode=True) assert torch.equal(outputs['source'], data_batch['img_photo']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) # test forward_train with torch.no_grad(): outputs = synthesizer(inputs, target_domain='photo', test_mode=True) assert torch.equal(outputs['source'], data_batch['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) with torch.no_grad(): outputs = synthesizer(targets, target_domain='mask', test_mode=True) assert torch.equal(outputs['source'], data_batch['img_photo']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) # test train_step message_hub = MessageHub.get_instance('cyclegan-test') message_hub.update_info('iter', 0) inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) data_batch = dict(inputs={'img_mask': inputs, 'img_photo': targets}) log_vars = synthesizer.train_step(data_batch, optimizer) assert isinstance(log_vars, dict) for v in [ 'loss_gan_d_mask', 'loss_gan_d_photo', 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ]: assert isinstance(log_vars[v].item(), float) # test train_step and forward_test (gpu) if torch.cuda.is_available(): synthesizer = synthesizer.cuda() optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) data_batch = {'img_mask': inputs, 'img_photo': targets} data_batch_cuda = copy.deepcopy(data_batch) data_batch_cuda['img_mask'] = inputs.cuda() data_batch_cuda['img_photo'] = targets.cuda() # forward_test with torch.no_grad(): outputs = synthesizer( data_batch_cuda['img_mask'], target_domain='photo', test_mode=True) assert torch.equal(outputs['source'].cpu(), data_batch_cuda['img_mask'].cpu()) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) with torch.no_grad(): outputs = synthesizer( data_batch_cuda['img_photo'], target_domain='mask', test_mode=True) assert torch.equal(outputs['source'].cpu(), data_batch_cuda['img_photo'].cpu()) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) # test forward_train with torch.no_grad(): outputs = synthesizer( data_batch_cuda['img_mask'], target_domain='photo', test_mode=False) assert torch.equal(outputs['source'], data_batch_cuda['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) with torch.no_grad(): outputs = synthesizer( data_batch_cuda['img_photo'], target_domain='mask', test_mode=False) assert torch.equal(outputs['source'], data_batch_cuda['img_photo']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 64, 64) # train_step inputs = torch.rand(1, 3, 64, 64).cuda() targets = torch.rand(1, 3, 64, 64).cuda() data_batch_cuda = dict(inputs={ 'img_mask': inputs, 'img_photo': targets }) log_vars = synthesizer.train_step(data_batch_cuda, optimizer) assert isinstance(log_vars, dict) for v in [ 'loss_gan_d_mask', 'loss_gan_d_photo', 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ]: assert isinstance(log_vars[v].item(), float) # test disc_steps and disc_init_steps train_settings = dict(discriminator_steps=2, disc_init_steps=2) synthesizer = CycleGAN( **model_cfg, **train_settings, data_preprocessor=DataPreprocessor()) optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict(params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) data_batch = dict(inputs={'img_mask': inputs, 'img_photo': targets}) # iter 0, 1 for i in range(2): message_hub.update_info('iter', i) log_vars = synthesizer.train_step(data_batch, optimizer) assert isinstance(log_vars, dict) for v in [ 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ]: assert log_vars.get(v) is None assert isinstance(log_vars['loss_gan_d_mask'].item(), float) assert isinstance(log_vars['loss_gan_d_photo'].item(), float) # iter 2, 3, 4, 5 for i in range(2, 6): message_hub.update_info('iter', i) log_vars = synthesizer.train_step(data_batch, optimizer) print(log_vars.keys()) assert isinstance(log_vars, dict) log_check_list = [ 'loss_gan_d_mask', 'loss_gan_d_photo', 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ] if (i + 1) % 2 == 1: log_None_list = [ 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ] for v in log_None_list: assert log_vars.get(v) is None log_check_list.remove(v) for v in log_check_list: assert isinstance(log_vars[v].item(), float) # test GAN image buffer size = 0 inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) data_batch = dict(inputs={'img_mask': inputs, 'img_photo': targets}) train_settings = dict(buffer_size=0) synthesizer = CycleGAN( **model_cfg, **train_settings, data_preprocessor=DataPreprocessor()) optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict(params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) log_vars = synthesizer.train_step(data_batch, optimizer) assert isinstance(log_vars, dict) for v in [ 'loss_gan_d_mask', 'loss_gan_d_photo', 'loss_gan_g_mask', 'loss_gan_g_photo', 'cycle_loss', 'id_loss' ]: assert isinstance(log_vars[v].item(), float) # test get opposite domain assert synthesizer._get_opposite_domain('photo') == 'mask' # test val_step and test_step data = dict( inputs=dict( img_photo=torch.randn(1, 3, 64, 64), img_mask=torch.randn(1, 3, 64, 64)), data_samples=[DataSample(mode='test')]) out = synthesizer.test_step(data) assert len(out) == 1 assert out[0].fake_photo.data.shape == (3, 64, 64) assert out[0].fake_mask.data.shape == (3, 64, 64) out = synthesizer.val_step(data) assert len(out) == 1 assert out[0].fake_photo.data.shape == (3, 64, 64) assert out[0].fake_mask.data.shape == (3, 64, 64) data = dict( inputs=dict( img_photo=torch.randn(1, 3, 64, 64), img_mask=torch.randn(1, 3, 64, 64))) out = synthesizer.test_step(data) assert len(out) == 1 assert out[0].fake_photo.data.shape == (3, 64, 64) assert out[0].fake_mask.data.shape == (3, 64, 64) out = synthesizer.val_step(data) assert len(out) == 1 assert out[0].fake_photo.data.shape == (3, 64, 64) assert out[0].fake_mask.data.shape == (3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_cyclegan/test_cyclegan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.cyclegan import ResnetGenerator @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') class TestResnetGenerator: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=3, base_channels=64, norm_cfg=dict(type='IN'), use_dropout=False, num_blocks=9, padding_mode='reflect', init_cfg=dict(type='normal', gain=0.02)) def test_cyclegan_generator_cpu(self): # test with default cfg real_a = torch.randn((2, 3, 256, 256)) gen = ResnetGenerator(**self.default_cfg) fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) # test args system cfg = deepcopy(self.default_cfg) cfg['num_blocks'] = 8 gen = ResnetGenerator(**cfg) fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_cyclegan_generator_cuda(self): # test with default cfg real_a = torch.randn((2, 3, 256, 256)).cuda() gen = ResnetGenerator(**self.default_cfg).cuda() fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) # test args system cfg = deepcopy(self.default_cfg) cfg['num_blocks'] = 8 gen = ResnetGenerator(**cfg).cuda() fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_cyclegan/test_cyclegan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmagic.models.editors.cyclegan.cyclegan_modules import ( GANImageBuffer, ResidualBlockWithDropout) def test_residual_block_with_dropout(): block = ResidualBlockWithDropout(16, 'zeros') input = torch.rand((2, 16, 128, 128)) output = block(input) assert output.detach().numpy().shape == (2, 16, 128, 128) block = ResidualBlockWithDropout(16, 'zeros', use_dropout=False) assert len(block.block) == 2 def test_gan_image_buffer(): # test buffer size = 0 buffer = GANImageBuffer(buffer_size=0) img_np = np.random.randn(1, 3, 256, 256) img_tensor = torch.from_numpy(img_np) img_tensor_return = buffer.query(img_tensor) assert torch.equal(img_tensor_return, img_tensor) # test buffer size > 0 buffer = GANImageBuffer(buffer_size=1) img_np = np.random.randn(2, 3, 256, 256) img_tensor = torch.from_numpy(img_np) img_tensor_0 = torch.unsqueeze(img_tensor[0], 0) img_tensor_1 = torch.unsqueeze(img_tensor[1], 0) img_tensor_00 = torch.cat([img_tensor_0, img_tensor_0], 0) img_tensor_return = buffer.query(img_tensor) assert (torch.equal(img_tensor_return, img_tensor) and torch.equal(buffer.image_buffer[0], img_tensor_0)) or \ (torch.equal(img_tensor_return, img_tensor_00) and torch.equal(buffer.image_buffer[0], img_tensor_1)) # test buffer size > 0, specify buffer chance buffer = GANImageBuffer(buffer_size=1, buffer_ratio=0.3) img_np = np.random.randn(2, 3, 256, 256) img_tensor = torch.from_numpy(img_np) img_tensor_0 = torch.unsqueeze(img_tensor[0], 0) img_tensor_1 = torch.unsqueeze(img_tensor[1], 0) img_tensor_00 = torch.cat([img_tensor_0, img_tensor_0], 0) img_tensor_return = buffer.query(img_tensor) assert (torch.equal(img_tensor_return, img_tensor) and torch.equal(buffer.image_buffer[0], img_tensor_0)) or \ (torch.equal(img_tensor_return, img_tensor_00) and torch.equal(buffer.image_buffer[0], img_tensor_1)) # set buffer ratio as 1 and 0 to cover more lines buffer = GANImageBuffer(buffer_size=1, buffer_ratio=1) img_np = np.random.randn(2, 3, 256, 256) img_tensor = torch.from_numpy(img_np) img_tensor_0 = torch.unsqueeze(img_tensor[0], 0) img_tensor_1 = torch.unsqueeze(img_tensor[1], 0) img_tensor_00 = torch.cat([img_tensor_0, img_tensor_0], 0) img_tensor_return = buffer.query(img_tensor) assert (torch.equal(img_tensor_return, img_tensor) and torch.equal(buffer.image_buffer[0], img_tensor_0)) or \ (torch.equal(img_tensor_return, img_tensor_00) and torch.equal(buffer.image_buffer[0], img_tensor_1)) buffer = GANImageBuffer(buffer_size=1, buffer_ratio=0) img_np = np.random.randn(2, 3, 256, 256) img_tensor = torch.from_numpy(img_np) img_tensor_0 = torch.unsqueeze(img_tensor[0], 0) img_tensor_1 = torch.unsqueeze(img_tensor[1], 0) img_tensor_00 = torch.cat([img_tensor_0, img_tensor_0], 0) img_tensor_return = buffer.query(img_tensor) assert (torch.equal(img_tensor_return, img_tensor) and torch.equal(buffer.image_buffer[0], img_tensor_0)) or \ (torch.equal(img_tensor_return, img_tensor_00) and torch.equal(buffer.image_buffer[0], img_tensor_1)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dcgan/test_dcgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import DCGAN, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='DCGANGenerator', noise_size=10, output_scale=16, base_channels=16) discriminator = dict( type='DCGANDiscriminator', input_scale=16, output_scale=4, out_channels=1) class TestDCGAN(TestCase): def test_init(self): gan = DCGAN( noise_size=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator) self.assertIsInstance(gan, DCGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = DCGAN( generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = DCGAN( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = DCGAN(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('test-lsgan') gan = DCGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dcgan/test_dcgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.dcgan import DCGANDiscriminator from mmagic.registry import MODELS class TestDCGANDiscriminator(object): @classmethod def setup_class(cls): cls.input_tensor = torch.randn((2, 3, 32, 32)) cls.default_config = dict( type='DCGANDiscriminator', input_scale=32, output_scale=4, out_channels=5) def test_dcgan_discriminator(self): # test default setting with builder d = MODELS.build(self.default_config) pred = d(self.input_tensor) assert pred.shape == (2, 5) assert d.num_downsamples == 3 assert len(d.downsamples) == 3 assert not d.downsamples[0].with_norm assert not d.output_layer.with_norm assert not d.output_layer.with_activation assert isinstance(d.downsamples[1].activate, torch.nn.LeakyReLU) assert isinstance(d.downsamples[1].norm, torch.nn.BatchNorm2d) # sanity check for args with cpu model d = DCGANDiscriminator(input_scale=64, output_scale=8, out_channels=2) assert d.input_scale == 64 and d.output_scale == 8 assert d.num_downsamples == 3 assert d.out_channels == 2 pred = d(torch.randn((1, 3, 64, 64))) assert pred.shape == (1, 50) with pytest.raises(TypeError): _ = DCGANDiscriminator(32, 4, 2, pretrained=dict()) # check for cuda if not torch.cuda.is_available(): return # test default setting with builder on GPU d = MODELS.build(self.default_config).cuda() pred = d(self.input_tensor.cuda()) assert pred.shape == (2, 5) assert d.num_downsamples == 3 assert len(d.downsamples) == 3 assert not d.downsamples[0].with_norm assert not d.output_layer.with_norm assert not d.output_layer.with_activation assert isinstance(d.downsamples[1].activate, torch.nn.LeakyReLU) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dcgan/test_dcgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.dcgan import DCGANGenerator from mmagic.registry import MODELS class TestDCGANGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((2, 100)) cls.default_config = dict( type='DCGANGenerator', output_scale=16, base_channels=32) def test_dcgan_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, DCGANGenerator) assert g.num_upsamples == 2 assert not g.output_layer.with_norm assert len(g.upsampling) == 1 assert g.upsampling[0].with_norm assert g.noise2feat.with_norm assert isinstance(g.output_layer.activate, torch.nn.Tanh) # check forward function img = g(self.noise) assert img.shape == (2, 3, 16, 16) img = g(self.noise[:, :, None, None]) assert img.shape == (2, 3, 16, 16) img = g(torch.randn, num_batches=2) assert img.shape == (2, 3, 16, 16) img = g(None, num_batches=2) assert img.shape == (2, 3, 16, 16) with pytest.raises(ValueError): _ = g(torch.randn((1, 100, 3))) with pytest.raises(AssertionError): _ = g(torch.randn) with pytest.raises(AssertionError): _ = g(None) with pytest.raises(AssertionError): _ = g(torch.randn(2, 10)) results = g(self.noise, return_noise=True) assert results['noise_batch'].shape == (2, 100, 1, 1) # sanity check for args with cpu model g = DCGANGenerator(32, base_channels=64) img = g(self.noise) assert img.shape == (2, 3, 32, 32) assert g.base_channels == 64 g = DCGANGenerator(16, out_channels=1, base_channels=32) img = g(self.noise) assert img.shape == (2, 1, 16, 16) g = DCGANGenerator(16, noise_size=10, base_channels=32) with pytest.raises(AssertionError): _ = g(self.noise) img = g(torch.randn(2, 10)) assert img.shape == (2, 3, 16, 16) g = DCGANGenerator( 16, default_act_cfg=dict(type='LeakyReLU'), base_channels=32) assert isinstance(g.noise2feat.activate, torch.nn.LeakyReLU) assert isinstance(g.upsampling[0].activate, torch.nn.LeakyReLU) assert isinstance(g.output_layer.activate, torch.nn.Tanh) with pytest.raises(TypeError): _ = DCGANGenerator( 16, noise_size=10, base_channels=32, pretrained=dict()) # check for cuda if not torch.cuda.is_available(): return g = MODELS.build(self.default_config).cuda() assert isinstance(g, DCGANGenerator) assert g.num_upsamples == 2 assert not g.output_layer.with_norm assert len(g.upsampling) == 1 assert g.upsampling[0].with_norm # check forward function img = g(self.noise) assert img.shape == (2, 3, 16, 16) img = g(self.noise[:, :, None, None]) assert img.shape == (2, 3, 16, 16) img = g(torch.randn, num_batches=2) assert img.shape == (2, 3, 16, 16) img = g(None, num_batches=2) assert img.shape == (2, 3, 16, 16) with pytest.raises(ValueError): _ = g(torch.randn((1, 100, 3))) with pytest.raises(AssertionError): _ = g(torch.randn) with pytest.raises(AssertionError): _ = g(None) results = g(self.noise, return_noise=True) assert results['noise_batch'].shape == (2, 100, 1, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_attention.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.ddpm.attention import (ApproximateGELU, CrossAttention, FeedForward, Transformer2DModel) def test_ApproximateGELU(): input = torch.rand((16, 16)) gelu = ApproximateGELU(16, 24) output = gelu.forward(input) assert output.shape == (16, 24) def test_crossattention(): input = torch.rand((2, 64, 64)) crossattention = CrossAttention(64) crossattention._slice_size = 2 output = crossattention.forward(input) assert output.shape == (2, 64, 64) def test_Transformer2DModel_init(): with pytest.raises(Exception): Transformer2DModel(in_channels=32, num_vector_embeds=4) with pytest.raises(Exception): Transformer2DModel() Transformer2DModel(in_channels=32, use_linear_projection=True) def test_FeedForward(): input = torch.rand((2, 64, 64)) feed_forward = FeedForward(64, 64, activation_fn='geglu-approximate') output = feed_forward.forward(input) assert output.shape == (2, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_ddpm_scheduler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.diffusion_schedulers.ddpm_scheduler import EditDDPMScheduler def test_ddpm(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) ddpm = EditDDPMScheduler( num_train_timesteps=1000, variance_type='learned_range') result = ddpm.step(modelout, 980, sample) assert result['prev_sample'].shape == (1, 4, 32, 32) ddpm.set_timesteps(100) predicted_variance = torch.tensor(1.0) ddpm._get_variance(t=0, predicted_variance=predicted_variance) ddpm._get_variance(t=1, variance_type='fixed_large') ddpm._get_variance(t=1, variance_type='fixed_large_log') ddpm._get_variance(t=1, variance_type='learned') with pytest.raises(Exception): ddpm.training_loss(1, 2, 3) with pytest.raises(Exception): ddpm.sample_timestep() steps = len(ddpm) assert steps == 1000 def test_ddpm_init(): EditDDPMScheduler(trained_betas=1) EditDDPMScheduler(beta_schedule='scaled_linear') EditDDPMScheduler(beta_schedule='squaredcos_cap_v2') with pytest.raises(Exception): EditDDPMScheduler(beta_schedule='tem') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_denoising_unet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.ddpm.denoising_unet import (DenoisingUnet, NormWithEmbedding) def test_DenoisingUnet(): input = torch.rand((1, 3, 32, 32)) unet = DenoisingUnet(32) output = unet.forward(input, 10) assert output['sample'].shape == (1, 6, 32, 32) def test_NormWithEmbedding(): input = torch.rand((4, 32)) emb = torch.rand((4, 32)) ins = NormWithEmbedding(32, 32) output = ins.forward(input, emb) assert output.shape == (4, 32, 4, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_embeddings.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.ddpm.embeddings import TimestepEmbedding, Timesteps def test_TimestepEmbedding(): input = torch.rand((1, 64, 16)) timestep_emb = TimestepEmbedding( in_channels=16, time_embed_dim=16, act_fn='mish') output = timestep_emb.forward(input) assert output.shape == (1, 64, 16) timestep_emb = TimestepEmbedding( in_channels=16, time_embed_dim=16, out_dim=96) timestep_emb.act = None output = timestep_emb.forward(input) assert output.shape == (1, 64, 96) def test_Timesteps(): input = torch.tensor([4]) timesteps = Timesteps(num_channels=9) emb = timesteps.forward(input) assert emb.shape == (1, 9) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_res_blocks.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.ddpm.res_blocks import (Downsample2D, ResnetBlock2D, Upsample2D) def test_resnetblock2d(): input = torch.rand((1, 64, 16, 16)) resblock = ResnetBlock2D(in_channels=64, up=True) output = resblock.forward(input, None) assert output.shape == (1, 64, 64, 64) resblock = ResnetBlock2D(in_channels=64, down=True) output = resblock.forward(input, None) assert output.shape == (1, 64, 8, 8) def test_Downsample2D(): input = torch.rand((1, 64, 16, 16)) downsample = Downsample2D(channels=64, use_conv=True, padding=0) output = downsample.forward(input) assert output.shape == (1, 64, 8, 8) def test_Upsample2D(): input = torch.rand((1, 64, 16, 16)) upsample = Upsample2D(channels=64, use_conv_transpose=True) output = upsample.forward(input) assert output.shape == (1, 64, 32, 32) upsample = Upsample2D(channels=64) output = upsample.forward(input, output_size=(32, 32)) assert output.shape == (1, 64, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ddpm/test_unet_blocks.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.ddpm.unet_blocks import (CrossAttnDownBlock2D, CrossAttnUpBlock2D, UNetMidBlock2DCrossAttn, get_down_block, get_up_block) def test_UNetMidBlock2DCrossAttn(): input = torch.rand((1, 64, 64, 64)) midblock = UNetMidBlock2DCrossAttn(64, 64, cross_attention_dim=64) midblock.set_attention_slice(1) output = midblock.forward(input) assert output.shape == (1, 64, 64, 64) with pytest.raises(Exception): midblock.set_attention_slice(8) def test_CrossAttnDownBlock2D(): input = torch.rand((1, 64, 64, 64)) downblock = CrossAttnDownBlock2D(64, 64, 64, cross_attention_dim=64) downblock.set_attention_slice(1) output, _ = downblock.forward(input) assert output.shape == (1, 64, 32, 32) with pytest.raises(Exception): downblock.set_attention_slice(8) def test_CrossAttnUpBlock2D(): downblock = CrossAttnUpBlock2D(64, 64, 64, 64, cross_attention_dim=64) downblock.set_attention_slice(1) def test_get_down_block(): with pytest.raises(Exception): get_down_block('tem', 1, 1, 1, 1, True, 'silu', 1) def get_get_up_block(): with pytest.raises(Exception): get_up_block('tem', 1, 1, 1, 1, 1, True, 'silu', 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deblurganv2/test_deblurganv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy from unittest import TestCase import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import Adam from mmagic.models import DataPreprocessor, DeblurGanV2 from mmagic.models.losses import PerceptualLoss from mmagic.models.losses.adv_loss import DiscLossWGANGP from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='DeblurGanV2Generator', backbone='FPNMobileNet', norm_layer='instance', output_ch=3, num_filter=64, num_filter_fpn=128, ) discriminator = dict( type='DeblurGanV2Discriminator', backbone='DoubleGan', norm_layer='instance', d_layers=3, ) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestDeblurGanV2(TestCase): def test_init(self): gan = DeblurGanV2( generator=generator, discriminator=discriminator, pixel_loss=dict( type='PerceptualLoss', layer_weights={'14': 1}, criterion='mse'), adv_lambda=0.001, warmup_num=3, disc_loss=dict(type='AdvLoss', loss_type='wgan-gp'), data_preprocessor=DataPreprocessor()) self.assertIsInstance(gan, DeblurGanV2) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) self.assertIsInstance(gan.pixel_loss, PerceptualLoss) self.assertIsInstance(gan.disc_loss, DiscLossWGANGP) gen_cfg = deepcopy(generator) disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = DeblurGanV2( generator=gen, discriminator=disc, pixel_loss=dict( type='PerceptualLoss', layer_weights={'14': 1}, criterion='mse'), adv_lambda=0.001, warmup_num=3, disc_loss=dict(type='AdvLoss', loss_type='wgan-gp'), data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = DeblurGanV2( generator=gen_cfg, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('test-lsgan') gan = DeblurGanV2( generator=generator, discriminator=discriminator, pixel_loss=dict( type='PerceptualLoss', layer_weights={'14': 1}, criterion='mse'), adv_lambda=0.001, warmup_num=3, disc_loss=dict(type='AdvLoss', loss_type='wgan-gp'), data_preprocessor=DataPreprocessor()) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = Adam( gan.generator.parameters(), lr=0.0001, betas=(0.5, 0.999)) disc_optim = Adam( list(gan.discriminator.patch_gan.parameters()) + list(gan.discriminator.full_gan.parameters()), lr=0.0001, betas=(0.5, 0.999)) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 256, 256) data = dict(inputs=[img], data_samples=[DataSample(gt_img=img)]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set(['loss_d', 'loss_g_content', 'loss_g_adv', 'loss_g'])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss_g_content', 'loss_g_adv', 'loss_g'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deblurganv2/test_deblurganv2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.deblurganv2 import DeblurGanV2Discriminator from mmagic.models.editors.deblurganv2.deblurganv2_discriminator import \ DoubleGan from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestDeblurGanv2Discriminator(object): @classmethod def setup_class(cls): cls.input_tensor = torch.randn((1, 3, 256, 256)) cls.default_config = dict( type='DeblurGanV2Discriminator', backbone='DoubleGan', norm_layer='instance', d_layers=3) def test_deblurganv2_discriminator(self): # test default setting with builder d = MODELS.build(self.default_config) assert isinstance(d, DoubleGan) pred = d(self.input_tensor) assert isinstance(pred, list) assert len(pred) == 2 assert d.full_gan assert d.patch_gan with pytest.raises(TypeError): _ = DeblurGanV2Discriminator() # sanity check for args with cpu model d = DeblurGanV2Discriminator( backbone='DoubleGan', norm_layer='instance', d_layers=3) pred = d(torch.randn((1, 3, 256, 256))) assert d.full_gan assert d.patch_gan assert isinstance(pred, list) assert len(pred) == 2 # check for cuda if not torch.cuda.is_available(): return # test default setting with builder on GPU d = MODELS.build(self.default_config).cuda() pred = d(self.input_tensor.cuda()) assert d.full_gan assert d.patch_gan assert isinstance(pred, list) assert len(pred) == 2 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deblurganv2/test_deblurganv2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.deblurganv2 import DeblurGanV2Generator from mmagic.models.editors.deblurganv2.deblurganv2_generator import \ FPNMobileNet from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestDeblurGanv2Generator(object): @classmethod def setup_class(cls): cls.input_tensor = torch.randn((1, 3, 256, 256)) cls.default_config = dict( type='DeblurGanV2Generator', backbone='FPNMobileNet', norm_layer='instance', output_ch=3, num_filter=64, num_filter_fpn=128) def test_deblurganv2_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, FPNMobileNet) # check forward function img = g(self.input_tensor) assert img.shape == (1, 3, 256, 256) img = g(torch.randn(4, 3, 256, 256)) assert img.shape == (4, 3, 256, 256) with pytest.raises(TypeError): _ = DeblurGanV2Generator() # sanity check for args with cpu model g = DeblurGanV2Generator( backbone='FPNMobileNet', norm_layer='instance', output_ch=3, num_filter=64, num_filter_fpn=128) img = g(self.input_tensor) assert img.shape == (1, 3, 256, 256) # check for cuda if not torch.cuda.is_available(): return g = MODELS.build(self.default_config).cuda() assert isinstance(g, DeblurGanV2Generator) g = DeblurGanV2Generator( backbone='FPNMobileNet', norm_layer='instance', output_ch=3, num_filter=64, num_filter_fpn=128).cuda() img = g(self.input_tensor) assert img.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_contextual_attention.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import ContextualAttentionModule def test_deepfill_contextual_attention_module(): cmodule = ContextualAttentionModule() x = torch.rand((2, 128, 64, 64)) mask = torch.zeros((2, 1, 64, 64)) mask[..., 20:100, 23:90] = 1. res, offset = cmodule(x, x, mask) assert res.shape == (2, 128, 64, 64) assert offset.shape == (2, 32, 32, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_contextual_attention_neck.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import SimpleGatedConvModule from mmagic.models.editors import ContextualAttentionNeck def test_deepfill_contextual_attention_neck(): # TODO: add unittest for contextual attention module neck = ContextualAttentionNeck(in_channels=128) x = torch.rand((2, 128, 64, 64)) mask = torch.zeros((2, 1, 64, 64)) mask[..., 20:100, 23:90] = 1. res, offset = neck(x, mask) assert res.shape == (2, 128, 64, 64) assert offset.shape == (2, 32, 32, 32, 32) if torch.cuda.is_available(): neck.cuda() res, offset = neck(x.cuda(), mask.cuda()) assert res.shape == (2, 128, 64, 64) assert offset.shape == (2, 32, 32, 32, 32) neck = ContextualAttentionNeck( in_channels=128, conv_type='gated_conv').cuda() res, offset = neck(x.cuda(), mask.cuda()) assert res.shape == (2, 128, 64, 64) assert offset.shape == (2, 32, 32, 32, 32) assert isinstance(neck.conv1, SimpleGatedConvModule) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_deepfill_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import DeepFillDecoder def test_deepfill_dec(): decoder = DeepFillDecoder(128, out_act_cfg=None) assert not decoder.with_out_activation decoder = DeepFillDecoder(128) x = torch.randn((2, 128, 64, 64)) input_dict = dict(out=x) res = decoder(input_dict) assert res.shape == (2, 3, 256, 256) assert decoder.dec2.stride == (1, 1) assert decoder.dec2.out_channels == 128 assert not decoder.dec7.with_activation assert res.min().item() >= -1. and res.max().item() <= 1 if torch.cuda.is_available(): decoder = DeepFillDecoder(128).cuda() x = torch.randn((2, 128, 64, 64)).cuda() input_dict = dict(out=x) res = decoder(input_dict) assert res.shape == (2, 3, 256, 256) assert decoder.dec2.stride == (1, 1) assert decoder.dec2.out_channels == 128 assert not decoder.dec7.with_activation assert res.min().item() >= -1. and res.max().item() <= 1 decoder = DeepFillDecoder( 128, conv_type='gated_conv', channel_factor=0.75).cuda() x = torch.randn((2, 128, 64, 64)).cuda() input_dict = dict(out=x) res = decoder(input_dict) assert res.shape == (2, 3, 256, 256) assert decoder.dec2.conv.stride == (1, 1) assert decoder.dec2.conv.out_channels == 96 * 2 assert not decoder.dec7.with_feat_act assert res.min().item() >= -1. and res.max().item() <= 1 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_deepfill_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.archs import MultiLayerDiscriminator from mmagic.models.editors import DeepFillv1Discriminators def test_deepfillv1_disc(): model_config = dict( global_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=256, fc_in_channels=256 * 16 * 16, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2)), local_disc_cfg=dict( type='MultiLayerDiscriminator', in_channels=3, max_channels=512, fc_in_channels=512 * 8 * 8, fc_out_channels=1, num_convs=4, norm_cfg=None, act_cfg=dict(type='ELU'), out_act_cfg=dict(type='LeakyReLU', negative_slope=0.2))) disc = DeepFillv1Discriminators(**model_config) disc.init_weights() global_x = torch.rand((2, 3, 256, 256)) local_x = torch.rand((2, 3, 128, 128)) global_pred, local_pred = disc((global_x, local_x)) assert global_pred.shape == (2, 1) assert local_pred.shape == (2, 1) assert isinstance(disc.global_disc, MultiLayerDiscriminator) assert isinstance(disc.local_disc, MultiLayerDiscriminator) with pytest.raises(TypeError): disc.init_weights(model_config) if torch.cuda.is_available(): disc = DeepFillv1Discriminators(**model_config).cuda() disc.init_weights() global_x = torch.rand((2, 3, 256, 256)).cuda() local_x = torch.rand((2, 3, 128, 128)).cuda() global_pred, local_pred = disc((global_x, local_x)) assert global_pred.shape == (2, 1) assert local_pred.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_deepfill_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import SimpleGatedConvModule from mmagic.models.editors import DeepFillEncoder def test_deepfill_enc(): encoder = DeepFillEncoder() x = torch.randn((2, 5, 256, 256)) outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.stride == (2, 2) assert encoder.enc2.out_channels == 64 encoder = DeepFillEncoder(encoder_type='stage2_conv') x = torch.randn((2, 5, 256, 256)) outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.out_channels == 32 assert encoder.enc3.out_channels == 64 assert encoder.enc4.out_channels == 64 encoder = DeepFillEncoder(encoder_type='stage2_attention') x = torch.randn((2, 5, 256, 256)) outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.out_channels == 32 assert encoder.enc3.out_channels == 64 assert encoder.enc4.out_channels == 128 if torch.cuda.is_available(): encoder = DeepFillEncoder().cuda() x = torch.randn((2, 5, 256, 256)).cuda() outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.stride == (2, 2) assert encoder.enc2.out_channels == 64 encoder = DeepFillEncoder(encoder_type='stage2_conv').cuda() x = torch.randn((2, 5, 256, 256)).cuda() outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.out_channels == 32 assert encoder.enc3.out_channels == 64 assert encoder.enc4.out_channels == 64 encoder = DeepFillEncoder(encoder_type='stage2_attention').cuda() x = torch.randn((2, 5, 256, 256)).cuda() outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 128, 64, 64) assert encoder.enc2.out_channels == 32 assert encoder.enc3.out_channels == 64 assert encoder.enc4.out_channels == 128 encoder = DeepFillEncoder( conv_type='gated_conv', channel_factor=0.75).cuda() x = torch.randn((2, 5, 256, 256)).cuda() outputs = encoder(x) assert isinstance(outputs, dict) assert 'out' in outputs res = outputs['out'] assert res.shape == (2, 96, 64, 64) assert isinstance(encoder.enc2, SimpleGatedConvModule) assert encoder.enc2.conv.stride == (2, 2) assert encoder.enc2.conv.out_channels == 48 * 2 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_deepfill_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import (ContextualAttentionNeck, DeepFillDecoder, DeepFillEncoder, DeepFillRefiner, GLDilationNeck) def test_deepfill_refiner(): refiner = DeepFillRefiner() x = torch.rand((2, 5, 256, 256)) mask = x.new_ones((2, 1, 256, 256)) mask[..., 30:100, 40:100] = 0. res, offset = refiner(x, mask) assert res.shape == (2, 3, 256, 256) assert offset.shape == (2, 32, 32, 32, 32) # check model architecture assert isinstance(refiner.encoder_attention, DeepFillEncoder) assert isinstance(refiner.encoder_conv, DeepFillEncoder) assert isinstance(refiner.contextual_attention_neck, ContextualAttentionNeck) assert isinstance(refiner.decoder, DeepFillDecoder) assert isinstance(refiner.dilation_neck, GLDilationNeck) if torch.cuda.is_available(): refiner = DeepFillRefiner().cuda() x = torch.rand((2, 5, 256, 256)).cuda() res, offset = refiner(x, mask.cuda()) assert res.shape == (2, 3, 256, 256) assert offset.shape == (2, 32, 32, 32, 32) # check model architecture assert isinstance(refiner.encoder_attention, DeepFillEncoder) assert isinstance(refiner.encoder_conv, DeepFillEncoder) assert isinstance(refiner.contextual_attention_neck, ContextualAttentionNeck) assert isinstance(refiner.decoder, DeepFillDecoder) assert isinstance(refiner.dilation_neck, GLDilationNeck) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv1/test_deepfillv1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from os import path as osp import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.models.editors import (DeepFillEncoderDecoder, DeepFillRefiner, GLEncoderDecoder) from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules def test_deepfill_encdec(): encdec = DeepFillEncoderDecoder() assert isinstance(encdec.stage1, GLEncoderDecoder) assert isinstance(encdec.stage2, DeepFillRefiner) if torch.cuda.is_available(): img = torch.rand((2, 3, 256, 256)).cuda() mask = img.new_zeros((2, 1, 256, 256)) mask[..., 20:100, 30:120] = 1. input_x = torch.cat([img, torch.ones_like(mask), mask], dim=1) encdec.cuda() stage1_res, stage2_res = encdec(input_x) assert stage1_res.shape == (2, 3, 256, 256) assert stage2_res.shape == (2, 3, 256, 256) encdec = DeepFillEncoderDecoder(return_offset=True).cuda() stage1_res, stage2_res, offset = encdec(input_x) assert offset.shape == (2, 32, 32, 32, 32) def test_deepfillv1_inpaintor(): register_all_modules() config_file = osp.join( osp.dirname(__file__), '../../..', 'configs', 'deepfillv1_test.py') cfg = Config.fromfile(config_file) deepfillv1 = MODELS.build(cfg.model) assert deepfillv1.__class__.__name__ == 'DeepFillv1Inpaintor' if torch.cuda.is_available(): deepfillv1.cuda() # check architecture assert deepfillv1.stage1_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep', 'loss_tv') assert deepfillv1.stage2_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_gan') assert deepfillv1.with_l1_hole_loss assert deepfillv1.with_l1_valid_loss assert deepfillv1.with_composed_percep_loss assert not deepfillv1.with_out_percep_loss assert deepfillv1.with_gan # prepare data gt_img = torch.rand((3, 256, 256)) mask = torch.zeros((1, 256, 256)) mask[..., 50:180, 60:170] = 1. masked_img = gt_img.unsqueeze(0) * (1. - mask) mask_bbox = [100, 100, 110, 110] data_batch = { 'inputs': masked_img, 'data_samples': [ DataSample( metainfo=dict(mask_bbox=mask_bbox), mask=mask, gt_img=gt_img, ) ] } # prepare model and optimizer optim_g = torch.optim.Adam(deepfillv1.generator.parameters(), lr=0.0001) optim_d = torch.optim.Adam(deepfillv1.disc.parameters(), lr=0.0001) optims = dict(generator=OptimWrapper(optim_g), disc=OptimWrapper(optim_d)) # check train_step with standard deepfillv1 model for i in range(5): log_vars = deepfillv1.train_step(data_batch, optims) if i % 2 == 0: assert 'real_loss_global' in log_vars assert 'fake_loss_global' in log_vars assert 'real_loss_local' in log_vars assert 'fake_loss_local' in log_vars assert 'loss' in log_vars else: assert 'real_loss_global' in log_vars assert 'fake_loss_global' in log_vars assert 'real_loss_local' in log_vars assert 'fake_loss_local' in log_vars assert 'stage1_loss_l1_hole' in log_vars assert 'stage1_loss_l1_valid' in log_vars assert 'stage2_loss_l1_hole' in log_vars assert 'stage2_loss_l1_valid' in log_vars assert 'stage2_loss_g_fake' in log_vars def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_deepfillv2/test_two_stage_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import platform from os.path import dirname, join import pytest import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_two_stage_inpaintor(): register_all_modules() config_file = join( dirname(__file__), '../../..', 'configs', 'two_stage_test.py') cfg = Config.fromfile(config_file) inpaintor = MODELS.build(cfg.model) assert inpaintor.__class__.__name__ == 'TwoStageInpaintor' if torch.cuda.is_available(): inpaintor.cuda() # check architecture assert inpaintor.stage1_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_composed_percep', 'loss_tv') assert inpaintor.stage2_loss_type == ('loss_l1_hole', 'loss_l1_valid', 'loss_gan') assert inpaintor.with_l1_hole_loss assert inpaintor.with_l1_valid_loss assert inpaintor.with_composed_percep_loss assert not inpaintor.with_out_percep_loss assert inpaintor.with_gan # prepare data gt_img = torch.randn(3, 128, 128) mask = torch.zeros((1, 128, 128)) mask[..., 12:45, 14:42] = 1. masked_img = gt_img.unsqueeze(0) * (1. - mask) + mask mask_bbox = [25, 25, 27, 27] data_batch = { 'inputs': masked_img, 'data_samples': [DataSample( mask=mask, mask_bbox=mask_bbox, gt_img=gt_img, )] } optim_g = torch.optim.Adam(inpaintor.generator.parameters(), lr=0.0001) optim_d = torch.optim.Adam(inpaintor.disc.parameters(), lr=0.0001) optims = dict(generator=OptimWrapper(optim_g), disc=OptimWrapper(optim_d)) # check train_step with standard two_stage model for i in range(5): log_vars = inpaintor.train_step(data_batch, optims) if i % 2 == 0: assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_disc_shift' in log_vars assert 'loss' in log_vars else: assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_disc_shift' in log_vars assert 'loss' in log_vars assert 'stage1_loss_l1_hole' in log_vars assert 'stage1_loss_l1_valid' in log_vars assert 'stage2_loss_l1_hole' in log_vars assert 'stage2_loss_l1_valid' in log_vars # check for forward_test data = inpaintor.data_preprocessor(data_batch, True) data_inputs, data_sample = data['inputs'], data['data_samples'] output = inpaintor.forward_test(data_inputs, data_sample) prediction = output.split()[0] assert 'fake_res' in prediction assert 'fake_img' in prediction assert 'pred_img' in prediction assert prediction.pred_img.shape == (3, 128, 128) # check for gp_loss cfg_copy = copy.deepcopy(cfg) cfg_copy.model.disc_input_with_mask = False cfg_copy.model.disc.in_channels = 3 cfg_copy.model.loss_gp = dict(type='GradientPenaltyLoss', loss_weight=10.) inpaintor = MODELS.build(cfg_copy.model) assert inpaintor.with_gp_loss log_vars = inpaintor.train_step(data_batch, optims) assert 'real_loss' in log_vars assert 'stage1_loss_l1_hole' in log_vars assert 'stage1_loss_l1_valid' in log_vars assert 'stage2_loss_l1_hole' in log_vars assert 'stage2_loss_l1_valid' in log_vars def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dic/test_dic.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import patch import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import DIC, DataPreprocessor, DICNet, LightCNN from mmagic.models.losses import (GANLoss, L1Loss, LightCNNFeatureLoss, PerceptualVGG) from mmagic.structures import DataSample @patch.object(PerceptualVGG, 'init_weights') def test_dic(init_weights): model = DIC( generator=dict( type='DICNet', in_channels=3, out_channels=3, mid_channels=4), discriminator=dict(type='LightCNN', in_channels=3), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), align_loss=dict(type='MSELoss', loss_weight=0.1, reduction='mean'), feature_loss=dict( type='LightCNNFeatureLoss', pretrained=None, loss_weight=0.1, criterion='l1'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=0.005, real_label_val=1.0, fake_label_val=0), train_cfg=dict(), test_cfg=dict(), data_preprocessor=DataPreprocessor( mean=[129.795, 108.12, 96.39], std=[255, 255, 255], )) assert isinstance(model, DIC) assert isinstance(model.generator, DICNet) assert isinstance(model.discriminator, LightCNN) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.feature_loss, LightCNNFeatureLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 16, 16) target = torch.rand(3, 128, 128) data_sample = DataSample(gt_img=target, gt_heatmap=torch.rand(68, 32, 32)) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_pixel_v0', 'loss_align_v0', 'loss_pixel_v1', 'loss_align_v1', 'loss_pixel_v2', 'loss_align_v2', 'loss_pixel_v3', 'loss_align_v3', 'loss_feature', 'loss_gan', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 128, 128) # feat output = model(torch.rand(1, 3, 16, 16), mode='tensor') assert output.shape == (1, 3, 128, 128) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dic/test_dic_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch import torch.nn as nn from mmagic.models.editors import (FeedbackBlock, FeedbackBlockCustom, FeedbackBlockHeatmapAttention) from mmagic.registry import MODELS def test_feedback_block(): x1 = torch.rand(2, 16, 32, 32) model = FeedbackBlock(16, 3, 8) x2 = model(x1) assert x2.shape == x1.shape x3 = model(x2) assert x3.shape == x2.shape def test_feedback_block_custom(): x1 = torch.rand(2, 3, 32, 32) model = FeedbackBlockCustom(3, 16, 3, 8) x2 = model(x1) assert x2.shape == (2, 16, 32, 32) def test_feedback_block_heatmap_attention(): x1 = torch.rand(2, 16, 32, 32) heatmap = torch.rand(2, 5, 32, 32) model = FeedbackBlockHeatmapAttention(16, 2, 8, 5, 2) x2 = model(x1, heatmap) assert x2.shape == x1.shape x3 = model(x2, heatmap) assert x3.shape == x2.shape @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_dic_net_cpu(): model_cfg = dict( type='DICNet', in_channels=3, out_channels=3, mid_channels=48, num_blocks=6, hg_mid_channels=256, hg_num_keypoints=68, num_steps=4, upscale_factor=8, detach_attention=False) # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'DICNet' # prepare data inputs = torch.rand(1, 3, 16, 16) targets = torch.rand(1, 3, 128, 128) # prepare loss loss_function = nn.L1Loss() # prepare optimizer optimizer = torch.optim.Adam(model.parameters()) # test on cpu output, _ = model(inputs) optimizer.zero_grad() loss = loss_function(output[-1], targets) loss.backward() optimizer.step() assert len(output) == 4 assert torch.is_tensor(output[-1]) assert output[-1].shape == targets.shape @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_dic_net_cuda(): # prepare data inputs = torch.rand(1, 3, 16, 16) targets = torch.rand(1, 3, 128, 128) model_cfg = dict( type='DICNet', in_channels=3, out_channels=3, mid_channels=48, num_blocks=6, hg_mid_channels=256, hg_num_keypoints=68, num_steps=4, upscale_factor=8, detach_attention=False) # build model model = MODELS.build(model_cfg) # prepare loss loss_function = nn.L1Loss() # test on gpu if torch.cuda.is_available(): model = model.cuda() optimizer = torch.optim.Adam(model.parameters()) inputs = inputs.cuda() targets = targets.cuda() output, _ = model(inputs) optimizer.zero_grad() loss = loss_function(output[-1], targets) loss.backward() optimizer.step() assert len(output) == 4 assert torch.is_tensor(output[-1]) assert output[-1].shape == targets.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dic/test_feedback_hour_glass.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.dic.feedback_hour_glass import ( Hourglass, ResBlock, reduce_to_five_heatmaps) from mmagic.registry import MODELS def test_res_block(): res_block = ResBlock(16, 32) x = torch.rand(2, 16, 64, 64) y = res_block(x) assert y.shape == (2, 32, 64, 64) res_block = ResBlock(16, 16) x = torch.rand(2, 16, 64, 64) y = res_block(x) assert y.shape == (2, 16, 64, 64) def test_hour_glass(): hour_glass = Hourglass(2, 16) x = torch.rand(2, 16, 64, 64) y = hour_glass(x) assert y.shape == x.shape def test_feedback_hour_glass(): model_cfg = dict( type='FeedbackHourglass', mid_channels=16, num_keypoints=20) fhg = MODELS.build(model_cfg) assert fhg.__class__.__name__ == 'FeedbackHourglass' x = torch.rand(2, 3, 64, 64) heatmap, last_hidden = fhg.forward(x) assert heatmap.shape == (2, 20, 16, 16) assert last_hidden.shape == (2, 16, 16, 16) heatmap, last_hidden = fhg.forward(x, last_hidden) assert heatmap.shape == (2, 20, 16, 16) assert last_hidden.shape == (2, 16, 16, 16) def test_reduce_to_five_heatmaps(): heatmap = torch.rand((2, 5, 64, 64)) new_heatmap = reduce_to_five_heatmaps(heatmap, False) assert new_heatmap.shape == (2, 5, 64, 64) new_heatmap = reduce_to_five_heatmaps(heatmap, True) assert new_heatmap.shape == (2, 5, 64, 64) heatmap = torch.rand((2, 68, 64, 64)) new_heatmap = reduce_to_five_heatmaps(heatmap, False) assert new_heatmap.shape == (2, 5, 64, 64) new_heatmap = reduce_to_five_heatmaps(heatmap, True) assert new_heatmap.shape == (2, 5, 64, 64) heatmap = torch.rand((2, 194, 64, 64)) new_heatmap = reduce_to_five_heatmaps(heatmap, False) assert new_heatmap.shape == (2, 5, 64, 64) new_heatmap = reduce_to_five_heatmaps(heatmap, True) assert new_heatmap.shape == (2, 5, 64, 64) with pytest.raises(NotImplementedError): heatmap = torch.rand((2, 12, 64, 64)) reduce_to_five_heatmaps(heatmap, False) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dic/test_light_cnn.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import MaxFeature from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_max_feature(): # cpu conv2d = MaxFeature(16, 16, filter_type='conv2d') x1 = torch.rand(3, 16, 16, 16) y1 = conv2d(x1) assert y1.shape == (3, 16, 16, 16) linear = MaxFeature(16, 16, filter_type='linear') x2 = torch.rand(3, 16) y2 = linear(x2) assert y2.shape == (3, 16) # gpu if torch.cuda.is_available(): x1 = x1.cuda() x2 = x2.cuda() conv2d = conv2d.cuda() linear = linear.cuda() y1 = conv2d(x1) assert y1.shape == (3, 16, 16, 16) y2 = linear(x2) assert y2.shape == (3, 16) # filter_type should be conv2d or linear with pytest.raises(ValueError): MaxFeature(12, 12, filter_type='conv1d') @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_light_cnn(): cfg = dict(type='LightCNN', in_channels=3) net = MODELS.build(cfg) # cpu inputs = torch.rand((2, 3, 128, 128)) output = net(inputs) assert output.shape == (2, 1) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(inputs.cuda()) assert output.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dim/test_dim.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import numpy as np import pytest import torch from mmengine.config import ConfigDict from mmagic.datasets.transforms import PackInputs from mmagic.models.editors import DIM from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def _demo_input_train(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) alpha = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) ori_merged = torch.from_numpy( np.random.random(color_shape).astype(np.float32)) fg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) bg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) if cuda: merged = merged.cuda() trimap = trimap.cuda() alpha = alpha.cuda() ori_merged = ori_merged.cuda() fg = fg.cuda() bg = bg.cuda() inputs = torch.cat((merged, trimap), dim=1) data_samples = [] for a, m, f, b in zip(alpha, ori_merged, fg, bg): ds = DataSample() ds.gt_alpha = a ds.gt_merged = m ds.gt_fg = f ds.gt_bg = b for k, v in meta.items(): ds.set_field(name=k, value=v, field_type='metainfo', dtype=None) data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def _demo_input_test(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. test_trans (str): what test transformation is used in data pipeline. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) ori_shape = (img_shape[0], img_shape[1], 1) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) inputs = torch.cat((merged, trimap), dim=1) results = { 'ori_alpha': np.random.random(ori_shape).astype(np.float32), 'ori_trimap': np.random.randint(256, size=ori_shape).astype(np.float32), 'ori_merged_shape': img_shape, } packinputs = PackInputs() data_samples = [] for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) if cuda: inputs = inputs.cuda() data_samples = DataSample.stack(data_samples) return inputs, data_samples def assert_pred_alpha(predictions, batch_size): assert isinstance(predictions, list) assert isinstance(predictions[0], DataSample) pred_alpha = predictions[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == batch_size def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_dim_config(): data_preprocessor = dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='rescale_to_zero_one', ) backbone = dict( type='SimpleEncoderDecoder', encoder=dict(type='VGG16', in_channels=4), decoder=dict(type='PlainDecoder')) refiner = dict(type='PlainRefiner') train_cfg = dict(train_backbone=True, train_refiner=True) test_cfg = dict(refine=True) loss_alpha = dict(type='L1Loss') # build mattor without refiner mattor = DIM( data_preprocessor, backbone, refiner=None, loss_alpha=loss_alpha, train_cfg=train_cfg, test_cfg=test_cfg.copy()) assert not mattor.with_refiner assert not mattor.test_cfg.refine # only train the refiner, this will freeze the backbone mattor = DIM( data_preprocessor, backbone, refiner, loss_alpha=loss_alpha, train_cfg=dict(train_backbone=False, train_refiner=True), test_cfg=test_cfg.copy()) assert not mattor.train_cfg.train_backbone assert mattor.train_cfg.train_refiner assert mattor.test_cfg.refine # only train the backbone while the refiner is used for inference but not # trained, this behavior is allowed currently but will cause a warning. mattor = DIM( data_preprocessor, backbone, refiner, loss_alpha=loss_alpha, train_cfg=dict(train_backbone=True, train_refiner=False), test_cfg=test_cfg.copy()) assert mattor.train_cfg.train_backbone assert not mattor.train_cfg.train_refiner assert mattor.test_cfg.refine @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_dim(): model_cfg = ConfigDict( type='DIM', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict(type='VGG16', in_channels=4), decoder=dict(type='PlainDecoder')), refiner=dict(type='PlainRefiner'), loss_alpha=dict(type='CharbonnierLoss', loss_weight=0.5), loss_comp=dict(type='CharbonnierCompLoss', loss_weight=0.5), loss_refine=dict(type='CharbonnierLoss'), train_cfg=dict(train_backbone=True, train_refiner=True), test_cfg=dict( refine=False, resize_method='pad', resize_mode='reflect', size_divisor=32, ), ) # 1. test dim model with refiner model_cfg.train_cfg.train_refiner = True model_cfg.test_cfg.refine = True # test model forward in train mode model = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64)) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp', 'loss_refine']) # test model forward in train mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_train = _demo_input_train((64, 64), cuda=True) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp', 'loss_refine']) # test model forward in test mode with torch.no_grad(): model = MODELS.build(model_cfg) inputs, data_samples = _demo_input_test((48, 48)) output_test = model(inputs, data_samples, mode='predict') assert isinstance(output_test, list) assert isinstance(output_test[0], DataSample) pred_alpha = output_test[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == (48, 48) # test model forward in test mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_test = _demo_input_test((48, 48), cuda=True) output_test = model(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # 2. test dim model without refiner model_cfg.refiner = None model_cfg.test_cfg.refine = True # test model forward in train mode model = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64)) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp']) # test model forward in train mode with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_train = _demo_input_train((64, 64), cuda=True) output_train = model(*input_train, mode='loss') assert_dict_keys_equal(output_train, ['loss_alpha', 'loss_comp']) # test model forward in test mode with torch.no_grad(): model = MODELS.build(model_cfg) input_test = _demo_input_test((48, 48)) output_test = model(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # check test with gpu if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() input_test = _demo_input_test((48, 48), cuda=True) output_test = model(*input_test, mode='predict') # test forward_raw model.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) model.forward(inputs) test_dim() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import unittest from copy import deepcopy from unittest import TestCase from unittest.mock import patch import torch import torch.nn as nn from mmengine.utils import digit_version from torchvision.version import __version__ as TV_VERSION from mmagic.models import DenoisingUnet, DiscoDiffusion from mmagic.models.diffusion_schedulers import EditDDIMScheduler from mmagic.utils import register_all_modules register_all_modules() class clip_mock(nn.Module): def __init__(self, device='cuda'): super().__init__() self.register_buffer('tensor', torch.randn([1, 512])) def encode_image(self, inputs): return inputs.mean() * self.tensor.repeat(inputs.shape[0], 1).to( inputs.device) def encode_text(self, inputs): return self.tensor.repeat(inputs.shape[0], 1).to(inputs.device) def forward(self, x): return x class clip_mock_wrapper(nn.Module): def __init__(self): super().__init__() self.model = clip_mock() def forward(self, x): return x class TestDiscoDiffusion(TestCase): def setUp(self): # unet self.unet32 = DenoisingUnet( image_size=32, in_channels=3, base_channels=8, resblocks_per_downsample=2, attention_res=(8, ), norm_cfg=dict(type='GN32', num_groups=8), dropout=0.0, num_classes=0, use_fp16=True, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=2, num_head_channels=8, use_new_attention_order=False), use_scale_shift_norm=True) # mock clip self.clip_models = [clip_mock_wrapper(), clip_mock_wrapper()] # diffusion_scheduler self.diffusion_scheduler = EditDDIMScheduler( variance_type='learned_range', beta_schedule='linear', clip_sample=False) def test_init(self): unet32 = deepcopy(self.unet32) diffusion_scheduler = deepcopy(self.diffusion_scheduler) clip_models = deepcopy(self.clip_models) self.disco_diffusion = DiscoDiffusion( unet=unet32, diffusion_scheduler=diffusion_scheduler, secondary_model=None, clip_models=clip_models, use_fp16=True) @unittest.skipIf( digit_version(TV_VERSION) <= digit_version('0.7.0'), reason='torchvision version limitation') @unittest.skipIf(not torch.cuda.is_available(), reason='requires cuda') def test_infer(self): unet32 = deepcopy(self.unet32) diffusion_scheduler = deepcopy(self.diffusion_scheduler) clip_models = deepcopy(self.clip_models) self.disco_diffusion = DiscoDiffusion( unet=unet32, diffusion_scheduler=diffusion_scheduler, secondary_model=None, clip_models=clip_models, use_fp16=True) self.disco_diffusion.cuda().eval() # test model structure text_prompts = { 0: ['clouds surround the mountains and palaces,sunshine,lake'] } image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 32, 32) # test with different text prompts text_prompts = { 0: [ 'a portrait of supergirl, by artgerm, rosstran, trending on artstation.' # noqa ] } image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 32, 32) # test with init_image init_image = 'tests/data/image/face/000001.png' text_prompts = { 0: [ 'a portrait of supergirl, by artgerm, rosstran, trending on artstation.' # noqa ] } image = self.disco_diffusion.infer( text_prompts=text_prompts, init_image=init_image, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 32, 32) # test with different image resolution text_prompts = { 0: ['clouds surround the mountains and palaces,sunshine,lake'] } image = self.disco_diffusion.infer( height=64, width=128, text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 64, 128) # clip guidance scale image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, clip_guidance_scale=8000, eta=0.8)['samples'] assert image.shape == (1, 3, 32, 32) # test with different loss settings tv_scale = 0.5 sat_scale = 0.5 range_scale = 100 image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8, tv_scale=tv_scale, sat_scale=sat_scale, range_scale=range_scale)['samples'] assert image.shape == (1, 3, 32, 32) # test with different cutter settings cut_overview = [12] * 100 + [4] * 900 cut_innercut = [4] * 100 + [12] * 900 cut_ic_pow = [1] * 200 + [0] * 800 cut_icgray_p = [0.2] * 200 + [0] * 800 cutn_batches = 2 image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8, cut_overview=cut_overview, cut_innercut=cut_innercut, cut_ic_pow=cut_ic_pow, cut_icgray_p=cut_icgray_p, cutn_batches=cutn_batches)['samples'] assert image.shape == (1, 3, 32, 32) # test with different unet unet64 = DenoisingUnet( image_size=64, in_channels=3, base_channels=8, resblocks_per_downsample=2, attention_res=(8, ), norm_cfg=dict(type='GN32', num_groups=8), dropout=0.0, num_classes=0, use_fp16=True, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=2, num_head_channels=8, use_new_attention_order=False), use_scale_shift_norm=True).cuda() unet64.convert_to_fp16() self.disco_diffusion.unet = unet64 image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 64, 64) class affineMock(nn.Module): def __init__(self, *args, **kwargs): super().__init__() def forward(self, x): return x mock_path = ('mmagic.models.editors.disco_diffusion.guider.' 'TORCHVISION_VERSION') affine_mock_path = ('mmagic.models.editors.disco_diffusion.guider.T.' 'RandomAffine') with patch(affine_mock_path, new=affineMock): with patch(mock_path, '0.8.1'): image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 64, 64) with patch(mock_path, '0.9.0'): image = self.disco_diffusion.infer( text_prompts=text_prompts, show_progress=True, num_inference_steps=2, eta=0.8)['samples'] assert image.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion_clip_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase from unittest.mock import MagicMock, patch import torch import torch.nn as nn from mmagic.models.archs import TokenizerWrapper from mmagic.models.editors import ClipWrapper from mmagic.models.editors.disco_diffusion.clip_wrapper import \ EmbeddingLayerWithFixes class TestClipWrapper(TestCase): def test_clip_not_installed(self): with patch.dict('sys.modules', {'clip': None}): with self.assertRaises(ImportError): ClipWrapper('clip') def test_open_clip_not_installed(self): with patch.dict('sys.modules', {'open_clip': None}): with self.assertRaises(ImportError): ClipWrapper('open_clip') def test_transformers_not_installed(self): with patch.dict('sys.modules', {'transformers': None}): with self.assertRaises(ImportError): ClipWrapper('huggingface') @patch('clip.load') def test_clip_load(self, mock_clip_load): mock_model = MagicMock() mock_clip_load.return_value = (mock_model, None) model = ClipWrapper('clip', name='test_model') mock_clip_load.assert_called_once_with(name='test_model') self.assertEqual(model.model, mock_model) def test_open_clip_load(self): mock_model = MagicMock() create_model_mock = MagicMock() create_model_mock.return_value = mock_model open_clip_mock = MagicMock() open_clip_mock.create_model = create_model_mock with patch.dict('sys.modules', {'open_clip': open_clip_mock}): model = ClipWrapper('open_clip', model_name='RN50') create_model_mock.assert_called_once_with(model_name='RN50') self.assertEqual(model.model, mock_model) @patch('transformers.CLIPTextModel.from_pretrained') def test_huggingface_load(self, mock_from_pretrained): mock_model = MagicMock() mock_model.config = MagicMock() mock_from_pretrained.return_value = mock_model model = ClipWrapper( 'huggingface', pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', subfolder='text_encoder') mock_from_pretrained.assert_called_once_with( pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', subfolder='text_encoder') self.assertEqual(model.model, mock_model) self.assertEqual(model.model.config, mock_model.config) def test_embedding_layer_with_fixes(): embedding_layer = nn.Embedding(10, 15) print(embedding_layer.weight.shape) embedding_layer_wrapper = EmbeddingLayerWithFixes(embedding_layer) assert embedding_layer_wrapper.external_embeddings == [] # test naive forward input_ids = torch.randint(0, 10, (3, 20)).type(torch.long) out_feat = embedding_layer_wrapper(input_ids) print(out_feat.shape) tokenizer = TokenizerWrapper('openai/clip-vit-base-patch32') # 'Goodbye' in kiswahili tokenizer.add_placeholder_token('kwaheri', num_vec_per_token=1) # 'how much' in kiswahili tokenizer.add_placeholder_token('ngapi', num_vec_per_token=4) # test add single embedding new_embedding = { 'name': 'kwaheri', # 'Goodbye' in kiswahili 'embedding': torch.ones(1, 15) * 4, 'start': tokenizer.get_token_info('kwaheri')['start'], 'end': tokenizer.get_token_info('kwaheri')['end'] } embedding_layer_wrapper.add_embeddings(new_embedding) input_text = ['hello world, kwaheri!', 'hello world', 'kwaheri'] input_ids = tokenizer( input_text, padding='max_length', truncation=True, return_tensors='pt')['input_ids'] out_feat = embedding_layer_wrapper(input_ids) assert (out_feat[0, 4] == 4).all() assert (out_feat[2, 1] == 4).all() new_embedding = { 'name': 'ngapi', # 'how much' in kiswahili 'embedding': torch.ones(4, 15) * 2.3, 'start': tokenizer.get_token_info('ngapi')['start'], 'end': tokenizer.get_token_info('ngapi')['end'] } embedding_layer_wrapper.add_embeddings(new_embedding) input_text = ['hello, ngapi!', 'hello world', 'kwaheri my friend, ngapi?'] input_ids = tokenizer( input_text, padding='max_length', truncation=True, return_tensors='pt')['input_ids'] out_feat = embedding_layer_wrapper(input_ids) assert (out_feat[0, 3:7] == 2.3).all() assert (out_feat[2, 5:9] == 2.3).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_dreambooth/test_dreambooth.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import platform from unittest import TestCase from unittest.mock import MagicMock import pytest import torch import torch.nn as nn from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules test_dir = osp.join(osp.dirname(__file__), '../../../..', 'tests') config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') model_path = osp.join(test_dir, 'configs', 'tmp_weight') ckpt_path = osp.join(test_dir, 'configs', 'ckpt') register_all_modules() stable_diffusion_tiny_url = 'diffusers/tiny-stable-diffusion-torch' val_prompts = ['a sks dog in basket'] config = dict( type='DreamBooth', vae=dict(type='AutoencoderKL', sample_size=64), unet=dict( sample_size=64, type='UNet2DConditionModel', down_block_types=('DownBlock2D', ), up_block_types=('UpBlock2D', ), block_out_channels=(32, ), cross_attention_dim=16, ), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_tiny_url, subfolder='text_encoder'), tokenizer=stable_diffusion_tiny_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), dtype='fp32', data_preprocessor=dict(type='DataPreprocessor'), enable_xformers=False, val_prompts=val_prompts) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestControlStableDiffusion(TestCase): def setUp(self): # mock SiLU if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): from mmagic.models.editors.ddpm.denoising_unet import SiLU torch.nn.SiLU = SiLU dreambooth = MODELS.build(config) assert not any([p.requires_grad for p in dreambooth.vae.parameters()]) assert not any( [p.requires_grad for p in dreambooth.text_encoder.parameters()]) self.dreambooth = dreambooth def test_val_step(self): dreambooth = self.dreambooth data = dict( inputs=[torch.ones([3, 64, 64])], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(prompt, *args, **kwargs): length = len(prompt) return dict(samples=torch.randn(length, 3, 64, 64)) encode_prompt = dreambooth._encode_prompt infer = dreambooth.infer dreambooth._encode_prompt = mock_encode_prompt dreambooth.infer = mock_infer output = dreambooth.val_step(data) assert len(output) == 1 dreambooth._encode_prompt = encode_prompt dreambooth.infer = infer def test_test_step(self): dreambooth = self.dreambooth data = dict( inputs=[torch.ones([3, 64, 64])], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(prompt, *args, **kwargs): length = len(prompt) return dict(samples=torch.randn(length, 3, 64, 64)) encode_prompt = dreambooth._encode_prompt infer = dreambooth.infer dreambooth._encode_prompt = mock_encode_prompt dreambooth.infer = mock_infer output = dreambooth.test_step(data) assert len(output) == 1 dreambooth._encode_prompt = encode_prompt dreambooth.infer = infer def test_train_step(self): dreambooth = self.dreambooth data = dict( inputs=[torch.ones([3, 64, 64])], data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) optimizer = MagicMock() update_params = MagicMock() optimizer.update_params = update_params optim_wrapper = optimizer class mock_text_encoder(nn.Module): def __init__(self): super().__init__() def forward(self, *args, **kwargs): return [torch.randn(1, 5, 16)] dreambooth.text_encoder = mock_text_encoder() dreambooth.train_step(data, optim_wrapper) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_duf/test_duf.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.duf import DynamicUpsamplingFilter def test_dynamic_upsampling_filter(): """Test DynamicUpsamplingFilter.""" with pytest.raises(TypeError): # The type of filter_size must be tuple DynamicUpsamplingFilter(filter_size=3) with pytest.raises(ValueError): # The length of filter size must be 2 DynamicUpsamplingFilter(filter_size=(3, 3, 3)) duf = DynamicUpsamplingFilter(filter_size=(5, 5)) x = torch.rand(1, 3, 4, 4) filters = torch.rand(1, 25, 16, 4, 4) output = duf(x, filters) assert output.shape == (1, 48, 4, 4) duf = DynamicUpsamplingFilter(filter_size=(3, 3)) x = torch.rand(1, 3, 4, 4) filters = torch.rand(1, 9, 16, 4, 4) output = duf(x, filters) assert output.shape == (1, 48, 4, 4) # gpu (since it has dcn, only supports gpu testing) if torch.cuda.is_available(): duf = DynamicUpsamplingFilter(filter_size=(3, 3)).cuda() x = torch.rand(1, 3, 4, 4).cuda() filters = torch.rand(1, 9, 16, 4, 4).cuda() output = duf(x, filters) assert output.shape == (1, 48, 4, 4) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_edsr/test_edsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import EDSRNet def test_edsr_cpu(): """Test EDSRNet.""" # x2 model EDSRNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=2) # x3 model, initialization and forward (cpu) net = EDSRNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=3) img = torch.rand(1, 3, 12, 12) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 36, 36) # x4 modeland, initialization and forward (cpu) net = EDSRNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=4) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 48, 48) # gray x4 modeland, initialization and forward (cpu) net = EDSRNet( in_channels=1, out_channels=1, mid_channels=8, num_blocks=2, upscale_factor=4, rgb_mean=[0], rgb_std=[1]) gray = torch.rand((1, 1, 12, 12)) output = net(gray) assert isinstance(output, torch.Tensor) assert output.shape == (1, 1, 48, 48) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_edsr_cuda(): net = EDSRNet( in_channels=1, out_channels=1, mid_channels=8, num_blocks=2, upscale_factor=4, rgb_mean=[0], rgb_std=[1]) gray = torch.rand((1, 1, 12, 12)) # x4 model forward (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(gray.cuda()) assert isinstance(output, torch.Tensor) assert output.shape == (1, 1, 48, 48) with pytest.raises(ValueError): # Currently supported upscale_factor is 2^n and 3 EDSRNet( in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=5) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_edvr/test_edvr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import EDVR, EDVRNet from mmagic.models.losses import CharbonnierLoss from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() def test_edvr(): model = EDVR( generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=4, num_frames=5, deform_groups=1, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=True), pixel_loss=dict( type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict(tsa_iter=5000), data_preprocessor=dict(type='DataPreprocessor')) assert isinstance(model, EDVR) assert isinstance(model.generator, EDVRNet) assert isinstance(model.pixel_loss, CharbonnierLoss) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # prepare data inputs = torch.rand(1, 5, 3, 20, 20) target = torch.rand(5, 3, 80, 80) data_sample = DataSample(gt_img=target) data = dict(inputs=inputs, data_samples=[data_sample]) log_vars = model.train_step(data, optim_wrapper) assert model.generator.conv_first.weight.requires_grad is False assert isinstance(log_vars, dict) model.step_counter = torch.tensor(5000) log_vars = model.train_step(data, optim_wrapper) assert model.generator.conv_first.weight.requires_grad is True assert isinstance(log_vars, dict) with pytest.raises(KeyError): model = EDVR( generator=dict( type='EDVRNet', in_channels=3, out_channels=3, mid_channels=4, num_frames=5, deform_groups=1, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=True), pixel_loss=dict( type='CharbonnierLoss', loss_weight=1.0, reduction='sum'), train_cfg=dict()) model.train_step(data, optim_wrapper) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_edvr/test_edvr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.edvr.edvr_net import (EDVRNet, PCDAlignment, TSAFusion) def test_pcd_alignment(): """Test PCDAlignment.""" # cpu pcd_alignment = PCDAlignment(mid_channels=4, deform_groups=2) input_list = [] for i in range(3, 0, -1): input_list.append(torch.rand(1, 4, 2**i, 2**i)) pcd_alignment = pcd_alignment input_list = [v for v in input_list] output = pcd_alignment(input_list, input_list) assert output.shape == (1, 4, 8, 8) with pytest.raises(AssertionError): pcd_alignment(input_list[0:2], input_list) # gpu if torch.cuda.is_available(): pcd_alignment = PCDAlignment(mid_channels=4, deform_groups=2) input_list = [] for i in range(3, 0, -1): input_list.append(torch.rand(1, 4, 2**i, 2**i)) pcd_alignment = pcd_alignment.cuda() input_list = [v.cuda() for v in input_list] output = pcd_alignment(input_list, input_list) assert output.shape == (1, 4, 8, 8) with pytest.raises(AssertionError): pcd_alignment(input_list[0:2], input_list) def test_tsa_fusion(): """Test TSAFusion.""" # cpu tsa_fusion = TSAFusion(mid_channels=4, num_frames=5, center_frame_idx=2) input_tensor = torch.rand(1, 5, 4, 8, 8) output = tsa_fusion(input_tensor) assert output.shape == (1, 4, 8, 8) # gpu if torch.cuda.is_available(): tsa_fusion = tsa_fusion.cuda() input_tensor = input_tensor.cuda() output = tsa_fusion(input_tensor) assert output.shape == (1, 4, 8, 8) def test_edvr_net(): """Test EDVRNet.""" # cpu # with tsa edvrnet = EDVRNet( 3, 3, mid_channels=8, num_frames=5, deform_groups=2, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=True) input_tensor = torch.rand(1, 5, 3, 8, 8) output = edvrnet(input_tensor) assert output.shape == (1, 3, 32, 32) # without tsa edvrnet = EDVRNet( 3, 3, mid_channels=8, num_frames=5, deform_groups=2, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=False) output = edvrnet(input_tensor) assert output.shape == (1, 3, 32, 32) with pytest.raises(AssertionError): # The height and width of inputs should be a multiple of 4 input_tensor = torch.rand(1, 5, 3, 3, 3) edvrnet(input_tensor) # gpu if torch.cuda.is_available(): # with tsa edvrnet = EDVRNet( 3, 3, mid_channels=8, num_frames=5, deform_groups=2, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=True).cuda() input_tensor = torch.rand(1, 5, 3, 8, 8).cuda() output = edvrnet(input_tensor) assert output.shape == (1, 3, 32, 32) # without tsa edvrnet = EDVRNet( 3, 3, mid_channels=8, num_frames=5, deform_groups=2, num_blocks_extraction=1, num_blocks_reconstruction=1, center_frame_idx=2, with_tsa=False).cuda() output = edvrnet(input_tensor) assert output.shape == (1, 3, 32, 32) with pytest.raises(AssertionError): # The height and width of inputs should be a multiple of 4 input_tensor = torch.rand(1, 5, 3, 3, 3).cuda() edvrnet(input_tensor) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_camera.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math from copy import deepcopy from unittest import TestCase from unittest.mock import patch import torch from mmengine.testing import assert_allclose from mmagic.models.editors.eg3d.camera import (BaseCamera, GaussianCamera, UniformCamera) class TestBaseCamera(TestCase): def setUp(self): self.default_cfg = dict( horizontal_mean=0, vertical_mean=3.141 / 2, horizontal_std=3.141 * 2, vertical_std=3.141 / 2, focal=1.025390625, radius=1.3) def test_init(self): cfg_ = deepcopy(self.default_cfg) camera = BaseCamera(**cfg_) self.assertEqual(camera.sampling_statregy.upper(), 'UNIFORM') cfg_ = deepcopy(self.default_cfg) cfg_['sampling_strategy'] = 'gaussian' camera = BaseCamera(**cfg_) self.assertEqual(camera.sampling_statregy.upper(), 'GAUSSIAN') # test FOV and FOCAL is both passed cfg_ = deepcopy(self.default_cfg) cfg_['fov'] = 2333 with self.assertRaises(AssertionError): BaseCamera(**cfg_) # test FOV and FOCAL is neither passed cfg_ = deepcopy(self.default_cfg) cfg_['focal'] = None camera = BaseCamera(**cfg_) self.assertIsNone(camera.focal) self.assertIsNone(camera.fov) def test_repr(self): cfg_ = deepcopy(self.default_cfg) camera = BaseCamera(**cfg_) repr_string = repr(camera) attribute_list = [ 'horizontal_mean', 'vertical_mean', 'horizontal_std', 'vertical_std', 'focal', 'look_at', 'up', 'radius', 'sampling_statregy' ] for attr in attribute_list: self.assertIn(attr, repr_string) self.assertIn('BaseCamera', repr_string) cfg_ = deepcopy(self.default_cfg) cfg_['focal'] = None camera = BaseCamera(**cfg_) repr_string = repr(camera) self.assertNotIn('focal', repr_string) self.assertNotIn('fov', repr_string) def test_sample_intrinsic(self): target = [1.025390625, 0.0, 0.5, 0.0, 1.025390625, 0.5, 0.0, 0.0, 1.0] target = torch.FloatTensor(target).reshape(3, 3) # test sample with default focal cfg_ = deepcopy(self.default_cfg) camera = BaseCamera(**cfg_) intrinsic = camera.sample_intrinsic(batch_size=3) assert_allclose(intrinsic, target[None, ...].repeat(3, 1, 1)) # test sample with default FOV cfg_ = deepcopy(self.default_cfg) cfg_['focal'] = None cfg_['fov'] = 69.18818449595669 camera = BaseCamera(**cfg_) intrinsic = camera.sample_intrinsic(batch_size=4) assert_allclose(intrinsic, target[None, ...].repeat(4, 1, 1)) # test sample fov and focal is passed at the same time with self.assertRaises(AssertionError): intrinsic = camera.sample_intrinsic(fov=1, focal=2, batch_size=4) # test focal is passed intrinsic = camera.sample_intrinsic(focal=1, batch_size=4) self.assertTrue((intrinsic[:, 0, 0] == 1).all()) self.assertTrue((intrinsic[:, 1, 1] == 1).all()) # test fov is passed target_focal = float(1 / (math.tan(1 * math.pi / 360) * 1.414)) intrinsic = camera.sample_intrinsic(fov=1, batch_size=4) self.assertTrue((intrinsic[:, 0, 0] == target_focal).all()) self.assertTrue((intrinsic[:, 1, 1] == target_focal).all()) # test focal and fov is not passed and not be initialized cfg_ = deepcopy(self.default_cfg) cfg_['focal'] = None camera = BaseCamera(**cfg_) with self.assertRaises(ValueError): camera.sample_intrinsic(batch_size=4) def test_sample_camera2world(self): cfg_ = deepcopy(self.default_cfg) camera = BaseCamera(**cfg_) cam2world = camera.sample_camera2world() self.assertEqual(cam2world.shape, (1, 4, 4)) mock_path = 'mmagic.models.editors.eg3d.camera.TORCH_VERSION' with patch(mock_path, '1.6.0'): print(torch.__version__) cfg_ = deepcopy(self.default_cfg) camera = BaseCamera(**cfg_) cam2world = camera.sample_camera2world() self.assertEqual(cam2world.shape, (1, 4, 4)) def test_sample_in_range(self): cfg_ = deepcopy(self.default_cfg) cfg_['sampling_strategy'] = 'unknow' camera = BaseCamera(**cfg_) with self.assertRaises(ValueError): camera._sample_in_range(1, 1, 1) class TestUniformCamera(TestCase): def setUp(self): self.default_cfg = dict( horizontal_mean=0, vertical_mean=3.141 / 2, horizontal_std=3.141 * 2, vertical_std=3.141 / 2, focal=1.025390625, radius=1.3) def test_init(self): cfg_ = deepcopy(self.default_cfg) camera = UniformCamera(**cfg_) self.assertEqual(camera.sampling_statregy.upper(), 'UNIFORM') def test_repr(self): cfg_ = deepcopy(self.default_cfg) camera = UniformCamera(**cfg_) repr_string = repr(camera) self.assertIn('UniformCamera', repr_string) class TestGaussianCamera(TestCase): def setUp(self): self.default_cfg = dict( horizontal_mean=0, vertical_mean=3.141 / 2, horizontal_std=3.141 * 2, vertical_std=3.141 / 2, focal=1.025390625, radius=1.3) def test_init(self): cfg_ = deepcopy(self.default_cfg) camera = GaussianCamera(**cfg_) self.assertEqual(camera.sampling_statregy.upper(), 'GAUSSIAN') def test_repr(self): cfg_ = deepcopy(self.default_cfg) camera = GaussianCamera(**cfg_) repr_string = repr(camera) self.assertIn('GaussianCamera', repr_string) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_dual_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy from unittest import TestCase import pytest import torch from mmagic.models.editors.eg3d.dual_discriminator import DualDiscriminator class TestEG3DDiscriminator(TestCase): def setUp(self): self.default_cfg = dict(in_size=32, cond_size=25) def test_init(self): cfg = deepcopy(self.default_cfg) disc = DualDiscriminator(**cfg) self.assertEqual(disc.convs[0][0].conv.weight.shape[1], 6) self.assertTrue(disc.use_dual_disc) cfg = deepcopy(self.default_cfg) cfg['use_dual_disc'] = False cfg['img_channels'] = 2 disc = DualDiscriminator(**cfg) self.assertEqual(disc.convs[0][0].conv.weight.shape[1], 2) self.assertFalse(disc.use_dual_disc) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_forward(self): cfg = deepcopy(self.default_cfg) disc = DualDiscriminator(**cfg) img, img_raw = torch.randn(2, 3, 32, 32), torch.randn(2, 3, 16, 16) cond = torch.randn(2, 25) out = disc(img, img_raw, cond) self.assertEqual(out.shape, (2, 1)) # test raise error with img_raw is None with self.assertRaises(AssertionError): disc(img, None, cond) # test cond_noise is not None cfg = deepcopy(self.default_cfg) cfg['disc_c_noise'] = 0.2 disc = DualDiscriminator(**cfg) img, img_raw = torch.randn(2, 3, 32, 32), torch.randn(2, 3, 16, 16) cond = torch.randn(2, 25) out = disc(img, img_raw, cond) self.assertEqual(out.shape, (2, 1)) # test input_bgr2rgb cfg = deepcopy(self.default_cfg) cfg['input_bgr2rgb'] = True disc = DualDiscriminator(**cfg) img, img_raw = torch.randn(2, 3, 32, 32), torch.randn(2, 3, 16, 16) cond = torch.randn(2, 25) out = disc(img, img_raw, cond) self.assertEqual(out.shape, (2, 1)) # test img_raw is None + use_dual_disc is False cfg = deepcopy(self.default_cfg) cfg['use_dual_disc'] = False disc = DualDiscriminator(**cfg) img = torch.randn(2, 3, 32, 32) cond = torch.randn(2, 25) out = disc(img, None, cond) self.assertEqual(out.shape, (2, 1)) # test img_raw is None + use_dual_disc is False + input_bgr2rgb cfg = deepcopy(self.default_cfg) cfg['use_dual_disc'] = False cfg['input_bgr2rgb'] = True disc = DualDiscriminator(**cfg) img = torch.randn(2, 3, 32, 32) cond = torch.randn(2, 25) out = disc(img, None, cond) self.assertEqual(out.shape, (2, 1)) # test cond is None cfg = deepcopy(self.default_cfg) cfg['cond_size'] = None disc = DualDiscriminator(**cfg) out = disc(img, img_raw, None) self.assertEqual(out.shape, (2, 1)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_eg3d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import MagicMock import torch import torch.nn as nn from mmagic.models.editors.eg3d.eg3d import EG3D from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestEG3D(TestCase): def setUp(self): self.generator_cfg = dict( type='TriplaneGenerator', out_size=32, noise_size=8, style_channels=8, num_mlps=1, triplane_size=8, triplane_channels=4, sr_in_size=8, sr_in_channels=8, neural_rendering_resolution=5, cond_scale=1, renderer_cfg=dict( ray_start=0.1, ray_end=2.6, box_warp=1.6, depth_resolution=4, white_back=True, depth_resolution_importance=4, ), rgb2bgr=True) self.camera_cfg = dict( type='UniformCamera', horizontal_mean=3.141, horizontal_std=3.141, vertical_mean=3.141 / 2, vertical_std=3.141 / 2, focal=1.025390625, up=[0, 0, 1], radius=1.2) # self.discriminator_cfg = dict() self.default_cfg = dict( generator=self.generator_cfg, camera=self.camera_cfg, data_preprocessor=dict(type='DataPreprocessor')) def test_init(self): cfg_ = deepcopy(self.default_cfg) model = EG3D(**cfg_) self.assertEqual(model.noise_size, 8) self.assertEqual(model.num_classes, None) self.assertIsNotNone(model.camera) # test camera is None cfg_ = deepcopy(self.default_cfg) cfg_['camera'] = None model = EG3D(**cfg_) self.assertIsNone(model.camera) # test camers is module camera_mock = MagicMock(spec=nn.Module) cfg_['camera'] = camera_mock model = EG3D(**cfg_) self.assertEqual(model.camera, camera_mock) def test_label_fn(self): # test camera is None cfg_ = deepcopy(self.default_cfg) cfg_['camera'] = None model = EG3D(**cfg_) label = torch.randn(1, 25) self.assertTrue((label == model.label_fn(label)).all()) with self.assertRaises(AssertionError): model.label_fn(None) def _check_datasample_output(self, outputs, out_size, n_points): target_keys = [ 'fake_img', 'depth', 'lr_img', 'ray_origins', 'ray_directions' ] target_shape = [(3, out_size, out_size), (1, n_points, n_points), (3, n_points, n_points), (n_points**2, 3), (n_points**2, 3)] for output in outputs: for key, shape in zip(target_keys, target_shape): self.assertTrue(hasattr(output, key)) self.assertEqual(getattr(output, key).shape, shape) def _check_dict_output(self, outputs, out_size, n_points, bz): target_keys = [ 'fake_img', 'depth', 'lr_img', 'ray_origins', 'ray_directions' ] target_shape = [(bz, 3, out_size, out_size), (bz, 1, n_points, n_points), (bz, 3, n_points, n_points), (bz, n_points**2, 3), (bz, n_points**2, 3)] for output in outputs: for key, shape in zip(target_keys, target_shape): self.assertIn(key, output) self.assertEqual(output[key].shape, shape) def test_forward(self): cfg_ = deepcopy(self.default_cfg) model = EG3D(**cfg_) outputs = model(dict(num_batches=4)) self.assertEqual(len(outputs), 4) # test label is passed data_samples = [] for _ in range(4): data_sample = DataSample() data_sample.set_gt_label(torch.randn(25)) data_samples.append(data_sample) data_samples = DataSample.stack(data_samples) outputs = model(dict(num_batches=4), data_samples) self.assertEqual(len(outputs), 4) self._check_datasample_output(outputs, 32, 5) # test noise is passed outputs = model(torch.randn(4, 8)) self.assertEqual(len(outputs), 4) self._check_datasample_output(outputs, 32, 5) # test orig/ema cfg_ = deepcopy(self.default_cfg) cfg_['ema_config'] = dict(interval=1) model = EG3D(**cfg_) outputs = model(dict(num_batches=4, sample_model='ema/orig')) self.assertEqual(len(outputs), 4) self.assertTrue(all([hasattr(output, 'orig') for output in outputs])) self.assertTrue(all([hasattr(output, 'ema') for output in outputs])) self._check_datasample_output([output.orig for output in outputs], 32, 5) self._check_datasample_output([output.ema for output in outputs], 32, 5) def test_interpolation(self): cfg_ = deepcopy(self.default_cfg) model = EG3D(**cfg_) output_list = model.interpolation(num_images=3, num_batches=2) self.assertEqual(len(output_list), 3) self._check_dict_output(output_list, 32, 5, 2) output_list = model.interpolation( num_images=3, num_batches=2, mode='camera', show_pbar=False) self.assertEqual(len(output_list), 3) self._check_dict_output(output_list, 32, 5, 2) output_list = model.interpolation( num_images=3, num_batches=2, mode='conditioning', show_pbar=False) self.assertEqual(len(output_list), 3) self._check_dict_output(output_list, 32, 5, 2) # test ema cfg_ = deepcopy(self.default_cfg) cfg_['ema_config'] = dict(interval=1) model = EG3D(**cfg_) output_list = model.interpolation( num_images=3, num_batches=2, sample_model='ema') self.assertEqual(len(output_list), 3) self._check_dict_output(output_list, 32, 5, 2) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_eg3d_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import Mock, patch import torch from mmagic.models.editors.eg3d.eg3d_generator import TriplaneGenerator class TestEG3DGenerator(TestCase): def setUp(self): self.default_cfg = dict( out_size=32, noise_size=8, style_channels=8, num_mlps=1, triplane_size=8, triplane_channels=4, sr_in_size=8, sr_in_channels=8, neural_rendering_resolution=5, cond_scale=1, renderer_cfg=dict( ray_start=0.1, ray_end=2.6, box_warp=1.6, depth_resolution=4, white_back=True, depth_resolution_importance=4, ), rgb2bgr=True) def test_init(self): cfg_ = deepcopy(self.default_cfg) gen = TriplaneGenerator(**cfg_) # check decoder in/out channels decoder_in_chns = gen.renderer.decoder.net[0].weight.shape[1] decoder_out_chns = gen.renderer.decoder.net[-1].weight.shape[0] self.assertEqual(decoder_in_chns, 4) self.assertEqual(decoder_out_chns, 8 + 1) # (sr_in_channels + 1) # test sr_factor not in [2, 4, 8] cfg_ = deepcopy(self.default_cfg) cfg_['out_size'] = 64 with self.assertRaises(AssertionError): TriplaneGenerator(**cfg_) cfg_['out_size'] = 10 with self.assertRaises(AssertionError): TriplaneGenerator(**cfg_) def test_forward(self): cfg_ = deepcopy(self.default_cfg) gen = TriplaneGenerator(**cfg_) noise = torch.randn(2, 8) cond = torch.randn(2, 25) out = gen(noise, cond) self.assertEqual(out['fake_img'].shape, (2, 3, 32, 32)) self.assertEqual(out['lr_img'].shape, (2, 3, 5, 5)) self.assertEqual(out['depth'].shape, (2, 1, 5, 5)) self.assertEqual(out['ray_directions'].shape, (2, 25, 3)) self.assertEqual(out['ray_origins'].shape, (2, 25, 3)) # test render_kwargs is work in forward render_kwargs = dict(a=1, b='b') render_mock = Mock( return_value=(torch.randn(2, 25, 8), torch.randn(2, 25, 1), None)) patch_func = 'mmagic.models.editors.eg3d.renderer.EG3DRenderer.forward' with patch(patch_func, new=render_mock): gen = TriplaneGenerator(**cfg_) gen(noise, cond, render_kwargs=render_kwargs) _, called_kwargs = render_mock.call_args self.assertIn('render_kwargs', called_kwargs) self.assertDictEqual(called_kwargs['render_kwargs'], render_kwargs) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_eg3d_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmagic.models.editors.eg3d.eg3d_modules import (SuperResolutionModule, TriPlaneBackbone) class TestTriPlaneBackbone(TestCase): def setUp(self): self.default_cfg = dict( out_size=32, noise_size=10, out_channels=9, style_channels=16, num_mlps=2, cond_size=4, cond_scale=1, cond_mapping_channels=4, zero_cond_input=False) def test_init(self): cfg_ = deepcopy(self.default_cfg) backbone = TriPlaneBackbone(**cfg_) self.assertEqual(backbone.cond_scale, 1) self.assertEqual(backbone.zero_cond_input, False) def test_mapping(self): cfg_ = deepcopy(self.default_cfg) backbone = TriPlaneBackbone(**cfg_) noise = torch.randn(2, 10) label = torch.randn(2, 4) style_code = backbone.mapping(noise, label) self.assertEqual(style_code.shape, (2, 16)) # test truncation < 1 style_code = backbone.mapping(noise, label, truncation=0.5) self.assertEqual(style_code.shape, (2, 16)) style_code = backbone.mapping(noise, label, truncation=0.5) self.assertEqual(style_code.shape, (2, 16)) # test zero_cond_input + label is None cfg_ = deepcopy(self.default_cfg) cfg_['zero_cond_input'] = True backbone = TriPlaneBackbone(**cfg_) style_code = backbone.mapping(noise) self.assertEqual(style_code.shape, (2, 16)) # test zero_cond_input + label is not None style_code = backbone.mapping(noise, label) self.assertEqual(style_code.shape, (2, 16)) # test cond_size < 0 cfg_ = deepcopy(self.default_cfg) cfg_['cond_size'] = None backbone = TriPlaneBackbone(**cfg_) # noise = torch.randn(2, 10) style_code = backbone.mapping(noise) self.assertEqual(style_code.shape, (2, 16)) def test_synthesis(self): cfg_ = deepcopy(self.default_cfg) backbone = TriPlaneBackbone(**cfg_) noise = torch.randn(2, 10) label = torch.randn(2, 4) style_code = backbone.mapping(noise, label) outputs_forward = backbone(noise, label) outputs_synthesis = backbone.synthesis(style_code) self.assertTrue((outputs_forward == outputs_synthesis).all()) class TestSuperResolutionModule(TestCase): def setUp(self): self.default_cfg = dict( in_channels=8, in_size=4, hidden_size=8, out_size=8, style_channels=5, sr_antialias=True) def test_init(self): cfg_ = deepcopy(self.default_cfg) sr_model = SuperResolutionModule(**cfg_) self.assertTrue(sr_model.block0.upsample) self.assertFalse(sr_model.block1.upsample) cfg_ = deepcopy(self.default_cfg) cfg_['hidden_size'] = 4 sr_model = SuperResolutionModule(**cfg_) self.assertFalse(sr_model.block0.upsample) self.assertTrue(sr_model.block1.upsample) def test_forward(self): cfg_ = deepcopy(self.default_cfg) sr_model = SuperResolutionModule(**cfg_) styles = torch.randn(2, 5) imgs = torch.randn(2, 3, 4, 4) features = torch.randn(2, 8, 4, 4) sr_imgs = sr_model(imgs, features, styles) self.assertEqual(sr_imgs.shape, (2, 3, 8, 8)) # test style is a list styles = [torch.randn(2, 5)] imgs = torch.randn(2, 3, 4, 4) features = torch.randn(2, 8, 4, 4) sr_imgs = sr_model(imgs, features, styles) self.assertEqual(sr_imgs.shape, (2, 3, 8, 8)) # test style's ndim is 3 styles = torch.randn(3, 2, 5) imgs = torch.randn(2, 3, 4, 4) features = torch.randn(2, 8, 4, 4) sr_imgs = sr_model(imgs, features, styles) self.assertEqual(sr_imgs.shape, (2, 3, 8, 8)) # test interpolation imgs = torch.randn(2, 3, 3, 3) features = torch.randn(2, 8, 3, 3) sr_imgs = sr_model(imgs, features, styles) self.assertEqual(sr_imgs.shape, (2, 3, 8, 8)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_eg3d_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.eg3d.eg3d_utils import (get_ray_limits_box, inverse_transform_sampling, linspace_batch) def test_get_ray_limits_box_and_linspace_batch(): rays_o = torch.rand(2, 4, 4, 3) rays_d = torch.rand(2, 4, 4, 3) rays_start, rays_end = get_ray_limits_box(rays_o, rays_d, 0.5) assert rays_start.shape == (2, 4, 4, 1) assert rays_end.shape == (2, 4, 4, 1) # linspace sampled_depth = linspace_batch(rays_start, rays_end, 5) assert sampled_depth.shape == (5, 2, 4, 4, 1) def test_inverse_transform_sampling(): bins = torch.randn(10, 11) weights = torch.randn(10, 9) n_importance = 5 samples = inverse_transform_sampling(bins, weights, n_importance) assert samples.shape == (10, 5) samples_det_1 = inverse_transform_sampling( bins, weights, n_importance, deterministic=True) samples_det_2 = inverse_transform_sampling( bins, weights, n_importance, deterministic=True) assert samples_det_1.shape == (10, 5) assert samples_det_2.shape == (10, 5) assert (samples_det_1 == samples_det_2).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_ray_sampler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.eg3d.ray_sampler import sample_rays def test_sample_rays(): cond1 = [ 0.5186675190925598, -0.8265361189842224, -0.21868225932121277, 0.2842874228954315, 0.8549759387969971, 0.5014145970344543, 0.13266240060329437, -0.17246174812316895, 2.3841852225814364e-07, -0.2557757496833801, 0.9667359590530396, -1.2567564249038696, -0.0, 0.0, -0.0, 1.0, 1.025390625, 0.0, 0.5, 0.0, 1.025390625, 0.5, 0.0, 0.0, 1.0 ] cond2 = [ 0.828181266784668, -0.29340365529060364, -0.47752493619918823, 0.6207822561264038, 0.5604602694511414, 0.43355682492256165, 0.7056292295455933, -0.9173181653022766, -2.9802322387695312e-08, -0.8520227670669556, 0.5235047340393066, -0.680556058883667, -0.0, 0.0, -0.0, 1.0, 1.025390625, 0.0, 0.5, 0.0, 1.025390625, 0.5, 0.0, 0.0, 1.0 ] cond1, cond2 = torch.FloatTensor(cond1), torch.FloatTensor(cond2) cond = torch.stack((cond1, cond2)) cam2world = cond[:, :16].view(-1, 4, 4) intrinsics = cond[:, 16:25].view(-1, 3, 3) resolution = 16 ray_origins, ray_directions = sample_rays(cam2world, intrinsics, resolution) assert ray_origins.shape[:2] == (2, resolution**2) assert ray_directions.shape[:2] == (2, resolution**2) # check if camera origin in one batch is all same for origin in ray_origins: assert (origin == origin[0]).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_eg3d/test_renderer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase from unittest.mock import Mock, patch import torch from mmagic.models.editors.eg3d.renderer import EG3DDecoder, EG3DRenderer class TestEG3DRenderer(TestCase): def setUp(self) -> None: self.n_tri, self.tri_feat, self.tri_res = 3, 16, 8 self.nerf_res = 10 self.decoder_out_channels = 5 self.decoder_rgb_padding = 0.233 self.decoder_cfg = dict( in_channels=self.tri_feat, hidden_channels=10, out_channels=self.decoder_out_channels, rgb_padding=self.decoder_rgb_padding) self.renderer_cfg = dict( ray_start=0.1, ray_end=2.6, box_warp=1.6, depth_resolution=5, white_back=True, depth_resolution_importance=10, decoder_cfg=deepcopy(self.decoder_cfg)) def test_init(self): cfg_ = deepcopy(self.renderer_cfg) renderer = EG3DRenderer(**cfg_) self.assertIsInstance(renderer.decoder, EG3DDecoder) self.assertEqual(renderer.decoder.rgb_padding, self.decoder_rgb_padding) def test_forward(self): nerf_res = self.nerf_res n_tri, tri_feat, tri_res = self.n_tri, self.tri_feat, self.tri_res plane = torch.randn(4, n_tri, tri_feat, tri_res, tri_res) ray_origins = torch.randn(4, nerf_res * nerf_res, 3) ray_directions = torch.randn(4, nerf_res * nerf_res, 3) cfg_ = deepcopy(self.renderer_cfg) renderer = EG3DRenderer(**cfg_) rgb, depth, weights = renderer(plane, ray_origins, ray_directions) self.assertEqual(rgb.shape, (4, nerf_res * nerf_res, self.decoder_out_channels)) self.assertEqual(depth.shape, (4, nerf_res * nerf_res, 1)) self.assertEqual(weights.shape, (4, nerf_res * nerf_res, 1)) # test white_back is True + density_noise > 0 cfg_ = deepcopy(self.renderer_cfg) cfg_['white_back'] = False cfg_['density_noise'] = 2 renderer = EG3DRenderer(**cfg_) rgb, depth, weights = renderer(plane, ray_origins, ray_directions) self.assertEqual(rgb.shape, (4, nerf_res * nerf_res, self.decoder_out_channels)) self.assertEqual(depth.shape, (4, nerf_res * nerf_res, 1)) self.assertEqual(weights.shape, (4, nerf_res * nerf_res, 1)) # test ray_start and end is auto cfg_ = deepcopy(self.renderer_cfg) cfg_['ray_start'] = cfg_['ray_end'] = 'auto' renderer = EG3DRenderer(**cfg_) rgb, depth, weights = renderer(plane, ray_origins, ray_directions) self.assertEqual(rgb.shape, (4, nerf_res * nerf_res, self.decoder_out_channels)) self.assertEqual(depth.shape, (4, nerf_res * nerf_res, 1)) self.assertEqual(weights.shape, (4, nerf_res * nerf_res, 1)) # test clamp mode is valid cfg_ = deepcopy(self.renderer_cfg) cfg_['clamp_mode'] = 'unsupport' renderer = EG3DRenderer(**cfg_) with self.assertRaises(AssertionError): renderer(plane, ray_origins, ray_directions) # test without hierarchical sampling + test render_kwargs render_kwargs = dict(depth_resolution_importance=0) mock_func = Mock(return_value=(rgb, depth, weights[..., None])) mock_path = ('mmagic.models.editors.eg3d.renderer.EG3DRenderer.' 'volume_rendering') with patch(mock_path, new=mock_func): renderer = EG3DRenderer(**cfg_) renderer( plane, ray_origins, ray_directions, render_kwargs=render_kwargs) mock_func.assert_called_once() # cover TORCH_VERSION < 1.8.0 mock_path = 'mmagic.models.editors.eg3d.renderer.TORCH_VERSION' with patch(mock_path, '1.6.0'): cfg_ = deepcopy(self.renderer_cfg) renderer = EG3DRenderer(**cfg_) renderer( plane, ray_origins, ray_directions, render_kwargs=render_kwargs) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_esrgan/test_esrgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import patch import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import ESRGAN, DataPreprocessor, ModifiedVGG, RRDBNet from mmagic.models.losses import GANLoss, L1Loss, PerceptualLoss, PerceptualVGG from mmagic.structures import DataSample @patch.object(PerceptualVGG, 'init_weights') def test_esrgan(init_weights): model = ESRGAN( generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=4, num_blocks=4, growth_channels=4, upscale_factor=4), discriminator=dict(type='ModifiedVGG', in_channels=3, mid_channels=64), pixel_loss=dict(type='L1Loss', loss_weight=1e-2, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'34': 1.0}, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-3, real_label_val=1.0, fake_label_val=0), train_cfg=None, test_cfg=None, data_preprocessor=DataPreprocessor()) assert isinstance(model, ESRGAN) assert isinstance(model.generator, RRDBNet) assert isinstance(model.discriminator, ModifiedVGG) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.perceptual_loss, PerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 32, 32) target = torch.rand(3, 128, 128) data_sample = DataSample(gt_img=target) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.data.shape == (3, 128, 128) # feat output = model(torch.rand(1, 3, 32, 32), mode='tensor') assert output.shape == (1, 3, 128, 128) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_esrgan/test_rrdb_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models import RRDBNet def test_rrdbnet_backbone(): """Test RRDBNet backbone.""" # model, initialization and forward (cpu) # x4 model net = RRDBNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, growth_channels=4, upscale_factor=4) input_shape = (1, 3, 12, 12) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 3, 48, 48) # x3 model with pytest.raises(ValueError): net = RRDBNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, growth_channels=4, upscale_factor=3) # x2 model net = RRDBNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, growth_channels=4, upscale_factor=2) input_shape = (1, 3, 12, 12) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 3, 24, 24) # model forward (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 3, 24, 24) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_fastcomposer/test_fastcomposer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import gc import platform from unittest import TestCase import numpy as np import pytest import torch from PIL import Image from mmagic.registry import MODELS from mmagic.utils import register_all_modules gc.collect() torch.cuda.empty_cache() register_all_modules() stable_diffusion_tiny_url = 'diffusers/tiny-stable-diffusion-torch' finetuned_model_path = '' vision_config = dict( attention_dropout=0.0, dropout=0.0, hidden_act='quick_gelu', hidden_size=1024, image_size=64, initializer_factor=1.0, initializer_range=0.02, intermediate_size=64, layer_norm_eps=1e-05, model_type='clip_vision_model', num_attention_heads=16, num_channels=3, num_hidden_layers=24, patch_size=14, projection_dim=768, transformers_version='4.29.1') config = dict( type='FastComposer', vae=dict(type='AutoencoderKL', sample_size=64), unet=dict( sample_size=64, type='UNet2DConditionModel', down_block_types=('DownBlock2D', ), up_block_types=('UpBlock2D', ), block_out_channels=(32, ), cross_attention_dim=16, ), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_tiny_url, subfolder='text_encoder'), tokenizer=stable_diffusion_tiny_url, pretrained_cfg=dict( finetuned_model_path=finetuned_model_path, enable_xformers_memory_efficient_attention=None, pretrained_model_name_or_path=stable_diffusion_tiny_url, image_encoder=vision_config, revision=None, non_ema_revision=None, object_localization=None, object_localization_weight=0.01, localization_layers=5, mask_loss=None, mask_loss_prob=0.5, object_localization_threshold=1.0, object_localization_normalize=None, no_object_augmentation=True, object_resolution=64), scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), dtype='fp32', data_preprocessor=dict(type='DataPreprocessor')) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') class TestFastComposer(TestCase): def setUp(self): self.fastcomposer = MODELS.build(config) def test_infer(self): fastcomposer = self.fastcomposer def mock_encode_prompt(prompt, do_classifier_free_guidance, num_images_per_prompt, *args, **kwargs): batch_size = len(prompt) if isinstance(prompt, list) else 1 batch_size *= num_images_per_prompt if do_classifier_free_guidance: batch_size *= 2 return torch.randn(batch_size, 5, 16) # 2 for cfg encode_prompt = fastcomposer._encode_prompt fastcomposer._encode_prompt = mock_encode_prompt prompt = 'A man img' negative_prompt = '' alpha_ = 0.75 guidance_scale = 5 num_steps = 1 num_images = 1 image = [] seed = -1 augmented_prompt_embeds = torch.randn(1, 5, 16) image.append( Image.fromarray( np.random.randint(0, 255, size=(64, 64, 3)).astype('uint8'))) if len(image) == 0: raise Exception('You need to upload at least one image.') num_subject_in_text = (np.array( self.fastcomposer.special_tokenizer.encode(prompt)) == self.fastcomposer.image_token_id).sum() if num_subject_in_text != len(image): raise Exception( "Number of subjects in the text description doesn't match " 'the number of reference images, #text subjects: ' f'{num_subject_in_text} #reference image: {len(image)}', ) if seed == -1: seed = np.random.randint(0, 1000000) generator = torch.manual_seed(seed) result = fastcomposer.infer( prompt, negative_prompt=negative_prompt, height=64, width=64, num_inference_steps=num_steps, guidance_scale=guidance_scale, num_images_per_prompt=num_images, generator=generator, alpha_=alpha_, reference_subject_images=image, augmented_prompt_embeds=augmented_prompt_embeds, output_type='tensor') fastcomposer._encode_prompt = encode_prompt assert result['samples'].shape == (num_images, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_fba/test_fba_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors import FBADecoder def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def test_fba_decoder(): with pytest.raises(AssertionError): # pool_scales must be list|tuple FBADecoder(pool_scales=1, in_channels=32, channels=16) inputs = dict() conv_out_1 = _demo_inputs((1, 11, 320, 320)) conv_out_2 = _demo_inputs((1, 64, 160, 160)) conv_out_3 = _demo_inputs((1, 256, 80, 80)) conv_out_4 = _demo_inputs((1, 512, 40, 40)) conv_out_5 = _demo_inputs((1, 1024, 40, 40)) conv_out_6 = _demo_inputs((1, 2048, 40, 40)) inputs['conv_out'] = [ conv_out_1, conv_out_2, conv_out_3, conv_out_4, conv_out_5, conv_out_6 ] inputs['merged'] = _demo_inputs((1, 3, 320, 320)) inputs['two_channel_trimap'] = _demo_inputs((1, 2, 320, 320)) model = FBADecoder( pool_scales=(1, 2, 3, 6), in_channels=2048, channels=256, norm_cfg=dict(type='GN', num_groups=32)) alpha, F, B = model(inputs) assert_tensor_with_shape(alpha, torch.Size([1, 1, 320, 320])) assert_tensor_with_shape(F, torch.Size([1, 3, 320, 320])) assert_tensor_with_shape(B, torch.Size([1, 3, 320, 320])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_fba/test_fba_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors import FBAResnetDilated def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def test_fba_encoder(): """Test FBA encoder.""" with pytest.raises(KeyError): # ResNet depth should be in [18, 34, 50, 101, 152] FBAResnetDilated( 20, in_channels=11, stem_channels=64, base_channels=64, ) with pytest.raises(AssertionError): # In ResNet: 1 <= num_stages <= 4 FBAResnetDilated( 50, in_channels=11, stem_channels=64, base_channels=64, num_stages=0) with pytest.raises(AssertionError): # In ResNet: 1 <= num_stages <= 4 FBAResnetDilated( 50, in_channels=11, stem_channels=64, base_channels=64, num_stages=5) with pytest.raises(AssertionError): # len(strides) == len(dilations) == num_stages FBAResnetDilated( 50, in_channels=11, stem_channels=64, base_channels=64, strides=(1, ), dilations=(1, 1), num_stages=3) with pytest.raises(TypeError): # pretrained must be a string path model = FBAResnetDilated( 50, in_channels=11, stem_channels=64, base_channels=64, ) model.init_weights(pretrained=233) model = FBAResnetDilated( depth=50, in_channels=11, stem_channels=64, base_channels=64, conv_cfg=dict(type='ConvWS'), norm_cfg=dict(type='GN', num_groups=32)) model.init_weights() model.train() input = _demo_inputs((1, 14, 320, 320)) output = model(input) assert 'conv_out' in output.keys() assert 'merged' in output.keys() assert 'two_channel_trimap' in output.keys() assert isinstance(output['conv_out'], list) assert len(output['conv_out']) == 6 assert isinstance(output['merged'], torch.Tensor) assert_tensor_with_shape(output['merged'], torch.Size([1, 3, 320, 320])) assert isinstance(output['two_channel_trimap'], torch.Tensor) assert_tensor_with_shape(output['two_channel_trimap'], torch.Size([1, 2, 320, 320])) if torch.cuda.is_available(): model = FBAResnetDilated( depth=50, in_channels=11, stem_channels=64, base_channels=64, conv_cfg=dict(type='ConvWS'), norm_cfg=dict(type='GN', num_groups=32)) model.init_weights() model.train() model.cuda() input = _demo_inputs((1, 14, 320, 320)).cuda() output = model(input) assert 'conv_out' in output.keys() assert 'merged' in output.keys() assert 'two_channel_trimap' in output.keys() assert isinstance(output['conv_out'], list) assert len(output['conv_out']) == 6 assert isinstance(output['merged'], torch.Tensor) assert_tensor_with_shape(output['merged'], torch.Size([1, 3, 320, 320])) assert isinstance(output['two_channel_trimap'], torch.Tensor) assert_tensor_with_shape(output['two_channel_trimap'], torch.Size([1, 2, 320, 320])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_flavr/test_flavr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import FLAVR, FLAVRNet def test_flavr(): model = FLAVR( generator=dict( type='FLAVRNet', num_input_frames=4, num_output_frames=2, mid_channels_list=[64, 32, 16, 8], encoder_layers_list=[1, 1, 1, 1], bias=False, norm_cfg=None, join_type='concat', up_mode='transpose'), pixel_loss=dict(type='L1Loss'), required_frames=4) assert isinstance(model, FLAVR) assert isinstance(model.generator, FLAVRNet) assert model.pixel_loss.__class__.__name__ == 'L1Loss' input_tensors = torch.rand((1, 9, 3, 16, 16)) input_tensors = model.split_frames(input_tensors) assert input_tensors.shape == (6, 4, 3, 16, 16), input_tensors.shape output_tensors = torch.rand((6, 1, 3, 16, 16)) result = model.merge_frames(input_tensors, output_tensors) assert len(result) == 15 assert result[0].shape == (16, 16, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_flavr/test_flavr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.flavr.flavr_net import UpConv3d from mmagic.registry import MODELS def test_flavr_net(): model_cfg = dict( type='FLAVRNet', num_input_frames=4, num_output_frames=2, mid_channels_list=[64, 32, 16, 8], encoder_layers_list=[1, 1, 1, 1], bias=False, norm_cfg=None, join_type='concat', up_mode='transpose') # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'FLAVRNet' # prepare data inputs = torch.rand(1, 4, 3, 256, 256) target = torch.rand(1, 2, 3, 256, 256) # test on cpu output = model(inputs) output = model(inputs) assert torch.is_tensor(output) assert output.shape == target.shape out = model.decoder._join_tensors(inputs, inputs) assert out.shape == (1, 8, 3, 256, 256) conv3d = UpConv3d(4, 4, 1, 1, 1, up_mode='trilinear', batchnorm=True) out = conv3d(inputs) assert out.shape == (1, 4, 3, 512, 512) # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() target = target.cuda() output = model(inputs) output = model(inputs) assert torch.is_tensor(output) assert output.shape == target.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_gca/test_gca.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmengine.config import ConfigDict from mmagic.datasets.transforms import PackInputs from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() def _demo_input_train(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) alpha = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) ori_merged = torch.from_numpy( np.random.random(color_shape).astype(np.float32)) fg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) bg = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) if cuda: merged = merged.cuda() trimap = trimap.cuda() alpha = alpha.cuda() ori_merged = ori_merged.cuda() fg = fg.cuda() bg = bg.cuda() inputs = torch.cat((merged, trimap), dim=1) data_samples = [] for a, m, f, b in zip(alpha, ori_merged, fg, bg): ds = DataSample() ds.gt_alpha = a ds.gt_merged = m ds.gt_fg = f ds.gt_bg = b for k, v in meta.items(): ds.set_field(name=k, value=v, field_type='metainfo', dtype=None) data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def _demo_input_test(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. test_trans (str): what test transformation is used in data pipeline. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) ori_shape = (img_shape[0], img_shape[1], 1) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) ori_alpha = np.random.random(ori_shape).astype(np.float32) ori_trimap = np.random.randint(256, size=ori_shape).astype(np.float32) inputs = torch.cat((merged, trimap), dim=1) if cuda: inputs = inputs.cuda() results = dict( ori_alpha=ori_alpha, ori_trimap=ori_trimap, ori_merged_shape=img_shape) data_samples = [] packinputs = PackInputs() for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def assert_pred_alpha(predictions, batch_size): assert isinstance(predictions, list) assert isinstance(predictions[0], DataSample) pred_alpha = predictions[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == batch_size def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) def test_gca(): model_cfg = ConfigDict( type='GCA', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='as_is', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='ResGCAEncoder', block='BasicBlock', layers=[3, 4, 4, 2], in_channels=6, with_spectral_norm=True, ), decoder=dict( type='ResGCADecoder', block='BasicBlockDec', layers=[2, 3, 3, 2], with_spectral_norm=True)), loss_alpha=dict(type='L1Loss'), test_cfg=dict( resize_method='pad', resize_mode='reflect', size_divisor=32, )) # test model forward in train mode model = MODELS.build(model_cfg) meta = {'format_trimap_to_onehot': True} inputs, data_samples = _demo_input_train((64, 64), batch_size=2, meta=meta) inputs6 = torch.cat((inputs, inputs[:, 3:, :, :], inputs[:, 3:, :, :]), dim=1) outputs = model(inputs6, data_samples, mode='loss') assert_dict_keys_equal(outputs, ['loss']) if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() inputs, data_samples = _demo_input_train((64, 64), batch_size=2, cuda=True, meta=meta) inputs6 = torch.cat((inputs, inputs[:, 3:, :, :], inputs[:, 3:, :, :]), dim=1) outputs = model(inputs6, data_samples, mode='loss') assert_dict_keys_equal(outputs, ['loss']) # test model forward in test mode with torch.no_grad(): model_cfg.backbone.encoder.in_channels = 4 model = MODELS.build(model_cfg) inputs = _demo_input_test((48, 48), meta=meta) outputs = model(*inputs, mode='predict') assert_pred_alpha(outputs, (48, 48)) if torch.cuda.is_available(): model = MODELS.build(model_cfg) model.cuda() inputs = _demo_input_test((48, 48), cuda=True, meta=meta) outputs = model(*inputs, mode='predict') assert_pred_alpha(outputs, (48, 48)) # test forward_dummy model.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) model.forward(inputs) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_gca/test_gca_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors.gca import GCAModule, ResGCAEncoder def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def test_res_gca_encoder(): """Test resnet encoder with shortcut and guided contextual attention.""" with pytest.raises(NotImplementedError): ResGCAEncoder('UnknownBlock', [3, 4, 4, 2], 3) target_shape = [(2, 32, 64, 64), (2, 32, 32, 32), (2, 64, 16, 16), (2, 128, 8, 8), (2, 256, 4, 4)] # target shape for model with late downsample target_late_ds = [(2, 32, 64, 64), (2, 64, 32, 32), (2, 64, 16, 16), (2, 128, 8, 8), (2, 256, 4, 4)] model = ResGCAEncoder('BasicBlock', [3, 4, 4, 2], 4) model.init_weights() model.train() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_shape[i]) model = ResGCAEncoder('BasicBlock', [3, 4, 4, 2], 6) model.init_weights() model.train() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_shape[i]) # test resnet shortcut encoder with late downsample model = ResGCAEncoder('BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_late_ds[i]) if torch.cuda.is_available(): # repeat above code again model = ResGCAEncoder('BasicBlock', [3, 4, 4, 2], 4) model.init_weights() model.train() model.cuda() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_shape[i]) model = ResGCAEncoder('BasicBlock', [3, 4, 4, 2], 6) model.init_weights() model.train() model.cuda() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_shape[i]) # test resnet shortcut encoder with late downsample model = ResGCAEncoder( 'BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() model.cuda() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['img_feat'], (2, 128, 8, 8)) assert_tensor_with_shape(outputs['unknown'], (2, 1, 8, 8)) for i in range(5): assert_tensor_with_shape(outputs[f'feat{i+1}'], target_late_ds[i]) def test_gca_module(): img_feat = torch.rand(1, 128, 64, 64) alpha_feat = torch.rand(1, 128, 64, 64) unknown = None gca = GCAModule(128, 128, rate=1) output = gca(img_feat, alpha_feat, unknown) assert output.shape == (1, 128, 64, 64) img_feat = torch.rand(1, 128, 64, 64) alpha_feat = torch.rand(1, 128, 64, 64) unknown = torch.rand(1, 1, 64, 64) gca = GCAModule(128, 128, rate=2) output = gca(img_feat, alpha_feat, unknown) assert output.shape == (1, 128, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_gca/test_resgca_dec.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors.gca import (ResGCADecoder, ResGCAEncoder, ResNetDec, ResNetEnc, ResShortcutDec, ResShortcutEnc) def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def test_resnet_decoder(): """Test resnet decoder.""" with pytest.raises(NotImplementedError): ResNetDec('UnknowBlock', [2, 3, 3, 2], 512) model = ResNetDec('BasicBlockDec', [2, 3, 3, 2], 512, kernel_size=5) model.init_weights() model.train() encoder = ResNetEnc('BasicBlock', [2, 4, 4, 2], 6) img = _demo_inputs((1, 6, 64, 64)) feat = encoder(img) prediction = model(feat) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) model = ResNetDec( 'BasicBlockDec', [2, 3, 3, 2], 512, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() encoder = ResNetEnc('BasicBlock', [2, 4, 4, 2], 6) img = _demo_inputs((1, 6, 64, 64)) feat = encoder(img) prediction = model(feat) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # test forward with gpu if torch.cuda.is_available(): model = ResNetDec('BasicBlockDec', [2, 3, 3, 2], 512, kernel_size=5) model.init_weights() model.train() model.cuda() encoder = ResNetEnc('BasicBlock', [2, 4, 4, 2], 6) encoder.cuda() img = _demo_inputs((1, 6, 64, 64)).cuda() feat = encoder(img) prediction = model(feat) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) model = ResNetDec( 'BasicBlockDec', [2, 3, 3, 2], 512, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() model.cuda() encoder = ResNetEnc('BasicBlock', [2, 4, 4, 2], 6) encoder.cuda() img = _demo_inputs((1, 6, 64, 64)).cuda() feat = encoder(img) prediction = model(feat) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) def test_res_shortcut_decoder(): """Test resnet decoder with shortcut.""" with pytest.raises(NotImplementedError): ResShortcutDec('UnknowBlock', [2, 3, 3, 2], 512) model = ResShortcutDec('BasicBlockDec', [2, 3, 3, 2], 512) model.init_weights() model.train() encoder = ResShortcutEnc('BasicBlock', [2, 4, 4, 2], 6) img = _demo_inputs((1, 6, 64, 64)) outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # test forward with gpu if torch.cuda.is_available(): model = ResShortcutDec('BasicBlockDec', [2, 3, 3, 2], 512) model.init_weights() model.train() model.cuda() encoder = ResShortcutEnc('BasicBlock', [2, 4, 4, 2], 6) encoder.cuda() img = _demo_inputs((1, 6, 64, 64)).cuda() outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) def test_res_gca_decoder(): """Test resnet decoder with shortcut and guided contextual attention.""" with pytest.raises(NotImplementedError): ResGCADecoder('UnknowBlock', [2, 3, 3, 2], 512) model = ResGCADecoder('BasicBlockDec', [2, 3, 3, 2], 512) model.init_weights() model.train() encoder = ResGCAEncoder('BasicBlock', [2, 4, 4, 2], 6) img = _demo_inputs((2, 6, 32, 32)) outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([2, 1, 32, 32])) # test forward with gpu if torch.cuda.is_available(): model = ResGCADecoder('BasicBlockDec', [2, 3, 3, 2], 512) model.init_weights() model.train() model.cuda() encoder = ResGCAEncoder('BasicBlock', [2, 4, 4, 2], 6) encoder.cuda() img = _demo_inputs((2, 6, 32, 32)).cuda() outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([2, 1, 32, 32])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_gca/test_resgca_enc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors.gca import ResNetEnc, ResShortcutEnc def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def test_resnet_encoder(): """Test resnet encoder.""" with pytest.raises(NotImplementedError): ResNetEnc('UnknownBlock', [3, 4, 4, 2], 3) with pytest.raises(TypeError): model = ResNetEnc('BasicBlock', [3, 4, 4, 2], 3) model.init_weights(list()) model = ResNetEnc('BasicBlock', [3, 4, 4, 2], 4, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)) feat = model(img) assert_tensor_with_shape(feat, torch.Size([2, 512, 2, 2])) # test resnet encoder with late downsample model = ResNetEnc('BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)) feat = model(img) assert_tensor_with_shape(feat, torch.Size([2, 512, 2, 2])) if torch.cuda.is_available(): # repeat above code again model = ResNetEnc( 'BasicBlock', [3, 4, 4, 2], 4, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() model.cuda() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)).cuda() feat = model(img) assert_tensor_with_shape(feat, torch.Size([2, 512, 2, 2])) # test resnet encoder with late downsample model = ResNetEnc('BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() model.cuda() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)).cuda() feat = model(img) assert_tensor_with_shape(feat, torch.Size([2, 512, 2, 2])) def test_res_shortcut_encoder(): """Test resnet encoder with shortcut.""" with pytest.raises(NotImplementedError): ResShortcutEnc('UnknownBlock', [3, 4, 4, 2], 3) target_shape = [(2, 32, 64, 64), (2, 32, 32, 32), (2, 64, 16, 16), (2, 128, 8, 8), (2, 256, 4, 4)] # target shape for model with late downsample target_late_ds_shape = [(2, 32, 64, 64), (2, 64, 32, 32), (2, 64, 16, 16), (2, 128, 8, 8), (2, 256, 4, 4)] model = ResShortcutEnc( 'BasicBlock', [3, 4, 4, 2], 4, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_shape[4]) model = ResShortcutEnc('BasicBlock', [3, 4, 4, 2], 6) model.init_weights() model.train() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_shape[4]) # test resnet shortcut encoder with late downsample model = ResShortcutEnc('BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)) outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_late_ds_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_late_ds_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_late_ds_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_late_ds_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_late_ds_shape[4]) if torch.cuda.is_available(): # repeat above code again model = ResShortcutEnc( 'BasicBlock', [3, 4, 4, 2], 4, with_spectral_norm=True) assert hasattr(model.conv1.conv, 'weight_orig') model.init_weights() model.train() model.cuda() # trimap has 1 channels img = _demo_inputs((2, 4, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_shape[4]) model = ResShortcutEnc('BasicBlock', [3, 4, 4, 2], 6) model.init_weights() model.train() model.cuda() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_shape[4]) # test resnet shortcut encoder with late downsample model = ResShortcutEnc( 'BasicBlock', [3, 4, 4, 2], 6, late_downsample=True) model.init_weights() model.train() model.cuda() # both image and trimap has 3 channels img = _demo_inputs((2, 6, 64, 64)).cuda() outputs = model(img) assert_tensor_with_shape(outputs['out'], (2, 512, 2, 2)) assert_tensor_with_shape(outputs['feat1'], target_late_ds_shape[0]) assert_tensor_with_shape(outputs['feat2'], target_late_ds_shape[1]) assert_tensor_with_shape(outputs['feat3'], target_late_ds_shape[2]) assert_tensor_with_shape(outputs['feat4'], target_late_ds_shape[3]) assert_tensor_with_shape(outputs['feat5'], target_late_ds_shape[4]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ggan/test_ggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import GGAN, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='DCGANGenerator', noise_size=10, output_scale=16, base_channels=16) discriminator = dict( type='DCGANDiscriminator', input_scale=16, output_scale=4, out_channels=1) class TestGGAN(TestCase): def test_init(self): gan = GGAN( noise_size=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator) self.assertIsInstance(gan, GGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = GGAN( generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = GGAN( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = GGAN(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('test-ggan') gan = GGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_glean/test_glean_styleganv2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest.mock import patch import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import SRGAN, DataPreprocessor, GLEANStyleGANv2 from mmagic.models.editors.stylegan2 import StyleGAN2Discriminator from mmagic.models.losses import (GANLoss, MSELoss, PerceptualLoss, PerceptualVGG) from mmagic.structures import DataSample @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') @patch.object(PerceptualVGG, 'init_weights') def test_glean(init_weights): model = SRGAN( generator=dict( type='GLEANStyleGANv2', in_size=16, out_size=64, style_channels=4), discriminator=dict(type='StyleGANv2Discriminator', in_size=64), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'21': 1.0}, vgg_type='vgg16', perceptual_weight=1e-2, style_weight=0, norm_img=True, criterion='mse', pretrained='torchvision://vgg16'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-2, real_label_val=1.0, fake_label_val=0), train_cfg=None, test_cfg=None, data_preprocessor=DataPreprocessor()) assert isinstance(model, SRGAN) assert isinstance(model.generator, GLEANStyleGANv2) assert isinstance(model.discriminator, StyleGAN2Discriminator) assert isinstance(model.pixel_loss, MSELoss) assert isinstance(model.perceptual_loss, PerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 16, 16) target = torch.rand(3, 64, 64) data_sample = DataSample(gt_img=target) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_pix', 'loss_perceptual', 'loss_gan', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 64, 64) # feat output = model(torch.rand(1, 3, 16, 16), mode='tensor') assert output.shape == (1, 3, 64, 64) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_glide/test_glide.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import unittest from unittest import TestCase import torch from mmagic.models.diffusion_schedulers import EditDDIMScheduler from mmagic.utils import register_all_modules from projects.glide.models import Glide, SuperResText2ImUNet, Text2ImUNet register_all_modules() class TestGLIDE(TestCase): def setUp(self): # low resolution cfg unet_cfg = dict( image_size=64, base_channels=192, in_channels=3, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=0, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=1, num_head_channels=64, use_new_attention_order=False, encoder_channels=512), use_scale_shift_norm=True, text_ctx=128, xf_width=512, xf_layers=16, xf_heads=8, xf_final_ln=True, xf_padding=True, ) diffusion_scheduler_cfg = dict( variance_type='learned_range', beta_schedule='squaredcos_cap_v2') # unet self.unet = Text2ImUNet(**unet_cfg) # diffusion_scheduler self.diffusion_scheduler = EditDDIMScheduler(**diffusion_scheduler_cfg) # high resolution cfg unet_up_cfg = dict( image_size=256, base_channels=192, in_channels=3, output_cfg=dict(var='FIXED'), resblocks_per_downsample=2, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=0, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=1, num_head_channels=64, use_new_attention_order=False, encoder_channels=512), use_scale_shift_norm=True, text_ctx=128, xf_width=512, xf_layers=16, xf_heads=8, xf_final_ln=True, xf_padding=True, ) diffusion_scheduler_up_cfg = dict( variance_type='learned_range', beta_schedule='linear') # unet up self.unet_up = SuperResText2ImUNet(**unet_up_cfg) self.diffusion_scheduler_up = EditDDIMScheduler( **diffusion_scheduler_up_cfg) @unittest.skipIf( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_init(self): self.GLIDE = Glide( unet=self.unet, diffusion_scheduler=self.diffusion_scheduler, unet_up=self.unet_up, diffusion_scheduler_up=self.diffusion_scheduler_up) @unittest.skipIf( ('win' in platform.system().lower()) or (not torch.cuda.is_available()), reason='skip on windows and cpu due to limited RAM.') def test_infer(self): # test infer resolution text_prompts = 'clouds surround the mountains and palaces,sunshine' image = self.GLIDE.infer( prompt=text_prompts, show_progress=True, num_inference_steps=2)['samples'] assert image.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules def test_gl_decoder(): register_all_modules() input_x = torch.randn(1, 256, 64, 64) template_cfg = dict(type='GLDecoder') gl_decoder = MODELS.build(template_cfg) output = gl_decoder(input_x) assert output.shape == (1, 3, 256, 256) cfg_copy = template_cfg.copy() cfg_copy['out_act'] = 'sigmoid' gl_decoder = MODELS.build(cfg_copy) output = gl_decoder(input_x) assert output.shape == (1, 3, 256, 256) with pytest.raises(ValueError): # conv_cfg must be a dict or None cfg_copy = template_cfg.copy() cfg_copy['out_act'] = 'relu' gl_decoder = MODELS.build(cfg_copy) output = gl_decoder(input_x) if torch.cuda.is_available(): gl_decoder = MODELS.build(template_cfg) gl_decoder = gl_decoder.cuda() output = gl_decoder(input_x.cuda()) assert output.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_dilation.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.archs import SimpleGatedConvModule from mmagic.models.editors.global_local import GLDilationNeck from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() def test_gl_dilation_neck(): x = torch.rand((2, 8, 64, 64)) template_cfg = dict(type='GLDilationNeck', in_channels=8) neck = MODELS.build(template_cfg) res = neck(x) assert res.shape == (2, 8, 64, 64) if torch.cuda.is_available(): neck = GLDilationNeck(in_channels=8).cuda() x = torch.rand((2, 8, 64, 64)).cuda() res = neck(x) assert res.shape == (2, 8, 64, 64) neck = GLDilationNeck(in_channels=8, conv_type='gated_conv').cuda() res = neck(x) assert isinstance(neck.dilation_convs[0], SimpleGatedConvModule) assert res.shape == (2, 8, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.registry import MODELS def test_gl_discs(): global_disc_cfg = dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=6, norm_cfg=dict(type='BN')) local_disc_cfg = dict( in_channels=3, max_channels=512, fc_in_channels=512 * 4 * 4, fc_out_channels=1024, num_convs=5, norm_cfg=dict(type='BN')) gl_disc_cfg = dict( type='GLDiscs', global_disc_cfg=global_disc_cfg, local_disc_cfg=local_disc_cfg) gl_discs = MODELS.build(gl_disc_cfg) gl_discs.init_weights() input_g = torch.randn(1, 3, 256, 256) input_l = torch.randn(1, 3, 128, 128) output = gl_discs((input_g, input_l)) assert output.shape == (1, 1) with pytest.raises(TypeError): gl_discs.init_weights(pretrained=dict(igccc=777)) if torch.cuda.is_available(): gl_discs = gl_discs.cuda() input_g = torch.randn(1, 3, 256, 256).cuda() input_l = torch.randn(1, 3, 128, 128).cuda() output = gl_discs((input_g, input_l)) assert output.shape == (1, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules def test_gl_encoder(): register_all_modules() input_x = torch.randn(1, 4, 256, 256) template_cfg = dict(type='GLEncoder') gl_encoder = MODELS.build(template_cfg) output = gl_encoder(input_x) assert output.shape == (1, 256, 64, 64) if torch.cuda.is_available(): gl_encoder = MODELS.build(template_cfg) gl_encoder = gl_encoder.cuda() output = gl_encoder(input_x.cuda()) assert output.shape == (1, 256, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.registry import MODELS from mmagic.utils import register_all_modules def test_gl_encdec(): register_all_modules() input_x = torch.randn(1, 4, 256, 256) template_cfg = dict(type='GLEncoderDecoder') gl_encdec = MODELS.build(template_cfg) gl_encdec.init_weights() output = gl_encdec(input_x) assert output.shape == (1, 3, 256, 256) cfg_ = template_cfg.copy() cfg_['decoder'] = dict(type='GLDecoder', out_act='sigmoid') gl_encdec = MODELS.build(cfg_) output = gl_encdec(input_x) assert output.shape == (1, 3, 256, 256) with pytest.raises(ValueError): cfg_ = template_cfg.copy() cfg_['decoder'] = dict(type='GLDecoder', out_act='igccc') gl_encdec = MODELS.build(cfg_) with pytest.raises(TypeError): gl_encdec.init_weights(pretrained=dict(igccc=4396)) if torch.cuda.is_available(): gl_encdec = MODELS.build(template_cfg) gl_encdec.init_weights() gl_encdec = gl_encdec.cuda() output = gl_encdec(input_x.cuda()) assert output.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_global_local/test_gl_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from os.path import dirname, join import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules def test_gl_inpaintor(): register_all_modules() config_file = join(dirname(__file__), '../../..', 'configs', 'gl_test.py') cfg = Config.fromfile(config_file) gl = MODELS.build(cfg.model) assert gl.__class__.__name__ == 'GLInpaintor' if torch.cuda.is_available(): gl.cuda() gt_img = torch.randn(3, 256, 256) mask = torch.zeros_like(gt_img)[0:1, ...] mask[..., 100:210, 100:210] = 1. masked_img = gt_img.unsqueeze(0) * (1. - mask) mask_bbox = [100, 100, 110, 110] data_batch = { 'inputs': masked_img, 'data_samples': [ DataSample( metainfo=dict(mask_bbox=mask_bbox), mask=mask, gt_img=gt_img, ) ] } optim_g = torch.optim.SGD(gl.generator.parameters(), lr=0.1) optim_d = torch.optim.SGD(gl.disc.parameters(), lr=0.1) optim_dict = dict( generator=OptimWrapper(optim_g), disc=OptimWrapper(optim_d)) for i in range(5): log_vars = gl.train_step(data_batch, optim_dict) if i <= 2: assert 'loss_l1_hole' in log_vars assert 'fake_loss' not in log_vars assert 'real_loss' not in log_vars assert 'loss_g_fake' not in log_vars elif i == 3: assert 'loss_l1_hole' not in log_vars assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_g_fake' not in log_vars else: assert 'loss_l1_hole' in log_vars assert 'fake_loss' in log_vars assert 'real_loss' in log_vars assert 'loss_g_fake' in log_vars gl_dirty = MODELS.build(cfg.model_dirty) if torch.cuda.is_available(): gl_dirty.cuda() res, loss = gl_dirty.generator_loss(gt_img, gt_img, gt_img, gt_img, mask, masked_img) assert len(loss) == 0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_guided_diffusion/test_adm.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import pytest import torch from mmagic.models import AblatedDiffusionModel from mmagic.utils import register_all_modules register_all_modules() class TestAdm(TestCase): def setup_class(cls): # test init cls.model = AblatedDiffusionModel( data_preprocessor=dict(type='DataPreprocessor'), unet=dict( type='DenoisingUnet', image_size=64, in_channels=3, base_channels=192, resblocks_per_downsample=3, attention_res=(32, 16, 8), norm_cfg=dict(type='GN32', num_groups=32), dropout=0.1, num_classes=1000, use_fp16=False, resblock_updown=True, attention_cfg=dict( type='MultiHeadAttentionBlock', num_heads=4, num_head_channels=64, use_new_attention_order=True), use_scale_shift_norm=True), diffusion_scheduler=dict( type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='squaredcos_cap_v2'), rgb2bgr=True, use_fp16=False) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_infer(self): # test no label infer self.model.cuda() samples = self.model.infer( init_image=None, batch_size=1, num_inference_steps=5, labels=None, classifier_scale=0.0, show_progress=False)['samples'] assert samples.shape == (1, 3, 64, 64) # test classifier guidance samples = self.model.infer( init_image=None, batch_size=1, num_inference_steps=5, labels=333, classifier_scale=1.0, show_progress=False)['samples'] assert samples.shape == (1, 3, 64, 64) # test with ddpm scheduler scheduler_kwargs = dict( type='EditDDPMScheduler', variance_type='learned_range', num_train_timesteps=5) # test no label infer samples = self.model.infer( scheduler_kwargs=scheduler_kwargs, init_image=None, batch_size=1, num_inference_steps=5, labels=None, classifier_scale=0.0, show_progress=False)['samples'] assert samples.shape == (1, 3, 64, 64) # test classifier guidance samples = self.model.infer( scheduler_kwargs=scheduler_kwargs, init_image=None, batch_size=1, num_inference_steps=5, labels=333, classifier_scale=1.0, show_progress=False)['samples'] assert samples.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_iconvsr/test_iconvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors import IconVSRNet def test_iconvsr(): """Test IconVSRNet.""" iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=None, edvr_pretrained=None) input_tensor = torch.rand(1, 5, 3, 64, 64) output = iconvsr(input_tensor) assert output.shape == (1, 5, 3, 256, 256) assert not iconvsr._raised_warning input_tensor = torch.rand(1, 5, 3, 16, 16) output = iconvsr(input_tensor) assert output.shape == (1, 5, 3, 64, 64) assert iconvsr._raised_warning # spynet_pretrained should be str or None with pytest.raises(TypeError): iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=123, edvr_pretrained=None) # edvr_pretrained should be str or None with pytest.raises(TypeError): iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=None, edvr_pretrained=123) if torch.cuda.is_available(): iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=None, edvr_pretrained=None).cuda() # input_tensor = torch.rand(1, 5, 3, 64, 64).cuda() input_tensor = torch.rand(1, 5, 3, 16, 16).cuda() output = iconvsr(input_tensor) # assert output.shape == (1, 5, 3, 256, 256) assert output.shape == (1, 5, 3, 64, 64) # spynet_pretrained should be str or None with pytest.raises(TypeError): iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=123, edvr_pretrained=None).cuda() # edvr_pretrained should be str or None with pytest.raises(TypeError): iconvsr = IconVSRNet( mid_channels=64, num_blocks=1, keyframe_stride=5, padding=2, spynet_pretrained=None, edvr_pretrained=123).cuda() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_indexnet/test_indexnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch from mmengine.config import ConfigDict from mmagic.datasets.transforms import PackInputs from mmagic.models.editors import IndexedUpsample from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules def _demo_input_train(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) ori_shape = (img_shape[0], img_shape[1], 1) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) inputs = torch.cat((merged, trimap), dim=1) if cuda: inputs = inputs.cuda() results = dict( alpha=np.random.random(ori_shape).astype(np.float32), merged=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32), fg=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32), bg=np.random.random( (img_shape[0], img_shape[1], 3)).astype(np.float32), ) data_samples = [] packinputs = PackInputs() for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def _demo_input_test(img_shape, batch_size=1, cuda=False, meta={}): """Create a superset of inputs needed to run backbone. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. test_trans (str): what test transformation is used in data pipeline. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) ori_shape = (img_shape[0], img_shape[1], 1) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) trimap = torch.from_numpy( np.random.randint(255, size=gray_shape).astype(np.float32)) inputs = torch.cat((merged, trimap), dim=1) if cuda: inputs = inputs.cuda() results = dict( ori_alpha=np.random.random(ori_shape).astype(np.float32), ori_trimap=np.random.randint(256, size=ori_shape).astype(np.float32), ori_merged_shape=img_shape) data_samples = [] packinputs = PackInputs() for _ in range(batch_size): ds = packinputs(results)['data_samples'] if cuda: ds = ds.cuda() data_samples.append(ds) data_samples = DataSample.stack(data_samples) return inputs, data_samples def assert_pred_alpha(predictions, batch_size): assert isinstance(predictions, list) assert isinstance(predictions[0], DataSample) pred_alpha = predictions[0].output.pred_alpha.data assert isinstance(pred_alpha, torch.Tensor) assert pred_alpha.dtype == torch.uint8 assert pred_alpha.shape[-2:] == batch_size def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img def test_indexnet(): register_all_modules() model_cfg = ConfigDict( type='IndexNet', data_preprocessor=dict( type='MattorPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], proc_trimap='rescale_to_zero_one', ), backbone=dict( type='SimpleEncoderDecoder', encoder=dict( type='IndexNetEncoder', in_channels=4, freeze_bn=True, ), decoder=dict(type='IndexNetDecoder')), loss_alpha=dict( type='CharbonnierLoss', loss_weight=0.5, sample_wise=True), loss_comp=dict( type='CharbonnierCompLoss', loss_weight=1.5, sample_wise=True), test_cfg=dict( resize_method='interp', resize_mode='bicubic', size_divisor=32, ), ) model_cfg.backbone.encoder.init_cfg = None # test indexnet inference with torch.no_grad(): indexnet = MODELS.build(model_cfg) indexnet.eval() input_test = _demo_input_test((48, 48)) output_test = indexnet(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # test inference with gpu if torch.cuda.is_available(): indexnet = MODELS.build(model_cfg).cuda() indexnet.eval() input_test = _demo_input_test((48, 48), cuda=True) output_test = indexnet(*input_test, mode='predict') assert_pred_alpha(output_test, (48, 48)) # test forward train though we do not guarantee the training for present model_cfg.loss_alpha = None model_cfg.loss_comp = dict(type='L1CompositionLoss') indexnet = MODELS.build(model_cfg) input_train = _demo_input_train((64, 64), batch_size=2) output_train = indexnet(*input_train, mode='loss') # assert output_train['num_samples'] == 2 assert_dict_keys_equal(output_train, ['loss_comp']) if torch.cuda.is_available(): model_cfg.loss_alpha = dict(type='L1Loss') model_cfg.loss_comp = None indexnet = MODELS.build(model_cfg).cuda() input_train = _demo_input_train((64, 64), batch_size=2, cuda=True) output_train = indexnet(*input_train, mode='loss') # assert output_train['num_samples'] == 2 assert_dict_keys_equal(output_train, ['loss_alpha']) # test forward indexnet.cpu().eval() inputs = torch.ones((1, 4, 32, 32)) indexnet.forward(inputs) def test_indexed_upsample(): """Test indexed upsample module for indexnet decoder.""" indexed_upsample = IndexedUpsample(12, 12) # test indexed_upsample without dec_idx_feat (no upsample) x = torch.rand(2, 6, 32, 32) shortcut = torch.rand(2, 6, 32, 32) output = indexed_upsample(x, shortcut) assert_tensor_with_shape(output, (2, 12, 32, 32)) # test indexed_upsample without dec_idx_feat (with upsample) x = torch.rand(2, 6, 32, 32) dec_idx_feat = torch.rand(2, 6, 64, 64) shortcut = torch.rand(2, 6, 64, 64) output = indexed_upsample(x, shortcut, dec_idx_feat) assert_tensor_with_shape(output, (2, 12, 64, 64)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_indexnet/test_indexnet_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors import IndexNetDecoder, IndexNetEncoder def test_indexnet_decoder(): """Test Indexnet decoder.""" # test indexnet decoder with default indexnet setting with pytest.raises(AssertionError): # shortcut must have four dimensions indexnet_decoder = IndexNetDecoder( 160, kernel_size=5, separable_conv=False) x = torch.rand(2, 256, 4, 4) shortcut = torch.rand(2, 128, 8, 8, 8) dec_idx_feat = torch.rand(2, 128, 8, 8, 8) outputs_enc = dict( out=x, shortcuts=[shortcut], dec_idx_feat_list=[dec_idx_feat]) indexnet_decoder(outputs_enc) indexnet_decoder = IndexNetDecoder( 160, kernel_size=5, separable_conv=False) indexnet_decoder.init_weights() indexnet_encoder = IndexNetEncoder(4) x = torch.rand(2, 4, 32, 32) outputs_enc = indexnet_encoder(x) out = indexnet_decoder(outputs_enc) assert out.shape == (2, 1, 32, 32) # test indexnet decoder with other setting indexnet_decoder = IndexNetDecoder(160, kernel_size=3, separable_conv=True) indexnet_decoder.init_weights() out = indexnet_decoder(outputs_enc) assert out.shape == (2, 1, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_indexnet/test_indexnet_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. try: import Iterable except ImportError: from collections.abc import Iterable import pytest import torch from mmagic.models import (DepthwiseIndexBlock, HolisticIndexBlock, IndexNetEncoder) def test_indexnet_encoder(): """Test Indexnet encoder.""" with pytest.raises(ValueError): # out_stride must be 16 or 32 IndexNetEncoder(4, out_stride=8) with pytest.raises(NameError): # index_mode must be 'holistic', 'o2o' or 'm2o' IndexNetEncoder(4, index_mode='unknown_mode') # test indexnet encoder with default indexnet setting indexnet_encoder = IndexNetEncoder( 4, out_stride=32, width_mult=1, index_mode='m2o', aspp=True, use_nonlinear=True, use_context=True) indexnet_encoder.init_weights() x = torch.rand(2, 4, 32, 32) outputs = indexnet_encoder(x) assert outputs['out'].shape == (2, 160, 1, 1) assert len(outputs['shortcuts']) == 7 target_shapes = [(2, 32, 32, 32), (2, 16, 16, 16), (2, 24, 16, 16), (2, 32, 8, 8), (2, 64, 4, 4), (2, 96, 2, 2), (2, 160, 2, 2)] for shortcut, target_shape in zip(outputs['shortcuts'], target_shapes): assert shortcut.shape == target_shape assert len(outputs['dec_idx_feat_list']) == 7 target_shapes = [(2, 32, 32, 32), None, (2, 24, 16, 16), (2, 32, 8, 8), (2, 64, 4, 4), None, (2, 160, 2, 2)] for dec_idx_feat, target_shape in zip(outputs['dec_idx_feat_list'], target_shapes): if dec_idx_feat is not None: assert dec_idx_feat.shape == target_shape # test indexnet encoder with other config indexnet_encoder = IndexNetEncoder( 4, out_stride=16, width_mult=2, index_mode='o2o', aspp=False, use_nonlinear=False, use_context=False) indexnet_encoder.init_weights() x = torch.rand(2, 4, 32, 32) outputs = indexnet_encoder(x) assert outputs['out'].shape == (2, 160, 2, 2) assert len(outputs['shortcuts']) == 7 target_shapes = [(2, 64, 32, 32), (2, 32, 16, 16), (2, 48, 16, 16), (2, 64, 8, 8), (2, 128, 4, 4), (2, 192, 2, 2), (2, 320, 2, 2)] for shortcut, target_shape in zip(outputs['shortcuts'], target_shapes): assert shortcut.shape == target_shape assert len(outputs['dec_idx_feat_list']) == 7 target_shapes = [(2, 64, 32, 32), None, (2, 48, 16, 16), (2, 64, 8, 8), (2, 128, 4, 4), None, None] for dec_idx_feat, target_shape in zip(outputs['dec_idx_feat_list'], target_shapes): if dec_idx_feat is not None: assert dec_idx_feat.shape == target_shape # test indexnet encoder with holistic index block indexnet_encoder = IndexNetEncoder( 4, out_stride=16, width_mult=2, index_mode='holistic', aspp=False, freeze_bn=True, use_nonlinear=False, use_context=False) indexnet_encoder.init_weights() x = torch.rand(2, 4, 32, 32) outputs = indexnet_encoder(x) assert outputs['out'].shape == (2, 160, 2, 2) assert len(outputs['shortcuts']) == 7 target_shapes = [(2, 64, 32, 32), (2, 32, 16, 16), (2, 48, 16, 16), (2, 64, 8, 8), (2, 128, 4, 4), (2, 192, 2, 2), (2, 320, 2, 2)] for shortcut, target_shape in zip(outputs['shortcuts'], target_shapes): assert shortcut.shape == target_shape assert len(outputs['dec_idx_feat_list']) == 7 target_shapes = [(2, 1, 32, 32), None, (2, 1, 16, 16), (2, 1, 8, 8), (2, 1, 4, 4), None, None] for dec_idx_feat, target_shape in zip(outputs['dec_idx_feat_list'], target_shapes): if dec_idx_feat is not None: assert dec_idx_feat.shape == target_shape def test_index_blocks(): """Test index blocks for indexnet encoder.""" # test holistic index block # test holistic index block without context and nonlinearty block = HolisticIndexBlock(128, use_context=False, use_nonlinear=False) assert not isinstance(block.index_block, Iterable) x = torch.rand(2, 128, 8, 8) enc_idx_feat, dec_idx_feat = block(x) assert enc_idx_feat.shape == (2, 1, 8, 8) assert dec_idx_feat.shape == (2, 1, 8, 8) # test holistic index block with context and nonlinearty block = HolisticIndexBlock(128, use_context=True, use_nonlinear=True) assert len(block.index_block) == 2 # nonlinear mode has two blocks x = torch.rand(2, 128, 8, 8) enc_idx_feat, dec_idx_feat = block(x) assert enc_idx_feat.shape == (2, 1, 8, 8) assert dec_idx_feat.shape == (2, 1, 8, 8) # test depthwise index block # test depthwise index block without context and nonlinearty in o2o mode block = DepthwiseIndexBlock( 128, use_context=False, mode='oso', use_nonlinear=False) assert not isinstance(block.index_blocks[0], Iterable) x = torch.rand(2, 128, 8, 8) enc_idx_feat, dec_idx_feat = block(x) assert enc_idx_feat.shape == (2, 128, 8, 8) assert dec_idx_feat.shape == (2, 128, 8, 8) # test depthwise index block with context and nonlinearty in m2o mode block = DepthwiseIndexBlock( 128, use_context=True, mode='m2o', use_nonlinear=True) assert len(block.index_blocks[0]) == 2 # nonlinear mode has two blocks x = torch.rand(2, 128, 8, 8) enc_idx_feat, dec_idx_feat = block(x) assert enc_idx_feat.shape == (2, 128, 8, 8) assert dec_idx_feat.shape == (2, 128, 8, 8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_inst_colorization/test_color_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.inst_colorization import color_utils class TestColorUtils: color_data_opt = dict( ab_thresh=0, p=1.0, sample_PS=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, ], ab_norm=110, ab_max=110., ab_quant=10., l_norm=100., l_cent=50., mask_cent=0.5) def test_xyz2lab(self): xyz = torch.rand(1, 3, 8, 8) lab = color_utils.xyz2lab(xyz) sc = torch.Tensor((0.95047, 1., 1.08883))[None, :, None, None] xyz_scale = xyz / sc mask = (xyz_scale > .008856).type(torch.FloatTensor) xyz_int = xyz_scale**(1 / 3.) * mask + (7.787 * xyz_scale + 16. / 116.) * (1 - mask) L = 116. * xyz_int[:, 1, :, :] - 16. a = 500. * (xyz_int[:, 0, :, :] - xyz_int[:, 1, :, :]) b = 200. * (xyz_int[:, 1, :, :] - xyz_int[:, 2, :, :]) assert lab.shape == (1, 3, 8, 8) assert lab.equal( torch.cat((L[:, None, :, :], a[:, None, :, :], b[:, None, :, :]), dim=1)) def test_rgb2xyz(self): rgb = torch.rand(1, 3, 8, 8) xyz = color_utils.rgb2xyz(rgb) mask = (rgb > .04045).type(torch.FloatTensor) rgb = (((rgb + .055) / 1.055)**2.4) * mask + rgb / 12.92 * (1 - mask) x = .412453 * rgb[:, 0, :, :] + .357580 * rgb[:, 1, :, :] \ + .180423 * rgb[:, 2, :, :] y = .212671 * rgb[:, 0, :, :] + .715160 * rgb[:, 1, :, :] \ + .072169 * rgb[:, 2, :, :] z = .019334 * rgb[:, 0, :, :] + .119193 * rgb[:, 1, :, :] \ + .950227 * rgb[:, 2, :, :] assert xyz.shape == (1, 3, 8, 8) assert xyz.equal( torch.cat((x[:, None, :, :], y[:, None, :, :], z[:, None, :, :]), dim=1)) def test_rgb2lab(self): rgb = torch.rand(1, 3, 8, 8) lab = color_utils.rgb2lab(rgb, self.color_data_opt) _lab = color_utils.xyz2lab(color_utils.rgb2xyz(rgb)) l_rs = (_lab[:, [0], :, :] - self.color_data_opt['l_cent']) / self.color_data_opt['l_norm'] ab_rs = _lab[:, 1:, :, :] / self.color_data_opt['ab_norm'] assert lab.shape == (1, 3, 8, 8) assert lab.equal(torch.cat((l_rs, ab_rs), dim=1)) def test_lab2rgb(self): lab = torch.rand(1, 3, 8, 8) rgb = color_utils.lab2rgb(lab, self.color_data_opt) L = lab[:, [0], :, :] * self.color_data_opt[ 'l_norm'] + self.color_data_opt['l_cent'] AB = lab[:, 1:, :, :] * self.color_data_opt['ab_norm'] lab = torch.cat((L, AB), dim=1) assert rgb.shape == (1, 3, 8, 8) assert rgb.equal(color_utils.xyz2rgb(color_utils.lab2xyz(lab))) def test_lab2xyz(self): lab = torch.rand(1, 3, 8, 8) xyz = color_utils.lab2xyz(lab) y_int = (lab[:, 0, :, :] + 16.) / 116. x_int = (lab[:, 1, :, :] / 500.) + y_int z_int = y_int - (lab[:, 2, :, :] / 200.) z_int = torch.max(torch.Tensor((0, )), z_int) out = torch.cat( (x_int[:, None, :, :], y_int[:, None, :, :], z_int[:, None, :, :]), dim=1) mask = (out > .2068966).type(torch.FloatTensor) sc = torch.Tensor((0.95047, 1., 1.08883))[None, :, None, None] out = (out**3.) * mask + (out - 16. / 116.) / 7.787 * (1 - mask) target = sc * out assert xyz.shape == (1, 3, 8, 8) assert xyz.equal(target) def test_xyz2rgb(self): xyz = torch.rand(1, 3, 8, 8) rgb = color_utils.xyz2rgb(xyz) r = 3.24048134 * xyz[:, 0, :, :] - 1.53715152 * xyz[:, 1, :, :] \ - 0.49853633 * xyz[:, 2, :, :] g = -0.96925495 * xyz[:, 0, :, :] + 1.87599 * xyz[:, 1, :, :] \ + .04155593 * xyz[:, 2, :, :] b = .05564664 * xyz[:, 0, :, :] - .20404134 * xyz[:, 1, :, :] \ + 1.05731107 * xyz[:, 2, :, :] _rgb = torch.cat( (r[:, None, :, :], g[:, None, :, :], b[:, None, :, :]), dim=1) _rgb = torch.max(_rgb, torch.zeros_like(_rgb)) mask = (_rgb > .0031308).type(torch.FloatTensor) assert rgb.shape == (1, 3, 8, 8) and mask.shape == (1, 3, 8, 8) assert rgb.equal((1.055 * (_rgb**(1. / 2.4)) - 0.055) * mask + 12.92 * _rgb * (1 - mask)) def test_get_colorization_data(self): data_raw = torch.rand(1, 3, 8, 8) res = color_utils.get_colorization_data(data_raw, self.color_data_opt) assert isinstance(res, dict) assert 'A' in res.keys() and 'B' in res.keys() \ and 'hint_B' in res.keys() and 'mask_B' in res.keys() assert res['A'].shape == res['mask_B'].shape == (1, 1, 8, 8) assert res['hint_B'].shape == res['B'].shape == (1, 2, 8, 8) def test_encode_ab_ind(self): data_ab = torch.rand(1, 2, 8, 8) data_q = color_utils.encode_ab_ind(data_ab, self.color_data_opt) A = 2 * 110. / 10. + 1 data_ab_rs = torch.round((data_ab * 110 + 110.) / 10.) assert data_q.shape == (1, 1, 8, 8) assert data_q.equal(data_ab_rs[:, [0], :, :] * A + data_ab_rs[:, [1], :, :]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_inst_colorization/test_colorization_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS def test_colorization_net(): model_cfg = dict( type='ColorizationNet', input_nc=4, output_nc=2, norm_type='batch') # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'ColorizationNet' # prepare data input_A = torch.rand(1, 1, 256, 256) input_B = torch.rand(1, 2, 256, 256) mask_B = torch.rand(1, 1, 256, 256) target_shape = (1, 2, 256, 256) # test on cpu (out_class, out_reg, feature_map) = model(input_A, input_B, mask_B) assert isinstance(feature_map, dict) assert feature_map['conv1_2'].shape == (1, 64, 256, 256) \ and feature_map['out_reg'].shape == target_shape # test on gpu if torch.cuda.is_available(): model = model.cuda() input_A = input_A.cuda() input_B = input_B.cuda() mask_B = mask_B.cuda() (out_class, out_reg, feature_map) = \ model(input_A, input_B, mask_B) assert isinstance(feature_map, dict) for item in feature_map.keys(): assert torch.is_tensor(feature_map[item]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_inst_colorization/test_fusion_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS def test_fusion_net(): model_cfg = dict( type='FusionNet', input_nc=4, output_nc=2, norm_type='batch') # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'FusionNet' # prepare data input_A = torch.rand(1, 1, 256, 256) input_B = torch.rand(1, 2, 256, 256) mask_B = torch.rand(1, 1, 256, 256) instance_feature = dict( conv1_2=torch.rand(1, 64, 256, 256), conv2_2=torch.rand(1, 128, 128, 128), conv3_3=torch.rand(1, 256, 64, 64), conv4_3=torch.rand(1, 512, 32, 32), conv5_3=torch.rand(1, 512, 32, 32), conv6_3=torch.rand(1, 512, 32, 32), conv7_3=torch.rand(1, 512, 32, 32), conv8_up=torch.rand(1, 256, 64, 64), conv8_3=torch.rand(1, 256, 64, 64), conv9_up=torch.rand(1, 128, 128, 128), conv9_3=torch.rand(1, 128, 128, 128), conv10_up=torch.rand(1, 128, 256, 256), conv10_2=torch.rand(1, 128, 256, 256), ) target_shape = (1, 2, 256, 256) box_info_box = [ torch.tensor([[175, 29, 96, 54, 52, 106], [14, 191, 84, 61, 51, 111], [117, 64, 115, 46, 75, 95], [41, 165, 121, 47, 50, 88], [46, 136, 94, 45, 74, 117], [79, 124, 62, 115, 53, 79], [156, 64, 77, 138, 36, 41], [200, 48, 114, 131, 8, 11], [115, 78, 92, 81, 63, 83]]), torch.tensor([[87, 15, 48, 27, 26, 53], [7, 96, 42, 31, 25, 55], [58, 32, 57, 23, 38, 48], [20, 83, 60, 24, 25, 44], [23, 68, 47, 23, 37, 58], [39, 62, 31, 58, 27, 39], [78, 32, 38, 69, 18, 21], [100, 24, 57, 66, 4, 5], [57, 39, 46, 41, 32, 41]]), torch.tensor([[43, 8, 24, 14, 13, 26], [3, 48, 21, 16, 13, 27], [29, 16, 28, 12, 19, 24], [10, 42, 30, 12, 12, 22], [11, 34, 23, 12, 19, 29], [19, 31, 15, 29, 14, 20], [39, 16, 19, 35, 9, 10], [50, 12, 28, 33, 2, 3], [28, 20, 23, 21, 16, 20]]), torch.tensor([[21, 4, 12, 7, 7, 13], [1, 24, 10, 8, 7, 14], [14, 8, 14, 6, 10, 12], [5, 21, 15, 6, 6, 11], [5, 17, 11, 6, 10, 15], [9, 16, 7, 15, 7, 10], [19, 8, 9, 18, 5, 5], [25, 6, 14, 17, 1, 1], [14, 10, 11, 11, 8, 10]]) ] # test on cpu out = model(input_A, input_B, mask_B, instance_feature, box_info_box) assert torch.is_tensor(out) assert out.shape == target_shape # test on gpu if torch.cuda.is_available(): model = model.cuda() input_A = input_A.cuda() input_B = input_B.cuda() mask_B = mask_B.cuda() for item in instance_feature.keys(): instance_feature[item] = instance_feature[item].cuda() box_info_box = [i.cuda() for i in box_info_box] output = model(input_A, input_B, mask_B, instance_feature, box_info_box) assert torch.is_tensor(output) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_inst_colorization/test_inst_colorization.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import unittest import pytest import torch from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') class TestInstColorization: def test_inst_colorization(self): if not torch.cuda.is_available(): # RoI pooling only support in GPU return unittest.skip('test requires GPU and torch+cuda') register_all_modules() model_cfg = dict( type='InstColorization', data_preprocessor=dict( type='DataPreprocessor', mean=[127.5], std=[127.5], ), image_model=dict( type='ColorizationNet', input_nc=4, output_nc=2, norm_type='batch'), instance_model=dict( type='ColorizationNet', input_nc=4, output_nc=2, norm_type='batch'), fusion_model=dict( type='FusionNet', input_nc=4, output_nc=2, norm_type='batch'), color_data_opt=dict( ab_thresh=0, p=1.0, sample_PS=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, ], ab_norm=110, ab_max=110., ab_quant=10., l_norm=100., l_cent=50., mask_cent=0.5), which_direction='AtoB', loss=dict(type='HuberLoss', delta=.01)) model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'InstColorization' # prepare data inputs = torch.rand(1, 3, 256, 256) target_shape = (1, 3, 256, 256) data_sample = DataSample(gt_img=inputs) metainfo = dict( cropped_img=torch.rand(9, 3, 256, 256), box_info=torch.tensor([[175, 29, 96, 54, 52, 106], [14, 191, 84, 61, 51, 111], [117, 64, 115, 46, 75, 95], [41, 165, 121, 47, 50, 88], [46, 136, 94, 45, 74, 117], [79, 124, 62, 115, 53, 79], [156, 64, 77, 138, 36, 41], [200, 48, 114, 131, 8, 11], [115, 78, 92, 81, 63, 83]]), box_info_2x=torch.tensor([[87, 15, 48, 27, 26, 53], [7, 96, 42, 31, 25, 55], [58, 32, 57, 23, 38, 48], [20, 83, 60, 24, 25, 44], [23, 68, 47, 23, 37, 58], [39, 62, 31, 58, 27, 39], [78, 32, 38, 69, 18, 21], [100, 24, 57, 66, 4, 5], [57, 39, 46, 41, 32, 41]]), box_info_4x=torch.tensor([[43, 8, 24, 14, 13, 26], [3, 48, 21, 16, 13, 27], [29, 16, 28, 12, 19, 24], [10, 42, 30, 12, 12, 22], [11, 34, 23, 12, 19, 29], [19, 31, 15, 29, 14, 20], [39, 16, 19, 35, 9, 10], [50, 12, 28, 33, 2, 3], [28, 20, 23, 21, 16, 20]]), box_info_8x=torch.tensor([[21, 4, 12, 7, 7, 13], [1, 24, 10, 8, 7, 14], [14, 8, 14, 6, 10, 12], [5, 21, 15, 6, 6, 11], [5, 17, 11, 6, 10, 15], [9, 16, 7, 15, 7, 10], [19, 8, 9, 18, 5, 5], [25, 6, 14, 17, 1, 1], [14, 10, 11, 11, 8, 10]]), empty_box=False) data_sample.set_metainfo(metainfo=metainfo) data = dict( inputs=inputs, data_samples=DataSample.stack([data_sample])) res = model(mode='tensor', **data) assert torch.is_tensor(res) assert res.shape == target_shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_inst_colorization/test_weight_layer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.inst_colorization.weight_layer import WeightLayer @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_weight_layer(): weight_layer = WeightLayer(64) instance_feature_conv1_2 = torch.rand(1, 64, 256, 256) conv1_2 = torch.rand(1, 64, 256, 256) box_info = torch.tensor([[175, 29, 96, 54, 52, 106], [14, 191, 84, 61, 51, 111], [117, 64, 115, 46, 75, 95], [41, 165, 121, 47, 50, 88], [46, 136, 94, 45, 74, 117], [79, 124, 62, 115, 53, 79], [156, 64, 77, 138, 36, 41], [200, 48, 114, 131, 8, 11], [115, 78, 92, 81, 63, 83]]) conv1_2 = weight_layer(instance_feature_conv1_2, conv1_2, box_info) assert conv1_2.shape == instance_feature_conv1_2.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_liif/test_liif.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from typing import List import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import LIIF, DataPreprocessor from mmagic.structures import DataSample def test_liif(): model = LIIF( generator=dict( type='LIIFEDSRNet', encoder=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=4, num_blocks=2), imnet=dict( type='MLPRefiner', in_dim=64, out_dim=3, hidden_list=[4, 4, 4, 4]), local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=64), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), data_preprocessor=DataPreprocessor( mean=[0.4488 * 255, 0.4371 * 255, 0.4040 * 255], std=[255., 255., 255.], # input_view=(-1, 1, 1), # output_view=(1, -1) )) # test attributes assert model.__class__.__name__ == 'LIIF' # prepare data inputs = torch.rand(1, 3, 8, 8) data_sample = DataSample( metainfo=dict(coord=torch.rand(256, 2), cell=torch.rand(256, 2))) data_sample.gt_img = torch.rand(256, 3) data = dict(inputs=inputs, data_samples=[data_sample]) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars['loss'], torch.Tensor) save_loss = log_vars['loss'] log_vars = model.train_step(data, optim_wrapper) log_vars = model.train_step(data, optim_wrapper) assert save_loss > log_vars['loss'] # val predictions = model.val_step(data) # predictions = predictions.split() assert isinstance(predictions, List) assert len(predictions) == 1 assert isinstance(predictions[0], DataSample) assert isinstance(predictions[0].output.pred_img.data, torch.Tensor) assert predictions[0].output.pred_img.shape == (3, 16, 16) # feat output = model( torch.rand(1, 3, 8, 8), DataSample.stack([data_sample]), mode='tensor') assert output.shape == (1, 256, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_liif/test_liif_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_liif_edsr_net(): model_cfg = dict( type='LIIFEDSRNet', encoder=dict( type='EDSRNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16), imnet=dict( type='MLPRefiner', in_dim=64, out_dim=3, hidden_list=[256, 256, 256, 256]), local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=30000) # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'LIIFEDSRNet' # prepare data inputs = torch.rand(1, 3, 22, 11) targets = torch.rand(1, 128 * 64, 3) coord = torch.rand(1, 128 * 64, 2) cell = torch.rand(1, 128 * 64, 2) # test on cpu output = model(inputs, coord, cell) output = model(inputs, coord, cell, True) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() coord = coord.cuda() cell = cell.cuda() output = model(inputs, coord, cell) output = model(inputs, coord, cell, True) assert torch.is_tensor(output) assert output.shape == targets.shape def test_liif_rdn_net(): model_cfg = dict( type='LIIFRDNNet', encoder=dict( type='RDNNet', in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=4, num_layers=8, channel_growth=64), imnet=dict( type='MLPRefiner', in_dim=64, out_dim=3, hidden_list=[256, 256, 256, 256]), local_ensemble=True, feat_unfold=True, cell_decode=True, eval_bsize=30000) # build model model = MODELS.build(model_cfg) # test attributes assert model.__class__.__name__ == 'LIIFRDNNet' # prepare data inputs = torch.rand(1, 3, 22, 11) targets = torch.rand(1, 128 * 64, 3) coord = torch.rand(1, 128 * 64, 2) cell = torch.rand(1, 128 * 64, 2) # test on cpu output = model(inputs, coord, cell) output = model(inputs, coord, cell, True) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() coord = coord.cuda() cell = cell.cuda() output = model(inputs, coord, cell) output = model(inputs, coord, cell, True) assert torch.is_tensor(output) assert output.shape == targets.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_liif/test_mlp_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import MLPRefiner def test_MLPRefiner(): model = MLPRefiner(8, 2, [6, 4]) inputs = torch.randn(1, 8) outputs = model(inputs) assert outputs.shape == (1, 2) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_lsgan/test_lsgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import LSGAN, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='DCGANGenerator', noise_size=10, output_scale=16, base_channels=16) discriminator = dict( type='DCGANDiscriminator', input_scale=16, output_scale=4, out_channels=1) class TestLSGAN(TestCase): def test_init(self): gan = LSGAN( noise_size=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator) self.assertIsInstance(gan, LSGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = LSGAN( generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = LSGAN( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = LSGAN(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('test-lsgan') gan = LSGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_lsgan/test_lsgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.lsgan import LSGANDiscriminator from mmagic.registry import MODELS class TestLSGANDiscriminator(object): @classmethod def setup_class(cls): cls.x = torch.randn((2, 3, 128, 128)) cls.default_config = dict( type='LSGANDiscriminator', in_channels=3, input_scale=128) def test_lsgan_discriminator(self): # test default setting with builder d = MODELS.build(self.default_config) assert isinstance(d, LSGANDiscriminator) score = d(self.x) assert score.shape == (2, 1) # test different input_scale config = dict(type='LSGANDiscriminator', in_channels=3, input_scale=64) d = MODELS.build(config) assert isinstance(d, LSGANDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x) assert score.shape == (2, 1) # test different config config = dict( type='LSGANDiscriminator', in_channels=3, input_scale=64, out_act_cfg=dict(type='Sigmoid')) d = MODELS.build(config) assert isinstance(d, LSGANDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x) assert score.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_lsgan_discriminator_cuda(self): # test default setting with builder d = MODELS.build(self.default_config).cuda() assert isinstance(d, LSGANDiscriminator) score = d(self.x.cuda()) assert score.shape == (2, 1) # test different input_scale config = dict(type='LSGANDiscriminator', in_channels=3, input_scale=64) d = MODELS.build(config).cuda() assert isinstance(d, LSGANDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x.cuda()) assert score.shape == (2, 1) # test different config config = dict( type='LSGANDiscriminator', in_channels=3, input_scale=64, out_act_cfg=dict(type='Sigmoid')) d = MODELS.build(config).cuda() assert isinstance(d, LSGANDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x.cuda()) assert score.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_lsgan/test_lsgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.lsgan import LSGANGenerator from mmagic.registry import MODELS class TestLSGANGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((3, 128)) cls.default_config = dict( type='LSGANGenerator', noise_size=128, output_scale=128) def test_lsgan_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, LSGANGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) x = g(None, num_batches=3, return_noise=True) assert x['noise_batch'].shape == (3, 128) x = g(self.noise, return_noise=True) assert x['noise_batch'].shape == (3, 128) x = g(torch.randn, num_batches=3, return_noise=True) assert x['noise_batch'].shape == (3, 128) # test different output_scale config = dict(type='LSGANGenerator', noise_size=128, output_scale=64) g = MODELS.build(config) assert isinstance(g, LSGANGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 64, 64) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_lsgan_generator_cuda(self): # test default setting with builder g = MODELS.build(self.default_config).cuda() assert isinstance(g, LSGANGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) x = g(None, num_batches=3, return_noise=True) assert x['noise_batch'].shape == (3, 128) x = g(self.noise.cuda(), return_noise=True) assert x['noise_batch'].shape == (3, 128) x = g(torch.randn, num_batches=3, return_noise=True) assert x['noise_batch'].shape == (3, 128) # test different output_scale config = dict(type='LSGANGenerator', noise_size=128, output_scale=64) g = MODELS.build(config).cuda() assert isinstance(g, LSGANGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_mspie_stylegan2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest import TestCase import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmagic.models import DataPreprocessor, MSPIEStyleGAN2 from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestMSPIEStyleGAN2(TestCase): @classmethod def setup_class(cls): cls.generator_cfg = dict( type='MSStyleGANv2Generator', out_size=32, style_channels=16) cls.disc_cfg = dict(type='MSStyleGAN2Discriminator', in_size=32) # reg params d_reg_interval = 16 g_reg_interval = 4 ema_half_life = 10. # G_smoothing_kimg cls.ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) cls.loss_config = dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2) @pytest.mark.skipif( ('win' in platform.system().lower() and 'cu' in torch.__version__) or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') def test_stylegan2_cpu(self): accu_iter = 1 message_hub = MessageHub.get_instance('test-mspie-s2') gan = MSPIEStyleGAN2( self.generator_cfg, self.disc_cfg, data_preprocessor=DataPreprocessor(), ema_config=self.ema_config, loss_config=self.loss_config, train_settings=dict(num_upblocks=3)) optimizer_g = torch.optim.SGD(gan.generator.parameters(), lr=0.01) optimizer_d = torch.optim.SGD(gan.discriminator.parameters(), lr=0.01) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(optimizer_g, accumulative_counts=accu_iter), discriminator=OptimWrapper( optimizer_d, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 32, 32) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here message_hub.update_info('iter', 0) _ = gan.train_step(data, optim_wrapper_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.mspie import MSStyleGAN2Discriminator class TestMSStyleGANv2Disc: @classmethod def setup_class(cls): cls.default_cfg = dict(in_size=64, channel_multiplier=1) def test_msstylegan2_disc_cpu(self): d = MSStyleGAN2Discriminator(**self.default_cfg) img = torch.randn((2, 3, 64, 64)) score = d(img) assert score.shape == (2, 1) d = MSStyleGAN2Discriminator( with_adaptive_pool=True, **self.default_cfg) img = torch.randn((2, 3, 64, 64)) score = d(img) assert score.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_msstylegan2_disc_cuda(self): d = MSStyleGAN2Discriminator(**self.default_cfg).cuda() img = torch.randn((2, 3, 64, 64)).cuda() score = d(img) assert score.shape == (2, 1) d = MSStyleGAN2Discriminator( with_adaptive_pool=True, **self.default_cfg).cuda() img = torch.randn((2, 3, 64, 64)).cuda() score = d(img) assert score.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch import torch.nn as nn from mmagic.models.editors.mspie import MSStyleGANv2Generator from mmagic.registry import MODELS from mmagic.utils import register_all_modules register_all_modules() @MODELS.register_module() class MockHeadPosEncoding(nn.Module): def __init__(self): super().__init__() class TestMSStyleGAN2: @classmethod def setup_class(cls): cls.default_cfg = dict(out_size=32, style_channels=16) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_msstylegan2_cpu(self): # test normal forward cfg = deepcopy(self.default_cfg) g = MSStyleGANv2Generator(**cfg) res = g(None, num_batches=2) assert res.shape == (2, 3, 32, 32) # set mix_prob as 1.0 and 0 to force cover lines cfg = deepcopy(self.default_cfg) cfg['mix_prob'] = 1 g = MSStyleGANv2Generator(**cfg) res = g(torch.randn, num_batches=2) assert res.shape == (2, 3, 32, 32) # test style-mixing with inject_inde is passed res = g(torch.randn, num_batches=2, inject_index=0) assert res.shape == (2, 3, 32, 32) cfg = deepcopy(self.default_cfg) cfg['mix_prob'] = 0 g = MSStyleGANv2Generator(**cfg) res = g(torch.randn, num_batches=2) assert res.shape == (2, 3, 32, 32) cfg = deepcopy(self.default_cfg) cfg['mix_prob'] = 1 g = MSStyleGANv2Generator(**cfg) res = g(None, num_batches=2) assert res.shape == (2, 3, 32, 32) cfg = deepcopy(self.default_cfg) cfg['mix_prob'] = 0 g = MSStyleGANv2Generator(**cfg) res = g(None, num_batches=2) assert res.shape == (2, 3, 32, 32) # test truncation less than 1 res = g(None, num_batches=2, truncation=0.5) assert res.shape == (2, 3, 32, 32) # test chosen scale res = g(None, num_batches=2, chosen_scale=2, randomize_noise=False) print(res.shape) # test injected_noise is not None injected_noise = g.make_injected_noise() res = g(None, num_batches=2, injected_noise=injected_noise) # test return noise is True res = g(None, num_batches=2, return_noise=True) assert isinstance(res, dict) # test chosen_scale is Tuple res = g(None, num_batches=2, chosen_scale=(0, 2)) print(res.shape) def test_train(self): cfg = deepcopy(self.default_cfg) g = MSStyleGANv2Generator(**cfg) # test train -> train g.train() assert g.training assert g.default_style_mode == g._default_style_mode # test train -> eval g.eval() assert not g.training assert g.default_style_mode == g.eval_style_mode # test eval -> eval g.eval() assert not g.training assert g.default_style_mode == g.eval_style_mode # test train -> train g.train() assert g.training assert g.default_style_mode == g._default_style_mode # def test_make_injected_noise(self): # cfg = deepcopy(self.default_cfg) # g = MSStyleGANv2Generator(**cfg) # pass def test_mean_latent(self): cfg = deepcopy(self.default_cfg) g = MSStyleGANv2Generator(**cfg) mean_latent = g.get_mean_latent(num_samples=4, bs_per_repeat=2) assert mean_latent.shape == (1, 16) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_head_pos_encoding(self): cfg = deepcopy(self.default_cfg) g = MSStyleGANv2Generator(**cfg, head_pos_encoding=dict(type='CSG')) res = g(None, num_batches=2) assert res.shape == (2, 3, 32, 32) g = MSStyleGANv2Generator( **cfg, head_pos_encoding=dict(type='CSG'), interp_head=True) res = g(None, num_batches=2) assert res.shape == (2, 3, 32, 32) g = MSStyleGANv2Generator( **cfg, head_pos_encoding=dict(type='MockHeadPosEncoding')) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy from unittest import TestCase import pytest import torch from mmagic.models.editors.mspie.mspie_stylegan2_modules import ( ModulatedPEConv2d, ModulatedPEStyleConv) class TestModulatedPEStyleConv(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( in_channels=8, out_channels=8, kernel_size=3, style_channels=16) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_upsample(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEStyleConv(**cfg, upsample=True) x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 64, 64)) # test return noise noise = torch.randn(1, 8, 64, 64) out = conv(x, style, noise) self.assertEqual(out.shape, (1, 8, 64, 64)) out, noise_return = conv(x, style, noise, return_noise=True) assert (noise_return == noise).all() @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_downsample(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEStyleConv(**cfg, downsample=True) x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 16, 16)) # test return noise noise = torch.randn(1, 8, 16, 16) out = conv(x, style, noise) self.assertEqual(out.shape, (1, 8, 16, 16)) out, noise_return = conv(x, style, noise, return_noise=True) assert (noise_return == noise).all() class TestModulatedPEConv2d(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( in_channels=8, out_channels=8, kernel_size=3, style_channels=16) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_equalized_lr_cfg(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEConv2d(**cfg, equalized_lr_cfg=None) x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 32, 32)) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_demodulate(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEConv2d(**cfg, demodulate=False) x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 32, 32)) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_up_after_conv(self): x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) cfg = deepcopy(self.default_cfg) conv = ModulatedPEConv2d( **cfg, upsample=True, deconv2conv=True, up_after_conv=True) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 64, 64)) conv = ModulatedPEConv2d( **cfg, upsample=True, deconv2conv=True, up_after_conv=False) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 64, 64)) conv = ModulatedPEConv2d( **cfg, upsample=True, deconv2conv=True, interp_pad=3) out = conv(x, style) self.assertEqual(out.shape, (1, 8, 67, 67)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_pe_singan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine import MessageHub from mmagic.engine import SinGANOptimWrapperConstructor from mmagic.models import PESinGAN from mmagic.utils import register_all_modules register_all_modules() class TestPESinGAN: @classmethod def setup_class(cls): cls.generator = dict( type='SinGANMSGeneratorPE', in_channels=3, out_channels=3, num_scales=3, interp_pad=True, noise_with_pad=True) cls.disc = dict( type='SinGANMultiScaleDiscriminator', in_channels=3, num_scales=3) # noqa cls.data_preprocessor = dict( type='DataPreprocessor', non_image_keys=['input_sample']) cls.noise_weight_init = 0.1 cls.iters_per_scale = 2 cls.disc_steps = 3 cls.generator_steps = 3 cls.fixed_noise_with_pad = True cls.lr_scheduler_args = dict(milestones=[1600], gamma=0.1) cls.data_batch = dict( inputs=dict( real_scale0=torch.randn(1, 3, 25, 25), real_scale1=torch.randn(1, 3, 30, 30), real_scale2=torch.randn(1, 3, 32, 32), )) cls.data_batch['inputs']['input_sample'] = torch.zeros_like( cls.data_batch['inputs']['real_scale0']) cls.optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999)))) def test_pesingan_cpu(self): message_hub = MessageHub.get_instance('test-pe-singan') message_hub.update_info('iter', 0) singan = PESinGAN( self.generator, self.disc, num_scales=3, data_preprocessor=self.data_preprocessor, noise_weight_init=self.noise_weight_init, iters_per_scale=self.iters_per_scale, lr_scheduler_args=self.lr_scheduler_args, fixed_noise_with_pad=self.fixed_noise_with_pad) optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(singan) for i in range(6): singan.train_step(self.data_batch, optim_wrapper_dict) message_hub.update_info('iter', message_hub.get_info('iter') + 1) # img = singan.forward(dict(num_batches=1), None) # if i in [0, 1]: # assert singan.curr_stage == 0 # assert img.shape[-2:] == (25, 25) # elif i in [2, 3]: # assert singan.curr_stage == 1 # assert img.shape[-2:] == (30, 30) # elif i in [4, 5]: # assert singan.curr_stage == 2 # assert img.shape[-2:] == (32, 32) singan = PESinGAN( dict( type='SinGANMSGeneratorPE', in_channels=3, out_channels=3, num_scales=3, interp_pad=True, noise_with_pad=False), self.disc, num_scales=3, data_preprocessor=self.data_preprocessor, noise_weight_init=0.1, iters_per_scale=2, discriminator_steps=1, generator_steps=1, lr_scheduler_args=dict(milestones=[1600], gamma=0.1), fixed_noise_with_pad=False) optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(singan) message_hub.update_info('iter', 0) for i in range(6): singan.train_step(self.data_batch, optim_wrapper_dict) message_hub.update_info('iter', message_hub.get_info('iter') + 1) outputs = singan.forward(dict(num_batches=1), None) img = torch.stack([out.fake_img.data for out in outputs]) if i in [0, 1]: assert singan.curr_stage == 0 assert img.shape[-2:] == (25, 25) elif i in [2, 3]: assert singan.curr_stage == 1 assert img.shape[-2:] == (30, 30) elif i in [4, 5]: assert singan.curr_stage == 2 assert img.shape[-2:] == (32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_pe_singan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.mspie import SinGANMSGeneratorPE class TestSinGANPEGen: @classmethod def setup_class(cls): cls.default_args = dict( in_channels=3, out_channels=3, kernel_size=3, num_layers=3, base_channels=32, num_scales=3, min_feat_channels=16) cls.fixed_noises = [ torch.randn(1, 1, 8, 8), torch.randn(1, 3, 10, 10), torch.randn(1, 3, 12, 12), torch.randn(1, 3, 16, 16) ] cls.input_sample = torch.zeros((1, 3, 8, 8)) cls.noise_weights = [1., 0.5, 0.5, 0.5] def test_singan_gen_pe(self): gen = SinGANMSGeneratorPE(**self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) output = gen( self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2, get_prev_res=True) assert output['prev_res_list'][0].shape == (1, 3, 8, 8) gen = SinGANMSGeneratorPE( padding_mode='reflect', **self.default_args) # noqa res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) with pytest.raises(NotImplementedError): _ = SinGANMSGeneratorPE( padding_mode='circular', **self.default_args) gen = SinGANMSGeneratorPE( padding=1, pad_at_head=False, **self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) gen = SinGANMSGeneratorPE( pad_at_head=True, interp_pad=True, **self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) gen = SinGANMSGeneratorPE( positional_encoding=dict( type='SPE2d', embedding_dim=4, padding_idx=0), allow_no_residual=True, first_stage_in_channels=8, **self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) gen = SinGANMSGeneratorPE( positional_encoding=dict(type='CSG2d'), allow_no_residual=True, first_stage_in_channels=2, **self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) gen = SinGANMSGeneratorPE( interp_pad=True, noise_with_pad=True, **self.default_args) res = gen(None, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 6, 6) gen = SinGANMSGeneratorPE( interp_pad=True, noise_with_pad=False, **self.default_args) res = gen(None, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_mspie/test_positional_encoding.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.mspie import CatersianGrid as CSG from mmagic.models.editors.mspie import SinusoidalPositionalEmbedding as SPE class TestSPE: @classmethod def setup_class(cls): cls.spe = SPE(4, 0, 32) def test_spe_cpu(self): # test spe 1d embed = self.spe(torch.randn((2, 10))) assert embed.shape == (2, 10, 4) # test spe 2d embed = self.spe(torch.randn((2, 3, 8, 8))) assert embed.shape == (2, 8, 8, 8) with pytest.raises(AssertionError): _ = self.spe(torch.randn(2, 3, 3)) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_spe_gpu(self): spe = self.spe.cuda() # test spe 1d embed = spe(torch.randn((2, 10)).cuda()) assert embed.shape == (2, 10, 4) assert embed.is_cuda # test spe 2d embed = spe(torch.randn((2, 3, 8, 8)).cuda()) assert embed.shape == (2, 8, 8, 8) with pytest.raises(AssertionError): _ = spe(torch.randn(2, 3, 3)) class TestCSG: @classmethod def setup_class(cls): cls.csg = CSG() def test_csg_cpu(self): csg = self.csg(torch.randn((2, 3, 4, 4))) assert csg.shape == (2, 2, 4, 4) with pytest.raises(AssertionError): _ = self.csg(torch.randn((2, 3, 3))) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_csg_cuda(self): embed = self.csg(torch.randn((2, 4, 5, 5)).cuda()) assert embed.shape == (2, 2, 5, 5) and embed.is_cuda def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_nafnet/test_naf_avgpool2d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.nafnet.naf_avgpool2d import NAFAvgPool2d def test_avgpool2d(): inputs = torch.ones((1, 3, 32, 32)) targets = torch.Tensor([1., 1., 1.]).view(1, 3, 1, 1) tar_info = 'kernel_size=None, base_size=(48, 48),' \ + ' stride=None, fast_imp=False' base_size = (int(inputs.shape[-2] * 1.5), int(inputs.shape[-1] * 1.5)) train_size = inputs.shape avg_pool_2d = NAFAvgPool2d( base_size=base_size, train_size=train_size, fast_imp=False) info = avg_pool_2d.extra_repr() outputs = avg_pool_2d(inputs) print(outputs) assert info == tar_info assert torch.all(torch.eq(targets, outputs)) avg_pool_2d = NAFAvgPool2d( base_size=int(inputs.shape[-2] * 1.5), train_size=train_size, fast_imp=False) info = avg_pool_2d.extra_repr() tar_info = 'kernel_size=None, base_size=48,' \ + ' stride=None, fast_imp=False' outputs = avg_pool_2d(inputs) print(outputs) assert info == tar_info assert torch.all(torch.eq(targets, outputs)) avg_pool_2d = NAFAvgPool2d( base_size=base_size, train_size=train_size, fast_imp=True) info = avg_pool_2d.extra_repr() tar_info = 'kernel_size=None, base_size=(48, 48),' \ + ' stride=None, fast_imp=True' outputs = avg_pool_2d(inputs) print(outputs) assert info == tar_info assert torch.all(torch.eq(targets, outputs)) avg_pool_2d = NAFAvgPool2d( base_size=(16, 16), train_size=train_size, fast_imp=True) info = avg_pool_2d.extra_repr() tar_info = 'kernel_size=None, base_size=(16, 16),' \ + ' stride=None, fast_imp=True' outputs = avg_pool_2d(inputs) print(outputs) assert info == tar_info assert torch.all(torch.eq(targets, outputs)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_nafnet/test_naf_layernorm2d.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.nafnet.naf_layerNorm2d import LayerNorm2d def test_layer_norm(): inputs = torch.ones((1, 3, 64, 64)) targets = torch.zeros((1, 3, 64, 64)) layer_norm_2d = LayerNorm2d(inputs.shape[1]) outputs = layer_norm_2d(inputs) assert outputs.shape == targets.shape assert torch.all(torch.eq(outputs, targets)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_nafnet/test_nafbaseline.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models import NAFBaseline, NAFBaselineLocal def test_nafnet(): model = NAFBaseline( img_channel=3, mid_channels=64, enc_blk_nums=[2, 2, 4, 8], middle_blk_num=12, dec_blk_nums=[2, 2, 2, 2], ) # test attributes assert model.__class__.__name__ == 'NAFBaseline' # prepare data inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) # test on cpu output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape def test_baseline_local(): model = NAFBaselineLocal( img_channel=3, mid_channels=64, enc_blk_nums=[1, 1, 1, 28], middle_blk_num=1, dec_blk_nums=[1, 1, 1, 1], ) # test attributes assert model.__class__.__name__ == 'NAFBaselineLocal' # prepare data inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) # test on cpu output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_nafnet/test_nafnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models import NAFNet, NAFNetLocal def test_nafnet(): model = NAFNet( img_channels=3, mid_channels=64, enc_blk_nums=[2, 2, 4, 8], middle_blk_num=12, dec_blk_nums=[2, 2, 2, 2], ) # test attributes assert model.__class__.__name__ == 'NAFNet' # prepare data inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) # test on cpu output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape def test_nafnet_local(): model = NAFNetLocal( img_channels=3, mid_channels=64, enc_blk_nums=[1, 1, 1, 28], middle_blk_num=1, dec_blk_nums=[1, 1, 1, 1], ) # test attributes assert model.__class__.__name__ == 'NAFNetLocal' # prepare data inputs = torch.rand(1, 3, 64, 64) targets = torch.rand(1, 3, 64, 64) # test on cpu output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() targets = targets.cuda() output = model(inputs) assert torch.is_tensor(output) assert output.shape == targets.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_mask_conv_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch import torch.nn as nn from mmagic.models.editors import MaskConvModule from mmagic.utils import register_all_modules register_all_modules() def test_mask_conv_module(): with pytest.raises(KeyError): # conv_cfg must be a dict or None conv_cfg = dict(type='conv') MaskConvModule(3, 8, 2, conv_cfg=conv_cfg) with pytest.raises(AssertionError): # norm_cfg must be a dict or None norm_cfg = ['norm'] MaskConvModule(3, 8, 2, norm_cfg=norm_cfg) with pytest.raises(AssertionError): # order elements must be ('conv', 'norm', 'act') order = ['conv', 'norm', 'act'] MaskConvModule(3, 8, 2, order=order) with pytest.raises(AssertionError): # order elements must be ('conv', 'norm', 'act') order = ('conv', 'norm') MaskConvModule(3, 8, 2, order=order) with pytest.raises(KeyError): # softmax is not supported act_cfg = dict(type='softmax') MaskConvModule(3, 8, 2, act_cfg=act_cfg) conv_cfg = dict(type='PConv', multi_channel=True) conv = MaskConvModule(3, 8, 2, conv_cfg=conv_cfg) x = torch.rand(1, 3, 256, 256) mask_in = torch.ones_like(x) mask_in[..., 20:130, 120:150] = 0. output, mask_update = conv(x, mask_in) assert output.shape == (1, 8, 255, 255) assert mask_update.shape == (1, 8, 255, 255) # add test for ['norm', 'conv', 'act'] conv = MaskConvModule( 3, 8, 2, order=('norm', 'conv', 'act'), conv_cfg=conv_cfg) x = torch.rand(1, 3, 256, 256) output = conv(x, mask_in, return_mask=False) assert output.shape == (1, 8, 255, 255) conv = MaskConvModule( 3, 8, 3, padding=1, conv_cfg=conv_cfg, with_spectral_norm=True) assert hasattr(conv.conv, 'weight_orig') output = conv(x, return_mask=False) assert output.shape == (1, 8, 256, 256) conv = MaskConvModule( 3, 8, 3, padding=1, norm_cfg=dict(type='BN'), padding_mode='reflect', conv_cfg=conv_cfg) assert isinstance(conv.padding_layer, nn.ReflectionPad2d) output = conv(x, mask_in, return_mask=False) assert output.shape == (1, 8, 256, 256) conv = MaskConvModule( 3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU'), conv_cfg=conv_cfg) output = conv(x, mask_in, return_mask=False) assert output.shape == (1, 8, 256, 256) with pytest.raises(KeyError): conv = MaskConvModule(3, 8, 3, padding=1, padding_mode='igccc') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_partial_conv.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors import PartialConv2d def test_pconv2d(): pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, multi_channel=True, eps=1e-8) x = torch.rand(1, 3, 6, 6) mask = torch.ones_like(x) mask[..., 2, 2] = 0. output, updated_mask = pconv2d(x, mask=mask) assert output.shape == (1, 2, 6, 6) assert updated_mask.shape == (1, 2, 6, 6) output = pconv2d(x, mask=None) assert output.shape == (1, 2, 6, 6) pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, multi_channel=True, eps=1e-8) output = pconv2d(x, mask=None) assert output.shape == (1, 2, 6, 6) pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, multi_channel=False, eps=1e-8) output = pconv2d(x, mask=None) assert output.shape == (1, 2, 6, 6) pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, bias=False, multi_channel=True, eps=1e-8) output = pconv2d(x, mask=mask, return_mask=False) assert output.shape == (1, 2, 6, 6) with pytest.raises(AssertionError): pconv2d(x, mask=torch.ones(1, 1, 6, 6)) pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, bias=False, multi_channel=False, eps=1e-8) output = pconv2d(x, mask=None) assert output.shape == (1, 2, 6, 6) with pytest.raises(AssertionError): output = pconv2d(x, mask=mask[0]) with pytest.raises(AssertionError): output = pconv2d(x, mask=torch.ones(1, 3, 6, 6)) if torch.cuda.is_available(): pconv2d = PartialConv2d( 3, 2, kernel_size=1, stride=1, bias=False, multi_channel=False, eps=1e-8).cuda().half() output = pconv2d(x.cuda().half(), mask=None) assert output.shape == (1, 2, 6, 6) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_pconv_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import PConvDecoder, PConvEncoder from mmagic.utils import register_all_modules register_all_modules() def test_pconv_dec(): pconv_enc = PConvEncoder() img = torch.randn(2, 3, 128, 128) mask = torch.ones_like(img) output = pconv_enc(img, mask) pconv_dec = PConvDecoder() input = { 'hidden_feats': output['hidden_feats'], 'hidden_masks': output['hidden_masks'] } h, h_mask = pconv_dec(input) assert h.detach().numpy().shape == (2, 3, 128, 128) assert h_mask.detach().numpy().shape == (2, 3, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_pconv_encoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from mmagic.models.editors import PConvEncoder def test_pconv_enc(): pconv_enc = PConvEncoder(norm_eval=False) pconv_enc.train() for name, module in pconv_enc.named_modules(): if isinstance(module, _BatchNorm): assert module.training pconv_enc = PConvEncoder(norm_eval=True) pconv_enc.train() for name, module in pconv_enc.named_modules(): if isinstance(module, _BatchNorm): assert not module.training pconv_enc = PConvEncoder() img = torch.randn(2, 3, 128, 128) mask = torch.ones_like(img) output = pconv_enc(img, mask) assert isinstance(output['hidden_feats'], dict) assert isinstance(output['hidden_masks'], dict) assert output['out'].detach().numpy().shape == (2, 512, 1, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_pconv_encoder_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors import PConvEncoderDecoder def test_pconv_encdec(): pconv_enc_cfg = dict(type='PConvEncoder') pconv_dec_cfg = dict(type='PConvDecoder') if torch.cuda.is_available(): pconv_encdec = PConvEncoderDecoder(pconv_enc_cfg, pconv_dec_cfg) pconv_encdec.init_weights() pconv_encdec.cuda() x = torch.randn((1, 3, 256, 256)).cuda() mask = torch.ones_like(x) mask[..., 50:150, 100:250] = 1. res, updated_mask = pconv_encdec(x, mask) assert res.shape == (1, 3, 256, 256) assert mask.shape == (1, 3, 256, 256) with pytest.raises(TypeError): pconv_encdec.init_weights(pretrained=dict(igccc=8989)) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pconv/test_pconv_inpaintor.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from os.path import dirname, join import pytest import torch from mmengine import Config from mmengine.optim import OptimWrapper from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_pconv_inpaintor(): register_all_modules() config_file = join( dirname(__file__), '../../..', 'configs', 'pconv_test.py') cfg = Config.fromfile(config_file) inpaintor = MODELS.build(cfg.model) assert inpaintor.__class__.__name__ == 'PConvInpaintor' if torch.cuda.is_available(): inpaintor = inpaintor.cuda() gt_img = torch.randn(3, 256, 256) mask = torch.zeros_like(gt_img)[0:1, ...] mask[..., 100:210, 100:210] = 1. masked_img = gt_img * (1. - mask) mask_bbox = [100, 100, 110, 110] data_batch = { 'inputs': [masked_img], 'data_samples': [DataSample( mask=mask, mask_bbox=mask_bbox, gt_img=gt_img, )] } optim_g = torch.optim.Adam(inpaintor.generator.parameters(), lr=0.0001) optim_g = OptimWrapper(optim_g) for i in range(5): log_vars = inpaintor.train_step(data_batch, optim_g) assert 'loss_l1_hole' in log_vars assert 'loss_l1_valid' in log_vars assert 'loss_tv' in log_vars # check for forward_test data = inpaintor.data_preprocessor(data_batch, True) data_inputs, data_sample = data['inputs'], data['data_samples'] output = inpaintor.forward_test(data_inputs, data_sample) prediction = output.split()[0] assert 'fake_res' in prediction assert 'fake_img' in prediction assert 'pred_img' in prediction assert prediction.pred_img.shape == (3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pggan/test_pggan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import numpy as np import pytest import torch from mmengine import MessageHub from mmagic.engine import PGGANOptimWrapperConstructor from mmagic.models import ProgressiveGrowingGAN from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestPGGAN(TestCase): generator_cfg = dict( type='PGGANGenerator', noise_size=8, out_scale=16, base_channels=32, max_channels=32) discriminator_cfg = dict( type='PGGANDiscriminator', in_scale=16, label_size=0) data_preprocessor = dict(type='DataPreprocessor') nkimgs_per_scale = {'4': 0.004, '8': 0.008, '16': 0.016} lr_schedule = dict(generator={'8': 0.0015}, discriminator={'8': 0.0015}) optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=lr_schedule) def test_pggan_cpu(self): message_hub = MessageHub.get_instance('test-pggan') message_hub.update_info('iter', 0) # test default config pggan = ProgressiveGrowingGAN( self.generator_cfg, self.discriminator_cfg, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, ema_config=dict(interval=1)) constructor = PGGANOptimWrapperConstructor(self.optim_wrapper_cfg) optim_wrapper_dict = constructor(pggan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 16, 16)) for _ in range(3) ]) for iter_num in range(6): pggan.train_step(data_batch, optim_wrapper_dict) # print(iter_num, pggan._next_scale_int) if iter_num in [0, 1]: assert pggan.curr_scale[0] == 4 elif iter_num in [2, 3]: assert pggan.curr_scale[0] == 8 elif iter_num in [4, 5]: assert pggan.curr_scale[0] == 16 if iter_num == 2: assert np.isclose(pggan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 3: assert np.isclose(pggan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 5: assert np.isclose(pggan._actual_nkimgs[-1], 0.012, atol=1e-8) # test forward outputs = pggan.forward(dict(img=torch.randn(3, 3, 16, 16))) assert len(outputs) == 3 assert all(['gt_img' in out for out in outputs]) outputs = pggan.forward(dict(num_batches=2)) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 16, 16) for out in outputs]) outputs = pggan.forward( dict( num_batches=2, return_noise=True, transition_weight=0.2, sample_model='ema')) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 16, 16) for out in outputs]) outputs = pggan.forward(dict(num_batches=2, sample_model='orig')) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 16, 16) for out in outputs]) outputs = pggan.forward(dict(num_batches=2, sample_model='ema/orig')) assert len(outputs) == 2 assert all([out.ema.fake_img.shape == (3, 16, 16) for out in outputs]) assert all([out.orig.fake_img.shape == (3, 16, 16) for out in outputs]) outputs = pggan.forward(dict(num_batches=2, curr_scale=8)) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 8, 8) for out in outputs]) outputs = pggan.forward(dict(noise=torch.randn(2, 8))) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 16, 16) for out in outputs]) outputs = pggan.forward(torch.randn(2, 8)) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 16, 16) for out in outputs]) # test train_step with error with pytest.raises(RuntimeError): data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 4, 32)) for _ in range(3) ]) _ = pggan.train_step(data_batch, optim_wrapper_dict) # test train_step without ema pggan = ProgressiveGrowingGAN( self.generator_cfg, self.discriminator_cfg, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale) optim_wrapper_dict = constructor(pggan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 16, 16)) for _ in range(3) ]) pggan.train_step(data_batch, optim_wrapper_dict) # test train_step with disc_step != 1 pggan._disc_steps = 2 pggan.train_step(data_batch, optim_wrapper_dict) # test default configs pggan = ProgressiveGrowingGAN( self.generator_cfg, self.discriminator_cfg, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, interp_real=dict(mode='bicubic'), ema_config=dict(interval=1)) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pggan_cuda(self): pggan = ProgressiveGrowingGAN( self.generator_cfg, self.discriminator_cfg, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, ema_config=dict(interval=1)).cuda() constructor = PGGANOptimWrapperConstructor(self.optim_wrapper_cfg) optim_wrapper_dict = constructor(pggan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 16, 16)) for _ in range(3) ]) for iter_num in range(6): pggan.train_step(data_batch, optim_wrapper_dict) if iter_num in [0, 1]: assert pggan.curr_scale[0] == 4 elif iter_num in [2, 3]: assert pggan.curr_scale[0] == 8 elif iter_num in [4, 5]: assert pggan.curr_scale[0] == 16 if iter_num == 2: assert np.isclose(pggan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 3: assert np.isclose(pggan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 5: assert np.isclose(pggan._actual_nkimgs[-1], 0.012, atol=1e-8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pggan/test_pggan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.pggan import PGGANDiscriminator class TestPGGANDiscriminator: @classmethod def setup_class(cls): cls.default_cfg = dict(in_scale=16, label_size=2) cls.default_inputx16 = torch.randn((2, 3, 16, 16)) cls.default_inputx4 = torch.randn((2, 3, 4, 4)) cls.default_inputx8 = torch.randn((2, 3, 8, 8)) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_pggan_discriminator(self): # test with default cfg disc = PGGANDiscriminator(**self.default_cfg) score, label = disc(self.default_inputx16, transition_weight=0.1) assert score.shape == (2, 1) assert label.shape == (2, 2) score, label = disc( self.default_inputx8, transition_weight=0.1, curr_scale=8) assert score.shape == (2, 1) assert label.shape == (2, 2) score, label = disc( self.default_inputx4, transition_weight=0.1, curr_scale=4) assert score.shape == (2, 1) assert label.shape == (2, 2) disc = PGGANDiscriminator( in_scale=16, mbstd_cfg=None, downsample_cfg=dict(type='nearest', scale_factor=0.5)) score = disc(self.default_inputx16, transition_weight=0.1) assert score.shape == (2, 1) assert label.shape == (2, 2) score = disc(self.default_inputx8, transition_weight=0.1, curr_scale=8) assert score.shape == (2, 1) assert label.shape == (2, 2) score = disc(self.default_inputx4, transition_weight=0.1, curr_scale=4) assert score.shape == (2, 1) assert label.shape == (2, 2) assert not disc.with_mbstd with pytest.raises(NotImplementedError): _ = PGGANDiscriminator( in_scale=16, mbstd_cfg=None, downsample_cfg=dict(type='xx')) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pggan_discriminator_cuda(self): # test with default cfg disc = PGGANDiscriminator(**self.default_cfg).cuda() score, label = disc( self.default_inputx16.cuda(), transition_weight=0.1) assert score.shape == (2, 1) assert label.shape == (2, 2) score, label = disc( self.default_inputx8.cuda(), transition_weight=0.1, curr_scale=8) assert score.shape == (2, 1) assert label.shape == (2, 2) score, label = disc( self.default_inputx4.cuda(), transition_weight=0.1, curr_scale=4) assert score.shape == (2, 1) assert label.shape == (2, 2) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pggan/test_pggan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch from mmagic.models.editors.pggan import PGGANGenerator class TestPGGANGenerator: @classmethod def setup_class(cls): cls.default_noise = torch.randn((2, 8)) cls.default_cfg = dict( noise_size=8, out_scale=16, base_channels=32, max_channels=32) def test_pggan_generator(self): # test with default cfg gen = PGGANGenerator(**self.default_cfg) res = gen(None, num_batches=2, transition_weight=0.1) assert res.shape == (2, 3, 16, 16) res = gen(self.default_noise, transition_weight=0.2) assert res.shape == (2, 3, 16, 16) with pytest.raises(AssertionError): _ = gen(self.default_noise[:, :, None], transition_weight=0.2) with pytest.raises(AssertionError): _ = gen(torch.randn((2, 1)), transition_weight=0.2) res = gen(torch.randn, num_batches=2, transition_weight=0.2) assert res.shape == (2, 3, 16, 16) # test with input scale res = gen(None, num_batches=2, curr_scale=4) assert res.shape == (2, 3, 4, 4) res = gen(None, num_batches=2, curr_scale=8) assert res.shape == (2, 3, 8, 8) # test return noise res = gen(None, num_batches=2, curr_scale=8, return_noise=True) assert res['fake_img'].shape == (2, 3, 8, 8) assert res['label'] is None assert isinstance(res['noise_batch'], torch.Tensor) # test args system cfg = deepcopy(self.default_cfg) cfg['out_scale'] = 32 gen = PGGANGenerator(**cfg) res = gen(None, num_batches=2, transition_weight=0.1) assert res.shape == (2, 3, 32, 32) cfg = deepcopy(self.default_cfg) cfg['out_scale'] = 4 gen = PGGANGenerator(**cfg) res = gen(None, num_batches=2, transition_weight=0.1) assert res.shape == (2, 3, 4, 4) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pggan_generator_cuda(self): # test with default cfg gen = PGGANGenerator(**self.default_cfg).cuda() res = gen(None, num_batches=2, transition_weight=0.1) assert res.shape == (2, 3, 16, 16) # test args system cfg = deepcopy(self.default_cfg) cfg['out_scale'] = 32 gen = PGGANGenerator(**cfg).cuda() res = gen(None, num_batches=2, transition_weight=0.1) assert res.shape == (2, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pggan/test_pggan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch import torch.nn as nn from mmagic.models.editors.pggan import (EqualizedLR, EqualizedLRConvDownModule, EqualizedLRConvModule, EqualizedLRConvUpModule, EqualizedLRLinearModule, MiniBatchStddevLayer, PGGANNoiseTo2DFeat, PixelNorm, equalized_lr) from mmagic.utils import register_all_modules register_all_modules() class TestEqualizedLR: @classmethod def setup_class(cls): cls.default_conv_cfg = dict( in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=1, norm_cfg=dict(type='BN')) cls.conv_input = torch.randn((2, 1, 5, 5)) cls.linear_input = torch.randn((2, 2)) def test_equalized_conv_module(self): conv = EqualizedLRConvModule(**self.default_conv_cfg) res = conv(self.conv_input) assert res.shape == (2, 1, 5, 5) has_equalized_lr = False for _, v in conv.conv._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert has_equalized_lr conv = EqualizedLRConvModule( equalized_lr_cfg=None, **self.default_conv_cfg) res = conv(self.conv_input) assert res.shape == (2, 1, 5, 5) has_equalized_lr = False for _, v in conv.conv._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert not has_equalized_lr conv = EqualizedLRConvModule( equalized_lr_cfg=dict(gain=1), **self.default_conv_cfg) res = conv(self.conv_input) assert res.shape == (2, 1, 5, 5) has_equalized_lr = False for _, v in conv.conv._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): assert v.gain == 1 has_equalized_lr = True assert has_equalized_lr @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_equalized_conv_module_cuda(self): conv = EqualizedLRConvModule(**self.default_conv_cfg).cuda() res = conv(self.conv_input.cuda()) assert res.shape == (2, 1, 5, 5) has_equalized_lr = False for _, v in conv.conv._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert has_equalized_lr def test_equalized_linear_module(self): linear = EqualizedLRLinearModule(2, 2) res = linear(self.linear_input) assert res.shape == (2, 2) has_equalized_lr = False for _, v in linear._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert has_equalized_lr linear = EqualizedLRLinearModule(2, 2, equalized_lr_cfg=None) res = linear(self.linear_input) assert res.shape == (2, 2) has_equalized_lr = False for _, v in linear._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert not has_equalized_lr @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_equalized_linear_module_cuda(self): linear = EqualizedLRLinearModule(2, 2).cuda() res = linear(self.linear_input.cuda()) assert res.shape == (2, 2) has_equalized_lr = False for _, v in linear._forward_pre_hooks.items(): if isinstance(v, EqualizedLR): has_equalized_lr = True assert has_equalized_lr def test_equalized_lr(self): with pytest.raises(RuntimeError): conv = nn.Conv2d(1, 1, 3, 1, 1) conv = equalized_lr(conv) conv = equalized_lr(conv) class TestEqualizedLRConvUpModule: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=1, kernel_size=3, padding=1, stride=2, conv_cfg=dict(type='deconv'), upsample=dict(type='fused_nn'), norm_cfg=dict(type='PixelNorm')) cls.default_input = torch.randn((2, 3, 5, 5)) def test_equalized_lr_convup_module(self, ): convup = EqualizedLRConvUpModule(**self.default_cfg) res = convup(self.default_input) assert res.shape == (2, 1, 10, 10) # test bp res = convup(torch.randn((2, 3, 5, 5), requires_grad=True)) assert res.shape == (2, 1, 10, 10) res.mean().backward() # test nearest cfg_ = deepcopy(self.default_cfg) cfg_['upsample'] = dict(type='nearest', scale_factor=2) cfg_['kernel_size'] = 4 convup = EqualizedLRConvUpModule(**cfg_) res = convup(self.default_input) assert res.shape == (2, 1, 20, 20) # test nearest cfg_ = deepcopy(self.default_cfg) cfg_['upsample'] = None cfg_['kernel_size'] = 4 convup = EqualizedLRConvUpModule(**cfg_) res = convup(self.default_input) assert res.shape == (2, 1, 10, 10) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_equalized_lr_convup_module_cuda(self): convup = EqualizedLRConvUpModule(**self.default_cfg).cuda() res = convup(self.default_input.cuda()) assert res.shape == (2, 1, 10, 10) # test bp res = convup(torch.randn((2, 3, 5, 5), requires_grad=True).cuda()) assert res.shape == (2, 1, 10, 10) res.mean().backward() class TestEqualizedLRConvDownModule: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=1, kernel_size=3, padding=1, stride=2, downsample=dict(type='fused_pool')) cls.default_input = torch.randn((2, 3, 8, 8)) def test_equalized_lr_conv_down(self): convdown = EqualizedLRConvDownModule(**self.default_cfg) res = convdown(self.default_input) assert res.shape == (2, 1, 4, 4) # test bp res = convdown(torch.randn((2, 3, 8, 8), requires_grad=True)) assert res.shape == (2, 1, 4, 4) res.mean().backward() # test avg pool cfg_ = deepcopy(self.default_cfg) cfg_['downsample'] = dict(type='avgpool', kernel_size=2, stride=2) convdown = EqualizedLRConvDownModule(**cfg_) res = convdown(self.default_input) assert res.shape == (2, 1, 2, 2) # test downsample is None cfg_ = deepcopy(self.default_cfg) cfg_['downsample'] = None convdown = EqualizedLRConvDownModule(**cfg_) res = convdown(self.default_input) assert res.shape == (2, 1, 4, 4) with pytest.raises(NotImplementedError): cfg_ = deepcopy(self.default_cfg) cfg_['downsample'] = dict(type='xxx', kernel_size=2, stride=2) _ = EqualizedLRConvDownModule(**cfg_) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_equalized_lr_conv_down_cuda(self): convdown = EqualizedLRConvDownModule(**self.default_cfg).cuda() res = convdown(self.default_input.cuda()) assert res.shape == (2, 1, 4, 4) # test bp res = convdown(torch.randn((2, 3, 8, 8), requires_grad=True).cuda()) assert res.shape == (2, 1, 4, 4) res.mean().backward() class TestPixelNorm: @classmethod def setup_class(cls): cls.input_tensor = torch.randn((2, 3, 4, 4)) def test_pixel_norm(self): pn = PixelNorm() res = pn(self.input_tensor) assert res.shape == (2, 3, 4, 4) # test zero case res = pn(self.input_tensor * 0) assert res.shape == (2, 3, 4, 4) assert (res == 0).all() @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pixel_norm_cuda(self): pn = PixelNorm().cuda() res = pn(self.input_tensor.cuda()) assert res.shape == (2, 3, 4, 4) # test zero case res = pn(self.input_tensor.cuda() * 0) assert res.shape == (2, 3, 4, 4) assert (res == 0).all() class TestMiniBatchStddevLayer: @classmethod def setup_class(cls): cls.default_input = torch.randn((2, 3, 4, 4)) def test_minibatch_stddev_layer(self): ministd_layer = MiniBatchStddevLayer() res = ministd_layer(self.default_input) assert res.shape == (2, 4, 4, 4) with pytest.raises(AssertionError): _ = ministd_layer(torch.randn((5, 4, 3, 3))) ministd_layer = MiniBatchStddevLayer(group_size=3) res = ministd_layer(torch.randn((2, 6, 4, 4))) assert res.shape == (2, 7, 4, 4) # test bp ministd_layer = MiniBatchStddevLayer() res = ministd_layer(self.default_input.requires_grad_()) assert res.shape == (2, 4, 4, 4) res.mean().backward() @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_minibatch_stddev_layer_cuda(self): ministd_layer = MiniBatchStddevLayer().cuda() res = ministd_layer(self.default_input.cuda()) assert res.shape == (2, 4, 4, 4) ministd_layer = MiniBatchStddevLayer(group_size=3).cuda() res = ministd_layer(torch.randn((2, 6, 4, 4)).cuda()) assert res.shape == (2, 7, 4, 4) # test bp ministd_layer = MiniBatchStddevLayer().cuda() res = ministd_layer(self.default_input.requires_grad_().cuda()) assert res.shape == (2, 4, 4, 4) res.mean().backward() class TestPGGANNoiseTo2DFeat: @classmethod def setup_class(cls): cls.default_input = torch.randn((2, 10)) cls.default_cfg = dict(noise_size=10, out_channels=1) def test_pggan_noise2feat(self): module = PGGANNoiseTo2DFeat(**self.default_cfg) res = module(self.default_input) assert res.shape == (2, 1, 4, 4) assert isinstance(module.linear, EqualizedLRLinearModule) assert not module.linear.bias assert module.with_norm assert isinstance(module.norm, PixelNorm) assert isinstance(module.activation, nn.LeakyReLU) module = PGGANNoiseTo2DFeat(**self.default_cfg, act_cfg=None) res = module(self.default_input) assert res.shape == (2, 1, 4, 4) assert isinstance(module.linear, EqualizedLRLinearModule) assert not module.linear.bias assert module.with_norm assert not module.with_activation module = PGGANNoiseTo2DFeat( **self.default_cfg, norm_cfg=None, normalize_latent=False) res = module(self.default_input) assert res.shape == (2, 1, 4, 4) assert isinstance(module.linear, EqualizedLRLinearModule) assert not module.linear.bias assert not module.with_norm assert isinstance(module.activation, nn.LeakyReLU) with pytest.raises(AssertionError): _ = module(torch.randn((2, 1, 2))) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pggan_noise2feat_cuda(self): module = PGGANNoiseTo2DFeat(**self.default_cfg).cuda() res = module(self.default_input.cuda()) assert res.shape == (2, 1, 4, 4) assert isinstance(module.linear, EqualizedLRLinearModule) assert not module.linear.bias assert module.with_norm assert isinstance(module.activation, nn.LeakyReLU) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pix2pix/test_pix2pix.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy import platform import sys import pytest import torch from mmengine.logging import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmagic.models import DataPreprocessor, Pix2Pix from mmagic.models.archs import PatchDiscriminator from mmagic.models.editors.pix2pix import UnetGenerator from mmagic.utils import register_all_modules register_all_modules() def obj_from_dict(info: dict, parent=None, default_args=None): """Initialize an object from dict. The dict must contain the key "type", which indicates the object type, it can be either a string or type, such as "list" or ``list``. Remaining fields are treated as the arguments for constructing the object. Args: info (dict): Object types and arguments. parent (:class:`module`): Module which may containing expected object classes. default_args (dict, optional): Default arguments for initializing the object. Returns: any type: Object built from the dict. """ assert isinstance(info, dict) and 'type' in info assert isinstance(default_args, dict) or default_args is None args = info.copy() obj_type = args.pop('type') # if mmcv.is_str(obj_type): if isinstance(obj_type, str): if parent is not None: obj_type = getattr(parent, obj_type) else: obj_type = sys.modules[obj_type] elif not isinstance(obj_type, type): raise TypeError('type must be a str or valid type, but ' f'got {type(obj_type)}') if default_args is not None: for name, value in default_args.items(): args.setdefault(name, value) return obj_type(**args) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_pix2pix(): # model settings model_cfg = dict( data_preprocessor=DataPreprocessor(), generator=dict( type='UnetGenerator', in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)), default_domain='photo', reachable_domains=['photo'], related_domains=['photo', 'mask']) # build synthesizer synthesizer = Pix2Pix(**model_cfg) # test attributes assert synthesizer.__class__.__name__ == 'Pix2Pix' assert isinstance(synthesizer.generators['photo'], UnetGenerator) assert isinstance(synthesizer.discriminators['photo'], PatchDiscriminator) # prepare data img_mask = torch.rand(1, 3, 256, 256) img_photo = torch.rand(1, 3, 256, 256) data_batch = dict(inputs={'img_mask': img_mask, 'img_photo': img_photo}) # prepare optimizer optim_cfg = dict(type='Adam', lr=2e-4, betas=(0.5, 0.999)) optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict(params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) # test forward_test domain = 'photo' with torch.no_grad(): outputs = synthesizer(img_mask, target_domain=domain, test_mode=True) assert torch.equal(outputs['source'], data_batch['inputs']['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 256, 256) # test forward_train outputs = synthesizer(img_mask, target_domain=domain, test_mode=False) assert torch.equal(outputs['source'], data_batch['inputs']['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 256, 256) # test train_step message_hub = MessageHub.get_instance('pix2pix-test') message_hub.update_info('iter', 0) log_vars = synthesizer.train_step(data_batch, optimizer) print(log_vars.keys()) assert isinstance(log_vars, dict) for v in ['loss_gan_d_fake', 'loss_gan_d_real', 'loss_gan_g']: assert isinstance(log_vars[v].item(), float) # test cuda if torch.cuda.is_available(): synthesizer = synthesizer.cuda() optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) data_batch_cuda = copy.deepcopy(data_batch) data_batch_cuda['inputs']['img_mask'] = img_mask.cuda() data_batch_cuda['inputs']['img_photo'] = img_photo.cuda() # forward_test with torch.no_grad(): outputs = synthesizer( data_batch_cuda['inputs']['img_mask'], target_domain=domain, test_mode=True) assert torch.equal(outputs['source'].cpu(), data_batch_cuda['inputs']['img_mask'].cpu()) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 256, 256) # test forward_train outputs = synthesizer( data_batch_cuda['inputs']['img_mask'], target_domain=domain, test_mode=False) assert torch.equal(outputs['source'], data_batch_cuda['inputs']['img_mask']) assert torch.is_tensor(outputs['target']) assert outputs['target'].size() == (1, 3, 256, 256) # train_step message_hub.update_info('iter', 0) log_vars = synthesizer.train_step(data_batch_cuda, optimizer) print(log_vars) assert isinstance(log_vars, dict) for v in ['loss_gan_d_fake', 'loss_gan_d_real', 'loss_gan_g']: assert isinstance(log_vars[v].item(), float) # test disc_steps and disc_init_steps data_batch['inputs']['img_mask'] = img_mask.cpu() data_batch['inputs']['img_photo'] = img_photo.cpu() synthesizer = Pix2Pix( **model_cfg, discriminator_steps=2, disc_init_steps=2).cpu() optimizer = OptimWrapperDict( generators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict(params=getattr(synthesizer, 'generators').parameters()))), discriminators=OptimWrapper( obj_from_dict( optim_cfg, torch.optim, dict( params=getattr(synthesizer, 'discriminators').parameters())))) # iter 0, 1 for i in range(2): message_hub.update_info('iter', i) log_vars = synthesizer.train_step(data_batch, optimizer) assert isinstance(log_vars, dict) assert log_vars.get('loss_gan_g') is None for v in ['loss_gan_d_fake', 'loss_gan_d_real']: assert isinstance(log_vars[v].item(), float) # iter 2, 3, 4, 5 for i in range(2, 6): message_hub.update_info('iter', i) log_vars = synthesizer.train_step(data_batch, optimizer) assert isinstance(log_vars, dict) log_check_list = ['loss_gan_d_fake', 'loss_gan_d_real', 'loss_gan_g'] if (i + 1) % 2 == 1: assert log_vars.get('loss_gan_g') is None log_check_list.remove('loss_gan_g') for v in log_check_list: assert isinstance(log_vars[v].item(), float) def test_pix2pix_val_step(): # model settings model_cfg = dict( data_preprocessor=DataPreprocessor(), generator=dict( type='UnetGenerator', in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)), discriminator=dict( type='PatchDiscriminator', in_channels=6, base_channels=64, num_conv=3, norm_cfg=dict(type='BN'), init_cfg=dict(type='normal', gain=0.02)), default_domain='photo', reachable_domains=['photo'], related_domains=['photo', 'mask']) synthesizer = Pix2Pix(**model_cfg) img_mask = torch.rand(1, 3, 256, 256) img_photo = torch.rand(1, 3, 256, 256) data_batch = dict(inputs={'img_mask': img_mask, 'img_photo': img_photo}) out = synthesizer.val_step(data_batch) assert isinstance(out, list) assert len(out) == 1 # assert 'gt_photo' in out[0] # assert 'gt_mask' in out[0] assert 'fake_photo' in out[0] def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pix2pix/test_pix2pix_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.pix2pix import UnetGenerator class TestUnetGenerator: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=3, num_down=8, base_channels=64, norm_cfg=dict(type='BN'), use_dropout=True, init_cfg=dict(type='normal', gain=0.02)) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_pix2pix_generator_cpu(self): # test with default cfg real_a = torch.randn((2, 3, 256, 256)) gen = UnetGenerator(**self.default_cfg) fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) # test args system cfg = deepcopy(self.default_cfg) cfg['num_down'] = 7 gen = UnetGenerator(**cfg) fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) with pytest.raises(TypeError): gen = UnetGenerator(**self.default_cfg) gen.init_weights(pretrained=10) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_pix2pix_generator_cuda(self): # test with default cfg real_a = torch.randn((2, 3, 256, 256)).cuda() gen = UnetGenerator(**self.default_cfg).cuda() fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) # test args system cfg = deepcopy(self.default_cfg) cfg['num_down'] = 7 gen = UnetGenerator(**cfg).cuda() fake_b = gen(real_a) assert fake_b.shape == (2, 3, 256, 256) with pytest.raises(TypeError): gen = UnetGenerator(**self.default_cfg) gen.init_weights(pretrained=10) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_pix2pix/test_pix2pix_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.pix2pix.pix2pix_modules import \ UnetSkipConnectionBlock def test_unet_skip_connection_block(): block = UnetSkipConnectionBlock(16, 16, is_innermost=True) input = torch.rand((2, 16, 128, 128)) output = block(input) assert output.detach().numpy().shape == (2, 32, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_plain/test_plain_decoder.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import numpy as np import pytest import torch from mmagic.models.archs import VGG16 from mmagic.models.editors import PlainDecoder def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def _demo_inputs(input_shape=(1, 4, 64, 64)): """Create a superset of inputs needed to run encoder. Args: input_shape (tuple): input batch dimensions. Default: (1, 4, 64, 64). """ img = np.random.random(input_shape).astype(np.float32) img = torch.from_numpy(img) return img @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_plain_decoder(): """Test PlainDecoder.""" with torch.no_grad(): model = PlainDecoder(512) model.init_weights() model.train() # create max_pooling index for training encoder = VGG16(4) img = _demo_inputs() outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # test forward with gpu if torch.cuda.is_available(): model = PlainDecoder(512) model.init_weights() model.train() model.cuda() encoder = VGG16(4) encoder.cuda() img = _demo_inputs().cuda() outputs = encoder(img) prediction = model(outputs) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_plain/test_plain_refiner.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import PlainRefiner @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_plain_refiner(): with torch.no_grad(): plain_refiner = PlainRefiner() plain_refiner.init_weights() input = torch.rand((2, 4, 128, 128)) raw_alpha = torch.rand((2, 1, 128, 128)) output = plain_refiner(input, raw_alpha) assert output.detach().numpy().shape == (2, 1, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_rdn/test_rdn_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch import torch.nn as nn from mmagic.models import RDNNet @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_rdn(): scale = 4 model = RDNNet( in_channels=3, out_channels=3, mid_channels=64, channel_growth=32, num_blocks=16, upscale_factor=scale) # test attributes assert model.__class__.__name__ == 'RDNNet' # prepare data inputs = torch.rand(1, 3, 32, 16) targets = torch.rand(1, 3, 128, 64) # prepare loss loss_function = nn.L1Loss() # prepare optimizer optimizer = torch.optim.Adam(model.parameters()) # test on cpu output = model(inputs) optimizer.zero_grad() loss = loss_function(output, targets) loss.backward() optimizer.step() assert torch.is_tensor(output) assert output.shape == targets.shape # test on gpu if torch.cuda.is_available(): model = model.cuda() optimizer = torch.optim.Adam(model.parameters()) inputs = inputs.cuda() targets = targets.cuda() output = model(inputs) optimizer.zero_grad() loss = loss_function(output, targets) loss.backward() optimizer.step() assert torch.is_tensor(output) assert output.shape == targets.shape def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_real_basicvsr/test_real_basicvsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest.mock import patch import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors import (RealBasicVSR, RealBasicVSRNet, UNetDiscriminatorWithSpectralNorm) from mmagic.models.losses import GANLoss, L1Loss, PerceptualLoss, PerceptualVGG from mmagic.structures import DataSample @patch.object(PerceptualVGG, 'init_weights') @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_real_basicvsr(init_weights): model = RealBasicVSR( generator=dict( type='RealBasicVSRNet', mid_channels=4, num_propagation_blocks=1, num_cleaning_blocks=1, dynamic_refine_thres=5, # change to 5 for test spynet_pretrained=None, is_fix_cleaning=False, is_sequential_cleaning=False), discriminator=dict( type='UNetDiscriminatorWithSpectralNorm', in_channels=3, mid_channels=4, skip_connection=True), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), cleaning_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-2, real_label_val=1.0, fake_label_val=0), is_use_sharpened_gt_in_pixel=True, is_use_sharpened_gt_in_percep=True, is_use_sharpened_gt_in_gan=False, data_preprocessor=DataPreprocessor()) assert isinstance(model, RealBasicVSR) assert isinstance(model.generator, RealBasicVSRNet) assert isinstance(model.discriminator, UNetDiscriminatorWithSpectralNorm) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.cleaning_loss, L1Loss) assert isinstance(model.perceptual_loss, PerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(5, 3, 64, 64) target = torch.rand(5, 3, 256, 256) data_sample = DataSample(gt_img=target, gt_unsharp=target) data = dict(inputs=[inputs], data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_clean', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (5, 3, 256, 256) # feat output = model(torch.rand(1, 5, 3, 64, 64), mode='tensor') assert output.shape == (1, 5, 3, 256, 256) # train_unsharp model.is_use_sharpened_gt_in_pixel = True model.is_use_sharpened_gt_in_percep = True model.is_use_sharpened_gt_in_gan = False log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_clean', 'loss_d_real', 'loss_d_fake' ]) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_real_basicvsr/test_real_basicvsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import RealBasicVSRNet @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_real_basicvsr_net(): """Test RealBasicVSR.""" # cpu # is_fix_cleaning = False real_basicvsr = RealBasicVSRNet(is_fix_cleaning=False) # is_sequential_cleaning = False real_basicvsr = RealBasicVSRNet( is_fix_cleaning=True, is_sequential_cleaning=False) input_tensor = torch.rand(1, 5, 3, 64, 64) output = real_basicvsr(input_tensor) assert output.shape == (1, 5, 3, 256, 256) # is_sequential_cleaning = True, return_lq = True real_basicvsr = RealBasicVSRNet( is_fix_cleaning=True, is_sequential_cleaning=True) output, lq = real_basicvsr(input_tensor, return_lqs=True) assert output.shape == (1, 5, 3, 256, 256) assert lq.shape == (1, 5, 3, 64, 64) # gpu if torch.cuda.is_available(): # is_fix_cleaning = False real_basicvsr = RealBasicVSRNet(is_fix_cleaning=False).cuda() # is_sequential_cleaning = False real_basicvsr = RealBasicVSRNet( is_fix_cleaning=True, is_sequential_cleaning=False).cuda() input_tensor = torch.rand(1, 5, 3, 64, 64).cuda() output = real_basicvsr(input_tensor) assert output.shape == (1, 5, 3, 256, 256) # is_sequential_cleaning = True, return_lq = True real_basicvsr = RealBasicVSRNet( is_fix_cleaning=True, is_sequential_cleaning=True).cuda() output, lq = real_basicvsr(input_tensor, return_lqs=True) assert output.shape == (1, 5, 3, 256, 256) assert lq.shape == (1, 5, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_real_esrgan/test_real_esrgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import patch import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import (DataPreprocessor, RealESRGAN, RRDBNet, UNetDiscriminatorWithSpectralNorm) from mmagic.models.losses import GANLoss, L1Loss, PerceptualLoss, PerceptualVGG from mmagic.structures import DataSample @patch.object(PerceptualVGG, 'init_weights') def test_real_esrgan(init_weights): model = RealESRGAN( generator=dict( type='RRDBNet', in_channels=3, out_channels=3, mid_channels=4, num_blocks=4, growth_channels=4, upscale_factor=4), discriminator=dict( type='UNetDiscriminatorWithSpectralNorm', in_channels=3, mid_channels=4, skip_connection=True), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={ '2': 0.1, '7': 0.1, '16': 1.0, '25': 1.0, '34': 1.0, }, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-1, real_label_val=1.0, fake_label_val=0), is_use_sharpened_gt_in_pixel=False, is_use_sharpened_gt_in_percep=False, is_use_sharpened_gt_in_gan=False, is_use_ema=False, train_cfg=None, test_cfg=None, data_preprocessor=DataPreprocessor()) assert isinstance(model, RealESRGAN) assert isinstance(model.generator, RRDBNet) assert isinstance(model.discriminator, UNetDiscriminatorWithSpectralNorm) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.perceptual_loss, PerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 32, 32) target = torch.rand(3, 128, 128) data_sample = DataSample(gt_img=target, gt_unsharp=target) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 128, 128) # val_ema model.generator_ema = model.generator model.is_use_ema = True output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 128, 128) # feat output = model(torch.rand(1, 3, 32, 32), mode='tensor') assert output.shape == (1, 3, 128, 128) # train_unsharp model.is_use_sharpened_gt_in_pixel = True model.is_use_sharpened_gt_in_percep = True model.is_use_sharpened_gt_in_gan = False log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_d_real', 'loss_d_fake' ]) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_real_esrgan/test_unet_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models import UNetDiscriminatorWithSpectralNorm @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_unet_disc_with_spectral_norm(): # cpu disc = UNetDiscriminatorWithSpectralNorm(in_channels=3) img = torch.randn(1, 3, 16, 16) output = disc(img) assert output.detach().numpy().shape == (1, 1, 16, 16) # cuda if torch.cuda.is_available(): disc = disc.cuda() img = img.cuda() output = disc(img) assert output.detach().cpu().numpy().shape == (1, 1, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_restormer/test_restormer_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors import Restormer @pytest.mark.skipif( torch.__version__ < '1.8.0', reason='skip on torch<1.8 due to unsupported PixelUnShuffle') def test_restormer_cpu(): """Test Restormer.""" # Motion Deblurring or Image Deraining net = Restormer( inp_channels=3, out_channels=3, dim=24, num_blocks=[2, 2, 2, 4], num_refinement_blocks=1, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False) img = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) # Image Denoising Gray net = Restormer( inp_channels=1, out_channels=1, dim=24, num_blocks=[2, 2, 2, 4], num_refinement_blocks=1, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False) img = torch.rand(1, 1, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 1, 16, 16) # Image Denoising Color net = Restormer( inp_channels=3, out_channels=3, dim=24, num_blocks=[2, 2, 2, 4], num_refinement_blocks=1, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='BiasFree', dual_pixel_task=False) img = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) # Image Dual Defocus Deblurring net = Restormer( inp_channels=6, out_channels=3, dim=24, num_blocks=[2, 2, 2, 4], num_refinement_blocks=1, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=True, dual_keys=['imgL', 'imgR']) img = dict() img['imgL'] = torch.rand(1, 3, 16, 16) img['imgR'] = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) @pytest.mark.skipif( torch.__version__ < '1.8.0', reason='skip on torch<1.8 due to unsupported PixelUnShuffle') def test_restormer_cuda(): net = Restormer( inp_channels=3, out_channels=3, dim=24, num_blocks=[2, 2, 2, 4], num_refinement_blocks=1, heads=[1, 2, 4, 8], ffn_expansion_factor=2.66, bias=False, LayerNorm_type='WithBias', dual_pixel_task=False) img = torch.rand(1, 3, 16, 16) # Image Deblurring or Image Deraining (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_sagan/test_sagan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy from unittest import TestCase import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import SAGAN, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='SAGANGenerator', # noise_size=10, num_classes=10, output_scale=32, base_channels=256, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=2, with_spectral_norm=True) discriminator = dict( type='ProjDiscriminator', num_classes=10, input_scale=32, base_channels=128, attention_cfg=dict(type='SelfAttentionBlock'), attention_after_nth_block=1, with_spectral_norm=True) class TestSAGAN(TestCase): def test_init(self): gan = SAGAN( noise_size=10, num_classes=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator, generator_steps=1, discriminator_steps=4) self.assertIsInstance(gan, SAGAN) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = SAGAN( noise_size=10, generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = SAGAN( noise_size=10, generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = SAGAN( noise_size=10, generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) # test init with different num_classes gan = SAGAN( num_classes=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator, generator_steps=1, discriminator_steps=4) def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('mmgen') gan = SAGAN( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) label = torch.randint(0, 10, (1, )) data_sample = DataSample(gt_img=img) data_sample.set_gt_label(label) data = dict(inputs=dict(), data_samples=[data_sample]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_sagan/test_sagan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.sagan import ProjDiscriminator from mmagic.registry import MODELS class TestSNGANPROJDiscriminator(object): @classmethod def setup_class(cls): cls.x = torch.randn((2, 3, 32, 32)) cls.label = torch.randint(0, 10, (2, )) cls.default_config = dict( type='ProjDiscriminator', input_scale=32, num_classes=10, input_channels=3) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_sngan_proj_discriminator(self): # test default setting with builder d = MODELS.build(self.default_config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different input_scale config = deepcopy(self.default_config) config['input_scale'] = 64 d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x, self.label) assert score.shape == (2, 1) # test num_classes == 0 (w/o proj_y) config = deepcopy(self.default_config) config['num_classes'] = 0 d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different base_channels config = deepcopy(self.default_config) config['base_channels'] = 128 d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different channels_cfg --> list config = deepcopy(self.default_config) config['channels_cfg'] = [1, 1, 1] d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different channels_cfg --> dict config = deepcopy(self.default_config) config['channels_cfg'] = {32: [1, 1, 1], 64: [2, 4, 8, 16]} d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different channels_cfg --> error (key not find) config = deepcopy(self.default_config) config['channels_cfg'] = {64: [2, 4, 8, 16]} with pytest.raises(KeyError): d = MODELS.build(config) # test different channels_cfg --> error (type not match) config = deepcopy(self.default_config) config['channels_cfg'] = '1234' with pytest.raises(ValueError): d = MODELS.build(config) # test different downsample_cfg --> list config = deepcopy(self.default_config) config['downsample_cfg'] = [True, False, False] d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different downsample_cfg --> dict config = deepcopy(self.default_config) config['downsample_cfg'] = { 32: [True, False, False], 64: [True, True, True, True] } d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different downsample_cfg --> error (key not find) config = deepcopy(self.default_config) config['downsample_cfg'] = {64: [True, True, True, True]} with pytest.raises(KeyError): d = MODELS.build(config) # test different downsample_cfg --> error (type not match) config = deepcopy(self.default_config) config['downsample_cfg'] = '1234' with pytest.raises(ValueError): d = MODELS.build(config) # test downsample_cfg and channels_cfg not match config = deepcopy(self.default_config) config['downsample_cfg'] = [True, False, False] config['channels_cfg'] = [1, 1, 1, 1] with pytest.raises(ValueError): d = MODELS.build(config) # test different act_cfg config = deepcopy(self.default_config) config['act_cfg'] = dict(type='Sigmoid') d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different with_spectral_norm config = deepcopy(self.default_config) config['with_spectral_norm'] = False d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different init_cfg --> studio config = deepcopy(self.default_config) config['init_cfg'] = dict(type='studio') d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different init_cfg --> BigGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='biggan') d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different init_cfg --> sngan config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan-proj') d = MODELS.build(config) assert isinstance(d, ProjDiscriminator) score = d(self.x, self.label) assert score.shape == (2, 1) # test different init_cfg --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): d = MODELS.build(config) # test pretrained --> raise error config = deepcopy(self.default_config) config['pretrained'] = 42 with pytest.raises(TypeError): d = MODELS.build(config) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_sngan_proj_discriminator_cuda(self): # test default setting with builder d = MODELS.build(self.default_config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different input_scale config = deepcopy(self.default_config) config['input_scale'] = 64 d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) x = torch.randn((2, 3, 64, 64)).cuda() score = d(x, self.label.cuda()) assert score.shape == (2, 1) # test num_classes == 0 (w/o proj_y) config = deepcopy(self.default_config) config['num_classes'] = 0 d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different base_channels config = deepcopy(self.default_config) config['base_channels'] = 128 d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different channels_cfg --> list config = deepcopy(self.default_config) config['channels_cfg'] = [1, 1, 1] d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different channels_cfg --> dict config = deepcopy(self.default_config) config['channels_cfg'] = {32: [1, 1, 1], 64: [2, 4, 8, 16]} d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different downsample_cfg --> list config = deepcopy(self.default_config) config['downsample_cfg'] = [True, False, False] d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different downsample_cfg --> dict config = deepcopy(self.default_config) config['downsample_cfg'] = { 32: [True, False, False], 64: [True, True, True, True] } d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different act_cfg config = deepcopy(self.default_config) config['act_cfg'] = dict(type='Sigmoid') d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different with_spectral_norm config = deepcopy(self.default_config) config['with_spectral_norm'] = False d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different init_cfg --> BigGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='biggan') d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) # test different init_cfg --> sngan config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan-proj') d = MODELS.build(config).cuda() assert isinstance(d, ProjDiscriminator) score = d(self.x.cuda(), self.label.cuda()) assert score.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_sagan/test_sagan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.sagan import SNGANGenerator from mmagic.registry import MODELS class TestSNGANPROJGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((2, 128)) cls.label = torch.randint(0, 10, (2, )) cls.default_config = dict( type='SNGANGenerator', noise_size=128, output_scale=32, num_classes=10, base_channels=32) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_sngan_proj_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test return noise x = g(None, num_batches=2, return_noise=True) assert x['fake_img'].shape == (2, 3, 32, 32) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) x = g(self.noise, label=self.label, return_noise=True) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) x = g(torch.randn, num_batches=2, return_noise=True) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) # test different output_scale config = deepcopy(self.default_config) config['output_scale'] = 64 g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 64, 64) # test num_classes == 0 and `use_cbn = True` config = deepcopy(self.default_config) config['num_classes'] = 0 with pytest.raises(ValueError): g = MODELS.build(config) # test num_classes == 0 and `use_cbn = False` config = deepcopy(self.default_config) config['num_classes'] = 0 config['use_cbn'] = False g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different base_channels config = deepcopy(self.default_config) config['base_channels'] = 64 g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different channels_cfg --> list config = deepcopy(self.default_config) config['channels_cfg'] = [1, 1, 1] g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different channels_cfg --> dict config = deepcopy(self.default_config) config['channels_cfg'] = {32: [1, 1, 1], 64: [16, 8, 4, 2]} g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different channels_cfg --> error (key not find) config = deepcopy(self.default_config) config['channels_cfg'] = {64: [16, 8, 4, 2]} with pytest.raises(KeyError): g = MODELS.build(config) # test different channels_cfg --> error (type not match) config = deepcopy(self.default_config) config['channels_cfg'] = '1234' with pytest.raises(ValueError): g = MODELS.build(config) # test different act_cfg config = deepcopy(self.default_config) config['act_cfg'] = dict(type='Sigmoid') g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test with_spectral_norm config = deepcopy(self.default_config) config['with_spectral_norm'] = True g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test with_embedding_spectral_norm config = deepcopy(self.default_config) config['with_embedding_spectral_norm'] = True g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test norm_eps config = deepcopy(self.default_config) config['norm_eps'] = 1e-9 g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test sn_eps config = deepcopy(self.default_config) config['sn_eps'] = 1e-12 g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> Studio config = deepcopy(self.default_config) config['init_cfg'] = dict(type='studio') g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> BigGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='biggan') g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> SNGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> SAGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sagan') g = MODELS.build(config) assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): g = MODELS.build(config) # test pretrained --> raise error config = deepcopy(self.default_config) config['pretrained'] = 42 with pytest.raises(TypeError): g = MODELS.build(config) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_sngan_proj_generator_cuda(self): # test default setting with builder g = MODELS.build(self.default_config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test return noise x = g(None, num_batches=2, return_noise=True) assert x['fake_img'].shape == (2, 3, 32, 32) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) x = g(self.noise.cuda(), label=self.label.cuda(), return_noise=True) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) x = g(torch.randn, num_batches=2, return_noise=True) assert x['noise_batch'].shape == (2, 128) assert x['label'].shape == (2, ) # test different output_scale config = deepcopy(self.default_config) config['output_scale'] = 64 g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 64, 64) # test different base_channels config = deepcopy(self.default_config) config['base_channels'] = 64 g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different channels_cfg --> list config = deepcopy(self.default_config) config['channels_cfg'] = [1, 1, 1] g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different channels_cfg --> dict config = deepcopy(self.default_config) config['channels_cfg'] = {32: [1, 1, 1], 64: [16, 8, 4, 2]} g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different act_cfg config = deepcopy(self.default_config) config['act_cfg'] = dict(type='Sigmoid') g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test with_spectral_norm config = deepcopy(self.default_config) config['with_spectral_norm'] = True g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test with_embedding_spectral_norm config = deepcopy(self.default_config) config['with_embedding_spectral_norm'] = True g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test norm_eps config = deepcopy(self.default_config) config['norm_eps'] = 1e-9 g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test sn_eps config = deepcopy(self.default_config) config['sn_eps'] = 1e-12 g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2).cuda() assert x.shape == (2, 3, 32, 32) # test different init_cfg --> BigGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='biggan') g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) # test different init_cfg --> SNGAN config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') g = MODELS.build(config).cuda() assert isinstance(g, SNGANGenerator) x = g(None, num_batches=2) assert x.shape == (2, 3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_sagan/test_sagan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from copy import deepcopy import pytest import torch from mmagic.registry import MODELS class TestSNGANGenResBlock(object): @classmethod def setup_class(cls): cls.input = torch.randn(2, 16, 5, 5) cls.label = torch.randint(0, 10, (2, )) cls.default_config = dict( type='SNGANGenResBlock', num_classes=10, in_channels=16, out_channels=16, use_cbn=True, use_norm_affine=False, norm_cfg=dict(type='BN'), upsample_cfg=dict(type='nearest', scale_factor=2), upsample=True, init_cfg=dict(type='BigGAN')) def test_snganGenResBlock(self): # test default config block = MODELS.build(self.default_config) out = block(self.input, self.label) assert out.shape == (2, 16, 10, 10) # test no upsample config and no learnable sc config = deepcopy(self.default_config) config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test learnable shortcut + w/o upsample config = deepcopy(self.default_config) config['out_channels'] = 32 config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 32, 5, 5) # test init_cfg + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test init_cfg == studio + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='studio') config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test init_cfg == sagan + learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sagan') block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 10, 10) # test init_cfg == sagan + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sagan') config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test init_cft --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): block = MODELS.build(config) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 10, 10) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_snganGenResBlock_cuda(self): # test default config block = MODELS.build(self.default_config).cuda() out = block(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 16, 10, 10) # test no upsample config and no learnable sc config = deepcopy(self.default_config) config['upsample'] = False block = MODELS.build(config).cuda() out = block(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 16, 5, 5) # test init_cfg == studio + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='studio') config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test init_cfg == sagan + learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sagan') block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 10, 10) # test init_cfg == sagan + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sagan') config['upsample'] = False block = MODELS.build(config) out = block(self.input, self.label) assert out.shape == (2, 16, 5, 5) # test learnable shortcut + w/o upsample config = deepcopy(self.default_config) config['out_channels'] = 32 config['upsample'] = False block = MODELS.build(config).cuda() out = block(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 32, 5, 5) # test init_cfg + w/o learnable shortcut config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') config['upsample'] = False block = MODELS.build(config).cuda() out = block(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 16, 5, 5) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config).cuda() out = block(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 16, 10, 10) class TestSNDiscResBlock(object): @classmethod def setup_class(cls): cls.input = torch.randn(2, 16, 10, 10) cls.default_config = dict( type='SNGANDiscResBlock', in_channels=16, out_channels=16, downsample=True, init_cfg=dict(type='BigGAN')) def test_snganDiscResBlock(self): # test default config block = MODELS.build(self.default_config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test w/o learnabel shortcut + w/o downsample config = deepcopy(self.default_config) config['downsample'] = False config['out_channels'] = 8 block = MODELS.build(config) out = block(self.input) assert out.shape == (2, 8, 10, 10) # test init cfg + w or w/o downsample for init_method in [ 'studio', 'biggan', 'sagan', 'sngan', 'sngan-proj', 'gan-proj' ]: config = deepcopy(self.default_config) config['init_cfg'] = dict(type=init_method) config['out_channels'] = 8 for downsample in [True, False]: config['downsample'] = downsample block = MODELS.build(config) out = block(self.input) if downsample: assert out.shape == (2, 8, 5, 5) else: assert out.shape == (2, 8, 10, 10) # test init_cft --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): block = MODELS.build(config) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_snganDiscResBlock_cuda(self): # test default config block = MODELS.build(self.default_config).cuda() out = block(self.input.cuda()) assert out.shape == (2, 16, 5, 5) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config).cuda() out = block(self.input.cuda()) assert out.shape == (2, 16, 5, 5) # test w/o learnabel shortcut + w/o downsample config = deepcopy(self.default_config) config['downsample'] = False config['out_channels'] = 8 block = MODELS.build(config).cuda() out = block(self.input.cuda()) assert out.shape == (2, 8, 10, 10) # test init cfg + w or w/o downsample for init_method in [ 'studio', 'biggan', 'sagan', 'sngan', 'sngan-proj', 'gan-proj' ]: config = deepcopy(self.default_config) config['init_cfg'] = dict(type=init_method) config['out_channels'] = 8 for downsample in [True, False]: config['downsample'] = downsample block = MODELS.build(config) out = block(self.input) if downsample: assert out.shape == (2, 8, 5, 5) else: assert out.shape == (2, 8, 10, 10) class TestSNDiscHeadResBlock(object): @classmethod def setup_class(cls): cls.input = torch.randn(2, 16, 10, 10) cls.default_config = dict( type='SNGANDiscHeadResBlock', in_channels=16, out_channels=16, init_cfg=dict(type='BigGAN')) def test_snganDiscHeadResBlock(self): # test default config block = MODELS.build(self.default_config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test init cfg + w or w/o downsample for init_method in [ 'studio', 'biggan', 'sagan', 'sngan', 'sngan-proj', 'gan-proj' ]: config = deepcopy(self.default_config) config['init_cfg'] = dict(type=init_method) block = MODELS.build(config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test init_cft --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): block = MODELS.build(config) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_snganDiscHeadResBlock_cuda(self): # test default config block = MODELS.build(self.default_config).cuda() out = block(self.input.cuda()) assert out.shape == (2, 16, 5, 5) # test init cfg + w or w/o downsample for init_method in [ 'studio', 'biggan', 'sagan', 'sngan', 'sngan-proj', 'gan-proj' ]: config = deepcopy(self.default_config) config['init_cfg'] = dict(type=init_method) block = MODELS.build(config) out = block(self.input) assert out.shape == (2, 16, 5, 5) # test conv_cfg config = deepcopy(self.default_config) config['conv_cfg'] = dict( kernel_size=1, stride=1, padding=0, act_cfg=None) block = MODELS.build(config).cuda() out = block(self.input.cuda()) assert out.shape == (2, 16, 5, 5) class TestSNConditionalNorm(object): @classmethod def setup_class(cls): cls.input = torch.randn((2, 4, 4, 4)) cls.label = torch.randint(0, 10, (2, )) cls.default_config = dict( type='SNConditionNorm', in_channels=4, num_classes=10, use_cbn=True, cbn_norm_affine=False, init_cfg=dict(type='BigGAN')) def test_conditionalNorm(self): # test build from default config norm = MODELS.build(self.default_config) out = norm(self.input, self.label) assert out.shape == (2, 4, 4, 4) # test w/o use_cbn config = deepcopy(self.default_config) config['use_cbn'] = False norm = MODELS.build(config) out = norm(self.input) assert out.shape == (2, 4, 4, 4) # test num_class < 0 and cbn = False config = deepcopy(self.default_config) config['num_classes'] = 0 config['use_cbn'] = False norm = MODELS.build(config) out = norm(self.input) assert out.shape == (2, 4, 4, 4) # test num_classes <= 0 and cbn = True config = deepcopy(self.default_config) config['num_classes'] = 0 with pytest.raises(ValueError): norm = MODELS.build(config) # test IN config = deepcopy(self.default_config) config['norm_cfg'] = dict(type='IN') norm = MODELS.build(config) out = norm(self.input, self.label) assert out.shape == (2, 4, 4, 4) # test sn_style == ajbrock config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'ajbrock' norm = MODELS.build(config) out = norm(self.input, self.label) for buffer in ['u0', 'sv0']: assert hasattr(norm.weight_embedding, buffer) assert hasattr(norm.bias_embedding, buffer) assert out.shape == (2, 4, 4, 4) # test sn_style == torch config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'torch' norm = MODELS.build(config) out = norm(self.input, self.label) for buffer in ['weight_u', 'weight_v', 'weight_orig']: assert hasattr(norm.weight_embedding, buffer) assert hasattr(norm.bias_embedding, buffer) assert out.shape == (2, 4, 4, 4) # test sn_style --> raise error config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'studio' with pytest.raises(NotImplementedError): norm = MODELS.build(config) # test SyncBN # config = deepcopy(self.default_config) # config['norm_cfg'] = dict(type='SyncBN') # norm = MODELS.build(config) # out = norm(self.input, self.label) # assert out.shape == (2, 4, 4, 4) # test unknown norm type config = deepcopy(self.default_config) config['norm_cfg'] = dict(type='GN') with pytest.raises(ValueError): norm = MODELS.build(config) # test init_cfg config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') norm = MODELS.build(config) out = norm(self.input, self.label) assert out.shape == (2, 4, 4, 4) # test init_cft --> raise error config = deepcopy(self.default_config) config['init_cfg'] = dict(type='wgan-gp') with pytest.raises(NotImplementedError): norm = MODELS.build(config) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_conditionalNorm_cuda(self): # test build from default config norm = MODELS.build(self.default_config).cuda() out = norm(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 4, 4, 4) # test w/o use_cbn config = deepcopy(self.default_config) config['use_cbn'] = False norm = MODELS.build(config).cuda() out = norm(self.input.cuda()) assert out.shape == (2, 4, 4, 4) # test num_class < 0 and cbn = False config = deepcopy(self.default_config) config['num_classes'] = 0 config['use_cbn'] = False norm = MODELS.build(config).cuda() out = norm(self.input.cuda()) assert out.shape == (2, 4, 4, 4) # test num_classes <= 0 and cbn = True config = deepcopy(self.default_config) config['num_classes'] = 0 with pytest.raises(ValueError): norm = MODELS.build(config) # test IN config = deepcopy(self.default_config) config['norm_cfg'] = dict(type='IN') norm = MODELS.build(config).cuda() out = norm(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 4, 4, 4) # test sn_style == ajbrock config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'ajbrock' norm = MODELS.build(config) out = norm(self.input, self.label) for buffer in ['u0', 'sv0']: assert hasattr(norm.weight_embedding, buffer) assert hasattr(norm.bias_embedding, buffer) assert out.shape == (2, 4, 4, 4) # test sn_style == torch config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'torch' norm = MODELS.build(config) out = norm(self.input, self.label) for buffer in ['weight_u', 'weight_v', 'weight_orig']: assert hasattr(norm.weight_embedding, buffer) assert hasattr(norm.bias_embedding, buffer) assert out.shape == (2, 4, 4, 4) # test sn_style --> raise error config = deepcopy(self.default_config) config['with_spectral_norm'] = True config['sn_style'] = 'studio' with pytest.raises(NotImplementedError): norm = MODELS.build(config) # test SyncBN # config = deepcopy(self.default_config) # config['norm_cfg'] = dict(type='SyncBN') # norm = MODELS.build(config) # out = norm(self.input, self.label) # assert out.shape == (2, 4, 4, 4) # test unknown norm type config = deepcopy(self.default_config) config['norm_cfg'] = dict(type='GN') with pytest.raises(ValueError): norm = MODELS.build(config) # test init_cfg config = deepcopy(self.default_config) config['init_cfg'] = dict(type='sngan') norm = MODELS.build(config).cuda() out = norm(self.input.cuda(), self.label.cuda()) assert out.shape == (2, 4, 4, 4) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_singan/test_singan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine import MessageHub from mmagic.engine import SinGANOptimWrapperConstructor from mmagic.models import SinGAN from mmagic.utils import register_all_modules register_all_modules() class TestSinGAN: @classmethod def setup_class(cls): cls.generator = dict( type='SinGANMultiScaleGenerator', in_channels=3, out_channels=3, num_scales=3) cls.disc = dict( type='SinGANMultiScaleDiscriminator', in_channels=3, num_scales=3) cls.data_preprocessor = dict( type='DataPreprocessor', non_image_keys=['input_sample']) cls.noise_weight_init = 0.1 cls.curr_scale = -1 cls.iters_per_scale = 2 cls.lr_scheduler_args = dict(milestones=[1600], gamma=0.1) cls.data_batch = dict( inputs=dict( real_scale0=torch.randn(1, 3, 25, 25), real_scale1=torch.randn(1, 3, 30, 30), real_scale2=torch.randn(1, 3, 32, 32), )) cls.data_batch['inputs']['input_sample'] = torch.zeros_like( cls.data_batch['inputs']['real_scale0']) cls.optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999))), discriminator=dict( optimizer=dict(type='Adam', lr=0.0005, betas=(0.5, 0.999)))) def test_singan_cpu(self): message_hub = MessageHub.get_instance('singan-test') message_hub.update_info('iter', 0) singan = SinGAN( self.generator, self.disc, num_scales=3, data_preprocessor=self.data_preprocessor, noise_weight_init=self.noise_weight_init, iters_per_scale=self.iters_per_scale, lr_scheduler_args=self.lr_scheduler_args) optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(singan) for i in range(6): singan.train_step(self.data_batch, optim_wrapper_dict) message_hub.update_info('iter', message_hub.get_info('iter') + 1) outputs = singan.forward(dict(num_batches=1), None) img = torch.stack([out.fake_img.data for out in outputs], dim=0) if i in [0, 1]: assert singan.curr_stage == 0 assert img.shape[-2:] == (25, 25) elif i in [2, 3]: assert singan.curr_stage == 1 assert img.shape[-2:] == (30, 30) elif i in [4, 5]: assert singan.curr_stage == 2 assert img.shape[-2:] == (32, 32) outputs = singan.forward( dict(num_batches=1, get_prev_res=True), None) assert all([hasattr(out, 'prev_res_list') for out in outputs]) # test forward singan with ema singan = SinGAN( self.generator, self.disc, num_scales=3, data_preprocessor=self.data_preprocessor, noise_weight_init=self.noise_weight_init, iters_per_scale=self.iters_per_scale, lr_scheduler_args=self.lr_scheduler_args, ema_confg=dict(type='ExponentialMovingAverage')) optim_wrapper_dict_builder = SinGANOptimWrapperConstructor( self.optim_wrapper_cfg) optim_wrapper_dict = optim_wrapper_dict_builder(singan) for i in range(6): singan.train_step(self.data_batch, optim_wrapper_dict) message_hub.update_info('iter', message_hub.get_info('iter') + 1) outputs = singan.forward( dict(num_batches=1, sample_model='ema/orig'), None) img = torch.stack([out.orig.fake_img.data for out in outputs], dim=0) img_ema = torch.stack([out.ema.fake_img.data for out in outputs], dim=0) if i in [0, 1]: assert singan.curr_stage == 0 assert img.shape[-2:] == (25, 25) assert img_ema.shape[-2:] == (25, 25) elif i in [2, 3]: assert singan.curr_stage == 1 assert img.shape[-2:] == (30, 30) assert img_ema.shape[-2:] == (30, 30) elif i in [4, 5]: assert singan.curr_stage == 2 assert img.shape[-2:] == (32, 32) assert img_ema.shape[-2:] == (32, 32) outputs = singan.forward( dict( num_batches=1, sample_model='ema/orig', get_prev_res=True), None) assert all([hasattr(out.orig, 'prev_res_list') for out in outputs]) assert all([hasattr(out.ema, 'prev_res_list') for out in outputs]) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_singan/test_singan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.singan import SinGANMultiScaleDiscriminator class TestSinGANDisc: @classmethod def setup_class(cls): cls.default_args = dict( in_channels=3, kernel_size=3, padding=0, num_layers=3, base_channels=32, num_scales=3, min_feat_channels=16) def test_singan_disc(self): disc = SinGANMultiScaleDiscriminator(**self.default_args) img = torch.randn(1, 3, 24, 24) res = disc(img, 2) assert res.shape[0] == 1 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_singan/test_singan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.singan import SinGANMultiScaleGenerator class TestSinGANGen: @classmethod def setup_class(cls): cls.default_args = dict( in_channels=3, out_channels=3, kernel_size=3, padding=0, num_layers=3, base_channels=32, num_scales=3, min_feat_channels=16) cls.fixed_noises = [ torch.randn(1, 3, 8, 8), torch.randn(1, 3, 10, 10), torch.randn(1, 3, 12, 12), torch.randn(1, 3, 16, 16) ] cls.input_sample = torch.zeros_like(cls.fixed_noises[0]) cls.noise_weights = [1., 0.5, 0.5, 0.5] def test_singan_gen(self): gen = SinGANMultiScaleGenerator(**self.default_args) res = gen(self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2) assert res.shape == (1, 3, 12, 12) output = gen( self.input_sample, self.fixed_noises, self.noise_weights, 'rand', 2, get_prev_res=True) assert output['prev_res_list'][0].shape == (1, 3, 8, 8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_singan/test_singan_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.singan.singan_modules import (DiscriminatorBlock, GeneratorBlock) def test_GeneratorBlock(): gen_block = GeneratorBlock(3, 6, 3, 1, 3, 4, 4) x = torch.randn(1, 3, 6, 6) prev = torch.randn(1, 6, 6, 6) out = gen_block(x, prev) assert out.shape == (1, 6, 6, 6) gen_block = GeneratorBlock(3, 6, 3, 1, 3, 4, 4, allow_no_residual=True) x = torch.randn(1, 3, 6, 6) prev = torch.randn(1, 3, 6, 6) out = gen_block(x, prev) assert out.shape == (1, 6, 6, 6) def test_DiscriminatorBlock(): disc_block = DiscriminatorBlock(3, 4, 1, 3, 1, 3) x = torch.randn(1, 3, 6, 6) out = disc_block(x) assert out.shape == (1, 1, 6, 6) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_srcnn/test_srcnn_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models import SRCNNNet def test_srcnn(): # model, initialization and forward (cpu) net = SRCNNNet( channels=(3, 4, 6, 3), kernel_sizes=(9, 1, 5), upscale_factor=4) img = torch.rand(1, 3, 4, 4) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) net = SRCNNNet( channels=(1, 4, 8, 1), kernel_sizes=(3, 3, 3), upscale_factor=2) img = torch.rand(1, 1, 4, 4) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 1, 8, 8) # model forward (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert isinstance(output, torch.Tensor) assert output.shape == (1, 1, 8, 8) with pytest.raises(AssertionError): # The length of channel tuple should be 4 net = SRCNNNet( channels=(3, 4, 3), kernel_sizes=(9, 1, 5), upscale_factor=4) with pytest.raises(AssertionError): # The length of kernel tuple should be 3 net = SRCNNNet( channels=(3, 4, 4, 3), kernel_sizes=(9, 1, 1, 5), upscale_factor=4) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_srgan/test_modified_vgg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import ModifiedVGG def test_modifiedVGG(): model = ModifiedVGG(3, 16) inputs = torch.randn(1, 3, 128, 128) outputs = model(inputs) assert outputs.shape == (1, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_srgan/test_sr_resnet.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models import ModifiedVGG, MSRResNet def test_srresnet_backbone(): """Test SRResNet backbone.""" # x2 model MSRResNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=2) # x3 model, initialization and forward (cpu) net = MSRResNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=3) input_shape = (1, 3, 12, 12) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 3, 36, 36) # x4 modeland, initialization and forward (cpu) net = MSRResNet( in_channels=3, out_channels=3, mid_channels=8, num_blocks=2, upscale_factor=4) output = net(img) assert output.shape == (1, 3, 48, 48) # x4 model forward (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 3, 48, 48) with pytest.raises(ValueError): # Currently supported upscale_factor is [2, 3, 4] MSRResNet( in_channels=3, out_channels=3, mid_channels=64, num_blocks=16, upscale_factor=16) def test_discriminator(): """Test discriminator backbone.""" # model, initialization and forward (cpu) net = ModifiedVGG(in_channels=3, mid_channels=64) input_shape = (1, 3, 128, 128) img = torch.rand(input_shape) output = net(img) assert output.shape == (1, 1) # model, initialization and forward (gpu) if torch.cuda.is_available(): net.cuda() output = net(img.cuda()) assert output.shape == (1, 1) with pytest.raises(AssertionError): # input size must be 128 * 128 input_shape = (1, 3, 64, 64) img = torch.rand(input_shape) output = net(img) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_srgan/test_srgan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import patch import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import SRGAN, DataPreprocessor, ModifiedVGG, MSRResNet from mmagic.models.losses import GANLoss, L1Loss, PerceptualLoss, PerceptualVGG from mmagic.structures import DataSample @patch.object(PerceptualVGG, 'init_weights') def test_srgan_resnet(init_weights): model = SRGAN( generator=dict( type='MSRResNet', in_channels=3, out_channels=3, mid_channels=4, num_blocks=4, upscale_factor=4), discriminator=dict(type='ModifiedVGG', in_channels=3, mid_channels=8), pixel_loss=dict(type='L1Loss', loss_weight=1e-2, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'34': 1.0}, vgg_type='vgg19', perceptual_weight=1.0, style_weight=0, norm_img=False), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=5e-3, real_label_val=1.0, fake_label_val=0), train_cfg=None, test_cfg=None, data_preprocessor=DataPreprocessor()) assert isinstance(model, SRGAN) assert isinstance(model.generator, MSRResNet) assert isinstance(model.discriminator, ModifiedVGG) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.perceptual_loss, PerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 32, 32) target = torch.rand(3, 128, 128) data_sample = DataSample(gt_img=target) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_gan', 'loss_pix', 'loss_perceptual', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 128, 128) # feat output = model(torch.rand(1, 3, 32, 32), mode='tensor') assert output.shape == (1, 3, 128, 128) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion/test_clip_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import importlib import sys import pytest import torch def test_clip_wrapper(): from transformers import CLIPConfig from mmagic.models.editors.stable_diffusion.clip_wrapper import \ StableDiffusionSafetyChecker clipconfig = CLIPConfig() safety_checker = StableDiffusionSafetyChecker(clipconfig) clip_input = torch.rand((1, 3, 224, 224)) images_input = torch.rand((1, 512, 512, 3)) result = safety_checker.forward(clip_input, images_input) assert result[0].shape == (1, 512, 512, 3) def test_load_clip_submodels(): from mmagic.models.editors.stable_diffusion.clip_wrapper import \ load_clip_submodels init_cfg = dict( type='Pretrained', pretrained_model_path='tem', ) submodels = [] with pytest.raises(Exception): load_clip_submodels(init_cfg, submodels, True) def test_load_clip_submodels_transformers_none(): transformer_location = sys.modules['transformers'] sys.modules['transformers'] = None importlib.reload( sys.modules['mmagic.models.editors.stable_diffusion.clip_wrapper']) from mmagic.models.editors.stable_diffusion.clip_wrapper import \ load_clip_submodels init_cfg = dict( type='Pretrained', pretrained_model_path='tem', ) submodels = [] with pytest.raises(ImportError): load_clip_submodels(init_cfg, submodels, True) sys.modules['transformers'] = transformer_location def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch import torch.nn as nn from addict import Dict from mmengine import MODELS, Config from mmagic.utils import register_all_modules register_all_modules() unet = dict( type='DenoisingUnet', image_size=128, base_channels=32, channels_cfg=[1, 2], unet_type='stable', act_cfg=dict(type='silu', inplace=False), cross_attention_dim=768, num_heads=2, in_channels=4, layers_per_block=1, down_block_types=['CrossAttnDownBlock2D', 'DownBlock2D'], up_block_types=['UpBlock2D', 'CrossAttnUpBlock2D'], output_cfg=dict(var='fixed')) vae = dict( type='EditAutoencoderKL', act_fn='silu', block_out_channels=[128], down_block_types=['DownEncoderBlock2D'], in_channels=3, latent_channels=4, layers_per_block=1, norm_num_groups=32, out_channels=3, sample_size=128, up_block_types=[ 'UpDecoderBlock2D', ]) diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) init_cfg = dict(type='Pretrained', pretrained_model_path=None) class dummy_tokenizer(nn.Module): def __init__(self): super().__init__() self.model_max_length = 0 def __call__(self, prompt, padding='max_length', max_length=0, truncation=False, return_tensors='pt'): text_inputs = Dict() text_inputs['input_ids'] = torch.ones([1, 77]) text_inputs['attention_mask'] = torch.ones([1, 77]) return text_inputs class dummy_text_encoder(nn.Module): def __init__(self): super().__init__() self.config = None def __call__(self, x, attention_mask): result = torch.rand([1, 77, 768]) return [result] model = dict( type='StableDiffusion', scheduler=diffusion_scheduler, unet=unet, vae=vae, init_cfg=init_cfg, text_encoder=dummy_text_encoder(), tokenizer=dummy_text_encoder()) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_stable_diffusion(): StableDiffuser = MODELS.build(Config(model)) StableDiffuser.tokenizer = dummy_tokenizer() StableDiffuser.text_encoder = dummy_text_encoder() with pytest.raises(Exception): StableDiffuser.infer(1, height=64, width=64) with pytest.raises(Exception): StableDiffuser.infer('temp', height=31, width=31) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (1, 3, 64, 64) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='image') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion_inpaint.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch import torch.nn as nn from addict import Dict from mmengine import MODELS, Config from mmagic.utils import register_all_modules register_all_modules() unet = dict( type='DenoisingUnet', image_size=128, base_channels=32, channels_cfg=[1, 2], unet_type='stable', act_cfg=dict(type='silu', inplace=False), cross_attention_dim=768, num_heads=2, in_channels=9, out_channels=4, layers_per_block=1, down_block_types=['CrossAttnDownBlock2D', 'DownBlock2D'], up_block_types=['UpBlock2D', 'CrossAttnUpBlock2D'], output_cfg=dict(var='fixed')) vae = dict( type='EditAutoencoderKL', act_fn='silu', block_out_channels=[128], down_block_types=['DownEncoderBlock2D'], in_channels=3, latent_channels=4, layers_per_block=1, norm_num_groups=32, out_channels=3, sample_size=128, up_block_types=[ 'UpDecoderBlock2D', ]) diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) init_cfg = dict(type='Pretrained', pretrained_model_path=None) class dummy_tokenizer(nn.Module): def __init__(self): super().__init__() self.model_max_length = 0 def __call__(self, prompt, padding='max_length', max_length=0, truncation=False, return_tensors='pt'): text_inputs = Dict() text_inputs['input_ids'] = torch.ones([1, 77]) text_inputs['attention_mask'] = torch.ones([1, 77]) return text_inputs class dummy_text_encoder(nn.Module): def __init__(self): super().__init__() self.config = None def __call__(self, x, attention_mask): result = torch.rand([1, 77, 768]) return [result] model = dict( type='StableDiffusionInpaint', scheduler=diffusion_scheduler, unet=unet, vae=vae, init_cfg=init_cfg, text_encoder=dummy_text_encoder(), tokenizer=dummy_text_encoder()) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') def test_stable_diffusion(): StableDiffuser = MODELS.build(Config(model)) StableDiffuser.tokenizer = dummy_tokenizer() StableDiffuser.text_encoder = dummy_text_encoder() config = getattr(StableDiffuser.vae, 'config', None) if config is None: class DummyConfig: pass config = DummyConfig() setattr(config, 'scaling_factor', 1.2) setattr(StableDiffuser.vae, 'config', config) image = torch.clip(torch.randn((1, 3, 64, 64)), -1, 1) mask = torch.clip(torch.randn((1, 1, 64, 64)), 0, 1) with pytest.raises(Exception): StableDiffuser.infer('temp', image, mask, height=31, width=31) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', image=image, mask_image=mask, height=64, width=64, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (1, 3, 64, 64) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', image=image, mask_image=mask, height=64, width=64, num_inference_steps=1, return_type='image') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion_tomesd.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch import torch.nn as nn from addict import Dict from mmengine import MODELS, Config from mmagic.utils import register_all_modules register_all_modules() unet = dict( type='DenoisingUnet', image_size=128, base_channels=32, channels_cfg=[1, 2], unet_type='stable', act_cfg=dict(type='silu', inplace=False), cross_attention_dim=768, num_heads=2, in_channels=4, layers_per_block=1, down_block_types=['CrossAttnDownBlock2D', 'DownBlock2D'], up_block_types=['UpBlock2D', 'CrossAttnUpBlock2D'], output_cfg=dict(var='fixed')) vae = dict( type='EditAutoencoderKL', act_fn='silu', block_out_channels=[128], down_block_types=['DownEncoderBlock2D'], in_channels=3, latent_channels=4, layers_per_block=1, norm_num_groups=32, out_channels=3, sample_size=128, up_block_types=[ 'UpDecoderBlock2D', ]) diffusion_scheduler = dict( type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', beta_start=0.00085, num_train_timesteps=1000, set_alpha_to_one=False, clip_sample=False) init_cfg = dict(type='Pretrained', pretrained_model_path=None) class dummy_tokenizer(nn.Module): def __init__(self): super().__init__() self.model_max_length = 0 def __call__(self, prompt, padding='max_length', max_length=0, truncation=False, return_tensors='pt'): text_inputs = Dict() text_inputs['input_ids'] = torch.ones([1, 77]) text_inputs['attention_mask'] = torch.ones([1, 77]) return text_inputs class dummy_text_encoder(nn.Module): def __init__(self): super().__init__() self.config = None def __call__(self, x, attention_mask): result = torch.rand([1, 77, 768]) return [result] model = dict( type='StableDiffusion', scheduler=diffusion_scheduler, unet=unet, vae=vae, init_cfg=init_cfg, text_encoder=dummy_text_encoder(), tokenizer=dummy_text_encoder(), tomesd_cfg=dict(ratio=0.5)) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') @pytest.mark.skipif( not hasattr(torch.Tensor, 'scatter_reduce') or torch.__version__ < '1.12.1', reason='required method') def test_stable_diffusion(): StableDiffuser = MODELS.build(Config(model)) StableDiffuser.tokenizer = dummy_tokenizer() StableDiffuser.text_encoder = dummy_text_encoder() with pytest.raises(Exception): StableDiffuser.infer(1, height=64, width=64) with pytest.raises(Exception): StableDiffuser.infer('temp', height=31, width=31) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (1, 3, 64, 64) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='image') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion/test_vae.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.stable_diffusion.vae import ( AttentionBlock, AutoencoderKL, DiagonalGaussianDistribution, Downsample2D, ResnetBlock2D, Upsample2D) def test_vae(): input = torch.rand((1, 3, 32, 32)) vae = AutoencoderKL() output = vae.forward(input) assert output['sample'].shape == (1, 3, 32, 32) def test_resnetblock2d(): input = torch.rand((1, 64, 16, 16)) resblock = ResnetBlock2D(in_channels=64, up=True) output = resblock.forward(input, None) assert output.shape == (1, 64, 64, 64) resblock = ResnetBlock2D(in_channels=64, down=True) output = resblock.forward(input, None) assert output.shape == (1, 64, 8, 8) def test_DiagonalGaussianDistribution(): param = torch.rand((1, 2, 16, 16)) sample = torch.rand((1, 1, 16, 16)) gauss_dist = DiagonalGaussianDistribution(param, deterministic=False) gauss_dist.sample() gauss_dist.kl() output = gauss_dist.nll(sample) assert output.shape == (1, ) gauss_dist = DiagonalGaussianDistribution(param, deterministic=True) gauss_dist.sample() gauss_dist.kl() output = gauss_dist.nll(sample) assert output.shape == (1, ) def test_AttentionBlock(): input = torch.rand((1, 64, 32, 32)) attention = AttentionBlock(64, num_head_channels=8) output = attention.forward(input) assert output.shape == (1, 64, 32, 32) def test_Downsample2D(): input = torch.rand((1, 64, 16, 16)) downsample = Downsample2D(channels=64, use_conv=True, padding=0) output = downsample.forward(input) assert output.shape == (1, 64, 8, 8) def test_Upsample2D(): input = torch.rand((1, 64, 16, 16)) upsample = Upsample2D(channels=64, use_conv_transpose=True) output = upsample.forward(input) assert output.shape == (1, 64, 32, 32) upsample = Upsample2D(channels=64) output = upsample.forward(input, output_size=(32, 32)) assert output.shape == (1, 64, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stable_diffusion_xl/test_stable_diffusion_xl.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmengine import MODELS, Config from mmengine.optim import OptimWrapper from torch.optim import SGD from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() stable_diffusion_xl_tiny_url = 'hf-internal-testing/tiny-stable-diffusion-xl-pipe' # noqa model = dict( type='StableDiffusionXL', unet=dict( type='UNet2DConditionModel', subfolder='unet', from_pretrained=stable_diffusion_xl_tiny_url), vae=dict(type='AutoencoderKL', sample_size=64), text_encoder_one=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_xl_tiny_url, subfolder='text_encoder'), tokenizer_one=stable_diffusion_xl_tiny_url, text_encoder_two=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_xl_tiny_url, subfolder='text_encoder_2'), tokenizer_two=stable_diffusion_xl_tiny_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_xl_tiny_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_xl_tiny_url, subfolder='scheduler'), val_prompts=['a dog', 'a dog']) @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') @pytest.mark.skipif( torch.__version__ < '1.9.0', reason='skip on torch<1.9 due to unsupported torch.concat') def test_stable_xl_diffusion(): StableDiffuser = MODELS.build(Config(model)) with pytest.raises(Exception): StableDiffuser.infer(1, height=64, width=64) with pytest.raises(Exception): StableDiffuser.infer('temp', height=31, width=31) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (1, 3, 64, 64) result = StableDiffuser.infer( 'an insect robot preparing a delicious meal', height=64, width=64, num_inference_steps=1, return_type='image') @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') @pytest.mark.skipif( torch.__version__ < '1.9.0', reason='skip on torch<1.9 due to unsupported torch.concat') def test_stable_diffusion_xl_step(): StableDiffuser = MODELS.build(Config(model)) # train step data = dict( inputs=torch.ones([1, 3, 64, 64]), time_ids=torch.zeros((1, 6)), data_samples=[ DataSample(prompt='an insect robot preparing a delicious meal') ]) optimizer = SGD(StableDiffuser.parameters(), lr=0.1) optim_wrapper = OptimWrapper(optimizer) log_vars = StableDiffuser.train_step(data, optim_wrapper) assert log_vars assert isinstance(log_vars['loss'], torch.Tensor) # val step data = dict(data_samples=[DataSample()]) outputs = StableDiffuser.val_step(data) assert len(outputs) == 2 assert isinstance(outputs[0].fake_img, torch.Tensor) assert outputs[0].fake_img.shape == (3, 32, 32) # test step outputs = StableDiffuser.test_step(data) assert len(outputs) == 2 assert isinstance(outputs[0].fake_img, torch.Tensor) assert outputs[0].fake_img.shape == (3, 32, 32) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan1/test_stylegan1.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest import TestCase import numpy as np import pytest import torch from mmengine import MessageHub from mmagic.engine import PGGANOptimWrapperConstructor from mmagic.models import StyleGAN1 from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestStyleGAN1(TestCase): style_channels = 16 generator_cfg = dict( type='StyleGAN1Generator', out_size=64, style_channels=16) discriminator_cfg = dict(type='StyleGAN1Discriminator', in_size=64) nkimgs_per_scale = {'16': 0.004, '32': 0.008, '64': 0.016} data_preprocessor = dict(type='DataPreprocessor') lr_schedule = dict(generator={'32': 0.0015}, discriminator={'32': 0.0015}) optim_wrapper_cfg = dict( generator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), discriminator=dict( optimizer=dict(type='Adam', lr=0.001, betas=(0., 0.99))), lr_schedule=lr_schedule) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_stylegan_cpu(self): message_hub = MessageHub.get_instance('test-s1') message_hub.update_info('iter', 0) # test default config stylegan = StyleGAN1( self.generator_cfg, self.discriminator_cfg, style_channels=self.style_channels, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, ema_config=dict(interval=1)) constructor = PGGANOptimWrapperConstructor(self.optim_wrapper_cfg) optim_wrapper_dict = constructor(stylegan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 64, 64)) for _ in range(3) ]) for iter_num in range(6): stylegan.train_step(data_batch, optim_wrapper_dict) if iter_num in [0, 1]: assert stylegan.curr_scale[0] == 16 elif iter_num in [2, 3]: assert stylegan.curr_scale[0] == 32 elif iter_num in [4, 5]: assert stylegan.curr_scale[0] == 64 if iter_num == 2: assert np.isclose(stylegan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 3: assert np.isclose(stylegan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 5: assert np.isclose( stylegan._actual_nkimgs[-1], 0.012, atol=1e-8) # test forward outputs = stylegan.forward(dict(num_batches=2)) # assert outputs.shape == (2, 3, 64, 64) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 64, 64) for out in outputs]) outputs = stylegan.forward( dict( num_batches=2, return_noise=True, transition_weight=0.2, sample_model='ema')) # assert outputs.shape == (2, 3, 64, 64) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 64, 64) for out in outputs]) outputs = stylegan.forward(dict(num_batches=2, sample_model='orig')) # assert outputs.shape == (2, 3, 64, 64) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 64, 64) for out in outputs]) outputs = stylegan.forward( dict(num_batches=2, sample_model='ema/orig')) # assert isinstance(outputs, dict) # assert list(outputs.keys()) == ['ema', 'orig'] # assert all([o.shape == (2, 3, 64, 64) for o in outputs.values()]) assert len(outputs) == 2 assert all([out.ema.fake_img.shape == (3, 64, 64) for out in outputs]) assert all([out.orig.fake_img.shape == (3, 64, 64) for out in outputs]) outputs = stylegan.forward(dict(num_batches=2, curr_scale=8)) # assert outputs.shape == (2, 3, 8, 8) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 8, 8) for out in outputs]) outputs = stylegan.forward(dict(noise=torch.randn(2, 16))) # assert outputs.shape == (2, 3, 64, 64) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 64, 64) for out in outputs]) outputs = stylegan.forward(torch.randn(2, 16)) # assert outputs.shape == (2, 3, 64, 64) assert len(outputs) == 2 assert all([out.fake_img.shape == (3, 64, 64) for out in outputs]) # test train_step with error with pytest.raises(RuntimeError): data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 4, 32)) for _ in range(3) ]) _ = stylegan.train_step(data_batch, optim_wrapper_dict) # test train_step without ema stylegan = StyleGAN1( self.generator_cfg, self.discriminator_cfg, style_channels=self.style_channels, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale) optim_wrapper_dict = constructor(stylegan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 64, 64)) for _ in range(3) ]) stylegan.train_step(data_batch, optim_wrapper_dict) # test train_step with disc_step != 1 stylegan._disc_steps = 2 stylegan.train_step(data_batch, optim_wrapper_dict) # test default configs stylegan = StyleGAN1( self.generator_cfg, self.discriminator_cfg, style_channels=self.style_channels, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, interp_real=dict(mode='bicubic'), ema_config=dict(interval=1)) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_stylegan_cuda(self): stylegan = StyleGAN1( self.generator_cfg, self.discriminator_cfg, style_channels=self.style_channels, data_preprocessor=self.data_preprocessor, nkimgs_per_scale=self.nkimgs_per_scale, ema_config=dict(interval=1)).cuda() constructor = PGGANOptimWrapperConstructor(self.optim_wrapper_cfg) optim_wrapper_dict = constructor(stylegan) data_batch = dict( inputs=dict(), data_samples=[ DataSample(gt_img=torch.randn(3, 64, 64)) for _ in range(3) ]) for iter_num in range(6): stylegan.train_step(data_batch, optim_wrapper_dict) if iter_num in [0, 1]: assert stylegan.curr_scale[0] == 16 elif iter_num in [2, 3]: assert stylegan.curr_scale[0] == 32 elif iter_num in [4, 5]: assert stylegan.curr_scale[0] == 64 if iter_num == 2: assert np.isclose(stylegan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 3: assert np.isclose(stylegan._actual_nkimgs[0], 0.006, atol=1e-8) elif iter_num == 5: assert np.isclose( stylegan._actual_nkimgs[-1], 0.012, atol=1e-8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan1/test_stylegan1_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.stylegan1 import StyleGAN1Discriminator from mmagic.utils import register_all_modules register_all_modules() class TestStyleGANv1Disc: @classmethod def setup_class(cls): cls.default_cfg = dict(in_size=64) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_stylegan1_disc_cuda(self): d = StyleGAN1Discriminator(**self.default_cfg).cuda() img = torch.randn((2, 3, 64, 64)).cuda() score = d(img) assert score.shape == (2, 1) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_stylegan1_disc_cpu(self): d = StyleGAN1Discriminator(**self.default_cfg) img = torch.randn((2, 3, 64, 64)) score = d(img) assert score.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan1/test_stylegan1_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.stylegan1 import StyleGAN1Generator from mmagic.utils import register_all_modules register_all_modules() class TestStyleGAN1Generator: @classmethod def setup_class(cls): cls.default_cfg = dict( out_size=256, style_channels=512, num_mlps=8, blur_kernel=[1, 2, 1], lr_mlp=0.01, default_style_mode='mix', eval_style_mode='single', mix_prob=0.9) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_g_cuda(self): # test default config g = StyleGAN1Generator(**self.default_cfg).cuda() res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=random_noise, randomize_noise=False) assert res.shape == (1, 3, 256, 256) res = g( None, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) styles = [torch.randn((1, 512)).cuda() for _ in range(2)] res = g( styles, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) res = g( torch.randn, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) g.eval() assert g.default_style_mode == 'single' g.train() assert g.default_style_mode == 'mix' with pytest.raises(AssertionError): styles = [torch.randn((1, 6)).cuda() for _ in range(2)] _ = g(styles, injected_noise=None, randomize_noise=False) cfg_ = deepcopy(self.default_cfg) cfg_['out_size'] = 128 g = StyleGAN1Generator(**cfg_).cuda() res = g(None, num_batches=2) assert res.shape == (2, 3, 128, 128) # test generate function truncation_latent = g.get_mean_latent() assert truncation_latent.shape == (1, 512) style_mixing_images = g.style_mixing( curr_scale=32, truncation_latent=truncation_latent, n_source=4, n_target=4) assert style_mixing_images.shape == (25, 3, 32, 32) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_g_cpu(self): # test default config g = StyleGAN1Generator(**self.default_cfg) res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=random_noise, randomize_noise=False) assert res.shape == (1, 3, 256, 256) res = g( None, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) styles = [torch.randn((1, 512)) for _ in range(2)] res = g( styles, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) res = g( torch.randn, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 256, 256) g.eval() assert g.default_style_mode == 'single' g.train() assert g.default_style_mode == 'mix' with pytest.raises(AssertionError): styles = [torch.randn((1, 6)) for _ in range(2)] _ = g(styles, injected_noise=None, randomize_noise=False) cfg_ = deepcopy(self.default_cfg) cfg_['out_size'] = 128 g = StyleGAN1Generator(**cfg_) res = g(None, num_batches=2) assert res.shape == (2, 3, 128, 128) # test generate function truncation_latent = g.get_mean_latent() assert truncation_latent.shape == (1, 512) style_mixing_images = g.style_mixing( curr_scale=32, truncation_latent=truncation_latent, n_source=4, n_target=4) assert style_mixing_images.shape == (25, 3, 32, 32) # set mix_prob as 1.0 and 0.0 to force cover lines cfg_ = deepcopy(self.default_cfg) cfg_['mix_prob'] = 1 g = StyleGAN1Generator(**cfg_) res = g(torch.randn, num_batches=2) assert res.shape == (2, 3, 256, 256) cfg_ = deepcopy(self.default_cfg) cfg_['mix_prob'] = 1 g = StyleGAN1Generator(**cfg_) res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) cfg_ = deepcopy(self.default_cfg) cfg_['mix_prob'] = 0 g = StyleGAN1Generator(**cfg_) res = g(torch.randn, num_batches=2) assert res.shape == (2, 3, 256, 256) cfg_ = deepcopy(self.default_cfg) cfg_['mix_prob'] = 0 g = StyleGAN1Generator(**cfg_) res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan1/test_stylegan1_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.stylegan1.stylegan1_modules import ( AdaptiveInstanceNorm, StyleConv) class TestAdaptiveInstanceNorm: @classmethod def setup_class(cls): cls.in_channel = 512 cls.style_dim = 512 @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_adain_cuda(self): adain = AdaptiveInstanceNorm(self.in_channel, self.style_dim).cuda() x = torch.randn((2, 512, 8, 8)).cuda() style = torch.randn((2, 512)).cuda() res = adain(x, style) assert res.shape == (2, 512, 8, 8) class TestStyleConv: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=512, out_channels=256, kernel_size=3, style_channels=512, padding=1, initial=False, blur_kernel=[1, 2, 1], upsample=True, fused=False) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_styleconv_cuda(self): conv = StyleConv(**self.default_cfg).cuda() input_x = torch.randn((2, 512, 32, 32)).cuda() input_style1 = torch.randn((2, 512)).cuda() input_style2 = torch.randn((2, 512)).cuda() res = conv(input_x, input_style1, input_style2) assert res.shape == (2, 256, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan1/test_stylegan_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock, patch import torch from mmagic.models.editors.stylegan1 import get_mean_latent, style_mixing get_module_device_str = 'mmagic.models.editors.stylegan1.stylegan_utils.get_module_device' # noqa @patch(get_module_device_str, MagicMock(return_value='cpu')) def test_get_mean_latent(): generator = MagicMock() generator.style_mapping = MagicMock(return_value=torch.randn(1024, 16)) mean_style = get_mean_latent(generator) assert mean_style.shape == (1, 16) def mock_generator(code, *args, **kwargs): if isinstance(code, torch.Tensor): n_sample = code.shape[0] elif isinstance(code, list): # is list n_sample = code[0].shape[0] return torch.randn(n_sample, 3, 16, 16) @patch(get_module_device_str, MagicMock(return_value='cpu')) def test_style_mixing(): out = style_mixing(mock_generator, n_source=10, n_target=11) assert out.shape == ((1 + 10 + (1 + 10) * 11), 3, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan2/test_ada/test_augment.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest import TestCase import pytest import torch from mmengine import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.editors.stylegan2.ada.augment import AugmentPipe class TestAuementPipe(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( xflip=1, rotate90=1, xint=1, xint_max=1, scale=1, rotate=1, aniso=1, xfrac=1, scale_std=1, rotate_max=1, aniso_std=1, xfrac_std=1, brightness=1, contrast=1, lumaflip=1, hue=1, saturation=1, brightness_std=1, contrast_std=1, hue_max=1, saturation_std=1, imgfilter=1, imgfilter_bands=[1, 1, 1, 1], imgfilter_std=1, noise=1, cutout=1, noise_std=1, cutout_size=0.5, ) @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0') or 'win' in platform.system().lower() or not torch.cuda.is_available(), reason=('torch version lower than 1.7.0 does not have ' '`torch.exp2` api, skip on windows due to uncompiled ops.')) def test_forward(self): augment_pipeline = AugmentPipe(**self.default_cfg) inp = torch.rand(2, 3, 64, 64) out = augment_pipeline(inp) assert out.shape == (2, 3, 64, 64) out = augment_pipeline(inp, debug_percentile=0.1) no_aug_cfg = { k: 0 for k, v in self.default_cfg.items() if isinstance(v, (float, int)) } augment_pipeline = AugmentPipe(**no_aug_cfg) inp = torch.rand(2, 3, 64, 64) out = augment_pipeline(inp) assert out.shape == (2, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan2/test_stylegan2.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest import TestCase import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmagic.models import DataPreprocessor, StyleGAN2 from mmagic.structures import DataSample class TestStyleGAN2(TestCase): @classmethod def setup_class(cls): cls.generator_cfg = dict( type='StyleGANv2Generator', out_size=32, style_channels=16) cls.disc_cfg = dict(type='StyleGAN2Discriminator', in_size=32) # reg params d_reg_interval = 16 g_reg_interval = 4 ema_half_life = 10. # G_smoothing_kimg cls.ema_config = dict( type='ExponentialMovingAverage', interval=1, momentum=1. - (0.5**(32. / (ema_half_life * 1000.)))) cls.loss_config = dict( r1_loss_weight=10. / 2. * d_reg_interval, r1_interval=d_reg_interval, norm_mode='HWC', g_reg_interval=g_reg_interval, g_reg_weight=2. * g_reg_interval, pl_batch_shrink=2) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_stylegan2_cpu(self): accu_iter = 1 message_hub = MessageHub.get_instance('test-s2') stylegan2 = StyleGAN2( self.generator_cfg, self.disc_cfg, data_preprocessor=DataPreprocessor(), ema_config=self.ema_config, loss_config=self.loss_config) optimizer_g = torch.optim.SGD( stylegan2.generator.parameters(), lr=0.01) optimizer_d = torch.optim.SGD( stylegan2.discriminator.parameters(), lr=0.01) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(optimizer_g, accumulative_counts=accu_iter), discriminator=OptimWrapper( optimizer_d, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 32, 32) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here message_hub.update_info('iter', 0) _ = stylegan2.train_step(data, optim_wrapper_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan2/test_stylegan2_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch import torch.nn as nn from mmengine import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.editors.stylegan2 import (ADAAug, ADAStyleGAN2Discriminator, StyleGAN2Discriminator) from mmagic.models.utils import get_module_device @pytest.mark.skipif( ('win' in platform.system().lower() and 'cu' in torch.__version__) or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') class TestStyleGANv2Disc: @classmethod def setup_class(cls): cls.default_cfg = dict(in_size=64, channel_multiplier=1) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_stylegan2_disc_cpu(self): d = StyleGAN2Discriminator(**self.default_cfg) img = torch.randn((2, 3, 64, 64)) score = d(img) assert score.shape == (2, 1) cfg = deepcopy(self.default_cfg) cfg['cond_size'] = 5 cfg['cond_mapping_channels'] = 16 d = StyleGAN2Discriminator(**cfg) score = d(img, torch.randn(2, 5)) assert score.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_stylegan2_disc_cuda(self): d = StyleGAN2Discriminator(**self.default_cfg).cuda() img = torch.randn((2, 3, 64, 64)).cuda() score = d(img) assert score.shape == (2, 1) cfg = deepcopy(self.default_cfg) cfg['cond_size'] = 5 cfg['cond_mapping_channels'] = 16 d = StyleGAN2Discriminator(**cfg).cuda() score = d(img, torch.randn(2, 5).cuda()) assert score.shape == (2, 1) def test_get_module_device_cpu(): device = get_module_device(nn.Conv2d(3, 3, 3, 1, 1)) assert device == torch.device('cpu') # The input module should contain parameters. with pytest.raises(ValueError): get_module_device(nn.Flatten()) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_get_module_device_cuda(): module = nn.Conv2d(3, 3, 3, 1, 1).cuda() device = get_module_device(module) assert device == next(module.parameters()).get_device() # The input module should contain parameters. with pytest.raises(ValueError): get_module_device(nn.Flatten().cuda()) class TestStyleGANv2AdaDisc: @classmethod def setup_class(cls): cls.default_cfg = dict( in_size=64, data_aug=dict(type='ADAAug'), channel_multiplier=1) @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0'), reason='torch version lower than 1.7.0 does not have `torch.exp2` api') def test_styleganv2_ada(self): disc = ADAStyleGAN2Discriminator(**self.default_cfg) assert hasattr(disc, 'ada_aug') img = torch.randn(2, 3, 64, 64) score = disc(img) assert score.shape == (2, 1) cfg = deepcopy(self.default_cfg) cfg['data_aug'] = None disc = ADAStyleGAN2Discriminator(**cfg) assert not hasattr(disc, 'ada_aug') img = torch.randn(2, 3, 64, 64) score = disc(img) assert score.shape == (2, 1) @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0'), reason='torch version lower than 1.7.0 does not have `torch.exp2` api') def test_ada_pipeline(): ada = ADAAug() ada.update(0, 2) ada.update(1, 2) ada.update(2, 2) assert (ada.log_buffer == 0).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan2/test_stylegan2_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.stylegan2 import StyleGAN2Generator class TestStyleGAN2Generator: @classmethod def setup_class(cls): cls.default_cfg = dict( out_size=64, style_channels=16, num_mlps=4, channel_multiplier=1) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_stylegan2_g_cpu(self): # test default config g = StyleGAN2Generator(**self.default_cfg) res = g(None, num_batches=2) assert res.shape == (2, 3, 64, 64) # test truncation_latent is None assert not hasattr(g, 'truncation_latent') res = g(None, num_batches=2, truncation=0.9) assert res.shape == (2, 3, 64, 64) assert hasattr(g, 'truncation_latent') assert g.truncation_latent.shape == (1, 16) res = g(None, num_batches=2, truncation=0.9) assert res.shape == (2, 3, 64, 64) truncation_mean = g.get_mean_latent() res = g( None, num_batches=2, randomize_noise=False, truncation=0.7, truncation_latent=truncation_mean) assert res.shape == (2, 3, 64, 64) res = g.style_mixing(2, 2, truncation_latent=truncation_mean) assert res.shape[2] == 64 random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=random_noise, randomize_noise=False) assert res.shape == (1, 3, 64, 64) random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) styles = [torch.randn((1, 16)) for _ in range(2)] res = g( styles, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) res = g( torch.randn, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) g.eval() assert g.default_style_mode == 'single' g.train() assert g.default_style_mode == 'mix' with pytest.raises(AssertionError): styles = [torch.randn((1, 6)) for _ in range(2)] _ = g(styles, injected_noise=None, randomize_noise=False) cfg_ = deepcopy(self.default_cfg) cfg_['out_size'] = 256 g = StyleGAN2Generator(**cfg_) res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) # set mix_prob as 1 and 0 to cover all lines g.mix_prob = 1 res = g(None, num_batches=2) g.mix_prob = 0 res = g(None, num_batches=2) # test cond channels is negative number cfg_ = deepcopy(self.default_cfg) cfg_['cond_size'] = -1 g = StyleGAN2Generator(**cfg_) assert not hasattr(g, 'embed') # test cond channels > 0 cfg_ = deepcopy(self.default_cfg) cfg_['cond_size'] = 10 g = StyleGAN2Generator(**cfg_) assert hasattr(g, 'embed') assert hasattr(g, 'w_avg') # test raise error with pytest.raises(AssertionError): g(None, num_batches=2) res = g(None, num_batches=2, label=torch.randn(2, 10)) assert res.shape == (2, 3, 64, 64) # test update_mean_latent_with_ema cfg_ = deepcopy(self.default_cfg) cfg_['update_mean_latent_with_ema'] = True g = StyleGAN2Generator(**cfg_) assert hasattr(g, 'w_avg') # test get_mean_latent mean_latent = g.get_mean_latent().clone() # copy for test assert mean_latent.shape == (16, ) assert (mean_latent == 0).all() # test update w_avg with ema g.eval() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False, update_ws=True) mean_latent_test = g.get_mean_latent().clone() # copy for test # should not be update in test assert (mean_latent_test == mean_latent).all() # test return features g.eval() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False, return_noise=True, return_features=True, feat_idx=1) assert res['feats'].shape == (1, 512, 8, 8) assert res['latent'].shape == (1, 10, 16) # test return latent only g.eval() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False, return_latent_only=True) assert res.shape == (1, 10, 16) g.train() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False, update_ws=True) mean_latent_train = g.get_mean_latent().clone() # copy for test # should be update in train assert (mean_latent_train != mean_latent).any() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False, update_ws=False) mean_latent_no_update = g.get_mean_latent().clone() # copy for test assert (mean_latent_train == mean_latent_no_update).all() @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_g_cuda(self): # test default config g = StyleGAN2Generator(**self.default_cfg).cuda() res = g(None, num_batches=2) assert res.shape == (2, 3, 64, 64) random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=random_noise, randomize_noise=False) assert res.shape == (1, 3, 64, 64) random_noise = g.make_injected_noise() res = g( None, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) styles = [torch.randn((1, 16)).cuda() for _ in range(2)] res = g( styles, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) res = g( torch.randn, num_batches=1, injected_noise=None, randomize_noise=False) assert res.shape == (1, 3, 64, 64) g.eval() assert g.default_style_mode == 'single' g.train() assert g.default_style_mode == 'mix' with pytest.raises(AssertionError): styles = [torch.randn((1, 6)).cuda() for _ in range(2)] _ = g(styles, injected_noise=None, randomize_noise=False) cfg_ = deepcopy(self.default_cfg) cfg_['out_size'] = 256 g = StyleGAN2Generator(**cfg_).cuda() res = g(None, num_batches=2) assert res.shape == (2, 3, 256, 256) # set mix_prob as 1 and 0 to cover all lines g.mix_prob = 1 res = g(None, num_batches=2) g.mix_prob = 0 res = g(None, num_batches=2) # test cond channels is negative number cfg_ = deepcopy(self.default_cfg) cfg_['cond_size'] = -1 g = StyleGAN2Generator(**cfg_) assert not hasattr(g, 'embed') # test cond channels > 0 cfg_ = deepcopy(self.default_cfg) cfg_['cond_size'] = 10 g = StyleGAN2Generator(**cfg_) assert hasattr(g, 'embed') # test raise error with pytest.raises(AssertionError): g(None, num_batches=2) res = g(None, num_batches=2, label=torch.randn(2, 10)) assert res.shape == (2, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan2/test_stylegan2_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.stylegan1 import get_mean_latent, style_mixing from mmagic.models.editors.stylegan2 import StyleGAN2Generator from mmagic.models.editors.stylegan2.stylegan2_modules import ( Blur, DownsampleUpFIRDn, ModulatedConv2d, ModulatedStyleConv, ModulatedToRGB) from mmagic.models.utils import get_module_device @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_get_module_device(): config = dict( out_size=64, style_channels=16, num_mlps=4, channel_multiplier=1) g = StyleGAN2Generator(**config) res = g(None, num_batches=2) assert res.shape == (2, 3, 64, 64) truncation_mean = get_mean_latent(g, 4096) res = g( None, num_batches=2, randomize_noise=False, truncation=0.7, truncation_latent=truncation_mean) # res = g.style_mixing(2, 2, truncation_latent=truncation_mean) res = style_mixing( g, n_source=2, n_target=2, truncation_latent=truncation_mean, style_channels=g.style_channels) assert get_module_device(g) == torch.device('cpu') class TestDownsampleUpFIRDn(): def test_DownsampleUpFIRDn(self): downsample = DownsampleUpFIRDn((2, 2), 2) assert downsample.pad == (0, 0) inp = torch.randn(1, 3, 4, 4) out = downsample(inp) assert out.shape == (1, 3, 2, 2) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_DownsampleUpFIRDn_cuda(self): downsample = DownsampleUpFIRDn((2, 2), 2).cuda() assert downsample.pad == (0, 0) inp = torch.randn(1, 3, 4, 4).cuda() out = downsample(inp) assert out.shape == (1, 3, 2, 2) class TestBlur: @classmethod def setup_class(cls): cls.kernel = [1, 3, 3, 1] cls.pad = (1, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_blur_cuda(self): blur = Blur(self.kernel, self.pad) x = torch.randn((2, 3, 8, 8)) res = blur(x) assert res.shape == (2, 3, 7, 7) class TestModStyleConv: @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=1, kernel_size=3, style_channels=5, upsample=True) def test_mod_styleconv_cpu(self): conv = ModulatedStyleConv(**self.default_cfg) input_x = torch.randn((2, 3, 4, 4)) input_style = torch.randn((2, 5)) res = conv(input_x, input_style) assert res.shape == (2, 1, 8, 8) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False conv = ModulatedStyleConv(**_cfg) input_x = torch.randn((2, 3, 4, 4)) input_style = torch.randn((2, 5)) res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) # test add noise noise = torch.randn(2, 1, 4, 4) res = conv(input_x, input_style, noise) assert res.shape == (2, 1, 4, 4) # test add noise + return_noise res = conv(input_x, input_style, noise, return_noise=True) assert isinstance(res, tuple) assert res[0].shape == (2, 1, 4, 4) assert (res[1] == noise).all() # test add noise is False res = conv(input_x, input_style, noise, add_noise=False) assert res.shape == (2, 1, 4, 4) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_mod_styleconv_cuda(self): conv = ModulatedStyleConv(**self.default_cfg).cuda() input_x = torch.randn((2, 3, 4, 4)).cuda() input_style = torch.randn((2, 5)).cuda() res = conv(input_x, input_style) assert res.shape == (2, 1, 8, 8) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False conv = ModulatedStyleConv(**_cfg).cuda() input_x = torch.randn((2, 3, 4, 4)).cuda() input_style = torch.randn((2, 5)).cuda() res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) class TestModulatedConv2d(): @classmethod def setup_class(cls): cls.default_cfg = dict( in_channels=3, out_channels=1, kernel_size=3, style_channels=5, upsample=True) def test_mod_conv_cpu(self): conv = ModulatedConv2d(**self.default_cfg) input_x = torch.randn((2, 3, 4, 4)) input_style = torch.randn((2, 5)) res = conv(input_x, input_style) assert res.shape == (2, 1, 8, 8) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False conv = ModulatedConv2d(**_cfg) input_x = torch.randn((2, 3, 4, 4)) input_style = torch.randn((2, 5)) res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False _cfg['downsample'] = True conv = ModulatedConv2d(**_cfg) input_x = torch.randn((2, 3, 8, 8)) input_style = torch.randn((2, 5)) res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) # test input gain res = conv(input_x, input_style, input_gain=torch.randn(2, 3)) assert res.shape == (2, 1, 4, 4) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_mod_conv_cuda(self): conv = ModulatedConv2d(**self.default_cfg).cuda() input_x = torch.randn((2, 3, 4, 4)).cuda() input_style = torch.randn((2, 5)).cuda() res = conv(input_x, input_style) assert res.shape == (2, 1, 8, 8) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False conv = ModulatedConv2d(**_cfg).cuda() input_x = torch.randn((2, 3, 4, 4)).cuda() input_style = torch.randn((2, 5)).cuda() res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) _cfg = deepcopy(self.default_cfg) _cfg['upsample'] = False _cfg['downsample'] = True conv = ModulatedConv2d(**_cfg).cuda() input_x = torch.randn((2, 3, 8, 8)).cuda() input_style = torch.randn((2, 5)).cuda() res = conv(input_x, input_style) assert res.shape == (2, 1, 4, 4) # test input gain res = conv(input_x, input_style, input_gain=torch.randn(2, 3).cuda()) assert res.shape == (2, 1, 4, 4) class TestToRGB: @classmethod def setup_class(cls): cls.default_cfg = dict(in_channels=5, style_channels=5, out_channels=3) def test_torgb_cpu(self): model = ModulatedToRGB(**self.default_cfg) input_x = torch.randn((2, 5, 4, 4)) style = torch.randn((2, 5)) res = model(input_x, style) assert res.shape == (2, 3, 4, 4) input_x = torch.randn((2, 5, 8, 8)) style = torch.randn((2, 5)) skip = torch.randn(2, 3, 4, 4) res = model(input_x, style, skip) assert res.shape == (2, 3, 8, 8) # test skip is passed + upsample is False cfg = deepcopy(self.default_cfg) cfg['upsample'] = False cfg['out_channels'] = 7 model = ModulatedToRGB(**cfg) input_x = torch.randn((2, 5, 4, 4)) skip = torch.randn(2, 7, 4, 4) style = torch.randn((2, 5)) res = model(input_x, style, skip) assert res.shape == (2, 7, 4, 4) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_torgb_cuda(self): model = ModulatedToRGB(**self.default_cfg).cuda() input_x = torch.randn((2, 5, 4, 4)).cuda() style = torch.randn((2, 5)).cuda() res = model(input_x, style) assert res.shape == (2, 3, 4, 4) input_x = torch.randn((2, 5, 8, 8)).cuda() style = torch.randn((2, 5)).cuda() skip = torch.randn(2, 3, 4, 4).cuda() res = model(input_x, style, skip) assert res.shape == (2, 3, 8, 8) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan3/test_stylegan3.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy from unittest import TestCase import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from mmagic.models import StyleGAN3 from mmagic.structures import DataSample from mmagic.utils import register_all_modules register_all_modules() class TestStyleGAN3(TestCase): @classmethod def setUpClass(cls): cls.default_cfg = dict( data_preprocessor=dict(type='DataPreprocessor'), generator=dict( type='StyleGANv3Generator', noise_size=6, style_channels=8, out_size=16, img_channels=3, synthesis_cfg=dict( type='SynthesisNetwork', channel_base=1024, channel_max=16, magnitude_ema_beta=0.999)), discriminator=dict( type='StyleGAN2Discriminator', in_size=16, channel_multiplier=1), ema_config=dict( type='RampUpEMA', interval=1, ema_kimg=10, ema_rampup=0.05, batch_size=32, eps=1e-08, start_iter=0), loss_config=dict( r1_loss_weight=16.0, r1_interval=16, norm_mode='HWC', g_reg_interval=4, g_reg_weight=8.0, pl_batch_shrink=2)) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_val_and_test_step(self): cfg = deepcopy(self.default_cfg) stylegan = StyleGAN3(**cfg) data = dict(inputs=dict(num_batches=2)) outputs = stylegan.test_step(data) self.assertEqual(len(outputs), 2) self.assertEqual(outputs[0].fake_img.data.shape, (3, 16, 16)) data = dict(inputs=dict(num_batches=2)) outputs = stylegan.val_step(data) self.assertEqual(len(outputs), 2) self.assertEqual(outputs[0].fake_img.data.shape, (3, 16, 16)) eq_cfg = dict( compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True) data = dict(inputs=dict(num_batches=2, eq_cfg=eq_cfg, mode='orig')) outputs = stylegan.test_step(data) outputs = stylegan.val_step(data) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_train_step(self): message_hub = MessageHub.get_instance('test-s3-train-step') cfg = deepcopy(self.default_cfg) stylegan = StyleGAN3(**cfg) optimizer_g = torch.optim.SGD(stylegan.generator.parameters(), lr=0.01) optimizer_d = torch.optim.SGD( stylegan.discriminator.parameters(), lr=0.01) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(optimizer_g, accumulative_counts=1), discriminator=OptimWrapper(optimizer_d, accumulative_counts=1)) img = torch.randn(3, 16, 16) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) message_hub.update_info('iter', 0) _ = stylegan.train_step(data, optim_wrapper_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan3/test_stylegan3_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy import pytest import torch from mmagic.models.editors.stylegan3 import StyleGAN3Generator class TestStyleGAN3Generator: @classmethod def setup_class(cls): synthesis_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 1024, 'channel_max': 16, 'magnitude_ema_beta': 0.999 } cls.default_cfg = dict( noise_size=6, style_channels=8, out_size=16, img_channels=3, synthesis_cfg=synthesis_cfg) synthesis_r_cfg = { 'type': 'SynthesisNetwork', 'channel_base': 1024, 'channel_max': 16, 'magnitude_ema_beta': 0.999, 'conv_kernel': 1, 'use_radial_filters': True } cls.s3_r_cfg = dict( noise_size=6, style_channels=8, out_size=16, img_channels=3, synthesis_cfg=synthesis_r_cfg) @pytest.mark.skipif( ('win' in platform.system().lower() and 'cu' in torch.__version__) or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') def test_cpu(self): generator = StyleGAN3Generator(**self.default_cfg) z = torch.randn((2, 6)) c = None y = generator(z, c) assert y.shape == (2, 3, 16, 16) y = generator(None, num_batches=2) assert y.shape == (2, 3, 16, 16) res = generator(torch.randn, num_batches=1) assert res.shape == (1, 3, 16, 16) cfg = deepcopy(self.default_cfg) cfg.update(dict(rgb2bgr=True)) generator = StyleGAN3Generator(**cfg) y = generator(None, num_batches=2) assert y.shape == (2, 3, 16, 16) # test return latents result = generator(None, num_batches=2, return_latents=True) assert isinstance(result, dict) assert result['fake_img'].shape == (2, 3, 16, 16) assert result['noise_batch'].shape == (2, 6) assert result['latent'].shape == (2, 16, 8) # test input_is_latent result = generator( None, num_batches=2, input_is_latent=True, return_latents=True) assert isinstance(result, dict) assert result['fake_img'].shape == (2, 3, 16, 16) assert result['noise_batch'].shape == (2, 8) assert result['latent'].shape == (2, 16, 8) generator = StyleGAN3Generator(**self.s3_r_cfg) z = torch.randn((2, 6)) c = None y = generator(z, c) assert y.shape == (2, 3, 16, 16) y = generator(None, num_batches=2) assert y.shape == (2, 3, 16, 16) res = generator(torch.randn, num_batches=1) assert res.shape == (1, 3, 16, 16) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_cuda(self): generator = StyleGAN3Generator(**self.default_cfg).cuda() z = torch.randn((2, 6)).cuda() c = None y = generator(z, c) assert y.shape == (2, 3, 16, 16) res = generator(torch.randn, num_batches=1) assert res.shape == (1, 3, 16, 16) cfg = deepcopy(self.default_cfg) cfg.update(dict(rgb2bgr=True)) generator = StyleGAN3Generator(**cfg).cuda() y = generator(None, num_batches=2) assert y.shape == (2, 3, 16, 16) generator = StyleGAN3Generator(**self.s3_r_cfg).cuda() z = torch.randn((2, 6)).cuda() c = None y = generator(z, c) assert y.shape == (2, 3, 16, 16) res = generator(torch.randn, num_batches=1) assert res.shape == (1, 3, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan3/test_stylegan3_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.stylegan3.stylegan3_modules import MappingNetwork @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip on windows due to uncompiled ops.') def test_MappingNetwork(): mapping_network = MappingNetwork(16, 4, 5, cond_size=8) z = torch.randn(1, 16) c = torch.randn(1, 8) out = mapping_network(z, c) assert out.shape == (1, 5, 4) # test w/o conditional input mapping_network = MappingNetwork(16, 4, 5, cond_size=-1) out = mapping_network(z) assert out.shape == (1, 5, 4) # test w/o noise input mapping_network = MappingNetwork(0, 4, 5, cond_size=8) out = mapping_network(None, c) assert out.shape == (1, 5, 4) # test num_ws is None --> no broadcast mapping_network = MappingNetwork(16, 4, num_ws=None, w_avg_beta=None) assert not hasattr(mapping_network, 'w_avg') out = mapping_network(z) assert out.shape == (1, 4) # test truncation is passed with pytest.raises(AssertionError): mapping_network(z, truncation=0.9) mapping_network = MappingNetwork(16, 4, 5) out = mapping_network(z, truncation=0.9) assert out.shape == (1, 5, 4) out_trunc_work = mapping_network(z, truncation=0.9, num_truncation_layer=3) assert out_trunc_work.shape == (1, 5, 4) assert (out_trunc_work[3:] == out[3:]).all() # test z is None + noise_size > 0 with pytest.raises(AssertionError): mapping_network(None) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_stylegan3/test_stylegan3_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from mmagic.models.editors.stylegan3.stylegan3_utils import ( apply_fractional_pseudo_rotation, apply_fractional_rotation, apply_fractional_translation, apply_integer_translation) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip due to uncompiled ops.') def test_integer_transformation(): x = torch.randn(1, 3, 16, 16) t = torch.randn(2) z, m = apply_integer_translation(x, t[0], t[1]) print(z.shape) print(m.shape) # cover more lines t = torch.zeros(2) z, m = apply_integer_translation(x, t[0], t[1]) t = torch.ones(2) * 2 z, m = apply_integer_translation(x, t[0], t[1]) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip due to uncompiled ops.') def test_fractional_translation(): x = torch.randn(1, 3, 16, 16) t = torch.randn(2) z, m = apply_fractional_translation(x, t[0], t[1]) print(z.shape) print(m.shape) # cover more lines t = torch.zeros(2) z, m = apply_fractional_translation(x, t[0], t[1]) t = torch.ones(2) * 2 z, m = apply_fractional_translation(x, t[0], t[1]) @pytest.mark.skipif( 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='skip due to uncompiled ops.') @pytest.mark.skipif( digit_version(TORCH_VERSION) < digit_version('1.8.0'), reason='version limitation') def test_fractional_rotation(): angle = torch.randn([]) x = torch.randn(1, 3, 16, 16) ref, ref_mask = apply_fractional_rotation(x, angle) print(ref.shape) print(ref_mask.shape) @pytest.mark.skipif( digit_version(TORCH_VERSION) < digit_version('1.8.0') or 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='version limitation') def test_fractional_pseduo_rotation(): angle = torch.randn([]) x = torch.randn(1, 3, 16, 16) ref, ref_mask = apply_fractional_pseudo_rotation(x, angle) print(ref.shape) print(ref_mask.shape) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_swinir/test_swinir_modules.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.swinir.swinir_modules import (PatchEmbed, PatchUnEmbed, Upsample, UpsampleOneStep) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_patchEmbed(): net = PatchEmbed( img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None) img = torch.randn(1, 3, 4, 4) output = net(img) assert output.shape == (1, 16, 3) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 16, 3) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_patchUnEmbed(): net = PatchUnEmbed( img_size=16, patch_size=4, in_chans=3, embed_dim=3, norm_layer=None) img = torch.randn(1, 64, 3) output = net(img, (8, 8)) assert output.shape == (1, 3, 8, 8) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda(), (8, 8)) assert output.shape == (1, 3, 8, 8) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_upsample(): net = Upsample(scale=2, num_feat=3) img = torch.randn(1, 3, 8, 8) output = net(img) assert output.shape == (1, 3, 16, 16) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 3, 16, 16) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_upsampleOneStep(): net = UpsampleOneStep( scale=2, num_feat=3, num_out_ch=4, ) img = torch.randn(1, 3, 8, 8) output = net(img) assert output.shape == (1, 4, 16, 16) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert output.shape == (1, 4, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_swinir/test_swinir_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors import SwinIRNet def test_swinir_cpu(): """Test SwinIRNet.""" # x2 model classical SR net = SwinIRNet( upscale=2, in_channels=3, img_size=48, window_size=8, img_range=1.0, depths=[6], embed_dim=60, num_heads=[6], mlp_ratio=2, upsampler='pixelshuffledirect', resi_connection='3conv') img = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 32, 32) net = SwinIRNet( upscale=1, in_channels=3, img_size=48, window_size=8, img_range=1.0, depths=[6], embed_dim=60, num_heads=[6], mlp_ratio=2, upsampler='', resi_connection='1conv') img = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 16, 16) # x3 model classical SR, initialization and forward (cpu) net = SwinIRNet( upscale=3, in_channels=3, img_size=16, window_size=8, img_range=1.0, depths=[2], embed_dim=8, num_heads=[2], mlp_ratio=2, upsampler='pixelshuffle', resi_connection='1conv') img = torch.rand(1, 3, 16, 16) output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 48, 48) # x4 model lightweight SR, initialization and forward (cpu) net = SwinIRNet( upscale=4, in_channels=3, img_size=16, window_size=8, img_range=1.0, depths=[2], embed_dim=8, num_heads=[2], mlp_ratio=2, ape=True, upsampler='nearest+conv', resi_connection='1conv') output = net(img) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 64, 64) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_swinir_cuda(): net = SwinIRNet( upscale=4, in_channels=3, img_size=16, window_size=8, img_range=1.0, depths=[2], embed_dim=8, num_heads=[2], mlp_ratio=2, upsampler='pixelshuffledirect', resi_connection='1conv') img = torch.rand(1, 3, 16, 16) # x4 model lightweight SR forward (gpu) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda()) assert isinstance(output, torch.Tensor) assert output.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_swinir/test_swinir_rstb.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.swinir.swinir_rstb import RSTB @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_rstb(): net = RSTB( dim=6, input_resolution=(8, 8), depth=6, num_heads=6, window_size=8) img = torch.randn(1, 64, 6) output = net(img, (8, 8)) assert output.shape == (1, 64, 6) if torch.cuda.is_available(): net = net.cuda() output = net(img.cuda(), (8, 8)) assert output.shape == (1, 64, 6) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_swinir/test_swinir_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.swinir.swinir_utils import (drop_path, to_2tuple, window_partition, window_reverse) def test_drop_path(): x = torch.randn(1, 3, 8, 8) x = drop_path(x) assert x.shape == (1, 3, 8, 8) def test_to_2tuple(): x = 8 x = to_2tuple(x) assert x == (8, 8) def test_window(): x = torch.randn(1, 8, 8, 3) x = window_partition(x, 4) assert x.shape == (4, 4, 4, 3) x = window_reverse(x, 4, 8, 8) assert x.shape == (1, 8, 8, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_tdan/test_tdan.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models.data_preprocessors import DataPreprocessor from mmagic.models.editors import TDAN, TDANNet from mmagic.models.losses import MSELoss from mmagic.structures import DataSample def test_tdan(): model = TDAN( generator=dict(type='TDANNet'), pixel_loss=dict(type='MSELoss', loss_weight=1.0, reduction='mean'), lq_pixel_loss=dict(type='MSELoss', loss_weight=0.01, reduction='mean'), data_preprocessor=DataPreprocessor(mean=[0.5, 0.5, 0.5])) assert model.__class__.__name__ == 'TDAN' assert isinstance(model.generator, TDANNet) assert isinstance(model.pixel_loss, MSELoss) assert isinstance(model.data_preprocessor, DataPreprocessor) optimizer = Adam(model.generator.parameters(), lr=0.001) optim_wrapper = OptimWrapper(optimizer) # prepare data inputs = torch.rand(5, 3, 16, 16) target = torch.rand(3, 64, 64) data_sample = DataSample(gt_img=target) data = dict(inputs=[inputs], data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 64, 64) # feat output = model(torch.rand(1, 5, 3, 16, 16), mode='tensor') assert output.shape == (1, 3, 64, 64) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_tdan/test_tdan_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import TDANNet def test_tdan_net(): """Test TDANNet.""" # gpu (DCN is available only on GPU) if torch.cuda.is_available(): tdan = TDANNet().cuda() input_tensor = torch.rand(1, 5, 3, 64, 64).cuda() output = tdan(input_tensor) assert len(output) == 2 # (1) HR center + (2) aligned LRs assert output[0].shape == (1, 3, 256, 256) # HR center frame assert output[1].shape == (1, 5, 3, 64, 64) # aligned LRs def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_tof/test_tof_vfi_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import TOFlowVFINet def test_tof_vfi_net(): model = TOFlowVFINet() # test attributes assert model.__class__.__name__ == 'TOFlowVFINet' # prepare data inputs = torch.rand(1, 2, 3, 256, 256) # test on cpu output = model(inputs) assert torch.is_tensor(output) assert output.shape == (1, 3, 256, 256) # test on gpu if torch.cuda.is_available(): model = model.cuda() inputs = inputs.cuda() output = model(inputs) assert torch.is_tensor(output) assert output.shape == (1, 3, 256, 256) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_tof/test_tof_vsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors import TOFlowVSRNet def test_toflow_vsr_net(): imgs = torch.rand(2, 7, 3, 16, 16) model = TOFlowVSRNet(adapt_official_weights=False) out = model(imgs) assert isinstance(out, torch.Tensor) assert out.shape == (2, 3, 16, 16) model = TOFlowVSRNet(adapt_official_weights=True) out = model(imgs) assert isinstance(out, torch.Tensor) assert out.shape == (2, 3, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ttsr/test_lte.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS def test_lte(): model_cfg = dict( type='LTE', requires_grad=False, pixel_range=1., load_pretrained_vgg=False) lte = MODELS.build(model_cfg) assert lte.__class__.__name__ == 'LTE' x = torch.rand(2, 3, 64, 64) x_level3, x_level2, x_level1 = lte(x) assert x_level1.shape == (2, 64, 64, 64) assert x_level2.shape == (2, 128, 32, 32) assert x_level3.shape == (2, 256, 16, 16) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ttsr/test_search_transformer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.registry import MODELS def test_search_transformer(): model_cfg = dict(type='SearchTransformer') model = MODELS.build(model_cfg) lr_pad_level3 = torch.randn((2, 32, 32, 32)) ref_pad_level3 = torch.randn((2, 32, 32, 32)) ref_level3 = torch.randn((2, 32, 32, 32)) ref_level2 = torch.randn((2, 16, 64, 64)) ref_level1 = torch.randn((2, 8, 128, 128)) s, textures = model(lr_pad_level3, ref_pad_level3, (ref_level3, ref_level2, ref_level1)) t_level3, t_level2, t_level1 = textures assert s.shape == (2, 1, 32, 32) assert t_level3.shape == (2, 32, 32, 32) assert t_level2.shape == (2, 16, 64, 64) assert t_level1.shape == (2, 8, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ttsr/test_ttsr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest.mock import patch import pytest import torch from mmengine.optim import OptimWrapper from torch.optim import Adam from mmagic.models import (LTE, TTSR, DataPreprocessor, SearchTransformer, TTSRDiscriminator, TTSRNet) from mmagic.models.losses import (GANLoss, L1Loss, PerceptualVGG, TransferalPerceptualLoss) from mmagic.registry import MODELS from mmagic.structures import DataSample @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') @patch.object(PerceptualVGG, 'init_weights') def test_ttsr(init_weights): model_cfg = dict( type='TTSR', generator=dict( type='TTSRNet', in_channels=3, out_channels=3, mid_channels=4, num_blocks=(1, 1, 1, 1)), extractor=dict(type='LTE', load_pretrained_vgg=False), transformer=dict(type='SearchTransformer'), discriminator=dict(type='TTSRDiscriminator', in_size=128), pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'), perceptual_loss=dict( type='PerceptualLoss', layer_weights={'29': 1.0}, vgg_type='vgg19', perceptual_weight=1e-2, style_weight=0.001, criterion='mse'), transferal_perceptual_loss=dict( type='TransferalPerceptualLoss', loss_weight=1e-2, use_attention=False, criterion='mse'), gan_loss=dict( type='GANLoss', gan_type='vanilla', loss_weight=1e-3, real_label_val=1.0, fake_label_val=0), data_preprocessor=DataPreprocessor( mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], )) # build restorer model = MODELS.build(model_cfg) # test attributes assert isinstance(model, TTSR) assert isinstance(model.generator, TTSRNet) assert isinstance(model.discriminator, TTSRDiscriminator) assert isinstance(model.transformer, SearchTransformer) assert isinstance(model.extractor, LTE) assert isinstance(model.pixel_loss, L1Loss) assert isinstance(model.transferal_perceptual_loss, TransferalPerceptualLoss) assert isinstance(model.gan_loss, GANLoss) optimizer_g = Adam( model.generator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optimizer_d = Adam( model.discriminator.parameters(), lr=0.0001, betas=(0.9, 0.999)) optim_wrapper = dict( generator=OptimWrapper(optimizer_g), extractor=OptimWrapper(optimizer_g), discriminator=OptimWrapper(optimizer_d)) # prepare data inputs = torch.rand(1, 3, 32, 32) data_sample = DataSample( gt_img=torch.rand(3, 128, 128), ref_img=torch.rand(3, 128, 128), img_lq=torch.rand(3, 128, 128), ref_lq=torch.rand(3, 128, 128)) data = dict(inputs=inputs, data_samples=[data_sample]) # train log_vars = model.train_step(data, optim_wrapper) log_vars = model.train_step(data, optim_wrapper) assert isinstance(log_vars, dict) assert set(log_vars.keys()) == set([ 'loss_pix', 'loss_perceptual', 'loss_style', 'loss_transferal', 'loss_gan', 'loss_d_real', 'loss_d_fake' ]) # val output = model.val_step(data) assert output[0].output.pred_img.shape == (3, 128, 128) # feat stacked_data_sample = DataSample.stack([data_sample]) output = model( torch.rand(1, 3, 32, 32), stacked_data_sample, mode='tensor') assert output.shape == (1, 3, 128, 128) # reset mock to clear some memory usage init_weights.reset_mock() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ttsr/test_ttsr_disc.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models import TTSRDiscriminator @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_ttsr_dict(): net = TTSRDiscriminator(in_channels=3, in_size=160) # cpu inputs = torch.rand((2, 3, 160, 160)) output = net(inputs) assert output.shape == (2, 1) # gpu if torch.cuda.is_available(): net = net.cuda() output = net(inputs.cuda()) assert output.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_ttsr/test_ttsr_net.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.editors.ttsr.ttsr_net import (CSFI2, CSFI3, SFE, MergeFeatures) from mmagic.registry import MODELS @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_sfe(): inputs = torch.rand(2, 3, 48, 48) sfe = SFE(3, 64, 16, 1.) outputs = sfe(inputs) assert outputs.shape == (2, 64, 48, 48) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_csfi(): inputs1 = torch.rand(2, 16, 24, 24) inputs2 = torch.rand(2, 16, 48, 48) inputs4 = torch.rand(2, 16, 96, 96) csfi2 = CSFI2(mid_channels=16) out1, out2 = csfi2(inputs1, inputs2) assert out1.shape == (2, 16, 24, 24) assert out2.shape == (2, 16, 48, 48) csfi3 = CSFI3(mid_channels=16) out1, out2, out4 = csfi3(inputs1, inputs2, inputs4) assert out1.shape == (2, 16, 24, 24) assert out2.shape == (2, 16, 48, 48) assert out4.shape == (2, 16, 96, 96) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_merge_features(): inputs1 = torch.rand(2, 16, 24, 24) inputs2 = torch.rand(2, 16, 48, 48) inputs4 = torch.rand(2, 16, 96, 96) merge_features = MergeFeatures(mid_channels=16, out_channels=3) out = merge_features(inputs1, inputs2, inputs4) assert out.shape == (2, 3, 96, 96) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_ttsr_net(): inputs = torch.rand(2, 3, 24, 24) soft_attention = torch.rand(2, 1, 24, 24) t_level3 = torch.rand(2, 64, 24, 24) t_level2 = torch.rand(2, 32, 48, 48) t_level1 = torch.rand(2, 16, 96, 96) ttsr_cfg = dict( type='TTSRNet', in_channels=3, out_channels=3, mid_channels=16, texture_channels=16) ttsr = MODELS.build(ttsr_cfg) outputs = ttsr(inputs, soft_attention, (t_level3, t_level2, t_level1)) assert outputs.shape == (2, 3, 96, 96) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_vico/test_vico.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import platform from unittest import TestCase from unittest.mock import MagicMock import pytest import torch import torch.nn as nn from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.registry import MODELS from mmagic.structures import DataSample from mmagic.utils import register_all_modules test_dir = osp.join(osp.dirname(__file__), '../../../..', 'tests') config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') model_path = osp.join(test_dir, 'configs', 'tmp_weight') ckpt_path = osp.join(test_dir, 'configs', 'ckpt') register_all_modules() stable_diffusion_tiny_url = 'diffusers/tiny-stable-diffusion-torch' val_prompts = ['a photo of S*'] image_cross_layers = [ # down blocks (2x transformer block) * (3x down blocks) = 6 0, 0, 0, 0, 0, 0, # mid block (1x transformer block) * (1x mid block)= 1 0, # up blocks (3x transformer block) * (3x up blocks) = 9 0, 1, 0, 1, 0, 1, 0, 1, 0, ] reg_loss_weight: float = 5e-4 placeholder: str = 'S*' initialize_token: str = 'dog' num_vectors_per_token: int = 1 config = dict( type='ViCo', vae=dict(type='AutoencoderKL', sample_size=64), unet=dict( sample_size=64, type='UNet2DConditionModel', down_block_types=('DownBlock2D', ), up_block_types=('UpBlock2D', ), block_out_channels=(32, ), cross_attention_dim=16, ), text_encoder=dict( type='ClipWrapper', clip_type='huggingface', pretrained_model_name_or_path=stable_diffusion_tiny_url, subfolder='text_encoder'), tokenizer=stable_diffusion_tiny_url, scheduler=dict( type='DDPMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), test_scheduler=dict( type='DDIMScheduler', from_pretrained=stable_diffusion_tiny_url, subfolder='scheduler'), dtype='fp32', data_preprocessor=dict(type='DataPreprocessor'), enable_xformers=False, image_cross_layers=image_cross_layers, reg_loss_weight=reg_loss_weight, placeholder=placeholder, initialize_token=initialize_token, num_vectors_per_token=num_vectors_per_token, val_prompts=val_prompts) @pytest.mark.skipif( 'win' in platform.system().lower() or digit_version(TORCH_VERSION) <= digit_version('1.8.1'), reason='skip on windows due to limited RAM' 'and get_submodule requires torch >= 1.9.0') class TestViCo(TestCase): def setUp(self): # mock SiLU if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): from mmagic.models.editors.ddpm.denoising_unet import SiLU torch.nn.SiLU = SiLU vico = MODELS.build(config) assert not any([p.requires_grad for p in vico.vae.parameters()]) self.vico = vico def test_infer(self): vico = self.vico def mock_encode_prompt(prompt, do_classifier_free_guidance, num_images_per_prompt, *args, **kwargs): batch_size = len(prompt) if isinstance(prompt, list) else 1 batch_size *= num_images_per_prompt if do_classifier_free_guidance: batch_size *= 2 return torch.randn(batch_size, 5, 16) # 2 for cfg def mock_infer(prompt, *args, **kwargs): length = len(prompt) return dict(samples=torch.randn(length, 3, 64, 64)) encode_prompt = vico._encode_prompt infer = vico.infer vico._encode_prompt = mock_encode_prompt vico.infer = mock_infer self._test_infer(vico, 1, 1) vico._encode_prompt = encode_prompt vico.infer = infer def _test_infer(self, vico, num_prompt, num_repeat): prompt = '' image_reference = torch.ones([1, 3, 64, 64]) result = vico.infer( [prompt] * num_prompt, image_reference=image_reference, height=64, width=64, num_images_per_prompt=num_repeat, num_inference_steps=1, return_type='numpy') assert result['samples'].shape == (1, 3, 64, 64) def test_val_step(self): vico = self.vico data = dict( inputs=[ dict( img=torch.ones([3, 64, 64]), img_ref=torch.ones([3, 64, 64])) ], data_samples=[DataSample(prompt='a photo of S*')]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(prompt, image_reference, *args, **kwargs): length = len(prompt) return dict(samples=torch.randn(length, 3, 64, 64)) encode_prompt = vico._encode_prompt infer = vico.infer vico._encode_prompt = mock_encode_prompt vico.infer = mock_infer output = vico.val_step(data) assert len(output) == 1 vico._encode_prompt = encode_prompt vico.infer = infer def test_test_step(self): vico = self.vico data = dict( inputs=[ dict( img=torch.ones([3, 64, 64]), img_ref=torch.ones([3, 64, 64])) ], data_samples=[DataSample(prompt='a photo of S*')]) def mock_encode_prompt(*args, **kwargs): return torch.randn(2, 5, 16) # 2 for cfg def mock_infer(prompt, image_reference, *args, **kwargs): length = len(prompt) return dict(samples=torch.randn(length, 3, 64, 64)) encode_prompt = vico._encode_prompt infer = vico.infer vico._encode_prompt = mock_encode_prompt vico.infer = mock_infer output = vico.test_step(data) assert len(output) == 1 vico._encode_prompt = encode_prompt vico.infer = infer def test_train_step(self): vico = self.vico data = dict( inputs=[ dict( img=torch.ones([3, 64, 64]), img_ref=torch.ones([3, 64, 64])) ], data_samples=[DataSample(prompt='a photo of S*')]) optimizer = MagicMock() update_params = MagicMock() optimizer.update_params = update_params optim_wrapper = optimizer class mock_text_encoder(nn.Module): def __init__(self): super().__init__() def forward(self, *args, **kwargs): return [torch.randn(1, 5, 16)] vico.text_encoder = mock_text_encoder() vico.train_step(data, optim_wrapper) ================================================ FILE: tests/test_models/test_editors/test_vico/test_vico_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest from diffusers.models.unet_2d_condition import UNet2DConditionModel from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.editors.vico.vico_utils import set_vico_modules @pytest.mark.skipif( 'win' in platform.system().lower() or digit_version(TORCH_VERSION) <= digit_version('1.8.1'), reason='skip on windows due to limited RAM' 'and get_submodule requires torch >= 1.9.0') def test_set_vico_modules(): model = UNet2DConditionModel() image_cross_layers = [1] * 16 set_vico_modules(model, image_cross_layers) # test set vico modules for name, layer in model.named_modules(): if len(name.split('.')) > 1: module_name = name.split('.')[-2] if module_name == 'attentions': assert layer.__class__.__name__ == 'ViCoTransformer2D' assert hasattr(layer, 'image_cross_attention') ================================================ FILE: tests/test_models/test_editors/test_wgan_gp/test_wgan_discriminator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.wgan_gp import WGANGPDiscriminator from mmagic.registry import MODELS class TestWGANGPDiscriminator(object): @classmethod def setup_class(cls): cls.x = torch.randn((2, 3, 128, 128)) cls.default_config = dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128) cls.conv_ln_module_config = dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='LN2d'), order=('conv', 'norm', 'act')) cls.conv_gn_module_config = dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='GN'), order=('conv', 'norm', 'act')) def test_wgangp_discriminator(self): # test default setting with builder d = MODELS.build(self.default_config) assert isinstance(d, WGANGPDiscriminator) score = d(self.x) assert score.shape == (2, 1) # test different in_scale config = dict(type='WGANGPDiscriminator', in_channel=3, in_scale=64) d = MODELS.build(config) assert isinstance(d, WGANGPDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x) assert score.shape == (2, 1) # test different conv config config = dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128, conv_module_cfg=self.conv_ln_module_config) d = MODELS.build(config) assert isinstance(d, WGANGPDiscriminator) score = d(self.x) assert score.shape == (2, 1) config = dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128, conv_module_cfg=self.conv_gn_module_config) d = MODELS.build(config) assert isinstance(d, WGANGPDiscriminator) score = d(self.x) assert score.shape == (2, 1) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_wgangp_discriminator_cuda(self): # test default setting with builder d = MODELS.build(self.default_config).cuda() assert isinstance(d, WGANGPDiscriminator) score = d(self.x.cuda()) assert score.shape == (2, 1) # test different in_scale config = dict(type='WGANGPDiscriminator', in_channel=3, in_scale=64) d = MODELS.build(config).cuda() assert isinstance(d, WGANGPDiscriminator) x = torch.randn((2, 3, 64, 64)) score = d(x.cuda()) assert score.shape == (2, 1) # test different conv config config = dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128, conv_module_cfg=self.conv_ln_module_config) d = MODELS.build(config).cuda() assert isinstance(d, WGANGPDiscriminator) score = d(self.x.cuda()) assert score.shape == (2, 1) config = dict( type='WGANGPDiscriminator', in_channel=3, in_scale=128, conv_module_cfg=self.conv_gn_module_config) d = MODELS.build(config).cuda() assert isinstance(d, WGANGPDiscriminator) score = d(self.x.cuda()) assert score.shape == (2, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_wgan_gp/test_wgan_generator.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.editors.wgan_gp import WGANGPGenerator from mmagic.registry import MODELS class TestWGANGPGenerator(object): @classmethod def setup_class(cls): cls.noise = torch.randn((2, 100)) cls.default_config = dict( type='WGANGPGenerator', noise_size=128, out_scale=128) def test_wgangp_generator(self): # test default setting with builder g = MODELS.build(self.default_config) assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) # test different out_scale config = dict(type='WGANGPGenerator', noise_size=128, out_scale=64) g = MODELS.build(config) assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 64, 64) # test different conv config config = dict( type='WGANGPGenerator', noise_size=128, out_scale=128, conv_module_cfg=dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='BN'), order=('conv', 'norm', 'act'))) g = MODELS.build(config) assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_wgangp_generator_cuda(self): # test default setting with builder g = MODELS.build(self.default_config).cuda() assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) # test different out_scale config = dict(type='WGANGPGenerator', noise_size=128, out_scale=64) g = MODELS.build(config).cuda() assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 64, 64) # test different conv config config = dict( type='WGANGPGenerator', noise_size=128, out_scale=128, conv_module_cfg=dict( conv_cfg=None, kernel_size=3, stride=1, padding=1, bias=True, act_cfg=dict(type='LeakyReLU', negative_slope=0.2), norm_cfg=dict(type='BN'), order=('conv', 'norm', 'act'))) g = MODELS.build(config).cuda() assert isinstance(g, WGANGPGenerator) x = g(None, num_batches=3) assert x.shape == (3, 3, 128, 128) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_wgan_gp/test_wgan_gp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from copy import deepcopy from unittest import TestCase import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict from torch.optim import SGD from mmagic.models import WGANGP, DataPreprocessor from mmagic.registry import MODELS from mmagic.structures import DataSample generator = dict( type='DCGANGenerator', noise_size=10, output_scale=16, base_channels=16) discriminator = dict( type='DCGANDiscriminator', input_scale=16, output_scale=4, out_channels=1) class TestWGANGP(TestCase): def test_init(self): gan = WGANGP( noise_size=10, data_preprocessor=DataPreprocessor(), generator=generator, discriminator=discriminator) self.assertIsInstance(gan, WGANGP) self.assertIsInstance(gan.data_preprocessor, DataPreprocessor) # test only generator have noise size gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 gan = WGANGP( generator=gen_cfg, discriminator=discriminator, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.noise_size, 10) # test init with nn.Module gen_cfg = deepcopy(generator) gen_cfg['noise_size'] = 10 disc_cfg = deepcopy(discriminator) gen = MODELS.build(gen_cfg) disc = MODELS.build(disc_cfg) gan = WGANGP( generator=gen, discriminator=disc, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.generator, gen) self.assertEqual(gan.discriminator, disc) # test init without discriminator gan = WGANGP(generator=gen, data_preprocessor=DataPreprocessor()) self.assertEqual(gan.discriminator, None) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_train_step(self): # prepare model accu_iter = 1 n_disc = 1 message_hub = MessageHub.get_instance('test-wgangp') gan = WGANGP( noise_size=10, generator=generator, discriminator=discriminator, data_preprocessor=DataPreprocessor(), discriminator_steps=n_disc) # prepare messageHub message_hub.update_info('iter', 0) # prepare optimizer gen_optim = SGD(gan.generator.parameters(), lr=0.1) disc_optim = SGD(gan.discriminator.parameters(), lr=0.1) optim_wrapper_dict = OptimWrapperDict( generator=OptimWrapper(gen_optim, accumulative_counts=accu_iter), discriminator=OptimWrapper( disc_optim, accumulative_counts=accu_iter)) # prepare inputs img = torch.randn(3, 16, 16) data = dict(inputs=dict(), data_samples=[DataSample(gt_img=img)]) # simulate train_loop here for idx in range(n_disc * accu_iter): message_hub.update_info('iter', idx) log = gan.train_step(data, optim_wrapper_dict) if (idx + 1) == n_disc * accu_iter: # should update at after (n_disc * accu_iter) self.assertEqual( set(log.keys()), set([ 'loss', 'loss_disc_fake', 'loss_disc_real', 'loss_gen', 'loss_gp' ])) else: # should not update when discriminator's updating is unfinished self.assertEqual( log.keys(), set(['loss', 'loss', 'loss_disc_fake', 'loss_disc_real'])) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_editors/test_wgan_gp/test_wgan_gp_module.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.editors.wgan_gp.wgan_gp_module import (ConvLNModule, WGANDecisionHead, WGANNoiseTo2DFeat) def test_ConvLNModule(): # test norm_cfg is None conv = ConvLNModule(3, 6, 3, 1, 1) assert conv.norm is None def test_WGANDecisionHead(): head = WGANDecisionHead(3, 8, 4) x = torch.randn(1, 3, 4, 4) out = head(x) assert out.shape == (1, 4) def test_WGANNoiseTo2DFeat(): noise2feat = WGANNoiseTo2DFeat(16, 32) noise = torch.randn(1, 16) feat = noise2feat(noise) assert feat.shape == (1, 32, 4, 4) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_clip_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import clip import pytest import torch from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.losses import CLIPLoss @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0'), reason='version limitation') def test_clip_loss(): clip_loss = CLIPLoss(clip_model=dict(in_size=32, clip_type='RN50')) image = torch.randn(1, 3, 32, 32) text = 'Image for test' text_inputs = torch.cat([clip.tokenize(text)]) loss = clip_loss(image, text_inputs) print(loss) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_composition_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import numpy.testing as npt import pytest import torch from mmagic.models import (CharbonnierCompLoss, L1CompositionLoss, MSECompositionLoss) def test_composition_losses(): with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported L1CompositionLoss(reduction='InvalidValue') with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported MSECompositionLoss(reduction='InvalidValue') with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported CharbonnierCompLoss(reduction='InvalidValue') unknown_h, unknown_w = (32, 32) weight = torch.zeros(1, 1, 64, 64) weight[0, 0, :unknown_h, :unknown_w] = 1 pred_alpha = weight.clone() * 0.5 ori_merged = torch.ones(1, 3, 64, 64) fg = torch.zeros(1, 3, 64, 64) bg = torch.ones(1, 3, 64, 64) * 4 l1_comp_loss = L1CompositionLoss(loss_weight=1.0, reduction='mean') loss = l1_comp_loss(pred_alpha, fg, bg, ori_merged) assert loss.shape == () assert loss.item() == 2.5 l1_comp_loss = L1CompositionLoss(loss_weight=0.5, reduction='none') loss = l1_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == (1, 3, 64, 64) assert (loss == torch.ones(1, 3, 64, 64) * weight * 0.5).all() l1_comp_loss = L1CompositionLoss(loss_weight=0.5, reduction='sum') loss = l1_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == () assert loss.item() == 1536 mse_comp_loss = MSECompositionLoss(loss_weight=1.0, reduction='mean') loss = mse_comp_loss(pred_alpha, fg, bg, ori_merged) assert loss.shape == () assert loss.item() == 7.0 mse_comp_loss = MSECompositionLoss(loss_weight=0.5, reduction='none') loss = mse_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == (1, 3, 64, 64) assert (loss == torch.ones(1, 3, 64, 64) * weight * 0.5).all() mse_comp_loss = MSECompositionLoss(loss_weight=0.5, reduction='sum') loss = mse_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == () assert loss.item() == 1536 cb_comp_loss = CharbonnierCompLoss( loss_weight=1.0, reduction='mean', eps=1e-12) loss = cb_comp_loss(pred_alpha, fg, bg, ori_merged) assert loss.shape == () assert loss.item() == 2.5 cb_comp_loss = CharbonnierCompLoss( loss_weight=0.5, reduction='none', eps=1e-6) loss = cb_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == (1, 3, 64, 64) npt.assert_almost_equal( loss.numpy(), torch.ones(1, 3, 64, 64) * weight * 0.5, decimal=6) cb_comp_loss = CharbonnierCompLoss( loss_weight=0.5, reduction='sum', eps=1e-6) loss = cb_comp_loss(pred_alpha, fg, bg, ori_merged, weight) assert loss.shape == () assert math.isclose(loss.item(), 1536, rel_tol=1e-6) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_face_id_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.losses import FaceIdLoss @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_face_id_loss(): face_id_loss = FaceIdLoss(loss_weight=2.5) assert face_id_loss.loss_weight == 2.5 gt, pred = torch.randn(1, 3, 224, 224), torch.randn(1, 3, 224, 224) loss = face_id_loss(pred, gt) assert loss.shape == () def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_feature_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models.losses import LightCNNFeatureLoss @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_light_cnn_feature_loss(): pretrained = 'https://download.openmmlab.com/mmediting/' + \ 'restorers/dic/light_cnn_feature.pth' pred = torch.rand((3, 3, 128, 128)) gt = torch.rand((3, 3, 128, 128)) feature_loss = LightCNNFeatureLoss(pretrained=pretrained) loss = feature_loss(pred, gt) assert loss.item() > 0 feature_loss = LightCNNFeatureLoss(pretrained=pretrained, criterion='mse') loss = feature_loss(pred, gt) assert loss.item() > 0 if torch.cuda.is_available(): pred = pred.cuda() gt = gt.cuda() feature_loss = feature_loss.cuda() pred.requires_grad = True loss = feature_loss(pred, gt) assert loss.item() > 0 optim = torch.optim.SGD(params=[pred], lr=10) optim.zero_grad() loss.backward() optim.step() loss_new = feature_loss(pred, gt) assert loss_new < loss feature_loss = LightCNNFeatureLoss( pretrained=pretrained, criterion='mse').cuda() loss = feature_loss(pred, gt) assert loss.item() > 0 # test criterion value error with pytest.raises(ValueError): LightCNNFeatureLoss(pretrained=pretrained, criterion='l2') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_gan_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy import numpy.testing as npt import pytest import torch from mmagic.models import GANLoss, GaussianBlur def test_gan_losses(): """Test gan losses.""" with pytest.raises(NotImplementedError): GANLoss( 'xixihaha', loss_weight=1.0, real_label_val=1.0, fake_label_val=0.0) input_1 = torch.ones(1, 1) input_2 = torch.ones(1, 3, 6, 6) * 2 # vanilla gan_loss = GANLoss( 'vanilla', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_1, True, is_disc=False) npt.assert_almost_equal(loss.item(), 0.6265233) loss = gan_loss(input_1, False, is_disc=False) npt.assert_almost_equal(loss.item(), 2.6265232) loss = gan_loss(input_1, True, is_disc=True) npt.assert_almost_equal(loss.item(), 0.3132616) loss = gan_loss(input_1, False, is_disc=True) npt.assert_almost_equal(loss.item(), 1.3132616) # lsgan gan_loss = GANLoss( 'lsgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), 2.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), 8.0) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), 1.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 4.0) # wgan gan_loss = GANLoss( 'wgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), 4) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), -2.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 2.0) # hinge gan_loss = GANLoss( 'hinge', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), 0.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 3.0) # smgan mask = torch.ones(1, 3, 6, 6) gan_loss = GANLoss( 'smgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False, mask=mask) npt.assert_almost_equal(loss.item(), 2.0) loss = gan_loss(input_2, False, is_disc=False, mask=mask) npt.assert_almost_equal(loss.item(), 8.0) loss = gan_loss(input_2, True, is_disc=True, mask=mask) npt.assert_almost_equal(loss.item(), 1.0) loss = gan_loss(input_2, False, is_disc=True, mask=mask) npt.assert_almost_equal(loss.item(), 3.786323, decimal=6) mask = torch.ones(1, 3, 6, 5) loss = gan_loss(input_2, True, is_disc=False, mask=mask) npt.assert_almost_equal(loss.item(), 2.0) if torch.cuda.is_available(): input_2 = input_2.cuda() mask = torch.ones(1, 3, 6, 6).cuda() gan_loss = GANLoss( 'smgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False, mask=mask) npt.assert_almost_equal(loss.item(), 2.0) loss = gan_loss(input_2, False, is_disc=False, mask=mask) npt.assert_almost_equal(loss.item(), 8.0) loss = gan_loss(input_2, True, is_disc=True, mask=mask) npt.assert_almost_equal(loss.item(), 1.0) loss = gan_loss(input_2, False, is_disc=True, mask=mask) npt.assert_almost_equal(loss.item(), 3.786323, decimal=6) # test GaussianBlur for smgan with pytest.raises(TypeError): gausian_blur = GaussianBlur(kernel_size=71, sigma=2) gausian_blur(mask).detach().cpu() with pytest.raises(TypeError): gausian_blur = GaussianBlur(kernel_size=(70, 70)) gausian_blur(mask).detach().cpu() with pytest.raises(TypeError): mask = numpy.ones((1, 3, 6, 6)) gausian_blur = GaussianBlur() gausian_blur(mask).detach().cpu() with pytest.raises(ValueError): mask = torch.ones(1, 3) gausian_blur = GaussianBlur() gausian_blur(mask).detach().cpu() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_gradient_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy.testing as npt import pytest import torch from mmagic.models import DiscShiftLoss, GradientLoss, GradientPenaltyLoss def test_gradient_loss(): with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported GradientLoss(reduction='InvalidValue') unknown_h, unknown_w = (32, 32) weight = torch.zeros(1, 1, 64, 64) weight[0, 0, :unknown_h, :unknown_w] = 1 pred = weight.clone() target = weight.clone() * 2 gradient_loss = GradientLoss(loss_weight=1.0, reduction='mean') loss = gradient_loss(pred, target) assert loss.shape == () npt.assert_almost_equal(loss.item(), 0.1860352) gradient_loss = GradientLoss(loss_weight=0.5, reduction='none') loss = gradient_loss(pred, target, weight) assert loss.shape == (1, 1, 64, 64) npt.assert_almost_equal(torch.sum(loss).item(), 252) gradient_loss = GradientLoss(loss_weight=0.5, reduction='sum') loss = gradient_loss(pred, target, weight) assert loss.shape == () npt.assert_almost_equal(loss.item(), 252) def test_gradient_penalty_losses(): """Test gradient penalty losses.""" input = torch.ones(1, 3, 6, 6) * 2 gan_loss = GradientPenaltyLoss(loss_weight=10.0) loss = gan_loss(lambda x: x, input, input, mask=None) assert loss.item() > 0 mask = torch.ones(1, 3, 6, 6) mask[:, :, 2:4, 2:4] = 0 loss = gan_loss(lambda x: x, input, input, mask=mask) assert loss.item() > 0 def test_disc_shift_loss(): loss_disc_shift = DiscShiftLoss() x = torch.Tensor([0.1]) loss = loss_disc_shift(x) npt.assert_almost_equal(loss.item(), 0.001) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_comps/test_clip_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import clip import pytest import torch from mmengine.utils import digit_version from mmengine.utils.dl_utils import TORCH_VERSION from mmagic.models.losses import CLIPLossComps @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0'), reason='version limitation') def test_clip_loss(): clip_loss_comps = CLIPLossComps( clip_model=dict(in_size=32), data_info=dict(image='fake_imgs', text='descriptions')) image = torch.randn(1, 3, 32, 32) text = 'Image for test' text_inputs = torch.cat([clip.tokenize(text)]) data_dict = dict(fake_imgs=image, descriptions=text_inputs) loss = clip_loss_comps(outputs_dict=data_dict) print(loss) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_comps/test_disc_auxiliary_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from functools import partial import pytest import torch from mmagic.models.editors.dcgan import DCGANDiscriminator from mmagic.models.editors.pggan import PGGANDiscriminator from mmagic.models.losses import (DiscShiftLossComps, GradientPenaltyLossComps, R1GradientPenaltyComps) from mmagic.models.losses.gan_loss import (gradient_penalty_loss, r1_gradient_penalty_loss) class TestDiscShiftLoss(object): @classmethod def setup_class(cls): cls.input_tensor = torch.randn((2, 10)) cls.default_cfg = dict( loss_weight=0.1, data_info=dict(pred='disc_pred')) cls.default_input_dict = dict(disc_pred=cls.input_tensor) def test_module_wrapper(self): # test with default config loss_module = DiscShiftLossComps(**self.default_cfg) loss = loss_module(self.default_input_dict) assert loss.ndim == 2 with pytest.raises(NotImplementedError): _ = loss_module(self.default_input_dict, 1) with pytest.raises(AssertionError): _ = loss_module(1, outputs_dict=self.default_input_dict) input_ = dict(outputs_dict=self.default_input_dict) loss = loss_module(**input_) assert loss.ndim == 2 with pytest.raises(AssertionError): _ = loss_module(self.input_tensor) # test without data_info loss_module = DiscShiftLossComps(data_info=None) loss = loss_module(self.input_tensor) assert loss.ndim == 2 class TestGradientPenalty: @classmethod def setup_class(cls): cls.input_img = torch.randn((2, 3, 8, 8)) cls.disc = DCGANDiscriminator( input_scale=8, output_scale=4, out_channels=5) cls.pggan_disc = PGGANDiscriminator( in_scale=8, base_channels=32, max_channels=32) cls.data_info = dict( discriminator='disc', real_data='real_imgs', fake_data='fake_imgs') def test_gp_loss(self): loss = gradient_penalty_loss(self.disc, self.input_img, self.input_img) assert loss > 0 loss = gradient_penalty_loss( self.disc, self.input_img, self.input_img, norm_mode='HWC') assert loss > 0 with pytest.raises(NotImplementedError): _ = gradient_penalty_loss( self.disc, self.input_img, self.input_img, norm_mode='xxx') loss = gradient_penalty_loss( self.disc, self.input_img, self.input_img, norm_mode='HWC') assert loss > 0 loss = gradient_penalty_loss( self.disc, self.input_img, self.input_img, norm_mode='HWC', mask=torch.ones_like(self.input_img)) assert loss > 0 data_dict = dict( real_imgs=self.input_img, fake_imgs=self.input_img, disc=partial(self.pggan_disc, transition_weight=0.5, curr_scale=8)) gp_loss = GradientPenaltyLossComps( loss_weight=10, norm_mode='pixel', data_info=self.data_info) loss = gp_loss(data_dict) assert loss > 0 loss = gp_loss(outputs_dict=data_dict) assert loss > 0 with pytest.raises(NotImplementedError): _ = gp_loss(asdf=1.) with pytest.raises(AssertionError): _ = gp_loss(1.) with pytest.raises(AssertionError): _ = gp_loss(1., 2, outputs_dict=data_dict) class TestR1GradientPenalty: @classmethod def setup_class(cls): cls.data_info = dict(discriminator='disc', real_data='real_imgs') cls.disc = DCGANDiscriminator( input_scale=8, output_scale=4, out_channels=5) cls.pggan_disc = PGGANDiscriminator( in_scale=8, base_channels=32, max_channels=32) cls.input_img = torch.randn((2, 3, 8, 8)) def test_r1_regularizer(self): loss = r1_gradient_penalty_loss(self.disc, self.input_img) assert loss > 0 loss = r1_gradient_penalty_loss( self.disc, self.input_img, norm_mode='HWC') assert loss > 0 with pytest.raises(NotImplementedError): _ = r1_gradient_penalty_loss( self.disc, self.input_img, norm_mode='xxx') loss = r1_gradient_penalty_loss( self.disc, self.input_img, norm_mode='HWC') assert loss > 0 loss = r1_gradient_penalty_loss( self.disc, self.input_img, norm_mode='HWC', mask=torch.ones_like(self.input_img)) assert loss > 0 data_dict = dict( real_imgs=self.input_img, disc=partial(self.pggan_disc, transition_weight=0.5, curr_scale=8)) gp_loss = R1GradientPenaltyComps( loss_weight=10, norm_mode='pixel', data_info=self.data_info) loss = gp_loss(data_dict) assert loss > 0 loss = gp_loss(outputs_dict=data_dict) assert loss > 0 with pytest.raises(NotImplementedError): _ = gp_loss(asdf=1.) with pytest.raises(AssertionError): _ = gp_loss(1.) with pytest.raises(AssertionError): _ = gp_loss(1., 2, outputs_dict=data_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_comps/test_face_id_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmagic.models import IDLossModel from mmagic.models.losses import FaceIdLossComps @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') def test_face_id_loss_comps(): face_id_loss_comps = FaceIdLossComps( loss_weight=2.5, data_info=dict(gt='real_imgs', pred='fake_imgs')) assert isinstance(face_id_loss_comps.net, IDLossModel) data_dict = dict( a=1, real_imgs=torch.randn(1, 3, 224, 224), fake_imgs=torch.randn(1, 3, 224, 224)) loss = face_id_loss_comps(outputs_dict=data_dict) assert loss.shape == () def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_comps/test_gan_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy.testing as npt import pytest import torch from mmagic.models.losses import GANLossComps def test_gan_losses(): """Test gan losses.""" with pytest.raises(NotImplementedError): GANLossComps( 'xixihaha', loss_weight=1.0, real_label_val=1.0, fake_label_val=0.0) input_1 = torch.ones(1, 1) input_2 = torch.ones(1, 3, 6, 6) * 2 # vanilla gan_loss = GANLossComps( 'vanilla', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_1, True, is_disc=False) npt.assert_almost_equal(loss.item(), 0.6265233) loss = gan_loss(input_1, False, is_disc=False) npt.assert_almost_equal(loss.item(), 2.6265232) loss = gan_loss(input_1, True, is_disc=True) npt.assert_almost_equal(loss.item(), 0.3132616) loss = gan_loss(input_1, False, is_disc=True) npt.assert_almost_equal(loss.item(), 1.3132616) # lsgan gan_loss = GANLossComps( 'lsgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), 2.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), 8.0) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), 1.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 4.0) # wgan gan_loss = GANLossComps( 'wgan', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), 4) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), -2.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 2.0) # wgan gan_loss = GANLossComps( 'wgan-logistic-ns', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) assert loss.item() > 0 loss = gan_loss(input_2, False, is_disc=False) assert loss.item() > 0 # hinge gan_loss = GANLossComps( 'hinge', loss_weight=2.0, real_label_val=1.0, fake_label_val=0.0) loss = gan_loss(input_2, True, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, False, is_disc=False) npt.assert_almost_equal(loss.item(), -4.0) loss = gan_loss(input_2, True, is_disc=True) npt.assert_almost_equal(loss.item(), 0.0) loss = gan_loss(input_2, False, is_disc=True) npt.assert_almost_equal(loss.item(), 3.0) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_comps/test_gen_auxiliary_loss_comps.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform import pytest import torch from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version from mmagic.models.editors.stylegan2 import StyleGAN2Generator from mmagic.models.losses import GeneratorPathRegularizerComps @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') class TestPathRegularizer: @classmethod def setup_class(cls): cls.data_info = dict(generator='generator', num_batches='num_batches') cls.gen = StyleGAN2Generator(32, 10, num_mlps=2) def test_path_regularizer_cpu(self): gen = self.gen output_dict = dict(generator=gen, num_batches=2) pl = GeneratorPathRegularizerComps(data_info=self.data_info) pl_loss = pl(output_dict) assert pl_loss > 0 output_dict = dict(generator=gen, num_batches=2, iteration=3) pl = GeneratorPathRegularizerComps( data_info=self.data_info, interval=2) pl_loss = pl(outputs_dict=output_dict) assert pl_loss is None with pytest.raises(NotImplementedError): _ = pl(asdf=1.) with pytest.raises(AssertionError): _ = pl(1.) with pytest.raises(AssertionError): _ = pl(1., 2, outputs_dict=output_dict) @pytest.mark.skipif( digit_version(TORCH_VERSION) <= digit_version('1.6.0'), reason='version limitation') @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') def test_path_regularizer_cuda(self): gen = self.gen.cuda() output_dict = dict(generator=gen, num_batches=2) pl = GeneratorPathRegularizerComps(data_info=self.data_info).cuda() pl_loss = pl(output_dict) assert pl_loss > 0 output_dict = dict(generator=gen, num_batches=2, iteration=3) pl = GeneratorPathRegularizerComps( data_info=self.data_info, interval=2).cuda() pl_loss = pl(outputs_dict=output_dict) assert pl_loss is None with pytest.raises(NotImplementedError): _ = pl(asdf=1.) with pytest.raises(AssertionError): _ = pl(1.) with pytest.raises(AssertionError): _ = pl(1., 2, outputs_dict=output_dict) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_loss_wrapper.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy.testing as npt import pytest import torch from mmagic.models import mask_reduce_loss, reduce_loss def test_utils(): loss = torch.rand(1, 3, 4, 4) weight = torch.zeros(1, 3, 4, 4) weight[:, :, :2, :2] = 1 # test reduce_loss() reduced = reduce_loss(loss, 'none') assert reduced is loss reduced = reduce_loss(loss, 'mean') npt.assert_almost_equal(reduced.numpy(), loss.mean()) reduced = reduce_loss(loss, 'sum') npt.assert_almost_equal(reduced.numpy(), loss.sum()) # test mask_reduce_loss() reduced = mask_reduce_loss(loss, weight=None, reduction='none') assert reduced is loss reduced = mask_reduce_loss(loss, weight=weight, reduction='mean') target = (loss * weight).sum(dim=[1, 2, 3]) / weight.sum(dim=[1, 2, 3]).mean() npt.assert_almost_equal(reduced.numpy(), target) reduced = mask_reduce_loss(loss, weight=weight, reduction='sum') npt.assert_almost_equal(reduced.numpy(), (loss * weight).sum()) weight_single_channel = weight[:, 0:1, ...] reduced = mask_reduce_loss( loss, weight=weight_single_channel, reduction='mean') target = (loss * weight).sum(dim=[1, 2, 3]) / weight.sum(dim=[1, 2, 3]).mean() npt.assert_almost_equal(reduced.numpy(), target) loss_b = torch.rand(2, 3, 4, 4) weight_b = torch.zeros(2, 1, 4, 4) weight_b[0, :, :3, :3] = 1 weight_b[1, :, :2, :2] = 1 reduced = mask_reduce_loss(loss_b, weight=weight_b, reduction='mean') target = (loss_b * weight_b).sum() / weight_b.sum() / 3. npt.assert_almost_equal(reduced.numpy(), target) with pytest.raises(AssertionError): weight_wrong = weight[0, 0, ...] reduced = mask_reduce_loss(loss, weight=weight_wrong, reduction='mean') with pytest.raises(AssertionError): weight_wrong = weight[:, 0:2, ...] reduced = mask_reduce_loss(loss, weight=weight_wrong, reduction='mean') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_perceptual_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import platform from unittest.mock import patch import pytest import torch from mmagic.models import (PerceptualLoss, PerceptualVGG, TransferalPerceptualLoss) @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') @patch.object(PerceptualVGG, 'init_weights') def test_perceptual_loss(init_weights): if torch.cuda.is_available(): loss_percep = PerceptualLoss(layer_weights={'0': 1.}).cuda() x = torch.randn(1, 3, 16, 16).cuda() x.requires_grad = True gt = torch.randn(1, 3, 16, 16).cuda() percep, style = loss_percep(x, gt) assert percep.item() > 0 assert style.item() > 0 optim = torch.optim.SGD(params=[x], lr=10) optim.zero_grad() percep.backward() optim.step() percep_new, _ = loss_percep(x, gt) assert percep_new < percep loss_percep = PerceptualLoss( layer_weights={ '0': 1. }, perceptual_weight=0.).cuda() x = torch.randn(1, 3, 16, 16).cuda() gt = torch.randn(1, 3, 16, 16).cuda() percep, style = loss_percep(x, gt) assert percep is None and style > 0 loss_percep = PerceptualLoss( layer_weights={ '0': 1. }, style_weight=0., criterion='mse').cuda() x = torch.randn(1, 3, 16, 16).cuda() gt = torch.randn(1, 3, 16, 16).cuda() percep, style = loss_percep(x, gt) assert style is None and percep > 0 loss_percep = PerceptualLoss( layer_weights={ '0': 1. }, layer_weights_style={ '1': 1. }).cuda() x = torch.randn(1, 3, 16, 16).cuda() gt = torch.randn(1, 3, 16, 16).cuda() percep, style = loss_percep(x, gt) assert percep > 0 and style > 0 # test whether vgg type is valid with pytest.raises(AssertionError): loss_percep = PerceptualLoss(layer_weights={'0': 1.}, vgg_type='igccc') # test whether criterion is valid with pytest.raises(NotImplementedError): loss_percep = PerceptualLoss( layer_weights={'0': 1.}, criterion='igccc') layer_name_list = ['2', '10', '30'] vgg_model = PerceptualVGG( layer_name_list, use_input_norm=False, vgg_type='vgg16', pretrained='torchvision://vgg16') x = torch.rand((1, 3, 32, 32)) output = vgg_model(x) assert isinstance(output, dict) assert len(output) == len(layer_name_list) assert set(output.keys()) == set(layer_name_list) # test whether the layer name is valid with pytest.raises(AssertionError): layer_name_list = ['2', '10', '30', '100'] vgg_model = PerceptualVGG( layer_name_list, use_input_norm=False, vgg_type='vgg16', pretrained='torchvision://vgg16') # reset mock to clear some memory usage init_weights.reset_mock() def test_t_perceptual_loss(): maps = [ torch.rand((2, 8, 8, 8), requires_grad=True), torch.rand((2, 4, 16, 16), requires_grad=True) ] textures = [torch.rand((2, 8, 8, 8)), torch.rand((2, 4, 16, 16))] soft = torch.rand((2, 1, 8, 8)) loss_t_percep = TransferalPerceptualLoss() t_percep = loss_t_percep(maps, soft, textures) assert t_percep.item() > 0 loss_t_percep = TransferalPerceptualLoss( use_attention=False, criterion='l1') t_percep = loss_t_percep(maps, soft, textures) assert t_percep.item() > 0 if torch.cuda.is_available(): maps = [ torch.rand((2, 8, 8, 8)).cuda(), torch.rand((2, 4, 16, 16)).cuda() ] textures = [ torch.rand((2, 8, 8, 8)).cuda(), torch.rand((2, 4, 16, 16)).cuda() ] soft = torch.rand((2, 1, 8, 8)).cuda() loss_t_percep = TransferalPerceptualLoss().cuda() maps[0].requires_grad = True maps[1].requires_grad = True t_percep = loss_t_percep(maps, soft, textures) assert t_percep.item() > 0 optim = torch.optim.SGD(params=maps, lr=10) optim.zero_grad() t_percep.backward() optim.step() t_percep_new = loss_t_percep(maps, soft, textures) assert t_percep_new < t_percep loss_t_percep = TransferalPerceptualLoss( use_attention=False, criterion='l1').cuda() t_percep = loss_t_percep(maps, soft, textures) assert t_percep.item() > 0 # test whether vgg type is valid with pytest.raises(ValueError): TransferalPerceptualLoss(criterion='l2') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_losses/test_pixelwise_loss.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import math import numpy.testing as npt import pytest import torch from mmagic.models import (CharbonnierLoss, L1Loss, MaskedTVLoss, MSELoss, PSNRLoss) def test_pixelwise_losses(): with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported L1Loss(reduction='InvalidValue') with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported MSELoss(reduction='InvalidValue') with pytest.raises(ValueError): # only 'none', 'mean' and 'sum' are supported CharbonnierLoss(reduction='InvalidValue') unknown_h, unknown_w = (32, 32) weight = torch.zeros(1, 1, 64, 64) weight[0, 0, :unknown_h, :unknown_w] = 1 pred = weight.clone() target = weight.clone() * 2 # test l1 loss l1_loss = L1Loss(loss_weight=1.0, reduction='mean') loss = l1_loss(pred, target) assert loss.shape == () assert loss.item() == 0.25 l1_loss = L1Loss(loss_weight=0.5, reduction='none') loss = l1_loss(pred, target, weight) assert loss.shape == (1, 1, 64, 64) assert (loss == torch.ones(1, 1, 64, 64) * weight * 0.5).all() l1_loss = L1Loss(loss_weight=0.5, reduction='sum') loss = l1_loss(pred, target, weight) assert loss.shape == () assert loss.item() == 512 # test mse loss mse_loss = MSELoss(loss_weight=1.0, reduction='mean') loss = mse_loss(pred, target) assert loss.shape == () assert loss.item() == 0.25 mse_loss = MSELoss(loss_weight=0.5, reduction='none') loss = mse_loss(pred, target, weight) assert loss.shape == (1, 1, 64, 64) assert (loss == torch.ones(1, 1, 64, 64) * weight * 0.5).all() mse_loss = MSELoss(loss_weight=0.5, reduction='sum') loss = mse_loss(pred, target, weight) assert loss.shape == () assert loss.item() == 512 # test charbonnier loss charbonnier_loss = CharbonnierLoss( loss_weight=1.0, reduction='mean', eps=1e-12) loss = charbonnier_loss(pred, target) assert loss.shape == () assert math.isclose(loss.item(), 0.25, rel_tol=1e-5) charbonnier_loss = CharbonnierLoss( loss_weight=0.5, reduction='none', eps=1e-6) loss = charbonnier_loss(pred, target, weight) assert loss.shape == (1, 1, 64, 64) npt.assert_almost_equal( loss.numpy(), torch.ones(1, 1, 64, 64) * weight * 0.5, decimal=6) charbonnier_loss = CharbonnierLoss( loss_weight=0.5, reduction='sum', eps=1e-12) loss = charbonnier_loss(pred, target) assert loss.shape == () assert math.isclose(loss.item(), 512, rel_tol=1e-5) # test samplewise option, use L1Loss as an example unknown_h, unknown_w = (32, 32) weight = torch.zeros(2, 1, 64, 64) weight[0, 0, :unknown_h, :unknown_w] = 1 # weight[1, 0, :unknown_h // 2, :unknown_w // 2] = 1 pred = weight.clone() target = weight.clone() # make mean l1_loss of sample 2 different from sample 1 target[0, ...] *= 2 l1_loss = L1Loss(loss_weight=1.0, reduction='mean', sample_wise=True) loss = l1_loss(pred, target, weight) assert loss.shape == () assert loss.item() == 0.5 masked_tv_loss = MaskedTVLoss(loss_weight=1.0) pred = torch.zeros((1, 1, 6, 6)) mask = torch.zeros_like(pred) mask[..., 2:4, 2:4] = 1. pred[..., 3, :] = 1. loss = masked_tv_loss(pred, mask) assert loss.shape == () npt.assert_almost_equal(loss.item(), 1.) # test PSNR Loss psnr_loss = PSNRLoss(loss_weight=1.0) pred = torch.ones(1, 1, 64, 64) target = torch.zeros(1, 1, 64, 64) loss = psnr_loss(pred, target) assert loss.shape == () assert loss.item() == 0.0 loss = psnr_loss(target, target) assert loss.item() == -80.0 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_utils/test_bbox_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.editors import PlainRefiner from mmagic.models.utils import extract_around_bbox, extract_bbox_patch def test_extract_bbox_patch(): img_np = np.random.randn(100, 100, 3) bbox = np.asarray([10, 10, 10, 10]) img_patch = extract_bbox_patch(bbox, img_np, channel_first=False) assert np.array_equal(img_patch, img_np[10:20, 10:20, ...]) img_np = np.random.randn(1, 3, 100, 100) bbox = np.asarray([[10, 10, 10, 10]]) img_patch = extract_bbox_patch(bbox, img_np) assert np.array_equal(img_patch, img_np[..., 10:20, 10:20]) img_tensor = torch.from_numpy(img_np) bbox = np.asarray([[10, 10, 10, 10]]) img_patch = extract_bbox_patch(bbox, img_tensor) assert np.array_equal(img_patch.numpy(), img_np[..., 10:20, 10:20]) with pytest.raises(AssertionError): img_np = np.random.randn(100, 100) bbox = np.asarray([[10, 10, 10, 10]]) img_patch = extract_bbox_patch(bbox, img_np) with pytest.raises(AssertionError): img_np = np.random.randn(2, 3, 100, 100) bbox = np.asarray([[10, 10, 10, 10]]) img_patch = extract_bbox_patch(bbox, img_np) with pytest.raises(AssertionError): img_np = np.random.randn(3, 100, 100) bbox = np.asarray([[10, 10, 10, 10]]) img_patch = extract_bbox_patch(bbox, img_np) def test_extract_around_bbox(): with pytest.raises(AssertionError): img_np = np.random.randn(100, 100, 3) bbox = np.asarray([10, 10, 10, 10]) extract_around_bbox(img_np, bbox, (4, 4)) with pytest.raises(TypeError): bbox = dict(test='fail') img_np = np.random.randn(100, 100, 3) extract_around_bbox(img_np, bbox, (15, 15)) img_np = np.random.randn(100, 100, 3) bbox = np.asarray([10, 10, 10, 10]) img_new, bbox_new = extract_around_bbox( img_np, bbox, (14, 14), channel_first=False) assert np.array_equal(img_np[8:22, 8:22, ...], img_new) assert np.array_equal(bbox_new, np.asarray([8, 8, 14, 14])) img_np = np.random.randn(1, 3, 100, 100) bbox = np.asarray([[10, 10, 10, 10]]) img_tensor = torch.from_numpy(img_np) bbox_tensor = torch.from_numpy(bbox) img_new, bbox_new = extract_around_bbox( img_tensor, bbox_tensor, target_size=[14, 14]) assert np.array_equal(img_np[..., 8:22, 8:22], img_new.numpy()) assert np.array_equal(bbox_new.numpy(), np.asarray([[8, 8, 14, 14]])) def assert_dict_keys_equal(dictionary, target_keys): """Check if the keys of the dictionary is equal to the target key set.""" assert isinstance(dictionary, dict) assert set(dictionary.keys()) == set(target_keys) def assert_tensor_with_shape(tensor, shape): """"Check if the shape of the tensor is equal to the target shape.""" assert isinstance(tensor, torch.Tensor) assert tensor.shape == shape def test_plain_refiner(): """Test PlainRefiner.""" model = PlainRefiner() model.init_weights() model.train() merged, alpha, trimap, raw_alpha = _demo_inputs_pair() prediction = model(torch.cat([merged, raw_alpha.sigmoid()], 1), raw_alpha) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) # test forward with gpu if torch.cuda.is_available(): model = PlainRefiner() model.init_weights() model.train() model.cuda() merged, alpha, trimap, raw_alpha = _demo_inputs_pair(cuda=True) prediction = model( torch.cat([merged, raw_alpha.sigmoid()], 1), raw_alpha) assert_tensor_with_shape(prediction, torch.Size([1, 1, 64, 64])) def _demo_inputs_pair(img_shape=(64, 64), batch_size=1, cuda=False): """Create a superset of inputs needed to run refiner. Args: img_shape (tuple): shape of the input image. batch_size (int): batch size of the input batch. cuda (bool): whether transfer input into gpu. """ color_shape = (batch_size, 3, img_shape[0], img_shape[1]) gray_shape = (batch_size, 1, img_shape[0], img_shape[1]) merged = torch.from_numpy(np.random.random(color_shape).astype(np.float32)) alpha = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) trimap = torch.from_numpy(np.random.random(gray_shape).astype(np.float32)) raw_alpha = torch.from_numpy( np.random.random(gray_shape).astype(np.float32)) if cuda: merged = merged.cuda() alpha = alpha.cuda() trimap = trimap.cuda() raw_alpha = raw_alpha.cuda() return merged, alpha, trimap, raw_alpha def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_utils/test_flow_warp.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import pytest import torch from mmagic.models.utils import flow_warp def tensor_shift(x, shift=(1, 1), fill_val=0): """Shift tensor for testing flow_warp. Args: x (Tensor): the input tensor. The shape is (b, c, h, w]. shift (tuple): shift pixel. fill_val (float): fill value. Returns: Tensor: the shifted tensor. """ _, _, h, w = x.size() shift_h, shift_w = shift new = torch.ones_like(x) * fill_val len_h = h - shift_h len_w = w - shift_w new[:, :, shift_h:shift_h + len_h, shift_w:shift_w + len_w] = x.narrow(2, 0, len_h).narrow(3, 0, len_w) return new def test_flow_warp(): x = torch.rand(1, 3, 10, 10) flow = torch.rand(1, 4, 4, 2) with pytest.raises(ValueError): # The spatial sizes of input and flow are not the same. flow_warp(x, flow) # cpu x = torch.rand(1, 3, 10, 10) flow = -torch.ones(1, 10, 10, 2) result = flow_warp(x, flow) assert result.size() == (1, 3, 10, 10) error = torch.sum(torch.abs(result - tensor_shift(x, (1, 1)))) assert error < 1e-5 # gpu if torch.cuda.is_available(): x = torch.rand(1, 3, 10, 10).cuda() flow = -torch.ones(1, 10, 10, 2).cuda() result = flow_warp(x, flow) assert result.size() == (1, 3, 10, 10) error = torch.sum(torch.abs(result - tensor_shift(x, (1, 1)))) assert error < 1e-5 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_utils/test_model_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import copy from collections import defaultdict import pytest import torch import torch.nn as nn from mmagic.models.utils import (build_module, generation_init_weights, get_module_device, get_valid_num_batches, set_requires_grad) from mmagic.registry import MODELS def test_generation_init_weights(): # Conv module = nn.Conv2d(3, 3, 1) module_tmp = copy.deepcopy(module) generation_init_weights(module, init_type='normal', init_gain=0.02) generation_init_weights(module, init_type='xavier', init_gain=0.02) generation_init_weights(module, init_type='kaiming') generation_init_weights(module, init_type='orthogonal', init_gain=0.02) with pytest.raises(NotImplementedError): generation_init_weights(module, init_type='abc') assert not torch.equal(module.weight.data, module_tmp.weight.data) # Linear module = nn.Linear(3, 1) module_tmp = copy.deepcopy(module) generation_init_weights(module, init_type='normal', init_gain=0.02) generation_init_weights(module, init_type='xavier', init_gain=0.02) generation_init_weights(module, init_type='kaiming') generation_init_weights(module, init_type='orthogonal', init_gain=0.02) with pytest.raises(NotImplementedError): generation_init_weights(module, init_type='abc') assert not torch.equal(module.weight.data, module_tmp.weight.data) # BatchNorm2d module = nn.BatchNorm2d(3) module_tmp = copy.deepcopy(module) generation_init_weights(module, init_type='normal', init_gain=0.02) assert not torch.equal(module.weight.data, module_tmp.weight.data) # test update init info module = nn.BatchNorm2d(3) module._params_init_info = defaultdict(dict) for name, param in module.named_parameters(): module._params_init_info[param][ 'init_info'] = f'The value is the same before and ' \ f'after calling `init_weights` ' \ f'of {module.__class__.__name__} ' module._params_init_info[param]['tmp_mean_value'] = param.data.mean( ).cpu() module_tmp = copy.deepcopy(module) generation_init_weights(module, init_type='normal', init_gain=0.02) assert not torch.equal(module.weight.data, module_tmp.weight.data) def test_set_requires_grad(): model = torch.nn.Conv2d(1, 3, 1, 1) set_requires_grad(model, False) for param in model.parameters(): assert not param.requires_grad def test_get_module_device_cpu(): device = get_module_device(nn.Conv2d(3, 3, 3, 1, 1)) assert device == torch.device('cpu') # The input module should contain parameters. with pytest.raises(ValueError): get_module_device(nn.Flatten()) def test_get_valid_num_batches(): # 1. batch inputs is Tensor assert get_valid_num_batches(torch.rand(5, 3, 4, 4)) == 5 # 2. batch inputs is dict batch_inputs = dict(num_batches=1, img=torch.randn(1, 3, 5, 5)) assert get_valid_num_batches(batch_inputs) == 1 # 3. batch inputs is dict but no tensor in it batch_inputs = dict(aaa='aaa', bbb='bbb') assert get_valid_num_batches(batch_inputs) == 1 # 4. test no batch input and no data samples assert get_valid_num_batches() == 1 # 5. test batch is None but data sample is not None data_samples = [None, None] assert get_valid_num_batches(None, data_samples) == 2 # 6. test batch input and data sample are neither not None batch_inputs = dict(num_batches=2, img=torch.randn(2, 3, 5, 5)) data_samples = [None, None] assert get_valid_num_batches(batch_inputs, data_samples) == 2 def test_build_module(): module = nn.Conv2d(3, 3, 3) assert build_module(module, MODELS) == module @MODELS.register_module() class MiniModule(nn.Module): def __init__(self, *args, **kwargs): super().__init__() for k, v in kwargs.items(): setattr(self, k, v) def forward(self, *args, **kwargs): return module_cfg = dict(type='MiniModule', attr1=1, attr2=2) module = build_module(module_cfg, MODELS) assert module.attr1 == 1 assert module.attr2 == 2 with pytest.raises(TypeError): build_module('MiniModule', MODELS) # remove the registered module MODELS._module_dict.pop('MiniModule') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_utils/test_sampling_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.models.utils.sampling_utils import label_sample_fn, noise_sample_fn def test_noise_sample_fn(): # test noise is a callable function noise_callable = torch.randn noise = noise_sample_fn(noise_callable, noise_size=(2, 3), device='cpu') assert noise.shape == (1, 2, 3) def test_label_sample_fn(): label = label_sample_fn(None, num_classes=-1) assert label is None label = label_sample_fn(None) assert label is None label_inp = torch.randint(0, 10, (1, )) assert (label_sample_fn(label_inp, num_classes=10) == label_inp).all() # np.ndarray input label_inp = np.array([3, 2, 1]) tar_label = torch.LongTensor([3, 2, 1]) assert (label_sample_fn(label_inp, num_classes=10, device='cpu') == tar_label).all() # list input label_inp = [0, 1, 1] tar_label = torch.LongTensor([0, 1, 1]) assert (label_sample_fn(label_inp, num_classes=10) == tar_label).all() label_inp = [np.array([0]), np.array([1]), np.array([0])] tar_label = torch.LongTensor([0, 1, 0]) assert (label_sample_fn(label_inp, num_classes=10) == tar_label).all() label_inp = [ torch.LongTensor([0]), torch.LongTensor([1]), torch.LongTensor([0]) ] tar_label = torch.LongTensor([0, 1, 0]) assert (label_sample_fn(label_inp, num_classes=10) == tar_label).all() # list input --> raise error label_inp = ['1', '2'] with pytest.raises(AssertionError): label_sample_fn(label_inp, num_classes=10) # callable input def label_function(num_batches): return torch.randint(0, 3, size=(num_batches, )) assert label_sample_fn(label_function, num_batches=3).shape == (3, ) # test raise error with pytest.raises(AssertionError): label_sample_fn(torch.randn(3, 3), num_classes=10) with pytest.raises(AssertionError): label_sample_fn(torch.randint(0, 3, (2, 2))) with pytest.raises(AssertionError): label_sample_fn([0, 10, 2, 3], num_classes=5) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_models/test_utils/test_tensor_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import torch from mmagic.models.utils.tensor_utils import get_unknown_tensor, normalize_vecs def test_tensor_utils(): input = torch.rand((2, 3, 128, 128)) output = get_unknown_tensor(input) assert output.detach().numpy().shape == (2, 1, 128, 128) input = torch.rand((2, 1, 128, 128)) output = get_unknown_tensor(input) assert output.detach().numpy().shape == (2, 1, 128, 128) def test_normalize_vector(): inp = torch.randn(4, 10) out = normalize_vecs(inp) def l2_norm(a): return a / torch.norm(a, dim=1, keepdim=True) l2_norm_out = l2_norm(inp) assert (out == l2_norm_out).all() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_structures/test_data_sample.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest import TestCase import numpy as np import torch from mmengine.structures import LabelData from mmengine.testing import assert_allclose from mmagic.structures import DataSample from mmagic.structures.data_sample import is_splitable_var def test_is_stacked_var(): assert is_splitable_var(DataSample()) assert is_splitable_var(torch.randn(10, 10)) assert is_splitable_var(np.ndarray((10, 10))) assert is_splitable_var([1, 2]) assert is_splitable_var((1, 2)) assert not is_splitable_var({'a': 1}) assert not is_splitable_var('a') class TestDataSample(TestCase): def test_init(self): meta_info = dict( target_size=[256, 256], scale_factor=np.array([1.5, 1.5]), img_shape=torch.rand(4)) data_sample = DataSample(metainfo=meta_info) assert 'target_size' in data_sample assert data_sample.target_size == [256, 256] assert data_sample.get('target_size') == [256, 256] assert len(data_sample) == 1 def _check_in_and_same(self, data_sample, field, value, is_meta=False): if is_meta: self.assertIn(field, data_sample.metainfo) else: self.assertIn(field, data_sample) if is_meta: val_in_data = data_sample.metainfo[field] else: val_in_data = getattr(data_sample, field) if isinstance(value, str): self.assertEqual(val_in_data, value) else: assert_allclose(val_in_data, value) def test_set_prefined_data(self): """Test fields mapping in this unit test.""" # DATA gt, gt_label = torch.randn(3, 256, 256), torch.randint(0, 2, (1, )) fg, bg = torch.randn(3, 256, 256), torch.randn(3, 256, 256) alpha = torch.randn(3, 256, 256) ref, ref_lq = torch.randn(3, 256, 256), torch.randn(3, 256, 256) # METAINFO img_path, gt_path, merged_path = 'aaa', 'bbb', 'ccc' gt_channel_order, gt_color_type = 'rgb', 'color' prompt = 'prompt' latent = torch.randn(1, 16, 512) feats = torch.randn(64, 256, 256) data = dict( gt=gt, gt_label=gt_label, fg=fg, bg=bg, alpha=alpha, ref=ref, ref_lq=ref_lq, img_path=img_path, gt_path=gt_path, merged_path=merged_path, gt_channel_order=gt_channel_order, gt_color_type=gt_color_type, prompt=prompt, latent=latent, feats=feats) data_sample = DataSample() data_sample.set_predefined_data(data) self._check_in_and_same(data_sample, 'gt_img', gt) self._check_in_and_same(data_sample, 'gt_fg', fg) self._check_in_and_same(data_sample, 'gt_bg', bg) self._check_in_and_same(data_sample, 'gt_alpha', alpha) self._check_in_and_same(data_sample, 'ref_img', ref) self._check_in_and_same(data_sample, 'ref_lq', ref_lq) self._check_in_and_same(data_sample, 'img_path', img_path, True) self._check_in_and_same(data_sample, 'gt_path', gt_path, True) self._check_in_and_same(data_sample, 'merged_path', merged_path, True) self._check_in_and_same(data_sample, 'gt_channel_order', gt_channel_order, True) self._check_in_and_same(data_sample, 'gt_color_type', gt_color_type, True) self._check_in_and_same(data_sample, 'prompt', prompt, False) self._check_in_and_same(data_sample, 'latent', latent) self._check_in_and_same(data_sample, 'feats', feats) # check gt label data_sample.gt_label.data = gt_label def _test_set_label(self, key): data_sample = DataSample() method = getattr(data_sample, 'set_' + key) # Test number method(1) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertIsInstance(label.label, torch.LongTensor) # Test tensor with single number method(torch.tensor(2)) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertIsInstance(label.label, torch.LongTensor) # Test array with single number method(np.array(3)) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertIsInstance(label.label, torch.LongTensor) # Test tensor method(torch.tensor([1, 2, 3])) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertIsInstance(label.label, torch.Tensor) self.assertTrue((label.label == torch.tensor([1, 2, 3])).all()) # Test array method(np.array([1, 2, 3])) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertTrue((label.label == torch.tensor([1, 2, 3])).all()) # Test Sequence method([1, 2, 3]) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertTrue((label.label == torch.tensor([1, 2, 3])).all()) # Test Sequence with float number method([0.2, 0, 0.8]) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertTrue((label.label == torch.tensor([0.2, 0, 0.8])).all()) # Test unavailable type with self.assertRaisesRegex(TypeError, " is not"): method('hi') # Test set num_classes data_sample = DataSample(metainfo={'num_classes': 10}) method = getattr(data_sample, 'set_' + key) method(5) self.assertIn(key, data_sample) label = getattr(data_sample, key) self.assertIsInstance(label, LabelData) self.assertIn('num_classes', label) self.assertEqual(label.num_classes, 10) # Test unavailable label with self.assertRaisesRegex(ValueError, r'data .*[15].* should '): method(15) def test_set_gt_label(self): self._test_set_label('gt_label') def test_del_gt_label(self): data_sample = DataSample() self.assertNotIn('gt_label', data_sample) data_sample.set_gt_label(1) self.assertIn('gt_label', data_sample) del data_sample.gt_label self.assertNotIn('gt_label', data_sample) def test_stack_and_split(self): # test stack data_sample1 = DataSample() data_sample1.set_gt_label(1) data_sample1.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample1.set_data({'mode': 'a'}) data_sample1.set_data({'prompt': 'I\'m a prompt!'}) data_sample1.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' }) data_sample2 = DataSample() data_sample2.set_gt_label(2) data_sample2.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample2.set_data({'mode': 'b'}) data_sample2.set_data({'prompt': 'I\'m an another prompt!'}) data_sample2.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' }) data_sample_merged = DataSample.stack([data_sample1, data_sample2]) assert (data_sample_merged.img == torch.stack( [data_sample1.img, data_sample2.img])).all() assert (data_sample_merged.gt_label.label == torch.LongTensor( [[1], [2]])).all() assert data_sample_merged.mode == ['a', 'b'] assert data_sample_merged.metainfo == dict( channel_order=['rgb', 'rgb'], color_flag=['color', 'color']) assert len(data_sample_merged) == 2 assert data_sample_merged.prompt == [ 'I\'m a prompt!', 'I\'m an another prompt!' ] # test split data_sample_merged.sample_model = 'ema' data_sample_merged.fake_img = DataSample(img=torch.randn(2, 3, 4, 4)) data_splited_1, data_splited_2 = data_sample_merged.split(True) assert (data_splited_1.gt_label.label == 1).all() assert (data_splited_2.gt_label.label == 2).all() assert (data_splited_1.img.shape == data_sample1.img.shape) assert (data_splited_2.img.shape == data_sample2.img.shape) assert (data_splited_1.img == data_sample1.img).all() assert (data_splited_2.img == data_sample2.img).all() assert (data_splited_1.metainfo == dict( channel_order='rgb', color_flag='color')) assert (data_splited_2.metainfo == dict( channel_order='rgb', color_flag='color')) assert data_splited_1.sample_model == 'ema' assert data_splited_2.sample_model == 'ema' assert data_splited_1.fake_img.img.shape == (3, 4, 4) assert data_splited_2.fake_img.img.shape == (3, 4, 4) assert data_splited_1.prompt == 'I\'m a prompt!' assert data_splited_2.prompt == 'I\'m an another prompt!' with self.assertRaises(TypeError): data_sample_merged.split() # test stack and split when batch size is 1 data_sample = DataSample() data_sample.set_gt_label(3) data_sample.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample.set_data({'mode': 'c'}) data_sample.set_data({'prompt': 'proooommmmpt'}) data_sample.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' }) data_sample_merged = DataSample.stack([data_sample]) assert (data_sample_merged.img == torch.stack([data_sample.img])).all() assert (data_sample_merged.gt_label.label == torch.LongTensor( [[3]])).all() assert data_sample_merged.mode == ['c'] assert data_sample_merged.metainfo == dict( channel_order=['rgb'], color_flag=['color']) data_sample_merged.prompt == ['proooommmmpt'] assert len(data_sample_merged) == 1 # test split data_splited = data_sample_merged.split() assert len(data_splited) == 1 data_splited = data_splited[0] assert (data_splited.gt_label.label == 3).all() assert (data_splited.img == data_sample.img).all() assert data_splited.prompt == 'proooommmmpt' assert (data_splited.metainfo == dict( channel_order='rgb', color_flag='color')) def test_len(self): empty_data = DataSample(sample_kwargs={'a': 'a'}) assert len(empty_data) == 1 empty_data = DataSample() assert len(empty_data) == 1 empty_data = DataSample( img=torch.randn(3, 3), metainfo=dict(img_shape=[3, 3])) assert len(empty_data) == 1 def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_cli.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import sys from mmagic.utils import modify_args def test_modify_args(): sys.argv = ['test.py', '--arg_1=1', '--arg-2=2'] modify_args() def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_img_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import pytest import torch from mmagic.utils import (all_to_tensor, can_convert_to_image, tensor2img, to_numpy) def test_all_to_tensor(): data = [np.random.rand(64, 64, 3), np.random.rand(64, 64, 3)] tensor = all_to_tensor(data) assert tensor.shape == torch.Size([2, 3, 64, 64]) data = np.random.rand(64, 64, 3) tensor = all_to_tensor(data) assert tensor.shape == torch.Size([3, 64, 64]) data = 1 tensor = all_to_tensor(data) assert tensor == torch.tensor(1) def test_can_convert_to_image(): values = [ np.random.rand(64, 64, 3), [np.random.rand(64, 61, 3), np.random.rand(64, 61, 3)], (64, 64), 'b' ] targets = [True, True, False, False] for val, tar in zip(values, targets): assert can_convert_to_image(val) == tar def test_tensor2img(): input = torch.rand(1, 3, 8, 8) result = tensor2img(input) assert result.shape == (8, 8, 3) input = torch.rand(1, 1, 8, 8) result = tensor2img(input) assert result.shape == (8, 8) input = torch.rand(4, 3, 8, 8) result = tensor2img(input) assert result.shape == (22, 22, 3) input = [torch.rand(1, 3, 8, 8), torch.rand(1, 3, 8, 8)] result = tensor2img(input) assert len(result) == len(input) for r in result: assert r.shape == (8, 8, 3) with pytest.raises(TypeError): tensor2img('wrong type') with pytest.raises(ValueError): tensor2img([torch.randn(2, 3, 4, 4, 4) for _ in range(2)]) def test_to_numpy(): input = torch.rand(1, 3, 8, 8) output = to_numpy(input) assert isinstance(output, np.ndarray) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_io_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.utils.io_utils import download_from_url def test_download_from_url(): # test to download a small file dest_path = download_from_url( 'https://download.openmmlab.com/mmgen/dataset/singan/balloons.png', dest_path='./') print(dest_path) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_logger.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.utils import print_colored_log def test_print_colored_log(): print_colored_log('Test print_colored_log info.') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_sampler.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from unittest.mock import MagicMock from torch.utils.data import DataLoader from mmagic.utils.sampler import ArgumentsSampler, ValDataSampler def test_argument_sampler(): sample_kwargs = dict( a=1, b=2, max_times=10, num_batches=2, forward_kwargs=dict(forward_mode='gen')) sampler = ArgumentsSampler(sample_kwargs=sample_kwargs, ) assert sampler.max_times == 10 for sample in sampler: assert 'inputs' in sample assert sample['inputs'] == dict(forward_mode='gen', num_batches=2) class MockDataset(): def __init__(self, length): self.length = length def __getitem__(self, idx): return idx def __len__(self): return self.length class MockValLoop(): def __init__(self): self.dataloaders = None def test_val_data_sampler(): runner = MagicMock() val_loop = MockValLoop() val_loop.dataloaders = [ DataLoader(MockDataset(10), batch_size=4), DataLoader(MockDataset(5), batch_size=4) ] # val_loop.dataloader = None runner.val_loop = val_loop val_sampler = ValDataSampler( sample_kwargs=dict(max_times=10), runner=runner) assert len(val_sampler._dataloader.dataset) == 15 tar_out = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1], [2, 3, 4]] for idx, out in enumerate(val_sampler): assert out == tar_out[idx] setattr(val_loop, 'dataloader', DataLoader(MockDataset(8), batch_size=4)) val_sampler = ValDataSampler( sample_kwargs=dict(max_times=10), runner=runner) assert len(val_sampler._dataloader.dataset) == 8 for idx, out in enumerate(val_sampler): assert out == tar_out[idx] # test iteration times val_sampler = ValDataSampler( sample_kwargs=dict(max_times=1), runner=runner) tar_out = [[0, 1, 2, 3]] for idx, out in enumerate(val_sampler): assert out == tar_out[idx] def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_setup_env.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from mmagic.utils import register_all_modules, try_import def test_register_all_modules(): register_all_modules() def test_try_import(): import numpy as np assert try_import('numpy') is np assert try_import('numpy111') is None def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_utils/test_trans_utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. from pathlib import Path import numpy as np import pytest from mmagic.datasets.transforms import (CropAroundCenter, CropAroundFg, CropAroundUnknown, LoadImageFromFile) from mmagic.utils import (adjust_gamma, bbox2mask, brush_stroke_mask, get_irregular_mask, random_bbox) dtype_range = { np.bool_: (False, True), np.bool8: (False, True), np.float16: (-1, 1), np.float32: (-1, 1), np.float64: (-1, 1) } class TestCrop: @classmethod def setup_class(cls): """Check the dimension of gray scale images read by LoadImageFromFile.""" image_loader = LoadImageFromFile(key='img') path_alpha = Path( __file__ ).parent.parent / 'data' / 'matting_dataset' / 'alpha' / 'GT05.jpg' # noqa: E501 result = image_loader({'img_path': path_alpha}) if result['img'].ndim == 3: cls.ext_dim = (1, ) elif result['img'].ndim == 2: cls.ext_dim = () else: raise ValueError('invalid ndim') @classmethod def check_ndim(cls, result_img_shape): if cls.ext_dim: return len(result_img_shape) == 3 else: return not (len(result_img_shape.ndim) == 3 and result_img_shape[-1] == 1) @classmethod def check_crop(cls, result_img_shape, result_bbox): crop_w = result_bbox[2] - result_bbox[0] """Check if the result_bbox is in correspond to result_img_shape.""" crop_h = result_bbox[3] - result_bbox[1] crop_shape = (crop_h, crop_w) return result_img_shape[:2] == crop_shape @staticmethod def check_crop_around_semi(alpha): return ((alpha > 0) & (alpha < 255)).any() @staticmethod def check_keys_contain(result_keys, target_keys): """Check if all elements in target_keys is in result_keys.""" return set(target_keys).issubset(set(result_keys)) def test_crop_around_center(self): with pytest.raises(TypeError): CropAroundCenter(320.) with pytest.raises(AssertionError): CropAroundCenter((320, 320, 320)) target_keys = ['fg', 'bg', 'alpha', 'trimap', 'crop_bbox'] fg = np.random.rand(240, 320, 3) bg = np.random.rand(240, 320, 3) trimap = np.random.rand(240, 320, *self.ext_dim) alpha = np.random.rand(240, 320, *self.ext_dim) # make sure there would be semi-transparent area trimap[128, 128] = 128 results = dict(fg=fg, bg=bg, trimap=trimap, alpha=alpha) crop_around_center = CropAroundCenter( crop_size=330) # this will trigger rescale crop_around_center_results = crop_around_center(results) assert self.check_keys_contain(crop_around_center_results.keys(), target_keys) assert self.check_ndim(crop_around_center_results['alpha'].shape) assert self.check_ndim(crop_around_center_results['trimap'].shape) assert self.check_crop(crop_around_center_results['alpha'].shape, crop_around_center_results['crop_bbox']) assert self.check_crop_around_semi(crop_around_center_results['alpha']) # make sure there would be semi-transparent area trimap[:, :] = 128 results = dict(fg=fg, bg=bg, trimap=trimap, alpha=alpha) crop_around_center = CropAroundCenter(crop_size=200) crop_around_center_results = crop_around_center(results) assert self.check_keys_contain(crop_around_center_results.keys(), target_keys) assert self.check_ndim(crop_around_center_results['alpha'].shape) assert self.check_ndim(crop_around_center_results['trimap'].shape) assert self.check_crop(crop_around_center_results['alpha'].shape, crop_around_center_results['crop_bbox']) assert self.check_crop_around_semi(crop_around_center_results['alpha']) repr_str = crop_around_center.__class__.__name__ + ( f'(crop_size={(200, 200)})') assert repr(crop_around_center) == repr_str def test_crop_around_fg(self): with pytest.raises(ValueError): # keys must contain 'seg' CropAroundFg(['fg', 'bg']) with pytest.raises(TypeError): # bd_ratio_range must be a tuple of 2 float CropAroundFg(['seg', 'merged'], bd_ratio_range=0.1) keys = ['bg', 'merged', 'seg'] target_keys = ['bg', 'merged', 'seg', 'crop_bbox'] bg = np.random.rand(60, 60, 3) merged = np.random.rand(60, 60, 3) seg = np.random.rand(60, 60) results = dict(bg=bg, merged=merged, seg=seg) crop_around_fg = CropAroundFg(keys) crop_around_fg_results = crop_around_fg(results) assert self.check_keys_contain(crop_around_fg_results.keys(), target_keys) assert self.check_crop(crop_around_fg_results['seg'].shape, crop_around_fg_results['crop_bbox']) crop_around_fg = CropAroundFg(keys, test_mode=True) crop_around_fg_results = crop_around_fg(results) result_img_shape = crop_around_fg_results['seg'].shape assert self.check_keys_contain(crop_around_fg_results.keys(), target_keys) assert self.check_crop(result_img_shape, crop_around_fg_results['crop_bbox']) # it should be a square in test mode assert result_img_shape[0] == result_img_shape[1] def test_crop_around_unknown(self): with pytest.raises(ValueError): # keys must contain 'alpha' CropAroundUnknown(['fg', 'bg'], [320]) with pytest.raises(TypeError): # crop_size must be a list CropAroundUnknown(['alpha'], 320) with pytest.raises(TypeError): # crop_size must be a list of int CropAroundUnknown(['alpha'], [320.]) with pytest.raises(ValueError): # unknown_source must be either 'alpha' or 'trimap' CropAroundUnknown(['alpha', 'fg'], [320], unknown_source='fg') with pytest.raises(ValueError): # if unknown_source is 'trimap', then keys must contain it CropAroundUnknown(['alpha', 'fg'], [320], unknown_source='trimap') keys = ['fg', 'bg', 'merged', 'alpha', 'trimap', 'ori_merged'] target_keys = [ 'fg', 'bg', 'merged', 'alpha', 'trimap', 'ori_merged', 'crop_bbox' ] # test cropping using trimap to decide unknown area fg = np.random.rand(240, 320, 3) bg = np.random.rand(240, 320, 3) merged = np.random.rand(240, 320, 3) ori_merged = merged.copy() alpha = np.zeros((240, 320, *self.ext_dim)) # make sure there would be unknown area alpha[:16, -16:] = 128 trimap = np.zeros_like(alpha) trimap[alpha > 0] = 128 trimap[alpha == 255] = 255 results = dict( fg=fg, bg=bg, merged=merged, ori_merged=ori_merged, alpha=alpha, trimap=trimap) crop_around_semi_trans = CropAroundUnknown( keys, crop_sizes=[320], unknown_source='trimap') crop_around_semi_trans_results = crop_around_semi_trans(results) assert self.check_keys_contain(crop_around_semi_trans_results.keys(), target_keys) assert self.check_ndim(crop_around_semi_trans_results['alpha'].shape) assert self.check_ndim(crop_around_semi_trans_results['trimap'].shape) assert self.check_crop(crop_around_semi_trans_results['alpha'].shape, crop_around_semi_trans_results['crop_bbox']) assert self.check_crop_around_semi( crop_around_semi_trans_results['alpha']) keys = ['fg', 'bg', 'merged', 'alpha', 'ori_merged'] target_keys = [ 'fg', 'bg', 'merged', 'alpha', 'ori_merged', 'crop_bbox' ] # test cropping using alpha to decide unknown area fg = np.random.rand(240, 320, 3) bg = np.random.rand(240, 320, 3) merged = np.random.rand(240, 320, 3) ori_merged = merged.copy() alpha = np.random.rand(240, 320, *self.ext_dim) # make sure there would be unknown area alpha[120:160, 120:160] = 128 results = dict( fg=fg, bg=bg, merged=merged, ori_merged=ori_merged, alpha=alpha) crop_around_semi_trans = CropAroundUnknown( keys, crop_sizes=[160], unknown_source='alpha') crop_around_semi_trans_results = crop_around_semi_trans(results) assert self.check_keys_contain(crop_around_semi_trans_results.keys(), target_keys) assert self.check_ndim(crop_around_semi_trans_results['alpha'].shape) assert self.check_crop(crop_around_semi_trans_results['alpha'].shape, crop_around_semi_trans_results['crop_bbox']) assert self.check_crop_around_semi( crop_around_semi_trans_results['alpha']) # test cropping when there is no unknown area fg = np.random.rand(240, 320, 3) bg = np.random.rand(240, 320, 3) merged = np.random.rand(240, 320, 3) ori_merged = merged.copy() alpha = np.zeros((240, 320, *self.ext_dim)) results = dict( fg=fg, bg=bg, merged=merged, ori_merged=ori_merged, alpha=alpha) crop_around_semi_trans = CropAroundUnknown( keys, crop_sizes=[240], unknown_source='alpha') crop_around_semi_trans_results = crop_around_semi_trans(results) assert self.check_keys_contain(crop_around_semi_trans_results.keys(), target_keys) assert self.check_ndim(crop_around_semi_trans_results['alpha'].shape) assert self.check_crop(crop_around_semi_trans_results['alpha'].shape, crop_around_semi_trans_results['crop_bbox']) repr_str = ( crop_around_semi_trans.__class__.__name__ + f"(keys={keys}, crop_sizes={[(240, 240)]}, unknown_source='alpha'," " interpolations=['bilinear', 'bilinear', 'bilinear', 'bilinear', " "'bilinear'])") assert crop_around_semi_trans.__repr__() == repr_str def test_adjust_gamma(): """Test Gamma Correction. Adpted from # https://github.com/scikit-image/scikit-image/blob/7e4840bd9439d1dfb6beaf549998452c99f97fdd/skimage/exposure/tests/test_exposure.py#L534 # noqa """ # Check that the shape is maintained. img = np.ones([1, 1]) result = adjust_gamma(img, 1.5) assert img.shape == result.shape # Same image should be returned for gamma equal to one. image = np.random.uniform(0, 255, (8, 8)) result = adjust_gamma(image, 1) np.testing.assert_array_equal(result, image) # White image should be returned for gamma equal to zero. image = np.random.uniform(0, 255, (8, 8)) result = adjust_gamma(image, 0) dtype = image.dtype.type np.testing.assert_array_equal(result, dtype_range[dtype][1]) # Verifying the output with expected results for gamma # correction with gamma equal to half. image = np.arange(0, 255, 4, np.uint8).reshape((8, 8)) expected = np.array([[0, 31, 45, 55, 63, 71, 78, 84], [90, 95, 100, 105, 110, 115, 119, 123], [127, 131, 135, 139, 142, 146, 149, 153], [156, 159, 162, 165, 168, 171, 174, 177], [180, 183, 186, 188, 191, 194, 196, 199], [201, 204, 206, 209, 211, 214, 216, 218], [221, 223, 225, 228, 230, 232, 234, 236], [238, 241, 243, 245, 247, 249, 251, 253]], dtype=np.uint8) result = adjust_gamma(image, 0.5) np.testing.assert_array_equal(result, expected) # Verifying the output with expected results for gamma # correction with gamma equal to two. image = np.arange(0, 255, 4, np.uint8).reshape((8, 8)) expected = np.array([[0, 0, 0, 0, 1, 1, 2, 3], [4, 5, 6, 7, 9, 10, 12, 14], [16, 18, 20, 22, 25, 27, 30, 33], [36, 39, 42, 45, 49, 52, 56, 60], [64, 68, 72, 76, 81, 85, 90, 95], [100, 105, 110, 116, 121, 127, 132, 138], [144, 150, 156, 163, 169, 176, 182, 189], [196, 203, 211, 218, 225, 233, 241, 249]], dtype=np.uint8) result = adjust_gamma(image, 2) np.testing.assert_array_equal(result, expected) # Test invalid image input image = np.arange(0, 255, 4, np.uint8).reshape((8, 8)) with pytest.raises(ValueError): adjust_gamma(image, -1) def test_bbox_mask(): # default config for random bbox mask cfg = dict( img_shape=(256, 256), max_bbox_shape=100, max_bbox_delta=10, min_margin=10) bbox = random_bbox(**cfg) mask_bbox = bbox2mask(cfg['img_shape'], bbox) assert mask_bbox.shape == (256, 256, 1) zero_area = np.sum((mask_bbox == 0).astype(np.uint8)) ones_area = np.sum((mask_bbox == 1).astype(np.uint8)) assert zero_area + ones_area == 256 * 256 assert mask_bbox.dtype == np.uint8 with pytest.raises(ValueError): cfg_ = cfg.copy() cfg_['max_bbox_shape'] = 300 bbox = random_bbox(**cfg_) with pytest.raises(ValueError): cfg_ = cfg.copy() cfg_['max_bbox_delta'] = 300 bbox = random_bbox(**cfg_) with pytest.raises(ValueError): cfg_ = cfg.copy() cfg_['max_bbox_shape'] = 254 bbox = random_bbox(**cfg_) cfg_ = cfg.copy() cfg_['max_bbox_delta'] = 1 bbox = random_bbox(**cfg_) mask_bbox = bbox2mask(cfg['img_shape'], bbox) assert mask_bbox.shape == (256, 256, 1) def test_free_form_mask(): img_shape = (256, 256, 3) for _ in range(10): mask = brush_stroke_mask(img_shape) assert mask.shape == (256, 256, 1) img_shape = (256, 256, 3) mask = brush_stroke_mask(img_shape, num_vertices=8) assert mask.shape == (256, 256, 1) zero_area = np.sum((mask == 0).astype(np.uint8)) ones_area = np.sum((mask == 1).astype(np.uint8)) assert zero_area + ones_area == 256 * 256 assert mask.dtype == np.uint8 img_shape = (256, 256, 3) mask = brush_stroke_mask(img_shape, brush_width=10) assert mask.shape == (256, 256, 1) with pytest.raises(TypeError): mask = brush_stroke_mask(img_shape, num_vertices=dict()) with pytest.raises(TypeError): mask = brush_stroke_mask(img_shape, brush_width=dict()) def test_irregular_mask(): img_shape = (256, 256) for _ in range(10): mask = get_irregular_mask(img_shape) assert mask.shape == (256, 256, 1) assert 0.15 < (np.sum(mask) / (img_shape[0] * img_shape[1])) < 0.50 zero_area = np.sum((mask == 0).astype(np.uint8)) ones_area = np.sum((mask == 1).astype(np.uint8)) assert zero_area + ones_area == 256 * 256 assert mask.dtype == np.uint8 with pytest.raises(TypeError): mask = get_irregular_mask(img_shape, brush_width=dict()) with pytest.raises(TypeError): mask = get_irregular_mask(img_shape, length_range=dict()) with pytest.raises(TypeError): mask = get_irregular_mask(img_shape, num_vertices=dict()) mask = get_irregular_mask(img_shape, brush_width=10) assert mask.shape == (256, 256, 1) mask = get_irregular_mask(img_shape, length_range=10) assert mask.shape == (256, 256, 1) mask = get_irregular_mask(img_shape, num_vertices=10) assert mask.shape == (256, 256, 1) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_visualization/test_concat_visualizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import mmcv import numpy as np import torch from mmagic.structures import DataSample from mmagic.visualization import ConcatImageVisualizer def test_concatimagevisualizer(): data_sample = DataSample( path_rgb='fake_dir/rgb.png', path_bgr='fake_dir/bgr.png', tensor3d=torch.ones(3, 32, 32) * torch.tensor([[[0.1]], [[0.2]], [[0.3]]]), array3d=np.ones(shape=(32, 32, 3)) * [0.4, 0.5, 0.6], tensor4d=torch.ones(2, 3, 32, 32) * torch.tensor( [[[[0.1]], [[0.2]], [[0.3]]], [[[0.4]], [[0.5]], [[0.6]]]]), ) vis = ConcatImageVisualizer( fn_key='path_rgb', img_keys=['tensor3d', 'array3d', 'tensor4d'], vis_backends=[dict(type='LocalVisBackend')], save_dir='work_dirs') vis.add_datasample(data_sample=data_sample, step=1) vis = ConcatImageVisualizer( fn_key='path_bgr', img_keys=['tensor3d', 'array3d', 'tensor4d'], vis_backends=[dict(type='LocalVisBackend')], save_dir='work_dirs', bgr2rgb=True) vis.add_datasample(data_sample=data_sample, step=2) for fn in 'rgb_1.png', 'bgr_2.png': img = mmcv.imread(f'work_dirs/vis_data/vis_image/{fn}') assert img.shape == (64, 16 * 3 * 2, 3) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_visualization/test_vis_backend.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import shutil import sys import time from unittest import TestCase from unittest.mock import MagicMock import numpy as np import torch from mmengine import Config, MessageHub from mmagic.visualization import (PaviVisBackend, TensorboardVisBackend, VisBackend, WandbVisBackend) class TestVisBackend(TestCase): def test_vis_backend(self): message_hub = MessageHub.get_instance('test-visbackend') config = Config(dict(work_dir='./mmagic/test/vis_backend_test/')) message_hub.update_info('cfg', config.pretty_text) data_root = 'tmp_dir' sys.modules['petrel_client'] = MagicMock() vis_backend = VisBackend(save_dir='tmp_dir', ceph_path='s3://xxx') self.assertEqual(vis_backend.experiment, vis_backend) # test path mapping src_path = osp.abspath( './mmagic/test/vis_backend_test/test_vis_data/test.png') tar_path = 's3://xxx/vis_backend_test/test_vis_data/test.png' file_client = vis_backend._file_client mapped_path = file_client._map_path(src_path) formatted_path = file_client._format_path(mapped_path) self.assertEqual(formatted_path, tar_path) # test with `delete_local` is True vis_backend.add_config(Config(dict(name='test'))) vis_backend.add_image( name='add_img', image=np.random.random((8, 8, 3)).astype(np.uint8)) vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3) # test with `delete_local` is False vis_backend._delete_local_image = False vis_backend.add_config(Config(dict(name='test'))) vis_backend.add_image( name='add_img', image=np.random.random((8, 8, 3)).astype(np.uint8)) vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3) vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3, file_path='new_scalar.json') self.assertTrue(osp.exists(osp.join(data_root, 'config.py'))) self.assertTrue( osp.exists(osp.join(data_root, 'vis_image', 'add_img_0.png'))) self.assertTrue(osp.exists(osp.join(data_root, 'new_scalar.json'))) self.assertTrue(osp.exists(osp.join(data_root, 'scalars.json'))) # test with `ceph_path` is None vis_backend = VisBackend(save_dir='tmp_dir') vis_backend.add_config(Config(dict(name='test'))) vis_backend.add_image( name='add_img', image=np.random.random((8, 8, 3)).astype(np.uint8)) vis_backend.add_scalar( name='scalar_tensor', value=torch.FloatTensor([0.693]), step=3) vis_backend.add_scalar(name='scalar', value=0.693, step=3) vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3) vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3, file_path='new_scalar.json') # raise error with self.assertRaises(AssertionError): vis_backend.add_scalars( scalar_dict=dict(lr=0.001), step=3, file_path='scalars.json') with self.assertRaises(AssertionError): vis_backend.add_scalars( scalar_dict=dict(lr=0.001), step=3, file_path='new_scalars') shutil.rmtree('tmp_dir') class TestTensorboardBackend(TestCase): def test_tensorboard(self): save_dir = 'tmp_dir' vis_backend = TensorboardVisBackend(save_dir) sys.modules['torch.utils.tensorboard'] = MagicMock() # add image vis_backend.add_image( name='add_img', image=np.random.random((8, 8, 3)).astype(np.uint8)) vis_backend.add_image( name='add_img', image=np.random.random((10, 8, 8, 3)).astype(np.uint8)) # add scalars vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3) class TestPaviBackend(TestCase): def test_pavi(self): save_dir = 'tmp_dir' exp_name = 'unit test' vis_backend = PaviVisBackend(save_dir=save_dir, exp_name=exp_name) with self.assertRaises(ImportError): vis_backend._init_env() sys.modules['pavi'] = MagicMock() vis_backend._init_env() exp = vis_backend.experiment self.assertEqual(exp, vis_backend._pavi) # add image vis_backend.add_image( name='add_img', image=np.random.random((8, 8, 3)).astype(np.uint8)) # add scalars vis_backend.add_scalars( scalar_dict=dict(lr=0.001, loss=torch.FloatTensor([0.693])), step=3) class TestWandbBackend(TestCase): def test_wandb(self): timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())) wandb_mock = MagicMock() sys.modules['wandb'] = wandb_mock vis_backend = WandbVisBackend( save_dir=f'parent_dir/exp_name/{timestamp}/vis_data', init_kwargs=dict(project='test_backend')) # test save gif image rgb_np = np.random.rand(11, 4, 4, 3).astype(np.uint8) vis_backend.add_image('test_gif', rgb_np, n_skip=2) vis_backend.add_image('test_gif', rgb_np, n_skip=1) # test save rgb image rgb_np = np.random.rand(4, 4, 3).astype(np.uint8) vis_backend.add_image('test_rgb', rgb_np) # test wandb backend with name wandb_mock.reset_mock() vis_backend = WandbVisBackend( save_dir=f'parent_dir/exp_name/{timestamp}/vis_data', init_kwargs=dict(project='test_backend', name='test_wandb')) vis_backend._init_env() _, called_kwargs = wandb_mock.init.call_args self.assertEqual(called_kwargs['name'], f'test_wandb_{timestamp}') def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tests/test_visualization/test_visualizer.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import shutil from unittest import TestCase import torch from mmagic.structures import DataSample from mmagic.utils import register_all_modules from mmagic.visualization import Visualizer register_all_modules() class TestGenVisualer(TestCase): def test_add_datasample(self): visualizer = Visualizer( save_dir='tmp_dir', vis_backends=[dict(type='VisBackend')]) img_root = osp.join('tmp_dir', 'vis_data', 'vis_image') # construct gen sample to vis gen_sample = [ DataSample( fake_img=torch.randn(3, 16, 16), gt_img=torch.randn(1, 16, 16), ema=DataSample(fake_img=torch.randn(10, 3, 16, 16)), gif=torch.randn(10, 3, 16, 16), something=DataSample( new=DataSample(img=torch.randn(3, 16, 16)))) for _ in range(3) ] visualizer.add_datasample( name='fake_img', gen_samples=gen_sample, target_mean=None, target_std=None, target_keys=['fake_img', 'gt_img'], step=0) osp.exists(osp.join(img_root, 'fake_img_0.png')) visualizer.add_datasample( name='target_is_none', gen_samples=gen_sample, target_mean=None, target_std=None, step=1) osp.exists(osp.join(img_root, 'target_is_none_1.png')) visualizer.add_datasample( name='target_is_none_gif', gen_samples=gen_sample, target_mean=None, target_std=None, vis_mode='gif', step=2) osp.exists(osp.join(img_root, 'target_is_none_gif_2.gif')) visualizer.add_datasample( name='something', gen_samples=gen_sample, n_row=3, target_keys='something.new', step=3) osp.exists(osp.join(img_root, 'something_3.png')) visualizer.add_datasample( name='ema_padding', gen_samples=gen_sample, n_row=2, color_order='rgb', target_keys='ema', vis_mode='gif', step=4) osp.exists(osp.join(img_root, 'emd_padding_4.gif')) visualizer.add_datasample( name='fake_img_padding', gen_samples=gen_sample, target_mean=None, target_std=None, target_keys=['fake_img', 'gt_img'], n_row=4, step=5) osp.exists(osp.join(img_root, 'fake_img_padding_5.png')) shutil.rmtree(img_root) def teardown_module(): import gc gc.collect() globals().clear() locals().clear() ================================================ FILE: tools/analysis_tools/get_flops.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import torch from mmengine import Config from mmengine.registry import init_default_scope from mmagic.registry import MODELS try: from mmengine.analysis import get_model_complexity_info except ImportError: raise ImportError('Please upgrade mmengine >= 0.6.0') def parse_args(): parser = argparse.ArgumentParser( description='Get a editor complexity', formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('config', help='train config file path') parser.add_argument( '--shape', type=int, nargs='+', default=[3, 250, 250], help='Input shape. Supported tasks:\n' 'Image Super-Resolution: --shape 3 h w\n' 'Video Super-Resolution: --shape t 3 h w\n' 'Video Interpolation: --shape t 3 h w\n' 'Image Restoration: --shape 3 h w\n' 'Inpainting: --shape 4 h w\n' 'Matting: --shape 4 h w\n' 'Unconditional GANs: --shape noisy_size\n' 'Image Translation: --shape 3 h w') parser.add_argument( '--activations', action='store_true', help='Whether to show the Activations') parser.add_argument( '--out-table', action='store_true', help='Whether to show the complexity table') parser.add_argument( '--out-arch', action='store_true', help='Whether to show the complexity arch') args = parser.parse_args() return args def main(): """ Examples: Image Super-Resolution: `python tools/analysis_tools/get_flops.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py --shape 3 250 250` # noqa Video Super-Resolution: `python tools/analysis_tools/get_flops.py configs/edvr/edvrm_8xb4-600k_reds.py --shape 5 3 256 256` # noqa Video Interpolation: `python tools/analysis_tools/get_flops.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py --shape 4 3 64 64` # noqa Image Restoration: `python tools/analysis_tools/get_flops.py configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py --shape 3 128 128` # noqa Inpainting: `python tools/analysis_tools/get_flops.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py --shape 4 64 64` # noqa Matting: `python tools/analysis_tools/get_flops.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py --shape 4 256 256` # noqa Unconditional GANs: `python tools/analysis_tools/get_flops.py configs/wgan-gp/wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py --shape 128` # noqa Image Translation: `python tools/analysis_tools/get_flops.py configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py --shape 3 250 250` """ args = parse_args() input_shape = tuple(args.shape) cfg = Config.fromfile(args.config) init_default_scope(cfg.get('default_scope', 'mmagic')) model = MODELS.build(cfg.model) inputs = torch.randn(1, *input_shape) if torch.cuda.is_available(): model.cuda() inputs = inputs.cuda() model.eval() if hasattr(model, 'generator'): model = model.generator elif hasattr(model, 'backbone'): model = model.backbone if hasattr(model, 'translation'): model.forward = model.translation elif hasattr(model, 'infer'): model.forward = model.infer analysis_results = get_model_complexity_info(model, inputs=inputs) flops = analysis_results['flops_str'] params = analysis_results['params_str'] activations = analysis_results['activations_str'] split_line = '=' * 30 print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}\n') if args.activations: print(f'Activations: {activations}\n{split_line}\n') if args.out_table: print(analysis_results['out_table'], '\n') if args.out_arch: print(analysis_results['out_arch'], '\n') if len(input_shape) == 4: print('!!!If your network computes N frames in one forward pass, you ' 'may want to divide the FLOPs by N to get the average FLOPs ' 'for each frame.') print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.') if __name__ == '__main__': main() ================================================ FILE: tools/analysis_tools/print_config.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse from mmengine import Config, DictAction def parse_args(): parser = argparse.ArgumentParser(description='Print the whole config') parser.add_argument('config', help='config file path') parser.add_argument( '--cfg-options', nargs='+', action=DictAction, help='override some settings in the used config, the key-value pair ' 'in xxx=yyy format will be merged into config file. If the value to ' 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 'Note that the quotation marks are necessary and that no white space ' 'is allowed.') args = parser.parse_args() return args def main(): args = parse_args() cfg = Config.fromfile(args.config) if args.cfg_options is not None: cfg.merge_from_dict(args.cfg_options) print(f'Config:\n{cfg.pretty_text}') if __name__ == '__main__': main() ================================================ FILE: tools/cpu_train.sh ================================================ #!/usr/bin/env bash CONFIG=$1 GPUS=$2 NNODES=${NNODES:-1} NODE_RANK=${NODE_RANK:-0} PORT=${PORT:-29500} MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ python $(dirname "$0")/train.py \ $CONFIG \ --launcher none ${@:3} ================================================ FILE: tools/dataset_converters/bgm/preprocess_bgm_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp from itertools import cycle import mmengine def generate_json(data_root, seg_root, bg_root, all_data): """Generate training json list for Background Matting video dataset. Args: data_root (str): Background Matting video data root. seg_root (str): Segmentation of Background Matting video data root. bg_root (str): Background video data root. all_data (bool): Whether use the last 80 frames of each video. If True, the last 80 frames will be added to training json. In the original Background Matting github repo, due to the use of motion cue, the last 80 frames is not used. """ # use fixed-camera data to train the Background Matting model video_root = osp.join(data_root, 'fixed-camera/train') if seg_root is None: seg_root = video_root if bg_root is None: bg_root = osp.join(data_root, 'background') video_dirs = [ entry for entry in os.listdir(video_root) if osp.isdir(osp.join(video_root, entry)) ] bg_dirs = [ entry for entry in os.listdir(bg_root) if osp.isdir(osp.join(bg_root, entry)) ] # create an iterator that loops over all the background video frames bg_frames = [] for bg_dir in bg_dirs: bg_frames.extend([ osp.join(bg_root, bg_dir, f) for f in sorted(mmengine.scandir(osp.join(bg_root, bg_dir))) ]) bg_stream = cycle(bg_frames) data_infos = [] for video_dir in video_dirs: video_full_path = osp.join(video_root, video_dir) seg_full_path = osp.join(seg_root, video_dir) num_frames = len( list(mmengine.scandir(video_full_path, suffix='_img.png'))) # In the original Background Matting github repo, the # last 80 frames is not used. effective_frames = num_frames if all_data else num_frames - 80 for i in range(1, effective_frames + 1): # Though it's not composited, to be consistent with adobe data, # we call the captured image `merged`. # Since background video may not be under the same directory as # the Background Matting video data, we use full path in Background # Matting dataset annotation file. merged = osp.join(video_full_path, f'{i:04d}_img.png') seg = osp.join(seg_full_path, f'{i:04d}_masksDL.png') bg = video_full_path + '.png' bg_sup = next(bg_stream) data_info = dict( merged_path=merged, seg_path=seg, bg_path=bg, bg_sup_path=bg_sup) data_infos.append(data_info) save_json_path = 'fixed_camera_train.json' mmengine.dump(data_infos, osp.join(data_root, save_json_path)) def parse_args(): parser = argparse.ArgumentParser( description='Prepare Background Matting video dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('data_root', help='Background Matting video data root') parser.add_argument( '--seg-root', help='Segmentation of Background Matting video data root. If not ' 'specified, it will be considered segmentation results are placed in ' 'the video frames folder just as the original repo.') parser.add_argument( '--bg-root', help='Background video data root. If not specified, it will use the ' 'three background videos in the Captured_Data folder.') parser.add_argument( '--all-data', action='store_true', help='Also use the last 80 frames of each video') return parser.parse_args() def main(): args = parse_args() if not osp.exists(args.data_root): raise FileNotFoundError(f'{args.data_root} does not exist!') print('generating Background Matting dataset annotation file...') generate_json(args.data_root, args.seg_root, args.bg_root, args.all_data) print('annotation file generated...') if __name__ == '__main__': main() ================================================ FILE: tools/dataset_converters/celeba-hq/README.md ================================================ # Preparing CelebA-HQ Dataset ```bibtex @article{karras2017progressive, title={Progressive growing of gans for improved quality, stability, and variation}, author={Karras, Tero and Aila, Timo and Laine, Samuli and Lehtinen, Jaakko}, journal={arXiv preprint arXiv:1710.10196}, year={2017} } ``` Follow the instructions [here](https://github.com/tkarras/progressive_growing_of_gans#preparing-datasets-for-training) to prepare the dataset. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── CelebA-HQ │ │ ├── train_256 | | ├── test_256 | | ├── train_celeba_img_list.txt | | ├── val_celeba_img_list.txt ``` ================================================ FILE: tools/dataset_converters/celeba-hq/README_zh-CN.md ================================================ # 准备 CelebA-HQ 数据集 ```bibtex @article{karras2017progressive, title={Progressive growing of gans for improved quality, stability, and variation}, author={Karras, Tero and Aila, Timo and Laine, Samuli and Lehtinen, Jaakko}, journal={arXiv preprint arXiv:1710.10196}, year={2017} } ``` 请按照[此处](https://github.com/tkarras/progressive_growing_of_gans#preparing-datasets-for-training)准备数据集。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── CelebA-HQ │ │ ├── train_256 | | ├── test_256 | | ├── train_celeba_img_list.txt | | ├── val_celeba_img_list.txt ``` ================================================ FILE: tools/dataset_converters/classic5/README.md ================================================ # Preparing Classic5 Dataset ```bibtex @article{zhang2017beyond, title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, journal={IEEE Transactions on Image Processing}, year={2017}, volume={26}, number={7}, pages={3142-3155}, } ``` The test datasets can be download from [here](https://github.com/cszn/DnCNN/tree/master/testsets). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── Classic5 ``` ================================================ FILE: tools/dataset_converters/classic5/README_zh-CN.md ================================================ # 准备 Classic5 数据集 ```bibtex @article{zhang2017beyond, title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, journal={IEEE Transactions on Image Processing}, year={2017}, volume={26}, number={7}, pages={3142-3155}, } ``` 测试数据集可以从 [此处](https://github.com/cszn/DnCNN/tree/master/testsets) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── Classic5 ``` ================================================ FILE: tools/dataset_converters/comp1k/README.md ================================================ # Preparing Composition-1k Dataset ## Introduction ```bibtex @inproceedings{xu2017deep, title={Deep image matting}, author={Xu, Ning and Price, Brian and Cohen, Scott and Huang, Thomas}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2970--2979}, year={2017} } ``` The Adobe Composition-1k dataset consists of foreground images and their corresponding alpha images. To get the full dataset, one need to composite the foregrounds with selected backgrounds from the COCO dataset and the Pascal VOC dataset. ## Obtain and Extract Please follow the instructions of [paper authors](https://sites.google.com/view/deepimagematting) to obtain the Composition-1k (comp1k) dataset. ## Composite the full dataset The Adobe composition-1k dataset contains only `alpha` and `fg` (and `trimap` in test set). It is needed to merge `fg` with COCO data (training) or VOC data (test) before training or evaluation. Use the following script to perform image composition and generate annotation files for training or testing: ```shell # The script is run under the root folder of MMagic python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --composite ``` The generated data is stored under `adobe_composition-1k/Training_set` and `adobe_composition-1k/Test_set` respectively. If you only want to composite test data (since compositing training data is time-consuming), you can skip compositing the training set by removing the `--composite` option: ```shell # skip compositing training set python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit ``` If you only want to preprocess test data, i.e. for FBA, you can skip the train set by adding the `--skip-train` option: ```shell # skip preprocessing training set python tools/data/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --skip-train ``` > Currently, `GCA` and `FBA` support online composition of training data. But you can modify the data pipeline of other models to perform online composition instead of loading composited images (we called it `merged` in our data pipeline). ## Check Directory Structure for DIM The result folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── adobe_composition-1k │ │ ├── Test_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── trimaps │ │ │ ├── merged (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── Training_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ ├── Other │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ ├── merged (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── test_list.json (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── training_list.json (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ ├── coco │ │ ├── train2014 (or train2017) │ ├── VOCdevkit │ │ ├── VOC2012 ``` ## Prepare the dataset for FBA FBA adopts dynamic dataset augmentation proposed in [Learning-base Sampling for Natural Image Matting](https://openaccess.thecvf.com/content_CVPR_2019/papers/Tang_Learning-Based_Sampling_for_Natural_Image_Matting_CVPR_2019_paper.pdf). In addition, to reduce artifacts during augmentation, it uses the extended version of foreground as foreground. We provide scripts to estimate foregrounds. Prepare the test set as follows: ```shell # skip preprocessing training set, as it composites online during training python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --skip-train ``` Extend the foreground of training set as follows: ```shell python tools/dataset_converters/matting/comp1k/extend_fg.py data/adobe_composition-1k ``` ## Check Directory Structure for DIM The final folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── adobe_composition-1k │ │ ├── Test_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── trimaps │ │ │ ├── merged (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── Training_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── fg_extended (generated by tools/data/matting/comp1k/extend_fg.py) │ │ │ ├── Other │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── fg_extended (generated by tools/data/matting/comp1k/extend_fg.py) │ │ ├── test_list.json (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── training_list_fba.json (generated by tools/data/matting/comp1k/extend_fg.py) │ ├── coco │ │ ├── train2014 (or train2017) │ ├── VOCdevkit │ │ ├── VOC2012 ``` ================================================ FILE: tools/dataset_converters/comp1k/README_zh-CN.md ================================================ # 准备 Composition-1k 数据集 ## 介绍 ```bibtex @inproceedings{xu2017deep, title={Deep image matting}, author={Xu, Ning and Price, Brian and Cohen, Scott and Huang, Thomas}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2970--2979}, year={2017} } ``` Adobe Composition-1k 数据集由前景图像及其相应的 alpha 图像组成。要获得完整的数据集,需要将前景与来自 COCO 数据集和 Pascal VOC 数据集的选定背景进行合成。 ## 获取和提取 请按照 [论文作者](https://sites.google.com/view/deepimagematting) 的说明获取 Composition-1k (comp1k) 数据集。 ## 合成完整数据集 Adobe composition-1k 数据集仅包含 `alpha` 和 `fg`(以及测试集中的 `trimap`)。在训练或评估之前,需要将 `fg` 与 COCO 数据(训练)或 VOC 数据(测试)合并。使用以下脚本执行图像合成并生成用于训练或测试的注释文件: ```shell # 在 MMagic 的根文件夹下运行脚本 python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --composite ``` 生成的数据分别存储在 “adobe_composition-1k/Training_set” 和 “adobe_composition-1k/Test_set” 下。如果你只想合成测试数据(因为合成训练数据很耗时),你可以通过删除 `--composite` 选项来跳过合成训练集: ```shell # 跳过合成训练集 python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit ``` 如果您只想预处理测试数据,即对于 FBA,您可以通过添加 `--skip-train` 选项来跳过训练集: ```shell # 跳过预处理训练集 python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --skip-train ``` > 目前,`GCA` 和 `FBA` 支持在线合成训练数据。但是你可以修改其他模型的数据管道来执行在线合成,而不是加载合成图像(我们在数据管道中称之为“合并”)。 ## 检查 DIM 的目录结构 最终的文件夹结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── adobe_composition-1k │ │ ├── Test_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── trimaps │ │ │ ├── merged (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── Training_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ ├── Other │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ ├── merged (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── test_list.json (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── training_list.json (generated by tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py) │ ├── coco │ │ ├── train2014 (or train2017) │ ├── VOCdevkit │ │ ├── VOC2012 ``` ## 为 FBA 准备数据集 FBA采用 [Learning-base Sampling for Natural Image Matting](https://openaccess.thecvf.com/content_CVPR_2019/papers/Tang_Learning-Based_Sampling_for_Natural_Image_Matting_CVPR_2019_paper.pdf) 中提出的动态数据集增强。此外,为了减少增强过程中的伪影,它使用前景的扩展版本作为前景。我们提供脚本来估计前景。 准备测试集: ```shell # 跳过预处理训练集,因为它在训练期间在线合成 python tools/dataset_converters/matting/comp1k/preprocess_comp1k_dataset.py data/adobe_composition-1k data/coco data/VOCdevkit --skip-train ``` 扩展训练集的前景: ```shell python tools/dataset_converters/matting/comp1k/extend_fg.py data/adobe_composition-1k ``` ## 检查 DIM 的目录结构 最终的文件夹结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── adobe_composition-1k │ │ ├── Test_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── trimaps │ │ │ ├── merged (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ │ ├── bg (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── Training_set │ │ │ ├── Adobe-licensed images │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── fg_extended (generated by tools/data/matting/comp1k/extend_fg.py) │ │ │ ├── Other │ │ │ │ ├── alpha │ │ │ │ ├── fg │ │ │ │ ├── fg_extended (generated by tools/data/matting/comp1k/extend_fg.py) │ │ ├── test_list.json (generated by tools/data/matting/comp1k/preprocess_comp1k_dataset.py) │ │ ├── training_list_fba.json (generated by tools/data/matting/comp1k/extend_fg.py) │ ├── coco │ │ ├── train2014 (or train2017) │ ├── VOCdevkit │ │ ├── VOC2012 ``` ================================================ FILE: tools/dataset_converters/comp1k/check_extended_fg.py ================================================ #!/usr/bin/env python # Copyright (c) OpenMMLab. All rights reserved. # This script checks the alpha-foreground difference between # the extended fg and the original fg import glob import os import os.path as osp import cv2 import numpy as np folder = 'data/adobe_composition-1k/Training_set/Adobe-licensed images' folder = osp.join(folder.split('/')) imgs = [ os.path.splitext(os.path.basename(x))[0] for x in glob.glob(osp.join(folder, 'fg', '*.jpg')) ] print('max,avg,img') for name in imgs: alpha = cv2.imread( osp.join(folder, 'alpha', '*.jpg'), cv2.IMREAD_GRAYSCALE).astype( np.float32)[..., None] / 255 fg = cv2.imread(osp.join(folder, 'fg', f'{name}.jpg')).astype(np.float32) xt = cv2.imread(osp.join(folder, 'fg_extended', f'{name}.jpg')).astype(np.float32) diff = np.abs((fg - xt) * alpha) print(f'{diff.max()},{diff.mean()},"{name}"', flush=True) ================================================ FILE: tools/dataset_converters/comp1k/evaluate_comp1k.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os.path as osp import re import cv2 import mmcv import mmengine import numpy as np from mmagic.evaluation import gauss_gradient from mmagic.utils import modify_args def sad(alpha, trimap, pred_alpha): if alpha.ndim != 2 or trimap.ndim != 2 or pred_alpha.ndim != 2: raise ValueError( 'input alpha, trimap and pred_alpha should has two dimensions, ' f'alpha {alpha.shape}, please check their shape: ' f'trimap {trimap.shape}, pred_alpha {pred_alpha.shape}') assert (pred_alpha[trimap == 0] == 0).all() assert (pred_alpha[trimap == 255] == 255).all() alpha = alpha.astype(np.float64) / 255 pred_alpha = pred_alpha.astype(np.float64) / 255 sad_result = np.abs(pred_alpha - alpha).sum() / 1000 return sad_result def mse(alpha, trimap, pred_alpha): if alpha.ndim != 2 or trimap.ndim != 2 or pred_alpha.ndim != 2: raise ValueError( 'input alpha, trimap and pred_alpha should has two dimensions, ' f'alpha {alpha.shape}, please check their shape: ' f'trimap {trimap.shape}, pred_alpha {pred_alpha.shape}') assert (pred_alpha[trimap == 0] == 0).all() assert (pred_alpha[trimap == 255] == 255).all() alpha = alpha.astype(np.float64) / 255 pred_alpha = pred_alpha.astype(np.float64) / 255 weight_sum = (trimap == 128).sum() if weight_sum != 0: mse_result = ((pred_alpha - alpha)**2).sum() / weight_sum else: mse_result = 0 return mse_result def gradient_error(alpha, trimap, pred_alpha, sigma=1.4): """Gradient error for evaluating alpha matte prediction. Args: alpha (ndarray): Ground-truth alpha matte. trimap (ndarray): Input trimap with its value in {0, 128, 255}. pred_alpha (ndarray): Predicted alpha matte. sigma (float): Standard deviation of the gaussian kernel. Default: 1.4. """ if alpha.ndim != 2 or trimap.ndim != 2 or pred_alpha.ndim != 2: raise ValueError( 'input alpha, trimap and pred_alpha should has two dimensions, ' f'alpha {alpha.shape}, please check their shape: ' f'trimap {trimap.shape}, pred_alpha {pred_alpha.shape}') if not ((pred_alpha[trimap == 0] == 0).all() and (pred_alpha[trimap == 255] == 255).all()): raise ValueError( 'pred_alpha should be masked by trimap before evaluation') alpha = alpha.astype(np.float64) pred_alpha = pred_alpha.astype(np.float64) alpha_normed = np.zeros_like(alpha) pred_alpha_normed = np.zeros_like(pred_alpha) cv2.normalize(alpha, alpha_normed, 1., 0., cv2.NORM_MINMAX) cv2.normalize(pred_alpha, pred_alpha_normed, 1., 0., cv2.NORM_MINMAX) alpha_grad = gauss_gradient(alpha_normed, sigma).astype(np.float32) pred_alpha_grad = gauss_gradient(pred_alpha_normed, sigma).astype(np.float32) grad_loss = ((alpha_grad - pred_alpha_grad)**2 * (trimap == 128)).sum() # same as SAD, divide by 1000 to reduce the magnitude of the result return grad_loss / 1000 def connectivity(alpha, trimap, pred_alpha, step=0.1): """Connectivity error for evaluating alpha matte prediction. Args: alpha (ndarray): Ground-truth alpha matte with shape (height, width). Value range of alpha is [0, 255]. trimap (ndarray): Input trimap with shape (height, width). Elements in trimap are one of {0, 128, 255}. pred_alpha (ndarray): Predicted alpha matte with shape (height, width). Value range of pred_alpha is [0, 255]. step (float): Step of threshold when computing intersection between `alpha` and `pred_alpha`. """ if alpha.ndim != 2 or trimap.ndim != 2 or pred_alpha.ndim != 2: raise ValueError( 'input alpha, trimap and pred_alpha should has two dimensions, ' f'alpha {alpha.shape}, please check their shape: ' f'trimap {trimap.shape}, pred_alpha {pred_alpha.shape}') if not ((pred_alpha[trimap == 0] == 0).all() and (pred_alpha[trimap == 255] == 255).all()): raise ValueError( 'pred_alpha should be masked by trimap before evaluation') alpha = alpha.astype(np.float32) / 255 pred_alpha = pred_alpha.astype(np.float32) / 255 thresh_steps = np.arange(0, 1 + step, step) round_down_map = -np.ones_like(alpha) for i in range(1, len(thresh_steps)): alpha_thresh = alpha >= thresh_steps[i] pred_alpha_thresh = pred_alpha >= thresh_steps[i] intersection = (alpha_thresh & pred_alpha_thresh).astype(np.uint8) # connected components _, output, stats, _ = cv2.connectedComponentsWithStats( intersection, connectivity=4) # start from 1 in dim 0 to exclude background size = stats[1:, -1] # largest connected component of the intersection omega = np.zeros_like(alpha) if len(size) != 0: max_id = np.argmax(size) # plus one to include background omega[output == max_id + 1] = 1 mask = (round_down_map == -1) & (omega == 0) round_down_map[mask] = thresh_steps[i - 1] round_down_map[round_down_map == -1] = 1 alpha_diff = alpha - round_down_map pred_alpha_diff = pred_alpha - round_down_map # only calculate difference larger than or equal to 0.15 alpha_phi = 1 - alpha_diff * (alpha_diff >= 0.15) pred_alpha_phi = 1 - pred_alpha_diff * (pred_alpha_diff >= 0.15) connectivity_error = np.sum( np.abs(alpha_phi - pred_alpha_phi) * (trimap == 128)) # same as SAD, divide by 1000 to reduce the magnitude of the result return connectivity_error / 1000 def evaluate_one(args): """Function to evaluate one sample of data. Args: args (tuple): Information needed to evaluate one sample of data. Returns: dict: The evaluation results including sad, mse, gradient error and connectivity error. """ pred_alpha_path, alpha_path, trimap_path = args pred_alpha = mmcv.imread(pred_alpha_path, flag='grayscale') alpha = mmcv.imread(alpha_path, flag='grayscale') if trimap_path is None: trimap = np.ones_like(alpha) else: trimap = mmcv.imread(trimap_path, flag='grayscale') sad_result = sad(alpha, trimap, pred_alpha) mse_result = mse(alpha, trimap, pred_alpha) grad_result = gradient_error(alpha, trimap, pred_alpha) conn_result = connectivity(alpha, trimap, pred_alpha) return (sad_result, mse_result, grad_result, conn_result) def evaluate(pred_root, gt_root, trimap_root, verbose, nproc): """Evaluate test results of Adobe composition-1k dataset. There are 50 different ground truth foregrounds and alpha mattes pairs, each of the foreground will be composited with 20 different backgrounds, producing 1000 images for testing. In some repo, the ground truth alpha matte will be copied 20 times and named the same as the images. This function accept both original alpha matte folder (contains 50 ground truth alpha mattes) and copied alpha matte folder (contains 1000 ground truth alpha mattes) for `gt_root`. Example of copied name: ``` alpha_matte1.png -> alpha_matte1_0.png alpha_matte1_1.png ... alpha_matte1_19.png alpha_matte1_20.png ``` Args: pred_root (str): Path to the predicted alpha matte folder. gt_root (str): Path to the ground truth alpha matte folder. trimap_root (str): Path to the predicted alpha matte folder. verbose (bool): Whether print result for each predicted alpha matte. nproc (int): number of processes. """ images = sorted(mmengine.scandir(pred_root)) gt_files_num = len(list(mmengine.scandir(gt_root))) # If ground truth alpha mattes are not copied (number of files is 50), we # use the below pattern to recover the name of the original alpha matte. if gt_files_num == 50: pattern = re.compile(r'(.+)_(?:\d+)(.png)') pairs = [] for img in images: pred_alpha_path = osp.join(pred_root, img) # if ground truth alpha matte are not copied, recover the original name if gt_files_num == 50: groups = pattern.match(img).groups() alpha_path = osp.join(gt_root, ''.join(groups)) # if ground truth alpha matte are copied, the name should be the same else: # gt_files_num == 1000 alpha_path = osp.join(gt_root, img) trimap_path = ( osp.join(trimap_root, img) if trimap_root is not None else None) pairs.append((pred_alpha_path, alpha_path, trimap_path)) results = mmengine.track_parallel_progress(evaluate_one, pairs, nproc) if verbose: # for sad_result, mse_result, grad_result, conn_result in results: for i, img in enumerate(images): sad_result, mse_result, grad_result, conn_result = results[i] print(f'{img} SAD: {sad_result:.6g} MattingMSE: {mse_result:.6g} ' f'GRAD: {grad_result:.6g} CONN: {conn_result:.6g}') sad_mean, mse_mean, grad_mean, conn_mean = np.mean(results, axis=0) print(f'MEAN: SAD: {sad_mean:.6g} MattingMSE: {mse_mean:.6g} ' f'GRAD: {grad_mean:.6g} CONN: {conn_mean:.6g}') def parse_args(): modify_args() parser = argparse.ArgumentParser( description='evaluate composition-1k prediction result') parser.add_argument( 'pred_root', help='Path to the predicted alpha matte folder') parser.add_argument( 'gt_root', help='Path to the ground truth alpha matte folder') parser.add_argument( '--trimap-root', help='Path to trimap folder. If not specified, ' 'results are calculated on the full image.') parser.add_argument( '-v', '--verbose', action='store_true', help='Whether print result for each predicted alpha matte') parser.add_argument( '--nproc', type=int, default=4, help='number of processes') return parser.parse_args() def main(): args = parse_args() if not osp.exists(args.pred_root): raise FileNotFoundError(f'pred_root {args.pred_root} not found') if not osp.exists(args.gt_root): raise FileNotFoundError(f'gt_root {args.gt_root} not found') evaluate(args.pred_root, args.gt_root, args.trimap_root, args.verbose, args.nproc) if __name__ == '__main__': main() ================================================ FILE: tools/dataset_converters/comp1k/extend_fg.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import re import subprocess import mmengine import numpy as np from PIL import Image from pymatting import estimate_foreground_ml, load_image def fix_png_file(filename, folder): """Fix png files in the target filename using pngfix. pngfix is a tool to fix PNG files. It's installed on Linux or MacOS by default. Args: filename (str): png file to run pngfix. """ subprocess.call( f'pngfix --quiet --strip=color --prefix=fixed_ "{filename}"', cwd=f'{folder}', shell=True) subprocess.call( f'mv "fixed_{filename}" "{filename}"', cwd=f'{folder}', shell=True) def join_first_contain(directories, filename, data_root): """Join the first directory that contains the file. Args: directories (list[str]): Directories to search for the file. filename (str): The target filename. data_root (str): Root of the data path. """ for directory in directories: cur_path = osp.join(directory, filename) if osp.exists(osp.join(data_root, cur_path)): return cur_path raise FileNotFoundError(f'Cannot find {filename} in dirs {directories}') class ExtendFg: def __init__(self, data_root, fg_dirs, alpha_dirs) -> None: self.data_root = data_root self.fg_dirs = fg_dirs self.alpha_dirs = alpha_dirs def extend(self, fg_name): fg_name = fg_name.strip() alpha_path = join_first_contain(self.alpha_dirs, fg_name, self.data_root) fg_path = join_first_contain(self.fg_dirs, fg_name, self.data_root) alpha_path = osp.join(self.data_root, alpha_path) fg_path = osp.join(self.data_root, fg_path) extended_path = re.sub('/fg/', '/fg_extended/', fg_path) extended_path = extended_path.replace('jpg', 'png') if not osp.exists(alpha_path): raise FileNotFoundError(f'{alpha_path} does not exist!') if not osp.exists(fg_path): raise FileNotFoundError(f'{fg_path} does not exist!') image = load_image(fg_path, 'RGB') alpha = load_image(alpha_path, 'GRAY') F = estimate_foreground_ml(image, alpha, return_background=False) fg = Image.fromarray(np.uint8(F * 255)) fg.save(extended_path) fix_png_file(osp.basename(extended_path), osp.dirname(extended_path)) data_info = dict() data_info['alpha_path'] = alpha_path data_info['fg_path'] = extended_path return data_info def parse_args(): parser = argparse.ArgumentParser( description='Prepare Adobe composition 1k dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('data_root', help='Adobe composition 1k dataset root') parser.add_argument( '--nproc', type=int, default=4, help='number of processor') args = parser.parse_args() return args def main(): args = parse_args() if not osp.exists(args.data_root): raise FileNotFoundError(f'{args.data_root} does not exist!') data_root = args.data_root print('preparing training data...') dir_prefix = 'Training_set' fname_prefix = 'training' fg_dirs = [ 'Training_set/Adobe-licensed images/fg', 'Training_set/Other/fg' ] alpha_dirs = [ 'Training_set/Adobe-licensed images/alpha', 'Training_set/Other/alpha' ] extended_dirs = [ 'Training_set/Adobe-licensed images/fg_extended', 'Training_set/Other/fg_extended' ] for p in extended_dirs: p = osp.join(data_root, p) os.makedirs(p, exist_ok=True) fg_names = osp.join(dir_prefix, f'{fname_prefix}_fg_names.txt') save_json_path = f'{fname_prefix}_list_fba.json' fg_names = open(osp.join(data_root, fg_names)).readlines() fg_iter = iter(fg_names) extend_fg = ExtendFg(data_root, fg_dirs, alpha_dirs) data_infos = mmengine.track_parallel_progress(extend_fg.extend, list(fg_iter), args.nproc) mmengine.dump(data_infos, osp.join(data_root, save_json_path)) print('train done') if __name__ == '__main__': main() ================================================ FILE: tools/dataset_converters/comp1k/filter_comp1k_anno.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os.path as osp import mmengine def generate_json(comp1k_json_path, target_list_path, save_json_path): data_infos = mmengine.load(comp1k_json_path) targets = mmengine.list_from_file(target_list_path) new_data_infos = [] for data_info in data_infos: for target in targets: if data_info['alpha_path'].endswith(target): new_data_infos.append(data_info) break mmengine.dump(new_data_infos, save_json_path) def parse_args(): parser = argparse.ArgumentParser( description='Filter composition-1k annotation file') parser.add_argument( 'comp1k_json_path', help='Path to the composition-1k dataset annotation file') parser.add_argument( 'target_list_path', help='Path to the file name list that need to filter out') parser.add_argument( 'save_json_path', help='Path to save the result json file') return parser.parse_args() def main(): args = parse_args() if not osp.exists(args.comp1k_json_path): raise FileNotFoundError(f'{args.comp1k_json_path} does not exist!') if not osp.exists(args.target_list_path): raise FileNotFoundError(f'{args.target_list_path} does not exist!') generate_json(args.comp1k_json_path, args.target_list_path, args.save_json_path) print('Done!') if __name__ == '__main__': main() ================================================ FILE: tools/dataset_converters/comp1k/preprocess_comp1k_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import math import os.path as osp import subprocess from itertools import chain, repeat import mmengine import numpy as np from PIL import Image from mmagic.utils import modify_args def fix_png_files(directory): """Fix png files in the target directory using pngfix. pngfix is a tool to fix PNG files. It's installed on Linux or MacOS by default. Args: directory (str): Directory to run pngfix. """ subprocess.call( 'pngfix --quiet --strip=color --prefix=fixed_ *.png', cwd=f'{directory}', shell=True) subprocess.call( 'for fixed_f in fixed_*; do mv "$fixed_f" "${fixed_f:6}"; done', cwd=f'{directory}', shell=True) def fix_png_file(filename, folder): """Fix png files in the target filename using pngfix. pngfix is a tool to fix PNG files. It's installed on Linux or MacOS by default. Args: filename (str): png file to run pngfix. """ subprocess.call( f'pngfix --quiet --strip=color --prefix=fixed_ "{filename}"', cwd=f'{folder}', shell=True) subprocess.call( f'mv "fixed_{filename}" "{filename}"', cwd=f'{folder}', shell=True) def join_first_contain(directories, filename, data_root): """Join the first directory that contains the file. Args: directories (list[str]): Directories to search for the file. filename (str): The target filename. data_root (str): Root of the data path. """ for directory in directories: cur_path = osp.join(directory, filename) if osp.exists(osp.join(data_root, cur_path)): return cur_path raise FileNotFoundError(f'Cannot find {filename} in dirs {directories}') def get_data_info(args): """Function to process one piece of data. Args: args (tuple): Information needed to process one piece of data. Returns: dict: The processed data info. """ name_with_postfix, source_bg_path, repeat_info, constant = args alpha, fg, alpha_path, fg_path = repeat_info data_root, composite, mode = constant if mode == 'training': dir_prefix = 'Training_set' trimap_dir = None elif mode == 'test': dir_prefix = 'Test_set' trimap_dir = 'Test_set/Adobe-licensed images/trimaps' else: raise KeyError(f'Unknown mode {mode}.') bg_path = osp.join(dir_prefix, 'bg', name_with_postfix).replace('.jpg', '.png') merged_path = osp.join(dir_prefix, 'merged', name_with_postfix).replace('.jpg', '.png') if not osp.exists(source_bg_path): raise FileNotFoundError(f'{source_bg_path} does not exist!') try: bg = Image.open(source_bg_path).convert('RGB') except Exception as ex: data_info = { 'alpha_path': alpha_path, 'fg_path': fg_path, 'bg_path': bg_path } print('err in ', data_info, ex) return data_info bw, bh = bg.size w, h = fg.size # rescale and crop bg wratio = float(w) / bw hratio = float(h) / bh ratio = wratio if wratio > hratio else hratio if ratio > 1: bg = bg.resize((math.ceil(bw * ratio), math.ceil(bh * ratio)), Image.BICUBIC) bg = bg.crop((0, 0, w, h)) # save cropped bg and merged mmengine.utils.mkdir_or_exist(osp.join(data_root, dir_prefix, 'bg')) bgfilename = osp.join(data_root, bg_path) bg.save(bgfilename, 'PNG') fix_png_file(osp.basename(bgfilename), osp.dirname(bgfilename)) if composite: merged = (fg * alpha + bg * (1. - alpha)).astype(np.uint8) mmengine.utils.mkdir_or_exist( osp.join(data_root, dir_prefix, 'merged')) mergedfilename = osp.join(data_root, merged_path) Image.fromarray(merged).save(mergedfilename, 'PNG') fix_png_file(osp.basename(mergedfilename), osp.dirname(mergedfilename)) data_info = dict() data_info['alpha_path'] = alpha_path data_info['fg_path'] = fg_path data_info['bg_path'] = bg_path data_info['merged_path'] = merged_path if trimap_dir is not None: trimap_path = osp.join(trimap_dir, name_with_postfix) trimap_full_path = osp.join(data_root, trimap_path) if not osp.exists(trimap_full_path): raise FileNotFoundError(f'{trimap_full_path} does not exist!') data_info['trimap_path'] = trimap_path return data_info def generate_json(data_root, source_bg_dir, composite, nproc, mode): """Generate training json list or test json list. It should be noted except for `source_bg_dir`, other strings are incomplete relative path. When using these strings to read from or write to disk, a data_root is added to form a complete relative path. Args: data_root (str): path to Adobe composition-1k directory. source_bg_dir (str): source background directory. composite (bool): whether composite fg with bg and write to file. nproc (int): number of processes. mode (str): training or test mode. """ if mode == 'training': dir_prefix = 'Training_set' fname_prefix = 'training' num_bg = 100 # each training fg is composited with 100 bg fg_dirs = [ 'Training_set/Adobe-licensed images/fg', 'Training_set/Other/fg' ] alpha_dirs = [ 'Training_set/Adobe-licensed images/alpha', 'Training_set/Other/alpha' ] elif mode == 'test': dir_prefix = 'Test_set' fname_prefix = 'test' num_bg = 20 # each test fg is composited with 20 bg fg_dirs = ['Test_set/Adobe-licensed images/fg'] alpha_dirs = ['Test_set/Adobe-licensed images/alpha'] else: raise KeyError(f'Unknown mode {mode}.') fg_names = osp.join(dir_prefix, f'{fname_prefix}_fg_names.txt') bg_names = osp.join(dir_prefix, f'{fname_prefix}_bg_names.txt') save_json_path = f'{fname_prefix}_list.json' fg_names = open(osp.join(data_root, fg_names)).readlines() bg_names = open(osp.join(data_root, bg_names)).readlines() assert len(fg_names) * num_bg == len(bg_names) repeat_infos = [] name_with_postfix = [] # repeat fg and alpha num_bg time for fg_name in fg_names: fg_name = fg_name.strip() alpha_path = join_first_contain(alpha_dirs, fg_name, data_root) fg_path = join_first_contain(fg_dirs, fg_name, data_root) alpha_full_path = osp.join(data_root, alpha_path) fg_full_path = osp.join(data_root, fg_path) if not osp.exists(alpha_full_path): raise FileNotFoundError(f'{alpha_full_path} does not exist!') if not osp.exists(fg_full_path): raise FileNotFoundError(f'{fg_full_path} does not exist!') # to be consistent with DIM's composition code, use PIL to read images fg = Image.open(fg_full_path).convert('RGB') alpha = ( np.array(Image.open(alpha_full_path).convert('RGB')) / 255. if composite else None) repeat_infos.append((alpha, fg, alpha_path, fg_path)) for bg_idx in range(num_bg): name_with_postfix.append(fg_name[:-4] + '_' + str(bg_idx) + fg_name[-4:]) repeat_infos = chain.from_iterable( (repeat(repeat_info, num_bg) for repeat_info in repeat_infos)) source_bg_paths = [] for bg_name in bg_names: bg_name = bg_name.strip() # in coco_2017, image names do not begin with 'COCO_train2014_' if '2017' in source_bg_dir: bg_name = bg_name[15:] # get rid of 'COCO_train2014_' source_bg_paths.append(osp.join(source_bg_dir, bg_name)) constants = repeat((data_root, composite, mode), len(bg_names)) data_infos = mmengine.track_parallel_progress( get_data_info, list(zip(name_with_postfix, source_bg_paths, repeat_infos, constants)), nproc) mmengine.dump(data_infos, osp.join(data_root, save_json_path)) def parse_args(): modify_args() parser = argparse.ArgumentParser( description='Prepare Adobe composition 1k dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('data_root', help='Adobe composition 1k dataset root') parser.add_argument('coco_root', help='COCO2014 or COCO2017 dataset root') parser.add_argument('voc_root', help='VOCdevkit directory root') parser.add_argument( '--composite', action='store_true', help='whether to composite training foreground and background offline') parser.add_argument( '--nproc', type=int, default=4, help='number of processes') parser.add_argument( '--skip-train', action='store_true', help='whether to skip the training data') args = parser.parse_args() return args def main(): args = parse_args() if not osp.exists(args.data_root): raise FileNotFoundError(f'{args.data_root} does not exist!') if not osp.exists(args.coco_root): raise FileNotFoundError(f'{args.coco_root} does not exist!') if not osp.exists(args.voc_root): raise FileNotFoundError(f'{args.voc_root} does not exist!') data_root = args.data_root if not args.skip_train: print('preparing training data...') if osp.exists(osp.join(args.coco_root, 'train2017')): train_source_bg_dir = osp.join(args.coco_root, 'train2017') elif osp.exists(osp.join(args.coco_root, 'train2014')): train_source_bg_dir = osp.join(args.coco_root, 'train2014') else: raise FileNotFoundError( f'Could not find train2014 or train2017 under {args.coco_root}' ) generate_json(data_root, train_source_bg_dir, args.composite, args.nproc, 'training') print('train done') fg_dir = 'Test_set/Adobe-licensed images/fg' alpha_dir = 'Test_set/Adobe-licensed images/alpha' print('fixing png of test fg') fix_png_files(osp.join(data_root, fg_dir)) print('fixing png of test alpha') fix_png_files(osp.join(data_root, alpha_dir)) print('\npreparing test data...') test_source_bg_dir = osp.join(args.voc_root, 'VOC2012/JPEGImages') generate_json(data_root, test_source_bg_dir, True, args.nproc, 'test') print('\nDone!') if __name__ == '__main__': main() ================================================ FILE: tools/dataset_converters/denoising/README.md ================================================ # Preparing Denoising Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The test datasets (Set12, BSD68, CBSD68, Kodak, McMaster, Urban100) can be download from [here](https://drive.google.com/file/d/1mwMLt-niNqcQpfN_ZduG9j4k6P_ZkOl0/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── denoising_gaussian_test |   |   ├── Set12 |   |   ├── BSD68 |   |   ├── CBSD68 |   |   ├── Kodak |   |   ├── McMaster |   |   ├── Urban100 ``` ================================================ FILE: tools/dataset_converters/denoising/README_zh-CN.md ================================================ # 准备 Denoising 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 测试数据集(Set12, BSD68, CBSD68, Kodak, McMaster, Urban100)可以从 [此处](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── denoising_gaussian_test |   |   ├── Set12 |   |   ├── BSD68 |   |   ├── CBSD68 |   |   ├── Kodak |   |   ├── McMaster |   |   ├── Urban100 ``` ================================================ FILE: tools/dataset_converters/deraining/README.md ================================================ # Preparing Deraining Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The test datasets (Rain100H, Rain100L, Test100, Test1200, Test2800) can be download from [here](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── Rain100H |   |   ├── input |   |   ├── target |   ├── Rain100L |   |   ├── input |   |   ├── target |   ├── Test100 |   |   ├── input |   |   ├── target |   ├── Test1200 |   |   ├── input |   |   ├── target |   ├── Test2800 |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/deraining/README_zh-CN.md ================================================ # 准备 Deraining 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 测试数据集(Rain100H, Rain100L, Test100, Test1200, Test2800)可以从 [此处](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── Rain100H |   |   ├── input |   |   ├── target |   ├── Rain100L |   |   ├── input |   |   ├── target |   ├── Test100 |   |   ├── input |   |   ├── target |   ├── Test1200 |   |   ├── input |   |   ├── target |   ├── Test2800 |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/df2k_ost/README.md ================================================ # Preparing DF2K_OST Dataset ```bibtex @inproceedings{wang2021real, title={Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data}, author={Wang, Xintao and Xie, Liangbin and Dong, Chao and Shan, Ying}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, pages={1905--1914}, year={2021} } ``` - The DIV2K dataset can be downloaded from [here](https://data.vision.ee.ethz.ch/cvl/DIV2K/) (We use the training set only). - The Flickr2K dataset can be downloaded [here](https://cv.snu.ac.kr/research/EDSR/Flickr2K.tar) (We use the training set only). - The OST dataset can be downloaded [here](https://openmmlab.oss-cn-hangzhou.aliyuncs.com/datasets/OST_dataset.zip) (We use the training set only). Please first put all the images into the `GT` folder (naming does not need to be in order): ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── df2k_ost │ │ ├── GT │ │ │ ├── 0001.png │ │ │ ├── 0002.png │ │ │ ├── ... ... ``` ## Crop sub-images For faster IO, we recommend to crop the images to sub-images. We provide such a script: ```shell python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost ``` The generated data is stored under `df2k_ost` and the data structure is as follows, where `_sub` indicates the sub-images. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── df2k_ost │ │ ├── GT │ │ ├── GT_sub │ │ ├── meta_info_df2k_ost.txt ... ``` ## Prepare annotation list If you use the annotation mode for the dataset, you first need to prepare a specific `txt` file. Each line in the annotation file contains the image names and image shape (usually for the ground-truth images), separated by a white space. Example of an annotation file: ```text 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) ``` Note that `preprocess_df2k_ost_dataset.py` will generate default annotation files. ## Prepare LMDB dataset for DF2K_OST If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb ``` ================================================ FILE: tools/dataset_converters/df2k_ost/README_zh-CN.md ================================================ # 准备 DF2K_OST 数据集 ```bibtex @inproceedings{wang2021real, title={Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data}, author={Wang, Xintao and Xie, Liangbin and Dong, Chao and Shan, Ying}, booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, pages={1905--1914}, year={2021} } ``` - DIV2K 数据集可以在 [这里](https://data.vision.ee.ethz.ch/cvl/DIV2K/) 下载 (我们只使用训练集)。 - Flickr2K 数据集可以在 [这里](https://cv.snu.ac.kr/research/EDSR/Flickr2K.tar) 下载 (我们只使用训练集)。 - OST 数据集可以在 [这里](https://openmmlab.oss-cn-hangzhou.aliyuncs.com/datasets/OST_dataset.zip) 下载 (我们只使用训练集)。 请先将所有图片放入 `GT` 文件夹(命名不需要按顺序): ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── df2k_ost │ │ ├── GT │ │ │ ├── 0001.png │ │ │ ├── 0002.png │ │ │ ├── ... ... ``` ## 裁剪子图像 为了更快的 IO,我们建议将图像裁剪为子图像。 我们提供了这样一个脚本: ```shell python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost ``` 生成的数据存放在 `df2k_ost` 下,数据结构如下,其中 `_sub` 表示子图像。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── df2k_ost │ │ ├── GT │ │ ├── GT_sub │ │ ├── meta_info_df2k_ost.txt ... ``` ## 准备标注列表文件 如果您想使用`标注模式`来处理数据集,需要先准备一个 `txt` 格式的标注文件。 标注文件中的每一行包含了图片名以及图片尺寸(这些通常是 ground-truth 图片),这两个字段用空格间隔开。 标注文件示例: ```text 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) ``` 请注意,`preprocess_df2k_ost_dataset.py` 脚本默认生成一份标注文件。 ## Prepare LMDB dataset for DF2K_OST 如果你想使用 LMDB 数据集来获得更快的 IO 速度,你可以通过以下方式制作 LMDB 文件: ```shell python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb ``` ================================================ FILE: tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import sys from multiprocessing import Pool import cv2 import lmdb import mmcv import mmengine import numpy as np def generate_anno_file(args): """Generate annotation file for DF2K_OST datasets from the ground-truth folder.""" print('Generate annotation files ...') txt_file = osp.join(args.data_root, args.anno_path) mmengine.utils.mkdir_or_exist(osp.dirname(txt_file)) img_list = sorted(os.listdir(osp.join(args.data_root, 'GT_sub'))) with open(txt_file, 'w') as f: for img in img_list: f.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') def main_extract_subimages(args): """A multi-thread tool to crop large images to sub-images for faster IO. It is used for DF2K_OST dataset. opt (dict): Configuration dict. It contains: n_thread (int): Thread number. compression_level (int): CV_IMWRITE_PNG_COMPRESSION from 0 to 9. A higher value means a smaller size and longer compression time. Use 0 for faster CPU decompression. Default: 3, same in cv2. input_folder (str): Path to the input folder. save_folder (str): Path to save folder. crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped. """ opt = {} opt['n_thread'] = args.n_thread opt['compression_level'] = args.compression_level # HR images opt['input_folder'] = osp.join(args.data_root, 'GT') opt['save_folder'] = osp.join(args.data_root, 'GT_sub') opt['crop_size'] = args.crop_size opt['step'] = args.step opt['thresh_size'] = args.thresh_size extract_subimages(opt) def extract_subimages(opt): """Crop images to subimages. Args: opt (dict): Configuration dict. It contains: input_folder (str): Path to the input folder. save_folder (str): Path to save folder. n_thread (int): Thread number. """ input_folder = opt['input_folder'] save_folder = opt['save_folder'] if not osp.exists(save_folder): os.makedirs(save_folder) print(f'mkdir {save_folder} ...') else: print(f'Folder {save_folder} already exists. Exit.') sys.exit(1) img_list = list(mmengine.scandir(input_folder, suffix='png')) img_list = [osp.join(input_folder, v) for v in img_list] prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(opt['n_thread']) for path in img_list: pool.apply_async( worker, args=(path, opt), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def worker(path, opt): """Worker for each process. Args: path (str): Image path. opt (dict): Configuration dict. It contains: crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is smaller than thresh_size will be dropped. save_folder (str): Path to save folder. compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION. Returns: process_info (str): Process information displayed in progress bar. """ crop_size = opt['crop_size'] step = opt['step'] thresh_size = opt['thresh_size'] img_name, extension = osp.splitext(osp.basename(path)) img = mmcv.imread(path, flag='unchanged') if img.ndim == 2 or img.ndim == 3: h, w = img.shape[:2] else: raise ValueError(f'Image ndim should be 2 or 3, but got {img.ndim}') h_space = np.arange(0, h - crop_size + 1, step) if h - (h_space[-1] + crop_size) > thresh_size: h_space = np.append(h_space, h - crop_size) w_space = np.arange(0, w - crop_size + 1, step) if w - (w_space[-1] + crop_size) > thresh_size: w_space = np.append(w_space, w - crop_size) index = 0 for x in h_space: for y in w_space: index += 1 cropped_img = img[x:x + crop_size, y:y + crop_size, ...] cv2.imwrite( osp.join(opt['save_folder'], f'{img_name}_s{index:03d}{extension}'), cropped_img, [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']]) process_info = f'Processing {img_name} ...' return process_info def make_lmdb_for_df2k_ost(data_root): """Create lmdb files for DF2K_OST dataset. Args: data_root (str): Data root path. """ folder_paths = [ osp.join(data_root, 'df2k_ost/GT_sub'), ] lmdb_paths = [ osp.join(data_root, 'df2k_ost/GT_sub.lmdb'), ] for folder_path, lmdb_path in zip(folder_paths, lmdb_paths): img_path_list, keys = prepare_keys_df2k_ost(folder_path) make_lmdb(folder_path, lmdb_path, img_path_list, keys) def prepare_keys_df2k_ost(folder_path): """Prepare image path list and keys for DF2K_OST dataset. Args: folder_path (str): Folder path. Returns: list[str]: Image path list. list[str]: Key list. """ print('Reading image path list ...') img_path_list = sorted( list(mmengine.scandir(folder_path, suffix='png', recursive=False))) keys = [img_path.split('.png')[0] for img_path in sorted(img_path_list)] return img_path_list, keys def make_lmdb(data_path, lmdb_path, img_path_list, keys, batch=5000, compress_level=1, multiprocessing_read=False, n_thread=40): """Make lmdb. Contents of lmdb. The file structure is: example.lmdb ├── data.mdb ├── lock.mdb ├── meta_info.txt The data.mdb and lock.mdb are standard lmdb files and you can refer to https://lmdb.readthedocs.io/en/release/ for more details. The meta_info.txt is a specified txt file to record the meta information of our datasets. It will be automatically created when preparing datasets by our provided dataset tools. Each line in the txt file records 1)image name (with extension), 2)image shape, and 3)compression level, separated by a white space. For example, the meta information could be: `000_00000000.png (720,1280,3) 1`, which means: 1) image name (with extension): 000_00000000.png; 2) image shape: (720,1280,3); 3) compression level: 1 We use the image name without extension as the lmdb key. If `multiprocessing_read` is True, it will read all the images to memory using multiprocessing. Thus, your server needs to have enough memory. Args: data_path (str): Data path for reading images. lmdb_path (str): Lmdb save path. img_path_list (str): Image path list. keys (str): Used for lmdb keys. batch (int): After processing batch images, lmdb commits. Default: 5000. compress_level (int): Compress level when encoding images. Default: 1. multiprocessing_read (bool): Whether use multiprocessing to read all the images to memory. Default: False. n_thread (int): For multiprocessing. """ assert len(img_path_list) == len(keys), ( 'img_path_list and keys should have the same length, ' f'but got {len(img_path_list)} and {len(keys)}') print(f'Create lmdb for {data_path}, save to {lmdb_path}...') print(f'Total images: {len(img_path_list)}') if not lmdb_path.endswith('.lmdb'): raise ValueError("lmdb_path must end with '.lmdb'.") if osp.exists(lmdb_path): print(f'Folder {lmdb_path} already exists. Exit.') sys.exit(1) if multiprocessing_read: # read all the images to memory (multiprocessing) dataset = {} # use dict to keep the order for multiprocessing shapes = {} print(f'Read images with multiprocessing, #thread: {n_thread} ...') prog_bar = mmengine.ProgressBar(len(img_path_list)) def callback(arg): """get the image data and update prog_bar.""" key, dataset[key], shapes[key] = arg prog_bar.update() pool = Pool(n_thread) for path, key in zip(img_path_list, keys): pool.apply_async( read_img_worker, args=(osp.join(data_path, path), key, compress_level), callback=callback) pool.close() pool.join() print(f'Finish reading {len(img_path_list)} images.') # create lmdb environment # obtain data size for one image img = mmcv.imread(osp.join(data_path, img_path_list[0]), flag='unchanged') _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) data_size_per_img = img_byte.nbytes print('Data size per image is: ', data_size_per_img) data_size = data_size_per_img * len(img_path_list) env = lmdb.open(lmdb_path, map_size=data_size * 10) # write data to lmdb prog_bar = mmengine.ProgressBar(len(img_path_list)) txn = env.begin(write=True) txt_file = open(osp.join(lmdb_path, 'meta_info.txt'), 'w') for idx, (path, key) in enumerate(zip(img_path_list, keys)): prog_bar.update() key_byte = key.encode('ascii') if multiprocessing_read: img_byte = dataset[key] h, w, c = shapes[key] else: _, img_byte, img_shape = read_img_worker( osp.join(data_path, path), key, compress_level) h, w, c = img_shape txn.put(key_byte, img_byte) # write meta information txt_file.write(f'{key}.png ({h},{w},{c}) {compress_level}\n') if idx % batch == 0: txn.commit() txn = env.begin(write=True) txn.commit() env.close() txt_file.close() print('\nFinish writing lmdb.') def read_img_worker(path, key, compress_level): """Read image worker. Args: path (str): Image path. key (str): Image key. compress_level (int): Compress level when encoding images. Returns: str: Image key. byte: Image byte. tuple[int]: Image shape. """ img = mmcv.imread(path, flag='unchanged') if img.ndim == 2: h, w = img.shape c = 1 else: h, w, c = img.shape _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) return (key, img_byte, (h, w, c)) def parse_args(): parser = argparse.ArgumentParser( description='Prepare DF2K_OST dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') parser.add_argument( '--anno-path', nargs='?', default='meta_info_df2k_ost.txt', type=str, help='annotation file path') parser.add_argument( '--crop-size', type=int, nargs='?', default=480, help='cropped size for HR images') parser.add_argument( '--step', type=int, nargs='?', default=240, help='step size for HR images') parser.add_argument( '--thresh-size', type=int, nargs='?', default=0, help='threshold size for HR images') parser.add_argument( '--compression-level', type=int, nargs='?', default=3, help='compression level when save png images') parser.add_argument( '--n-thread', type=int, nargs='?', default=20, help='thread number when using multiprocessing') parser.add_argument( '--make-lmdb', action='store_true', help='whether to prepare lmdb files') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() # extract subimages main_extract_subimages(args) # generate annotation files generate_anno_file(args) # prepare lmdb files if necessary if args.make_lmdb: make_lmdb_for_df2k_ost(args.data_root) ================================================ FILE: tools/dataset_converters/div2k/README.md ================================================ # Preparing DIV2K Dataset ```bibtex @InProceedings{Agustsson_2017_CVPR_Workshops, author = {Agustsson, Eirikur and Timofte, Radu}, title = {NTIRE 2017 Challenge on Single Image Super-Resolution: Dataset and Study}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR) Workshops}, month = {July}, year = {2017} } ``` - Training dataset: [DIV2K dataset](https://data.vision.ee.ethz.ch/cvl/DIV2K/). - Validation dataset: [Set5](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u) and [Set14](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u). Note that we merge the original val dataset (image names from 0801 to 0900) to the original train dataset (image names from 0001 to 0800). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ │ ├── 0001.png │ │ │ ├── 0002.png │ │ │ ├── ... │ │ │ ├── 0800.png │ │ │ ├── 0801.png │ │ │ ├── ... │ │ │ ├── 0900.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ ├── DIV2K_valid_HR │ │ ├── DIV2K_valid_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ ├── Set5 │ │ ├── GTmod12 │ │ ├── LRbicx2 │ │ ├── LRbicx3 │ │ ├── LRbicx4 │ ├── Set14 │ │ ├── GTmod12 │ │ ├── LRbicx2 │ │ ├── LRbicx3 │ │ ├── LRbicx4 ``` ## Crop sub-images For faster IO, we recommend to crop the DIV2K images to sub-images. We provide such a script: ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` The generated data is stored under `DIV2K` and the data structure is as follows, where `_sub` indicates the sub-images. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ ├── DIV2K_train_HR_sub │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ │ ├── X2_sub │ │ │ ├── X3_sub │ │ │ ├── X4_sub │ │ ├── DIV2K_valid_HR │ │ ├── ... │ │ ├── meta_info_DIV2K800sub_GT.txt │ │ ├── meta_info_DIV2K100sub_GT.txt ... ``` ## Prepare annotation list If you use the annotation mode for the dataset, you first need to prepare a specific `txt` file. Each line in the annotation file contains the image names and image shape (usually for the ground-truth images), separated by a white space. Example of an annotation file: ```text 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) ``` Note that `preprocess_div2k_dataset` will generate default annotation files. ## Prepare LMDB dataset for DIV2K If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb ``` ================================================ FILE: tools/dataset_converters/div2k/README_zh-CN.md ================================================ # 准备 DIV2K 数据集 ```bibtex @InProceedings{Agustsson_2017_CVPR_Workshops, author = {Agustsson, Eirikur and Timofte, Radu}, title = {NTIRE 2017 Challenge on Single Image Super-Resolution: Dataset and Study}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR) Workshops}, month = {July}, year = {2017} } ``` - 训练集: [DIV2K dataset](https://data.vision.ee.ethz.ch/cvl/DIV2K/). - 验证集: [Set5](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u) 和 [Set14](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u). 请注意,我们将原始的验证集(文件名 0801 到 0900)合并进了原始的训练集(文件名 0001 到 0800)。文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ │ ├── 0001.png │ │ │ ├── 0002.png │ │ │ ├── ... │ │ │ ├── 0800.png │ │ │ ├── 0801.png │ │ │ ├── ... │ │ │ ├── 0900.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ ├── DIV2K_valid_HR │ │ ├── DIV2K_valid_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ ├── Set5 │ │ ├── GTmod12 │ │ ├── LRbicx2 │ │ ├── LRbicx3 │ │ ├── LRbicx4 │ ├── Set14 │ │ ├── GTmod12 │ │ ├── LRbicx2 │ │ ├── LRbicx3 │ │ ├── LRbicx4 ``` ## 裁剪子图 为了加快 IO,建议将 DIV2K 中的图片裁剪为一系列子图,为此,我们提供了一个脚本: ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` 生成的数据保存在 `DIV2K` 目录下,其文件结构如下所示,其中 `_sub` 表示子图: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR │ │ ├── DIV2K_train_HR_sub │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 │ │ │ ├── X4 │ │ │ ├── X2_sub │ │ │ ├── X3_sub │ │ │ ├── X4_sub │ │ ├── DIV2K_valid_HR │ │ ├── ... │ │ ├── meta_info_DIV2K800sub_GT.txt │ │ ├── meta_info_DIV2K100sub_GT.txt ... ``` ## 准备标注列表文件 如果您想使用`标注模式`来处理数据集,需要先准备一个 `txt` 格式的标注文件。 标注文件中的每一行包含了图片名以及图片尺寸(这些通常是 ground-truth 图片),这两个字段用空格间隔开。 标注文件示例: ```text 0001_s001.png (480,480,3) 0001_s002.png (480,480,3) ``` 请注意,`preprocess_div2k_dataset` 脚本默认生成一份标注文件。 ## 准备 LMDB 格式的 DIV2K 数据集 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件 ```shell python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb ``` ================================================ FILE: tools/dataset_converters/div2k/preprocess_div2k_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import re import sys from multiprocessing import Pool import cv2 import lmdb import mmcv import mmengine import numpy as np def generate_anno_file(args): """Generate annotation file for DIV2K datasets from the ground-truth folder.""" print('Generate annotation files ...') train_file = osp.join(args.data_root, args.anno_train_path) test_file = osp.join(args.data_root, args.anno_test_path) mmengine.utils.mkdir_or_exist(osp.dirname(train_file)) mmengine.utils.mkdir_or_exist(osp.dirname(test_file)) img_list = sorted( os.listdir(osp.join(args.data_root, 'DIV2K_train_HR_sub'))) with open(train_file, 'w') as f1, open(test_file, 'w') as f2: for img in img_list: if img[:4] < '0801': f1.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') else: f2.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') def main_extract_subimages(args): """A multi-thread tool to crop large images to sub-images for faster IO. It is used for DIV2K dataset. opt (dict): Configuration dict. It contains: n_thread (int): Thread number. compression_level (int): CV_IMWRITE_PNG_COMPRESSION from 0 to 9. A higher value means a smaller size and longer compression time. Use 0 for faster CPU decompression. Default: 3, same in cv2. scales (list[int]): The downsampling factors corresponding to the LR folders you want to process. Default: [2, 3, 4]. input_folder (str): Path to the input folder. save_folder (str): Path to save folder. crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped. Usage: For each folder, run this script. By default, there are four folders to be processed for DIV2K dataset according to scale factor list ([2,3,4]) DIV2K_train_HR DIV2K_train_LR_bicubic/X2 DIV2K_train_LR_bicubic/X3 DIV2K_train_LR_bicubic/X4 After process, each sub_folder should have the same number of subimages. You can also specify scales by modifying the argument 'scales'. Remember to modify opt configurations according to your settings. """ opt = {} opt['n_thread'] = args.n_thread opt['compression_level'] = args.compression_level # HR images opt['input_folder'] = osp.join(args.data_root, 'DIV2K_train_HR') opt['save_folder'] = osp.join(args.data_root, 'DIV2K_train_HR_sub') opt['crop_size'] = args.crop_size opt['step'] = args.step opt['thresh_size'] = args.thresh_size extract_subimages(opt) for scale in args.scales: opt['input_folder'] = osp.join(args.data_root, f'DIV2K_train_LR_bicubic/X{scale}') opt['save_folder'] = osp.join(args.data_root, f'DIV2K_train_LR_bicubic/X{scale}_sub') opt['crop_size'] = args.crop_size // scale opt['step'] = args.step // scale opt['thresh_size'] = args.thresh_size // scale extract_subimages(opt) def extract_subimages(opt): """Crop images to subimages. Args: opt (dict): Configuration dict. It contains: input_folder (str): Path to the input folder. save_folder (str): Path to save folder. n_thread (int): Thread number. """ input_folder = opt['input_folder'] save_folder = opt['save_folder'] if not osp.exists(save_folder): os.makedirs(save_folder) print(f'mkdir {save_folder} ...') else: print(f'Folder {save_folder} already exists. Exit.') sys.exit(1) img_list = list(mmengine.scandir(input_folder)) img_list = [osp.join(input_folder, v) for v in img_list] prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(opt['n_thread']) for path in img_list: pool.apply_async( worker, args=(path, opt), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def worker(path, opt): """Worker for each process. Args: path (str): Image path. opt (dict): Configuration dict. It contains: crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is smaller than thresh_size will be dropped. save_folder (str): Path to save folder. compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION. Returns: process_info (str): Process information displayed in progress bar. """ crop_size = opt['crop_size'] step = opt['step'] thresh_size = opt['thresh_size'] img_name, extension = osp.splitext(osp.basename(path)) # remove the x2, x3, x4 and x8 in the filename for DIV2K img_name = re.sub('x[2348]', '', img_name) img = mmcv.imread(path, flag='unchanged') if img.ndim == 2 or img.ndim == 3: h, w = img.shape[:2] else: raise ValueError(f'Image ndim should be 2 or 3, but got {img.ndim}') h_space = np.arange(0, h - crop_size + 1, step) if h - (h_space[-1] + crop_size) > thresh_size: h_space = np.append(h_space, h - crop_size) w_space = np.arange(0, w - crop_size + 1, step) if w - (w_space[-1] + crop_size) > thresh_size: w_space = np.append(w_space, w - crop_size) index = 0 for x in h_space: for y in w_space: index += 1 cropped_img = img[x:x + crop_size, y:y + crop_size, ...] cv2.imwrite( osp.join(opt['save_folder'], f'{img_name}_s{index:03d}{extension}'), cropped_img, [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']]) process_info = f'Processing {img_name} ...' return process_info def make_lmdb_for_div2k(data_root): """Create lmdb files for DIV2K dataset. Args: data_root (str): Data root path. Usage: Typically, there are four folders to be processed for DIV2K dataset. DIV2K_train_HR_sub DIV2K_train_LR_bicubic/X2_sub DIV2K_train_LR_bicubic/X3_sub DIV2K_train_LR_bicubic/X4_sub Remember to modify opt configurations according to your settings. """ folder_paths = [ osp.join(data_root, 'DIV2K_train_HR_sub'), osp.join(data_root, 'DIV2K_train_LR_bicubic/X2_sub'), osp.join(data_root, 'DIV2K_train_LR_bicubic/X3_sub'), osp.join(data_root, 'DIV2K_train_LR_bicubic/X4_sub') ] lmdb_paths = [ osp.join(data_root, 'DIV2K_train_HR_sub.lmdb'), osp.join(data_root, 'DIV2K_train_LR_bicubic_X2_sub.lmdb'), osp.join(data_root, 'DIV2K_train_LR_bicubic_X3_sub.lmdb'), osp.join(data_root, 'DIV2K_train_LR_bicubic_X4_sub.lmdb') ] for folder_path, lmdb_path in zip(folder_paths, lmdb_paths): img_path_list, keys = prepare_keys_div2k(folder_path) make_lmdb(folder_path, lmdb_path, img_path_list, keys) def prepare_keys_div2k(folder_path): """Prepare image path list and keys for DIV2K dataset. Args: folder_path (str): Folder path. Returns: list[str]: Image path list. list[str]: Key list. """ print('Reading image path list ...') img_path_list = sorted( list(mmengine.scandir(folder_path, suffix='png', recursive=False))) keys = [img_path.split('.png')[0] for img_path in sorted(img_path_list)] return img_path_list, keys def make_lmdb(data_path, lmdb_path, img_path_list, keys, batch=5000, compress_level=1, multiprocessing_read=False, n_thread=40): """Make lmdb. Contents of lmdb. The file structure is: example.lmdb ├── data.mdb ├── lock.mdb ├── meta_info.txt The data.mdb and lock.mdb are standard lmdb files and you can refer to https://lmdb.readthedocs.io/en/release/ for more details. The meta_info.txt is a specified txt file to record the meta information of our datasets. It will be automatically created when preparing datasets by our provided dataset tools. Each line in the txt file records 1)image name (with extension), 2)image shape, and 3)compression level, separated by a white space. For example, the meta information could be: `000_00000000.png (720,1280,3) 1`, which means: 1) image name (with extension): 000_00000000.png; 2) image shape: (720,1280,3); 3) compression level: 1 We use the image name without extension as the lmdb key. If `multiprocessing_read` is True, it will read all the images to memory using multiprocessing. Thus, your server needs to have enough memory. Args: data_path (str): Data path for reading images. lmdb_path (str): Lmdb save path. img_path_list (str): Image path list. keys (str): Used for lmdb keys. batch (int): After processing batch images, lmdb commits. Default: 5000. compress_level (int): Compress level when encoding images. Default: 1. multiprocessing_read (bool): Whether use multiprocessing to read all the images to memory. Default: False. n_thread (int): For multiprocessing. """ assert len(img_path_list) == len(keys), ( 'img_path_list and keys should have the same length, ' f'but got {len(img_path_list)} and {len(keys)}') print(f'Create lmdb for {data_path}, save to {lmdb_path}...') print(f'Total images: {len(img_path_list)}') if not lmdb_path.endswith('.lmdb'): raise ValueError("lmdb_path must end with '.lmdb'.") if osp.exists(lmdb_path): print(f'Folder {lmdb_path} already exists. Exit.') sys.exit(1) if multiprocessing_read: # read all the images to memory (multiprocessing) dataset = {} # use dict to keep the order for multiprocessing shapes = {} print(f'Read images with multiprocessing, #thread: {n_thread} ...') prog_bar = mmengine.ProgressBar(len(img_path_list)) def callback(arg): """get the image data and update prog_bar.""" key, dataset[key], shapes[key] = arg prog_bar.update() pool = Pool(n_thread) for path, key in zip(img_path_list, keys): pool.apply_async( read_img_worker, args=(osp.join(data_path, path), key, compress_level), callback=callback) pool.close() pool.join() print(f'Finish reading {len(img_path_list)} images.') # create lmdb environment # obtain data size for one image img = mmcv.imread(osp.join(data_path, img_path_list[0]), flag='unchanged') _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) data_size_per_img = img_byte.nbytes print('Data size per image is: ', data_size_per_img) data_size = data_size_per_img * len(img_path_list) env = lmdb.open(lmdb_path, map_size=data_size * 10) # write data to lmdb prog_bar = mmengine.ProgressBar(len(img_path_list)) txn = env.begin(write=True) txt_file = open(osp.join(lmdb_path, 'meta_info.txt'), 'w') for idx, (path, key) in enumerate(zip(img_path_list, keys)): prog_bar.update() key_byte = key.encode('ascii') if multiprocessing_read: img_byte = dataset[key] h, w, c = shapes[key] else: _, img_byte, img_shape = read_img_worker( osp.join(data_path, path), key, compress_level) h, w, c = img_shape txn.put(key_byte, img_byte) # write meta information txt_file.write(f'{key}.png ({h},{w},{c}) {compress_level}\n') if idx % batch == 0: txn.commit() txn = env.begin(write=True) txn.commit() env.close() txt_file.close() print('\nFinish writing lmdb.') def read_img_worker(path, key, compress_level): """Read image worker. Args: path (str): Image path. key (str): Image key. compress_level (int): Compress level when encoding images. Returns: str: Image key. byte: Image byte. tuple[int]: Image shape. """ img = mmcv.imread(path, flag='unchanged') if img.ndim == 2: h, w = img.shape c = 1 else: h, w, c = img.shape _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) return (key, img_byte, (h, w, c)) def parse_args(): parser = argparse.ArgumentParser( description='Prepare DIV2K dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') parser.add_argument( '--anno-train-path', nargs='?', default='meta_info_DIV2K800sub_GT.txt', type=str, help='annotation file path of train dataset') parser.add_argument( '--anno-test-path', nargs='?', default='meta_info_DIV2K100sub_GT.txt', type=str, help='annotation file path of test dataset') parser.add_argument( '--scales', nargs='*', default=[2, 3, 4], type=int, help='scale factor list') parser.add_argument( '--crop-size', nargs='?', default=480, type=int, help='cropped size for HR images') parser.add_argument( '--step', nargs='?', default=240, type=int, help='step size for HR images') parser.add_argument( '--thresh-size', nargs='?', default=0, type=int, help='threshold size for HR images') parser.add_argument( '--compression-level', nargs='?', default=3, type=int, help='compression level when save png images') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') parser.add_argument( '--make-lmdb', action='store_true', help='whether to prepare lmdb files') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() # extract subimages main_extract_subimages(args) # generate annotation files generate_anno_file(args) # prepare lmdb files if necessary if args.make_lmdb: make_lmdb_for_div2k(args.data_root) ================================================ FILE: tools/dataset_converters/dpdd/README.md ================================================ # Preparing DPDD Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The test datasets can be download from [here](https://drive.google.com/file/d/1dDWUQ_D93XGtcywoUcZE1HOXCV4EuLyw/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── DPDD |   |   ├── inputL |   |   ├── inputR |   |   ├── inputC |   |   ├── target |   |   ├── indoor_labels.npy |   |   ├── indoor_labels.txt |   |   ├── outdoor_labels.npy |   |   ├── outdoor_labels.txt ``` ================================================ FILE: tools/dataset_converters/dpdd/README_zh-CN.md ================================================ # 准备 DPDD 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 测试数据集可以从 [此处](https://drive.google.com/file/d/1dDWUQ_D93XGtcywoUcZE1HOXCV4EuLyw/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── DPDD |   |   ├── inputL |   |   ├── inputR |   |   ├── inputC |   |   ├── target |   |   ├── indoor_labels.npy |   |   ├── indoor_labels.txt |   |   ├── outdoor_labels.npy |   |   ├── outdoor_labels.txt ``` ================================================ FILE: tools/dataset_converters/glean/README.md ================================================ # Preparing GLEAN Dataset ```bibtex @InProceedings{chan2021glean, author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ``` ## Preparing cat_train dataset 1. Download [cat dataset](http://dl.yf.io/lsun/objects/cat.zip) from [LSUN homepage](https://www.yf.io/p/lsun) 2. Download [cat_train/meta_info_LSUNcat_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_train/meta_info_LSUNcat_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) 3. Export and downsample images Export images from lmdb file and resize the input images to the designated size. We provide such a script: ```shell python tools/dataset_converters/glean/preprocess_cat_train_dataset.py --lmdb-path .data/cat --meta-file-path ./data/cat_train/meta_info_LSUNcat_GT.txt --out-dir ./data/cat_train ``` The generated data is stored under `cat_train` and the folder structure is as follows. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── cat_train │ │ ├── GT │ │ ├── BIx8_down │ │ ├── BIx16_down │ │ ├── meta_info_LSUNcat_GT.txt ... ``` ## Preparing cat_test dataset 1. Download [CAT dataset](https://archive.org/download/CAT_DATASET/CAT_DATASET_02.zip) from [here](https://archive.org/details/CAT_DATASET). 2. Download [cat_test/meta_info_Cat100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_test/meta_info_Cat100_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) 3. Downsample images Resize the input images to the designated size. We provide such a script: ```shell python tools/dataset_converters/glean/preprocess_cat_test_dataset.py --data-path ./data/CAT_03 --meta-file-path ./data/cat_test/meta_info_Cat100_GT.txt --out-dir ./data/cat_test ``` The generated data is stored under `cat_test` and the folder structure is as follows. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── cat_test │ │ ├── GT │ │ ├── BIx8_down │ │ ├── BIx16_down │ │ ├── meta_info_Cat100_GT.txt ... ``` ## Preparing FFHQ dataset 1. Download [FFHQ dataset (images1024x1024)](https://drive.google.com/drive/folders/1tZUcXDBeOibC6jcMCtgRRz67pzrAHeHL) from it's [homepage](https://github.com/NVlabs/ffhq-dataset) Then you can refactor the folder structure looks like: ```text ffhq ├── images |   ├── 00000.png |   ├── 00001.png |   ├── ... |   ├── 69999.png ``` 2. Download [ffhq/meta_info_FFHQ_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/FFHQ/meta_info_FFHQ_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) 3. Downsample images Resize the input images to the designated size. We provide such a script: ```shell python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/ffhq/images ``` The generated data is stored under `ffhq` and the folder structure is as follows. ```text mmagic ├── mmagic ├── tools ├── configs ├── data | ├── ffhq | | ├── images │ │ ├── BIx8_down | | ├── BIx16_down | | ├── meta_info_FFHQ_GT.txt ... ``` ## Preparing CelebA-HQ dataset 1. Preparing datasets following it's [homepage](https://github.com/tkarras/progressive_growing_of_gans) Then you can refactor the folder structure looks like: ```text CelebA-HQ ├── GT |   ├── 00000.png |   ├── 00001.png |   ├── ... |   ├── 30000.png ``` 2. Download [CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) 3. Downsample images Resize the input images to the designated size. We provide such a script: ```shell python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/CelebA-HQ/GT ``` The generated data is stored under `CelebA-HQ` and the folder structure is as follows. ```text mmagic ├── mmagic ├── tools ├── configsdata ├── data | ├── CelebA-HQ | | ├── GT │ │ ├── BIx8_down | | ├── BIx16_down | | ├── meta_info_CelebAHQ_val100_GT.txt ... ``` ## Preparing FFHQ_CelebAHQ dataset We merge FFHQ(`ffhq/images`) and CelebA-HQ(`CelebA-HQ/GT`) to generate FFHQ_CelebAHQ dataset. The folder structure should looks like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data | ├── FFHQ_CelebAHQ | | ├── GT ... ``` ================================================ FILE: tools/dataset_converters/glean/README_zh-CN.md ================================================ # 准备 GLEAN 数据集 ```bibtex @InProceedings{chan2021glean, author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, year = {2021} } ``` ## 准备 cat_train 数据集 1. 从[LSUN 主页](https://www.yf.io/p/lsun)下载[cat 数据集](http://dl.yf.io/lsun/objects/cat.zip)。 2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[cat_train/meta_info_LSUNcat_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_train/meta_info_LSUNcat_GT.txt)。 3. 导出图像并下采样 从 lmdb 文件中导出图像,并下采样到所需尺寸。为此,我们提供了一个脚本: ```shell python tools/dataset_converters/glean/preprocess_cat_train_dataset.py --lmdb-path .data/cat --meta-file-path ./data/cat_train/meta_info_LSUNcat_GT.txt --out-dir ./data/cat_train ``` 生成的数据存储在 `cat_train` 目录下,目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── cat_train │ │ ├── GT │ │ ├── BIx8_down │ │ ├── BIx16_down │ │ ├── meta_info_LSUNcat_GT.txt ... ``` ## 准备 cat_test 数据集 1. 从数据集[主页](https://archive.org/details/CAT_DATASET)下载[CAT 数据集](https://archive.org/download/CAT_DATASET/CAT_DATASET_02.zip)。 2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[cat_test/meta_info_Cat100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_test/meta_info_Cat100_GT.txt)。 3. 下采样 将图像下采样到所需尺寸。为此,我们提供了一个脚本: ```shell python tools/dataset_converters/glean/preprocess_cat_test_dataset.py --data-path ./data/CAT_03 --meta-file-path ./data/cat_test/meta_info_Cat100_GT.txt --out-dir ./data/cat_test ``` 生成的数据存储在 `cat_test` 目录下,目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── cat_test │ │ ├── GT │ │ ├── BIx8_down │ │ ├── BIx16_down │ │ ├── meta_info_Cat100_GT.txt ... ``` ## 准备 FFHQ 数据集 1. 从数据集[主页](https://github.com/NVlabs/ffhq-dataset)下载[FFHQ 数据集 (images1024x1024)](https://drive.google.com/drive/folders/1tZUcXDBeOibC6jcMCtgRRz67pzrAHeHL)。 将文件目录重构为如下所示: ```text ffhq ├── images |   ├── 00000.png |   ├── 00001.png |   ├── ... |   ├── 69999.png ``` 2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[ffhq/meta_info_FFHQ_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/FFHQ/meta_info_FFHQ_GT.txt)。 3. 下采样 将图像下采样到所需尺寸。为此,我们提供了一个脚本: ```shell python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/ffhq/images ``` 生成的数据存储在 `ffhq` 目录下,目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data | ├── ffhq | | ├── images │ │ ├── BIx8_down | | ├── BIx16_down | | ├── meta_info_FFHQ_GT.txt ... ``` ## 准备 CelebA-HQ 数据集 1. 根据数据集[主页](https://github.com/tkarras/progressive_growing_of_gans)文档准备数据集。 将文件目录重构为如下所示: ```text CelebA-HQ ├── GT |   ├── 00000.png |   ├── 00001.png |   ├── ... |   ├── 30000.png ``` 2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt)。 3. 下采样 将图像下采样到所需尺寸。为此,我们提供了一个脚本: ```shell python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/CelebA-HQ/GT ``` 生成的数据存储在 `CelebA-HQ` 目录下,目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configsdata ├── data | ├── CelebA-HQ | | ├── GT │ │ ├── BIx8_down | | ├── BIx16_down | | ├── meta_info_CelebAHQ_val100_GT.txt ... ``` ## 准备 FFHQ_CelebAHQ 数据集 将 FFHQ(`ffhq/images`) 和 CelebA-HQ(`CelebA-HQ/GT`) 合并,生成 FFHQ_CelebAHQ 数据集。 文件目录重构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data | ├── FFHQ_CelebAHQ | | ├── GT ... ``` ================================================ FILE: tools/dataset_converters/glean/preprocess_cat_test_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp from multiprocessing import Pool import mmengine import numpy as np from skimage import img_as_float from skimage.io import imread, imsave from mmagic.datasets.transforms import MATLABLikeResize def imresize(img_path, output_path, scale=None, output_shape=None): """Resize the image using MATLAB-like downsampling. Args: img_path (str): Input image path. output_path (str): Output image path. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. """ matlab_resize = MATLABLikeResize( keys=['data'], scale=scale, output_shape=output_shape) img = imread(img_path) img = img_as_float(img) data = {'data': img} output = matlab_resize(data)['data'] output = np.clip(output, 0.0, 1.0) * 255 output = np.around(output).astype(np.uint8) imsave(output_path, output) def worker(img_name, args): """Worker for each process. Args: img_name (str): Image filename. Returns: process_info (str): Process information displayed in progress bar. """ gt_dir = osp.join(args.out_dir, 'GT') bix8_dir = osp.join(args.out_dir, 'BIx8_down') bix16_dir = osp.join(args.out_dir, 'BIx16_down') new_img_name = img_name + '.png' imresize( osp.join(args.data_path, img_name + '.jpg'), osp.join(gt_dir, new_img_name), output_shape=(256, 256)) imresize( osp.join(gt_dir, new_img_name), osp.join(bix8_dir, new_img_name), scale=1 / 8) imresize( osp.join(gt_dir, new_img_name), osp.join(bix16_dir, new_img_name), scale=1 / 16) process_info = f'Processing {new_img_name} ...' return process_info def downsample_images(args): """Downsample images for cat_test datasets from the ground-truth.""" meta_file = open(args.meta_file_path, 'r') img_list = [_.split('.')[0] for _ in meta_file.readlines()] prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(args.n_thread) for path in img_list: pool.apply_async( worker, args=(path, args), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def parse_args(): parser = argparse.ArgumentParser( description='Prepare cat dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-path', help='dataset root') parser.add_argument('--meta-file-path', help='meta file path') parser.add_argument('--out-dir', help='output directory of dataset') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() if not osp.exists(args.out_dir): os.makedirs(args.out_dir) gt_dir = osp.join(args.out_dir, 'GT') bix8_dir = osp.join(args.out_dir, 'BIx8_down') bix16_dir = osp.join(args.out_dir, 'BIx16_down') if not osp.exists(gt_dir): os.makedirs(gt_dir) if not osp.exists(bix8_dir): os.makedirs(bix8_dir) if not osp.exists(bix16_dir): os.makedirs(bix16_dir) # downsample images downsample_images(args) ================================================ FILE: tools/dataset_converters/glean/preprocess_cat_train_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp from multiprocessing import Pool import lmdb import mmengine import numpy as np from PIL import Image from skimage import img_as_float from skimage.io import imread, imsave from mmagic.datasets.transforms import MATLABLikeResize def export_images(lmdb_path, meta_file_path, out_dir): """Export images from lmdb file. Ref: https://github.com/fyu/lsun Args: lmdb_path (str): Lmdb file path. meta_file_path (str): Meta file path. out_dir (str): Output directory of dataset. """ print('Exporting', lmdb_path, 'to', out_dir) env = lmdb.open( lmdb_path, map_size=1099511627776, max_readers=100, readonly=True) meta_file = open(meta_file_path, 'r') img_list = [_.split('.')[0] for _ in meta_file.readlines()] txn = env.begin(write=False) cursor = txn.cursor() count = 0 for key, val in cursor: if key.decode('ascii') in img_list: image_out_path = osp.join(out_dir, key.decode('ascii') + '.webp') with open(image_out_path, 'wb') as fp: fp.write(val) count += 1 if count % 1000 == 0: print('Finished', count, 'images') if count > len(img_list): break print('\nFinish exporting images.') def imresize(img_path, output_path, scale=None, output_shape=None): """Resize the image using MATLAB-like downsampling. Args: img_path (str): Input image path. output_path (str): Output image path. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. """ matlab_resize = MATLABLikeResize( keys=['data'], scale=scale, output_shape=output_shape) img = imread(img_path) img = img_as_float(img) data = {'data': img} output = matlab_resize(data)['data'] output = np.clip(output, 0.0, 1.0) * 255 output = np.around(output).astype(np.uint8) imsave(output_path, output) def worker(img_name, out_dir): """Worker for each process. Args: img_name (str): Image filename. out_dir (str): Output directory of dataset. Returns: process_info (str): Process information displayed in progress bar. """ _gt_dir = osp.join(out_dir, '_GT') gt_dir = osp.join(out_dir, 'GT') bix8_dir = osp.join(out_dir, 'BIx8_down') bix16_dir = osp.join(out_dir, 'BIx16_down') new_img_name = img_name + '.png' img = Image.open(osp.join(_gt_dir, img_name + '.webp')) img.load() img.save(osp.join(_gt_dir, new_img_name)) imresize( osp.join(_gt_dir, new_img_name), osp.join(gt_dir, new_img_name), output_shape=(256, 256)) imresize( osp.join(gt_dir, new_img_name), osp.join(bix8_dir, new_img_name), scale=1 / 8) imresize( osp.join(gt_dir, new_img_name), osp.join(bix16_dir, new_img_name), scale=1 / 16) process_info = f'Processing {new_img_name} ...' return process_info def downsample_images(args): """Downsample images for cat_train datasets from the ground-truth.""" meta_file = open(args.meta_file_path, 'r') img_list = [_.split('.')[0] for _ in meta_file.readlines()] prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(args.n_thread) for path in img_list: pool.apply_async( worker, args=(path, args.out_dir), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def parse_args(): parser = argparse.ArgumentParser( description='Prepare cat dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--lmdb-path', help='lmdb file path') parser.add_argument('--meta-file-path', help='meta file path') parser.add_argument('--out-dir', help='output directory of dataset') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() if not osp.exists(args.out_dir): os.makedirs(args.out_dir) _gt_dir = osp.join(args.out_dir, '_GT') gt_dir = osp.join(args.out_dir, 'GT') bix8_dir = osp.join(args.out_dir, 'BIx8_down') bix16_dir = osp.join(args.out_dir, 'BIx16_down') if not osp.exists(_gt_dir): os.makedirs(_gt_dir) if not osp.exists(gt_dir): os.makedirs(gt_dir) if not osp.exists(bix8_dir): os.makedirs(bix8_dir) if not osp.exists(bix16_dir): os.makedirs(bix16_dir) # export images export_images(args.lmdb_path, args.meta_file_path, _gt_dir) # downsample images downsample_images(args) ================================================ FILE: tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp from multiprocessing import Pool import mmengine import numpy as np from skimage import img_as_float from skimage.io import imread, imsave from mmagic.datasets.transforms import MATLABLikeResize def imresize(img_path, output_path, scale=None, output_shape=None): """Resize the image using MATLAB-like downsampling. Args: img_path (str): Input image path. output_path (str): Output image path. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. """ matlab_resize = MATLABLikeResize( keys=['data'], scale=scale, output_shape=output_shape) img = imread(img_path) img = img_as_float(img) data = {'data': img} output = matlab_resize(data)['data'] output = np.clip(output, 0.0, 1.0) * 255 output = np.around(output).astype(np.uint8) imsave(output_path, output) def worker(img_name, args): """Worker for each process. Args: img_name (str): Image filename. Returns: process_info (str): Process information displayed in progress bar. """ gt_dir = args.data_root bix8_dir = osp.join(gt_dir, '../BIx8_down') bix16_dir = osp.join(gt_dir, '../BIx16_down') imresize( osp.join(gt_dir, img_name), osp.join(bix8_dir, img_name), scale=1 / 8) imresize( osp.join(gt_dir, img_name), osp.join(bix16_dir, img_name), scale=1 / 16) process_info = f'Processing {img_name} ...' return process_info def downsample_images(args): """Downsample images from the ground-truth.""" img_list = sorted(os.listdir(args.data_root)) prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(args.n_thread) for path in img_list: pool.apply_async( worker, args=(path, args), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def parse_args(): parser = argparse.ArgumentParser( description='Prepare ffhq dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() bix8_dir = osp.join(args.data_root, '../BIx8_down') bix16_dir = osp.join(args.data_root, '../BIx16_down') if not osp.exists(bix16_dir): os.makedirs(bix16_dir) if not osp.exists(bix8_dir): os.makedirs(bix8_dir) # downsample images downsample_images(args) ================================================ FILE: tools/dataset_converters/gopro/README.md ================================================ # Preparing GoPro Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The train datasets can be download from [here](https://drive.google.com/file/d/1zgALzrLCC_tcXKu_iHQTHukKUVT1aodI/). The test datasets can be download from [here](https://drive.google.com/file/d/1k6DTSHu4saUgrGTYkkZXTptILyG9RRll/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── GoPro |   |   ├── train |   |   | ├── blur |   |   | ├── sharp |   |   ├── test |   |   | ├── blur |   |   | ├── sharp ``` ================================================ FILE: tools/dataset_converters/gopro/README_zh-CN.md ================================================ # 准备 GoPro 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 训练数据集可以从 [此处](https://drive.google.com/file/d/1zgALzrLCC_tcXKu_iHQTHukKUVT1aodI/) 下载。测试数据集可以从 [此处](https://drive.google.com/file/d/1k6DTSHu4saUgrGTYkkZXTptILyG9RRll/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── GoPro |   |   ├── train |   |   | ├── blur |   |   | ├── sharp |   |   ├── test |   |   | ├── blur |   |   | ├── sharp ``` ================================================ FILE: tools/dataset_converters/hide/README.md ================================================ # Preparing HIDE Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The test datasets can be download from [here](https://drive.google.com/file/d/1XRomKYJF1H92g1EuD06pCQe4o6HlwB7A/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── HIDE |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/hide/README_zh-CN.md ================================================ # 准备 HIDE 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 测试数据集可以从 [此处](https://drive.google.com/file/d/1XRomKYJF1H92g1EuD06pCQe4o6HlwB7A/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── HIDE |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/live1/README.md ================================================ # Preparing LIVE1 Dataset ```bibtex @article{zhang2017beyond, title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, journal={IEEE Transactions on Image Processing}, year={2017}, volume={26}, number={7}, pages={3142-3155}, } ``` The test datasets can be download from [here](https://github.com/cszn/DnCNN/tree/master/testsets). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── LIVE1 ``` ================================================ FILE: tools/dataset_converters/live1/README_zh-CN.md ================================================ # 准备 LIVE1 数据集 ```bibtex @article{zhang2017beyond, title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, journal={IEEE Transactions on Image Processing}, year={2017}, volume={26}, number={7}, pages={3142-3155}, } ``` 测试数据集可以从 [此处](https://github.com/cszn/DnCNN/tree/master/testsets) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── LIVE1 ``` ================================================ FILE: tools/dataset_converters/ntire21_decompression/README.md ================================================ # Preparing NTIRE21 decompression Dataset ```bibtex @inproceedings{yang2021dataset, title={{NTIRE 2021} Challenge on Quality Enhancement of Compressed Video: Dataset and Study}, author={Ren Yang and Radu Timofte}, booktitle={IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops}, year={2021} } ``` The test datasets can be download from it's [Homepage](https://github.com/RenYang-home/NTIRE21_VEnh). Please follows the tutorials of the [Homepage](https://github.com/RenYang-home/NTIRE21_VEnh) to generate datasets. The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── NTIRE21_decompression_track1 |   |   ├── GT |   |   | ├── 001 |   |   | | ├── 001.png |   |   | | ├── ... |   |   | ├── ... |   |   | ├── 010 |   |   ├── LQ |   |   | ├── 001 |   |   | | ├── 001.png |   |   | | ├── ... |   |   | ├── ... |   |   | ├── 010 |   ├── NTIRE21_decompression_track2 |   |   ├── GT |   |   ├── LQ |   ├── NTIRE21_decompression_track3 |   |   ├── GT |   |   ├── LQ ``` ================================================ FILE: tools/dataset_converters/ntire21_decompression/README_zh-CN.md ================================================ # 准备 NTIRE21 decompression 数据集 ```bibtex @inproceedings{yang2021dataset, title={{NTIRE 2021} Challenge on Quality Enhancement of Compressed Video: Dataset and Study}, author={Ren Yang and Radu Timofte}, booktitle={IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops}, year={2021} } ``` 测试数据集可以从其[主页](https://github.com/RenYang-home/NTIRE21_VEnh)下载。 请按照[主页](https://github.com/RenYang-home/NTIRE21_VEnh)教程生成数据集。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── NTIRE21_decompression_track1 |   |   ├── GT |   |   | ├── 001 |   |   | | ├── 001.png |   |   | | ├── ... |   |   | ├── ... |   |   | ├── 010 |   |   ├── LQ |   |   | ├── 001 |   |   | | ├── 001.png |   |   | | ├── ... |   |   | ├── ... |   |   | ├── 010 |   ├── NTIRE21_decompression_track2 |   |   ├── GT |   |   ├── LQ |   ├── NTIRE21_decompression_track3 |   |   ├── GT |   |   ├── LQ ``` ================================================ FILE: tools/dataset_converters/paired-pix2pix/README.md ================================================ # Preparing Paired Dataset for Pix2pix ```bibtex @inproceedings{isola2017image, title={Image-to-image translation with conditional adversarial networks}, author={Isola, Phillip and Zhu, Jun-Yan and Zhou, Tinghui and Efros, Alexei A}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={1125--1134}, year={2017} } ``` You can download paired datasets from [here](http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/). Then, you need to unzip and move corresponding datasets to follow the folder structure shown above. The datasets have been well-prepared by the original authors. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── paired │ │ ├── facades │ │ ├── maps | | ├── edges2shoes | | | ├── train | | | ├── test ``` ================================================ FILE: tools/dataset_converters/paired-pix2pix/README_zh-CN.md ================================================ # 为 Pix2pix 准备配对数据集 ```bibtex @inproceedings{isola2017image, title={Image-to-image translation with conditional adversarial networks}, author={Isola, Phillip and Zhu, Jun-Yan and Zhou, Tinghui and Efros, Alexei A}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={1125--1134}, year={2017} } ``` 您可以从[此处](http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/)下载配对数据集。然后,您需要解压缩并移动相应的数据集以遵循如下所示的文件夹结构。数据集已经由原作者准备好了。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── paired │ │ ├── facades │ │ ├── maps | | ├── edges2shoes | | | ├── train | | | ├── test ``` ================================================ FILE: tools/dataset_converters/paris-street-view/README.md ================================================ # Preparing Paris Street View Dataset ```bibtex @inproceedings{pathak2016context, title={Context encoders: Feature learning by inpainting}, author={Pathak, Deepak and Krahenbuhl, Philipp and Donahue, Jeff and Darrell, Trevor and Efros, Alexei A}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2536--2544}, year={2016} } ``` Obtain the dataset [here](https://github.com/pathak22/context-encoder/issues/24). ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── paris_street_view │ │ ├── train | | ├── val ``` ================================================ FILE: tools/dataset_converters/paris-street-view/README_zh-CN.md ================================================ # 准备 Paris Street View 数据集 ```bibtex @inproceedings{pathak2016context, title={Context encoders: Feature learning by inpainting}, author={Pathak, Deepak and Krahenbuhl, Philipp and Donahue, Jeff and Darrell, Trevor and Efros, Alexei A}, booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, pages={2536--2544}, year={2016} } ``` 请从[此处](https://github.com/pathak22/context-encoder/issues/24)获取数据集。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── paris_street_view │ │ ├── train | | ├── val ``` ================================================ FILE: tools/dataset_converters/places365/README.md ================================================ # Preparing Places365 Dataset ```bibtex @article{zhou2017places, title={Places: A 10 million Image Database for Scene Recognition}, author={Zhou, Bolei and Lapedriza, Agata and Khosla, Aditya and Oliva, Aude and Torralba, Antonio}, journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, year={2017}, publisher={IEEE} } ``` Prepare the data from [Places365](http://places2.csail.mit.edu/download.html). ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── Places │ │ ├── data_large │ │ ├── val_large | | ├── meta | | | ├── places365_train_challenge.txt | | | ├── places365_val.txt ``` ================================================ FILE: tools/dataset_converters/places365/README_zh-CN.md ================================================ # 准备 Places365 数据集 ```bibtex @article{zhou2017places, title={Places: A 10 million Image Database for Scene Recognition}, author={Zhou, Bolei and Lapedriza, Agata and Khosla, Aditya and Oliva, Aude and Torralba, Antonio}, journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, year={2017}, publisher={IEEE} } ``` 请从 [Places365](http://places2.csail.mit.edu/download.html) 下载并准备数据。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── Places │ │ ├── data_large │ │ ├── val_large | | ├── meta | | | ├── places365_train_challenge.txt | | | ├── places365_val.txt ``` ================================================ FILE: tools/dataset_converters/realblur/README.md ================================================ # Preparing RealBlur Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The test datasets RealBlurR can be download from [here](https://drive.google.com/file/d/1glgeWXCy7Y0qWDc0MXBTUlZYJf8984hS/). The test datasets RealBlurJ can be download from [here](https://drive.google.com/file/d/1Rb1DhhXmX7IXfilQ-zL9aGjQfAAvQTrW/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── RealBlur_R |   |   ├── input |   |   ├── target |   ├── RealBlur_J |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/realblur/README_zh-CN.md ================================================ # 准备 RealBlur 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 测试数据集 RealBlurR 可以从 [此处](https://drive.google.com/file/d/1glgeWXCy7Y0qWDc0MXBTUlZYJf8984hS/) 下载。 测试数据集 RealBlurJ 可以从 [此处](https://drive.google.com/file/d/1Rb1DhhXmX7IXfilQ-zL9aGjQfAAvQTrW/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── RealBlur_R |   |   ├── input |   |   ├── target |   ├── RealBlur_J |   |   ├── input |   |   ├── target ``` ================================================ FILE: tools/dataset_converters/realsrset/README.md ================================================ # Preparing RealSRSet Dataset ```bibtex @inproceedings{zhang2021designing, title={Designing a Practical Degradation Model for Deep Blind Image Super-Resolution}, author={Zhang, Kai and Liang, Jingyun and Van Gool, Luc and Timofte, Radu}, booktitle={IEEE International Conference on Computer Vision}, pages={4791--4800}, year={2021} } ``` The datasets RealSRSet can be download from [here](https://github.com/cszn/BSRGAN/tree/main/testsets/RealSRSet). The datasets RealSRSet+5images can be download from [here](https://github.com/JingyunLiang/SwinIR/releases/download/v0.0/RealSRSet+5images.zip). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── realsrset |   ├── RealSRSet+5images ``` ================================================ FILE: tools/dataset_converters/realsrset/README_zh-CN.md ================================================ # 准备 RealSRSet 数据集 ```bibtex @inproceedings{zhang2021designing, title={Designing a Practical Degradation Model for Deep Blind Image Super-Resolution}, author={Zhang, Kai and Liang, Jingyun and Van Gool, Luc and Timofte, Radu}, booktitle={IEEE International Conference on Computer Vision}, pages={4791--4800}, year={2021} } ``` 数据集 RealSRSet 可以从 [此处](https://github.com/cszn/BSRGAN/tree/main/testsets/RealSRSet) 下载。 数据集 RealSRSet+5images 可以从 [此处](https://github.com/JingyunLiang/SwinIR/releases/download/v0.0/RealSRSet+5images.zip) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── realsrset |   ├── RealSRSet+5images ``` ================================================ FILE: tools/dataset_converters/reds/README.md ================================================ # Preparing REDS Dataset ```bibtex @InProceedings{Nah_2019_CVPR_Workshops_REDS, author = {Nah, Seungjun and Baik, Sungyong and Hong, Seokil and Moon, Gyeongsik and Son, Sanghyun and Timofte, Radu and Lee, Kyoung Mu}, title = {NTIRE 2019 Challenge on Video Deblurring and Super-Resolution: Dataset and Study}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR) Workshops}, month = {June}, year = {2019} } ``` - Training dataset: [REDS dataset](https://seungjunnah.github.io/Datasets/reds.html). - Validation dataset: [REDS dataset](https://seungjunnah.github.io/Datasets/reds.html) and Vid4. Note that we merge train and val datasets in REDS for easy switching between REDS4 partition (used in EDVR) and the official validation partition. The original val dataset (clip names from 000 to 029) are modified to avoid conflicts with training dataset (total 240 clips). Specifically, the clip names are changed to 240, 241, ... 269. You can prepare the REDS dataset by running: ```shell python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS ``` ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── REDS │ │ ├── train_sharp │ │ │ ├── 000 │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic │ │ │ ├── X4 │ │ │ | ├── 000 │ │ │ | ├── 001 │ │ │ | ├── ... │ │ ├── meta_info_reds4_train.txt │ │ ├── meta_info_reds4_val.txt │ │ ├── meta_info_official_train.txt │ │ ├── meta_info_official_val.txt │ │ ├── meta_info_REDS_GT.txt │ ├── REDS4 │ │ ├── GT │ │ ├── sharp_bicubic ``` ## Prepare LMDB dataset for REDS If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb ``` ## Crop to sub-images MMagic also supports cropping REDS images to sub-images for faster IO. We provide such a script: ```shell python tools/dataset_converters/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 ``` The generated data is stored under `REDS` and the data structure is as follows, where `_sub` indicates the sub-images. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── REDS │ │ ├── train_sharp │ │ │ ├── 000 │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_sub │ │ │ ├── 000_s001 │ │ │ ├── 000_s002 │ │ │ ├── ... │ │ │ ├── 001_s001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic │ │ │ ├── X4 │ │ │ │ ├── 000 │ │ │ │ ├── 001 │ │ │ │ ├── ... │ │ │ ├── X4_sub │ │ │ ├── 000_s001 │ │ │ ├── 000_s002 │ │ │ ├── ... │ │ │ ├── 001_s001 │ │ │ ├── ... ``` Note that by default `preprocess_reds_dataset.py` does not make lmdb and annotation file for the cropped dataset. You may need to modify the scripts a little bit for such operations. ================================================ FILE: tools/dataset_converters/reds/README_zh-CN.md ================================================ # 准备 REDS 数据集 ```bibtex @InProceedings{Nah_2019_CVPR_Workshops_REDS, author = {Nah, Seungjun and Baik, Sungyong and Hong, Seokil and Moon, Gyeongsik and Son, Sanghyun and Timofte, Radu and Lee, Kyoung Mu}, title = {NTIRE 2019 Challenge on Video Deblurring and Super-Resolution: Dataset and Study}, booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR) Workshops}, month = {June}, year = {2019} } ``` - 训练集: [REDS 数据集](https://seungjunnah.github.io/Datasets/reds.html). - 验证集: [REDS 数据集](https://seungjunnah.github.io/Datasets/reds.html) 和 Vid4. 请注意,我们合并了 REDS 的训练集和验证集,以便在 REDS4 划分(在 `EDVR` 中会使用到)和官方验证集划分之间切换。 原始验证集的名称被修改了(clip 000 到 029),以避免与训练集发生冲突(总共 240 个 clip)。具体而言,验证集中的 clips 被改名为 240、241、... 269。 可通过运行以下命令来准备 REDS 数据集: ```shell python tools/dataset_converters/reds/preprocess_reds_dataset.py ./data/REDS ``` ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── REDS │ │ ├── train_sharp │ │ │ ├── 000 │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic │ │ │ ├── X4 │ │ │ | ├── 000 │ │ │ | ├── 001 │ │ │ | ├── ... │ │ ├── meta_info_reds4_train.txt │ │ ├── meta_info_reds4_val.txt │ │ ├── meta_info_official_train.txt │ │ ├── meta_info_official_val.txt │ │ ├── meta_info_REDS_GT.txt │ ├── REDS4 │ │ ├── GT │ │ ├── sharp_bicubic ``` ## 准备 LMDB 格式的 REDS 数据集 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件: ```shell python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb ``` ## 裁剪为子图 MMagic 支持将 REDS 图像裁剪为子图像以加快 IO。我们提供了这样一个脚本: ```shell python tools/dataset_converters/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 ``` 生成的数据存储在 `REDS` 下,数据结构如下,其中`_sub`表示子图像。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── REDS │ │ ├── train_sharp │ │ │ ├── 000 │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_sub │ │ │ ├── 000_s001 │ │ │ ├── 000_s002 │ │ │ ├── ... │ │ │ ├── 001_s001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic │ │ │ ├── X4 │ │ │ │ ├── 000 │ │ │ │ ├── 001 │ │ │ │ ├── ... │ │ │ ├── X4_sub │ │ │ ├── 000_s001 │ │ │ ├── 000_s002 │ │ │ ├── ... │ │ │ ├── 001_s001 │ │ │ ├── ... ``` 请注意,默认情况下,`preprocess_reds_dataset.py` 不会为裁剪后的数据集制作 lmdb 和注释文件。您可能需要为此类操作稍微修改脚本。 ================================================ FILE: tools/dataset_converters/reds/crop_sub_images.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import re import sys from multiprocessing import Pool import cv2 import mmcv import mmengine import numpy as np def worker(path, opt): """Worker for each process. Args: path (str): Image path. opt (dict): Configuration dict. It contains: crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is smaller than thresh_size will be dropped. save_folder (str): Path to save folder. compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION. Returns: process_info (str): Process information displayed in progress bar. """ crop_size = opt['crop_size'] step = opt['step'] thresh_size = opt['thresh_size'] sequence, img_name = re.split(r'[\\/]', path)[-2:] img_name, extension = osp.splitext(osp.basename(path)) img = mmcv.imread(path, flag='unchanged') if img.ndim == 2 or img.ndim == 3: h, w = img.shape[:2] else: raise ValueError(f'Image ndim should be 2 or 3, but got {img.ndim}') h_space = np.arange(0, h - crop_size + 1, step) if h - (h_space[-1] + crop_size) > thresh_size: h_space = np.append(h_space, h - crop_size) w_space = np.arange(0, w - crop_size + 1, step) if w - (w_space[-1] + crop_size) > thresh_size: w_space = np.append(w_space, w - crop_size) index = 0 for x in h_space: for y in w_space: index += 1 cropped_img = img[x:x + crop_size, y:y + crop_size, ...] sub_folder = osp.join(opt['save_folder'], f'{sequence}_s{index:03d}') mmengine.mkdir_or_exist(sub_folder) cv2.imwrite( osp.join(sub_folder, f'{img_name}{extension}'), cropped_img, [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']]) process_info = f'Processing {img_name} ...' return process_info def extract_subimages(opt): """Crop images to subimages. Args: opt (dict): Configuration dict. It contains: input_folder (str): Path to the input folder. save_folder (str): Path to save folder. n_thread (int): Thread number. """ input_folder = opt['input_folder'] save_folder = opt['save_folder'] if not osp.exists(save_folder): os.makedirs(save_folder) print(f'mkdir {save_folder} ...') else: print(f'Folder {save_folder} already exists. Exit.') sys.exit(1) img_list = list(mmengine.scandir(input_folder, recursive=True)) img_list = [osp.join(input_folder, v) for v in img_list] prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(opt['n_thread']) for path in img_list: pool.apply_async( worker, args=(path, opt), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def main_extract_subimages(args): """A multi-thread tool to crop large images to sub-images for faster IO. It is used for REDS dataset. opt (dict): Configuration dict. It contains: n_thread (int): Thread number. compression_level (int): CV_IMWRITE_PNG_COMPRESSION from 0 to 9. A higher value means a smaller size and longer compression time. Use 0 for faster CPU decompression. Default: 3, same in cv2. scales (list[int]): The downsampling factors corresponding to the LR folders you want to process. Default: []. input_folder (str): Path to the input folder. save_folder (str): Path to save folder. crop_size (int): Crop size. step (int): Step for overlapped sliding window. thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped. Usage: For each folder, run this script. For example, if scales = [4], there are two folders to be processed: train_sharp train_sharp_bicubic/X4 After process, each sub_folder should have the same number of subimages. You can also specify scales by modifying the argument 'scales'. Remember to modify opt configurations according to your settings. """ opt = {} opt['n_thread'] = args.n_thread opt['compression_level'] = args.compression_level # HR images opt['input_folder'] = osp.join(args.data_root, 'train_sharp') opt['save_folder'] = osp.join(args.data_root, 'train_sharp_sub') opt['crop_size'] = args.crop_size opt['step'] = args.step opt['thresh_size'] = args.thresh_size extract_subimages(opt) for scale in args.scales: opt['input_folder'] = osp.join(args.data_root, f'train_sharp_bicubic/X{scale}') opt['save_folder'] = osp.join(args.data_root, f'train_sharp_bicubic/X{scale}_sub') opt['crop_size'] = args.crop_size // scale opt['step'] = args.step // scale opt['thresh_size'] = args.thresh_size // scale extract_subimages(opt) def parse_args(): parser = argparse.ArgumentParser( description='Preprocess REDS datasets', epilog='You can first download REDS datasets using the script from:' 'https://gist.github.com/SeungjunNah/b10d369b92840cb8dd2118dd4f41d643') parser.add_argument('--data-root', type=str, help='root path for REDS') parser.add_argument( '--scales', nargs='*', default=[], help='scale factor list') parser.add_argument( '--crop-size', type=int, nargs='?', default=480, help='cropped size for HR images') parser.add_argument( '--step', type=int, nargs='?', default=240, help='step size for HR images') parser.add_argument( '--thresh-size', type=int, nargs='?', default=0, help='threshold size for HR images') parser.add_argument( '--compression-level', type=int, nargs='?', default=3, help='compression level when save png images') parser.add_argument( '--n-thread', type=int, nargs='?', default=20, help='thread number when using multiprocessing') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() # extract subimages args.scales = [int(v) for v in args.scales] main_extract_subimages(args) ================================================ FILE: tools/dataset_converters/reds/preprocess_reds_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import glob import os import os.path as osp import re import shutil import sys import cv2 import lmdb import mmcv import mmengine def make_lmdb(mode, data_path, lmdb_path, batch=5000, compress_level=1): """Create lmdb for the REDS dataset. Contents of lmdb. The file structure is: example.lmdb ├── data.mdb ├── lock.mdb ├── meta_info.txt The data.mdb and lock.mdb are standard lmdb files and you can refer to https://lmdb.readthedocs.io/en/release/ for more details. The meta_info.txt is a specified txt file to record the meta information of our datasets. It will be automatically created when preparing datasets by our provided dataset tools. Each line in the txt file records 1)image name (with extension), 2)image shape, and 3)compression level, separated by a white space. For example, the meta information could be: `000_00000000.png (720,1280,3) 1`, which means: 1) image name (with extension): 000_00000000.png; 2) image shape: (720,1280,3); 3) compression level: 1 We use the image name without extension as the lmdb key. Args: mode (str): REDS dataset mode. Choices: ['train_sharp', 'train_blur', 'train_blur_comp', 'train_sharp_bicubic', 'train_blur_bicubic']. They are used to identify different reds dataset for different tasks. Specifically: 'train_sharp': GT frames; 'train_blur': Blur frames for deblur task. 'train_blur_comp': Blur and compressed frames for deblur and compression task. 'train_sharp_bicubic': Bicubic downsampled sharp frames for SR task. 'train_blur_bicubic': Bicubic downsampled blur frames for SR task. data_path (str): Data path for reading images. lmdb_path (str): Lmdb save path. batch (int): After processing batch images, lmdb commits. Default: 5000. compress_level (int): Compress level when encoding images. Default: 1. """ print(f'Create lmdb for {data_path}, save to {lmdb_path}...') if mode in ['train_sharp', 'train_blur', 'train_blur_comp']: h_dst, w_dst = 720, 1280 else: h_dst, w_dst = 180, 320 if osp.exists(lmdb_path): print(f'Folder {lmdb_path} already exists. Exit.') sys.exit(1) print('Reading image path list ...') img_path_list = sorted( list(mmengine.scandir(data_path, suffix='png', recursive=True))) keys = [] for img_path in img_path_list: parts = re.split(r'[\\/]', img_path) folder = parts[-2] img_name = parts[-1].split('.png')[0] keys.append(folder + '_' + img_name) # example: 000_00000000 # create lmdb environment # obtain data size for one image img = mmcv.imread(osp.join(data_path, img_path_list[0]), flag='unchanged') _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) data_size_per_img = img_byte.nbytes print('Data size per image is: ', data_size_per_img) data_size = data_size_per_img * len(img_path_list) env = lmdb.open(lmdb_path, map_size=data_size * 10) # write data to lmdb pbar = mmengine.ProgressBar(len(img_path_list)) txn = env.begin(write=True) txt_file = open(osp.join(lmdb_path, 'meta_info.txt'), 'w') for idx, (path, key) in enumerate(zip(img_path_list, keys)): pbar.update() key_byte = key.encode('ascii') img = mmcv.imread(osp.join(data_path, path), flag='unchanged') h, w, c = img.shape _, img_byte = cv2.imencode( '.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) assert h == h_dst and w == w_dst and c == 3, ( f'Wrong shape ({h, w}), should be ({h_dst, w_dst}).') txn.put(key_byte, img_byte) # write meta information txt_file.write(f'{key}.png ({h},{w},{c}) {compress_level}\n') if idx % batch == 0: txn.commit() txn = env.begin(write=True) txn.commit() env.close() txt_file.close() print('\nFinish writing lmdb.') def merge_train_val(train_path, val_path): """Merge the train and val datasets of REDS. Because the EDVR uses a different validation partition, so we merge train and val datasets in REDS for easy switching between REDS4 partition (used in EDVR) and the official validation partition. The original val dataset (clip names from 000 to 029) are modified to avoid conflicts with training dataset (total 240 clips). Specifically, the clip names are changed to 240, 241, ... 269. Args: train_path (str): Training folder paths. val_path (str): Validation folder paths. """ print(f'Move {val_path} to {train_path}...') val_folders = glob.glob(osp.join(val_path, '*')) for folder in val_folders: index = int(re.split(r'[\\/]', folder)[-1]) new_folder_idx = f'{index + 240:03d}' shutil.move(folder, osp.join(train_path, new_folder_idx)) def generate_anno_file(root_path, file_name='meta_info_REDS_GT.txt'): """Generate anno file for REDS datasets from the ground-truth folder. Args: root_path (str): Root path for REDS datasets. """ print(f'Generate annotation files {file_name}...') txt_file = osp.join(root_path, file_name) mmengine.utils.mkdir_or_exist(osp.dirname(txt_file)) with open(txt_file, 'w') as f: for i in range(270): for j in range(100): f.write(f'{i:03d}/{j:08d}.png (720, 1280, 3)\n') def split_anno_file(root_path, val_partition='REDS4'): """Split anno file for REDS datasets from the ground-truth folder. Args: root_path (str): Root path for REDS datasets. val_partition (str): The way of split. Selected from `RED4` and `official`. Default: 'REDS4' """ print(f'Split annotation files in {val_partition} mode...') if val_partition == 'official': val_partition = [f'{v:03d}' for v in range(240, 270)] train_txt_file = osp.join(root_path, 'meta_info_official_train.txt') val_txt_file = osp.join(root_path, 'meta_info_official_val.txt') else: val_partition = ['000', '011', '015', '020'] train_txt_file = osp.join(root_path, 'meta_info_reds4_train.txt') val_txt_file = osp.join(root_path, 'meta_info_reds4_val.txt') train_list = [] val_list = [] for i in range(270): for j in range(100): if f'{i:03d}' in val_partition: val_list.append(f'{i:03d}/{j:08d}.png (720, 1280, 3)') else: train_list.append(f'{i:03d}/{j:08d}.png (720, 1280, 3)') mmengine.utils.mkdir_or_exist(osp.dirname(train_txt_file)) with open(train_txt_file, 'w') as f: f.write('\n'.join(train_list)) mmengine.utils.mkdir_or_exist(osp.dirname(val_txt_file)) with open(val_txt_file, 'w') as f: f.write('\n'.join(val_list)) def unzip(zip_path): """Unzip zip files. It will scan all zip files in zip_path and return unzip folder names. Args: zip_path (str): Path for zip files. Returns: list: unzip folder names. """ zip_files = mmengine.scandir(zip_path, suffix='zip', recursive=False) import shutil import zipfile unzip_folders = [] for zip_file in zip_files: zip_file = osp.join(zip_path, zip_file) unzip_folder = zip_file.replace('.zip', '').split('_part')[0] print(f'Unzip {zip_file} to {unzip_folder}') with zipfile.ZipFile(zip_file, 'r') as zip_ref: zip_ref.extractall(unzip_folder) data_name = osp.basename(unzip_folder) data_type = data_name.split('_')[0] # if data path like `train_sharp/train/train_sharp/*` # begin reorganizing to `train_sharp/*` if osp.isdir(osp.join(unzip_folder, data_type, data_name)): data_folder = osp.join(unzip_folder, data_type, data_name) for i in os.listdir(data_folder): shutil.move(osp.join(data_folder, i), unzip_folder) shutil.rmtree(osp.join(unzip_folder, data_type)) # end reorganizing unzip_folders.append(unzip_folder) return unzip_folders def parse_args(): parser = argparse.ArgumentParser( description='Preprocess REDS datasets', epilog='You can first download REDS datasets using the script from:' 'https://gist.github.com/SeungjunNah/b10d369b92840cb8dd2118dd4f41d643') parser.add_argument('--root-path', type=str, help='root path for REDS') parser.add_argument( '--make-lmdb', action='store_true', help='create lmdb files') args = parser.parse_args() return args if __name__ == '__main__': """You can first download datasets using the scripts: https://gist.github.com/SeungjunNah/b10d369b92840cb8dd2118dd4f41d643. The folder structure should be like: REDS ├── train_sharp_part1.zip ├── train_sharp_part2.zip ├── train_sharp_part3.zip ├── train_sharp_bicubic.zip ├── val_sharp.zip ├── val_sharp_bicubic.zip The following are optional: REDS ├── train_blur_bicubic.zip ├── val_blur_bicubic.zip ├── train_blur_part1.zip ├── train_blur_part2.zip ├── train_blur_part3.zip ├── val_blur.zip ├── train_blur_comp_part1.zip ├── train_blur_comp_part2.zip ├── train_blur_comp_part3.zip ├── val_blur_comp.zip """ args = parse_args() root_path = args.root_path # unzip files and obtain available folder names folder_paths = unzip(root_path) folder_paths = set(folder_paths) train_folders = [ osp.basename(v) for v in folder_paths if 'train' in osp.basename(v) ] for train_folder in train_folders: train_path = osp.join(root_path, train_folder) val_path = osp.join(root_path, train_folder.replace('train_', 'val_')) # folders with 'bicubic' will have subfolder X4 if 'bicubic' in train_folder: train_path = osp.join(train_path, 'X4') val_path = osp.join(val_path, 'X4') # merge train and val datasets merge_train_val(train_path, val_path) # remove validation folders if 'bicubic' in train_folder: val_path = osp.dirname(val_path) print(f'Remove {val_path}') shutil.rmtree(val_path) # generate image list anno file generate_anno_file(root_path) split_anno_file(root_path, val_partition='RED4') split_anno_file(root_path, val_partition='official') # create lmdb file if args.make_lmdb: for train_folder in train_folders: lmdb_path = osp.join(root_path, train_folder + '.lmdb') data_path = osp.join(root_path, train_folder) if 'bicubic' in train_folder: data_path = osp.join(data_path, 'X4') make_lmdb( mode=train_folder, data_path=data_path, lmdb_path=lmdb_path) ================================================ FILE: tools/dataset_converters/sidd/README.md ================================================ # Preparing SIDD Dataset ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` The train datasets can be download from [here](https://drive.google.com/file/d/1UHjWZzLPGweA9ZczmV8lFSRcIxqiOVJw/). The validation datasets can be download from [here](https://drive.google.com/file/d/11vfqV-lqousZTuAit1Qkqghiv_taY0KZ/). For validation datasets, we need to export images from mat file. We provide such a script: ```shell python tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py --data-root ./data/SIDD/val --out-dir ./data/SIDD/val ``` The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── SIDD |   |   ├── train |   |   | ├── gt |   |   | ├── noisy |   |   ├── val |   |   | ├── gt |   |   | ├── noisy |   |   | ├── ValidationNoisyBlocksSrgb.mat |   |   | ├── ValidationGtBlocksSrgb.mat ``` ================================================ FILE: tools/dataset_converters/sidd/README_zh-CN.md ================================================ # 准备 SIDD 数据集 ```bibtex @inproceedings{Zamir2021Restormer, title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, booktitle={CVPR}, year={2022} } ``` 训练数据集可以从 [此处](https://drive.google.com/file/d/1UHjWZzLPGweA9ZczmV8lFSRcIxqiOVJw/) 下载。验证数据集可以从 [此处](https://drive.google.com/file/d/11vfqV-lqousZTuAit1Qkqghiv_taY0KZ/) 下载。 验证数据集需要从 mat 文件中导出,为此,我们提供了一个脚本: ```shell python tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py --data-root ./data/SIDD/val --out-dir ./data/SIDD/val ``` 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── SIDD |   |   ├── train |   |   | ├── gt |   |   | ├── noisy |   |   ├── val |   |   | ├── gt |   |   | ├── noisy |   |   | ├── ValidationNoisyBlocksSrgb.mat |   |   | ├── ValidationGtBlocksSrgb.mat ``` ================================================ FILE: tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import cv2 import numpy as np import scipy.io as sio import torch from skimage import img_as_ubyte from tqdm import tqdm def export_images(args): """Export images from mat file.""" noisy_dir = osp.join(args.out_dir, 'noisy') os.makedirs(noisy_dir, exist_ok=True) gt_dir = osp.join(args.out_dir, 'gt') os.makedirs(gt_dir, exist_ok=True) noisy_matfile = osp.join(args.data_root, 'ValidationNoisyBlocksSrgb.mat') gt_matfile = osp.join(args.data_root, 'ValidationGtBlocksSrgb.mat') noisy_images = sio.loadmat(noisy_matfile) gt_images = sio.loadmat(gt_matfile) noisy_images = np.float32( np.array(noisy_images['ValidationNoisyBlocksSrgb'])) noisy_images /= 255. gt_images = np.float32(np.array(gt_images['ValidationGtBlocksSrgb'])) gt_images /= 255. # processing noisy images print('Exporting', noisy_matfile, 'to', noisy_dir) for i in tqdm(range(40)): for k in range(32): noisy_patch = torch.from_numpy( noisy_images[i, k, :, :, :]).unsqueeze(0).permute(0, 3, 1, 2) noisy_patch = torch.clamp(noisy_patch, 0, 1).detach().permute(0, 2, 3, 1).squeeze(0) save_path = osp.join(noisy_dir, f'val_{str(i*32+k)}_NOISY.png') cv2.imwrite( save_path, cv2.cvtColor(img_as_ubyte(noisy_patch), cv2.COLOR_RGB2BGR)) # processing gt images print('Exporting', gt_matfile, 'to', gt_dir) for i in tqdm(range(40)): for k in range(32): gt_patch = torch.from_numpy( gt_images[i, k, :, :, :]).unsqueeze(0).permute(0, 3, 1, 2) gt_patch = torch.clamp(gt_patch, 0, 1).detach().permute(0, 2, 3, 1).squeeze(0) save_path = osp.join(gt_dir, f'val_{str(i*32+k)}_GT.png') cv2.imwrite( save_path, cv2.cvtColor(img_as_ubyte(gt_patch), cv2.COLOR_RGB2BGR)) print('\nFinish exporting images.') def parse_args(): parser = argparse.ArgumentParser( description='Prepare SIDD test dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') parser.add_argument('--out-dir', help='output directory of dataset') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() # export images export_images(args) ================================================ FILE: tools/dataset_converters/spmcs/README.md ================================================ # Preparing SPMCS Dataset ```bibtex @InProceedings{tao2017spmc, author={Xin Tao and Hongyun Gao and Renjie Liao and Jue Wang and Jiaya Jia}, title = {Detail-Revealing Deep Video Super-Resolution}, booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, month = {Oct}, year = {2017} } ``` The datasets can be download from [here](https://opendatalab.org.cn/SPMCS). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── SPMCS |   |   ├── GT |   |   ├── BIx4 |   |   ├── BDx4 |   |   ├── meta_info_SPMCS_GT.txt ``` ================================================ FILE: tools/dataset_converters/spmcs/README_zh-CN.md ================================================ # 准备 SPMCS 数据集 ```bibtex @InProceedings{tao2017spmc, author={Xin Tao and Hongyun Gao and Renjie Liao and Jue Wang and Jiaya Jia}, title = {Detail-Revealing Deep Video Super-Resolution}, booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, month = {Oct}, year = {2017} } ``` 数据集可以从 [此处](https://opendatalab.org.cn/SPMCS) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── SPMCS |   |   ├── GT |   |   ├── BIx4 |   |   ├── BDx4 |   |   ├── meta_info_SPMCS_GT.txt ``` ================================================ FILE: tools/dataset_converters/udm10/README.md ================================================ # Preparing UDM10 Dataset ```bibtex @inproceedings{PFNL, title={Progressive Fusion Video Super-Resolution Network via Exploiting Non-Local Spatio-Temporal Correlations}, author={Yi, Peng and Wang, Zhongyuan and Jiang, Kui and Jiang, Junjun and Ma, Jiayi}, booktitle={IEEE International Conference on Computer Vision (ICCV)}, pages={3106-3115}, year={2019}, } ``` The datasets can be downloaded from [here](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── UDM10 |   |   ├── GT |   |   ├── BIx4 |   |   ├── BDx4 ``` ================================================ FILE: tools/dataset_converters/udm10/README_zh-CN.md ================================================ # 准备 UDM10 数据集 ```bibtex @inproceedings{PFNL, title={Progressive Fusion Video Super-Resolution Network via Exploiting Non-Local Spatio-Temporal Correlations}, author={Yi, Peng and Wang, Zhongyuan and Jiang, Kui and Jiang, Junjun and Ma, Jiayi}, booktitle={IEEE International Conference on Computer Vision (ICCV)}, pages={3106-3115}, year={2019}, } ``` 数据集可以从 [此处](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── UDM10 |   |   ├── GT |   |   ├── BIx4 |   |   ├── BDx4 ``` ================================================ FILE: tools/dataset_converters/unconditional_gans/README.md ================================================ # Unconditional GANs Datasets **Data preparation for unconditional model** is simple. What you need to do is downloading the images and put them into a directory. Next, you should set a symlink in the `data` directory. For standard unconditional gans with static architectures, like DCGAN and StyleGAN2, `UnconditionalImageDataset` is designed to train such unconditional models. Here is an example config for FFHQ dataset: ```python dataset_type = 'BasicImageDataset' train_pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Flip', keys=['img'], direction='horizontal'), dict(type='PackInputs', keys=['img'], meta_keys=['img_path']) ] # `batch_size` and `data_root` need to be set. train_dataloader = dict( batch_size=4, num_workers=8, persistent_workers=True, sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=None, # set by user pipeline=train_pipeline)) ``` Here, we adopt `InfinitySampler` to avoid frequent dataloader reloading, which will accelerate the training procedure. As shown in the example, `pipeline` provides important data pipeline to process images, including loading from file system, resizing, cropping, transferring to `torch.Tensor` and packing to `DataSample`. All of supported data pipelines can be found in `mmagic/datasets/transforms`. For unconditional GANs with dynamic architectures like PGGAN and StyleGANv1, `GrowScaleImgDataset` is recommended to use for training. Since such dynamic architectures need real images in different scales, directly adopting `UnconditionalImageDataset` will bring heavy I/O cost for loading multiple high-resolution images. Here is an example we use for training PGGAN in CelebA-HQ dataset: ```python dataset_type = 'GrowScaleImgDataset' pipeline = [ dict(type='LoadImageFromFile', key='img'), dict(type='Flip', keys=['img'], direction='horizontal'), dict(type='PackInputs') ] # `samples_per_gpu` and `imgs_root` need to be set. train_dataloader = dict( num_workers=4, batch_size=64, dataset=dict( type='GrowScaleImgDataset', data_roots={ '1024': './data/ffhq/images', '256': './data/ffhq/ffhq_imgs/ffhq_256', '64': './data/ffhq/ffhq_imgs/ffhq_64' }, gpu_samples_base=4, # note that this should be changed with total gpu number gpu_samples_per_scale={ '4': 64, '8': 32, '16': 16, '32': 8, '64': 4, '128': 4, '256': 4, '512': 4, '1024': 4 }, len_per_stage=300000, pipeline=pipeline), sampler=dict(type='InfiniteSampler', shuffle=True)) ``` In this dataset, you should provide a dictionary of image paths to the `data_roots`. Thus, you should resize the images in the dataset in advance. For the resizing methods in the data pre-processing, we adopt bilinear interpolation methods in all of the experiments studied in MMagic. Note that this dataset should be used with `PGGANFetchDataHook`. In this config file, this hook should be added in the customized hooks, as shown below. ```python custom_hooks = [ dict( type='VisualizationHook', interval=5000, fixed_input=True, # vis ema and orig at the same time vis_kwargs_list=dict( type='Noise', name='fake_img', sample_model='ema/orig', target_keys=['ema', 'orig'])), dict(type='PGGANFetchDataHook') ] ``` This fetching data hook helps the dataloader update the status of dataset to change the data source and batch size during training. Here, we provide several download links of datasets frequently used in unconditional models: [LSUN](http://dl.yf.io/lsun/), [CelebA](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html), [CelebA-HQ](https://drive.google.com/drive/folders/11Vz0fqHS2rXDb5pprgTjpD7S2BAJhi1P), [FFHQ](https://drive.google.com/drive/folders/1u2xu7bSrWxrbUxk-dT-UvEJq8IjdmNTP). ================================================ FILE: tools/dataset_converters/unpaired-cyclegan/README.md ================================================ # Preparing Unpaired Dataset for CycleGAN ```bibtex @inproceedings{zhu2017unpaired, title={Unpaired image-to-image translation using cycle-consistent adversarial networks}, author={Zhu, Jun-Yan and Park, Taesung and Isola, Phillip and Efros, Alexei A}, booktitle={Proceedings of the IEEE international conference on computer vision}, pages={2223--2232}, year={2017} } ``` You can download unpaired datasets from [here](https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/). Then, you need to unzip and move corresponding datasets to follow the folder structure shown above. The datasets have been well-prepared by the original authors. ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── unpaired │ │ ├── facades | | ├── horse2zebra | | ├── summer2winter_yosemite | | | ├── trainA | | | ├── trainB | | | ├── testA | | | ├── testB ``` ================================================ FILE: tools/dataset_converters/unpaired-cyclegan/README_zh-CN.md ================================================ # 为 CycleGAN 准备未配对数据集 ```bibtex @inproceedings{zhu2017unpaired, title={Unpaired image-to-image translation using cycle-consistent adversarial networks}, author={Zhu, Jun-Yan and Park, Taesung and Isola, Phillip and Efros, Alexei A}, booktitle={Proceedings of the IEEE international conference on computer vision}, pages={2223--2232}, year={2017} } ``` 您可以从[此处](https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/)下载未配对的数据集。然后,您需要解压缩并移动相应的数据集以遵循如上所示的文件夹结构。数据集已经由原作者准备好了。 ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── unpaired │ │ ├── facades | | ├── horse2zebra | | ├── summer2winter_yosemite | | | ├── trainA | | | ├── trainB | | | ├── testA | | | ├── testB ``` ================================================ FILE: tools/dataset_converters/vid4/README.md ================================================ # Preparing Vid4 Dataset ```bibtex @article{xue2019video, title={On Bayesian adaptive video super resolution}, author={Liu, Ce and Sun, Deqing}, journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, volume={36}, number={2}, pages={346--360}, year={2013}, publisher={IEEE} } ``` The Vid4 dataset can be downloaded from [here](https://drive.google.com/file/d/1ZuvNNLgR85TV_whJoHM7uVb-XW1y70DW/view?usp=sharing). There are two degradations in the dataset. 1. BIx4 contains images downsampled by bicubic interpolation 2. BDx4 contains images blurred by Gaussian kernel with σ=1.6, followed by a subsampling every four pixels. Note that we should prepare a annotation file (such as meta_info_Vid4_GT.txt) for Vid4 dataset as follows. ```text calendar 41 (576,720,3) city 34 (576,704,3) foliage 49 (480,720,3) walk 47 (480,720,3) ``` For ToFlow, we should prepare directly upsampling dataset. We provide such a script: ```shell python tools/dataset_converters/vid4/preprocess_vid4_dataset.py --data-root ./data/Vid4/BIx4 ``` The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── Vid4 │ │ ├── GT │ │ │ ├── calendar │ │ │ ├── city │ │ │ ├── foliage │ │ │ ├── walk │ │ ├── BDx4 │ │ ├── BIx4 │ │ ├── BIx4up_direct │ │ ├── meta_info_Vid4_GT.txt ``` ================================================ FILE: tools/dataset_converters/vid4/README_zh-CN.md ================================================ # 准备 Vid4 数据集 ```bibtex @article{xue2019video, title={On Bayesian adaptive video super resolution}, author={Liu, Ce and Sun, Deqing}, journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, volume={36}, number={2}, pages={346--360}, year={2013}, publisher={IEEE} } ``` 可以从 [此处](https://drive.google.com/file/d/1ZuvNNLgR85TV_whJoHM7uVb-XW1y70DW/view?usp=sharing) 下载 Vid4 数据集,其中包含了由两种下采样方法得到的图片: 1. BIx4 包含了由双线性插值下采样得到的图片 2. BDx4 包含了由 `σ=1.6` 的高斯核模糊,然后每4个像素进行一次采样得到的图片 请注意,应为 Vid4 数据集准备一个如下所列的标注文件(例如 meta_info_Vid4_GT.txt)。 ```text calendar 41 (576,720,3) city 34 (576,704,3) foliage 49 (480,720,3) walk 47 (480,720,3) ``` 对于 ToFlow,应准备直接上采样的数据集,为此,我们提供了一个脚本: ```shell python tools/dataset_converters/vid4/preprocess_vid4_dataset.py --data-root ./data/Vid4/BIx4 ``` 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── Vid4 │ │ ├── GT │ │ │ ├── calendar │ │ │ ├── city │ │ │ ├── foliage │ │ │ ├── walk │ │ ├── BDx4 │ │ ├── BIx4 │ │ ├── BIx4up_direct │ │ ├── meta_info_Vid4_GT.txt ``` ================================================ FILE: tools/dataset_converters/vid4/preprocess_vid4_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp from multiprocessing import Pool import mmengine import numpy as np from skimage import img_as_float from skimage.io import imread, imsave from mmagic.datasets.transforms import MATLABLikeResize def imresize(img_path, output_path, scale=None, output_shape=None): """Resize the image using MATLAB-like downsampling. Args: img_path (str): Input image path. output_path (str): Output image path. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. """ matlab_resize = MATLABLikeResize( keys=['data'], scale=scale, output_shape=output_shape) img = imread(img_path) img = img_as_float(img) data = {'data': img} output = matlab_resize(data)['data'] output = np.clip(output, 0.0, 1.0) * 255 output = np.around(output).astype(np.uint8) imsave(output_path, output) def worker(img_name, args): """Worker for each process. Args: img_name (str): Image filename. Returns: process_info (str): Process information displayed in progress bar. """ up_dir = osp.join(args.data_root, '../BIx4up_direct') mmengine.utils.mkdir_or_exist(osp.dirname(osp.join(up_dir, img_name))) imresize( osp.join(args.data_root, img_name), osp.join(up_dir, img_name), scale=4) process_info = f'Processing {img_name} ...' return process_info def upsample_images(args): """Upsample images.""" img_list = [] clip_list = sorted(os.listdir(args.data_root)) for clip in clip_list: clip_root = osp.join(args.data_root, clip) img_list.extend( [osp.join(clip, i) for i in sorted(os.listdir(clip_root))]) prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(args.n_thread) for path in img_list: pool.apply_async( worker, args=(path, args), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def parse_args(): parser = argparse.ArgumentParser( description='Prepare cat dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() up_dir = osp.join(args.data_root, '../BIx4up_direct') if not osp.exists(up_dir): os.makedirs(up_dir) # upsample images upsample_images(args) ================================================ FILE: tools/dataset_converters/videolq/README.md ================================================ # Preparing VideoLQ Dataset ```bibtex @inproceedings{chan2022investigating, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {Investigating Tradeoffs in Real-World Video Super-Resolution}, booktitle = {IEEE Conference on Computer Vision and Pattern Recognition}, year = {2022} } ``` You can download the dataset using [Dropbox](https://www.dropbox.com/sh/hc06f1livdhutbo/AAAMPy92EOqVjRN8waT0ie8ja?dl=0) / [Google Drive](https://drive.google.com/drive/folders/1-1iJRNdqdFZWOnoUU4xG1Z1QhwsGwMDy?usp=sharing) / [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/chan0899_e_ntu_edu_sg/ErSugvUBxoBMlvSAHhqT5BEB9-4ZaqxzJIcc9uvVa8JGHg?e=WpHJTc). The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── VideoLQ │ │ ├── 000 │ │ │ ├── 00000000.png │ │ │ ├── 00000001.png │ │ │ ├── ... │ │ ├── 001 │ │ ├── 002 │ │ ├── ... ``` ================================================ FILE: tools/dataset_converters/videolq/README_zh-CN.md ================================================ # 准备 VideoLQ 数据集 ```bibtex @inproceedings{chan2022investigating, author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, title = {Investigating Tradeoffs in Real-World Video Super-Resolution}, booktitle = {IEEE Conference on Computer Vision and Pattern Recognition}, year = {2022} } ``` 数据集可以从 [Dropbox](https://www.dropbox.com/sh/hc06f1livdhutbo/AAAMPy92EOqVjRN8waT0ie8ja?dl=0) / [Google Drive](https://drive.google.com/drive/folders/1-1iJRNdqdFZWOnoUU4xG1Z1QhwsGwMDy?usp=sharing) / [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/chan0899_e_ntu_edu_sg/ErSugvUBxoBMlvSAHhqT5BEB9-4ZaqxzJIcc9uvVa8JGHg?e=WpHJTc) 下载。 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data |   ├── VideoLQ │ │ ├── 000 │ │ │ ├── 00000000.png │ │ │ ├── 00000001.png │ │ │ ├── ... │ │ ├── 001 │ │ ├── 002 │ │ ├── ... ``` ================================================ FILE: tools/dataset_converters/vimeo90k/README.md ================================================ # Preparing Vimeo90K Dataset ```bibtex @article{xue2019video, title={Video Enhancement with Task-Oriented Flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision (IJCV)}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` The training and test datasets can be downloaded from [here](http://toflow.csail.mit.edu/). Then you can rename the directory `vimeo_septuplet/sequences` to `vimeo90k/GT`. The Vimeo90K dataset has a `clip/sequence/img` folder structure: ```text vimeo90k ├── GT │ ├── 00001 │ │ ├── 0001 │ │ │ ├── im1.png │ │ │ ├── im2.png │ │ │ ├── ... │ │ ├── 0002 │ │ ├── 0003 │ │ ├── ... │ ├── 00002 │ ├── ... ├── sep_trainlist.txt ├── sep_testlist.txt ``` To generate the downsampling images BIx4 and BDx4 and prepare the annotation file, you need to run the following command: ```shell python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k ``` The folder structure should look like: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── vimeo_triplet │ │ ├── GT │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png │ │ │ │ │ ├── im2.png │ │ │ │ │ ├── ... │ │ │ │ ├── 0002 │ │ │ │ ├── 0003 │ │ │ │ ├── ... │ │ │ ├── 00002 │ │ │ ├── ... │ │ ├── BIx4 │ │ ├── BDx4 │ │ ├── meta_info_Vimeo90K_test_GT.txt │ │ ├── meta_info_Vimeo90K_train_GT.txt ``` ## Prepare LMDB dataset for Vimeo90K If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k --train_list ./data/vimeo90k/sep_trainlist.txt --gt-path ./data/vimeo90k/GT --lq-path ./data/Vimeo90k/BIx4 --make-lmdb ``` ================================================ FILE: tools/dataset_converters/vimeo90k/README_zh-CN.md ================================================ # 准备 Vimeo90K 数据集 ```bibtex @article{xue2019video, title={Video Enhancement with Task-Oriented Flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision (IJCV)}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` 训练集和测试集可以从 [此处](http://toflow.csail.mit.edu/) 下载。 将数据集路径 `vimeo_septuplet/sequences` 重命名为 `vimeo90k/GT`。Vimeo90K 数据集包含了如下所示的 `clip/sequence/img` 目录结构: ```text vimeo90k ├── GT │ ├── 00001 │ │ ├── 0001 │ │ │ ├── im1.png │ │ │ ├── im2.png │ │ │ ├── ... │ │ ├── 0002 │ │ ├── 0003 │ │ ├── ... │ ├── 00002 │ ├── ... ├── sep_trainlist.txt ├── sep_testlist.txt ``` 为了生成下采样图像BIx4和BDx4,以及准备所需的标注文件,需要执行如下命令: ```shell python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k ``` 文件目录结构应如下所示: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── vimeo_triplet │ │ ├── GT │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png │ │ │ │ │ ├── im2.png │ │ │ │ │ ├── ... │ │ │ │ ├── 0002 │ │ │ │ ├── 0003 │ │ │ │ ├── ... │ │ │ ├── 00002 │ │ │ ├── ... │ │ ├── BIx4 │ │ ├── BDx4 │ │ ├── meta_info_Vimeo90K_test_GT.txt │ │ ├── meta_info_Vimeo90K_train_GT.txt ``` ## 准备 LMDB 格式的 Vimeo90K 数据集 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件 ```shell python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k --train_list ./data/vimeo90k/sep_trainlist.txt --gt-path ./data/vimeo90k/GT --lq-path ./data/Vimeo90k/BIx4 --make-lmdb ``` ================================================ FILE: tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import math import os import os.path as osp import sys from multiprocessing import Pool import cv2 import lmdb import mmcv import mmengine import numpy as np from skimage import img_as_float from skimage.io import imread, imsave from mmagic.datasets.transforms import MATLABLikeResize, blur_kernels from mmagic.utils import modify_args def make_lmdb(mode, data_path, lmdb_path, train_list, batch=5000, compress_level=1): """Create lmdb for the Vimeo90K dataset. Contents of lmdb. The file structure is: example.lmdb ├── data.mdb ├── lock.mdb ├── meta_info.txt The data.mdb and lock.mdb are standard lmdb files and you can refer to https://lmdb.readthedocs.io/en/release/ for more details. The meta_info.txt is a specified txt file to record the meta information of our datasets. It will be automatically created when preparing datasets by our provided dataset tools. Each line in the txt file records 1)image name (with extension), 2)image shape, and 3)compression level, separated by a white space. For example, the meta information could be: `000_00000000.png (720,1280,3) 1`, which means: 1) image name (with extension): 000_00000000.png; 2) image shape: (720,1280,3); 3) compression level: 1 We use the image name without extension as the lmdb key. Args: mode (str): Dataset mode. 'gt' or 'lq'. data_path (str): Data path for reading images. lmdb_path (str): Lmdb save path. train_list (str): Train list path for Vimeo90K datasets. batch (int): After processing batch images, lmdb commits. Default: 5000. compress_level (int): Compress level when encoding images. Default: 1. """ print(f'Create lmdb for {data_path}, save to {lmdb_path}...') if mode == 'gt': h_dst, w_dst = 256, 448 else: h_dst, w_dst = 64, 112 if osp.exists(lmdb_path): print(f'Folder {lmdb_path} already exists. Exit.') sys.exit(1) print('Reading image path list ...') with open(train_list) as f: train_list = [line.strip() for line in f] all_img_list = [] keys = [] for line in train_list: folder, sub_folder = line.split('/') for j in range(1, 8): all_img_list.append( osp.join(data_path, folder, sub_folder, f'im{j}.png')) keys.append('{}_{}_{}'.format(folder, sub_folder, j)) all_img_list = sorted(all_img_list) keys = sorted(keys) if mode == 'gt': # only read the 4th frame for the gt mode print('Only keep the 4th frame for gt mode.') all_img_list = [v for v in all_img_list if v.endswith('im4.png')] keys = [v for v in keys if v.endswith('_4')] # create lmdb environment # obtain data size for one image img = mmcv.imread(osp.join(data_path, all_img_list[0]), flag='unchanged') _, img_byte = cv2.imencode('.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) data_size_per_img = img_byte.nbytes print('Data size per image is: ', data_size_per_img) data_size = data_size_per_img * len(all_img_list) env = lmdb.open(lmdb_path, map_size=data_size * 10) # write data to lmdb pbar = mmengine.ProgressBar(len(all_img_list)) txn = env.begin(write=True) txt_file = open(osp.join(lmdb_path, 'meta_info.txt'), 'w') for idx, (path, key) in enumerate(zip(all_img_list, keys)): pbar.update() key_byte = key.encode('ascii') img = mmcv.imread(osp.join(data_path, path), flag='unchanged') h, w, c = img.shape _, img_byte = cv2.imencode( '.png', img, [cv2.IMWRITE_PNG_COMPRESSION, compress_level]) assert h == h_dst and w == w_dst and c == 3, ( f'Wrong shape ({h, w}), should be ({h_dst, w_dst}).') txn.put(key_byte, img_byte) # write meta information txt_file.write(f'{key}.png ({h},{w},{c}) {compress_level}\n') if idx % batch == 0: txn.commit() txn = env.begin(write=True) txn.commit() env.close() txt_file.close() print('\nFinish writing lmdb.') def generate_anno_file(clip_list, file_name='meta_info_Vimeo90K_GT.txt'): """Generate anno file for Vimeo90K datasets from the official clip list. Args: clip_list (str): Clip list path for Vimeo90K datasets. file_name (str): Saved file name. Default: 'meta_info_Vimeo90K_GT.txt'. """ print(f'Generate annotation files {file_name}...') with open(clip_list) as f: lines = [line.rstrip() for line in f] txt_file = osp.join(osp.dirname(clip_list), file_name) with open(txt_file, 'w') as f: for line in lines: f.write(f'{line} 7 (256, 448, 3)\n') def imresize(img_path, output_path, scale=None, output_shape=None): """Resize the image using MATLAB-like downsampling. Args: img_path (str): Input image path. output_path (str): Output image path. scale (float | None, optional): The scale factor of the resize operation. If None, it will be determined by output_shape. Default: None. output_shape (tuple(int) | None, optional): The size of the output image. If None, it will be determined by scale. Note that if scale is provided, output_shape will not be used. Default: None. """ matlab_resize = MATLABLikeResize( keys=['data'], scale=scale, output_shape=output_shape) img = imread(img_path) img = img_as_float(img) data = {'data': img} output = matlab_resize(data)['data'] output = np.clip(output, 0.0, 1.0) * 255 output = np.around(output).astype(np.uint8) imsave(output_path, output) def mesh_grid(kernel_size): """Generate the mesh grid, centering at zero. Args: kernel_size (int): The size of the kernel. Returns: xy_grid (np.ndarray): stacked xy coordinates with shape (kernel_size, kernel_size, 2). """ range_ = np.arange(-(kernel_size - 1.) / 2., (kernel_size - 1.) / 2. + 1.) x_grid, y_grid = np.meshgrid(range_, range_) xy_grid = np.hstack((x_grid.reshape((kernel_size * kernel_size, 1)), y_grid.reshape(kernel_size * kernel_size, 1))).reshape(kernel_size, kernel_size, 2) return xy_grid def bd_downsample(img_path, output_path, sigma=1.6, scale=4): """Downsampling using BD degradation(Gaussian blurring and downsampling). Args: img_path (str): Input image path. output_path (str): Output image path. sigma (float): The sigma of Gaussian blurring kernel. Default: 1.6. scale (int): The scale factor of the downsampling. Default: 4. """ # Gaussian blurring kernelsize = math.ceil(sigma * 3) * 2 + 2 kernel = blur_kernels.bivariate_gaussian( kernelsize, sigma, grid=mesh_grid(kernelsize)) img = cv2.imread(img_path) img = img_as_float(img) output = cv2.filter2D( img, -1, kernel, anchor=((kernelsize - 1) // 2, (kernelsize - 1) // 2), borderType=cv2.BORDER_REPLICATE) # downsampling output = output[int(scale / 2) - 1:-int(scale / 2) + 1:scale, int(scale / 2) - 1:-int(scale / 2) + 1:scale, :] output = np.clip(output, 0.0, 1.0) * 255 output = output.astype(np.float32) output = np.floor(output + 0.5) cv2.imwrite(output_path, output) def worker(clip_path, args): """Worker for each process. Args: clip_name (str): Path of the clip. Returns: process_info (str): Process information displayed in progress bar. """ gt_dir = osp.join(args.data_root, 'GT', clip_path) bi_dir = osp.join(args.data_root, 'BIx4', clip_path) bd_dir = osp.join(args.data_root, 'BDx4', clip_path) mmengine.utils.mkdir_or_exist(bi_dir) mmengine.utils.mkdir_or_exist(bd_dir) img_list = sorted(os.listdir(gt_dir)) for img in img_list: imresize(osp.join(gt_dir, img), osp.join(bi_dir, img), scale=1 / 4) bd_downsample(osp.join(gt_dir, img), osp.join(bd_dir, img)) process_info = f'Processing {clip_path} ...' return process_info def downsample_images(args): """Downsample images.""" clip_list = [] gt_dir = osp.join(args.data_root, 'GT') sequence_list = sorted(os.listdir(gt_dir)) for sequence in sequence_list: sequence_root = osp.join(gt_dir, sequence) clip_list.extend( [osp.join(sequence, i) for i in sorted(os.listdir(sequence_root))]) prog_bar = mmengine.ProgressBar(len(clip_list)) pool = Pool(args.n_thread) for path in clip_list: pool.apply_async( worker, args=(path, args), callback=lambda arg: prog_bar.update()) pool.close() pool.join() print('All processes done.') def parse_args(): modify_args() parser = argparse.ArgumentParser( description='Preprocess Vimeo90K datasets', epilog='You can download the Vimeo90K dataset ' 'from:http://toflow.csail.mit.edu/') parser.add_argument('--data-root', help='dataset root') parser.add_argument( '--n-thread', nargs='?', default=8, type=int, help='thread number when using multiprocessing') parser.add_argument( '--train_list', default=None, help='official training list path for Vimeo90K') parser.add_argument('--gt-path', default=None, help='GT path for Vimeo90K') parser.add_argument('--lq-path', default=None, help='LQ path for Vimeo90K') parser.add_argument( '--make-lmdb', action='store_true', help='create lmdb files') args = parser.parse_args() return args if __name__ == '__main__': args = parse_args() # generate BIx4 and BDx4 downsample_images(args) # generate image list anno file generate_anno_file( osp.join(args.data_root, 'sep_trainlist.txt'), 'meta_info_Vimeo90K_train_GT.txt') generate_anno_file( osp.join(args.data_root, 'sep_testlist.txt'), 'meta_info_Vimeo90K_test_GT.txt') # create lmdb files if args.make_lmdb: if args.gt_path is None or args.lq_path is None: raise ValueError('gt_path and lq_path cannot be None when ' 'when creating lmdb files.') # create lmdb for gt lmdb_path = osp.join( osp.dirname(args.gt_path), 'vimeo90k_train_GT.lmdb') make_lmdb( mode='gt', data_path=args.gt_path, lmdb_path=lmdb_path, train_list=args.train_list) # create lmdb for lq lmdb_path = osp.join( osp.dirname(args.lq_path), 'vimeo90k_train_LR7frames.lmdb') make_lmdb( mode='lq', data_path=args.lq_path, lmdb_path=lmdb_path, train_list=args.train_list) ================================================ FILE: tools/dataset_converters/vimeo90k-triplet/README.md ================================================ # Preparing Vimeo90K-triplet Dataset ```bibtex @article{xue2019video, title={Video Enhancement with Task-Oriented Flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision (IJCV)}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` The training and test datasets can be download from [here](http://toflow.csail.mit.edu/). The Vimeo90K-triplet dataset has a `clip/sequence/img` folder structure: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── vimeo_triplet │ │ ├── tri_testlist.txt │ │ ├── tri_trainlist.txt │ │ ├── sequences │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png │ │ │ │ │ ├── im2.png │ │ │ │ │ └── im3.png │ │ │ │ ├── 0002 │ │ │ │ ├── 0003 │ │ │ │ ├── ... │ │ │ ├── 00002 │ │ │ ├── ... ``` ================================================ FILE: tools/dataset_converters/vimeo90k-triplet/README_zh-CN.md ================================================ # 准备 Vimeo90K-triplet 数据集 ```bibtex @article{xue2019video, title={Video Enhancement with Task-Oriented Flow}, author={Xue, Tianfan and Chen, Baian and Wu, Jiajun and Wei, Donglai and Freeman, William T}, journal={International Journal of Computer Vision (IJCV)}, volume={127}, number={8}, pages={1106--1125}, year={2019}, publisher={Springer} } ``` 训练集和测试集可以从 [此处](http://toflow.csail.mit.edu/) 下载。 Vimeo90K-triplet 数据集包含了如下所示的 `clip/sequence/img` 目录结构: ```text mmagic ├── mmagic ├── tools ├── configs ├── data │ ├── vimeo_triplet │ │ ├── tri_testlist.txt │ │ ├── tri_trainlist.txt │ │ ├── sequences │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png │ │ │ │ │ ├── im2.png │ │ │ │ │ └── im3.png │ │ │ │ ├── 0002 │ │ │ │ ├── 0003 │ │ │ │ ├── ... │ │ │ ├── 00002 │ │ │ ├── ... ``` ================================================ FILE: tools/dist_test.sh ================================================ #!/usr/bin/env bash CONFIG=$1 CHECKPOINT=$2 GPUS=$3 NNODES=${NNODES:-1} NODE_RANK=${NODE_RANK:-0} PORT=${PORT:-29500} MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ python -m torch.distributed.launch \ --nnodes=$NNODES \ --node_rank=$NODE_RANK \ --master_addr=$MASTER_ADDR \ --nproc_per_node=$GPUS \ --master_port=$PORT \ $(dirname "$0")/test.py \ $CONFIG \ $CHECKPOINT \ --launcher pytorch \ ${@:4} ================================================ FILE: tools/dist_train.sh ================================================ #!/usr/bin/env bash CONFIG=$1 GPUS=$2 NNODES=${NNODES:-1} NODE_RANK=${NODE_RANK:-0} PORT=${PORT:-29500} MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ python -m torch.distributed.launch \ --nnodes=$NNODES \ --node_rank=$NODE_RANK \ --master_addr=$MASTER_ADDR \ --nproc_per_node=$GPUS \ --master_port=$PORT \ $(dirname "$0")/train.py \ $CONFIG \ --launcher pytorch ${@:3} ================================================ FILE: tools/gui/README.md ================================================ # MMagic Viewer - [Introduction](#introduction) - [Major features](#major-features) - [Prerequisites](#prerequisites) - [Getting Started](#getting-started) - [Examples](#examples) - [Contributing](#contributing) ## Introduction **MMagic Viewer** is a qualitative comparison tools to facilitate your research. ## Major features - **Patch-based comparison** - Crop a patch on multiple images to compare - Batch comparison - Flexible settings on number of columns and size of images. - Save your comparison result - **Before/After slider comparison** - Support both videos and images comparison - Record and save comparison results as a video clip ## Prerequisites MMagic Viewer works on Linux, Windows and macOS. It requires: - Python >= 3.6 - PyQt5 - opencv-python (headless version) ## Getting Started **Step 0.** Install PyQt5. ```shell pip install PyQt5 ``` **Step 1.** Install and check opencv-python version. If your meet following errors: ``` QObject::moveToThread: Current thread is not the object's thread. Available platform plugins are: xcb... . ``` Please install opencv-python-headless version. ```shell pip install opencv-python-headless ``` **Step 2.** Install MMagic. ```shell git clone https://github.com/open-mmlab/mmagic.git ``` **Step 3.** Run ```shell python tools/gui/gui.py ``` ## Examples **1. Patch-based comparison: batch images** https://user-images.githubusercontent.com/49083766/199232588-7a07a3d9-725d-48be-89bf-1ffb45bd5d74.mp4 **2. Patch-based comparison: single image** https://user-images.githubusercontent.com/49083766/199232606-f8539191-4bda-4b2c-975a-59020927abae.mp4 **3. Before/After slider comparison: images** https://user-images.githubusercontent.com/49083766/199232615-2c56dcf1-0b42-41a5-884c-16a8f28a2647.mp4 **4. Before/After slider comparison: input video frames** https://user-images.githubusercontent.com/49083766/199232617-e03a06dc-727b-43bb-8110-049d0fff28ba.mp4 **5. Before/After slider comparison: input Mp4 video** https://user-images.githubusercontent.com/49083766/199232651-87d8064e-cbaf-4d30-b90b-94ee0af7d497.mp4 **6. Before/After slider comparison: record** https://user-images.githubusercontent.com/49083766/199232634-eca70d28-8437-400a-8ab9-d2fe396b6ea9.mp4 ## Contributing We appreciate all contributions to improve MMagic Viewer. You can create your issue to report bugs or request new features. Welcome to give us suggestions or contribute your codes. ================================================ FILE: tools/gui/component.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import os import time import cv2 import numpy as np from PyQt5 import QtCore, QtGui, QtWidgets from utils import layout2widget class QLabelClick(QtWidgets.QLabel): clicked = QtCore.pyqtSignal(str) def __init__(self): super().__init__() def mousePressEvent(self, event): self.clicked.emit(self.text()) class QLabelSlider(QtWidgets.QLabel): def __init__(self, parent, scale, label_1, label_2, title): super().__init__() self.parent = parent self.hSlider = -1 self.vSlider = -1 self.oldSlider = -1 self.scale = scale self.label_1 = label_1 self.label_2 = label_2 self.title = title self.images = self.parent.images self.auto_mode = 0 def mousePressEvent(self, ev: QtGui.QMouseEvent) -> None: if ev.button() == QtCore.Qt.LeftButton: if self.hSlider > -1: self.oldSlider = self.hSlider elif self.vSlider > -1: self.oldSlider = self.vSlider return super().mousePressEvent(ev) def mouseReleaseEvent(self, ev: QtGui.QMouseEvent) -> None: if ev.button() == QtCore.Qt.LeftButton: self.oldSlider = -1 self.update() return super().mouseReleaseEvent(ev) def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None: if self.oldSlider > -1: if self.hSlider > -1: self.hSlider = ev.pos().x() elif self.vSlider > -1: self.vSlider = ev.pos().y() self.update() return super().mouseMoveEvent(ev) def paintEvent(self, ev: QtGui.QPaintEvent) -> None: qp = QtGui.QPainter() qp.begin(self) qp.drawImage(0, 0, QtGui.QImage(self.getImage())) pen = QtGui.QPen(QtCore.Qt.green, 3) qp.setPen(pen) qp.drawLine(self.hSlider, 0, self.hSlider, self.height()) length = 9 qp.drawText(self.hSlider - 10 - len(self.label_1) * length, 20, self.label_1) qp.drawText(self.hSlider + 10, 20, self.label_2) qp.drawText(10, self.height() - 10, self.title) qp.end() def set_scale(self, scale): self.hSlider = int(self.hSlider * scale / self.scale) self.scale = scale self.update() def setImage(self, images): self.images = images self.update() def set_auoMode(self, mode): if mode != 3 or self.auto_mode < 3: self.auto_mode = mode def auto_slider(self): try: if self.auto_mode == 1: self.hSlider += 1 if self.hSlider > self.w: self.hSlider = 0 elif self.auto_mode == 2: self.hSlider -= 1 if self.hSlider < 0: self.hSlider = self.w elif self.auto_mode == 3: self.hSlider += 1 if self.hSlider >= self.w: self.auto_mode = 4 elif self.auto_mode == 4: self.hSlider -= 1 if self.hSlider <= 0: self.auto_mode = 3 self.update() except Exception: print(Exception) pass def getImage(self): img1, img2 = self.images if img1 is None or img2 is None: return h1, w1, c = img1.shape h2, w2, c = img2.shape if w2 > w1: img1 = cv2.resize(img1, (w2, h2)) h, w = h2, w2 else: img2 = cv2.resize(img2, (w1, h1)) h, w = h1, w1 self.h = int(h * self.scale) self.w = int(w * self.scale) self.setFixedHeight(self.h) self.setFixedWidth(self.w) if self.hSlider < 0: self.hSlider = int(self.w / 2.0) v = int(self.hSlider / self.scale) img11 = img1[:, 0:v].copy() img22 = img2[:, v:].copy() img = np.hstack((img11, img22)) # img = cv2.line(img, (v, 0), (v, h2), (0, 222, 0), 4) rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_dis = QtGui.QImage(rgb_img, w, h, w * c, QtGui.QImage.Format_RGB888) img = QtGui.QPixmap.fromImage(img_dis).scaled(self.width(), self.height()) return img class QLabelPaint(QtWidgets.QLabel): def __init__(self, parent, beginPoint=None, endPoint=None): super().__init__() self.beginPoint = beginPoint self.endPoint = endPoint self.parent = parent self.statusBar = self.parent.statusBar if self.beginPoint and self.endPoint: self.isShow = True else: self.isShow = False def mousePressEvent(self, ev: QtGui.QMouseEvent) -> None: if ev.button() == QtCore.Qt.LeftButton: self.endPoint = None self.beginPoint = ev.pos() self.isShow = False return super().mousePressEvent(ev) def mouseReleaseEvent(self, ev: QtGui.QMouseEvent) -> None: if ev.button() == QtCore.Qt.LeftButton: self.endPoint = ev.pos() self.update() self.isShow = True self.parent.set_rect(self.beginPoint, self.endPoint) return super().mouseReleaseEvent(ev) def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None: self.endPoint = ev.pos() self.update() self.statusBar.showMessage( f'Start: {self.beginPoint.x()},{self.beginPoint.y()}; \ End: {self.endPoint.x()},{self.endPoint.y()}') return super().mouseMoveEvent(ev) def paintEvent(self, ev: QtGui.QPaintEvent) -> None: super().paintEvent(ev) if self.beginPoint and self.endPoint: qp = QtGui.QPainter() qp.begin(self) pen = QtGui.QPen(QtCore.Qt.red, 2) qp.setPen(pen) w = abs(self.beginPoint.x() - self.endPoint.x()) h = abs(self.beginPoint.y() - self.endPoint.y()) qp.drawRect(self.beginPoint.x(), self.beginPoint.y(), w, h) qp.end() if self.isShow and isinstance(self.parent, ConcatImageWidget): self.parent.show_images(self.beginPoint.x(), self.beginPoint.y(), w, h) self.isShow = False class ConcatImageWidget(QtWidgets.QWidget): def __init__(self, parent, mode, col_num=4): super(ConcatImageWidget, self).__init__(parent) self.parent = parent self.statusBar = self.parent.statusBar self.hlayout = QtWidgets.QHBoxLayout() self.setLayout(self.hlayout) self.mode = mode self.scale = 1 self.col_num = col_num self.file_path = None self.labels = None self.gt = None self.img_h = 0 self.rect = None def show_images(self, x=0, y=0, w=0, h=0): self.rect = [x, y, w, h] vlayout = QtWidgets.QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout_img = QtWidgets.QHBoxLayout() hlayout_img.setContentsMargins(0, 0, 0, 0) hlayout_text = QtWidgets.QHBoxLayout() hlayout_text.setContentsMargins(0, 0, 0, 0) for i, (path, text) in enumerate(zip(self.file_path, self.labels)): img = QtGui.QPixmap(path).scaled(self.gt_w, self.gt_h) if self.mode == 0: img = img.copy(QtCore.QRect(x, y, w, h)) if self.img_h > 0: img_w = int(float(self.img_h) / img.height() * img.width()) img = img.scaled(img_w, self.img_h) label = QtWidgets.QLabel() label.setFixedWidth(img.width()) label.setFixedHeight(img.height()) label.setMargin(0) label.setPixmap(img) hlayout_img.addWidget(label) label_text = QtWidgets.QLabel() label_text.setMargin(0) label_text.setAlignment(QtCore.Qt.AlignCenter) label_text.setText(text) label_text.adjustSize() hlayout_text.addWidget(label_text) if (i + 1) % self.col_num == 0: vlayout.addWidget(layout2widget(hlayout_img)) vlayout.addWidget(layout2widget(hlayout_text)) hlayout_img = QtWidgets.QHBoxLayout() hlayout_img.setContentsMargins(0, 0, 0, 0) hlayout_text = QtWidgets.QHBoxLayout() hlayout_text.setContentsMargins(0, 0, 0, 0) if len(hlayout_img) > 0: for i in range(0, self.col_num - len(hlayout_img)): label = QtWidgets.QLabel() label.setMargin(0) label.setFixedWidth(img.width()) label.setFixedHeight(img.height()) hlayout_img.addWidget(label) label = QtWidgets.QLabel() label.setMargin(0) hlayout_text.addWidget(label) vlayout.addWidget(layout2widget(hlayout_img)) vlayout.addWidget(layout2widget(hlayout_text)) total_w = self.gt_w + (img.width() + 2) * self.col_num self.setFixedWidth(total_w) if self.hlayout.count() > 1: item = self.hlayout.itemAt(1) self.hlayout.removeItem(item) if item.widget(): item.widget().deleteLater() self.hlayout.addWidget(layout2widget(vlayout)) else: self.hlayout.addWidget(layout2widget(vlayout)) def set_images(self, file_path, labels, gt=None, scale=1, rect=None): self.file_path = file_path self.labels = labels self.gt = gt self.scale = scale for i in reversed(range(self.hlayout.count())): self.hlayout.itemAt(i).widget().deleteLater() self.hlayout.setContentsMargins(0, 0, 0, 0) img = QtGui.QPixmap(self.gt) self.gt_w, self.gt_h = img.width() * scale, img.height() * scale img = img.scaled(self.gt_w, self.gt_h) row = (len(self.file_path) + self.col_num - 1) // self.col_num self.img_h = int(float(self.gt_h - (row - 1) * 29) / row) beginPoint = None endPoint = None if rect: beginPoint = QtCore.QPoint(rect[0], rect[1]) endPoint = QtCore.QPoint(rect[2], rect[3]) label = QLabelPaint(self, beginPoint, endPoint) label.setMargin(0) label.setAlignment(QtCore.Qt.AlignTop) label.setPixmap(img) self.hlayout.addWidget(label) if rect: self.show_images(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]) else: self.show_images(0, 0, self.gt_w, self.gt_h) def set_rect(self, beginPoint, endPoint): self.parent.rect = [ beginPoint.x(), beginPoint.y(), endPoint.x(), endPoint.y() ] self.parent.old_scale = self.scale class VideoPlayer(QtCore.QThread): sigout = QtCore.pyqtSignal(np.ndarray) sigend = QtCore.pyqtSignal(bool) def __init__(self, parent): super(VideoPlayer, self).__init__(parent) self.parent = parent def set(self, path, fps=None): self.path = path self.video, self.fps, self.actual_frames = self.setVideo(path, fps) self.time = self.actual_frames / self.fps self.total_frames = self.actual_frames self.num = 0 self.working = True self.isPause = False self.mutex = QtCore.QMutex() self.cond = QtCore.QWaitCondition() def setVideo(self, path, fps): if os.path.isfile(path): v = cv2.VideoCapture(path) total_frames = v.get(cv2.CAP_PROP_FRAME_COUNT) if fps is None: fps = v.get(cv2.CAP_PROP_FPS) else: files = sorted(os.listdir(path)) v = ['/'.join([path, f]) for f in files] total_frames = len(v) if fps is None: fps = 25 return v, fps, total_frames def pause(self): self.isPause = True def resume(self): self.isPause = False self.cond.wakeAll() def __del__(self): self.working = False self.wait() def run(self): while self.working: self.mutex.lock() if self.isPause: self.cond.wait(self.mutex) if isinstance(self.video, list): img = cv2.imread(self.video[self.num]) self.num += 1 self.sigout.emit(img) if self.num >= self.total_frames: self.sigend.emit(True) self.num = 0 time.sleep(1 / self.fps) self.mutex.unlock() class VideoSlider(QtCore.QThread): sigout = QtCore.pyqtSignal(list) sigend = QtCore.pyqtSignal(bool) def __init__(self, parent): super(VideoSlider, self).__init__(parent) self.parent = parent self.mutex = QtCore.QMutex() self.cond = QtCore.QWaitCondition() def set(self, path1, path2, fps1=None, fps2=None): self.path1 = path1 self.path2 = path2 self.v1, self.fps1, self.total_frames1 = self.setVideo(path1, fps1) self.v2, self.fps2, self.total_frames2 = self.setVideo(path2, fps2) if self.fps1 != self.fps2: return False self.fps = self.fps1 self.num = 0 self.working = True self.isPause = False return True def setVideo(self, path, fps): if os.path.isfile(path): v = cv2.VideoCapture(path) total_frames = v.get(cv2.CAP_PROP_FRAME_COUNT) fps = v.get(cv2.CAP_PROP_FPS) else: files = sorted(os.listdir(path)) v = ['/'.join([path, f]) for f in files] total_frames = len(v) if fps is None: fps = 25 return v, fps, total_frames def pause(self): self.isPause = True def resume(self): self.isPause = False self.cond.wakeAll() def __del__(self): self.working = False self.wait() def run(self): while self.working: self.mutex.lock() if self.isPause: self.cond.wait(self.mutex) if isinstance(self.v1, list): num = self.num if self.num < self.total_frames1 \ else self.total_frames1 - 1 img1 = cv2.imread(self.v1[num]) elif isinstance(self.v1, cv2.VideoCapture): r, img1 = self.v1.read() if not r: self.v1, self.fps1, self.total_frames1 = self.setVideo( self.path1, self.fps1) if isinstance(self.v2, list): num = self.num if self.num < self.total_frames2 \ else self.total_frames2 - 1 img2 = cv2.imread(self.v2[num]) elif isinstance(self.v2, cv2.VideoCapture): r, img2 = self.v2.read() if not r: self.v2, self.fps2, self.total_frames2 = self.setVideo( self.path2, self.fps2) self.num += 1 self.sigout.emit([img1, img2]) if self.num >= self.total_frames1 and \ self.num >= self.total_frames2: self.num = 0 time.sleep(1 / self.fps) self.mutex.unlock() ================================================ FILE: tools/gui/gui.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import sys from component import QLabelClick from page_sr import SRPage from PyQt5 import QtWidgets class Homepage(QtWidgets.QWidget): def __init__(self, main_window): super().__init__() self.main_window = main_window layout = QtWidgets.QGridLayout() self.setLayout(layout) t1 = QLabelClick() t2 = QLabelClick() t3 = QLabelClick() t4 = QLabelClick() t1.setText('general') t2.setText('sr') t3.setText('inpainting') t4.setText('matting') layout.addWidget(t1, 0, 0) layout.addWidget(t2, 0, 1) layout.addWidget(t3, 1, 0) layout.addWidget(t4, 1, 1) t1.clicked.connect(self.main_window.change_window) t2.clicked.connect(self.main_window.change_window) t3.clicked.connect(self.main_window.change_window) t4.clicked.connect(self.main_window.change_window) class MainWindow(QtWidgets.QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle('MMagic Viewer') # # MenuBar # menubar_Aaa = self.menuBar().addMenu('Aaa') # menubar_Bbb = self.menuBar().addMenu('Bbb') # menubar_Ccc = self.menuBar().addMenu('Ccc') # menubar_Aaa.addAction('New') # save = QtWidgets.QAction('Save', self) # save.setShortcut('Ctrl+S') # menubar_Aaa.addAction(save) # menubar_Bbb.addAction('New') # menubar_Ccc.addAction('New') # # ToolBar # self.toolBar = QtWidgets.QToolBar('ToolBar') # open = QtWidgets.QAction(QtGui.QIcon(), 'Open', self) # save = QtWidgets.QAction(QtGui.QIcon(), 'Save', self) # self.toolBar.addAction(open) # self.toolBar.addAction(save) # self.addToolBar(QtCore.Qt.ToolBarArea.LeftToolBarArea, self.toolBar) # StatusBar self.statusBar = QtWidgets.QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.showMessage('') self.homepage = Homepage(self) self.sr = SRPage(self) self.setCentralWidget(self.sr) def change_window(self, wname): if wname == 'sr': self.setCentralWidget(self.sr) elif wname == 'general': self.setCentralWidget(self.general) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) myWin = MainWindow() myWin.showMaximized() sys.exit(app.exec_()) ================================================ FILE: tools/gui/page_general.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import cv2 import numpy as np from PyQt5 import QtCore, QtGui, QtWidgets from utils import layout2widget class SliderTab(QtWidgets.QWidget): def __init__(self): super().__init__() self.images = [None, None] self.cb_1 = QtWidgets.QComboBox() self.cb_2 = QtWidgets.QComboBox() self.cb_1.currentIndexChanged.connect(self.change_image) self.cb_2.currentIndexChanged.connect(self.change_image) self.btn_add = QtWidgets.QPushButton() self.btn_add.setText('Add') self.btn_add.clicked.connect(self.add) left_grid = QtWidgets.QGridLayout() left_grid.addWidget(self.cb_1, 0, 0) left_grid.addWidget(self.cb_2, 1, 0) left_grid.addWidget(self.btn_add, 2, 0) self.imageArea = QtWidgets.QLabel() self.imageArea.setFrameShape(QtWidgets.QFrame.Box) self.imageArea.setLineWidth(2) self.imageArea.setAlignment(QtCore.Qt.AlignBottom) self.imageArea.setStyleSheet( 'border-width: 0px; border-style: solid; border-color: rgb(100, 100, 100);background-color: rgb(255, 255, 255)' # noqa ) self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider.setMaximum(800) self.slider.valueChanged.connect(self.show_image) right_grid = QtWidgets.QGridLayout() right_grid.addWidget(self.imageArea, 0, 0) right_grid.addWidget(self.slider, 1, 0) # Splitter hsplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) hsplitter.addWidget(layout2widget(left_grid)) hsplitter.addWidget(layout2widget(right_grid)) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(hsplitter) self.setLayout(hlayout) def add(self): path, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select gt file', '', 'Images (*.jpg *.png *.mp4 *.avi)') if self.cb_1.count() > 0: if self.cb_1.findText(path) > -1: self.cb_1.removeItem(self.cb_1.findText(path)) if self.cb_2.findText(path) > -1: self.cb_2.removeItem(self.cb_2.findText(path)) self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_2.setCurrentIndex(self.cb_2.count() - 1) else: self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_1.setCurrentIndex(0) self.cb_2.setCurrentIndex(0) def change_image(self): self.images[0] = cv2.imread(self.cb_1.currentText()) self.images[1] = cv2.imread(self.cb_2.currentText()) if self.images[0] is None or self.images[1] is None: return self.show_image() def show_image(self): img1, img2 = self.images h2, w2, c2 = img2.shape img2 = cv2.resize(img2, (800, int(800 / w2 * h2))) h2, w2, c2 = img2.shape img1 = cv2.resize(img1, (w2, h2)) v = self.slider.value() img11 = img1[:, 0:v].copy() img22 = img2[:, v:].copy() img = np.hstack((img11, img22)) img = cv2.line(img, (v, 0), (v, h2), (0, 222, 0), 4) rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_dis = QtGui.QImage(rgb_img, w2, h2, w2 * c2, QtGui.QImage.Format_RGB888) jpg = QtGui.QPixmap.fromImage(img_dis).scaled( self.imageArea.width(), int(self.imageArea.width() / w2 * h2)) self.imageArea.setPixmap(jpg) class GeneralPage(QtWidgets.QWidget): def __init__(self) -> None: super().__init__() self.tab_slider = SliderTab() self.tabs = QtWidgets.QTabWidget() self.tabs.addTab(self.tab_slider, 'before/after slider') layout = QtWidgets.QVBoxLayout() self.setLayout(layout) layout.addWidget(self.tabs) ================================================ FILE: tools/gui/page_sr.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import datetime import os import cv2 from component import ConcatImageWidget, QLabelSlider, VideoSlider from PyQt5 import QtCore, QtWidgets from utils import layout2widget class PatchTab(QtWidgets.QWidget): def __init__(self, parent): super().__init__() self.parent = parent self.statusBar = self.parent.statusBar self.file_paths = [] self.labels = [] self.rect = None self.images = None self.isShow = False # Left Widget self.btn_add_file = QtWidgets.QPushButton() self.btn_add_file.setText('Add') self.btn_add_file.clicked.connect(self.add_file) self.btn_open_file = QtWidgets.QPushButton() self.btn_open_file.setText('Open new') self.btn_open_file.clicked.connect(self.open_file) self.input_label = QtWidgets.QLineEdit() self.input_file = QtWidgets.QLineEdit() self.tb_files = QtWidgets.QTableWidget() self.tb_files.setColumnCount(3) self.tb_files.setHorizontalHeaderLabels( ['File/Folder', 'Label', 'Other']) self.tb_files.horizontalHeader().setSectionResizeMode( QtWidgets.QHeaderView.Stretch) self.tb_files.setSelectionBehavior( QtWidgets.QAbstractItemView.SelectRows) self.tb_files.setSelectionMode( QtWidgets.QAbstractItemView.SingleSelection) self.tb_files.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tb_files.customContextMenuRequested.connect(self.tableMenu) left_grid = QtWidgets.QGridLayout() left_grid.addWidget(self.tb_files, 0, 0, 5, 10) left_grid.addWidget(self.input_file, 6, 0, 1, 4) left_grid.addWidget(self.input_label, 6, 4, 1, 2) left_grid.addWidget(self.btn_open_file, 6, 6, 1, 2) left_grid.addWidget(self.btn_add_file, 6, 8, 1, 2) # Right Widget styleSheet = ''' QGroupBox { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E0E0E0, stop: 1 #FFFFFF); border: 1px solid #999999; border-radius: 5px; margin-top: 2ex; /*leave space at the top for the title */ padding: 2ex 10ex; font-size: 20px; color: black; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; /* position at the top center */ padding: 0 3px; left: 30px; font-size: 8px; color: black; } ''' # noqa # select mode self.modeRect = QtWidgets.QGroupBox('Select Mode') self.modeRect.setFlat(True) # self.modeRect.setStyleSheet(styleSheet) btn_mode1 = QtWidgets.QRadioButton('Input whole image', self.modeRect) btn_mode2 = QtWidgets.QRadioButton('Input crop image', self.modeRect) self.btnGroup_mode = QtWidgets.QButtonGroup() self.btnGroup_mode.addButton(btn_mode1, 0) self.btnGroup_mode.addButton(btn_mode2, 1) self.btnGroup_mode.button(0).setChecked(True) self.btnGroup_mode.idToggled.connect(self.reset) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(btn_mode1) hlayout.addWidget(btn_mode2) self.modeRect.setLayout(hlayout) # select dirType self.dirTypeRect = QtWidgets.QGroupBox('Select File or Directory') self.dirTypeRect.setFlat(True) # self.dirTypeRect.setStyleSheet(styleSheet) btn_dirType1 = QtWidgets.QRadioButton('Directory', self.dirTypeRect) btn_dirType2 = QtWidgets.QRadioButton('File', self.dirTypeRect) self.btnGroup_dirType = QtWidgets.QButtonGroup() self.btnGroup_dirType.addButton(btn_dirType1, 0) self.btnGroup_dirType.addButton(btn_dirType2, 1) self.btnGroup_dirType.button(0).setChecked(True) self.btnGroup_dirType.idToggled.connect(self.reset) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(btn_dirType1) hlayout.addWidget(btn_dirType2) self.dirTypeRect.setLayout(hlayout) # select gt self.cb_gt = QtWidgets.QComboBox() self.cb_gt.currentTextChanged.connect(self.change_gt) # set column self.spin_cols = QtWidgets.QSpinBox() self.spin_cols.setMinimum(1) self.spin_cols.setMaximum(10) self.spin_cols.setValue(4) self.spin_cols.valueChanged.connect(self.set_column) # set scale self.scale = 100 self.txt_scale = QtWidgets.QLabel('100 %') self.slider_scale = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_scale.setMinimum(1) self.slider_scale.setMaximum(200) self.slider_scale.setValue(100) self.slider_scale.valueChanged.connect(self.set_scale) # operation self.btn_run = QtWidgets.QPushButton() self.btn_run.setText('Run') self.btn_run.clicked.connect(self.run) self.btn_reset = QtWidgets.QPushButton() self.btn_reset.setText('Reset') self.btn_reset.clicked.connect(self.reset) self.btn_save = QtWidgets.QPushButton() self.btn_save.setText('Save') self.btn_save.clicked.connect(self.save) right_grid = QtWidgets.QGridLayout() right_grid.addWidget(self.modeRect, 0, 0, 1, 20) right_grid.addWidget(self.dirTypeRect, 1, 0, 1, 20) right_grid.addWidget(self.cb_gt, 2, 0, 1, 15) right_grid.addWidget(QtWidgets.QLabel('Reference'), 2, 16, 1, 3) right_grid.addWidget(self.spin_cols, 3, 0, 1, 15) right_grid.addWidget(QtWidgets.QLabel('Set columns'), 3, 16, 1, 3) right_grid.addWidget(self.txt_scale, 4, 0, 1, 1) right_grid.addWidget(self.slider_scale, 4, 1, 1, 14) right_grid.addWidget(QtWidgets.QLabel('Set scale'), 4, 16, 1, 3) right_grid.addWidget(self.btn_run, 5, 0, 1, 20) right_grid.addWidget(self.btn_reset, 6, 0, 1, 20) right_grid.addWidget(self.btn_save, 7, 0, 1, 20) # Bottom Widget self.image_scroll = QtWidgets.QScrollArea() self.image_scroll.installEventFilter(self) # Splitter hsplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) vsplitter = QtWidgets.QSplitter(QtCore.Qt.Vertical) hsplitter.addWidget(layout2widget(left_grid)) hsplitter.addWidget(layout2widget(right_grid)) hsplitter.setStretchFactor(0, 1) hsplitter.setStretchFactor(1, 2) vsplitter.addWidget(hsplitter) vsplitter.addWidget(self.image_scroll) vsplitter.setStretchFactor(0, 1) vsplitter.setStretchFactor(1, 5) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(vsplitter) self.setLayout(hlayout) def open_file(self): """Open a file or directory from dialog.""" if self.btnGroup_dirType.checkedId() == 0: path = QtWidgets.QFileDialog.getExistingDirectory() if len(path) <= 0: return label = path.split('/')[-1] self.input_file.setText(path) self.input_label.setText(label) else: path, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select file', '', 'Images (*.jpg *.png)') if len(path) <= 0: return label = path.split('/')[-1].split('.')[0] self.input_file.setText(path) self.input_label.setText(label) def add_file(self): """Add opened file or directory to table.""" if os.path.exists(self.input_file.text()): row = self.tb_files.rowCount() self.tb_files.setRowCount(row + 1) self.tb_files.setItem( row, 0, QtWidgets.QTableWidgetItem(self.input_file.text())) self.tb_files.setItem( row, 1, QtWidgets.QTableWidgetItem(self.input_label.text())) # if self.cb_gt.count() == 0: # self.set_gt(self.input_file.text()) else: QtWidgets.QMessageBox.about(self, 'Message', 'Please input available file/folder') def tableMenu(self, pos): """Set mouse right button menu of table.""" menu = QtWidgets.QMenu() menu_up = menu.addAction('move up') menu_down = menu.addAction('move down') menu_delete = menu.addAction('delete') menu_gt = menu.addAction('set reference') menu_pos = self.tb_files.mapToGlobal(pos) row = None for i in self.tb_files.selectionModel().selection().indexes(): row = i.row() if row is None or row >= self.tb_files.rowCount(): return action = menu.exec(menu_pos) if action == menu_up: self.tb_swap(row, -1) elif action == menu_down: self.tb_swap(row, 1) elif action == menu_delete: self.tb_files.removeRow(row) elif action == menu_gt: for r in range(self.tb_files.rowCount()): self.tb_files.setItem(r, 2, QtWidgets.QTableWidgetItem('')) self.tb_files.setItem(row, 2, QtWidgets.QTableWidgetItem('Reference')) self.set_gt(self.tb_files.item(row, 0).text()) if self.isShow: self.run() def tb_swap(self, row, move): """Move items of table.""" if move == -1: if 0 == row: return target = row - 1 elif move == 1: if self.tb_files.rowCount() - 1 == row: return target = row + 1 for col in range(self.tb_files.columnCount()): tmp = self.tb_files.takeItem(row, col) self.tb_files.setItem(row, col, self.tb_files.takeItem(target, col)) self.tb_files.setItem(target, col, tmp) def set_gt(self, path): """Set GT ComboBox items.""" self.cb_gt.clear() if os.path.isfile(path): self.cb_gt.addItem(path) else: files = sorted(os.listdir(path)) for f in files: self.cb_gt.addItem(path + '/' + f) def change_gt(self): if self.isShow: self.run() def set_scale(self): """Set scale.""" scale = self.slider_scale.value() self.txt_scale.setText(f'{scale} %') self.scale = scale if self.isShow: rect = None if self.rect: rect = [ int(r * scale / 100.0 / self.old_scale) for r in self.rect ] self.run(rect) def set_column(self): """Set column.""" if self.isShow: self.run() def run(self, rect=None): """Generate patch compare result.""" if self.cb_gt.currentText() == '': QtWidgets.QMessageBox.about(self, 'Message', 'Please set gt!') return rows = self.tb_files.rowCount() if rows <= 0: QtWidgets.QMessageBox.about(self, 'Message', 'Please add a file at least!') return files = [] self.labels = [] for r in range(rows): if self.tb_files.item(r, 2).text() != 'Reference': files.append(self.tb_files.item(r, 0).text()) self.labels.append(self.tb_files.item(r, 1).text()) file_name = os.path.basename(self.cb_gt.currentText()) self.file_paths = [] for i, file in enumerate(files): if self.btnGroup_dirType.checkedId() == 0: self.file_paths.append(file + '/' + file_name) else: self.file_paths.append(file) mode = self.btnGroup_mode.checkedId() self.images = ConcatImageWidget(self, mode, self.spin_cols.value()) self.images.set_images(self.file_paths, self.labels, self.cb_gt.currentText(), self.scale / 100.0, rect) self.image_scroll.setWidget(self.images) self.isShow = True def reset(self): """Init window.""" self.file_paths = [] self.labels = [] self.isShow = False self.input_label.clear() self.input_file.clear() self.tb_files.setRowCount(0) self.cb_gt.clear() self.spin_cols.setValue(4) self.slider_scale.setValue(100) self.images = ConcatImageWidget(self, 0, self.spin_cols.value()) self.image_scroll.setWidget(self.images) def save(self): """Save patch compare result.""" path, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'save') if len(path) <= 0: return if self.images: self.images.grab().save(path) QtWidgets.QMessageBox.about(self, 'Message', 'Success!') else: QtWidgets.QMessageBox.about(self, 'Message', 'Nothing to save.') def wheelEvent(self, ev) -> None: key = QtWidgets.QApplication.keyboardModifiers() if key == QtCore.Qt.ControlModifier: scale = ev.angleDelta().y() / 120 self.scale += scale if self.scale < 1: self.scale = 1 self.txt_scale.setText(f'{self.scale} %') self.slider_scale.setValue(self.scale) if self.scale > 200 and self.isShow: rect = None if self.rect: rect = [ int(r * self.scale / 100.0 / self.old_scale) for r in self.rect ] self.run(rect) return super().wheelEvent(ev) def keyPressEvent(self, ev) -> None: if ev.key() == QtCore.Qt.Key_Left: if self.cb_gt.currentIndex() > 0: self.cb_gt.setCurrentIndex(self.cb_gt.currentIndex() - 1) else: self.cb_gt.setCurrentIndex(self.cb_gt.count() - 1) elif ev.key() == QtCore.Qt.Key_Right: if self.cb_gt.currentIndex() < self.cb_gt.count() - 1: self.cb_gt.setCurrentIndex(self.cb_gt.currentIndex() + 1) else: self.cb_gt.setCurrentIndex(0) return super().keyPressEvent(ev) def eventFilter(self, object, event) -> bool: if object == self.image_scroll: if event.type() == QtCore.QEvent.KeyPress: self.keyPressEvent(event) return False return super().eventFilter(object, event) class SliderTab(QtWidgets.QWidget): def __init__(self, parent): super().__init__() self.parent = parent self.images = [None, None] self.imageArea = None # Type setting self.typeRect = QtWidgets.QGroupBox('Type') self.typeRect.setFlat(True) btn_type1 = QtWidgets.QRadioButton('Video', self.typeRect) btn_type2 = QtWidgets.QRadioButton('Image', self.typeRect) self.btnGroup_type = QtWidgets.QButtonGroup() self.btnGroup_type.addButton(btn_type1, 0) self.btnGroup_type.addButton(btn_type2, 1) self.btnGroup_type.button(0).setChecked(True) self.btnGroup_type.idToggled.connect(self.reset) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(btn_type1) hlayout.addWidget(btn_type2) self.typeRect.setLayout(hlayout) # Mode setting self.modeRect = QtWidgets.QGroupBox('Mode') self.modeRect.setFlat(True) btn_mode1 = QtWidgets.QRadioButton('Match', self.modeRect) btn_mode2 = QtWidgets.QRadioButton('Single', self.modeRect) self.btnGroup_mode = QtWidgets.QButtonGroup() self.btnGroup_mode.addButton(btn_mode1, 0) self.btnGroup_mode.addButton(btn_mode2, 1) self.btnGroup_mode.button(0).setChecked(True) self.btnGroup_mode.idToggled.connect(self.reset) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(btn_mode1) hlayout.addWidget(btn_mode2) self.modeRect.setLayout(hlayout) # Settings self.cb_1 = QtWidgets.QComboBox() self.cb_2 = QtWidgets.QComboBox() self.cb_1.currentIndexChanged.connect(self.change_image_1) self.cb_2.currentIndexChanged.connect(self.change_image_2) self.input_label_1 = QtWidgets.QLineEdit() self.input_label_2 = QtWidgets.QLineEdit() self.input_title = QtWidgets.QLineEdit() self.input_label_1.textChanged.connect(self.set_label) self.input_label_2.textChanged.connect(self.set_label) self.input_title.textChanged.connect(self.set_label) # Set scale self.scale = 100 self.txt_scale = QtWidgets.QLabel('100 %') self.slider_scale = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_scale.setMinimum(1) self.slider_scale.setMaximum(200) self.slider_scale.setValue(100) self.slider_scale.valueChanged.connect(self.set_scale) # Auto slider setting self.autoRect = QtWidgets.QGroupBox('Auto Slider') self.autoRect.setFlat(True) btn_autoMode1 = QtWidgets.QRadioButton('Right', self.autoRect) btn_autoMode2 = QtWidgets.QRadioButton('Left', self.autoRect) btn_autoMode3 = QtWidgets.QRadioButton('Alternate', self.autoRect) self.btnGroup_auto = QtWidgets.QButtonGroup() self.btnGroup_auto.addButton(btn_autoMode1, 0) self.btnGroup_auto.addButton(btn_autoMode2, 1) self.btnGroup_auto.addButton(btn_autoMode3, 2) self.btnGroup_auto.button(2).setChecked(True) self.btnGroup_auto.idToggled.connect(self.set_autoSlider) self.slider_auto = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_auto.setMinimum(0) self.slider_auto.setMaximum(200) self.slider_auto.setValue(0) self.slider_auto.valueChanged.connect(self.set_autoSlider) glayout = QtWidgets.QGridLayout() glayout.addWidget(QtWidgets.QLabel('Direction:'), 0, 0, 1, 1) glayout.addWidget(btn_autoMode3, 0, 2, 1, 1) glayout.addWidget(btn_autoMode1, 0, 3, 1, 1) glayout.addWidget(btn_autoMode2, 0, 4, 1, 1) glayout.addWidget(QtWidgets.QLabel('Speed:'), 1, 0, 1, 1) glayout.addWidget(self.slider_auto, 1, 1, 1, 4) self.autoRect.setLayout(glayout) # Add file self.btn_add_1 = QtWidgets.QPushButton() self.btn_add_2 = QtWidgets.QPushButton() self.btn_add_1.setText('Add a video') self.btn_add_2.setText('Add frames') self.btn_add_1.clicked.connect(self.add_1) self.btn_add_2.clicked.connect(self.add_2) # Buttons self.btn_pause = QtWidgets.QPushButton() self.btn_pause.setText('Pause (Space)') self.btn_pause.clicked.connect(self.pause) self.btn_pause.setEnabled(False) self.btn_reset = QtWidgets.QPushButton() self.btn_reset.setText('Reset') self.btn_reset.clicked.connect(self.reset) self.btn_save = QtWidgets.QPushButton() self.btn_save.setText('Save') self.btn_save.clicked.connect(self.save) self.btn_record = QtWidgets.QPushButton() self.btn_record.setText('Record (Enter)') self.btn_record.clicked.connect(self.record) self.txt_prompt = QtWidgets.QLabel() self.txt_prompt.setStyleSheet('color: red; font-size: 28px') left_grid = QtWidgets.QGridLayout() left_grid.addWidget(self.typeRect, 0, 0, 1, 10) left_grid.addWidget(self.modeRect, 1, 0, 1, 10) left_grid.addWidget(QtWidgets.QLabel('Left'), 2, 0, 1, 1) left_grid.addWidget(self.cb_1, 2, 1, 1, 9) left_grid.addWidget(QtWidgets.QLabel('Right'), 3, 0, 1, 1) left_grid.addWidget(self.cb_2, 3, 1, 1, 9) left_grid.addWidget(QtWidgets.QLabel('Set label 1'), 4, 0, 1, 1) left_grid.addWidget(self.input_label_1, 4, 1, 1, 9) left_grid.addWidget(QtWidgets.QLabel('Set label 2'), 5, 0, 1, 1) left_grid.addWidget(self.input_label_2, 5, 1, 1, 9) left_grid.addWidget(QtWidgets.QLabel('Set title'), 6, 0, 1, 1) left_grid.addWidget(self.input_title, 6, 1, 1, 9) left_grid.addWidget(QtWidgets.QLabel('Set scale'), 7, 0, 1, 1) left_grid.addWidget(self.slider_scale, 7, 1, 1, 8) left_grid.addWidget(self.txt_scale, 7, 9, 1, 1) left_grid.addWidget(self.autoRect, 8, 0, 1, 10) left_grid.addWidget(self.btn_add_1, 9, 0, 1, 5) left_grid.addWidget(self.btn_add_2, 9, 5, 1, 5) left_grid.addWidget(self.btn_pause, 10, 0, 1, 10) left_grid.addWidget(self.btn_reset, 11, 0, 1, 10) left_grid.addWidget(self.btn_save, 12, 0, 1, 10) left_grid.addWidget(self.btn_record, 13, 0, 1, 10) left_grid.addWidget(QtWidgets.QLabel(), 14, 0, 10, 10) left_grid.addWidget(self.txt_prompt, 25, 0, 20, 10) # Image area self.image_scroll = QtWidgets.QScrollArea() self.image_scroll.setAlignment(QtCore.Qt.AlignCenter) self.image_scroll.installEventFilter(self) right_grid = QtWidgets.QGridLayout() right_grid.addWidget(self.image_scroll, 0, 0) # Splitter hsplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) hsplitter.addWidget(layout2widget(left_grid)) hsplitter.addWidget(layout2widget(right_grid)) hsplitter.setStretchFactor(0, 1) hsplitter.setStretchFactor(1, 5) hlayout = QtWidgets.QHBoxLayout() hlayout.addWidget(hsplitter) self.setLayout(hlayout) # Timer self.timer_slider = QtCore.QTimer(self) self.timer_slider.timeout.connect(self.auto_slider) self.timer_record = QtCore.QTimer(self) self.timer_record.timeout.connect(self.recording) # Player self.player = VideoSlider(self) self.player.sigout.connect(self.setImg) # self.player1_end = False # self.player2_end = False # self.player1 = VideoPlayer(self) # self.player2 = VideoPlayer(self) # self.player1.sigout.connect(self.setImg1) # self.player2.sigout.connect(self.setImg2) # self.player1.sigend.connect(self.set_player1) # self.player2.sigend.connect(self.set_player2) self.record_num = 0 self.show_image() def set_autoSlider(self): if self.imageArea: self.timer_slider.stop() if self.slider_auto.value() > 0: self.imageArea.set_auoMode(self.btnGroup_auto.checkedId() + 1) self.timer_slider.start(1000 / (self.slider_auto.value())) else: self.imageArea.set_auoMode(0) def auto_slider(self): self.imageArea.auto_slider() def add_image(self, cb, btn): if self.btnGroup_mode.checkedId() == 0: path = QtWidgets.QFileDialog.getExistingDirectory(self) if len(path) <= 0: return cb.clear() files = sorted(os.listdir(path)) for f in files: cb.addItem(path + '/' + f) else: if btn == 'add_1': path, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select gt file', '', 'Images (*.jpg *.png)') if len(path) <= 0: return files = [path] elif btn == 'add_2': paths = QtWidgets.QFileDialog.getExistingDirectory(self) if len(paths) <= 0: return files = sorted(os.listdir(paths)) files = [paths + '/' + f for f in files] for path in files: if self.cb_1.count() > 0: if self.cb_1.findText(path) > -1: self.cb_1.removeItem(self.cb_1.findText(path)) if self.cb_2.findText(path) > -1: self.cb_2.removeItem(self.cb_2.findText(path)) self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_2.setCurrentIndex(self.cb_2.count() - 1) else: self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_1.setCurrentIndex(0) self.cb_2.setCurrentIndex(0) def add_1(self): if self.btnGroup_type.checkedId() == 1: self.add_image(self.cb_1, 'add_1') else: path, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select gt file', '', 'Images (*.mp4 *.avi)') if len(path) <= 0: return if self.cb_1.count() > 0: if self.cb_1.findText(path) > -1: self.cb_1.removeItem(self.cb_1.findText(path)) if self.cb_2.findText(path) > -1: self.cb_2.removeItem(self.cb_2.findText(path)) self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_2.setCurrentIndex(self.cb_2.count() - 1) else: self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_1.setCurrentIndex(0) self.cb_2.setCurrentIndex(0) def add_2(self): if self.btnGroup_type.checkedId() == 1: self.add_image(self.cb_2, 'add_2') else: path = QtWidgets.QFileDialog.getExistingDirectory(self) if len(path) <= 0: return if self.cb_1.count() > 0: if self.cb_1.findText(path) > -1: self.cb_1.removeItem(self.cb_1.findText(path)) if self.cb_2.findText(path) > -1: self.cb_2.removeItem(self.cb_2.findText(path)) self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_2.setCurrentIndex(self.cb_2.count() - 1) else: self.cb_1.addItem(path) self.cb_2.addItem(path) self.cb_1.setCurrentIndex(0) self.cb_2.setCurrentIndex(0) def set_label(self): if self.imageArea is not None: self.imageArea.label_1 = self.input_label_1.text() self.imageArea.label_2 = self.input_label_2.text() self.imageArea.title = self.input_title.text() self.imageArea.update() def set_scale(self): """Set scale.""" self.scale = self.slider_scale.value() self.txt_scale.setText(f'{self.scale} %') if self.imageArea is not None: self.imageArea.set_scale(self.scale / 100.0) def change_image_1(self): if self.btnGroup_type.checkedId() == 0: self.change_video() else: if self.btnGroup_mode.checkedId() == 0: self.cb_2.setCurrentIndex(self.cb_1.currentIndex()) self.images[0] = cv2.imread(self.cb_1.currentText()) self.images[1] = cv2.imread(self.cb_2.currentText()) self.show_image() def change_image_2(self): if self.btnGroup_type.checkedId() == 0: self.change_video() else: if self.btnGroup_mode.checkedId() == 0: self.cb_1.setCurrentIndex(self.cb_2.currentIndex()) self.images[0] = cv2.imread(self.cb_1.currentText()) self.images[1] = cv2.imread(self.cb_2.currentText()) self.show_image() def change_video(self): if self.cb_1.currentText() != '' and self.cb_2.currentText() != '': self.player.set(self.cb_1.currentText(), self.cb_2.currentText()) self.player.start() self.btn_pause.setEnabled(True) # def setImg1(self, img): # self.images[0] = img # self.imageArea.setImage(self.images) # def setImg2(self, img): # self.images[1] = img # self.imageArea.setImage(self.images) def setImg(self, images): self.images = images self.imageArea.setImage(self.images) def show_image(self): self.imageArea = QLabelSlider(self, self.slider_scale.value() / 100.0 + 1e-7, self.input_label_1.text(), self.input_label_2.text(), self.input_title.text()) self.imageArea.setFrameShape(QtWidgets.QFrame.Box) self.imageArea.setLineWidth(2) self.imageArea.setAlignment(QtCore.Qt.AlignBottom) self.imageArea.setStyleSheet( 'border-width: 0px; border-style: solid; border-color: rgb(100, 100, 100);background-color: rgb(255, 255, 255)' # noqa ) self.image_scroll.setWidget(self.imageArea) def pause(self): if self.btn_pause.text() == 'Pause (Space)': self.player.pause() self.timer_slider.stop() self.btn_pause.setText('Play (Space)') else: self.player.resume() self.set_autoSlider() self.btn_pause.setText('Pause (Space)') def reset(self): self.images = [None, None] self.cb_1.clear() self.cb_2.clear() self.show_image() if self.btnGroup_type.checkedId() == 1: if self.btnGroup_mode.checkedId() == 0: self.btn_add_1.setText('Set image 1') self.btn_add_2.setText('Set image 2') else: self.btn_add_1.setText('Add file') self.btn_add_2.setText('Add directory') else: self.btn_add_1.setText('Add a video') self.btn_add_2.setText('Add frames') self.btn_pause.setText('Pause (Space)') self.btn_pause.setEnabled(False) self.btn_record.setText('Record (Enter)') self.timer_slider.stop() self.timer_record.stop() def save(self): """Save slider compare result.""" path, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'save') if len(path) <= 0: return if self.imageArea: self.imageArea.grab().save(path) QtWidgets.QMessageBox.about(self, 'Message', 'Success!') else: QtWidgets.QMessageBox.about(self, 'Message', 'Nothing to save.') def record(self): if self.btn_record.text() == 'Record (Enter)': self.record_num = 0 self.timer_record.start(1000 / 25) self.txt_prompt.setText('Recording...') self.btn_record.setText('End (Enter)') elif self.btn_record.text() == 'End (Enter)': paths = sorted(os.listdir('.tmp/')) paths = ['.tmp/' + p for p in paths] if len(paths) <= 0: return img = cv2.imread(paths[0]) h, w, _ = img.shape cur = datetime.datetime.now() fname = f'{cur.year}{cur.month}{cur.day}{cur.hour}{cur.minute}{cur.second}.mp4' # noqa fourcc = cv2.VideoWriter_fourcc(*'mp4v') self.recorder = cv2.VideoWriter(fname, fourcc, 25, (w, h)) self.txt_prompt.setText('Saving...') for i in range(self.record_num): img = cv2.imread(paths[i]) img = cv2.resize(img, (w, h)) self.recorder.write(img) os.remove(paths[i]) self.recorder.release() self.timer_record.stop() self.txt_prompt.setText('') self.btn_record.setText('Record (Enter)') QtWidgets.QMessageBox.about(self, 'Message', f'Save {fname} success!') def recording(self): if not os.path.isdir('.tmp/'): os.makedirs('.tmp/') fname = '.tmp/' + str(self.record_num).zfill(8) + '.png' self.record_num += 1 self.imageArea.grab().save(fname) def wheelEvent(self, ev) -> None: key = QtWidgets.QApplication.keyboardModifiers() if key == QtCore.Qt.ControlModifier: scale = ev.angleDelta().y() / 120 self.scale += scale if self.scale < 1: self.scale = 1 self.txt_scale.setText(f'{self.scale} %') if self.scale > 200 and self.imageArea is not None: self.imageArea.set_scale(self.scale / 100.0) else: self.slider_scale.setValue(self.scale) return super().wheelEvent(ev) def keyPressEvent(self, ev) -> None: if ev.key() == QtCore.Qt.Key_Left: if self.cb_1.currentIndex() > 0: self.cb_1.setCurrentIndex(self.cb_1.currentIndex() - 1) else: self.cb_1.setCurrentIndex(self.cb_1.count() - 1) elif ev.key() == QtCore.Qt.Key_Right: if self.cb_1.currentIndex() < self.cb_1.count() - 1: self.cb_1.setCurrentIndex(self.cb_1.currentIndex() + 1) else: self.cb_1.setCurrentIndex(0) elif ev.key( ) == QtCore.Qt.Key_Enter or ev.key() + 1 == QtCore.Qt.Key_Enter: self.record() elif ev.key() == QtCore.Qt.Key_Space: self.pause() def eventFilter(self, object, event) -> bool: if object == self.image_scroll or object == self: if event.type() == QtCore.QEvent.KeyPress: self.keyPressEvent(event) return True return super().eventFilter(object, event) class SRPage(QtWidgets.QWidget): def __init__(self, parent) -> None: super().__init__() self.parent = parent self.statusBar = self.parent.statusBar self.tab_patch = PatchTab(self) self.tab_slider = SliderTab(self) self.tabs = QtWidgets.QTabWidget() self.tabs.addTab(self.tab_patch, 'patch compare') self.tabs.addTab(self.tab_slider, 'before/after slider') layout = QtWidgets.QVBoxLayout() self.setLayout(layout) layout.addWidget(self.tabs) # self.tabs.currentChanged.connect(self.tabsCurrentChanged) ================================================ FILE: tools/gui/utils.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import cv2 import numpy as np from PyQt5 import QtGui, QtWidgets def layout2widget(layout): wg = QtWidgets.QWidget() wg.setLayout(layout) return wg def qimage2array(img): w = img.width() h = img.height() img = img.convertToFormat(QtGui.QImage.Format.Format_RGBA8888) img = img.bits() img.setsize(w * h * 4) img = np.frombuffer(img, np.uint8) img = np.reshape(img, (h, w, 4)) img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR) return img ================================================ FILE: tools/model_converters/publish_model.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import subprocess import torch from packaging import version def parse_args(): parser = argparse.ArgumentParser( description='Process a checkpoint to be published') parser.add_argument('in_file', help='input checkpoint filename') parser.add_argument('out_file', help='output checkpoint filename') args = parser.parse_args() return args def process_checkpoint(in_file, out_file): checkpoint = torch.load(in_file, map_location='cpu') # remove optimizer for smaller file size if 'optimizer' in checkpoint: del checkpoint['optimizer'] # if it is necessary to remove some sensitive data in checkpoint['meta'], # add the code here. if version.parse(torch.__version__) >= version.parse('1.6'): torch.save(checkpoint, out_file, _use_new_zipfile_serialization=False) else: torch.save(checkpoint, out_file) sha = subprocess.check_output(['sha256sum', out_file]).decode() final_file = out_file.rstrip('.pth') + f'-{sha[:8]}.pth' subprocess.Popen(['mv', out_file, final_file]) def main(): args = parse_args() process_checkpoint(args.in_file, args.out_file) if __name__ == '__main__': main() ================================================ FILE: tools/slurm_test.sh ================================================ #!/usr/bin/env bash set -x PARTITION=$1 JOB_NAME=$2 CONFIG=$3 CHECKPOINT=$4 GPUS=${GPUS:-8} GPUS_PER_NODE=${GPUS_PER_NODE:-8} CPUS_PER_TASK=${CPUS_PER_TASK:-5} PY_ARGS=${@:5} SRUN_ARGS=${SRUN_ARGS:-""} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ srun -p ${PARTITION} \ --job-name=${JOB_NAME} \ --gres=gpu:${GPUS_PER_NODE} \ --ntasks=${GPUS} \ --ntasks-per-node=${GPUS_PER_NODE} \ --cpus-per-task=${CPUS_PER_TASK} \ --kill-on-bad-exit=1 \ ${SRUN_ARGS} \ python -u tools/test.py ${CONFIG} ${CHECKPOINT} --launcher="slurm" ${PY_ARGS} ================================================ FILE: tools/slurm_train.sh ================================================ #!/usr/bin/env bash export MASTER_PORT=$((12000 + $RANDOM % 20000)) set -x PARTITION=$1 JOB_NAME=$2 CONFIG=$3 WORK_DIR=$4 GPUS=${GPUS:-8} GPUS_PER_NODE=${GPUS_PER_NODE:-8} CPUS_PER_TASK=${CPUS_PER_TASK:-5} PY_ARGS=${@:5} SRUN_ARGS=${SRUN_ARGS:-""} PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ srun -p ${PARTITION} \ --job-name=${JOB_NAME} \ --gres=gpu:${GPUS_PER_NODE} \ --ntasks=${GPUS} \ --ntasks-per-node=${GPUS_PER_NODE} \ --cpus-per-task=${CPUS_PER_TASK} \ --kill-on-bad-exit=1 \ ${SRUN_ARGS} \ python -u tools/train.py ${CONFIG} --work-dir=${WORK_DIR} --launcher="slurm" ${PY_ARGS} ================================================ FILE: tools/test.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import os import os.path as osp import mmengine from mmengine.config import Config, DictAction from mmengine.hooks import Hook from mmengine.runner import Runner from mmagic.utils import print_colored_log # TODO: support fuse_conv_bn, visualization, and format_only def parse_args(): parser = argparse.ArgumentParser(description='Test (and eval) a model') parser.add_argument('config', help='test config file path') parser.add_argument('checkpoint', help='checkpoint file') parser.add_argument('--out', help='the file to save metric results.') parser.add_argument( '--work-dir', help='the directory to save the file containing evaluation metrics') parser.add_argument( '--cfg-options', nargs='+', action=DictAction, help='override some settings in the used config, the key-value pair ' 'in xxx=yyy format will be merged into config file. If the value to ' 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 'Note that the quotation marks are necessary and that no white space ' 'is allowed.') parser.add_argument( '--launcher', choices=['none', 'pytorch', 'slurm', 'mpi'], default='none', help='job launcher') # When using PyTorch version >= 2.0.0, the `torch.distributed.launch` # will pass the `--local-rank` parameter to `tools/train.py` instead # of `--local_rank`. parser.add_argument('--local_rank', '--local-rank', type=int, default=0) args = parser.parse_args() if 'LOCAL_RANK' not in os.environ: os.environ['LOCAL_RANK'] = str(args.local_rank) return args def main(): args = parse_args() # load config cfg = Config.fromfile(args.config) cfg.launcher = args.launcher if args.cfg_options is not None: cfg.merge_from_dict(args.cfg_options) # work_dir is determined in this priority: CLI > segment in file > filename if args.work_dir is not None: # update configs according to CLI args if args.work_dir is not None cfg.work_dir = args.work_dir elif cfg.get('work_dir', None) is None: # use config filename as default work_dir if cfg.work_dir is None cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0]) cfg.load_from = args.checkpoint # build the runner from config runner = Runner.from_cfg(cfg) print_colored_log(f'Working directory: {cfg.work_dir}') print_colored_log(f'Log directory: {runner._log_dir}') if args.out: class SaveMetricHook(Hook): def after_test_epoch(self, _, metrics=None): if metrics is not None: mmengine.dump(metrics, args.out) runner.register_hook(SaveMetricHook(), 'LOWEST') # start testing runner.test() if __name__ == '__main__': main() ================================================ FILE: tools/train.py ================================================ # Copyright (c) OpenMMLab. All rights reserved. import argparse import logging import os import os.path as osp from mmengine.config import Config, DictAction from mmengine.runner import Runner from mmagic.utils import print_colored_log def parse_args(): parser = argparse.ArgumentParser(description='Train a model') parser.add_argument('config', help='train config file path') parser.add_argument('--work-dir', help='the dir to save logs and models') parser.add_argument( '--resume', action='store_true', help='Whether to resume checkpoint.') parser.add_argument( '--amp', action='store_true', default=False, help='enable automatic-mixed-precision training') parser.add_argument( '--auto-scale-lr', action='store_true', help='enable automatically scaling LR.') parser.add_argument( '--cfg-options', nargs='+', action=DictAction, help='override some settings in the used config, the key-value pair ' 'in xxx=yyy format will be merged into config file. If the value to ' 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 'Note that the quotation marks are necessary and that no white space ' 'is allowed.') parser.add_argument( '--launcher', choices=['none', 'pytorch', 'slurm', 'mpi'], default='none', help='job launcher') # When using PyTorch version >= 2.0.0, the `torch.distributed.launch` # will pass the `--local-rank` parameter to `tools/train.py` instead # of `--local_rank`. parser.add_argument('--local_rank', '--local-rank', type=int, default=0) args = parser.parse_args() if 'LOCAL_RANK' not in os.environ: os.environ['LOCAL_RANK'] = str(args.local_rank) return args def main(): args = parse_args() # load config cfg = Config.fromfile(args.config) cfg.launcher = args.launcher if args.cfg_options is not None: cfg.merge_from_dict(args.cfg_options) # work_dir is determined in this priority: CLI > segment in file > filename if args.work_dir: # none or empty str # update configs according to CLI args if args.work_dir is not None cfg.work_dir = args.work_dir elif cfg.get('work_dir', None) is None: # use config filename as default work_dir if cfg.work_dir is None cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0]) # enable automatic-mixed-precision training if args.amp is True: if ('constructor' not in cfg.optim_wrapper) or \ cfg.optim_wrapper['constructor'] == 'DefaultOptimWrapperConstructor': # noqa optim_wrapper = cfg.optim_wrapper.type if optim_wrapper == 'AmpOptimWrapper': print_colored_log( 'AMP training is already enabled in your config.', logger='current', level=logging.WARNING) else: assert optim_wrapper == 'OptimWrapper', ( '`--amp` is only supported when the optimizer wrapper ' f'`type is OptimWrapper` but got {optim_wrapper}.') cfg.optim_wrapper.type = 'AmpOptimWrapper' cfg.optim_wrapper.loss_scale = 'dynamic' else: for key, val in cfg.optim_wrapper.items(): if isinstance(val, dict) and 'type' in val: assert val.type == 'OptimWrapper', ( '`--amp` is only supported when the optimizer wrapper ' f'`type is OptimWrapper` but got {val.type}.') cfg.optim_wrapper[key].type = 'AmpOptimWrapper' cfg.optim_wrapper[key].loss_scale = 'dynamic' if args.resume: cfg.resume = True # build the runner from config runner = Runner.from_cfg(cfg) print_colored_log(f'Working directory: {cfg.work_dir}') print_colored_log(f'Log directory: {runner._log_dir}') # start training runner.train() print_colored_log(f'Log saved under {runner._log_dir}') print_colored_log(f'Checkpoint saved under {cfg.work_dir}') if __name__ == '__main__': main()