diff --git a/.gitignore b/.gitignore index 47d1f5a..3eac843 100644 --- a/.gitignore +++ b/.gitignore @@ -131,6 +131,9 @@ dmypy.json .pyre/ wandb/ +artifacts/ +input/ +output/ *.lmdb/ *.pkl *.pt diff --git a/README.md b/README.md index 6820ea1..20b1872 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,12 @@ ## Description -Official Implementation of Barbershop. **KEEP UPDATING! Please Git Pull the latest version.** -## Updates -`2021/12/27` Add dilation and erosion parameters to smooth the boundary. - -#### `2021/12/24` Important Update: Add semantic mask inpainting module to solve the occlusion problem. Please git pull the latest version. - -`2021/12/18` Add a rough version of the project. - -`2021/06/02` Add project page. +This repository is a fork of the [official implmentation of Barbershop](https://github.com/ZPdesu/Barbershop). This repository build on the official reporsitory to add the following features: +- Combine [`main.py`](https://github.com/ZPdesu/Barbershop/blob/main/main.py) and [`align_face.py`](https://github.com/ZPdesu/Barbershop/blob/main/align_face.py) into a single command line interface as part of the updated [`main.py`](https://github.com/soumik12345/Barbershop/blob/main/main.py). +- Provide a notebook [`inference.ipynb`](https://github.com/soumik12345/Barbershop/blob/main/inference.ipynb) for performing step-by-step inference and visualization of the result. +- Add an integration with Weights & Biases, which enables the predictions to be visualized as a W&B Table. The integration works with both the script and the notebook. ## Installation - Clone the repository: @@ -37,36 +32,20 @@ cd Barbershop We recommend running this repository using [Anaconda](https://docs.anaconda.com/anaconda/install/). All dependencies for defining the environment are provided in `environment/environment.yaml`. - -## Download II2S images -Please download the [II2S](https://drive.google.com/drive/folders/15jsR9yy_pfDHiS9aE3HcYDgwtBbAneId?usp=sharing) -and put them in the `input/face` folder. - - -## Getting Started -Preprocess your own images. Please put the raw images in the `unprocessed` folder. -``` -python align_face.py -``` - +## Getting Started Produce realistic results: ``` -python main.py --im_path1 90.png --im_path2 15.png --im_path3 117.png --sign realistic --smooth 5 +python main.py --identity_image 90.png --structure_image 15.png --appearance_image 117.png --sign realistic --smooth 5 ``` Produce results faithful to the masks: ``` -python main.py --im_path1 90.png --im_path2 15.png --im_path3 117.png --sign fidelity --smooth 5 +python main.py --identity_image 90.png --structure_image 15.png --appearance_image 117.png --sign fidelity --smooth 5 ``` +You can also use the [Jupyter Notebook](./inference.ipynb) to producde the results. The results are now logged automatically as a Weights and Biases Table. - -## Todo List -* add a detailed readme -* update mask inpainting code -* integrate image encoder -* add preprocessing step -* ... +![](https://i.imgur.com/subthu8.png) ## Acknowledgments This code borrows heavily from [II2S](https://github.com/ZPdesu/II2S). diff --git a/align_face.py b/align_face.py index 5746794..5712483 100644 --- a/align_face.py +++ b/align_face.py @@ -6,45 +6,65 @@ from utils.shape_predictor import align_face import PIL -parser = argparse.ArgumentParser(description='Align_face') +parser = argparse.ArgumentParser(description="Align_face") -parser.add_argument('-unprocessed_dir', type=str, default='unprocessed', help='directory with unprocessed images') -parser.add_argument('-output_dir', type=str, default='input/face', help='output directory') +parser.add_argument( + "-unprocessed_dir", + type=str, + default="unprocessed", + help="directory with unprocessed images", +) +parser.add_argument( + "-output_dir", type=str, default="input/face", help="output directory" +) -parser.add_argument('-output_size', type=int, default=1024, help='size to downscale the input images to, must be power of 2') -parser.add_argument('-seed', type=int, help='manual seed to use') -parser.add_argument('-cache_dir', type=str, default='cache', help='cache directory for model weights') +parser.add_argument( + "-output_size", + type=int, + default=1024, + help="size to downscale the input images to, must be power of 2", +) +parser.add_argument("-seed", type=int, help="manual seed to use") +parser.add_argument( + "-cache_dir", type=str, default="cache", help="cache directory for model weights" +) ############### -parser.add_argument('-inter_method', type=str, default='bicubic') - +parser.add_argument("-inter_method", type=str, default="bicubic") args = parser.parse_args() +print(vars(args)) cache_dir = Path(args.cache_dir) cache_dir.mkdir(parents=True, exist_ok=True) output_dir = Path(args.output_dir) -output_dir.mkdir(parents=True,exist_ok=True) +output_dir.mkdir(parents=True, exist_ok=True) print("Downloading Shape Predictor") -f=open_url("https://drive.google.com/uc?id=1huhv8PYpNNKbGCLOaYUjOgR1pY5pmbJx", cache_dir=cache_dir, return_path=True) +f = open_url( + "https://drive.google.com/uc?id=1huhv8PYpNNKbGCLOaYUjOgR1pY5pmbJx", + cache_dir=cache_dir, + return_path=True, +) predictor = dlib.shape_predictor(f) for im in Path(args.unprocessed_dir).glob("*.*"): - faces = align_face(str(im),predictor) + faces = align_face(str(im), predictor) - for i,face in enumerate(faces): - if(args.output_size): - factor = 1024//args.output_size - assert args.output_size*factor == 1024 + for i, face in enumerate(faces): + if args.output_size: + factor = 1024 // args.output_size + assert args.output_size * factor == 1024 face_tensor = torchvision.transforms.ToTensor()(face).unsqueeze(0).cuda() face_tensor_lr = face_tensor[0].cpu().detach().clamp(0, 1) face = torchvision.transforms.ToPILImage()(face_tensor_lr) if factor != 1: - face = face.resize((args.output_size, args.output_size), PIL.Image.LANCZOS) + face = face.resize( + (args.output_size, args.output_size), PIL.Image.LANCZOS + ) if len(faces) > 1: - face.save(Path(args.output_dir) / (im.stem+f"_{i}.png")) + face.save(Path(args.output_dir) / (im.stem + f"_{i}.png")) else: - face.save(Path(args.output_dir) / (im.stem + f".png")) \ No newline at end of file + face.save(Path(args.output_dir) / (im.stem + f".png")) diff --git a/datasets/image_dataset.py b/datasets/image_dataset.py index 2701da5..aff4057 100644 --- a/datasets/image_dataset.py +++ b/datasets/image_dataset.py @@ -5,8 +5,8 @@ import torchvision.transforms as transforms import os -class ImagesDataset(Dataset): +class ImagesDataset(Dataset): def __init__(self, opts, image_path=None): if not image_path: image_root = opts.input_dir @@ -16,9 +16,12 @@ def __init__(self, opts, image_path=None): elif type(image_path) == list: self.image_paths = image_path - self.image_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) + self.image_transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), + ] + ) self.opts = opts def __len__(self): @@ -26,7 +29,7 @@ def __len__(self): def __getitem__(self, index): im_path = self.image_paths[index] - im_H = Image.open(im_path).convert('RGB') + im_H = Image.open(im_path).convert("RGB") im_L = im_H.resize((256, 256), PIL.Image.LANCZOS) im_name = os.path.splitext(os.path.basename(im_path))[0] if self.image_transform: @@ -34,6 +37,3 @@ def __getitem__(self, index): im_L = self.image_transform(im_L) return im_H, im_L, im_name - - - diff --git a/environment/environment.yml b/environment/environment.yml index f445cb0..fd9e925 100644 --- a/environment/environment.yml +++ b/environment/environment.yml @@ -160,7 +160,7 @@ dependencies: - cachetools==4.2.4 - charset-normalizer==2.0.7 - click==8.0.3 - - clip==1.0 + - clip==0.2.0 - deprecated==1.2.13 - dlib==19.22.1 - et-xmlfile==1.1.0 @@ -206,4 +206,5 @@ dependencies: - uritemplate==3.0.1 - urllib3==1.26.7 - wrapt==1.13.3 + - wandb==0.12.11 prefix: ~/.conda/envs/Barbershop diff --git a/inference.ipynb b/inference.ipynb new file mode 100644 index 0000000..1d604d9 --- /dev/null +++ b/inference.ipynb @@ -0,0 +1,516 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import dlib\n", + "import wandb\n", + "import numpy as np\n", + "from PIL import Image\n", + "from pathlib import Path\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import torch\n", + "import torchvision\n", + "\n", + "from models.Embedding import Embedding\n", + "from models.Alignment import Alignment\n", + "from models.Blending import Blending\n", + "\n", + "from utils.drive import open_url\n", + "from utils.shape_predictor import align_face" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Failed to detect the name of this notebook, you can set it manually with the WANDB_NOTEBOOK_NAME environment variable to enable code saving.\n", + "\u001b[34m\u001b[1mwandb\u001b[0m: Currently logged in as: \u001b[33mgeekyrakshit\u001b[0m (use `wandb login --relogin` to force relogin)\n" + ] + }, + { + "data": { + "text/html": [ + "Tracking run with wandb version 0.12.11" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Run data is saved locally in /home/paperspace/Workspace/Barbershop/wandb/run-20220330_184722-1btth4r6" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Syncing run firm-galaxy-18 to Weights & Biases (docs)
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "wandb.login()\n", + "wandb.init(project=\"barbershop\", entity=\"geekyrakshit\", job_type=\"predict\")\n", + "\n", + "config = wandb.config\n", + "config.wandb_project = 'barbershop'\n", + "config.wandb_entity = None\n", + "config.images_artifact = 'geekyrakshit/barbershop/II2S-Images:v0'\n", + "config.ffhq_models_artifact = 'geekyrakshit/barbershop/ffhq:v0'\n", + "config.segmentation_models_artifact = 'geekyrakshit/barbershop/segmentation:v0'\n", + "config.output_dir = 'output'\n", + "config.identity_image = '90.png'\n", + "config.structure_image = '15.png'\n", + "config.appearance_image = '117.png'\n", + "config.sign = 'realistic'\n", + "config.smooth = 5\n", + "config.size = 1024\n", + "config.channel_multiplier = 2\n", + "config.latent = 512\n", + "config.n_mlp = 8\n", + "config.device = \"cuda\"\n", + "config.seed = None\n", + "config.tile_latent = False\n", + "config.opt_name = 'adam'\n", + "config.learning_rate = 0.01\n", + "config.lr_schedule = 'fixed'\n", + "config.save_intermediate = False\n", + "config.save_interval = 300\n", + "config.verbose = False\n", + "config.percept_lambda = 1.0\n", + "config.l2_lambda = 1.0\n", + "config.p_norm_lambda = 0.001\n", + "config.l_F_lambda = 0.1\n", + "config.W_steps = 1100\n", + "config.FS_steps = 250\n", + "config.ce_lambda = 1.0\n", + "config.style_lambda = 40000.0\n", + "config.align_steps1 = 140\n", + "config.align_steps2 = 100\n", + "config.face_lambda = 1.0\n", + "config.hair_lambda = 1.0\n", + "config.blend_steps = 400\n", + "config.unprocessed_dir = 'unprocessed'\n", + "config.align_output_dir = 'input/face'\n", + "config.output_size = 1024\n", + "config.cache_dir = 'cache'\n", + "config.inter_method = 'bicubic'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def apply_align_faces(configs, identity_image):\n", + " cache_dir = Path(configs.cache_dir)\n", + " cache_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " output_dir = Path(configs.align_output_dir)\n", + " output_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " print(\"Downloading Shape Predictor\")\n", + " f = open_url(\n", + " \"https://drive.google.com/uc?id=1huhv8PYpNNKbGCLOaYUjOgR1pY5pmbJx\",\n", + " cache_dir=cache_dir,\n", + " return_path=True,\n", + " )\n", + " predictor = dlib.shape_predictor(f)\n", + "\n", + " identity_image = Path(identity_image)\n", + "\n", + " faces = align_face(str(identity_image), predictor)\n", + "\n", + " for i, face in enumerate(faces):\n", + " if configs.output_size:\n", + " factor = 1024 // configs.output_size\n", + " assert configs.output_size * factor == 1024\n", + " face_tensor = torchvision.transforms.ToTensor()(face).unsqueeze(0).cuda()\n", + " face_tensor_lr = face_tensor[0].cpu().detach().clamp(0, 1)\n", + " face = torchvision.transforms.ToPILImage()(face_tensor_lr)\n", + " if factor != 1:\n", + " face = face.resize(\n", + " (configs.output_size, configs.output_size), Image.LANCZOS\n", + " )\n", + " if len(faces) > 1:\n", + " face.save(Path(configs.align_output_dir) / (identity_image.stem + f\"_{i}.png\"))\n", + " else:\n", + " face.save(Path(configs.align_output_dir) / (identity_image.stem + f\".png\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mwandb\u001b[0m: Downloading large artifact II2S-Images:v0, 155.34MB. 120 files... Done. 0:0:0\n", + "\u001b[34m\u001b[1mwandb\u001b[0m: Downloading large artifact ffhq:v0, 126.55MB. 1 files... Done. 0:0:0\n", + "\u001b[34m\u001b[1mwandb\u001b[0m: Downloading large artifact segmentation:v0, 50.82MB. 1 files... Done. 0:0:0\n" + ] + } + ], + "source": [ + "images_artifact = wandb.use_artifact(config.images_artifact, type=\"dataset\")\n", + "images_artifact_dir = images_artifact.download()\n", + "\n", + "ffhq_model_artifact = wandb.use_artifact(\n", + " config.ffhq_models_artifact, type=\"model\"\n", + ")\n", + "ffhq_model_artifact_dir = ffhq_model_artifact.download()\n", + "ffhq_model_file = os.path.join(ffhq_model_artifact_dir, \"ffhq.pt\")\n", + "\n", + "segmentation_model_artifact = wandb.use_artifact(\n", + " config.segmentation_models_artifact, type=\"model\"\n", + ")\n", + "segmentation_model_artifact_dir = segmentation_model_artifact.download()\n", + "segmentation_model_file = os.path.join(\n", + " segmentation_model_artifact_dir, \"seg.pth\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading Shape Predictor\n", + "90.png: Number of faces detected: 1\n" + ] + } + ], + "source": [ + "identity_image = os.path.join(images_artifact_dir, config.identity_image)\n", + "structure_image = os.path.join(images_artifact_dir, config.structure_image)\n", + "appearance_image = os.path.join(images_artifact_dir, config.appearance_image)\n", + "\n", + "apply_align_faces(config, identity_image)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading StyleGAN2 from checkpoint: ./artifacts/ffhq:v0/ffhq.pt\n", + "Setting up Perceptual loss...\n", + "Loading model from: /home/paperspace/Workspace/Barbershop/losses/lpips/weights/v0.1/vgg.pth\n", + "...[net-lin [vgg]] initialized\n", + "...Done\n" + ] + } + ], + "source": [ + "device = \"cuda:0\" if torch.cuda.is_available() else \"cpu\"\n", + "\n", + "ii2s = Embedding(config, checkpoint_file=ffhq_model_file).to(device=device)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading StyleGAN2 from checkpoint: ./artifacts/ffhq:v0/ffhq.pt\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "align = Alignment(\n", + " config,\n", + " ffhq_checkpoint_file=ffhq_model_file,\n", + " segmentation_checkpoint_file=segmentation_model_file,\n", + ").to(device=device)\n", + "aligned_image = align.align_images(\n", + " identity_image,\n", + " structure_image,\n", + " sign=config.sign,\n", + " align_more_region=False,\n", + " smooth=config.smooth,\n", + ")\n", + "if structure_image != appearance_image:\n", + " aligned_image = align.align_images(\n", + " identity_image,\n", + " appearance_image,\n", + " sign=config.sign,\n", + " align_more_region=False,\n", + " smooth=config.smooth,\n", + " save_intermediate=False,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading StyleGAN2 from checkpoint: ./artifacts/ffhq:v0/ffhq.pt\n", + "Setting up Perceptual loss...\n", + "Loading model from: /home/paperspace/Workspace/Barbershop/losses/masked_lpips/weights/v0.1/vgg.pth\n", + "...[net-lin [vgg]] initialized\n", + "...Done\n", + "Setting up Perceptual loss...\n", + "Loading model from: /home/paperspace/Workspace/Barbershop/losses/masked_lpips/weights/v0.1/vgg.pth\n", + "...[net-lin [vgg]] initialized\n", + "...Done\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "blend = Blending(\n", + " config,\n", + " ffhq_checkpoint_file=ffhq_model_file,\n", + " segmentation_checkpoint_file=segmentation_model_file,\n", + ").to(device=device)\n", + "blended_image = blend.blend_images(\n", + " identity_image, structure_image, appearance_image, sign=config.sign\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_results(images, titles, figure_size=(12, 12)):\n", + " fig = plt.figure(figsize=figure_size)\n", + " for i in range(len(images)):\n", + " fig.add_subplot(1, len(images), i + 1).set_title(titles[i])\n", + " _ = plt.imshow(images[i])\n", + " plt.axis(\"off\")\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "identity_image = np.array(Image.open(identity_image))\n", + "structure_image = np.array(Image.open(structure_image))\n", + "appearance_image = np.array(Image.open(appearance_image))\n", + "\n", + "plot_results(\n", + " images=[\n", + " identity_image,\n", + " structure_image,\n", + " appearance_image,\n", + " aligned_image,\n", + " blended_image\n", + " ], titles=[\n", + " \"Identity Image\",\n", + " \"Structure Image\",\n", + " \"Appearance Image\",\n", + " \"Aligned Image\",\n", + " \"Blended Image\"\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "table_data = [[\n", + " config.sign,\n", + " wandb.Image(identity_image),\n", + " wandb.Image(structure_image),\n", + " wandb.Image(appearance_image),\n", + " wandb.Image(aligned_image),\n", + " wandb.Image(blended_image)\n", + "]]\n", + "\n", + "table = wandb.Table(\n", + " data=table_data,\n", + " columns=[\n", + " \"Realistic/Fidelity\",\n", + " \"Identity-Image\",\n", + " \"Structure-Image\",\n", + " \"Appearance-Image\",\n", + " \"Aligned-Image\",\n", + " \"Blended-Image\",\n", + " ],\n", + ")\n", + "\n", + "wandb.log({\"Predictions\": table})" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + "Waiting for W&B process to finish... (success)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "34fcf209011c4b338c6d41669182a08b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Label(value='6.339 MB of 6.339 MB uploaded (0.000 MB deduped)\\r'), FloatProgress(value=0.999970…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Synced firm-galaxy-18: https://wandb.ai/geekyrakshit/barbershop/runs/1btth4r6
Synced 6 W&B file(s), 1 media file(s), 6 artifact file(s) and 0 other file(s)" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Find logs at: ./wandb/run-20220330_184722-1btth4r6/logs" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "wandb.finish()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "fff2847cd74d0abab8e7b713e45368b315320c9df162762b3e6d925ce5c86810" + }, + "kernelspec": { + "display_name": "Python 3.7.12 ('Barbershop')", + "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.7.11" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/losses/align_loss.py b/losses/align_loss.py index 261fea8..2991bc3 100644 --- a/losses/align_loss.py +++ b/losses/align_loss.py @@ -1,43 +1,47 @@ import torch from losses.style.style_loss import StyleLoss + class AlignLossBuilder(torch.nn.Module): def __init__(self, opt): super(AlignLossBuilder, self).__init__() self.opt = opt - self.parsed_loss = [[opt.l2_lambda, 'l2'], [opt.percept_lambda, 'percep']] - if opt.device == 'cuda': + self.parsed_loss = [[opt.l2_lambda, "l2"], [opt.percept_lambda, "percep"]] + if opt.device == "cuda": use_gpu = True else: use_gpu = False self.cross_entropy = torch.nn.CrossEntropyLoss() - self.style = StyleLoss(distance="l2", VGG16_ACTIVATIONS_LIST=[3, 8, 15, 22], normalize=False).to(opt.device) + self.style = StyleLoss( + distance="l2", VGG16_ACTIVATIONS_LIST=[3, 8, 15, 22], normalize=False + ).to(opt.device) self.style.eval() - tmp = torch.zeros(16).to(opt.device) tmp[0] = 1 self.cross_entropy_wo_background = torch.nn.CrossEntropyLoss(weight=1 - tmp) self.cross_entropy_only_background = torch.nn.CrossEntropyLoss(weight=tmp) - - def cross_entropy_loss(self, down_seg, target_mask): loss = self.opt.ce_lambda * self.cross_entropy(down_seg, target_mask) return loss - def style_loss(self, im1, im2, mask1, mask2): - loss = self.opt.style_lambda * self.style(im1 * mask1, im2 * mask2, mask1=mask1, mask2=mask2) + loss = self.opt.style_lambda * self.style( + im1 * mask1, im2 * mask2, mask1=mask1, mask2=mask2 + ) return loss - def cross_entropy_loss_wo_background(self, down_seg, target_mask): - loss = self.opt.ce_lambda * self.cross_entropy_wo_background(down_seg, target_mask) + loss = self.opt.ce_lambda * self.cross_entropy_wo_background( + down_seg, target_mask + ) return loss def cross_entropy_loss_only_background(self, down_seg, target_mask): - loss = self.opt.ce_lambda * self.cross_entropy_only_background(down_seg, target_mask) - return loss \ No newline at end of file + loss = self.opt.ce_lambda * self.cross_entropy_only_background( + down_seg, target_mask + ) + return loss diff --git a/losses/blend_loss.py b/losses/blend_loss.py index 0675ca3..bb86b59 100644 --- a/losses/blend_loss.py +++ b/losses/blend_loss.py @@ -3,29 +3,28 @@ import os from losses import masked_lpips + class BlendLossBuilder(torch.nn.Module): def __init__(self, opt): super(BlendLossBuilder, self).__init__() self.opt = opt - self.parsed_loss = [[1.0, 'face'], [1.0, 'hair']] - if opt.device == 'cuda': + self.parsed_loss = [[1.0, "face"], [1.0, "hair"]] + if opt.device == "cuda": use_gpu = True else: use_gpu = False self.face_percept = masked_lpips.PerceptualLoss( - model="net-lin", net="vgg", vgg_blocks=['1', '2', '3'], use_gpu=use_gpu + model="net-lin", net="vgg", vgg_blocks=["1", "2", "3"], use_gpu=use_gpu ) self.face_percept.eval() self.hair_percept = masked_lpips.PerceptualLoss( - model="net-lin", net="vgg", vgg_blocks=['1', '2', '3'], use_gpu=use_gpu + model="net-lin", net="vgg", vgg_blocks=["1", "2", "3"], use_gpu=use_gpu ) self.hair_percept.eval() - - def _loss_face_percept(self, gen_im, ref_im, mask, **kwargs): return self.face_percept(gen_im, ref_im, mask=mask) @@ -34,29 +33,20 @@ def _loss_hair_percept(self, gen_im, ref_im, mask, **kwargs): return self.hair_percept(gen_im, ref_im, mask=mask) - def forward(self, gen_im, im_1, im_3, mask_face, mask_hair): loss = 0 loss_fun_dict = { - 'face': self._loss_face_percept, - 'hair': self._loss_hair_percept, + "face": self._loss_face_percept, + "hair": self._loss_hair_percept, } losses = {} for weight, loss_type in self.parsed_loss: - if loss_type == 'face': - var_dict = { - 'gen_im': gen_im, - 'ref_im': im_1, - 'mask': mask_face - } - elif loss_type == 'hair': - var_dict = { - 'gen_im': gen_im, - 'ref_im': im_3, - 'mask': mask_hair - } + if loss_type == "face": + var_dict = {"gen_im": gen_im, "ref_im": im_1, "mask": mask_face} + elif loss_type == "hair": + var_dict = {"gen_im": gen_im, "ref_im": im_3, "mask": mask_hair} tmp_loss = loss_fun_dict[loss_type](**var_dict) losses[loss_type] = tmp_loss - loss += weight*tmp_loss - return loss, losses \ No newline at end of file + loss += weight * tmp_loss + return loss, losses diff --git a/losses/embedding_loss.py b/losses/embedding_loss.py index 6e5324f..af1068c 100644 --- a/losses/embedding_loss.py +++ b/losses/embedding_loss.py @@ -9,9 +9,9 @@ def __init__(self, opt): super(EmbeddingLossBuilder, self).__init__() self.opt = opt - self.parsed_loss = [[opt.l2_lambda, 'l2'], [opt.percept_lambda, 'percep']] + self.parsed_loss = [[opt.l2_lambda, "l2"], [opt.percept_lambda, "percep"]] self.l2 = torch.nn.MSELoss() - if opt.device == 'cuda': + if opt.device == "cuda": use_gpu = True else: use_gpu = False @@ -19,39 +19,33 @@ def __init__(self, opt): self.percept.eval() # self.percept = VGGLoss() - - - def _loss_l2(self, gen_im, ref_im, **kwargs): return self.l2(gen_im, ref_im) - def _loss_lpips(self, gen_im, ref_im, **kwargs): return self.percept(gen_im, ref_im).sum() - - - def forward(self, ref_im_H,ref_im_L, gen_im_H, gen_im_L): + def forward(self, ref_im_H, ref_im_L, gen_im_H, gen_im_L): loss = 0 loss_fun_dict = { - 'l2': self._loss_l2, - 'percep': self._loss_lpips, + "l2": self._loss_l2, + "percep": self._loss_lpips, } losses = {} for weight, loss_type in self.parsed_loss: - if loss_type == 'l2': + if loss_type == "l2": var_dict = { - 'gen_im': gen_im_H, - 'ref_im': ref_im_H, + "gen_im": gen_im_H, + "ref_im": ref_im_H, } - elif loss_type == 'percep': + elif loss_type == "percep": var_dict = { - 'gen_im': gen_im_L, - 'ref_im': ref_im_L, + "gen_im": gen_im_L, + "ref_im": ref_im_L, } tmp_loss = loss_fun_dict[loss_type](**var_dict) losses[loss_type] = tmp_loss - loss += weight*tmp_loss - return loss, losses \ No newline at end of file + loss += weight * tmp_loss + return loss, losses diff --git a/losses/lpips/__init__.py b/losses/lpips/__init__.py index 2dd73e7..47a8fb0 100644 --- a/losses/lpips/__init__.py +++ b/losses/lpips/__init__.py @@ -1,4 +1,3 @@ - from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -10,18 +9,34 @@ from ..lpips import dist_model + class PerceptualLoss(torch.nn.Module): - def __init__(self, model='net-lin', net='alex', colorspace='rgb', spatial=False, use_gpu=True, gpu_ids=[0]): # VGG using our perceptually-learned weights (LPIPS metric) - # def __init__(self, model='net', net='vgg', use_gpu=True): # "default" way of using VGG as a perceptual loss + def __init__( + self, + model="net-lin", + net="alex", + colorspace="rgb", + spatial=False, + use_gpu=True, + gpu_ids=[0], + ): # VGG using our perceptually-learned weights (LPIPS metric) + # def __init__(self, model='net', net='vgg', use_gpu=True): # "default" way of using VGG as a perceptual loss super(PerceptualLoss, self).__init__() - print('Setting up Perceptual loss...') + print("Setting up Perceptual loss...") self.use_gpu = use_gpu self.spatial = spatial self.gpu_ids = gpu_ids self.model = dist_model.DistModel() - self.model.initialize(model=model, net=net, use_gpu=use_gpu, colorspace=colorspace, spatial=self.spatial, gpu_ids=gpu_ids) - print('...[%s] initialized'%self.model.name()) - print('...Done') + self.model.initialize( + model=model, + net=net, + use_gpu=use_gpu, + colorspace=colorspace, + spatial=self.spatial, + gpu_ids=gpu_ids, + ) + print("...[%s] initialized" % self.model.name()) + print("...Done") def forward(self, pred, target, normalize=False): """ @@ -34,107 +49,127 @@ def forward(self, pred, target, normalize=False): """ if normalize: - target = 2 * target - 1 - pred = 2 * pred - 1 + target = 2 * target - 1 + pred = 2 * pred - 1 return self.model.forward(target, pred) -def normalize_tensor(in_feat,eps=1e-10): - norm_factor = torch.sqrt(torch.sum(in_feat**2,dim=1,keepdim=True)) - return in_feat/(norm_factor+eps) -def l2(p0, p1, range=255.): - return .5*np.mean((p0 / range - p1 / range)**2) +def normalize_tensor(in_feat, eps=1e-10): + norm_factor = torch.sqrt(torch.sum(in_feat**2, dim=1, keepdim=True)) + return in_feat / (norm_factor + eps) + + +def l2(p0, p1, range=255.0): + return 0.5 * np.mean((p0 / range - p1 / range) ** 2) + + +def psnr(p0, p1, peak=255.0): + return 10 * np.log10(peak**2 / np.mean((1.0 * p0 - 1.0 * p1) ** 2)) -def psnr(p0, p1, peak=255.): - return 10*np.log10(peak**2/np.mean((1.*p0-1.*p1)**2)) -def dssim(p0, p1, range=255.): - return (1 - structural_similarity(p0, p1, data_range=range, multichannel=True)) / 2. +def dssim(p0, p1, range=255.0): + return ( + 1 - structural_similarity(p0, p1, data_range=range, multichannel=True) + ) / 2.0 -def rgb2lab(in_img,mean_cent=False): + +def rgb2lab(in_img, mean_cent=False): from skimage import color + img_lab = color.rgb2lab(in_img) - if(mean_cent): - img_lab[:,:,0] = img_lab[:,:,0]-50 + if mean_cent: + img_lab[:, :, 0] = img_lab[:, :, 0] - 50 return img_lab + def tensor2np(tensor_obj): # change dimension of a tensor object into a numpy array - return tensor_obj[0].cpu().float().numpy().transpose((1,2,0)) + return tensor_obj[0].cpu().float().numpy().transpose((1, 2, 0)) + def np2tensor(np_obj): - # change dimenion of np array into tensor array + # change dimenion of np array into tensor array return torch.Tensor(np_obj[:, :, :, np.newaxis].transpose((3, 2, 0, 1))) -def tensor2tensorlab(image_tensor,to_norm=True,mc_only=False): + +def tensor2tensorlab(image_tensor, to_norm=True, mc_only=False): # image tensor to lab tensor from skimage import color img = tensor2im(image_tensor) img_lab = color.rgb2lab(img) - if(mc_only): - img_lab[:,:,0] = img_lab[:,:,0]-50 - if(to_norm and not mc_only): - img_lab[:,:,0] = img_lab[:,:,0]-50 - img_lab = img_lab/100. + if mc_only: + img_lab[:, :, 0] = img_lab[:, :, 0] - 50 + if to_norm and not mc_only: + img_lab[:, :, 0] = img_lab[:, :, 0] - 50 + img_lab = img_lab / 100.0 return np2tensor(img_lab) -def tensorlab2tensor(lab_tensor,return_inbnd=False): + +def tensorlab2tensor(lab_tensor, return_inbnd=False): from skimage import color import warnings + warnings.filterwarnings("ignore") - lab = tensor2np(lab_tensor)*100. - lab[:,:,0] = lab[:,:,0]+50 + lab = tensor2np(lab_tensor) * 100.0 + lab[:, :, 0] = lab[:, :, 0] + 50 - rgb_back = 255.*np.clip(color.lab2rgb(lab.astype('float')),0,1) - if(return_inbnd): + rgb_back = 255.0 * np.clip(color.lab2rgb(lab.astype("float")), 0, 1) + if return_inbnd: # convert back to lab, see if we match - lab_back = color.rgb2lab(rgb_back.astype('uint8')) - mask = 1.*np.isclose(lab_back,lab,atol=2.) - mask = np2tensor(np.prod(mask,axis=2)[:,:,np.newaxis]) - return (im2tensor(rgb_back),mask) + lab_back = color.rgb2lab(rgb_back.astype("uint8")) + mask = 1.0 * np.isclose(lab_back, lab, atol=2.0) + mask = np2tensor(np.prod(mask, axis=2)[:, :, np.newaxis]) + return (im2tensor(rgb_back), mask) else: return im2tensor(rgb_back) + def rgb2lab(input): from skimage import color - return color.rgb2lab(input / 255.) -def tensor2im(image_tensor, imtype=np.uint8, cent=1., factor=255./2.): + return color.rgb2lab(input / 255.0) + + +def tensor2im(image_tensor, imtype=np.uint8, cent=1.0, factor=255.0 / 2.0): image_numpy = image_tensor[0].cpu().float().numpy() image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + cent) * factor return image_numpy.astype(imtype) -def im2tensor(image, imtype=np.uint8, cent=1., factor=255./2.): - return torch.Tensor((image / factor - cent) - [:, :, :, np.newaxis].transpose((3, 2, 0, 1))) + +def im2tensor(image, imtype=np.uint8, cent=1.0, factor=255.0 / 2.0): + return torch.Tensor( + (image / factor - cent)[:, :, :, np.newaxis].transpose((3, 2, 0, 1)) + ) + def tensor2vec(vector_tensor): return vector_tensor.data.cpu().numpy()[:, :, 0, 0] + def voc_ap(rec, prec, use_07_metric=False): - """ ap = voc_ap(rec, prec, [use_07_metric]) + """ap = voc_ap(rec, prec, [use_07_metric]) Compute VOC AP given precision and recall. If use_07_metric is true, uses the VOC 07 11 point method (default:False). """ if use_07_metric: # 11 point metric - ap = 0. - for t in np.arange(0., 1.1, 0.1): + ap = 0.0 + for t in np.arange(0.0, 1.1, 0.1): if np.sum(rec >= t) == 0: p = 0 else: p = np.max(prec[rec >= t]) - ap = ap + p / 11. + ap = ap + p / 11.0 else: # correct AP calculation # first append sentinel values at the end - mrec = np.concatenate(([0.], rec, [1.])) - mpre = np.concatenate(([0.], prec, [0.])) + mrec = np.concatenate(([0.0], rec, [1.0])) + mpre = np.concatenate(([0.0], prec, [0.0])) # compute the precision envelope for i in range(mpre.size - 1, 0, -1): @@ -148,13 +183,16 @@ def voc_ap(rec, prec, use_07_metric=False): ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) return ap -def tensor2im(image_tensor, imtype=np.uint8, cent=1., factor=255./2.): -# def tensor2im(image_tensor, imtype=np.uint8, cent=1., factor=1.): + +def tensor2im(image_tensor, imtype=np.uint8, cent=1.0, factor=255.0 / 2.0): + # def tensor2im(image_tensor, imtype=np.uint8, cent=1., factor=1.): image_numpy = image_tensor[0].cpu().float().numpy() image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + cent) * factor return image_numpy.astype(imtype) -def im2tensor(image, imtype=np.uint8, cent=1., factor=255./2.): -# def im2tensor(image, imtype=np.uint8, cent=1., factor=1.): - return torch.Tensor((image / factor - cent) - [:, :, :, np.newaxis].transpose((3, 2, 0, 1))) + +def im2tensor(image, imtype=np.uint8, cent=1.0, factor=255.0 / 2.0): + # def im2tensor(image, imtype=np.uint8, cent=1., factor=1.): + return torch.Tensor( + (image / factor - cent)[:, :, :, np.newaxis].transpose((3, 2, 0, 1)) + ) diff --git a/losses/lpips/base_model.py b/losses/lpips/base_model.py index 8de1d16..20b3b34 100644 --- a/losses/lpips/base_model.py +++ b/losses/lpips/base_model.py @@ -5,12 +5,13 @@ from pdb import set_trace as st from IPython import embed -class BaseModel(): + +class BaseModel: def __init__(self): - pass; - + pass + def name(self): - return 'BaseModel' + return "BaseModel" def initialize(self, use_gpu=True, gpu_ids=[0]): self.use_gpu = use_gpu @@ -36,15 +37,15 @@ def save(self, label): # helper saving function that can be used by subclasses def save_network(self, network, path, network_label, epoch_label): - save_filename = '%s_net_%s.pth' % (epoch_label, network_label) + save_filename = "%s_net_%s.pth" % (epoch_label, network_label) save_path = os.path.join(path, save_filename) torch.save(network.state_dict(), save_path) # helper loading function that can be used by subclasses def load_network(self, network, network_label, epoch_label): - save_filename = '%s_net_%s.pth' % (epoch_label, network_label) + save_filename = "%s_net_%s.pth" % (epoch_label, network_label) save_path = os.path.join(self.save_dir, save_filename) - print('Loading network from %s'%save_path) + print("Loading network from %s" % save_path) network.load_state_dict(torch.load(save_path)) def update_learning_rate(): @@ -54,5 +55,11 @@ def get_image_paths(self): return self.image_paths def save_done(self, flag=False): - np.save(os.path.join(self.save_dir, 'done_flag'),flag) - np.savetxt(os.path.join(self.save_dir, 'done_flag'),[flag,],fmt='%i') + np.save(os.path.join(self.save_dir, "done_flag"), flag) + np.savetxt( + os.path.join(self.save_dir, "done_flag"), + [ + flag, + ], + fmt="%i", + ) diff --git a/losses/lpips/dist_model.py b/losses/lpips/dist_model.py index 6c69380..45caa2b 100644 --- a/losses/lpips/dist_model.py +++ b/losses/lpips/dist_model.py @@ -1,4 +1,3 @@ - from __future__ import absolute_import import sys @@ -21,14 +20,29 @@ from . import networks_basic as networks from losses import lpips as util + class DistModel(BaseModel): def name(self): return self.model_name - def initialize(self, model='net-lin', net='alex', colorspace='Lab', pnet_rand=False, pnet_tune=False, model_path=None, - use_gpu=True, printNet=False, spatial=False, - is_train=False, lr=.0001, beta1=0.5, version='0.1', gpu_ids=[0]): - ''' + def initialize( + self, + model="net-lin", + net="alex", + colorspace="Lab", + pnet_rand=False, + pnet_tune=False, + model_path=None, + use_gpu=True, + printNet=False, + spatial=False, + is_train=False, + lr=0.0001, + beta1=0.5, + version="0.1", + gpu_ids=[0], + ): + """ INPUTS model - ['net-lin'] for linearly calibrated network ['net'] for off-the-shelf network @@ -48,7 +62,7 @@ def initialize(self, model='net-lin', net='alex', colorspace='Lab', pnet_rand=Fa beta1 - float - initial momentum term for adam version - 0.1 for latest, 0.0 was original (with a bug) gpu_ids - int array - [0] by default, gpus to use - ''' + """ BaseModel.initialize(self, use_gpu=use_gpu, gpu_ids=gpu_ids) self.model = model @@ -56,63 +70,83 @@ def initialize(self, model='net-lin', net='alex', colorspace='Lab', pnet_rand=Fa self.is_train = is_train self.spatial = spatial self.gpu_ids = gpu_ids - self.model_name = '%s [%s]'%(model,net) - - if(self.model == 'net-lin'): # pretrained net + linear layer - self.net = networks.PNetLin(pnet_rand=pnet_rand, pnet_tune=pnet_tune, pnet_type=net, - use_dropout=True, spatial=spatial, version=version, lpips=True) + self.model_name = "%s [%s]" % (model, net) + + if self.model == "net-lin": # pretrained net + linear layer + self.net = networks.PNetLin( + pnet_rand=pnet_rand, + pnet_tune=pnet_tune, + pnet_type=net, + use_dropout=True, + spatial=spatial, + version=version, + lpips=True, + ) kw = {} if not use_gpu: - kw['map_location'] = 'cpu' - if(model_path is None): + kw["map_location"] = "cpu" + if model_path is None: import inspect - model_path = os.path.abspath(os.path.join(inspect.getfile(self.initialize), '..', 'weights/v%s/%s.pth'%(version,net))) - if(not is_train): - print('Loading model from: %s'%model_path) + model_path = os.path.abspath( + os.path.join( + inspect.getfile(self.initialize), + "..", + "weights/v%s/%s.pth" % (version, net), + ) + ) + + if not is_train: + print("Loading model from: %s" % model_path) self.net.load_state_dict(torch.load(model_path, **kw), strict=False) - elif(self.model=='net'): # pretrained network + elif self.model == "net": # pretrained network self.net = networks.PNetLin(pnet_rand=pnet_rand, pnet_type=net, lpips=False) - elif(self.model in ['L2','l2']): - self.net = networks.L2(use_gpu=use_gpu,colorspace=colorspace) # not really a network, only for testing - self.model_name = 'L2' - elif(self.model in ['DSSIM','dssim','SSIM','ssim']): - self.net = networks.DSSIM(use_gpu=use_gpu,colorspace=colorspace) - self.model_name = 'SSIM' + elif self.model in ["L2", "l2"]: + self.net = networks.L2( + use_gpu=use_gpu, colorspace=colorspace + ) # not really a network, only for testing + self.model_name = "L2" + elif self.model in ["DSSIM", "dssim", "SSIM", "ssim"]: + self.net = networks.DSSIM(use_gpu=use_gpu, colorspace=colorspace) + self.model_name = "SSIM" else: raise ValueError("Model [%s] not recognized." % self.model) self.parameters = list(self.net.parameters()) - if self.is_train: # training mode + if self.is_train: # training mode # extra network on top to go from distances (d0,d1) => predicted human judgment (h*) self.rankLoss = networks.BCERankingLoss() self.parameters += list(self.rankLoss.net.parameters()) self.lr = lr self.old_lr = lr - self.optimizer_net = torch.optim.Adam(self.parameters, lr=lr, betas=(beta1, 0.999)) - else: # test mode + self.optimizer_net = torch.optim.Adam( + self.parameters, lr=lr, betas=(beta1, 0.999) + ) + else: # test mode self.net.eval() - if(use_gpu): + if use_gpu: self.net.to(gpu_ids[0]) self.net = torch.nn.DataParallel(self.net, device_ids=gpu_ids) - if(self.is_train): - self.rankLoss = self.rankLoss.to(device=gpu_ids[0]) # just put this on GPU0 + if self.is_train: + self.rankLoss = self.rankLoss.to( + device=gpu_ids[0] + ) # just put this on GPU0 - if(printNet): - print('---------- Networks initialized -------------') + if printNet: + print("---------- Networks initialized -------------") networks.print_network(self.net) - print('-----------------------------------------------') + print("-----------------------------------------------") def forward(self, in0, in1, retPerLayer=False): - ''' Function computes the distance between image patches in0 and in1 + """Function computes the distance between image patches in0 and in1 INPUTS in0, in1 - torch.Tensor object of shape Nx3xXxY - image patch scaled to [-1,1] OUTPUT computed distances between in0 and in1 - ''' + """ return self.net.forward(in0, in1, retPerLayer=retPerLayer) @@ -126,51 +160,54 @@ def optimize_parameters(self): def clamp_weights(self): for module in self.net.modules(): - if(hasattr(module, 'weight') and module.kernel_size==(1,1)): - module.weight.data = torch.clamp(module.weight.data,min=0) + if hasattr(module, "weight") and module.kernel_size == (1, 1): + module.weight.data = torch.clamp(module.weight.data, min=0) def set_input(self, data): - self.input_ref = data['ref'] - self.input_p0 = data['p0'] - self.input_p1 = data['p1'] - self.input_judge = data['judge'] + self.input_ref = data["ref"] + self.input_p0 = data["p0"] + self.input_p1 = data["p1"] + self.input_judge = data["judge"] - if(self.use_gpu): + if self.use_gpu: self.input_ref = self.input_ref.to(device=self.gpu_ids[0]) self.input_p0 = self.input_p0.to(device=self.gpu_ids[0]) self.input_p1 = self.input_p1.to(device=self.gpu_ids[0]) self.input_judge = self.input_judge.to(device=self.gpu_ids[0]) - self.var_ref = Variable(self.input_ref,requires_grad=True) - self.var_p0 = Variable(self.input_p0,requires_grad=True) - self.var_p1 = Variable(self.input_p1,requires_grad=True) + self.var_ref = Variable(self.input_ref, requires_grad=True) + self.var_p0 = Variable(self.input_p0, requires_grad=True) + self.var_p1 = Variable(self.input_p1, requires_grad=True) - def forward_train(self): # run forward pass + def forward_train(self): # run forward pass # print(self.net.module.scaling_layer.shift) # print(torch.norm(self.net.module.net.slice1[0].weight).item(), torch.norm(self.net.module.lin0.model[1].weight).item()) self.d0 = self.forward(self.var_ref, self.var_p0) self.d1 = self.forward(self.var_ref, self.var_p1) - self.acc_r = self.compute_accuracy(self.d0,self.d1,self.input_judge) + self.acc_r = self.compute_accuracy(self.d0, self.d1, self.input_judge) - self.var_judge = Variable(1.*self.input_judge).view(self.d0.size()) + self.var_judge = Variable(1.0 * self.input_judge).view(self.d0.size()) - self.loss_total = self.rankLoss.forward(self.d0, self.d1, self.var_judge*2.-1.) + self.loss_total = self.rankLoss.forward( + self.d0, self.d1, self.var_judge * 2.0 - 1.0 + ) return self.loss_total def backward_train(self): torch.mean(self.loss_total).backward() - def compute_accuracy(self,d0,d1,judge): - ''' d0, d1 are Variables, judge is a Tensor ''' - d1_lt_d0 = (d1 %f' % (type,self.old_lr, lr)) + print("update lr [%s] decay: %f -> %f" % (type, self.old_lr, lr)) self.old_lr = lr -def score_2afc_dataset(data_loader, func, name=''): - ''' Function computes Two Alternative Forced Choice (2AFC) score using + +def score_2afc_dataset(data_loader, func, name=""): + """Function computes Two Alternative Forced Choice (2AFC) score using distance function 'func' in dataset 'data_loader' INPUTS data_loader - CustomDatasetDataLoader object - contains a TwoAFCDataset inside @@ -219,33 +257,34 @@ def score_2afc_dataset(data_loader, func, name=''): OUTPUTS [0] - 2AFC score in [0,1], fraction of time func agrees with human evaluators [1] - dictionary with following elements - d0s,d1s - N arrays containing distances between reference patch to perturbed patches + d0s,d1s - N arrays containing distances between reference patch to perturbed patches gts - N array in [0,1], preferred patch selected by human evaluators (closer to "0" for left patch p0, "1" for right patch p1, "0.6" means 60pct people preferred right patch, 40pct preferred left) scores - N array in [0,1], corresponding to what percentage function agreed with humans CONSTS N - number of test triplets in data_loader - ''' + """ d0s = [] d1s = [] gts = [] for data in tqdm(data_loader.load_data(), desc=name): - d0s+=func(data['ref'],data['p0']).data.cpu().numpy().flatten().tolist() - d1s+=func(data['ref'],data['p1']).data.cpu().numpy().flatten().tolist() - gts+=data['judge'].cpu().numpy().flatten().tolist() + d0s += func(data["ref"], data["p0"]).data.cpu().numpy().flatten().tolist() + d1s += func(data["ref"], data["p1"]).data.cpu().numpy().flatten().tolist() + gts += data["judge"].cpu().numpy().flatten().tolist() d0s = np.array(d0s) d1s = np.array(d1s) gts = np.array(gts) - scores = (d0s 1: + face.save(Path(configs.align_output_dir) / (identity_image.stem + f"_{i}.png")) + else: + face.save(Path(configs.align_output_dir) / (identity_image.stem + f".png")) +def main(args): + wandb.login() + with wandb.init( + project=args.wandb_project, + entity=args.wandb_entity, + job_type="predict", + config=vars(args), + ): + + images_artifact = wandb.use_artifact(args.images_artifact, type="dataset") + images_artifact_dir = images_artifact.download() + + ffhq_model_artifact = wandb.use_artifact( + args.ffhq_models_artifact, type="model" + ) + ffhq_model_artifact_dir = ffhq_model_artifact.download() + ffhq_model_file = os.path.join(ffhq_model_artifact_dir, "ffhq.pt") + + segmentation_model_artifact = wandb.use_artifact( + args.segmentation_models_artifact, type="model" + ) + segmentation_model_artifact_dir = segmentation_model_artifact.download() + segmentation_model_file = os.path.join( + segmentation_model_artifact_dir, "seg.pth" + ) + + identity_image = os.path.join(images_artifact_dir, args.identity_image) + structure_image = os.path.join(images_artifact_dir, args.structure_image) + appearance_image = os.path.join(images_artifact_dir, args.appearance_image) + + apply_align_faces(args, identity_image=identity_image) + + device = "cuda:0" if torch.cuda.is_available() else "cpu" + + ii2s = Embedding(args, checkpoint_file=ffhq_model_file).to(device=device) + + im_set = {identity_image, structure_image, appearance_image} + ii2s.invert_images_in_W([*im_set]) + ii2s.invert_images_in_FS([*im_set]) + + align = Alignment( + args, + ffhq_checkpoint_file=ffhq_model_file, + segmentation_checkpoint_file=segmentation_model_file, + ).to(device=device) + aligned_image = align.align_images( + identity_image, + structure_image, + sign=args.sign, + align_more_region=False, + smooth=args.smooth, + ) + if structure_image != appearance_image: + aligned_image = align.align_images( + identity_image, + appearance_image, + sign=args.sign, + align_more_region=False, + smooth=args.smooth, + save_intermediate=False, + ) + + blend = Blending( + args, + ffhq_checkpoint_file=ffhq_model_file, + segmentation_checkpoint_file=segmentation_model_file, + ).to(device=device) + blended_image = blend.blend_images( + identity_image, structure_image, appearance_image, sign=args.sign + ) + + table_data = [[ + args.sign, + wandb.Image(np.array(Image.open(identity_image))), + wandb.Image(np.array(Image.open(structure_image))), + wandb.Image(np.array(Image.open(appearance_image))), + wandb.Image(np.array(aligned_image)), + wandb.Image(np.array(blended_image)), + ]] + + table = wandb.Table( + data=table_data, + columns=[ + "Realistic/Fidelity", + "Identity-Image", + "Structure-Image", + "Appearance-Image", + "Aligned-Image", + "Blended-Image", + ], + ) + wandb.log({"Predictions": table}) if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Barbershop') + parser = argparse.ArgumentParser(description="Barbershop") # I/O arguments - parser.add_argument('--input_dir', type=str, default='input/face', - help='The directory of the images to be inverted') - parser.add_argument('--output_dir', type=str, default='output', - help='The directory to save the latent codes and inversion images') - parser.add_argument('--im_path1', type=str, default='16.png', help='Identity image') - parser.add_argument('--im_path2', type=str, default='15.png', help='Structure image') - parser.add_argument('--im_path3', type=str, default='117.png', help='Appearance image') - parser.add_argument('--sign', type=str, default='realistic', help='realistic or fidelity results') - parser.add_argument('--smooth', type=int, default=5, help='dilation and erosion parameter') + parser.add_argument( + "--wandb_project", type=str, default="barbershop", help="WandB Project Name" + ) + parser.add_argument("--wandb_entity", type=str, default=None, help="WandB Entity") + parser.add_argument( + "--images_artifact", + type=str, + default="geekyrakshit/barbershop/II2S-Images:v0", + help="WandB Artifact address for II2S Images", + ) + parser.add_argument( + "--ffhq_models_artifact", + type=str, + default="geekyrakshit/barbershop/ffhq:v0", + help="WandB Artifact address for ffhq model", + ) + parser.add_argument( + "--segmentation_models_artifact", + type=str, + default="geekyrakshit/barbershop/segmentation:v0", + help="WandB Artifact address for segmentation model", + ) + parser.add_argument( + "--output_dir", + type=str, + default="output", + help="The directory to save the latent codes and inversion images", + ) + parser.add_argument( + "--identity_image", type=str, default="16.png", help="Identity image" + ) + parser.add_argument( + "--structure_image", type=str, default="15.png", help="Structure image" + ) + parser.add_argument( + "--appearance_image", type=str, default="117.png", help="Appearance image" + ) + parser.add_argument( + "--sign", type=str, default="realistic", help="realistic or fidelity results" + ) + parser.add_argument( + "--smooth", type=int, default=5, help="dilation and erosion parameter" + ) + + # Align Face Setting + parser.add_argument( + "--unprocessed_dir", + type=str, + default="unprocessed", + help="directory with unprocessed images", + ) + parser.add_argument( + "--align_output_dir", type=str, default="input/face", help="output directory" + ) + parser.add_argument( + "--output_size", + type=int, + default=1024, + help="size to downscale the input images to, must be power of 2", + ) + parser.add_argument( + "--cache_dir", type=str, default="cache", help="cache directory for model weights" + ) # StyleGAN2 setting - parser.add_argument('--size', type=int, default=1024) - parser.add_argument('--ckpt', type=str, default="pretrained_models/ffhq.pt") - parser.add_argument('--channel_multiplier', type=int, default=2) - parser.add_argument('--latent', type=int, default=512) - parser.add_argument('--n_mlp', type=int, default=8) + parser.add_argument("--size", type=int, default=1024) + parser.add_argument("--channel_multiplier", type=int, default=2) + parser.add_argument("--latent", type=int, default=512) + parser.add_argument("--n_mlp", type=int, default=8) # Arguments - parser.add_argument('--device', type=str, default='cuda') - parser.add_argument('--seed', type=int, default=None) - parser.add_argument('--tile_latent', action='store_true', help='Whether to forcibly tile the same latent N times') - parser.add_argument('--opt_name', type=str, default='adam', help='Optimizer to use in projected gradient descent') - parser.add_argument('--learning_rate', type=float, default=0.01, help='Learning rate to use during optimization') - parser.add_argument('--lr_schedule', type=str, default='fixed', help='fixed, linear1cycledrop, linear1cycle') - parser.add_argument('--save_intermediate', action='store_true', - help='Whether to store and save intermediate HR and LR images during optimization') - parser.add_argument('--save_interval', type=int, default=300, help='Latent checkpoint interval') - parser.add_argument('--verbose', action='store_true', help='Print loss information') - parser.add_argument('--seg_ckpt', type=str, default='pretrained_models/seg.pth') - + parser.add_argument("--device", type=str, default="cuda") + parser.add_argument("--seed", type=int, default=None) + parser.add_argument( + "--tile_latent", + action="store_true", + help="Whether to forcibly tile the same latent N times", + ) + parser.add_argument( + "--opt_name", + type=str, + default="adam", + help="Optimizer to use in projected gradient descent", + ) + parser.add_argument( + "--learning_rate", + type=float, + default=0.01, + help="Learning rate to use during optimization", + ) + parser.add_argument( + "--lr_schedule", + type=str, + default="fixed", + help="fixed, linear1cycledrop, linear1cycle", + ) + parser.add_argument( + "--save_intermediate", + action="store_true", + help="Whether to store and save intermediate HR and LR images during optimization", + ) + parser.add_argument( + "--save_interval", type=int, default=300, help="Latent checkpoint interval" + ) + parser.add_argument("--verbose", action="store_true", help="Print loss information") + # parser.add_argument('--seg_ckpt', type=str, default='pretrained_models/seg.pth') # Embedding loss options - parser.add_argument('--percept_lambda', type=float, default=1.0, help='Perceptual loss multiplier factor') - parser.add_argument('--l2_lambda', type=float, default=1.0, help='L2 loss multiplier factor') - parser.add_argument('--p_norm_lambda', type=float, default=0.001, help='P-norm Regularizer multiplier factor') - parser.add_argument('--l_F_lambda', type=float, default=0.1, help='L_F loss multiplier factor') - parser.add_argument('--W_steps', type=int, default=1100, help='Number of W space optimization steps') - parser.add_argument('--FS_steps', type=int, default=250, help='Number of W space optimization steps') - - + parser.add_argument( + "--percept_lambda", + type=float, + default=1.0, + help="Perceptual loss multiplier factor", + ) + parser.add_argument( + "--l2_lambda", type=float, default=1.0, help="L2 loss multiplier factor" + ) + parser.add_argument( + "--p_norm_lambda", + type=float, + default=0.001, + help="P-norm Regularizer multiplier factor", + ) + parser.add_argument( + "--l_F_lambda", type=float, default=0.1, help="L_F loss multiplier factor" + ) + parser.add_argument( + "--W_steps", type=int, default=1100, help="Number of W space optimization steps" + ) + parser.add_argument( + "--FS_steps", type=int, default=250, help="Number of W space optimization steps" + ) # Alignment loss options - parser.add_argument('--ce_lambda', type=float, default=1.0, help='cross entropy loss multiplier factor') - parser.add_argument('--style_lambda', type=str, default=4e4, help='style loss multiplier factor') - parser.add_argument('--align_steps1', type=int, default=140, help='') - parser.add_argument('--align_steps2', type=int, default=100, help='') - + parser.add_argument( + "--ce_lambda", + type=float, + default=1.0, + help="cross entropy loss multiplier factor", + ) + parser.add_argument( + "--style_lambda", type=str, default=4e4, help="style loss multiplier factor" + ) + parser.add_argument("--align_steps1", type=int, default=140, help="") + parser.add_argument("--align_steps2", type=int, default=100, help="") # Blend loss options - parser.add_argument('--face_lambda', type=float, default=1.0, help='') - parser.add_argument('--hair_lambda', type=str, default=1.0, help='') - parser.add_argument('--blend_steps', type=int, default=400, help='') - - - + parser.add_argument("--face_lambda", type=float, default=1.0, help="") + parser.add_argument("--hair_lambda", type=str, default=1.0, help="") + parser.add_argument("--blend_steps", type=int, default=400, help="") args = parser.parse_args() - main(args) \ No newline at end of file + main(args) diff --git a/models/Alignment.py b/models/Alignment.py index 8b9740d..bd59e5c 100644 --- a/models/Alignment.py +++ b/models/Alignment.py @@ -24,14 +24,19 @@ class Alignment(nn.Module): - - def __init__(self, opts, net=None): + def __init__( + self, + opts, + ffhq_checkpoint_file: str, + segmentation_checkpoint_file: str, + net=None, + ): super(Alignment, self).__init__() self.opts = opts - if not net: - self.net = Net(self.opts) - else: - self.net = net + self.segmentation_checkpoint_file = segmentation_checkpoint_file + self.net = ( + Net(self.opts, checkpoint_file=ffhq_checkpoint_file) if not net else net + ) self.load_segmentation_network() self.load_downsampling() @@ -41,9 +46,9 @@ def load_segmentation_network(self): self.seg = BiSeNet(n_classes=16) self.seg.to(self.opts.device) - if not os.path.exists(self.opts.seg_ckpt): - download_weight(self.opts.seg_ckpt) - self.seg.load_state_dict(torch.load(self.opts.seg_ckpt)) + if not os.path.exists(self.segmentation_checkpoint_file): + download_weight(self.segmentation_checkpoint_file) + self.seg.load_state_dict(torch.load(self.segmentation_checkpoint_file)) for param in self.seg.parameters(): param.requires_grad = False self.seg.eval() @@ -56,7 +61,9 @@ def load_downsampling(self): def setup_align_loss_builder(self): self.loss_builder = AlignLossBuilder(self.opts) - def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_intermediate=True): + def create_target_segmentation_mask( + self, img_path1, img_path2, sign, save_intermediate=True + ): device = self.opts.device @@ -64,12 +71,21 @@ def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_inter down_seg1, _, _ = self.seg(im1) seg_target1 = torch.argmax(down_seg1, dim=1).long() - ggg = torch.where(seg_target1 == 0, torch.zeros_like(seg_target1), torch.ones_like(seg_target1)) - - - hair_mask1 = torch.where(seg_target1 == 10, torch.ones_like(seg_target1), torch.zeros_like(seg_target1)) + ggg = torch.where( + seg_target1 == 0, + torch.zeros_like(seg_target1), + torch.ones_like(seg_target1), + ) + + hair_mask1 = torch.where( + seg_target1 == 10, + torch.ones_like(seg_target1), + torch.zeros_like(seg_target1), + ) seg_target1 = seg_target1[0].byte().cpu().detach() - seg_target1 = torch.where(seg_target1 == 10, torch.zeros_like(seg_target1), seg_target1) + seg_target1 = torch.where( + seg_target1 == 10, torch.zeros_like(seg_target1), seg_target1 + ) im2 = self.preprocess_img(img_path2) down_seg2, _, _ = self.seg(im2) @@ -77,36 +93,57 @@ def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_inter ggg = torch.where(seg_target2 == 10, torch.ones_like(seg_target2), ggg) - hair_mask2 = torch.where(seg_target2 == 10, torch.ones_like(seg_target2), torch.zeros_like(seg_target2)) + hair_mask2 = torch.where( + seg_target2 == 10, + torch.ones_like(seg_target2), + torch.zeros_like(seg_target2), + ) seg_target2 = seg_target2[0].byte().cpu().detach() - OB_region = torch.where( - (seg_target2 != 10) * (seg_target2 != 0) * (seg_target2 != 15) * ( - seg_target1 == 0), - 255 * torch.ones_like(seg_target1), torch.zeros_like(seg_target1)) - - - new_target = torch.where(seg_target2 == 10, 10 * torch.ones_like(seg_target1), seg_target1) - - inpainting_region = torch.where((new_target != 0) * (new_target != 10), 255 * torch.ones_like(new_target), - OB_region).numpy() - tmp = torch.where(torch.from_numpy(inpainting_region) == 255, torch.zeros_like(new_target), new_target) / 10 + (seg_target2 != 10) + * (seg_target2 != 0) + * (seg_target2 != 15) + * (seg_target1 == 0), + 255 * torch.ones_like(seg_target1), + torch.zeros_like(seg_target1), + ) + + new_target = torch.where( + seg_target2 == 10, 10 * torch.ones_like(seg_target1), seg_target1 + ) + + inpainting_region = torch.where( + (new_target != 0) * (new_target != 10), + 255 * torch.ones_like(new_target), + OB_region, + ).numpy() + tmp = ( + torch.where( + torch.from_numpy(inpainting_region) == 255, + torch.zeros_like(new_target), + new_target, + ) + / 10 + ) new_target_inpainted = ( - cv2.inpaint(tmp.clone().numpy(), inpainting_region, 3, cv2.INPAINT_NS).astype(np.uint8) * 10) - new_target_final = torch.where(OB_region, torch.from_numpy(new_target_inpainted), new_target) + cv2.inpaint( + tmp.clone().numpy(), inpainting_region, 3, cv2.INPAINT_NS + ).astype(np.uint8) + * 10 + ) + new_target_final = torch.where( + OB_region, torch.from_numpy(new_target_inpainted), new_target + ) # new_target_final = new_target target_mask = new_target_final.unsqueeze(0).long().cuda() - - ############################# add auto-inpainting - optimizer_align, latent_align = self.setup_align_optimizer() latent_end = latent_align[:, 6:, :].clone().detach() - pbar = tqdm(range(80), desc='Create Target Mask Step1', leave=False) + pbar = tqdm(range(80), desc="Create Target Mask Step1", leave=False) for step in pbar: optimizer_align.zero_grad() latent_in = torch.cat([latent_align[:, :6, :], latent_end], dim=1) @@ -114,33 +151,38 @@ def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_inter loss_dict = {} - if sign == 'realistic': - ce_loss = self.loss_builder.cross_entropy_loss_wo_background(down_seg, target_mask) - ce_loss += self.loss_builder.cross_entropy_loss_only_background(down_seg, ggg) + if sign == "realistic": + ce_loss = self.loss_builder.cross_entropy_loss_wo_background( + down_seg, target_mask + ) + ce_loss += self.loss_builder.cross_entropy_loss_only_background( + down_seg, ggg + ) else: ce_loss = self.loss_builder.cross_entropy_loss(down_seg, target_mask) - loss_dict["ce_loss"] = ce_loss.item() loss = ce_loss - loss.backward() optimizer_align.step() - gen_seg_target = torch.argmax(down_seg, dim=1).long() free_mask = hair_mask1 * (1 - hair_mask2) - target_mask = torch.where(free_mask==1, gen_seg_target, target_mask) + target_mask = torch.where(free_mask == 1, gen_seg_target, target_mask) previouse_target_mask = target_mask.clone().detach() ############################################ - target_mask = torch.where(OB_region.to(device).unsqueeze(0), torch.zeros_like(target_mask), target_mask) + target_mask = torch.where( + OB_region.to(device).unsqueeze(0), + torch.zeros_like(target_mask), + target_mask, + ) optimizer_align, latent_align = self.setup_align_optimizer() latent_end = latent_align[:, 6:, :].clone().detach() - pbar = tqdm(range(80), desc='Create Target Mask Step2', leave=False) + pbar = tqdm(range(80), desc="Create Target Mask Step2", leave=False) for step in pbar: optimizer_align.zero_grad() latent_in = torch.cat([latent_align[:, :6, :], latent_end], dim=1) @@ -148,9 +190,13 @@ def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_inter loss_dict = {} - if sign == 'realistic': - ce_loss = self.loss_builder.cross_entropy_loss_wo_background(down_seg, target_mask) - ce_loss += self.loss_builder.cross_entropy_loss_only_background(down_seg, ggg) + if sign == "realistic": + ce_loss = self.loss_builder.cross_entropy_loss_wo_background( + down_seg, target_mask + ) + ce_loss += self.loss_builder.cross_entropy_loss_only_background( + down_seg, ggg + ) else: ce_loss = self.loss_builder.cross_entropy_loss(down_seg, target_mask) @@ -160,51 +206,83 @@ def create_target_segmentation_mask(self, img_path1, img_path2, sign, save_inter loss.backward() optimizer_align.step() - gen_seg_target = torch.argmax(down_seg, dim=1).long() # free_mask = hair_mask1 * (1 - hair_mask2) # target_mask = torch.where((free_mask == 1) * (gen_seg_target!=0), gen_seg_target, previouse_target_mask) - target_mask = torch.where((OB_region.to(device).unsqueeze(0)) * (gen_seg_target != 0), gen_seg_target, previouse_target_mask) + target_mask = torch.where( + (OB_region.to(device).unsqueeze(0)) * (gen_seg_target != 0), + gen_seg_target, + previouse_target_mask, + ) ##################### Save Visualization of Target Segmentation Mask if save_intermediate: - save_vis_mask(img_path1, img_path2, sign, self.opts.output_dir, target_mask.squeeze().cpu()) - - hair_mask_target = torch.where(target_mask == 10, torch.ones_like(target_mask), torch.zeros_like(target_mask)) - hair_mask_target = F.interpolate(hair_mask_target.float().unsqueeze(0), size=(512, 512), mode='nearest') + save_vis_mask( + img_path1, + img_path2, + sign, + self.opts.output_dir, + target_mask.squeeze().cpu(), + ) + + hair_mask_target = torch.where( + target_mask == 10, + torch.ones_like(target_mask), + torch.zeros_like(target_mask), + ) + hair_mask_target = F.interpolate( + hair_mask_target.float().unsqueeze(0), size=(512, 512), mode="nearest" + ) return target_mask, hair_mask_target, hair_mask1, hair_mask2 - def preprocess_img(self, img_path): - im = torchvision.transforms.ToTensor()(Image.open(img_path))[:3].unsqueeze(0).to(self.opts.device) + im = ( + torchvision.transforms.ToTensor()(Image.open(img_path))[:3] + .unsqueeze(0) + .to(self.opts.device) + ) im = (self.downsample(im).clamp(0, 1) - seg_mean) / seg_std return im def setup_align_optimizer(self, latent_path=None): if latent_path: - latent_W = torch.from_numpy(convert_npy_code(np.load(latent_path))).to(self.opts.device).requires_grad_(True) + latent_W = ( + torch.from_numpy(convert_npy_code(np.load(latent_path))) + .to(self.opts.device) + .requires_grad_(True) + ) else: - latent_W = self.net.latent_avg.reshape(1, 1, 512).repeat(1, 18, 1).clone().detach().to(self.opts.device).requires_grad_(True) - - + latent_W = ( + self.net.latent_avg.reshape(1, 1, 512) + .repeat(1, 18, 1) + .clone() + .detach() + .to(self.opts.device) + .requires_grad_(True) + ) opt_dict = { - 'sgd': torch.optim.SGD, - 'adam': torch.optim.Adam, - 'sgdm': partial(torch.optim.SGD, momentum=0.9), - 'adamax': torch.optim.Adamax + "sgd": torch.optim.SGD, + "adam": torch.optim.Adam, + "sgdm": partial(torch.optim.SGD, momentum=0.9), + "adamax": torch.optim.Adamax, } - optimizer_align = opt_dict[self.opts.opt_name]([latent_W], lr=self.opts.learning_rate) + optimizer_align = opt_dict[self.opts.opt_name]( + [latent_W], lr=self.opts.learning_rate + ) return optimizer_align, latent_W - - def create_down_seg(self, latent_in): - gen_im, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False, - start_layer=0, end_layer=8) + gen_im, _ = self.net.generator( + [latent_in], + input_is_latent=True, + return_latents=False, + start_layer=0, + end_layer=8, + ) gen_im_0_1 = (gen_im + 1) / 2 # get hair mask of synthesized image @@ -212,39 +290,57 @@ def create_down_seg(self, latent_in): down_seg, _, _ = self.seg(im) return down_seg, gen_im - def dilate_erosion(self, free_mask, device, dilate_erosion=5): - free_mask = F.interpolate(free_mask.cpu(), size=(256, 256), mode='nearest').squeeze() - free_mask_D, free_mask_E = cuda_unsqueeze(dilate_erosion_mask_tensor(free_mask, dilate_erosion=dilate_erosion), device) + free_mask = F.interpolate( + free_mask.cpu(), size=(256, 256), mode="nearest" + ).squeeze() + free_mask_D, free_mask_E = cuda_unsqueeze( + dilate_erosion_mask_tensor(free_mask, dilate_erosion=dilate_erosion), device + ) return free_mask_D, free_mask_E - def align_images(self, img_path1, img_path2, sign='realistic', align_more_region=False, smooth=5, - save_intermediate=True): + def align_images( + self, + img_path1, + img_path2, + sign="realistic", + align_more_region=False, + smooth=5, + save_intermediate=True, + ): ################## img_path1: Identity Image ################## img_path2: Structure Image device = self.opts.device output_dir = self.opts.output_dir - target_mask, hair_mask_target, hair_mask1, hair_mask2 = \ - self.create_target_segmentation_mask(img_path1=img_path1, img_path2=img_path2, sign=sign, - save_intermediate=save_intermediate) + ( + target_mask, + hair_mask_target, + hair_mask1, + hair_mask2, + ) = self.create_target_segmentation_mask( + img_path1=img_path1, + img_path2=img_path2, + sign=sign, + save_intermediate=save_intermediate, + ) im_name_1 = os.path.splitext(os.path.basename(img_path1))[0] im_name_2 = os.path.splitext(os.path.basename(img_path2))[0] - latent_FS_path_1 = os.path.join(output_dir, 'FS', f'{im_name_1}.npz') - latent_FS_path_2 = os.path.join(output_dir, 'FS', f'{im_name_2}.npz') + latent_FS_path_1 = os.path.join(output_dir, "FS", f"{im_name_1}.npz") + latent_FS_path_2 = os.path.join(output_dir, "FS", f"{im_name_2}.npz") latent_1, latent_F_1 = load_FS_latent(latent_FS_path_1, device) latent_2, latent_F_2 = load_FS_latent(latent_FS_path_2, device) - latent_W_path_1 = os.path.join(output_dir, 'W+', f'{im_name_1}.npy') - latent_W_path_2 = os.path.join(output_dir, 'W+', f'{im_name_2}.npy') + latent_W_path_1 = os.path.join(output_dir, "W+", f"{im_name_1}.npy") + latent_W_path_2 = os.path.join(output_dir, "W+", f"{im_name_2}.npy") optimizer_align, latent_align_1 = self.setup_align_optimizer(latent_W_path_1) - pbar = tqdm(range(self.opts.align_steps1), desc='Align Step 1', leave=False) + pbar = tqdm(range(self.opts.align_steps1), desc="Align Step 1", leave=False) for step in pbar: optimizer_align.zero_grad() latent_in = torch.cat([latent_align_1[:, :6, :], latent_1[:, 6:, :]], dim=1) @@ -264,8 +360,13 @@ def align_images(self, img_path1, img_path2, sign='realistic', align_more_region loss.backward() optimizer_align.step() - intermediate_align, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False, - start_layer=0, end_layer=3) + intermediate_align, _ = self.net.generator( + [latent_in], + input_is_latent=True, + return_latents=False, + start_layer=0, + end_layer=3, + ) intermediate_align = intermediate_align.clone().detach() ############################################## @@ -273,24 +374,40 @@ def align_images(self, img_path1, img_path2, sign='realistic', align_more_region optimizer_align, latent_align_2 = self.setup_align_optimizer(latent_W_path_2) with torch.no_grad(): - tmp_latent_in = torch.cat([latent_align_2[:, :6, :], latent_2[:, 6:, :]], dim=1) - down_seg_tmp, I_Structure_Style_changed = self.create_down_seg(tmp_latent_in) + tmp_latent_in = torch.cat( + [latent_align_2[:, :6, :], latent_2[:, 6:, :]], dim=1 + ) + down_seg_tmp, I_Structure_Style_changed = self.create_down_seg( + tmp_latent_in + ) current_mask_tmp = torch.argmax(down_seg_tmp, dim=1).long() - HM_Structure = torch.where(current_mask_tmp == 10, torch.ones_like(current_mask_tmp), - torch.zeros_like(current_mask_tmp)) - HM_Structure = F.interpolate(HM_Structure.float().unsqueeze(0), size=(256, 256), mode='nearest') - - pbar = tqdm(range(self.opts.align_steps2), desc='Align Step 2', leave=False) + HM_Structure = torch.where( + current_mask_tmp == 10, + torch.ones_like(current_mask_tmp), + torch.zeros_like(current_mask_tmp), + ) + HM_Structure = F.interpolate( + HM_Structure.float().unsqueeze(0), size=(256, 256), mode="nearest" + ) + + pbar = tqdm(range(self.opts.align_steps2), desc="Align Step 2", leave=False) for step in pbar: optimizer_align.zero_grad() latent_in = torch.cat([latent_align_2[:, :6, :], latent_2[:, 6:, :]], dim=1) down_seg, gen_im = self.create_down_seg(latent_in) Current_Mask = torch.argmax(down_seg, dim=1).long() - HM_G_512 = torch.where(Current_Mask == 10, torch.ones_like(Current_Mask), - torch.zeros_like(Current_Mask)).float().unsqueeze(0) - HM_G = F.interpolate(HM_G_512, size=(256, 256), mode='nearest') + HM_G_512 = ( + torch.where( + Current_Mask == 10, + torch.ones_like(Current_Mask), + torch.zeros_like(Current_Mask), + ) + .float() + .unsqueeze(0) + ) + HM_G = F.interpolate(HM_G_512, size=(256, 256), mode="nearest") loss_dict = {} @@ -302,7 +419,9 @@ def align_images(self, img_path1, img_path2, sign='realistic', align_more_region #### Style Loss H1_region = self.downsample_256(I_Structure_Style_changed) * HM_Structure H2_region = self.downsample_256(gen_im) * HM_G - style_loss = self.loss_builder.style_loss(H1_region, H2_region, mask1=HM_Structure, mask2=HM_G) + style_loss = self.loss_builder.style_loss( + H1_region, H2_region, mask1=HM_Structure, mask2=HM_G + ) loss_dict["style_loss"] = style_loss.item() loss += style_loss @@ -313,8 +432,13 @@ def align_images(self, img_path1, img_path2, sign='realistic', align_more_region loss.backward() optimizer_align.step() - latent_F_out_new, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False, - start_layer=0, end_layer=3) + latent_F_out_new, _ = self.net.generator( + [latent_in], + input_is_latent=True, + return_latents=False, + start_layer=0, + end_layer=3, + ) latent_F_out_new = latent_F_out_new.clone().detach() free_mask = 1 - (1 - hair_mask1.unsqueeze(0)) * (1 - hair_mask_target) @@ -323,49 +447,89 @@ def align_images(self, img_path1, img_path2, sign='realistic', align_more_region free_mask, _ = self.dilate_erosion(free_mask, device, dilate_erosion=smooth) ############################## - free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode='bicubic')[0] + free_mask_down_32 = F.interpolate( + free_mask.float(), size=(32, 32), mode="bicubic" + )[0] interpolation_low = 1 - free_mask_down_32 - latent_F_mixed = intermediate_align + interpolation_low.unsqueeze(0) * ( - latent_F_1 - intermediate_align) + latent_F_1 - intermediate_align + ) if not align_more_region: free_mask = hair_mask_target ########################## _, free_mask = self.dilate_erosion(free_mask, device, dilate_erosion=smooth) ########################## - free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode='bicubic')[0] + free_mask_down_32 = F.interpolate( + free_mask.float(), size=(32, 32), mode="bicubic" + )[0] interpolation_low = 1 - free_mask_down_32 - latent_F_mixed = latent_F_out_new + interpolation_low.unsqueeze(0) * ( - latent_F_mixed - latent_F_out_new) - - free_mask = F.interpolate((hair_mask2.unsqueeze(0) * hair_mask_target).float(), size=(256, 256), mode='nearest').cuda() + latent_F_mixed - latent_F_out_new + ) + + free_mask = F.interpolate( + (hair_mask2.unsqueeze(0) * hair_mask_target).float(), + size=(256, 256), + mode="nearest", + ).cuda() ########################## _, free_mask = self.dilate_erosion(free_mask, device, dilate_erosion=smooth) ########################## - free_mask_down_32 = F.interpolate(free_mask.float(), size=(32, 32), mode='bicubic')[0] + free_mask_down_32 = F.interpolate( + free_mask.float(), size=(32, 32), mode="bicubic" + )[0] interpolation_low = 1 - free_mask_down_32 latent_F_mixed = latent_F_2 + interpolation_low.unsqueeze(0) * ( - latent_F_mixed - latent_F_2) - - gen_im, _ = self.net.generator([latent_1], input_is_latent=True, return_latents=False, start_layer=4, - end_layer=8, layer_in=latent_F_mixed) - self.save_align_results(im_name_1, im_name_2, sign, gen_im, latent_1, latent_F_mixed, - save_intermediate=save_intermediate) - - def save_align_results(self, im_name_1, im_name_2, sign, gen_im, latent_in, latent_F, save_intermediate=True): + latent_F_mixed - latent_F_2 + ) + + gen_im, _ = self.net.generator( + [latent_1], + input_is_latent=True, + return_latents=False, + start_layer=4, + end_layer=8, + layer_in=latent_F_mixed, + ) + return self.save_align_results( + im_name_1, + im_name_2, + sign, + gen_im, + latent_1, + latent_F_mixed, + save_intermediate=save_intermediate, + ) + + def save_align_results( + self, + im_name_1, + im_name_2, + sign, + gen_im, + latent_in, + latent_F, + save_intermediate=True, + ): save_im = toPIL(((gen_im[0] + 1) / 2).detach().cpu().clamp(0, 1)) - save_dir = os.path.join(self.opts.output_dir, 'Align_{}'.format(sign)) + save_dir = os.path.join(self.opts.output_dir, "Align_{}".format(sign)) os.makedirs(save_dir, exist_ok=True) - latent_path = os.path.join(save_dir, '{}_{}.npz'.format(im_name_1, im_name_2)) + latent_path = os.path.join(save_dir, "{}_{}.npz".format(im_name_1, im_name_2)) if save_intermediate: - image_path = os.path.join(save_dir, '{}_{}.png'.format(im_name_1, im_name_2)) + image_path = os.path.join( + save_dir, "{}_{}.png".format(im_name_1, im_name_2) + ) save_im.save(image_path) - np.savez(latent_path, latent_in=latent_in.detach().cpu().numpy(), latent_F=latent_F.detach().cpu().numpy()) + np.savez( + latent_path, + latent_in=latent_in.detach().cpu().numpy(), + latent_F=latent_F.detach().cpu().numpy(), + ) + return save_im diff --git a/models/Blending.py b/models/Blending.py index f964385..1c4b198 100644 --- a/models/Blending.py +++ b/models/Blending.py @@ -14,30 +14,35 @@ import cv2 from utils.data_utils import load_FS_latent from utils.data_utils import cuda_unsqueeze -from utils.image_utils import load_image, dilate_erosion_mask_path, dilate_erosion_mask_tensor +from utils.image_utils import ( + load_image, + dilate_erosion_mask_path, + dilate_erosion_mask_tensor, +) from utils.model_utils import download_weight toPIL = torchvision.transforms.ToPILImage() - - class Blending(nn.Module): - - def __init__(self, opts, net=None): + def __init__( + self, + opts, + ffhq_checkpoint_file: str, + segmentation_checkpoint_file: str, + net=None, + ): super(Blending, self).__init__() self.opts = opts - if not net: - self.net = Net(self.opts) - else: - self.net = net + self.segmentation_checkpoint_file = segmentation_checkpoint_file + self.net = ( + Net(self.opts, checkpoint_file=ffhq_checkpoint_file) if not net else net + ) self.load_segmentation_network() self.load_downsampling() self.setup_blend_loss_builder() - - def load_downsampling(self): self.downsample = BicubicDownSample(factor=self.opts.size // 512) @@ -47,27 +52,29 @@ def load_segmentation_network(self): self.seg = BiSeNet(n_classes=16) self.seg.to(self.opts.device) - if not os.path.exists(self.opts.seg_ckpt): - download_weight(self.opts.seg_ckpt) - self.seg.load_state_dict(torch.load(self.opts.seg_ckpt)) + if not os.path.exists(self.segmentation_checkpoint_file): + download_weight(self.segmentation_checkpoint_file) + self.seg.load_state_dict(torch.load(self.segmentation_checkpoint_file)) for param in self.seg.parameters(): param.requires_grad = False self.seg.eval() - def setup_blend_optimizer(self): - interpolation_latent = torch.zeros((18, 512), requires_grad=True, device=self.opts.device) + interpolation_latent = torch.zeros( + (18, 512), requires_grad=True, device=self.opts.device + ) - opt_blend = ClampOptimizer(torch.optim.Adam, [interpolation_latent], lr=self.opts.learning_rate) + opt_blend = ClampOptimizer( + torch.optim.Adam, [interpolation_latent], lr=self.opts.learning_rate + ) return opt_blend, interpolation_latent def setup_blend_loss_builder(self): self.loss_builder = BlendLossBuilder(self.opts) - - def blend_images(self, img_path1, img_path2, img_path3, sign='realistic'): + def blend_images(self, img_path1, img_path2, img_path3, sign="realistic"): device = self.opts.device output_dir = self.opts.output_dir @@ -80,44 +87,72 @@ def blend_images(self, img_path1, img_path2, img_path3, sign='realistic'): I_3 = load_image(img_path3, downsample=True).to(device).unsqueeze(0) HM_1D, _ = cuda_unsqueeze(dilate_erosion_mask_path(img_path1, self.seg), device) - HM_3D, HM_3E = cuda_unsqueeze(dilate_erosion_mask_path(img_path3, self.seg), device) + HM_3D, HM_3E = cuda_unsqueeze( + dilate_erosion_mask_path(img_path3, self.seg), device + ) opt_blend, interpolation_latent = self.setup_blend_optimizer() - latent_1, latent_F_mixed = load_FS_latent(os.path.join(output_dir, 'Align_{}'.format(sign), - '{}_{}.npz'.format(im_name_1, im_name_3)),device) - latent_3, _ = load_FS_latent(os.path.join(output_dir, 'FS', - '{}.npz'.format(im_name_3)), device) + latent_1, latent_F_mixed = load_FS_latent( + os.path.join( + output_dir, + "Align_{}".format(sign), + "{}_{}.npz".format(im_name_1, im_name_3), + ), + device, + ) + latent_3, _ = load_FS_latent( + os.path.join(output_dir, "FS", "{}.npz".format(im_name_3)), device + ) with torch.no_grad(): - I_X, _ = self.net.generator([latent_1], input_is_latent=True, return_latents=False, start_layer=4, - end_layer=8, layer_in=latent_F_mixed) + I_X, _ = self.net.generator( + [latent_1], + input_is_latent=True, + return_latents=False, + start_layer=4, + end_layer=8, + layer_in=latent_F_mixed, + ) I_X_0_1 = (I_X + 1) / 2 IM = (self.downsample(I_X_0_1) - seg_mean) / seg_std down_seg, _, _ = self.seg(IM) current_mask = torch.argmax(down_seg, dim=1).long().cpu().float() - HM_X = torch.where(current_mask == 10, torch.ones_like(current_mask), torch.zeros_like(current_mask)) - HM_X = F.interpolate(HM_X.unsqueeze(0), size=(256, 256), mode='nearest').squeeze() + HM_X = torch.where( + current_mask == 10, + torch.ones_like(current_mask), + torch.zeros_like(current_mask), + ) + HM_X = F.interpolate( + HM_X.unsqueeze(0), size=(256, 256), mode="nearest" + ).squeeze() HM_XD, _ = cuda_unsqueeze(dilate_erosion_mask_tensor(HM_X), device) target_mask = (1 - HM_1D) * (1 - HM_3D) * (1 - HM_XD) - - pbar = tqdm(range(self.opts.blend_steps), desc='Blend', leave=False) + pbar = tqdm(range(self.opts.blend_steps), desc="Blend", leave=False) for step in pbar: opt_blend.zero_grad() - latent_mixed = latent_1 + interpolation_latent.unsqueeze(0) * (latent_3 - latent_1) - - I_G, _ = self.net.generator([latent_mixed], input_is_latent=True, return_latents=False, start_layer=4, - end_layer=8, layer_in=latent_F_mixed) + latent_mixed = latent_1 + interpolation_latent.unsqueeze(0) * ( + latent_3 - latent_1 + ) + + I_G, _ = self.net.generator( + [latent_mixed], + input_is_latent=True, + return_latents=False, + start_layer=4, + end_layer=8, + layer_in=latent_F_mixed, + ) I_G_0_1 = (I_G + 1) / 2 im_dict = { - 'gen_im': self.downsample_256(I_G), - 'im_1': I_1, - 'im_3': I_3, - 'mask_face': target_mask, - 'mask_hair': HM_3E + "gen_im": self.downsample_256(I_G), + "im_1": I_1, + "im_3": I_3, + "mask_face": target_mask, + "mask_hair": HM_3E, } loss, loss_dic = self.loss_builder(**im_dict) @@ -130,25 +165,51 @@ def blend_images(self, img_path1, img_path2, img_path3, sign='realistic'): opt_blend.step() ############## Load F code from '{}_{}.npz'.format(im_name_1, im_name_2) - _, latent_F_mixed = load_FS_latent(os.path.join(output_dir, 'Align_{}'.format(sign), - '{}_{}.npz'.format(im_name_1, im_name_2)), device) - I_G, _ = self.net.generator([latent_mixed], input_is_latent=True, return_latents=False, start_layer=4, - end_layer=8, layer_in=latent_F_mixed) - - self.save_blend_results(im_name_1, im_name_2, im_name_3, sign, I_G, latent_mixed, latent_F_mixed) - - def save_blend_results(self, im_name_1, im_name_2, im_name_3, sign, gen_im, latent_in, latent_F): + _, latent_F_mixed = load_FS_latent( + os.path.join( + output_dir, + "Align_{}".format(sign), + "{}_{}.npz".format(im_name_1, im_name_2), + ), + device, + ) + I_G, _ = self.net.generator( + [latent_mixed], + input_is_latent=True, + return_latents=False, + start_layer=4, + end_layer=8, + layer_in=latent_F_mixed, + ) + + return self.save_blend_results( + im_name_1, im_name_2, im_name_3, sign, I_G, latent_mixed, latent_F_mixed + ) + + def save_blend_results( + self, im_name_1, im_name_2, im_name_3, sign, gen_im, latent_in, latent_F + ): save_im = toPIL(((gen_im[0] + 1) / 2).detach().cpu().clamp(0, 1)) - save_dir = os.path.join(self.opts.output_dir, 'Blend_{}'.format(sign)) + save_dir = os.path.join(self.opts.output_dir, "Blend_{}".format(sign)) os.makedirs(save_dir, exist_ok=True) - latent_path = os.path.join(save_dir, '{}_{}_{}.npz'.format(im_name_1, im_name_2, im_name_3)) - image_path = os.path.join(save_dir, '{}_{}_{}.png'.format(im_name_1, im_name_2, im_name_3)) - output_image_path = os.path.join(self.opts.output_dir, '{}_{}_{}_{}.png'.format(im_name_1, im_name_2, im_name_3, sign)) + latent_path = os.path.join( + save_dir, "{}_{}_{}.npz".format(im_name_1, im_name_2, im_name_3) + ) + image_path = os.path.join( + save_dir, "{}_{}_{}.png".format(im_name_1, im_name_2, im_name_3) + ) + output_image_path = os.path.join( + self.opts.output_dir, + "{}_{}_{}_{}.png".format(im_name_1, im_name_2, im_name_3, sign), + ) save_im.save(image_path) save_im.save(output_image_path) - np.savez(latent_path, latent_in=latent_in.detach().cpu().numpy(), latent_F=latent_F.detach().cpu().numpy()) - - + np.savez( + latent_path, + latent_in=latent_in.detach().cpu().numpy(), + latent_F=latent_F.detach().cpu().numpy(), + ) + return save_im diff --git a/models/Embedding.py b/models/Embedding.py index 5ddf259..b5e2087 100644 --- a/models/Embedding.py +++ b/models/Embedding.py @@ -15,17 +15,15 @@ toPIL = torchvision.transforms.ToPILImage() -class Embedding(nn.Module): - def __init__(self, opts): +class Embedding(nn.Module): + def __init__(self, opts, checkpoint_file: str): super(Embedding, self).__init__() self.opts = opts - self.net = Net(self.opts) + self.net = Net(self.opts, checkpoint_file=checkpoint_file) self.load_downsampling() self.setup_embedding_loss_builder() - - def load_downsampling(self): factor = self.opts.size // 256 self.downsample = BicubicDownSample(factor=factor) @@ -33,38 +31,40 @@ def load_downsampling(self): def setup_W_optimizer(self): opt_dict = { - 'sgd': torch.optim.SGD, - 'adam': torch.optim.Adam, - 'sgdm': partial(torch.optim.SGD, momentum=0.9), - 'adamax': torch.optim.Adamax + "sgd": torch.optim.SGD, + "adam": torch.optim.Adam, + "sgdm": partial(torch.optim.SGD, momentum=0.9), + "adamax": torch.optim.Adamax, } latent = [] - if (self.opts.tile_latent): + if self.opts.tile_latent: tmp = self.net.latent_avg.clone().detach().cuda() tmp.requires_grad = True for i in range(self.net.layer_num): latent.append(tmp) - optimizer_W = opt_dict[self.opts.opt_name]([tmp], lr=self.opts.learning_rate) + optimizer_W = opt_dict[self.opts.opt_name]( + [tmp], lr=self.opts.learning_rate + ) else: for i in range(self.net.layer_num): tmp = self.net.latent_avg.clone().detach().cuda() tmp.requires_grad = True latent.append(tmp) - optimizer_W = opt_dict[self.opts.opt_name](latent, lr=self.opts.learning_rate) + optimizer_W = opt_dict[self.opts.opt_name]( + latent, lr=self.opts.learning_rate + ) return optimizer_W, latent - - def setup_FS_optimizer(self, latent_W, F_init): latent_F = F_init.clone().detach().requires_grad_(True) latent_S = [] opt_dict = { - 'sgd': torch.optim.SGD, - 'adam': torch.optim.Adam, - 'sgdm': partial(torch.optim.SGD, momentum=0.9), - 'adamax': torch.optim.Adamax + "sgd": torch.optim.SGD, + "adam": torch.optim.Adam, + "sgdm": partial(torch.optim.SGD, momentum=0.9), + "adamax": torch.optim.Adamax, } for i in range(self.net.layer_num): @@ -77,40 +77,40 @@ def setup_FS_optimizer(self, latent_W, F_init): latent_S.append(tmp) - optimizer_FS = opt_dict[self.opts.opt_name](latent_S[self.net.S_index:] + [latent_F], lr=self.opts.learning_rate) + optimizer_FS = opt_dict[self.opts.opt_name]( + latent_S[self.net.S_index :] + [latent_F], lr=self.opts.learning_rate + ) return optimizer_FS, latent_F, latent_S - - - def setup_dataloader(self, image_path=None): - self.dataset = ImagesDataset(opts=self.opts,image_path=image_path) + self.dataset = ImagesDataset(opts=self.opts, image_path=image_path) self.dataloader = DataLoader(self.dataset, batch_size=1, shuffle=False) print("Number of images: {}".format(len(self.dataset))) def setup_embedding_loss_builder(self): self.loss_builder = EmbeddingLossBuilder(self.opts) - def invert_images_in_W(self, image_path=None): self.setup_dataloader(image_path=image_path) device = self.opts.device - ibar = tqdm(self.dataloader, desc='Images') + ibar = tqdm(self.dataloader, desc="Images") for ref_im_H, ref_im_L, ref_name in ibar: optimizer_W, latent = self.setup_W_optimizer() - pbar = tqdm(range(self.opts.W_steps), desc='Embedding', leave=False) + pbar = tqdm(range(self.opts.W_steps), desc="Embedding", leave=False) for step in pbar: optimizer_W.zero_grad() latent_in = torch.stack(latent).unsqueeze(0) - gen_im, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False) + gen_im, _ = self.net.generator( + [latent_in], input_is_latent=True, return_latents=False + ) im_dict = { - 'ref_im_H': ref_im_H.to(device), - 'ref_im_L': ref_im_L.to(device), - 'gen_im_H': gen_im, - 'gen_im_L': self.downsample(gen_im) + "ref_im_H": ref_im_H.to(device), + "ref_im_L": ref_im_L.to(device), + "gen_im_H": gen_im, + "gen_im_L": self.downsample(gen_im), } loss, loss_dic = self.cal_loss(im_dict, latent_in) @@ -118,42 +118,55 @@ def invert_images_in_W(self, image_path=None): optimizer_W.step() if self.opts.verbose: - pbar.set_description('Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}' - .format(loss, loss_dic['l2'], loss_dic['percep'], loss_dic['p-norm'])) + pbar.set_description( + "Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}".format( + loss, loss_dic["l2"], loss_dic["percep"], loss_dic["p-norm"] + ) + ) - if self.opts.save_intermediate and step % self.opts.save_interval== 0: + if self.opts.save_intermediate and step % self.opts.save_interval == 0: self.save_W_intermediate_results(ref_name, gen_im, latent_in, step) self.save_W_results(ref_name, gen_im, latent_in) - - - def invert_images_in_FS(self, image_path=None): self.setup_dataloader(image_path=image_path) output_dir = self.opts.output_dir device = self.opts.device - ibar = tqdm(self.dataloader, desc='Images') + ibar = tqdm(self.dataloader, desc="Images") for ref_im_H, ref_im_L, ref_name in ibar: - latent_W_path = os.path.join(output_dir, 'W+', f'{ref_name[0]}.npy') - latent_W = torch.from_numpy(convert_npy_code(np.load(latent_W_path))).to(device) - F_init, _ = self.net.generator([latent_W], input_is_latent=True, return_latents=False, start_layer=0, end_layer=3) + latent_W_path = os.path.join(output_dir, "W+", f"{ref_name[0]}.npy") + latent_W = torch.from_numpy(convert_npy_code(np.load(latent_W_path))).to( + device + ) + F_init, _ = self.net.generator( + [latent_W], + input_is_latent=True, + return_latents=False, + start_layer=0, + end_layer=3, + ) optimizer_FS, latent_F, latent_S = self.setup_FS_optimizer(latent_W, F_init) - - pbar = tqdm(range(self.opts.FS_steps), desc='Embedding', leave=False) + pbar = tqdm(range(self.opts.FS_steps), desc="Embedding", leave=False) for step in pbar: optimizer_FS.zero_grad() latent_in = torch.stack(latent_S).unsqueeze(0) - gen_im, _ = self.net.generator([latent_in], input_is_latent=True, return_latents=False, - start_layer=4, end_layer=8, layer_in=latent_F) + gen_im, _ = self.net.generator( + [latent_in], + input_is_latent=True, + return_latents=False, + start_layer=4, + end_layer=8, + layer_in=latent_F, + ) im_dict = { - 'ref_im_H': ref_im_H.to(device), - 'ref_im_L': ref_im_L.to(device), - 'gen_im_H': gen_im, - 'gen_im_L': self.downsample(gen_im) + "ref_im_H": ref_im_H.to(device), + "ref_im_L": ref_im_L.to(device), + "gen_im_H": gen_im, + "gen_im_L": self.downsample(gen_im), } loss, loss_dic = self.cal_loss(im_dict, latent_in) @@ -162,74 +175,73 @@ def invert_images_in_FS(self, image_path=None): if self.opts.verbose: pbar.set_description( - 'Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}, L_F loss: {:.3f}' - .format(loss, loss_dic['l2'], loss_dic['percep'], loss_dic['p-norm'], loss_dic['l_F'])) + "Embedding: Loss: {:.3f}, L2 loss: {:.3f}, Perceptual loss: {:.3f}, P-norm loss: {:.3f}, L_F loss: {:.3f}".format( + loss, + loss_dic["l2"], + loss_dic["percep"], + loss_dic["p-norm"], + loss_dic["l_F"], + ) + ) self.save_FS_results(ref_name, gen_im, latent_in, latent_F) - - - def cal_loss(self, im_dict, latent_in, latent_F=None, F_init=None): loss, loss_dic = self.loss_builder(**im_dict) p_norm_loss = self.net.cal_p_norm_loss(latent_in) - loss_dic['p-norm'] = p_norm_loss + loss_dic["p-norm"] = p_norm_loss loss += p_norm_loss if latent_F is not None and F_init is not None: l_F = self.net.cal_l_F(latent_F, F_init) - loss_dic['l_F'] = l_F + loss_dic["l_F"] = l_F loss += l_F return loss, loss_dic - - def save_W_results(self, ref_name, gen_im, latent_in): save_im = toPIL(((gen_im[0] + 1) / 2).detach().cpu().clamp(0, 1)) save_latent = latent_in.detach().cpu().numpy() - output_dir = os.path.join(self.opts.output_dir, 'W+') + output_dir = os.path.join(self.opts.output_dir, "W+") os.makedirs(output_dir, exist_ok=True) - latent_path = os.path.join(output_dir, f'{ref_name[0]}.npy') - image_path = os.path.join(output_dir, f'{ref_name[0]}.png') + latent_path = os.path.join(output_dir, f"{ref_name[0]}.npy") + image_path = os.path.join(output_dir, f"{ref_name[0]}.png") save_im.save(image_path) np.save(latent_path, save_latent) - - def save_W_intermediate_results(self, ref_name, gen_im, latent_in, step): save_im = toPIL(((gen_im[0] + 1) / 2).detach().cpu().clamp(0, 1)) save_latent = latent_in.detach().cpu().numpy() - - intermediate_folder = os.path.join(self.opts.output_dir, 'W+', ref_name[0]) + intermediate_folder = os.path.join(self.opts.output_dir, "W+", ref_name[0]) os.makedirs(intermediate_folder, exist_ok=True) - latent_path = os.path.join(intermediate_folder, f'{ref_name[0]}_{step:04}.npy') - image_path = os.path.join(intermediate_folder, f'{ref_name[0]}_{step:04}.png') + latent_path = os.path.join(intermediate_folder, f"{ref_name[0]}_{step:04}.npy") + image_path = os.path.join(intermediate_folder, f"{ref_name[0]}_{step:04}.png") save_im.save(image_path) np.save(latent_path, save_latent) - def save_FS_results(self, ref_name, gen_im, latent_in, latent_F): save_im = toPIL(((gen_im[0] + 1) / 2).detach().cpu().clamp(0, 1)) - output_dir = os.path.join(self.opts.output_dir, 'FS') + output_dir = os.path.join(self.opts.output_dir, "FS") os.makedirs(output_dir, exist_ok=True) - latent_path = os.path.join(output_dir, f'{ref_name[0]}.npz') - image_path = os.path.join(output_dir, f'{ref_name[0]}.png') + latent_path = os.path.join(output_dir, f"{ref_name[0]}.npz") + image_path = os.path.join(output_dir, f"{ref_name[0]}.png") save_im.save(image_path) - np.savez(latent_path, latent_in=latent_in.detach().cpu().numpy(), - latent_F=latent_F.detach().cpu().numpy()) - + np.savez( + latent_path, + latent_in=latent_in.detach().cpu().numpy(), + latent_F=latent_F.detach().cpu().numpy(), + ) def set_seed(self): if self.opt.seed: diff --git a/models/Net.py b/models/Net.py index 0afffe4..cb2e52a 100644 --- a/models/Net.py +++ b/models/Net.py @@ -5,27 +5,32 @@ import os from utils.model_utils import download_weight -class Net(nn.Module): - def __init__(self, opts): +class Net(nn.Module): + def __init__(self, opts, checkpoint_file: str): super(Net, self).__init__() self.opts = opts - self.generator = Generator(opts.size, opts.latent, opts.n_mlp, channel_multiplier=opts.channel_multiplier) + self.checkpoint_file = checkpoint_file + self.generator = Generator( + opts.size, + opts.latent, + opts.n_mlp, + channel_multiplier=opts.channel_multiplier, + ) self.cal_layer_num() self.load_weights() self.load_PCA_model() - def load_weights(self): - if not os.path.exists(self.opts.ckpt): - print('Downloading StyleGAN2 checkpoint: {}'.format(self.opts.ckpt)) - download_weight(self.opts.ckpt) + if not os.path.exists(self.checkpoint_file): + print("Downloading StyleGAN2 checkpoint: {}".format(self.checkpoint_file)) + download_weight(self.checkpoint_file) - print('Loading StyleGAN2 from checkpoint: {}'.format(self.opts.ckpt)) - checkpoint = torch.load(self.opts.ckpt) + print("Loading StyleGAN2 from checkpoint: {}".format(self.checkpoint_file)) + checkpoint = torch.load(self.checkpoint_file) device = self.opts.device - self.generator.load_state_dict(checkpoint['g_ema']) - self.latent_avg = checkpoint['latent_avg'] + self.generator.load_state_dict(checkpoint["g_ema"]) + self.latent_avg = checkpoint["latent_avg"] self.generator.to(device) self.latent_avg = self.latent_avg.to(device) @@ -33,7 +38,6 @@ def load_weights(self): param.requires_grad = False self.generator.eval() - def build_PCA_model(self, PCA_path): with torch.no_grad(): @@ -49,31 +53,23 @@ def build_PCA_model(self, PCA_path): X_mean = pulse_space.mean(0) transformer.fit(pulse_space - X_mean) X_comp, X_stdev, X_var_ratio = transformer.get_components() - np.savez(PCA_path, X_mean=X_mean, X_comp=X_comp, X_stdev=X_stdev, X_var_ratio=X_var_ratio) - + np.savez( + PCA_path, + X_mean=X_mean, + X_comp=X_comp, + X_stdev=X_stdev, + X_var_ratio=X_var_ratio, + ) def load_PCA_model(self): device = self.opts.device - - PCA_path = self.opts.ckpt[:-3] + '_PCA.npz' - + PCA_path = self.checkpoint_file[:-3] + "_PCA.npz" if not os.path.isfile(PCA_path): self.build_PCA_model(PCA_path) - PCA_model = np.load(PCA_path) - self.X_mean = torch.from_numpy(PCA_model['X_mean']).float().to(device) - self.X_comp = torch.from_numpy(PCA_model['X_comp']).float().to(device) - self.X_stdev = torch.from_numpy(PCA_model['X_stdev']).float().to(device) - - - - # def make_noise(self): - # noises_single = self.generator.make_noise() - # noises = [] - # for noise in noises_single: - # noises.append(noise.repeat(1, 1, 1, 1).normal_()) - # - # return noises + self.X_mean = torch.from_numpy(PCA_model["X_mean"]).float().to(device) + self.X_comp = torch.from_numpy(PCA_model["X_comp"]).float().to(device) + self.X_stdev = torch.from_numpy(PCA_model["X_stdev"]).float().to(device) def cal_layer_num(self): if self.opts.size == 1024: @@ -82,20 +78,15 @@ def cal_layer_num(self): self.layer_num = 16 elif self.opts.size == 256: self.layer_num = 14 - self.S_index = self.layer_num - 11 - return - def cal_p_norm_loss(self, latent_in): - latent_p_norm = (torch.nn.LeakyReLU(negative_slope=5)(latent_in) - self.X_mean).bmm( - self.X_comp.T.unsqueeze(0)) / self.X_stdev + latent_p_norm = ( + torch.nn.LeakyReLU(negative_slope=5)(latent_in) - self.X_mean + ).bmm(self.X_comp.T.unsqueeze(0)) / self.X_stdev p_norm_loss = self.opts.p_norm_lambda * (latent_p_norm.pow(2).mean()) return p_norm_loss - def cal_l_F(self, latent_F, F_init): return self.opts.l_F_lambda * (latent_F - F_init).pow(2).mean() - - diff --git a/models/face_parsing/makeup.py b/models/face_parsing/makeup.py index b03f141..df14d5a 100644 --- a/models/face_parsing/makeup.py +++ b/models/face_parsing/makeup.py @@ -24,7 +24,7 @@ def sharpen(img): def hair(image, parsing, part=17, color=[230, 50, 20]): - b, g, r = color #[10, 50, 250] # [10, 250, 10] + b, g, r = color # [10, 50, 250] # [10, 250, 10] tar_color = np.zeros_like(image) tar_color[:, :, 0] = b tar_color[:, :, 1] = g @@ -47,6 +47,7 @@ def hair(image, parsing, part=17, color=[230, 50, 20]): # changed = cv2.resize(changed, (512, 512)) return changed + # # def lip(image, parsing, part=17, color=[230, 50, 20]): # b, g, r = color #[10, 50, 250] # [10, 250, 10] @@ -76,7 +77,7 @@ def hair(image, parsing, part=17, color=[230, 50, 20]): # return changed -if __name__ == '__main__': +if __name__ == "__main__": # 1 face # 10 nose # 11 teeth @@ -84,47 +85,28 @@ def hair(image, parsing, part=17, color=[230, 50, 20]): # 13 lower lip # 17 hair num = 116 - table = { - 'hair': 17, - 'upper_lip': 12, - 'lower_lip': 13 - } - image_path = '/home/zll/data/CelebAMask-HQ/test-img/{}.jpg'.format(num) - parsing_path = 'res/test_res/{}.png'.format(num) + table = {"hair": 17, "upper_lip": 12, "lower_lip": 13} + image_path = "/home/zll/data/CelebAMask-HQ/test-img/{}.jpg".format(num) + parsing_path = "res/test_res/{}.png".format(num) image = cv2.imread(image_path) ori = image.copy() parsing = np.array(cv2.imread(parsing_path, 0)) parsing = cv2.resize(parsing, image.shape[0:2], interpolation=cv2.INTER_NEAREST) - parts = [table['hair'], table['upper_lip'], table['lower_lip']] + parts = [table["hair"], table["upper_lip"], table["lower_lip"]] # colors = [[20, 20, 200], [100, 100, 230], [100, 100, 230]] colors = [[100, 200, 100]] for part, color in zip(parts, colors): image = hair(image, parsing, part, color) - cv2.imwrite('res/makeup/116_ori.png', cv2.resize(ori, (512, 512))) - cv2.imwrite('res/makeup/116_2.png', cv2.resize(image, (512, 512))) + cv2.imwrite("res/makeup/116_ori.png", cv2.resize(ori, (512, 512))) + cv2.imwrite("res/makeup/116_2.png", cv2.resize(image, (512, 512))) - cv2.imshow('image', cv2.resize(ori, (512, 512))) - cv2.imshow('color', cv2.resize(image, (512, 512))) + cv2.imshow("image", cv2.resize(ori, (512, 512))) + cv2.imshow("color", cv2.resize(image, (512, 512))) # cv2.imshow('image', ori) # cv2.imshow('color', image) cv2.waitKey(0) cv2.destroyAllWindows() - - - - - - - - - - - - - - - diff --git a/models/face_parsing/model.py b/models/face_parsing/model.py index e8c3dc8..6089142 100644 --- a/models/face_parsing/model.py +++ b/models/face_parsing/model.py @@ -8,24 +8,37 @@ import torchvision from .resnet import Resnet18 + # from modules.bn import InPlaceABNSync as BatchNorm2d import numpy as np -seg_mean = torch.from_numpy(np.array([[0.485, 0.456, 0.406]])).float().cuda().reshape(1,3,1,1) -seg_std = torch.from_numpy(np.array([[0.229, 0.224, 0.225]])).float().cuda().reshape(1,3,1,1) +seg_mean = ( + torch.from_numpy(np.array([[0.485, 0.456, 0.406]])) + .float() + .cuda() + .reshape(1, 3, 1, 1) +) +seg_std = ( + torch.from_numpy(np.array([[0.229, 0.224, 0.225]])) + .float() + .cuda() + .reshape(1, 3, 1, 1) +) seg_criterion = nn.CrossEntropyLoss() class ConvBNReLU(nn.Module): def __init__(self, in_chan, out_chan, ks=3, stride=1, padding=1, *args, **kwargs): super(ConvBNReLU, self).__init__() - self.conv = nn.Conv2d(in_chan, - out_chan, - kernel_size = ks, - stride = stride, - padding = padding, - bias = False) + self.conv = nn.Conv2d( + in_chan, + out_chan, + kernel_size=ks, + stride=stride, + padding=padding, + bias=False, + ) self.bn = nn.BatchNorm2d(out_chan) self.init_weight() @@ -38,7 +51,9 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) + class BiSeNetOutput(nn.Module): def __init__(self, in_chan, mid_chan, n_classes, *args, **kwargs): @@ -56,7 +71,8 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) def get_params(self): wd_params, nowd_params = [], [] @@ -74,7 +90,7 @@ class AttentionRefinementModule(nn.Module): def __init__(self, in_chan, out_chan, *args, **kwargs): super(AttentionRefinementModule, self).__init__() self.conv = ConvBNReLU(in_chan, out_chan, ks=3, stride=1, padding=1) - self.conv_atten = nn.Conv2d(out_chan, out_chan, kernel_size= 1, bias=False) + self.conv_atten = nn.Conv2d(out_chan, out_chan, kernel_size=1, bias=False) self.bn_atten = nn.BatchNorm2d(out_chan) self.sigmoid_atten = nn.Sigmoid() self.init_weight() @@ -92,7 +108,8 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) class ContextPath(nn.Module): @@ -116,16 +133,16 @@ def forward(self, x): avg = F.avg_pool2d(feat32, feat32.size()[2:]) avg = self.conv_avg(avg) - avg_up = F.interpolate(avg, (H32, W32), mode='nearest') + avg_up = F.interpolate(avg, (H32, W32), mode="nearest") feat32_arm = self.arm32(feat32) feat32_sum = feat32_arm + avg_up - feat32_up = F.interpolate(feat32_sum, (H16, W16), mode='nearest') + feat32_up = F.interpolate(feat32_sum, (H16, W16), mode="nearest") feat32_up = self.conv_head32(feat32_up) feat16_arm = self.arm16(feat16) feat16_sum = feat16_arm + feat32_up - feat16_up = F.interpolate(feat16_sum, (H8, W8), mode='nearest') + feat16_up = F.interpolate(feat16_sum, (H8, W8), mode="nearest") feat16_up = self.conv_head16(feat16_up) return feat8, feat16_up, feat32_up # x8, x8, x16 @@ -134,7 +151,8 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) def get_params(self): wd_params, nowd_params = [], [] @@ -169,7 +187,8 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) def get_params(self): wd_params, nowd_params = [], [] @@ -187,18 +206,12 @@ class FeatureFusionModule(nn.Module): def __init__(self, in_chan, out_chan, *args, **kwargs): super(FeatureFusionModule, self).__init__() self.convblk = ConvBNReLU(in_chan, out_chan, ks=1, stride=1, padding=0) - self.conv1 = nn.Conv2d(out_chan, - out_chan//4, - kernel_size = 1, - stride = 1, - padding = 0, - bias = False) - self.conv2 = nn.Conv2d(out_chan//4, - out_chan, - kernel_size = 1, - stride = 1, - padding = 0, - bias = False) + self.conv1 = nn.Conv2d( + out_chan, out_chan // 4, kernel_size=1, stride=1, padding=0, bias=False + ) + self.conv2 = nn.Conv2d( + out_chan // 4, out_chan, kernel_size=1, stride=1, padding=0, bias=False + ) self.relu = nn.ReLU(inplace=True) self.sigmoid = nn.Sigmoid() self.init_weight() @@ -219,7 +232,8 @@ def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) def get_params(self): wd_params, nowd_params = [], [] @@ -254,22 +268,29 @@ def forward(self, x): feat_out16 = self.conv_out16(feat_cp8) feat_out32 = self.conv_out32(feat_cp16) - feat_out = F.interpolate(feat_out, (H, W), mode='bilinear', align_corners=True) - feat_out16 = F.interpolate(feat_out16, (H, W), mode='bilinear', align_corners=True) - feat_out32 = F.interpolate(feat_out32, (H, W), mode='bilinear', align_corners=True) + feat_out = F.interpolate(feat_out, (H, W), mode="bilinear", align_corners=True) + feat_out16 = F.interpolate( + feat_out16, (H, W), mode="bilinear", align_corners=True + ) + feat_out32 = F.interpolate( + feat_out32, (H, W), mode="bilinear", align_corners=True + ) return feat_out, feat_out16, feat_out32 def init_weight(self): for ly in self.children(): if isinstance(ly, nn.Conv2d): nn.init.kaiming_normal_(ly.weight, a=1) - if not ly.bias is None: nn.init.constant_(ly.bias, 0) + if not ly.bias is None: + nn.init.constant_(ly.bias, 0) def get_params(self): wd_params, nowd_params, lr_mul_wd_params, lr_mul_nowd_params = [], [], [], [] for name, child in self.named_children(): child_wd_params, child_nowd_params = child.get_params() - if isinstance(child, FeatureFusionModule) or isinstance(child, BiSeNetOutput): + if isinstance(child, FeatureFusionModule) or isinstance( + child, BiSeNetOutput + ): lr_mul_wd_params += child_wd_params lr_mul_nowd_params += child_nowd_params else: diff --git a/models/face_parsing/modules/bn.py b/models/face_parsing/modules/bn.py index cd3928b..1c4a007 100644 --- a/models/face_parsing/modules/bn.py +++ b/models/face_parsing/modules/bn.py @@ -16,7 +16,15 @@ class ABN(nn.Module): This gathers a `BatchNorm2d` and an activation function in a single module """ - def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, activation="leaky_relu", slope=0.01): + def __init__( + self, + num_features, + eps=1e-5, + momentum=0.1, + affine=True, + activation="leaky_relu", + slope=0.01, + ): """Creates an Activated Batch Normalization module Parameters @@ -45,10 +53,10 @@ def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, activation self.weight = nn.Parameter(torch.ones(num_features)) self.bias = nn.Parameter(torch.zeros(num_features)) else: - self.register_parameter('weight', None) - self.register_parameter('bias', None) - self.register_buffer('running_mean', torch.zeros(num_features)) - self.register_buffer('running_var', torch.ones(num_features)) + self.register_parameter("weight", None) + self.register_parameter("bias", None) + self.register_buffer("running_mean", torch.zeros(num_features)) + self.register_buffer("running_var", torch.ones(num_features)) self.reset_parameters() def reset_parameters(self): @@ -59,8 +67,16 @@ def reset_parameters(self): nn.init.constant_(self.bias, 0) def forward(self, x): - x = functional.batch_norm(x, self.running_mean, self.running_var, self.weight, self.bias, - self.training, self.momentum, self.eps) + x = functional.batch_norm( + x, + self.running_mean, + self.running_var, + self.weight, + self.bias, + self.training, + self.momentum, + self.eps, + ) if self.activation == ACT_RELU: return functional.relu(x, inplace=True) @@ -72,19 +88,29 @@ def forward(self, x): return x def __repr__(self): - rep = '{name}({num_features}, eps={eps}, momentum={momentum},' \ - ' affine={affine}, activation={activation}' + rep = ( + "{name}({num_features}, eps={eps}, momentum={momentum}," + " affine={affine}, activation={activation}" + ) if self.activation == "leaky_relu": - rep += ', slope={slope})' + rep += ", slope={slope})" else: - rep += ')' + rep += ")" return rep.format(name=self.__class__.__name__, **self.__dict__) class InPlaceABN(ABN): """InPlace Activated Batch Normalization""" - def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, activation="leaky_relu", slope=0.01): + def __init__( + self, + num_features, + eps=1e-5, + momentum=0.1, + affine=True, + activation="leaky_relu", + slope=0.01, + ): """Creates an InPlace Activated Batch Normalization module Parameters @@ -102,11 +128,23 @@ def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, activation slope : float Negative slope for the `leaky_relu` activation. """ - super(InPlaceABN, self).__init__(num_features, eps, momentum, affine, activation, slope) + super(InPlaceABN, self).__init__( + num_features, eps, momentum, affine, activation, slope + ) def forward(self, x): - return inplace_abn(x, self.weight, self.bias, self.running_mean, self.running_var, - self.training, self.momentum, self.eps, self.activation, self.slope) + return inplace_abn( + x, + self.weight, + self.bias, + self.running_mean, + self.running_var, + self.training, + self.momentum, + self.eps, + self.activation, + self.slope, + ) class InPlaceABNSync(ABN): @@ -115,16 +153,26 @@ class InPlaceABNSync(ABN): """ def forward(self, x): - return inplace_abn_sync(x, self.weight, self.bias, self.running_mean, self.running_var, - self.training, self.momentum, self.eps, self.activation, self.slope) + return inplace_abn_sync( + x, + self.weight, + self.bias, + self.running_mean, + self.running_var, + self.training, + self.momentum, + self.eps, + self.activation, + self.slope, + ) def __repr__(self): - rep = '{name}({num_features}, eps={eps}, momentum={momentum},' \ - ' affine={affine}, activation={activation}' + rep = ( + "{name}({num_features}, eps={eps}, momentum={momentum}," + " affine={affine}, activation={activation}" + ) if self.activation == "leaky_relu": - rep += ', slope={slope})' + rep += ", slope={slope})" else: - rep += ')' + rep += ")" return rep.format(name=self.__class__.__name__, **self.__dict__) - - diff --git a/models/face_parsing/modules/deeplab.py b/models/face_parsing/modules/deeplab.py index fd25b78..4d26409 100644 --- a/models/face_parsing/modules/deeplab.py +++ b/models/face_parsing/modules/deeplab.py @@ -7,25 +7,52 @@ class DeeplabV3(nn.Module): - def __init__(self, - in_channels, - out_channels, - hidden_channels=256, - dilations=(12, 24, 36), - norm_act=ABN, - pooling_size=None): + def __init__( + self, + in_channels, + out_channels, + hidden_channels=256, + dilations=(12, 24, 36), + norm_act=ABN, + pooling_size=None, + ): super(DeeplabV3, self).__init__() self.pooling_size = pooling_size - self.map_convs = nn.ModuleList([ - nn.Conv2d(in_channels, hidden_channels, 1, bias=False), - nn.Conv2d(in_channels, hidden_channels, 3, bias=False, dilation=dilations[0], padding=dilations[0]), - nn.Conv2d(in_channels, hidden_channels, 3, bias=False, dilation=dilations[1], padding=dilations[1]), - nn.Conv2d(in_channels, hidden_channels, 3, bias=False, dilation=dilations[2], padding=dilations[2]) - ]) + self.map_convs = nn.ModuleList( + [ + nn.Conv2d(in_channels, hidden_channels, 1, bias=False), + nn.Conv2d( + in_channels, + hidden_channels, + 3, + bias=False, + dilation=dilations[0], + padding=dilations[0], + ), + nn.Conv2d( + in_channels, + hidden_channels, + 3, + bias=False, + dilation=dilations[1], + padding=dilations[1], + ), + nn.Conv2d( + in_channels, + hidden_channels, + 3, + bias=False, + dilation=dilations[2], + padding=dilations[2], + ), + ] + ) self.map_bn = norm_act(hidden_channels * 4) - self.global_pooling_conv = nn.Conv2d(in_channels, hidden_channels, 1, bias=False) + self.global_pooling_conv = nn.Conv2d( + in_channels, hidden_channels, 1, bias=False + ) self.global_pooling_bn = norm_act(hidden_channels) self.red_conv = nn.Conv2d(hidden_channels * 4, out_channels, 1, bias=False) @@ -70,13 +97,19 @@ def _global_pooling(self, x): pool = x.view(x.size(0), x.size(1), -1).mean(dim=-1) pool = pool.view(x.size(0), x.size(1), 1, 1) else: - pooling_size = (min(try_index(self.pooling_size, 0), x.shape[2]), - min(try_index(self.pooling_size, 1), x.shape[3])) + pooling_size = ( + min(try_index(self.pooling_size, 0), x.shape[2]), + min(try_index(self.pooling_size, 1), x.shape[3]), + ) padding = ( (pooling_size[1] - 1) // 2, - (pooling_size[1] - 1) // 2 if pooling_size[1] % 2 == 1 else (pooling_size[1] - 1) // 2 + 1, + (pooling_size[1] - 1) // 2 + if pooling_size[1] % 2 == 1 + else (pooling_size[1] - 1) // 2 + 1, (pooling_size[0] - 1) // 2, - (pooling_size[0] - 1) // 2 if pooling_size[0] % 2 == 1 else (pooling_size[0] - 1) // 2 + 1 + (pooling_size[0] - 1) // 2 + if pooling_size[0] % 2 == 1 + else (pooling_size[0] - 1) // 2 + 1, ) pool = functional.avg_pool2d(x, pooling_size, stride=1) diff --git a/models/face_parsing/modules/dense.py b/models/face_parsing/modules/dense.py index 9638d6e..158ac49 100644 --- a/models/face_parsing/modules/dense.py +++ b/models/face_parsing/modules/dense.py @@ -7,7 +7,9 @@ class DenseModule(nn.Module): - def __init__(self, in_channels, growth, layers, bottleneck_factor=4, norm_act=ABN, dilation=1): + def __init__( + self, in_channels, growth, layers, bottleneck_factor=4, norm_act=ABN, dilation=1 + ): super(DenseModule, self).__init__() self.in_channels = in_channels self.growth = growth @@ -16,15 +18,44 @@ def __init__(self, in_channels, growth, layers, bottleneck_factor=4, norm_act=AB self.convs1 = nn.ModuleList() self.convs3 = nn.ModuleList() for i in range(self.layers): - self.convs1.append(nn.Sequential(OrderedDict([ - ("bn", norm_act(in_channels)), - ("conv", nn.Conv2d(in_channels, self.growth * bottleneck_factor, 1, bias=False)) - ]))) - self.convs3.append(nn.Sequential(OrderedDict([ - ("bn", norm_act(self.growth * bottleneck_factor)), - ("conv", nn.Conv2d(self.growth * bottleneck_factor, self.growth, 3, padding=dilation, bias=False, - dilation=dilation)) - ]))) + self.convs1.append( + nn.Sequential( + OrderedDict( + [ + ("bn", norm_act(in_channels)), + ( + "conv", + nn.Conv2d( + in_channels, + self.growth * bottleneck_factor, + 1, + bias=False, + ), + ), + ] + ) + ) + ) + self.convs3.append( + nn.Sequential( + OrderedDict( + [ + ("bn", norm_act(self.growth * bottleneck_factor)), + ( + "conv", + nn.Conv2d( + self.growth * bottleneck_factor, + self.growth, + 3, + padding=dilation, + bias=False, + dilation=dilation, + ), + ), + ] + ) + ) + ) in_channels += self.growth @property diff --git a/models/face_parsing/modules/functions.py b/models/face_parsing/modules/functions.py index 093615f..b33ab11 100644 --- a/models/face_parsing/modules/functions.py +++ b/models/face_parsing/modules/functions.py @@ -1,5 +1,5 @@ from os import path -import torch +import torch import torch.distributed as dist import torch.autograd as autograd import torch.cuda.comm as comm @@ -7,15 +7,20 @@ from torch.utils.cpp_extension import load _src_path = path.join(path.dirname(path.abspath(__file__)), "src") -_backend = load(name="inplace_abn", - extra_cflags=["-O3"], - sources=[path.join(_src_path, f) for f in [ - "inplace_abn.cpp", - "inplace_abn_cpu.cpp", - "inplace_abn_cuda.cu", - "inplace_abn_cuda_half.cu" - ]], - extra_cuda_cflags=["--expt-extended-lambda"]) +_backend = load( + name="inplace_abn", + extra_cflags=["-O3"], + sources=[ + path.join(_src_path, f) + for f in [ + "inplace_abn.cpp", + "inplace_abn_cpu.cpp", + "inplace_abn_cuda.cu", + "inplace_abn_cuda_half.cu", + ] + ], + extra_cuda_cflags=["--expt-extended-lambda"], +) # Activation names ACT_RELU = "relu" @@ -76,8 +81,19 @@ def _act_backward(ctx, x, dx): class InPlaceABN(autograd.Function): @staticmethod - def forward(ctx, x, weight, bias, running_mean, running_var, - training=True, momentum=0.1, eps=1e-05, activation=ACT_LEAKY_RELU, slope=0.01): + def forward( + ctx, + x, + weight, + bias, + running_mean, + running_var, + training=True, + momentum=0.1, + eps=1e-05, + activation=ACT_LEAKY_RELU, + slope=0.01, + ): # Save context ctx.training = training ctx.momentum = momentum @@ -97,7 +113,9 @@ def forward(ctx, x, weight, bias, running_mean, running_var, # Update running stats running_mean.mul_((1 - ctx.momentum)).add_(ctx.momentum * mean) - running_var.mul_((1 - ctx.momentum)).add_(ctx.momentum * var * count / (count - 1)) + running_var.mul_((1 - ctx.momentum)).add_( + ctx.momentum * var * count / (count - 1) + ) # Mark in-place modified tensors ctx.mark_dirty(x, running_mean, running_var) @@ -136,10 +154,24 @@ def backward(ctx, dz): return dx, dweight, dbias, None, None, None, None, None, None, None + class InPlaceABNSync(autograd.Function): @classmethod - def forward(cls, ctx, x, weight, bias, running_mean, running_var, - training=True, momentum=0.1, eps=1e-05, activation=ACT_LEAKY_RELU, slope=0.01, equal_batches=True): + def forward( + cls, + ctx, + x, + weight, + bias, + running_mean, + running_var, + training=True, + momentum=0.1, + eps=1e-05, + activation=ACT_LEAKY_RELU, + slope=0.01, + equal_batches=True, + ): # Save context ctx.training = training ctx.momentum = momentum @@ -151,8 +183,8 @@ def forward(cls, ctx, x, weight, bias, running_mean, running_var, # Prepare inputs ctx.world_size = dist.get_world_size() if dist.is_initialized() else 1 - #count = _count_samples(x) - batch_size = x.new_tensor([x.shape[0]],dtype=torch.long) + # count = _count_samples(x) + batch_size = x.new_tensor([x.shape[0]], dtype=torch.long) x = x.contiguous() weight = weight.contiguous() if ctx.affine else x.new_empty(0) @@ -160,14 +192,14 @@ def forward(cls, ctx, x, weight, bias, running_mean, running_var, if ctx.training: mean, var = _backend.mean_var(x) - if ctx.world_size>1: + if ctx.world_size > 1: # get global batch size if equal_batches: batch_size *= ctx.world_size else: dist.all_reduce(batch_size, dist.ReduceOp.SUM) - ctx.factor = x.shape[0]/float(batch_size.item()) + ctx.factor = x.shape[0] / float(batch_size.item()) mean_all = mean.clone() * ctx.factor dist.all_reduce(mean_all, dist.ReduceOp.SUM) @@ -180,8 +212,10 @@ def forward(cls, ctx, x, weight, bias, running_mean, running_var, # Update running stats running_mean.mul_((1 - ctx.momentum)).add_(ctx.momentum * mean) - count = batch_size.item() * x.view(x.shape[0],x.shape[1],-1).shape[-1] - running_var.mul_((1 - ctx.momentum)).add_(ctx.momentum * var * (float(count) / (count - 1))) + count = batch_size.item() * x.view(x.shape[0], x.shape[1], -1).shape[-1] + running_var.mul_((1 - ctx.momentum)).add_( + ctx.momentum * var * (float(count) / (count - 1)) + ) # Mark in-place modified tensors ctx.mark_dirty(x, running_mean, running_var) @@ -212,7 +246,7 @@ def backward(ctx, dz): edz_local = edz.clone() eydz_local = eydz.clone() - if ctx.world_size>1: + if ctx.world_size > 1: edz *= ctx.factor dist.all_reduce(edz, dist.ReduceOp.SUM) @@ -228,7 +262,15 @@ def backward(ctx, dz): return dx, dweight, dbias, None, None, None, None, None, None, None + inplace_abn = InPlaceABN.apply inplace_abn_sync = InPlaceABNSync.apply -__all__ = ["inplace_abn", "inplace_abn_sync", "ACT_RELU", "ACT_LEAKY_RELU", "ACT_ELU", "ACT_NONE"] +__all__ = [ + "inplace_abn", + "inplace_abn_sync", + "ACT_RELU", + "ACT_LEAKY_RELU", + "ACT_ELU", + "ACT_NONE", +] diff --git a/models/face_parsing/modules/misc.py b/models/face_parsing/modules/misc.py index 3c50b69..2fbacbc 100644 --- a/models/face_parsing/modules/misc.py +++ b/models/face_parsing/modules/misc.py @@ -2,6 +2,7 @@ import torch import torch.distributed as dist + class GlobalAvgPool2d(nn.Module): def __init__(self): """Global average pooling over the input's spatial dimensions""" @@ -11,11 +12,11 @@ def forward(self, inputs): in_size = inputs.size() return inputs.view((in_size[0], in_size[1], -1)).mean(dim=2) + class SingleGPU(nn.Module): def __init__(self, module): super(SingleGPU, self).__init__() - self.module=module + self.module = module def forward(self, input): return self.module(input.cuda(non_blocking=True)) - diff --git a/models/face_parsing/modules/residual.py b/models/face_parsing/modules/residual.py index b7d51ad..9bfa65e 100644 --- a/models/face_parsing/modules/residual.py +++ b/models/face_parsing/modules/residual.py @@ -6,14 +6,16 @@ class IdentityResidualBlock(nn.Module): - def __init__(self, - in_channels, - channels, - stride=1, - dilation=1, - groups=1, - norm_act=ABN, - dropout=None): + def __init__( + self, + in_channels, + channels, + stride=1, + dilation=1, + groups=1, + norm_act=ABN, + dropout=None, + ): """Configurable identity-mapping residual block Parameters @@ -50,29 +52,77 @@ def __init__(self, self.bn1 = norm_act(in_channels) if not is_bottleneck: layers = [ - ("conv1", nn.Conv2d(in_channels, channels[0], 3, stride=stride, padding=dilation, bias=False, - dilation=dilation)), + ( + "conv1", + nn.Conv2d( + in_channels, + channels[0], + 3, + stride=stride, + padding=dilation, + bias=False, + dilation=dilation, + ), + ), ("bn2", norm_act(channels[0])), - ("conv2", nn.Conv2d(channels[0], channels[1], 3, stride=1, padding=dilation, bias=False, - dilation=dilation)) + ( + "conv2", + nn.Conv2d( + channels[0], + channels[1], + 3, + stride=1, + padding=dilation, + bias=False, + dilation=dilation, + ), + ), ] if dropout is not None: layers = layers[0:2] + [("dropout", dropout())] + layers[2:] else: layers = [ - ("conv1", nn.Conv2d(in_channels, channels[0], 1, stride=stride, padding=0, bias=False)), + ( + "conv1", + nn.Conv2d( + in_channels, + channels[0], + 1, + stride=stride, + padding=0, + bias=False, + ), + ), ("bn2", norm_act(channels[0])), - ("conv2", nn.Conv2d(channels[0], channels[1], 3, stride=1, padding=dilation, bias=False, - groups=groups, dilation=dilation)), + ( + "conv2", + nn.Conv2d( + channels[0], + channels[1], + 3, + stride=1, + padding=dilation, + bias=False, + groups=groups, + dilation=dilation, + ), + ), ("bn3", norm_act(channels[1])), - ("conv3", nn.Conv2d(channels[1], channels[2], 1, stride=1, padding=0, bias=False)) + ( + "conv3", + nn.Conv2d( + channels[1], channels[2], 1, stride=1, padding=0, bias=False + ), + ), ] if dropout is not None: layers = layers[0:4] + [("dropout", dropout())] + layers[4:] self.convs = nn.Sequential(OrderedDict(layers)) if need_proj_conv: - self.proj_conv = nn.Conv2d(in_channels, channels[-1], 1, stride=stride, padding=0, bias=False) + self.proj_conv = nn.Conv2d( + in_channels, channels[-1], 1, stride=stride, padding=0, bias=False + ) def forward(self, x): if hasattr(self, "proj_conv"): diff --git a/models/face_parsing/resnet.py b/models/face_parsing/resnet.py index aa2bf95..e74be59 100644 --- a/models/face_parsing/resnet.py +++ b/models/face_parsing/resnet.py @@ -8,13 +8,14 @@ # from modules.bn import InPlaceABNSync as BatchNorm2d -resnet18_url = 'https://download.pytorch.org/models/resnet18-5c106cde.pth' +resnet18_url = "https://download.pytorch.org/models/resnet18-5c106cde.pth" def conv3x3(in_planes, out_planes, stride=1): """3x3 convolution with padding""" - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, - padding=1, bias=False) + return nn.Conv2d( + in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False + ) class BasicBlock(nn.Module): @@ -28,10 +29,9 @@ def __init__(self, in_chan, out_chan, stride=1): self.downsample = None if in_chan != out_chan or stride != 1: self.downsample = nn.Sequential( - nn.Conv2d(in_chan, out_chan, - kernel_size=1, stride=stride, bias=False), + nn.Conv2d(in_chan, out_chan, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(out_chan), - ) + ) def forward(self, x): residual = self.conv1(x) @@ -50,7 +50,7 @@ def forward(self, x): def create_layer_basic(in_chan, out_chan, bnum, stride=1): layers = [BasicBlock(in_chan, out_chan, stride=stride)] - for i in range(bnum-1): + for i in range(bnum - 1): layers.append(BasicBlock(out_chan, out_chan, stride=1)) return nn.Sequential(*layers) @@ -58,8 +58,7 @@ def create_layer_basic(in_chan, out_chan, bnum, stride=1): class Resnet18(nn.Module): def __init__(self): super(Resnet18, self).__init__() - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, - bias=False) + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = nn.BatchNorm2d(64) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = create_layer_basic(64, 64, bnum=2, stride=1) @@ -74,16 +73,17 @@ def forward(self, x): x = self.maxpool(x) x = self.layer1(x) - feat8 = self.layer2(x) # 1/8 - feat16 = self.layer3(feat8) # 1/16 - feat32 = self.layer4(feat16) # 1/32 + feat8 = self.layer2(x) # 1/8 + feat16 = self.layer3(feat8) # 1/16 + feat32 = self.layer4(feat16) # 1/32 return feat8, feat16, feat32 def init_weight(self): state_dict = modelzoo.load_url(resnet18_url) self_state_dict = self.state_dict() for k, v in state_dict.items(): - if 'fc' in k: continue + if "fc" in k: + continue self_state_dict.update({k: v}) self.load_state_dict(self_state_dict) @@ -94,7 +94,7 @@ def get_params(self): wd_params.append(module.weight) if not module.bias is None: nowd_params.append(module.bias) - elif isinstance(module, nn.BatchNorm2d): + elif isinstance(module, nn.BatchNorm2d): nowd_params += list(module.parameters()) return wd_params, nowd_params diff --git a/models/face_parsing/transform.py b/models/face_parsing/transform.py index a28e9d5..d24f55d 100644 --- a/models/face_parsing/transform.py +++ b/models/face_parsing/transform.py @@ -7,18 +7,20 @@ import random import numpy as np + class RandomCrop(object): def __init__(self, size, *args, **kwargs): self.size = size def __call__(self, im_lb): - im = im_lb['im'] - lb = im_lb['lb'] + im = im_lb["im"] + lb = im_lb["lb"] assert im.size == lb.size W, H = self.size w, h = im.size - if (W, H) == (w, h): return dict(im=im, lb=lb) + if (W, H) == (w, h): + return dict(im=im, lb=lb) if w < W or h < H: scale = float(W) / w if w < h else float(H) / h w, h = int(scale * w + 1), int(scale * h + 1) @@ -26,10 +28,7 @@ def __call__(self, im_lb): lb = lb.resize((w, h), Image.NEAREST) sw, sh = random.random() * (w - W), random.random() * (h - H) crop = int(sw), int(sh), int(sw) + W, int(sh) + H - return dict( - im = im.crop(crop), - lb = lb.crop(crop) - ) + return dict(im=im.crop(crop), lb=lb.crop(crop)) class HorizontalFlip(object): @@ -40,9 +39,8 @@ def __call__(self, im_lb): if random.random() > self.p: return im_lb else: - im = im_lb['im'] - lb = im_lb['lb'] - + im = im_lb["im"] + lb = im_lb["lb"] flip_lb = np.array(lb) # flip_lb[lb == 2] = 3 @@ -52,47 +50,52 @@ def __call__(self, im_lb): # flip_lb[lb == 7] = 8 # flip_lb[lb == 8] = 7 flip_lb = Image.fromarray(flip_lb) - return dict(im = im.transpose(Image.FLIP_LEFT_RIGHT), - lb = flip_lb.transpose(Image.FLIP_LEFT_RIGHT), - ) + return dict( + im=im.transpose(Image.FLIP_LEFT_RIGHT), + lb=flip_lb.transpose(Image.FLIP_LEFT_RIGHT), + ) class RandomScale(object): - def __init__(self, scales=(1, ), *args, **kwargs): + def __init__(self, scales=(1,), *args, **kwargs): self.scales = scales def __call__(self, im_lb): - im = im_lb['im'] - lb = im_lb['lb'] + im = im_lb["im"] + lb = im_lb["lb"] W, H = im.size scale = random.choice(self.scales) w, h = int(W * scale), int(H * scale) - return dict(im = im.resize((w, h), Image.BILINEAR), - lb = lb.resize((w, h), Image.NEAREST), - ) + return dict( + im=im.resize((w, h), Image.BILINEAR), + lb=lb.resize((w, h), Image.NEAREST), + ) class ColorJitter(object): - def __init__(self, brightness=None, contrast=None, saturation=None, *args, **kwargs): - if not brightness is None and brightness>0: - self.brightness = [max(1-brightness, 0), 1+brightness] - if not contrast is None and contrast>0: - self.contrast = [max(1-contrast, 0), 1+contrast] - if not saturation is None and saturation>0: - self.saturation = [max(1-saturation, 0), 1+saturation] + def __init__( + self, brightness=None, contrast=None, saturation=None, *args, **kwargs + ): + if not brightness is None and brightness > 0: + self.brightness = [max(1 - brightness, 0), 1 + brightness] + if not contrast is None and contrast > 0: + self.contrast = [max(1 - contrast, 0), 1 + contrast] + if not saturation is None and saturation > 0: + self.saturation = [max(1 - saturation, 0), 1 + saturation] def __call__(self, im_lb): - im = im_lb['im'] - lb = im_lb['lb'] + im = im_lb["im"] + lb = im_lb["lb"] r_brightness = random.uniform(self.brightness[0], self.brightness[1]) r_contrast = random.uniform(self.contrast[0], self.contrast[1]) r_saturation = random.uniform(self.saturation[0], self.saturation[1]) im = ImageEnhance.Brightness(im).enhance(r_brightness) im = ImageEnhance.Contrast(im).enhance(r_contrast) im = ImageEnhance.Color(im).enhance(r_saturation) - return dict(im = im, - lb = lb, - ) + return dict( + im=im, + lb=lb, + ) class MultiScale(object): @@ -101,7 +104,7 @@ def __init__(self, scales): def __call__(self, img): W, H = img.size - sizes = [(int(W*ratio), int(H*ratio)) for ratio in self.scales] + sizes = [(int(W * ratio), int(H * ratio)) for ratio in self.scales] imgs = [] [imgs.append(img.resize(size, Image.BILINEAR)) for size in sizes] return imgs @@ -117,11 +120,9 @@ def __call__(self, im_lb): return im_lb - - -if __name__ == '__main__': - flip = HorizontalFlip(p = 1) +if __name__ == "__main__": + flip = HorizontalFlip(p=1) crop = RandomCrop((321, 321)) rscales = RandomScale((0.75, 1.0, 1.5, 1.75, 2.0)) - img = Image.open('data/img.jpg') - lb = Image.open('data/label.png') + img = Image.open("data/img.jpg") + lb = Image.open("data/label.png") diff --git a/models/optimizer/ClampOptimizer.py b/models/optimizer/ClampOptimizer.py index cfcb907..aa53ec6 100644 --- a/models/optimizer/ClampOptimizer.py +++ b/models/optimizer/ClampOptimizer.py @@ -3,28 +3,21 @@ from torch.optim import Optimizer import numpy as np + class ClampOptimizer(Optimizer): def __init__(self, optimizer, params, **kwargs): self.opt = optimizer(params, **kwargs) self.params = params - - - @torch.no_grad() def step(self, closure=None): loss = self.opt.step(closure) - for param in self.params: tmp_latent_norm = torch.clamp(param.data, 0, 1) param.data.add_(tmp_latent_norm - param.data) - return loss - def zero_grad(self): self.opt.zero_grad() - - diff --git a/models/stylegan2/model.py b/models/stylegan2/model.py index 2fdd5ac..bd4f3c8 100644 --- a/models/stylegan2/model.py +++ b/models/stylegan2/model.py @@ -10,15 +10,17 @@ from models.stylegan2.op import FusedLeakyReLU, fused_leaky_relu, upfirdn2d import torchvision + toPIL = torchvision.transforms.ToPILImage() import numpy as np + class PixelNorm(nn.Module): def __init__(self): super().__init__() def forward(self, input): - return input * torch.rsqrt(torch.mean(input ** 2, dim=1, keepdim=True) + 1e-8) + return input * torch.rsqrt(torch.mean(input**2, dim=1, keepdim=True) + 1e-8) def make_kernel(k): @@ -37,8 +39,8 @@ def __init__(self, kernel, factor=2): super().__init__() self.factor = factor - kernel = make_kernel(kernel) * (factor ** 2) - self.register_buffer('kernel', kernel) + kernel = make_kernel(kernel) * (factor**2) + self.register_buffer("kernel", kernel) p = kernel.shape[0] - factor @@ -59,7 +61,7 @@ def __init__(self, kernel, factor=2): self.factor = factor kernel = make_kernel(kernel) - self.register_buffer('kernel', kernel) + self.register_buffer("kernel", kernel) p = kernel.shape[0] - factor @@ -81,9 +83,9 @@ def __init__(self, kernel, pad, upsample_factor=1): kernel = make_kernel(kernel) if upsample_factor > 1: - kernel = kernel * (upsample_factor ** 2) + kernel = kernel * (upsample_factor**2) - self.register_buffer('kernel', kernel) + self.register_buffer("kernel", kernel) self.pad = pad @@ -102,7 +104,7 @@ def __init__( self.weight = nn.Parameter( torch.randn(out_channel, in_channel, kernel_size, kernel_size) ) - self.scale = 1 / math.sqrt(in_channel * kernel_size ** 2) + self.scale = 1 / math.sqrt(in_channel * kernel_size**2) self.stride = stride self.padding = padding @@ -126,8 +128,8 @@ def forward(self, input): def __repr__(self): return ( - f'{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]},' - f' {self.weight.shape[2]}, stride={self.stride}, padding={self.padding})' + f"{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]}," + f" {self.weight.shape[2]}, stride={self.stride}, padding={self.padding})" ) @@ -164,7 +166,7 @@ def forward(self, input): def __repr__(self): return ( - f'{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]})' + f"{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]})" ) @@ -217,7 +219,7 @@ def __init__( self.blur = Blur(blur_kernel, pad=(pad0, pad1)) - fan_in = in_channel * kernel_size ** 2 + fan_in = in_channel * kernel_size**2 self.scale = 1 / math.sqrt(fan_in) self.padding = kernel_size // 2 @@ -231,8 +233,8 @@ def __init__( def __repr__(self): return ( - f'{self.__class__.__name__}({self.in_channel}, {self.out_channel}, {self.kernel_size}, ' - f'upsample={self.upsample}, downsample={self.downsample})' + f"{self.__class__.__name__}({self.in_channel}, {self.out_channel}, {self.kernel_size}, " + f"upsample={self.upsample}, downsample={self.downsample})" ) def forward(self, input, style): @@ -386,7 +388,7 @@ def __init__( for i in range(n_mlp): layers.append( EqualLinear( - style_dim, style_dim, lr_mul=lr_mlp, activation='fused_lrelu' + style_dim, style_dim, lr_mul=lr_mlp, activation="fused_lrelu" ) ) @@ -404,7 +406,6 @@ def __init__( 1024: 16 * channel_multiplier, } - self.input = ConstantInput(self.channels[4]) self.conv1 = StyledConv( self.channels[4], self.channels[4], 3, style_dim, blur_kernel=blur_kernel @@ -423,11 +424,11 @@ def __init__( for layer_idx in range(self.num_layers): res = (layer_idx + 5) // 2 - shape = [1, 1, 2 ** res, 2 ** res] - self.noises.register_buffer(f'noise_{layer_idx}', torch.randn(*shape)) + shape = [1, 1, 2**res, 2**res] + self.noises.register_buffer(f"noise_{layer_idx}", torch.randn(*shape)) for i in range(3, self.log_size + 1): - out_channel = self.channels[2 ** i] + out_channel = self.channels[2**i] self.convs.append( StyledConv( @@ -455,11 +456,11 @@ def __init__( def make_noise(self): device = self.input.input.device - noises = [torch.randn(1, 1, 2 ** 2, 2 ** 2, device=device)] + 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)) + noises.append(torch.randn(1, 1, 2**i, 2**i, device=device)) return noises @@ -475,21 +476,20 @@ def get_latent(self, input): return self.style(input) def forward( - self, - styles, - return_latents=False, - inject_index=None, - truncation=1, - truncation_latent=None, - input_is_latent=False, - noise=None, - randomize_noise=True, - layer_in=None, - skip=None, - start_layer=0, - end_layer=8, - return_rgb=False, - + self, + styles, + return_latents=False, + inject_index=None, + truncation=1, + truncation_latent=None, + input_is_latent=False, + noise=None, + randomize_noise=True, + layer_in=None, + skip=None, + start_layer=0, + end_layer=8, + return_rgb=False, ): if not input_is_latent: styles = [self.style(s) for s in styles] @@ -499,7 +499,7 @@ def forward( noise = [None] * self.num_layers else: noise = [ - getattr(self.noises, f'noise_{i}') for i in range(self.num_layers) + getattr(self.noises, f"noise_{i}") for i in range(self.num_layers) ] if truncation < 1: @@ -539,7 +539,7 @@ def forward( i = 1 current_layer = 1 for conv1, conv2, noise1, noise2, to_rgb in zip( - self.convs[::2], self.convs[1::2], noise[1::2], noise[2::2], self.to_rgbs + self.convs[::2], self.convs[1::2], noise[1::2], noise[2::2], self.to_rgbs ): if current_layer < start_layer: pass @@ -566,29 +566,55 @@ def forward( def generate_im_from_w_space(self, code, noises=None): latent = torch.from_numpy(code).cuda() - I_G, _ = self([latent], input_is_latent=True, return_latents=False, noise=noises, start_layer=0, - end_layer=8) + I_G, _ = self( + [latent], + input_is_latent=True, + return_latents=False, + noise=noises, + start_layer=0, + end_layer=8, + ) I_G_0_1 = (I_G + 1) / 2 im = np.array(toPIL(I_G_0_1[0].cpu().detach().clamp(0, 1))) return im def generate_initial_intermediate(self, code, noises=None): latent = torch.from_numpy(code).cuda() - intermediate, _ = self([latent], input_is_latent=True, return_latents=False, noise=noises, - start_layer=0, end_layer=3) + intermediate, _ = self( + [latent], + input_is_latent=True, + return_latents=False, + noise=noises, + start_layer=0, + end_layer=3, + ) return intermediate - - def update_on_FS(self, code, initial_intermediate, initial_F, initial_S, noises=None): + def update_on_FS( + self, code, initial_intermediate, initial_F, initial_S, noises=None + ): latent = torch.from_numpy(code).cuda() - intermediate, _ = self([latent], input_is_latent=True, return_latents=False, noise=noises, - start_layer=0, end_layer=3) + intermediate, _ = self( + [latent], + input_is_latent=True, + return_latents=False, + noise=noises, + start_layer=0, + end_layer=3, + ) difference = initial_F - initial_intermediate new_intermediate = intermediate + difference - I_G, _ = self([initial_S], input_is_latent=True, return_latents=False, noise=noises, start_layer=4, - end_layer=8, layer_in=new_intermediate) + I_G, _ = self( + [initial_S], + input_is_latent=True, + return_latents=False, + noise=noises, + start_layer=4, + end_layer=8, + layer_in=new_intermediate, + ) I_G_0_1 = (I_G + 1) / 2 im = np.array(toPIL(I_G_0_1[0].cpu().detach().clamp(0, 1))) return im @@ -700,7 +726,7 @@ def __init__(self, size, channel_multiplier=2, blur_kernel=[1, 3, 3, 1]): self.final_conv = ConvLayer(in_channel + 1, channels[4], 3) self.final_linear = nn.Sequential( - EqualLinear(channels[4] * 4 * 4, channels[4], activation='fused_lrelu'), + EqualLinear(channels[4] * 4 * 4, channels[4], activation="fused_lrelu"), EqualLinear(channels[4], 1), ) @@ -723,4 +749,3 @@ def forward(self, input): out = self.final_linear(out) return out - diff --git a/models/stylegan2/op/fused_act.py b/models/stylegan2/op/fused_act.py index ccb031e..9995c7c 100644 --- a/models/stylegan2/op/fused_act.py +++ b/models/stylegan2/op/fused_act.py @@ -71,7 +71,7 @@ def backward(ctx, grad_output): class FusedLeakyReLU(nn.Module): - def __init__(self, channel, negative_slope=0.2, scale=2 ** 0.5): + def __init__(self, channel, negative_slope=0.2, scale=2**0.5): super().__init__() self.bias = nn.Parameter(torch.zeros(channel)) @@ -82,7 +82,7 @@ def forward(self, input): return fused_leaky_relu(input, self.bias, self.negative_slope, self.scale) -def fused_leaky_relu(input, bias, negative_slope=0.2, scale=2 ** 0.5): +def fused_leaky_relu(input, bias, negative_slope=0.2, scale=2**0.5): if input.device.type == "cpu": rest_dim = [1] * (input.ndim - bias.ndim - 1) return ( diff --git a/utils/PCA_utils.py b/utils/PCA_utils.py index c4ea063..78054cb 100644 --- a/utils/PCA_utils.py +++ b/utils/PCA_utils.py @@ -1,14 +1,18 @@ from sklearn.decomposition import IncrementalPCA import numpy as np -class IPCAEstimator(): + + +class IPCAEstimator: def __init__(self, n_components): self.n_components = n_components self.whiten = False - self.transformer = IncrementalPCA(n_components, whiten=self.whiten, batch_size=max(100, 5*n_components)) + self.transformer = IncrementalPCA( + n_components, whiten=self.whiten, batch_size=max(100, 5 * n_components) + ) self.batch_support = True def get_param_str(self): - return "ipca_c{}{}".format(self.n_components, '_w' if self.whiten else '') + return "ipca_c{}{}".format(self.n_components, "_w" if self.whiten else "") def fit(self, X): self.transformer.fit(X) @@ -16,14 +20,19 @@ def fit(self, X): def fit_partial(self, X): try: self.transformer.partial_fit(X) - self.transformer.n_samples_seen_ = \ - self.transformer.n_samples_seen_.astype(np.int64) # avoid overflow + self.transformer.n_samples_seen_ = self.transformer.n_samples_seen_.astype( + np.int64 + ) # avoid overflow return True except ValueError as e: - print(f'\nIPCA error:', e) + print(f"\nIPCA error:", e) return False def get_components(self): - stdev = np.sqrt(self.transformer.explained_variance_) # already sorted + stdev = np.sqrt(self.transformer.explained_variance_) # already sorted var_ratio = self.transformer.explained_variance_ratio_ - return self.transformer.components_, stdev, var_ratio # PCA outputs are normalized \ No newline at end of file + return ( + self.transformer.components_, + stdev, + var_ratio, + ) # PCA outputs are normalized diff --git a/utils/bicubic.py b/utils/bicubic.py index bf1cc31..bf5fb7a 100644 --- a/utils/bicubic.py +++ b/utils/bicubic.py @@ -10,26 +10,42 @@ def bicubic_kernel(self, x, a=-0.50): https://clouard.users.greyc.fr/Pantheon/experiments/rescaling/index-en.html#bicubic """ abs_x = torch.abs(x) - if abs_x <= 1.: - return (a + 2.) * torch.pow(abs_x, 3.) - (a + 3.) * torch.pow(abs_x, 2.) + 1 - elif 1. < abs_x < 2.: - return a * torch.pow(abs_x, 3) - 5. * a * torch.pow(abs_x, 2.) + 8. * a * abs_x - 4. * a + if abs_x <= 1.0: + return ( + (a + 2.0) * torch.pow(abs_x, 3.0) + - (a + 3.0) * torch.pow(abs_x, 2.0) + + 1 + ) + elif 1.0 < abs_x < 2.0: + return ( + a * torch.pow(abs_x, 3) + - 5.0 * a * torch.pow(abs_x, 2.0) + + 8.0 * a * abs_x + - 4.0 * a + ) else: return 0.0 - def __init__(self, factor=4, cuda=True, padding='reflect'): + def __init__(self, factor=4, cuda=True, padding="reflect"): super().__init__() self.factor = factor size = factor * 4 - k = torch.tensor([self.bicubic_kernel((i - torch.floor(torch.tensor(size / 2)) + 0.5) / factor) - for i in range(size)], dtype=torch.float32) + k = torch.tensor( + [ + self.bicubic_kernel( + (i - torch.floor(torch.tensor(size / 2)) + 0.5) / factor + ) + for i in range(size) + ], + dtype=torch.float32, + ) k = k / torch.sum(k) # k = torch.einsum('i,j->ij', (k, k)) k1 = torch.reshape(k, shape=(1, 1, size, 1)) self.k1 = torch.cat([k1, k1, k1], dim=0) k2 = torch.reshape(k, shape=(1, 1, 1, size)) self.k2 = torch.cat([k2, k2, k2], dim=0) - self.cuda = '.cuda' if cuda else '' + self.cuda = ".cuda" if cuda else "" self.padding = padding for param in self.parameters(): param.requires_grad = False @@ -42,8 +58,8 @@ def forward(self, x, nhwc=False, clip_round=False, byte_output=False): pad_along_height = max(filter_height - stride, 0) pad_along_width = max(filter_width - stride, 0) - filters1 = self.k1.type('torch{}.FloatTensor'.format(self.cuda)) - filters2 = self.k2.type('torch{}.FloatTensor'.format(self.cuda)) + filters1 = self.k1.type("torch{}.FloatTensor".format(self.cuda)) + filters2 = self.k2.type("torch{}.FloatTensor".format(self.cuda)) # compute actual padding values for each side pad_top = pad_along_height // 2 @@ -53,23 +69,22 @@ def forward(self, x, nhwc=False, clip_round=False, byte_output=False): # apply mirror padding if nhwc: - x = torch.transpose(torch.transpose( - x, 2, 3), 1, 2) # NHWC to NCHW + x = torch.transpose(torch.transpose(x, 2, 3), 1, 2) # NHWC to NCHW # downscaling performed by 1-d convolution x = F.pad(x, (0, 0, pad_top, pad_bottom), self.padding) x = F.conv2d(input=x, weight=filters1, stride=(stride, 1), groups=3) if clip_round: - x = torch.clamp(torch.round(x), 0.0, 255.) + x = torch.clamp(torch.round(x), 0.0, 255.0) x = F.pad(x, (pad_left, pad_right, 0, 0), self.padding) x = F.conv2d(input=x, weight=filters2, stride=(1, stride), groups=3) if clip_round: - x = torch.clamp(torch.round(x), 0.0, 255.) + x = torch.clamp(torch.round(x), 0.0, 255.0) if nhwc: x = torch.transpose(torch.transpose(x, 1, 3), 1, 2) if byte_output: - return x.type('torch.ByteTensor'.format(self.cuda)) + return x.type("torch.ByteTensor".format(self.cuda)) else: return x diff --git a/utils/data_utils.py b/utils/data_utils.py index 3c33b0e..ff626ce 100644 --- a/utils/data_utils.py +++ b/utils/data_utils.py @@ -7,8 +7,17 @@ import torch IMG_EXTENSIONS = [ - '.jpg', '.JPG', '.jpeg', '.JPEG', - '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tiff' + ".jpg", + ".JPG", + ".jpeg", + ".JPEG", + ".png", + ".PNG", + ".ppm", + ".PPM", + ".bmp", + ".BMP", + ".tiff", ] @@ -16,10 +25,9 @@ def is_image_file(filename): return any(filename.endswith(extension) for extension in IMG_EXTENSIONS) - def make_dataset(dir): images = [] - assert os.path.isdir(dir), '%s is not a valid directory' % dir + assert os.path.isdir(dir), "%s is not a valid directory" % dir for root, _, fnames in sorted(os.walk(dir)): for fname in fnames: if is_image_file(fname): @@ -28,7 +36,7 @@ def make_dataset(dir): return images -def cuda_unsqueeze(li_variables=None, device='cuda'): +def cuda_unsqueeze(li_variables=None, device="cuda"): if li_variables is None: return None @@ -53,11 +61,9 @@ def convert_npy_code(latent): return latent - def load_FS_latent(latent_path, device): dict = np.load(latent_path) - latent_in = torch.from_numpy(dict['latent_in']).to(device) - latent_F = torch.from_numpy(dict['latent_F']).to(device) + latent_in = torch.from_numpy(dict["latent_in"]).to(device) + latent_F = torch.from_numpy(dict["latent_F"]).to(device) return latent_in, latent_F - diff --git a/utils/drive.py b/utils/drive.py index 62ae698..8820e46 100644 --- a/utils/drive.py +++ b/utils/drive.py @@ -11,6 +11,7 @@ import re import uuid + def is_url(obj: Any) -> bool: """Determine whether the given object is a valid URL string.""" if not isinstance(obj, str) or not "://" in obj: @@ -27,7 +28,13 @@ def is_url(obj: Any) -> bool: return True -def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: bool = True, return_path: bool = False) -> Any: +def open_url( + url: str, + cache_dir: str = None, + num_attempts: int = 10, + verbose: bool = True, + return_path: bool = False, +) -> Any: """Download the given URL and return a binary-mode file object to access the data.""" assert is_url(url) assert num_attempts >= 1 @@ -37,7 +44,7 @@ def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: b if cache_dir is not None: cache_files = glob.glob(os.path.join(cache_dir, url_md5 + "_*")) if len(cache_files) == 1: - if(return_path): + if return_path: return cache_files[0] else: return open(cache_files[0], "rb") @@ -58,14 +65,21 @@ def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: b if len(res.content) < 8192: content_str = res.content.decode("utf-8") if "download_warning" in res.headers.get("Set-Cookie", ""): - links = [html.unescape(link) for link in content_str.split('"') if "export=download" in link] + links = [ + html.unescape(link) + for link in content_str.split('"') + if "export=download" in link + ] if len(links) == 1: url = requests.compat.urljoin(url, links[0]) raise IOError("Google Drive virus checker nag") if "Google Drive - Quota exceeded" in content_str: raise IOError("Google Drive quota exceeded") - match = re.search(r'filename="([^"]*)"', res.headers.get("Content-Disposition", "")) + match = re.search( + r'filename="([^"]*)"', + res.headers.get("Content-Disposition", ""), + ) url_name = match[1] if match else url url_data = res.content if verbose: @@ -83,12 +97,15 @@ def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: b if cache_dir is not None: safe_name = re.sub(r"[^0-9a-zA-Z-._]", "_", url_name) cache_file = os.path.join(cache_dir, url_md5 + "_" + safe_name) - temp_file = os.path.join(cache_dir, "tmp_" + uuid.uuid4().hex + "_" + url_md5 + "_" + safe_name) + temp_file = os.path.join( + cache_dir, "tmp_" + uuid.uuid4().hex + "_" + url_md5 + "_" + safe_name + ) os.makedirs(cache_dir, exist_ok=True) with open(temp_file, "wb") as f: f.write(url_data) - os.replace(temp_file, cache_file) # atomic - if(return_path): return cache_file + os.replace(temp_file, cache_file) # atomic + if return_path: + return cache_file # Return data as file object. - return io.BytesIO(url_data) \ No newline at end of file + return io.BytesIO(url_data) diff --git a/utils/image_utils.py b/utils/image_utils.py index 61516d6..12a501f 100644 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -14,11 +14,8 @@ import scipy - - - def load_image(img_path, normalize=True, downsample=False): - img = PIL.Image.open(img_path).convert('RGB') + img = PIL.Image.open(img_path).convert("RGB") if downsample: img = img.resize((256, 256), PIL.Image.LANCZOS) img = transforms.ToTensor()(img) @@ -27,38 +24,54 @@ def load_image(img_path, normalize=True, downsample=False): return img - def dilate_erosion_mask_path(im_path, seg_net, dilate_erosion=5): # # Mask # mask = Image.open(mask_path).convert("RGB") # mask = mask.resize((256, 256), PIL.Image.NEAREST) # mask = transforms.ToTensor()(mask) # [0, 1] - IM1 = (BicubicDownSample(factor=2)(torchvision.transforms.ToTensor()(Image.open(im_path))[:3].unsqueeze(0).cuda()).clamp( - 0, 1) - seg_mean) / seg_std + IM1 = ( + BicubicDownSample(factor=2)( + torchvision.transforms.ToTensor()(Image.open(im_path))[:3] + .unsqueeze(0) + .cuda() + ).clamp(0, 1) + - seg_mean + ) / seg_std down_seg1, _, _ = seg_net(IM1) mask = torch.argmax(down_seg1, dim=1).long().cpu().float() mask = torch.where(mask == 10, torch.ones_like(mask), torch.zeros_like(mask)) - mask = F.interpolate(mask.unsqueeze(0), size=(256, 256), mode='nearest').squeeze() + mask = F.interpolate(mask.unsqueeze(0), size=(256, 256), mode="nearest").squeeze() # Hair mask + Hair image hair_mask = mask hair_mask = hair_mask.numpy() - hair_mask_dilate = scipy.ndimage.binary_dilation(hair_mask, iterations=dilate_erosion) + hair_mask_dilate = scipy.ndimage.binary_dilation( + hair_mask, iterations=dilate_erosion + ) hair_mask_erode = scipy.ndimage.binary_erosion(hair_mask, iterations=dilate_erosion) hair_mask_dilate = np.expand_dims(hair_mask_dilate, axis=0) hair_mask_erode = np.expand_dims(hair_mask_erode, axis=0) - return torch.from_numpy(hair_mask_dilate).float(), torch.from_numpy(hair_mask_erode).float() + return ( + torch.from_numpy(hair_mask_dilate).float(), + torch.from_numpy(hair_mask_erode).float(), + ) + def dilate_erosion_mask_tensor(mask, dilate_erosion=5): hair_mask = mask.clone() hair_mask = hair_mask.numpy() - hair_mask_dilate = scipy.ndimage.binary_dilation(hair_mask, iterations=dilate_erosion) + hair_mask_dilate = scipy.ndimage.binary_dilation( + hair_mask, iterations=dilate_erosion + ) hair_mask_erode = scipy.ndimage.binary_erosion(hair_mask, iterations=dilate_erosion) hair_mask_dilate = np.expand_dims(hair_mask_dilate, axis=0) hair_mask_erode = np.expand_dims(hair_mask_erode, axis=0) - return torch.from_numpy(hair_mask_dilate).float(), torch.from_numpy(hair_mask_erode).float() + return ( + torch.from_numpy(hair_mask_dilate).float(), + torch.from_numpy(hair_mask_erode).float(), + ) diff --git a/utils/model_utils.py b/utils/model_utils.py index f49fff7..25759e2 100644 --- a/utils/model_utils.py +++ b/utils/model_utils.py @@ -2,16 +2,17 @@ import os -weight_dic = {'afhqwild.pt': 'https://drive.google.com/file/d/14OnzO4QWaAytKXVqcfWo_o2MzoR4ygnr/view?usp=sharing', - 'afhqdog.pt': 'https://drive.google.com/file/d/16v6jPtKVlvq8rg2Sdi3-R9qZEVDgvvEA/view?usp=sharing', - 'afhqcat.pt': 'https://drive.google.com/file/d/1HXLER5R3EMI8DSYDBZafoqpX4EtyOf2R/view?usp=sharing', - 'ffhq.pt': 'https://drive.google.com/file/d/1AT6bNR2ppK8f2ETL_evT27f3R_oyWNHS/view?usp=sharing', - 'metfaces.pt': 'https://drive.google.com/file/d/16wM2PwVWzaMsRgPExvRGsq6BWw_muKbf/view?usp=sharing', - 'seg.pth': 'https://drive.google.com/file/d/1lIKvQaFKHT5zC7uS4p17O9ZpfwmwlS62/view?usp=sharing' - +weight_dic = { + "afhqwild.pt": "https://drive.google.com/file/d/14OnzO4QWaAytKXVqcfWo_o2MzoR4ygnr/view?usp=sharing", + "afhqdog.pt": "https://drive.google.com/file/d/16v6jPtKVlvq8rg2Sdi3-R9qZEVDgvvEA/view?usp=sharing", + "afhqcat.pt": "https://drive.google.com/file/d/1HXLER5R3EMI8DSYDBZafoqpX4EtyOf2R/view?usp=sharing", + "ffhq.pt": "https://drive.google.com/file/d/1AT6bNR2ppK8f2ETL_evT27f3R_oyWNHS/view?usp=sharing", + "metfaces.pt": "https://drive.google.com/file/d/16wM2PwVWzaMsRgPExvRGsq6BWw_muKbf/view?usp=sharing", + "seg.pth": "https://drive.google.com/file/d/1lIKvQaFKHT5zC7uS4p17O9ZpfwmwlS62/view?usp=sharing", } def download_weight(weight_path): - gdown.download(weight_dic[os.path.basename(weight_path)], - output=weight_path, fuzzy=True) + gdown.download( + weight_dic[os.path.basename(weight_path)], output=weight_path, fuzzy=True + ) diff --git a/utils/seg_utils.py b/utils/seg_utils.py index d570279..d178b25 100644 --- a/utils/seg_utils.py +++ b/utils/seg_utils.py @@ -1,27 +1,31 @@ - import numpy as np import os import PIL + + def vis_seg(pred): num_labels = 16 - color = np.array([[0, 0, 0], ## 0 - [102, 204, 255], ## 1 - [255, 204, 255], ## 2 - [255, 255, 153], ## 3 - [255, 255, 153], ## 4 - [255, 255, 102], ## 5 - [51, 255, 51], ## 6 - [0, 153, 255], ## 7 - [0, 255, 255], ## 8 - [0, 255, 255], ## 9 - [204, 102, 255], ## 10 - [0, 153, 255], ## 11 - [0, 255, 153], ## 12 - [0, 51, 0], - [102, 153, 255], ## 14 - [255, 153, 102], ## 15 - ]) + color = np.array( + [ + [0, 0, 0], ## 0 + [102, 204, 255], ## 1 + [255, 204, 255], ## 2 + [255, 255, 153], ## 3 + [255, 255, 153], ## 4 + [255, 255, 102], ## 5 + [51, 255, 51], ## 6 + [0, 153, 255], ## 7 + [0, 255, 255], ## 8 + [0, 255, 255], ## 9 + [204, 102, 255], ## 10 + [0, 153, 255], ## 11 + [0, 255, 153], ## 12 + [0, 51, 0], + [102, 153, 255], ## 14 + [255, 153, 102], ## 15 + ] + ) h, w = np.shape(pred) rgb = np.zeros((h, w, 3), dtype=np.uint8) # print(color.shape) @@ -38,6 +42,8 @@ def vis_seg(pred): def save_vis_mask(img_path1, img_path2, sign, output_dir, mask): im_name_1 = os.path.splitext(os.path.basename(img_path1))[0] im_name_2 = os.path.splitext(os.path.basename(img_path2))[0] - vis_path = os.path.join(output_dir, 'vis_mask_{}_{}_{}.png'.format(im_name_1, im_name_2, sign)) + vis_path = os.path.join( + output_dir, "vis_mask_{}_{}_{}.png".format(im_name_1, im_name_2, sign) + ) vis_mask = vis_seg(mask) PIL.Image.fromarray(vis_mask).save(vis_path) diff --git a/utils/shape_predictor.py b/utils/shape_predictor.py index b7c2528..0831abe 100644 --- a/utils/shape_predictor.py +++ b/utils/shape_predictor.py @@ -23,7 +23,8 @@ # http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 """ -def get_landmark(filepath,predictor): + +def get_landmark(filepath, predictor): """get landmark with dlib :return: np.array shape=(68, 2) """ @@ -40,24 +41,24 @@ def get_landmark(filepath,predictor): return lms -def align_face(filepath,predictor): +def align_face(filepath, predictor): """ :param filepath: str :return: list of PIL Images """ - lms = get_landmark(filepath,predictor) + lms = get_landmark(filepath, predictor) imgs = [] for lm in lms: - lm_chin = lm[0: 17] # left-right - lm_eyebrow_left = lm[17: 22] # left-right - lm_eyebrow_right = lm[22: 27] # left-right - lm_nose = lm[27: 31] # top-down - lm_nostrils = lm[31: 36] # top-down - lm_eye_left = lm[36: 42] # left-clockwise - lm_eye_right = lm[42: 48] # left-clockwise - lm_mouth_outer = lm[48: 60] # left-clockwise - lm_mouth_inner = lm[60: 68] # left-clockwise + lm_chin = lm[0:17] # left-right + lm_eyebrow_left = lm[17:22] # left-right + lm_eyebrow_right = lm[22:27] # left-right + lm_nose = lm[27:31] # top-down + lm_nostrils = lm[31:36] # top-down + lm_eye_left = lm[36:42] # left-clockwise + lm_eye_right = lm[42:48] # left-clockwise + lm_mouth_outer = lm[48:60] # left-clockwise + lm_mouth_inner = lm[60:68] # left-clockwise # Calculate auxiliary vectors. eye_left = np.mean(lm_eye_left, axis=0) @@ -89,45 +90,76 @@ def align_face(filepath,predictor): # Shrink. shrink = int(np.floor(qsize / output_size * 0.5)) if shrink > 1: - rsize = (int(np.rint(float(img.size[0]) / shrink)), int(np.rint(float(img.size[1]) / shrink))) + rsize = ( + int(np.rint(float(img.size[0]) / shrink)), + int(np.rint(float(img.size[1]) / shrink)), + ) img = img.resize(rsize, PIL.Image.ANTIALIAS) quad /= shrink qsize /= shrink # Crop. border = max(int(np.rint(qsize * 0.1)), 3) - crop = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), - int(np.ceil(max(quad[:, 1])))) - crop = (max(crop[0] - border, 0), max(crop[1] - border, 0), min(crop[2] + border, img.size[0]), - min(crop[3] + border, img.size[1])) + crop = ( + int(np.floor(min(quad[:, 0]))), + int(np.floor(min(quad[:, 1]))), + int(np.ceil(max(quad[:, 0]))), + int(np.ceil(max(quad[:, 1]))), + ) + crop = ( + max(crop[0] - border, 0), + max(crop[1] - border, 0), + min(crop[2] + border, img.size[0]), + min(crop[3] + border, img.size[1]), + ) if crop[2] - crop[0] < img.size[0] or crop[3] - crop[1] < img.size[1]: img = img.crop(crop) quad -= crop[0:2] # Pad. - pad = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), - int(np.ceil(max(quad[:, 1])))) - pad = (max(-pad[0] + border, 0), max(-pad[1] + border, 0), max(pad[2] - img.size[0] + border, 0), - max(pad[3] - img.size[1] + border, 0)) + pad = ( + int(np.floor(min(quad[:, 0]))), + int(np.floor(min(quad[:, 1]))), + int(np.ceil(max(quad[:, 0]))), + int(np.ceil(max(quad[:, 1]))), + ) + pad = ( + max(-pad[0] + border, 0), + max(-pad[1] + border, 0), + max(pad[2] - img.size[0] + border, 0), + max(pad[3] - img.size[1] + border, 0), + ) if enable_padding and max(pad) > border - 4: pad = np.maximum(pad, int(np.rint(qsize * 0.3))) - img = np.pad(np.float32(img), ((pad[1], pad[3]), (pad[0], pad[2]), (0, 0)), 'reflect') + img = np.pad( + np.float32(img), ((pad[1], pad[3]), (pad[0], pad[2]), (0, 0)), "reflect" + ) h, w, _ = img.shape y, x, _ = np.ogrid[:h, :w, :1] - mask = np.maximum(1.0 - np.minimum(np.float32(x) / pad[0], np.float32(w - 1 - x) / pad[2]), - 1.0 - np.minimum(np.float32(y) / pad[1], np.float32(h - 1 - y) / pad[3])) + mask = np.maximum( + 1.0 + - np.minimum(np.float32(x) / pad[0], np.float32(w - 1 - x) / pad[2]), + 1.0 + - np.minimum(np.float32(y) / pad[1], np.float32(h - 1 - y) / pad[3]), + ) blur = qsize * 0.02 - img += (scipy.ndimage.gaussian_filter(img, [blur, blur, 0]) - img) * np.clip(mask * 3.0 + 1.0, 0.0, 1.0) + img += ( + scipy.ndimage.gaussian_filter(img, [blur, blur, 0]) - img + ) * np.clip(mask * 3.0 + 1.0, 0.0, 1.0) img += (np.median(img, axis=(0, 1)) - img) * np.clip(mask, 0.0, 1.0) - img = PIL.Image.fromarray(np.uint8(np.clip(np.rint(img), 0, 255)), 'RGB') + img = PIL.Image.fromarray(np.uint8(np.clip(np.rint(img), 0, 255)), "RGB") quad += pad[:2] # Transform. - img = img.transform((transform_size, transform_size), PIL.Image.QUAD, (quad + 0.5).flatten(), - PIL.Image.BILINEAR) + img = img.transform( + (transform_size, transform_size), + PIL.Image.QUAD, + (quad + 0.5).flatten(), + PIL.Image.BILINEAR, + ) if output_size < transform_size: img = img.resize((output_size, output_size), PIL.Image.ANTIALIAS) # Save aligned image. imgs.append(img) - return imgs \ No newline at end of file + return imgs