AshanGimhana
commited on
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- .gitignore +4 -0
- LICENSE +21 -0
- README.md +330 -13
- cog.yaml +25 -0
- configs/__init__.py +0 -0
- configs/__pycache__/__init__.cpython-310.pyc +0 -0
- configs/__pycache__/paths_config.cpython-310.pyc +0 -0
- configs/data_configs.py +13 -0
- configs/paths_config.py +12 -0
- configs/transforms_config.py +37 -0
- criteria/__init__.py +0 -0
- criteria/aging_loss.py +59 -0
- criteria/id_loss.py +55 -0
- criteria/lpips/__init__.py +0 -0
- criteria/lpips/lpips.py +35 -0
- criteria/lpips/networks.py +96 -0
- criteria/lpips/utils.py +30 -0
- criteria/w_norm.py +14 -0
- datasets/__init__.py +0 -0
- datasets/__pycache__/__init__.cpython-310.pyc +0 -0
- datasets/__pycache__/augmentations.cpython-310.pyc +0 -0
- datasets/augmentations.py +24 -0
- datasets/images_dataset.py +33 -0
- datasets/inference_dataset.py +29 -0
- docs/1005_style_mixing.jpg +0 -0
- docs/1936.jpg +0 -0
- docs/2195.jpg +0 -0
- docs/866.jpg +0 -0
- docs/teaser.jpeg +3 -0
- environment/sam_env.yaml +36 -0
- licenses/LICENSE_InterDigitalInc +150 -0
- licenses/LICENSE_S-aiueo32 +25 -0
- licenses/LICENSE_TreB1eN +21 -0
- licenses/LICENSE_eladrich +21 -0
- licenses/LICENSE_lessw2020 +201 -0
- licenses/LICENSE_rosinality +21 -0
- models/__init__.py +0 -0
- models/__pycache__/__init__.cpython-310.pyc +0 -0
- models/__pycache__/psp.cpython-310.pyc +0 -0
- models/dex_vgg.py +65 -0
- models/encoders/__init__.py +0 -0
- models/encoders/__pycache__/__init__.cpython-310.pyc +0 -0
- models/encoders/__pycache__/helpers.cpython-310.pyc +0 -0
- models/encoders/__pycache__/psp_encoders.cpython-310.pyc +0 -0
- models/encoders/helpers.py +119 -0
- models/encoders/model_irse.py +48 -0
- models/encoders/psp_encoders.py +114 -0
- models/psp.py +131 -0
- models/stylegan2/__init__.py +0 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
docs/teaser.jpeg filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.idea
|
2 |
+
.DS_Store
|
3 |
+
pretrained_models/
|
4 |
+
shape_predictor_68_face_landmarks.dat
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2021 Yuval Alaluf
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,13 +1,330 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Only a Matter of Style: Age Transformation Using a Style-Based Regression Model (SIGGRAPH 2021)
|
2 |
+
|
3 |
+
> The task of age transformation illustrates the change of an individual's appearance over time. Accurately modeling this complex transformation over an input facial image is extremely challenging as it requires making convincing and possibly large changes to facial features and head shape, while still preserving the input identity. In this work, we present an image-to-image translation method that learns to directly encode real facial images into the latent space of a pre-trained unconditional GAN (e.g., StyleGAN) subject to a given aging shift. We employ a pre-trained age regression network used to explicitly guide the encoder to generate the latent codes corresponding to the desired age. In this formulation, our method approaches the continuous aging process as a regression task between the input age and desired target age, providing fine-grained control on the generated image. Moreover, unlike other approaches that operate solely in the latent space using a prior on the path controlling age, our method learns a more disentangled, non-linear path. We demonstrate that the end-to-end nature of our approach, coupled with the rich semantic latent space of StyleGAN, allows for further editing of the generated images. Qualitative and quantitative evaluations show the advantages of our method compared to state-of-the-art approaches.
|
4 |
+
|
5 |
+
<a href="https://arxiv.org/abs/2102.02754"><img src="https://img.shields.io/badge/arXiv-2008.00951-b31b1b.svg" height=22.5></a>
|
6 |
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" height=22.5></a>
|
7 |
+
|
8 |
+
<a href="https://www.youtube.com/watch?v=zDTUbtmUbG8"><img src="https://img.shields.io/static/v1?label=Two Minute Papers&message=SAM Video&color=red" height=22.5></a>
|
9 |
+
<a href="https://youtu.be/X_pYC_LtBFw"><img src="https://img.shields.io/static/v1?label=SIGGRAPH 2021 &message=5 Minute Video&color=red" height=22.5></a>
|
10 |
+
<a href="https://replicate.ai/yuval-alaluf/sam"><img src="https://img.shields.io/static/v1?label=Replicate&message=Demo and Docker Image&color=darkgreen" height=22.5></a>
|
11 |
+
|
12 |
+
|
13 |
+
Inference Notebook: <a href="http://colab.research.google.com/github/yuval-alaluf/SAM/blob/master/notebooks/inference_playground.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" height=22.5></a>
|
14 |
+
Animation Notebook: <a href="http://colab.research.google.com/github/yuval-alaluf/SAM/blob/master/notebooks/animation_inference_playground.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" height=22.5></a>
|
15 |
+
|
16 |
+
|
17 |
+
<p align="center">
|
18 |
+
<img src="docs/teaser.jpeg" width="800px"/>
|
19 |
+
</p>
|
20 |
+
|
21 |
+
## Description
|
22 |
+
Official Implementation of our Style-based Age Manipulation (SAM) paper for both training and evaluation. SAM
|
23 |
+
allows modeling fine-grained age transformation using a single input facial image
|
24 |
+
|
25 |
+
<p align="center">
|
26 |
+
<img src="docs/2195.jpg" width="800px"/>
|
27 |
+
<img src="docs/1936.jpg" width="800px"/>
|
28 |
+
</p>
|
29 |
+
|
30 |
+
## Table of Contents
|
31 |
+
* [Getting Started](#getting-started)
|
32 |
+
+ [Prerequisites](#prerequisites)
|
33 |
+
+ [Installation](#installation)
|
34 |
+
* [Pretrained Models](#pretrained-models)
|
35 |
+
* [Training](#training)
|
36 |
+
+ [Preparing your Data](#preparing-your-data)
|
37 |
+
+ [Training SAM](#training-sam)
|
38 |
+
+ [Additional Notes](#additional-notes)
|
39 |
+
* [Notebooks](#notebooks)
|
40 |
+
+ [Inference Notebook](#inference-notebook)
|
41 |
+
+ [MP4 Notebook](#mp4-notebook)
|
42 |
+
* [Testing](#testing)
|
43 |
+
+ [Inference](#inference)
|
44 |
+
+ [Side-by-Side Inference](#side-by-side-inference)
|
45 |
+
+ [Reference-Guided Inference](#reference-guided-inference)
|
46 |
+
+ [Style Mixing](#style-mixing)
|
47 |
+
* [Repository structure](#repository-structure)
|
48 |
+
* [Credits](#credits)
|
49 |
+
* [Acknowledgments](#acknowledgments)
|
50 |
+
* [Citation](#citation)
|
51 |
+
|
52 |
+
|
53 |
+
## Getting Started
|
54 |
+
### Prerequisites
|
55 |
+
- Linux or macOS
|
56 |
+
- NVIDIA GPU + CUDA CuDNN (CPU may be possible with some modifications, but is not inherently supported)
|
57 |
+
- Python 3
|
58 |
+
|
59 |
+
### Installation
|
60 |
+
- Dependencies:
|
61 |
+
We recommend running this repository using [Anaconda](https://docs.anaconda.com/anaconda/install/).
|
62 |
+
All dependencies for defining the environment are provided in `environment/sam_env.yaml`.
|
63 |
+
|
64 |
+
## Pretrained Models
|
65 |
+
Please download the pretrained aging model from the following links.
|
66 |
+
|
67 |
+
| Path | Description
|
68 |
+
| :--- | :----------
|
69 |
+
|[SAM](https://drive.google.com/file/d/1XyumF6_fdAxFmxpFcmPf-q84LU_22EMC/view?usp=sharing) | SAM trained on the FFHQ dataset for age transformation.
|
70 |
+
|
71 |
+
You can run this to download it to the right place:
|
72 |
+
|
73 |
+
```
|
74 |
+
mkdir pretrained_models
|
75 |
+
pip install gdown
|
76 |
+
gdown "https://drive.google.com/u/0/uc?id=1XyumF6_fdAxFmxpFcmPf-q84LU_22EMC&export=download" -O pretrained_models/sam_ffhq_aging.pt
|
77 |
+
wget "https://github.com/italojs/facial-landmarks-recognition/raw/master/shape_predictor_68_face_landmarks.dat"
|
78 |
+
```
|
79 |
+
|
80 |
+
In addition, we provide various auxiliary models needed for training your own SAM model from scratch.
|
81 |
+
This includes the pretrained pSp encoder model for generating the encodings of the input image and the aging classifier
|
82 |
+
used to compute the aging loss during training.
|
83 |
+
|
84 |
+
| Path | Description
|
85 |
+
| :--- | :----------
|
86 |
+
|[pSp Encoder](https://drive.google.com/file/d/1bMTNWkh5LArlaWSc_wa8VKyq2V42T2z0/view?usp=sharing) | pSp taken from [pixel2style2pixel](https://github.com/eladrich/pixel2style2pixel) trained on the FFHQ dataset for StyleGAN inversion.
|
87 |
+
|[FFHQ StyleGAN](https://drive.google.com/file/d/1EM87UquaoQmk17Q8d5kYIAHqu0dkYqdT/view?usp=sharing) | StyleGAN model pretrained on FFHQ taken from [rosinality](https://github.com/rosinality/stylegan2-pytorch) with 1024x1024 output resolution.
|
88 |
+
|[IR-SE50 Model](https://drive.google.com/file/d/1KW7bjndL3QG3sxBbZxreGHigcCCpsDgn/view?usp=sharing) | Pretrained IR-SE50 model taken from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch) for use in our ID loss during training.
|
89 |
+
|[VGG Age Classifier](https://drive.google.com/file/d/1atzjZm_dJrCmFWCqWlyspSpr3nI6Evsh/view?usp=sharing) | VGG age classifier from DEX and fine-tuned on the FFHQ-Aging dataset for use in our aging loss
|
90 |
+
|
91 |
+
By default, we assume that all auxiliary models are downloaded and saved to the directory `pretrained_models`.
|
92 |
+
However, you may use your own paths by changing the necessary values in `configs/path_configs.py`.
|
93 |
+
|
94 |
+
## Training
|
95 |
+
### Preparing your Data
|
96 |
+
Please refer to `configs/paths_config.py` to define the necessary data paths and model paths for training and inference.
|
97 |
+
Then, refer to `configs/data_configs.py` to define the source/target data paths for the train and test sets as well as the
|
98 |
+
transforms to be used for training and inference.
|
99 |
+
|
100 |
+
As an example, we can first go to `configs/paths_config.py` and define:
|
101 |
+
```
|
102 |
+
dataset_paths = {
|
103 |
+
'ffhq': '/path/to/ffhq/images256x256'
|
104 |
+
'celeba_test': '/path/to/CelebAMask-HQ/test_img',
|
105 |
+
}
|
106 |
+
```
|
107 |
+
Then, in `configs/data_configs.py`, we define:
|
108 |
+
```
|
109 |
+
DATASETS = {
|
110 |
+
'ffhq_aging': {
|
111 |
+
'transforms': transforms_config.AgingTransforms,
|
112 |
+
'train_source_root': dataset_paths['ffhq'],
|
113 |
+
'train_target_root': dataset_paths['ffhq'],
|
114 |
+
'test_source_root': dataset_paths['celeba_test'],
|
115 |
+
'test_target_root': dataset_paths['celeba_test'],
|
116 |
+
}
|
117 |
+
}
|
118 |
+
```
|
119 |
+
When defining the datasets for training and inference, we will use the values defined in the above dictionary.
|
120 |
+
|
121 |
+
|
122 |
+
### Training SAM
|
123 |
+
The main training script can be found in `scripts/train.py`.
|
124 |
+
Intermediate training results are saved to `opts.exp_dir`. This includes checkpoints, train outputs, and test outputs.
|
125 |
+
Additionally, if you have tensorboard installed, you can visualize tensorboard logs in `opts.exp_dir/logs`.
|
126 |
+
|
127 |
+
Training SAM with the settings used in the paper can be done by running the following command:
|
128 |
+
```
|
129 |
+
python scripts/train.py \
|
130 |
+
--dataset_type=ffhq_aging \
|
131 |
+
--exp_dir=/path/to/experiment \
|
132 |
+
--workers=6 \
|
133 |
+
--batch_size=6 \
|
134 |
+
--test_batch_size=6 \
|
135 |
+
--test_workers=6 \
|
136 |
+
--val_interval=2500 \
|
137 |
+
--save_interval=10000 \
|
138 |
+
--start_from_encoded_w_plus \
|
139 |
+
--id_lambda=0.1 \
|
140 |
+
--lpips_lambda=0.1 \
|
141 |
+
--lpips_lambda_aging=0.1 \
|
142 |
+
--lpips_lambda_crop=0.6 \
|
143 |
+
--l2_lambda=0.25 \
|
144 |
+
--l2_lambda_aging=0.25 \
|
145 |
+
--l2_lambda_crop=1 \
|
146 |
+
--w_norm_lambda=0.005 \
|
147 |
+
--aging_lambda=5 \
|
148 |
+
--cycle_lambda=1 \
|
149 |
+
--input_nc=4 \
|
150 |
+
--target_age=uniform_random \
|
151 |
+
--use_weighted_id_loss
|
152 |
+
```
|
153 |
+
|
154 |
+
### Additional Notes
|
155 |
+
- See `options/train_options.py` for all training-specific flags.
|
156 |
+
- Note that using the flag `--start_from_encoded_w_plus` requires you to specify the path to the pretrained pSp encoder.
|
157 |
+
By default, this path is taken from `configs.paths_config.model_paths['pretrained_psp']`.
|
158 |
+
- If you wish to resume from a specific checkpoint (e.g. a pretrained SAM model), you may do so using `--checkpoint_path`.
|
159 |
+
|
160 |
+
|
161 |
+
## Notebooks
|
162 |
+
### Inference Notebook
|
163 |
+
To help visualize the results of SAM we provide a Jupyter notebook found in `notebooks/inference_playground.ipynb`.
|
164 |
+
The notebook will download the pretrained aging model and run inference on the images found in `notebooks/images`.
|
165 |
+
|
166 |
+
In addition, [Replicate](https://replicate.ai/) have created a demo for SAM where you can easily upload an image and run SAM on a desired set of ages! Check
|
167 |
+
out the demo [here](https://replicate.ai/yuval-alaluf/sam).
|
168 |
+
|
169 |
+
### MP4 Notebook
|
170 |
+
To show full lifespan results using SAM we provide an additional notebook `notebooks/animation_inference_playground.ipynb` that will
|
171 |
+
run aging on multiple ages between 0 and 100 and interpolate between the results to display full aging.
|
172 |
+
The results will be saved as an MP4 files in `notebooks/animations` showing the aging and de-aging results.
|
173 |
+
|
174 |
+
## Testing
|
175 |
+
### Inference
|
176 |
+
Having trained your model or if you're using a pretrained SAM model, you can use `scripts/inference.py` to run inference
|
177 |
+
on a set of images.
|
178 |
+
For example,
|
179 |
+
```
|
180 |
+
python scripts/inference.py \
|
181 |
+
--exp_dir=/path/to/experiment \
|
182 |
+
--checkpoint_path=experiment/checkpoints/best_model.pt \
|
183 |
+
--data_path=/path/to/test_data \
|
184 |
+
--test_batch_size=4 \
|
185 |
+
--test_workers=4 \
|
186 |
+
--couple_outputs
|
187 |
+
--target_age=0,10,20,30,40,50,60,70,80
|
188 |
+
```
|
189 |
+
Additional notes to consider:
|
190 |
+
- During inference, the options used during training are loaded from the saved checkpoint and are then updated using the
|
191 |
+
test options passed to the inference script.
|
192 |
+
- Adding the flag `--couple_outputs` will save an additional image containing the input and output images side-by-side in the sub-directory
|
193 |
+
`inference_coupled`. Otherwise, only the output image is saved to the sub-directory `inference_results`.
|
194 |
+
- In the above example, we will run age transformation with target ages 0,10,...,80.
|
195 |
+
- The results of each target age are saved to the sub-directories `inference_results/TARGET_AGE` and `inference_coupled/TARGET_AGE`.
|
196 |
+
- By default, the images will be saved at resolution of 1024x1024, the original output size of StyleGAN.
|
197 |
+
- If you wish to save outputs resized to resolutions of 256x256, you can do so by adding the flag `--resize_outputs`.
|
198 |
+
|
199 |
+
### Side-by-Side Inference
|
200 |
+
The above inference script will save each aging result in a different sub-directory for each target age. Sometimes,
|
201 |
+
however, it is more convenient to save all aging results of a given input side-by-side like the following:
|
202 |
+
|
203 |
+
<p align="center">
|
204 |
+
<img src="docs/866.jpg" width="800px"/>
|
205 |
+
</p>
|
206 |
+
|
207 |
+
To do so, we provide a script `inference_side_by_side.py` that works in a similar manner as the regular inference script:
|
208 |
+
```
|
209 |
+
python scripts/inference_side_by_side.py \
|
210 |
+
--exp_dir=/path/to/experiment \
|
211 |
+
--checkpoint_path=experiment/checkpoints/best_model.pt \
|
212 |
+
--data_path=/path/to/test_data \
|
213 |
+
--test_batch_size=4 \
|
214 |
+
--test_workers=4 \
|
215 |
+
--target_age=0,10,20,30,40,50,60,70,80
|
216 |
+
```
|
217 |
+
Here, all aging results 0,10,...,80 will be save side-by-side with the original input image.
|
218 |
+
|
219 |
+
### Reference-Guided Inference
|
220 |
+
In the paper, we demonstrated how one can perform style-mixing on the fine-level style inputs with a reference image
|
221 |
+
to control global features such as hair color. For example,
|
222 |
+
|
223 |
+
<p align="center">
|
224 |
+
<img src="docs/1005_style_mixing.jpg" width="800px"/>
|
225 |
+
</p>
|
226 |
+
|
227 |
+
To perform style mixing using reference images, we provide the script `reference_guided_inference.py`. Here,
|
228 |
+
we first perform aging using the specified target age(s). Then, style mixing is performed using the specified
|
229 |
+
reference images and the specified layers. For example, one can run:
|
230 |
+
```
|
231 |
+
python scripts/reference_guided_inference.py \
|
232 |
+
--exp_dir=/path/to/experiment \
|
233 |
+
--checkpoint_path=experiment/checkpoints/best_model.pt \
|
234 |
+
--data_path=/path/to/test_data \
|
235 |
+
--test_batch_size=4 \
|
236 |
+
--test_workers=4 \
|
237 |
+
--ref_images_paths_file=/path/to/ref_list.txt \
|
238 |
+
--latent_mask=8,9 \
|
239 |
+
--target_age=50,60,70,80
|
240 |
+
```
|
241 |
+
Here, the reference images should be specified in the file defined by `--ref_images_paths_file` and should have the
|
242 |
+
following format:
|
243 |
+
```
|
244 |
+
/path/to/reference/1.jpg
|
245 |
+
/path/to/reference/2.jpg
|
246 |
+
/path/to/reference/3.jpg
|
247 |
+
/path/to/reference/4.jpg
|
248 |
+
/path/to/reference/5.jpg
|
249 |
+
```
|
250 |
+
In the above example, we will aging using 4 different target ages. For each target age, we first transform the
|
251 |
+
test samples defined by `--data_path` and then perform style mixing on layers 8,9 defined by `--latent_mask`.
|
252 |
+
The results of each target age are saved in its own sub-directory.
|
253 |
+
|
254 |
+
### Style Mixing
|
255 |
+
Instead of performing style mixing using a reference image, you can perform style mixing using randomly generated
|
256 |
+
w latent vectors by running the script `style_mixing.py`. This script works in a similar manner to the reference
|
257 |
+
guided inference except you do not need to specify the `--ref_images_paths_file` flag.
|
258 |
+
|
259 |
+
## Repository structure
|
260 |
+
| Path | Description <img width=200>
|
261 |
+
| :--- | :---
|
262 |
+
| SAM | Repository root folder
|
263 |
+
| ├ configs | Folder containing configs defining model/data paths and data transforms
|
264 |
+
| ├ criteria | Folder containing various loss criterias for training
|
265 |
+
| ├ datasets | Folder with various dataset objects and augmentations
|
266 |
+
| ├ docs | Folder containing images displayed in the README
|
267 |
+
| ├ environment | Folder containing Anaconda environment used in our experiments
|
268 |
+
| ├ models | Folder containing all the models and training objects
|
269 |
+
| │ ├ encoders | Folder containing various architecture implementations
|
270 |
+
| │ ├ stylegan2 | StyleGAN2 model from [rosinality](https://github.com/rosinality/stylegan2-pytorch)
|
271 |
+
| │ ├ psp.py | Implementation of pSp encoder
|
272 |
+
| │ └ dex_vgg.py | Implementation of DEX VGG classifier used in computation of aging loss
|
273 |
+
| ├ notebook | Folder with jupyter notebook containing SAM inference playground
|
274 |
+
| ├ options | Folder with training and test command-line options
|
275 |
+
| ├ scripts | Folder with running scripts for training and inference
|
276 |
+
| ├ training | Folder with main training logic and Ranger implementation from [lessw2020](https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer)
|
277 |
+
| ├ utils | Folder with various utility functions
|
278 |
+
| <img width=300> | <img>
|
279 |
+
|
280 |
+
|
281 |
+
## Credits
|
282 |
+
**StyleGAN2 model and implementation:**
|
283 |
+
https://github.com/rosinality/stylegan2-pytorch
|
284 |
+
Copyright (c) 2019 Kim Seonghyeon
|
285 |
+
License (MIT) https://github.com/rosinality/stylegan2-pytorch/blob/master/LICENSE
|
286 |
+
|
287 |
+
**IR-SE50 model and implementations:**
|
288 |
+
https://github.com/TreB1eN/InsightFace_Pytorch
|
289 |
+
Copyright (c) 2018 TreB1eN
|
290 |
+
License (MIT) https://github.com/TreB1eN/InsightFace_Pytorch/blob/master/LICENSE
|
291 |
+
|
292 |
+
**Ranger optimizer implementation:**
|
293 |
+
https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer
|
294 |
+
License (Apache License 2.0) https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer/blob/master/LICENSE
|
295 |
+
|
296 |
+
**LPIPS model and implementation:**
|
297 |
+
https://github.com/S-aiueo32/lpips-pytorch
|
298 |
+
Copyright (c) 2020, Sou Uchida
|
299 |
+
License (BSD 2-Clause) https://github.com/S-aiueo32/lpips-pytorch/blob/master/LICENSE
|
300 |
+
|
301 |
+
**DEX VGG model and implementation:**
|
302 |
+
https://github.com/InterDigitalInc/HRFAE
|
303 |
+
Copyright (c) 2020, InterDigital R&D France
|
304 |
+
https://github.com/InterDigitalInc/HRFAE/blob/master/LICENSE.txt
|
305 |
+
|
306 |
+
**pSp model and implementation:**
|
307 |
+
https://github.com/eladrich/pixel2style2pixel
|
308 |
+
Copyright (c) 2020 Elad Richardson, Yuval Alaluf
|
309 |
+
https://github.com/eladrich/pixel2style2pixel/blob/master/LICENSE
|
310 |
+
|
311 |
+
## Acknowledgments
|
312 |
+
This code borrows heavily from [pixel2style2pixel](https://github.com/eladrich/pixel2style2pixel)
|
313 |
+
|
314 |
+
## Citation
|
315 |
+
If you use this code for your research, please cite our paper <a href="https://arxiv.org/abs/2102.02754">Only a Matter of Style: Age Transformation Using a Style-Based Regression Model</a>:
|
316 |
+
|
317 |
+
```
|
318 |
+
@article{alaluf2021matter,
|
319 |
+
author = {Alaluf, Yuval and Patashnik, Or and Cohen-Or, Daniel},
|
320 |
+
title = {Only a Matter of Style: Age Transformation Using a Style-Based Regression Model},
|
321 |
+
journal = {ACM Trans. Graph.},
|
322 |
+
issue_date = {August 2021},
|
323 |
+
volume = {40},
|
324 |
+
number = {4},
|
325 |
+
year = {2021},
|
326 |
+
articleno = {45},
|
327 |
+
publisher = {Association for Computing Machinery},
|
328 |
+
url = {https://doi.org/10.1145/3450626.3459805}
|
329 |
+
}
|
330 |
+
```
|
cog.yaml
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
image: "r8.im/yuval-alaluf/sam"
|
2 |
+
build:
|
3 |
+
gpu: true
|
4 |
+
python_version: "3.8"
|
5 |
+
system_packages:
|
6 |
+
- "cmake"
|
7 |
+
- "libgl1-mesa-glx"
|
8 |
+
- "libglib2.0-0"
|
9 |
+
- "ninja-build"
|
10 |
+
python_packages:
|
11 |
+
- "Pillow==8.3.1"
|
12 |
+
- "cmake==3.21.1"
|
13 |
+
- "dlib==19.22.1"
|
14 |
+
- "imageio==2.9.0"
|
15 |
+
- "ipython==7.21.0"
|
16 |
+
- "matplotlib==3.1.3"
|
17 |
+
- "numpy==1.21.1"
|
18 |
+
- "opencv-python==4.5.3.56"
|
19 |
+
- "scipy==1.4.1"
|
20 |
+
- "tensorboard==2.2.1"
|
21 |
+
- "torch==1.8.0"
|
22 |
+
- "torchvision==0.9.0"
|
23 |
+
- "tqdm==4.42.1"
|
24 |
+
predict: "predict.py:Predictor"
|
25 |
+
|
configs/__init__.py
ADDED
File without changes
|
configs/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (155 Bytes). View file
|
|
configs/__pycache__/paths_config.cpython-310.pyc
ADDED
Binary file (533 Bytes). View file
|
|
configs/data_configs.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from configs import transforms_config
|
2 |
+
from configs.paths_config import dataset_paths
|
3 |
+
|
4 |
+
|
5 |
+
DATASETS = {
|
6 |
+
'ffhq_aging': {
|
7 |
+
'transforms': transforms_config.AgingTransforms,
|
8 |
+
'train_source_root': dataset_paths['ffhq'],
|
9 |
+
'train_target_root': dataset_paths['ffhq'],
|
10 |
+
'test_source_root': dataset_paths['celeba_test'],
|
11 |
+
'test_target_root': dataset_paths['celeba_test'],
|
12 |
+
}
|
13 |
+
}
|
configs/paths_config.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
dataset_paths = {
|
2 |
+
'celeba_test': '',
|
3 |
+
'ffhq': '',
|
4 |
+
}
|
5 |
+
|
6 |
+
model_paths = {
|
7 |
+
'pretrained_psp_encoder': 'pretrained_models/psp_ffhq_encode.pt',
|
8 |
+
'ir_se50': 'pretrained_models/model_ir_se50.pth',
|
9 |
+
'stylegan_ffhq': 'pretrained_models/stylegan2-ffhq-config-f.pt',
|
10 |
+
'shape_predictor': 'shape_predictor_68_face_landmarks.dat',
|
11 |
+
'age_predictor': 'pretrained_models/dex_age_classifier.pth'
|
12 |
+
}
|
configs/transforms_config.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from abc import abstractmethod
|
2 |
+
import torchvision.transforms as transforms
|
3 |
+
|
4 |
+
|
5 |
+
class TransformsConfig(object):
|
6 |
+
|
7 |
+
def __init__(self, opts):
|
8 |
+
self.opts = opts
|
9 |
+
|
10 |
+
@abstractmethod
|
11 |
+
def get_transforms(self):
|
12 |
+
pass
|
13 |
+
|
14 |
+
|
15 |
+
class AgingTransforms(TransformsConfig):
|
16 |
+
|
17 |
+
def __init__(self, opts):
|
18 |
+
super(AgingTransforms, self).__init__(opts)
|
19 |
+
|
20 |
+
def get_transforms(self):
|
21 |
+
transforms_dict = {
|
22 |
+
'transform_gt_train': transforms.Compose([
|
23 |
+
transforms.Resize((256, 256)),
|
24 |
+
transforms.RandomHorizontalFlip(0.5),
|
25 |
+
transforms.ToTensor(),
|
26 |
+
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]),
|
27 |
+
'transform_source': None,
|
28 |
+
'transform_test': transforms.Compose([
|
29 |
+
transforms.Resize((256, 256)),
|
30 |
+
transforms.ToTensor(),
|
31 |
+
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]),
|
32 |
+
'transform_inference': transforms.Compose([
|
33 |
+
transforms.Resize((256, 256)),
|
34 |
+
transforms.ToTensor(),
|
35 |
+
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])
|
36 |
+
}
|
37 |
+
return transforms_dict
|
criteria/__init__.py
ADDED
File without changes
|
criteria/aging_loss.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch import nn
|
3 |
+
import torch.nn.functional as F
|
4 |
+
|
5 |
+
from configs.paths_config import model_paths
|
6 |
+
from models.dex_vgg import VGG
|
7 |
+
|
8 |
+
|
9 |
+
class AgingLoss(nn.Module):
|
10 |
+
|
11 |
+
def __init__(self, opts):
|
12 |
+
super(AgingLoss, self).__init__()
|
13 |
+
self.age_net = VGG()
|
14 |
+
ckpt = torch.load(model_paths['age_predictor'], map_location="cpu")['state_dict']
|
15 |
+
ckpt = {k.replace('-', '_'): v for k, v in ckpt.items()}
|
16 |
+
self.age_net.load_state_dict(ckpt)
|
17 |
+
self.age_net.cuda()
|
18 |
+
self.age_net.eval()
|
19 |
+
self.min_age = 0
|
20 |
+
self.max_age = 100
|
21 |
+
self.opts = opts
|
22 |
+
|
23 |
+
def __get_predicted_age(self, age_pb):
|
24 |
+
predict_age_pb = F.softmax(age_pb)
|
25 |
+
predict_age = torch.zeros(age_pb.size(0)).type_as(predict_age_pb)
|
26 |
+
for i in range(age_pb.size(0)):
|
27 |
+
for j in range(age_pb.size(1)):
|
28 |
+
predict_age[i] += j * predict_age_pb[i][j]
|
29 |
+
return predict_age
|
30 |
+
|
31 |
+
def extract_ages(self, x):
|
32 |
+
x = F.interpolate(x, size=(224, 224), mode='bilinear')
|
33 |
+
predict_age_pb = self.age_net(x)['fc8']
|
34 |
+
predicted_age = self.__get_predicted_age(predict_age_pb)
|
35 |
+
return predicted_age
|
36 |
+
|
37 |
+
def forward(self, y_hat, y, target_ages, id_logs, label=None):
|
38 |
+
n_samples = y.shape[0]
|
39 |
+
|
40 |
+
if id_logs is None:
|
41 |
+
id_logs = []
|
42 |
+
|
43 |
+
input_ages = self.extract_ages(y) / 100.
|
44 |
+
output_ages = self.extract_ages(y_hat) / 100.
|
45 |
+
|
46 |
+
for i in range(n_samples):
|
47 |
+
# if id logs for the same exists, update the dictionary
|
48 |
+
if len(id_logs) > i:
|
49 |
+
id_logs[i].update({f'input_age_{label}': float(input_ages[i]) * 100,
|
50 |
+
f'output_age_{label}': float(output_ages[i]) * 100,
|
51 |
+
f'target_age_{label}': float(target_ages[i]) * 100})
|
52 |
+
# otherwise, create a new entry for the sample
|
53 |
+
else:
|
54 |
+
id_logs.append({f'input_age_{label}': float(input_ages[i]) * 100,
|
55 |
+
f'output_age_{label}': float(output_ages[i]) * 100,
|
56 |
+
f'target_age_{label}': float(target_ages[i]) * 100})
|
57 |
+
|
58 |
+
loss = F.mse_loss(output_ages, target_ages)
|
59 |
+
return loss, id_logs
|
criteria/id_loss.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch import nn
|
3 |
+
from configs.paths_config import model_paths
|
4 |
+
from models.encoders.model_irse import Backbone
|
5 |
+
|
6 |
+
|
7 |
+
class IDLoss(nn.Module):
|
8 |
+
def __init__(self):
|
9 |
+
super(IDLoss, self).__init__()
|
10 |
+
print('Loading ResNet ArcFace')
|
11 |
+
self.facenet = Backbone(input_size=112, num_layers=50, drop_ratio=0.6, mode='ir_se')
|
12 |
+
self.facenet.load_state_dict(torch.load(model_paths['ir_se50']))
|
13 |
+
self.face_pool = torch.nn.AdaptiveAvgPool2d((112, 112))
|
14 |
+
self.facenet.eval()
|
15 |
+
|
16 |
+
def extract_feats(self, x):
|
17 |
+
x = x[:, :, 35:223, 32:220] # Crop interesting region
|
18 |
+
x = self.face_pool(x)
|
19 |
+
x_feats = self.facenet(x)
|
20 |
+
return x_feats
|
21 |
+
|
22 |
+
def forward(self, y_hat, y, x, label=None, weights=None):
|
23 |
+
n_samples = x.shape[0]
|
24 |
+
x_feats = self.extract_feats(x)
|
25 |
+
y_feats = self.extract_feats(y)
|
26 |
+
y_hat_feats = self.extract_feats(y_hat)
|
27 |
+
y_feats = y_feats.detach()
|
28 |
+
total_loss = 0
|
29 |
+
sim_improvement = 0
|
30 |
+
id_logs = []
|
31 |
+
count = 0
|
32 |
+
for i in range(n_samples):
|
33 |
+
diff_target = y_hat_feats[i].dot(y_feats[i])
|
34 |
+
diff_input = y_hat_feats[i].dot(x_feats[i])
|
35 |
+
diff_views = y_feats[i].dot(x_feats[i])
|
36 |
+
|
37 |
+
if label is None:
|
38 |
+
id_logs.append({'diff_target': float(diff_target),
|
39 |
+
'diff_input': float(diff_input),
|
40 |
+
'diff_views': float(diff_views)})
|
41 |
+
else:
|
42 |
+
id_logs.append({f'diff_target_{label}': float(diff_target),
|
43 |
+
f'diff_input_{label}': float(diff_input),
|
44 |
+
f'diff_views_{label}': float(diff_views)})
|
45 |
+
|
46 |
+
loss = 1 - diff_target
|
47 |
+
if weights is not None:
|
48 |
+
loss = weights[i] * loss
|
49 |
+
|
50 |
+
total_loss += loss
|
51 |
+
id_diff = float(diff_target) - float(diff_views)
|
52 |
+
sim_improvement += id_diff
|
53 |
+
count += 1
|
54 |
+
|
55 |
+
return total_loss / count, sim_improvement / count, id_logs
|
criteria/lpips/__init__.py
ADDED
File without changes
|
criteria/lpips/lpips.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
|
4 |
+
from criteria.lpips.networks import get_network, LinLayers
|
5 |
+
from criteria.lpips.utils import get_state_dict
|
6 |
+
|
7 |
+
|
8 |
+
class LPIPS(nn.Module):
|
9 |
+
r"""Creates a criterion that measures
|
10 |
+
Learned Perceptual Image Patch Similarity (LPIPS).
|
11 |
+
Arguments:
|
12 |
+
net_type (str): the network type to compare the features:
|
13 |
+
'alex' | 'squeeze' | 'vgg'. Default: 'alex'.
|
14 |
+
version (str): the version of LPIPS. Default: 0.1.
|
15 |
+
"""
|
16 |
+
def __init__(self, net_type: str = 'alex', version: str = '0.1'):
|
17 |
+
|
18 |
+
assert version in ['0.1'], 'v0.1 is only supported now'
|
19 |
+
|
20 |
+
super(LPIPS, self).__init__()
|
21 |
+
|
22 |
+
# pretrained network
|
23 |
+
self.net = get_network(net_type).to("cuda")
|
24 |
+
|
25 |
+
# linear layers
|
26 |
+
self.lin = LinLayers(self.net.n_channels_list).to("cuda")
|
27 |
+
self.lin.load_state_dict(get_state_dict(net_type, version))
|
28 |
+
|
29 |
+
def forward(self, x: torch.Tensor, y: torch.Tensor):
|
30 |
+
feat_x, feat_y = self.net(x), self.net(y)
|
31 |
+
|
32 |
+
diff = [(fx - fy) ** 2 for fx, fy in zip(feat_x, feat_y)]
|
33 |
+
res = [l(d).mean((2, 3), True) for d, l in zip(diff, self.lin)]
|
34 |
+
|
35 |
+
return torch.sum(torch.cat(res, 0)) / x.shape[0]
|
criteria/lpips/networks.py
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Sequence
|
2 |
+
|
3 |
+
from itertools import chain
|
4 |
+
|
5 |
+
import torch
|
6 |
+
import torch.nn as nn
|
7 |
+
from torchvision import models
|
8 |
+
|
9 |
+
from criteria.lpips.utils import normalize_activation
|
10 |
+
|
11 |
+
|
12 |
+
def get_network(net_type: str):
|
13 |
+
if net_type == 'alex':
|
14 |
+
return AlexNet()
|
15 |
+
elif net_type == 'squeeze':
|
16 |
+
return SqueezeNet()
|
17 |
+
elif net_type == 'vgg':
|
18 |
+
return VGG16()
|
19 |
+
else:
|
20 |
+
raise NotImplementedError('choose net_type from [alex, squeeze, vgg].')
|
21 |
+
|
22 |
+
|
23 |
+
class LinLayers(nn.ModuleList):
|
24 |
+
def __init__(self, n_channels_list: Sequence[int]):
|
25 |
+
super(LinLayers, self).__init__([
|
26 |
+
nn.Sequential(
|
27 |
+
nn.Identity(),
|
28 |
+
nn.Conv2d(nc, 1, 1, 1, 0, bias=False)
|
29 |
+
) for nc in n_channels_list
|
30 |
+
])
|
31 |
+
|
32 |
+
for param in self.parameters():
|
33 |
+
param.requires_grad = False
|
34 |
+
|
35 |
+
|
36 |
+
class BaseNet(nn.Module):
|
37 |
+
def __init__(self):
|
38 |
+
super(BaseNet, self).__init__()
|
39 |
+
|
40 |
+
# register buffer
|
41 |
+
self.register_buffer(
|
42 |
+
'mean', torch.Tensor([-.030, -.088, -.188])[None, :, None, None])
|
43 |
+
self.register_buffer(
|
44 |
+
'std', torch.Tensor([.458, .448, .450])[None, :, None, None])
|
45 |
+
|
46 |
+
def set_requires_grad(self, state: bool):
|
47 |
+
for param in chain(self.parameters(), self.buffers()):
|
48 |
+
param.requires_grad = state
|
49 |
+
|
50 |
+
def z_score(self, x: torch.Tensor):
|
51 |
+
return (x - self.mean) / self.std
|
52 |
+
|
53 |
+
def forward(self, x: torch.Tensor):
|
54 |
+
x = self.z_score(x)
|
55 |
+
|
56 |
+
output = []
|
57 |
+
for i, (_, layer) in enumerate(self.layers._modules.items(), 1):
|
58 |
+
x = layer(x)
|
59 |
+
if i in self.target_layers:
|
60 |
+
output.append(normalize_activation(x))
|
61 |
+
if len(output) == len(self.target_layers):
|
62 |
+
break
|
63 |
+
return output
|
64 |
+
|
65 |
+
|
66 |
+
class SqueezeNet(BaseNet):
|
67 |
+
def __init__(self):
|
68 |
+
super(SqueezeNet, self).__init__()
|
69 |
+
|
70 |
+
self.layers = models.squeezenet1_1(True).features
|
71 |
+
self.target_layers = [2, 5, 8, 10, 11, 12, 13]
|
72 |
+
self.n_channels_list = [64, 128, 256, 384, 384, 512, 512]
|
73 |
+
|
74 |
+
self.set_requires_grad(False)
|
75 |
+
|
76 |
+
|
77 |
+
class AlexNet(BaseNet):
|
78 |
+
def __init__(self):
|
79 |
+
super(AlexNet, self).__init__()
|
80 |
+
|
81 |
+
self.layers = models.alexnet(True).features
|
82 |
+
self.target_layers = [2, 5, 8, 10, 12]
|
83 |
+
self.n_channels_list = [64, 192, 384, 256, 256]
|
84 |
+
|
85 |
+
self.set_requires_grad(False)
|
86 |
+
|
87 |
+
|
88 |
+
class VGG16(BaseNet):
|
89 |
+
def __init__(self):
|
90 |
+
super(VGG16, self).__init__()
|
91 |
+
|
92 |
+
self.layers = models.vgg16(True).features
|
93 |
+
self.target_layers = [4, 9, 16, 23, 30]
|
94 |
+
self.n_channels_list = [64, 128, 256, 512, 512]
|
95 |
+
|
96 |
+
self.set_requires_grad(False)
|
criteria/lpips/utils.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections import OrderedDict
|
2 |
+
|
3 |
+
import torch
|
4 |
+
|
5 |
+
|
6 |
+
def normalize_activation(x, eps=1e-10):
|
7 |
+
norm_factor = torch.sqrt(torch.sum(x ** 2, dim=1, keepdim=True))
|
8 |
+
return x / (norm_factor + eps)
|
9 |
+
|
10 |
+
|
11 |
+
def get_state_dict(net_type: str = 'alex', version: str = '0.1'):
|
12 |
+
# build url
|
13 |
+
url = 'https://raw.githubusercontent.com/richzhang/PerceptualSimilarity/' \
|
14 |
+
+ f'master/lpips/weights/v{version}/{net_type}.pth'
|
15 |
+
|
16 |
+
# download
|
17 |
+
old_state_dict = torch.hub.load_state_dict_from_url(
|
18 |
+
url, progress=True,
|
19 |
+
map_location=None if torch.cuda.is_available() else torch.device('cpu')
|
20 |
+
)
|
21 |
+
|
22 |
+
# rename keys
|
23 |
+
new_state_dict = OrderedDict()
|
24 |
+
for key, val in old_state_dict.items():
|
25 |
+
new_key = key
|
26 |
+
new_key = new_key.replace('lin', '')
|
27 |
+
new_key = new_key.replace('model.', '')
|
28 |
+
new_state_dict[new_key] = val
|
29 |
+
|
30 |
+
return new_state_dict
|
criteria/w_norm.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch import nn
|
3 |
+
|
4 |
+
|
5 |
+
class WNormLoss(nn.Module):
|
6 |
+
|
7 |
+
def __init__(self, opts):
|
8 |
+
super(WNormLoss, self).__init__()
|
9 |
+
self.opts = opts
|
10 |
+
|
11 |
+
def forward(self, latent, latent_avg=None):
|
12 |
+
if self.opts.start_from_latent_avg or self.opts.start_from_encoded_w_plus:
|
13 |
+
latent = latent - latent_avg
|
14 |
+
return torch.sum(latent.norm(2, dim=(1, 2))) / latent.shape[0]
|
datasets/__init__.py
ADDED
File without changes
|
datasets/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (156 Bytes). View file
|
|
datasets/__pycache__/augmentations.cpython-310.pyc
ADDED
Binary file (1.22 kB). View file
|
|
datasets/augmentations.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import torch
|
3 |
+
|
4 |
+
|
5 |
+
class AgeTransformer(object):
|
6 |
+
|
7 |
+
def __init__(self, target_age):
|
8 |
+
self.target_age = target_age
|
9 |
+
|
10 |
+
def __call__(self, img):
|
11 |
+
img = self.add_aging_channel(img)
|
12 |
+
return img
|
13 |
+
|
14 |
+
def add_aging_channel(self, img):
|
15 |
+
target_age = self.__get_target_age()
|
16 |
+
target_age = int(target_age) / 100 # normalize aging amount to be in range [-1,1]
|
17 |
+
img = torch.cat((img, target_age * torch.ones((1, img.shape[1], img.shape[2]))))
|
18 |
+
return img
|
19 |
+
|
20 |
+
def __get_target_age(self):
|
21 |
+
if self.target_age == "uniform_random":
|
22 |
+
return np.random.randint(low=0., high=101, size=1)[0]
|
23 |
+
else:
|
24 |
+
return self.target_age
|
datasets/images_dataset.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch.utils.data import Dataset
|
2 |
+
from PIL import Image
|
3 |
+
from utils import data_utils
|
4 |
+
|
5 |
+
|
6 |
+
class ImagesDataset(Dataset):
|
7 |
+
|
8 |
+
def __init__(self, source_root, target_root, opts, target_transform=None, source_transform=None):
|
9 |
+
self.source_paths = sorted(data_utils.make_dataset(source_root))
|
10 |
+
self.target_paths = sorted(data_utils.make_dataset(target_root))
|
11 |
+
self.source_transform = source_transform
|
12 |
+
self.target_transform = target_transform
|
13 |
+
self.opts = opts
|
14 |
+
|
15 |
+
def __len__(self):
|
16 |
+
return len(self.source_paths)
|
17 |
+
|
18 |
+
def __getitem__(self, index):
|
19 |
+
from_path = self.source_paths[index]
|
20 |
+
from_im = Image.open(from_path)
|
21 |
+
from_im = from_im.convert('RGB') if self.opts.label_nc == 0 else from_im.convert('L')
|
22 |
+
|
23 |
+
to_path = self.target_paths[index]
|
24 |
+
to_im = Image.open(to_path).convert('RGB')
|
25 |
+
if self.target_transform:
|
26 |
+
to_im = self.target_transform(to_im)
|
27 |
+
|
28 |
+
if self.source_transform:
|
29 |
+
from_im = self.source_transform(from_im)
|
30 |
+
else:
|
31 |
+
from_im = to_im
|
32 |
+
|
33 |
+
return from_im, to_im
|
datasets/inference_dataset.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch.utils.data import Dataset
|
2 |
+
from PIL import Image
|
3 |
+
from utils import data_utils
|
4 |
+
|
5 |
+
|
6 |
+
class InferenceDataset(Dataset):
|
7 |
+
|
8 |
+
def __init__(self, root=None, paths_list=None, opts=None, transform=None, return_path=False):
|
9 |
+
if paths_list is None:
|
10 |
+
self.paths = sorted(data_utils.make_dataset(root))
|
11 |
+
else:
|
12 |
+
self.paths = data_utils.make_dataset_from_paths_list(paths_list)
|
13 |
+
self.transform = transform
|
14 |
+
self.opts = opts
|
15 |
+
self.return_path = return_path
|
16 |
+
|
17 |
+
def __len__(self):
|
18 |
+
return len(self.paths)
|
19 |
+
|
20 |
+
def __getitem__(self, index):
|
21 |
+
from_path = self.paths[index]
|
22 |
+
from_im = Image.open(from_path)
|
23 |
+
from_im = from_im.convert('RGB') if self.opts.label_nc == 0 else from_im.convert('L')
|
24 |
+
if self.transform:
|
25 |
+
from_im = self.transform(from_im)
|
26 |
+
if self.return_path:
|
27 |
+
return from_im, from_path
|
28 |
+
else:
|
29 |
+
return from_im
|
docs/1005_style_mixing.jpg
ADDED
docs/1936.jpg
ADDED
docs/2195.jpg
ADDED
docs/866.jpg
ADDED
docs/teaser.jpeg
ADDED
Git LFS Details
|
environment/sam_env.yaml
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: sam_env
|
2 |
+
channels:
|
3 |
+
- conda-forge
|
4 |
+
- defaults
|
5 |
+
dependencies:
|
6 |
+
- _libgcc_mutex=0.1=main
|
7 |
+
- ca-certificates=2020.4.5.1=hecc5488_0
|
8 |
+
- certifi=2020.4.5.1=py36h9f0ad1d_0
|
9 |
+
- libedit=3.1.20181209=hc058e9b_0
|
10 |
+
- libffi=3.2.1=hd88cf55_4
|
11 |
+
- libgcc-ng=9.1.0=hdf63c60_0
|
12 |
+
- libstdcxx-ng=9.1.0=hdf63c60_0
|
13 |
+
- ncurses=6.2=he6710b0_1
|
14 |
+
- ninja=1.10.0=hc9558a2_0
|
15 |
+
- openssl=1.1.1g=h516909a_0
|
16 |
+
- pip=20.0.2=py36_3
|
17 |
+
- python=3.6.7=h0371630_0
|
18 |
+
- python_abi=3.6=1_cp36m
|
19 |
+
- readline=7.0=h7b6447c_5
|
20 |
+
- setuptools=46.4.0=py36_0
|
21 |
+
- sqlite=3.31.1=h62c20be_1
|
22 |
+
- tk=8.6.8=hbc83047_0
|
23 |
+
- wheel=0.34.2=py36_0
|
24 |
+
- xz=5.2.5=h7b6447c_0
|
25 |
+
- zlib=1.2.11=h7b6447c_3
|
26 |
+
- pip:
|
27 |
+
- scipy==1.4.1
|
28 |
+
- matplotlib==3.2.1
|
29 |
+
- tqdm==4.46.0
|
30 |
+
- numpy==1.18.4
|
31 |
+
- opencv-python==4.2.0.34
|
32 |
+
- pillow==7.1.2
|
33 |
+
- tensorboard==2.2.1
|
34 |
+
- torch==1.6.0
|
35 |
+
- torchvision==0.4.2
|
36 |
+
prefix: ~/anaconda3/envs/sam_env
|
licenses/LICENSE_InterDigitalInc
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
LIMITED SOFTWARE EVALUATION LICENSE AGREEMENT
|
2 |
+
|
3 |
+
|
4 |
+
|
5 |
+
This Limited Software Evaluation License Agreement (the “Agreement”) is entered into as of April 9th 2020, (“Effective Date”)
|
6 |
+
|
7 |
+
The following limited software evaluation license agreement (“the Agreement”) constitute an agreement between you (the “licensee”) and InterDigital R&D France, a French company existing and organized under the laws of France with its registered offices located at 975 avenue des champs blancs 35510 Cesson-Sévigné, FRANCE (hereinafter “InterDigital”)
|
8 |
+
This Agreement governs the download and use of the Software (as defined below). Your use of the Software is subject to the terms and conditions set forth in this Agreement. By installing, using, accessing or copying the Software, you hereby irrevocably accept the terms and conditions of this Agreement. If you do not accept all or parts of the terms and conditions of this Agreement you cannot install, use, access nor copy the Software
|
9 |
+
|
10 |
+
Article 1. Definitions
|
11 |
+
|
12 |
+
“Affiliate” as used herein shall mean any entity that, directly or indirectly, through one or more intermediates, is controlled by, controls, or is under common control with InterDigital or The Licensee, as the case may be. For purposes of this definition only, the term “control” means the possession of the power to direct or cause the direction of the management and policies of an entity, whether by ownership of voting stock or partnership interest, by contract, or otherwise, including direct or indirect ownership of more than fifty percent (50%) of the voting interest in the entity in question.
|
13 |
+
|
14 |
+
“Authorized Purpose” means any use of the Software for research on the Software and evaluation of the Software exclusively, and academic research using the Software without any commercial use. For the avoidance of doubt, a commercial use includes, but is not limited to:
|
15 |
+
- using the Software in advertisements of any kind,
|
16 |
+
- licensing or selling of the Software,
|
17 |
+
- use the Software to provide any service to any third Party
|
18 |
+
- use the Software to develop a competitive product of the Software
|
19 |
+
|
20 |
+
“Documentation” means textual materials delivered by InterDigital to the Licensee pursuant to this Agreement relating to the Software, in written or electronic format, including but not limited to: technical reference manuals, technical notes, user manuals, and application guides.
|
21 |
+
|
22 |
+
“Limited Period” means the life of the copyright owned by InterDigital on the Software in each and every country where such copyright would exist.
|
23 |
+
|
24 |
+
“Intellectual Property Rights” means all copyrights, trademarks, trade secrets, patents, mask works and other intellectual property rights recognized in any jurisdiction worldwide, including all applications and registrations with respect thereto.
|
25 |
+
|
26 |
+
"Open Source software" shall mean any software, including where appropriate, any and all modifications, derivative works, enhancements, upgrades, improvements, fixed bugs, and/or statically linked to the source code of such software, released under a free software license, that requires as a condition of royalty-free usage, copy, modification and/or redistribution of the Open Source Software to:
|
27 |
+
• Redistribute the Open Source Software royalty-free, and/or;
|
28 |
+
• Redistribute the Open Source Software under the same license/distribution terms as those contained in the open source or free software license under which it has originally been released and/or;
|
29 |
+
• Release to the public, disclose or otherwise make available the source code of the Open Source Software.
|
30 |
+
|
31 |
+
For purposes of the Agreement, by means of example and without limitation, any software that is released or distributed under any of the following licenses shall be qualified as Open Source Software: (A) GNU General Public License (GPL), (B) GNU Lesser/Library GPL (LGPL), (C) the Artistic License, (D) the Mozilla Public License, (E) the Common Public License, (F) the Sun Community Source License (SCSL), (G) the Sun Industry Standards Source License (SISSL), (H) BSD License, (I) MIT License, (J) Apache Software License, (K) Open SSL License, (L) IBM Public License, (M) Open Software License.
|
32 |
+
|
33 |
+
“Software” means any computer programming code, in object and/or source version, and related Documentation delivered by InterDigital to the Licensee pursuant to this Agreement as described in Exhibit A attached and incorporated herein by reference.
|
34 |
+
|
35 |
+
Article 2. License
|
36 |
+
|
37 |
+
InterDigital grants Licensee a free, worldwide, non-exclusive, license on copyright owned on the Software to download, use, modify and reproduce solely for the Authorized Purpose for the Limited Period.
|
38 |
+
|
39 |
+
The Licensee shall not pay any royalty, license fee or maintenance fee, or other fee of any nature under this Agreement.
|
40 |
+
|
41 |
+
The Licensee shall have the right to correct, adapt, modify, reverse engineer, disassemble, decompile and any action leading to the transformation of Software provided that such action is made to accomplish the Authorized Purpose.
|
42 |
+
|
43 |
+
Licensee shall have the right to make a demonstration of the Software, provided that it is in the Purpose and provided that Licensee shall maintain control of the Software at all time. This includes the control of any computer or server on which the Software is installed: no third party shall have access to such computer or server under any circumstances. No computer nor server containing the Software will be left in the possession of any third Party.
|
44 |
+
|
45 |
+
Article 3. Restrictions on use of the Software
|
46 |
+
|
47 |
+
Licensee shall not remove, obscure or modify any copyright, trademark or other proprietary rights notices, marks or labels contained on or within the Software, falsify or delete any author attributions, legal notices or other labels of the origin or source of the material.
|
48 |
+
|
49 |
+
Licensee shall not have the right to distribute the Software, either modified or not, to any third Party.
|
50 |
+
|
51 |
+
The rights granted here above do not include any rights to automatically obtain any upgrade or update of the Software, acquired or otherwise made available by InterDigital. Such deliverance shall be discussed on a case by case basis by the Parties.
|
52 |
+
|
53 |
+
Article 4. Ownership
|
54 |
+
|
55 |
+
Title to and ownership of the Software, the Documentation and/or any Intellectual Property Right protecting the Software or/and the Documentation shall, at all times, remain with InterDigital. Licensee agrees that except for the rights granted on copyright on the Software set forth in Section 2 above, in no event does anything in this Agreement grant, provide or convey any other rights, immunities or interest in or to any Intellectual Property Rights (including especially patents) of InterDigital or any of its Affiliates whether by implication, estoppel or otherwise.
|
56 |
+
|
57 |
+
|
58 |
+
Article 5. Publication/Communication
|
59 |
+
|
60 |
+
Any publication or oral communication resulting from the use of the Software shall be elaborated in good faith and shall not be driven by a deliberate will to denigrate InterDigital or any of its products. In any publication and on any support joined to an oral communication (for instance a PowerPoint document) resulting from the use of the Software, the following statement shall be inserted:
|
61 |
+
|
62 |
+
“HRFAE is an InterDigital product”
|
63 |
+
|
64 |
+
And in any publication, the latest publication about the software shall be properly cited. The latest publication currently is:
|
65 |
+
"Arxiv preprint (ref to come shortly)”
|
66 |
+
|
67 |
+
In any oral communication resulting from the use of the Software, the Licensee shall orally indicate that the Software is InterDigital’s property.
|
68 |
+
|
69 |
+
Article 6. No Warranty - Disclaimer
|
70 |
+
|
71 |
+
THE SOFTWARE AND DOCUMENTATION ARE PROVIDED TO LICENSEE ON AN “AS IS” BASIS. INTERDIGITAL MAKES NO WARRANTY THAT THE LICENSED TECHNOLOGY WILL OPERATE ON ANY PARTICULAR HARDWARE, PLATFORM, OR ENVIRONMENT. THERE IS NO WARRANTY THAT THE OPERATION OF THE LICENSED TECHNOLOGY SHALL BE UNINTERRUPTED, WITHOUT BUGS OR ERROR FREE. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED HEREUNDER WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED LIABILITIES AND WARRANTIES OF NONINFRINGEMENT OF INTELLECTUAL PROPERTY, FREEDOM FROM INHERENT DEFECTS, CONFORMITY TO A SAMPLE OR MODEL, MERCHANTABILITY, FITNESS AND/OR SUITABILITY FOR A SPECIFIC OR GENERAL PURPOSE AND THOSE ARISING BY STATUTE OR BY LAW, OR FROM A CAUSE OF DEALING OR USAGE OF TRADE.
|
72 |
+
|
73 |
+
InterDigital shall not be obliged to perform any modifications, derivative works, enhancements, upgrades, updates or improvements of the Software or to fix any bug that could arise.
|
74 |
+
|
75 |
+
Hence, the Licensee uses the Software at his own cost, risks and responsibility. InterDigital shall not be liable for any damage that could arise to Licensee by using the Software, either in accordance with this Agreement or not.
|
76 |
+
|
77 |
+
InterDigital shall not be liable for any consequential or indirect losses, including any indirect loss of profits, revenues, business, and/or anticipated savings, whether or not in the contemplation of the Parties at the time of entering into the Agreement unless expressly set out in the Agreement, or arising from gross negligence, willful misconduct or fraud.
|
78 |
+
|
79 |
+
Licensee agrees that it will defend, indemnify and hold harmless InterDigital and its Affiliates against any and all losses, damages, costs and expenses arising from a breach by the Licensee of any of its obligations or representations hereunder, including, without limitation, any third party, and/or any claims in connection with any such breach and/or any use of the Software, including any claim from third party arising from access, use or any other activity in relation to this Software.
|
80 |
+
|
81 |
+
The Licensee shall not make any warranty, representation, or commitment on behalf of InterDigital to any other third party.
|
82 |
+
|
83 |
+
Article 7. Open Source Software
|
84 |
+
|
85 |
+
InterDigital hereby notifies the Licensee, and the Licensee hereby acknowledges and accepts, that the Software contains Open Source Software. The list of such Open Source Software is enclosed in exhibit B and the relevant license are contained at the root of the Software when downloaded. Hence, the Licensee shall comply with such license and agree on its terms on at its own risks.
|
86 |
+
|
87 |
+
The Licensee hereby represents, warrants and covenants to InterDigital that The Licensee’s use of the Software shall not result in the Contamination of all or part of the Software, directly or indirectly, or of any Intellectual Property of InterDigital or its Affiliates.
|
88 |
+
|
89 |
+
Contamination effect shall mean that the licensing terms under which one Open Source software, distinct from the Software, is released would also apply, by viral effect, to the software to which such Open Source software is linked to, combined with or otherwise connected to.
|
90 |
+
|
91 |
+
Article 8. No Future Contract Obligation
|
92 |
+
|
93 |
+
Neither this Agreement nor the furnishing of the Software, nor any other Confidential Information shall be construed to obligate either party to: (a) enter into any further agreement or negotiation concerning the deployment of the Software; (b) refrain from entering into any agreement or negotiation with any other third party regarding the same or any other subject matter; or (c) refrain from pursuing its business in whatever manner it elects even if this involves competing with the other party.
|
94 |
+
|
95 |
+
Article 9. Term and Termination
|
96 |
+
|
97 |
+
This Agreement shall terminate at the end of the Limited Period, unless earlier terminated by either party on the ground of material breach by the other party, which breach is not remedied after thirty (30) days advance written notice, specifying the breach with reasonable particularity and referencing this Agreement.
|
98 |
+
|
99 |
+
Article 10. General Provisions
|
100 |
+
|
101 |
+
12.1 Severability. If any provision of this Agreement shall be held to be in contravention of applicable law, this Agreement shall be construed as if such provision were not a part thereof, and in all other respects the terms hereof shall remain in full force and effect.
|
102 |
+
|
103 |
+
12.2 Governing Law. Regardless of the place of execution, delivery, performance or any other aspect of this Agreement, this Agreement and all of the rights of the parties under this Agreement shall be governed by, construed under and enforced in accordance with the substantive law of the France without regard to conflicts of law principles. In case of a dispute that could not be settled amicably, the courts of Nanterre shall be exclusively competent.
|
104 |
+
|
105 |
+
12.3 Survival. The provisions of articles 1, 3, 4, 6, 7, 9, 10.2 and 10.6 shall survive termination of this Agreement.
|
106 |
+
12.4 Assignment. InterDigital may assign this license to any third Party. Such assignment will be announced on the website as defined in article 5. Licensee may not assign this agreement to any third party without the previous written agreement from InterDigital.
|
107 |
+
|
108 |
+
12.5 Entire Agreement. This Agreement constitutes the entire agreement between the parties hereto with respect to the subject matter hereof and supersedes any prior agreements or understanding.
|
109 |
+
|
110 |
+
12.6 Notices. To have legal effect, notices must be provided by registered or certified mail, return receipt requested, to the representatives of InterDigital at the following address:
|
111 |
+
|
112 |
+
InterDigital
|
113 |
+
Legal Dept
|
114 |
+
975 avenue des champs blancs
|
115 |
+
35510 Cesson-Sévigné
|
116 |
+
FRANCE
|
117 |
+
|
118 |
+
=======================================================================
|
119 |
+
|
120 |
+
Exhibit A
|
121 |
+
Software
|
122 |
+
|
123 |
+
|
124 |
+
The Software is comprised of the following software and Documentation:
|
125 |
+
|
126 |
+
- README.md file that explains the content of the software and the procedure to use it.
|
127 |
+
- Source python files, as well as pretrained models
|
128 |
+
|
129 |
+
=======================================================================
|
130 |
+
|
131 |
+
Exhibit B
|
132 |
+
Open Source licenses
|
133 |
+
|
134 |
+
|
135 |
+
PIL http://www.pythonware.com/products/pil/license.htm
|
136 |
+
|
137 |
+
numpy https://numpy.org/license.html
|
138 |
+
|
139 |
+
tensorboardX https://github.com/lanpa/tensorboardX/blob/master/LICENSE
|
140 |
+
|
141 |
+
pytorch https://github.com/pytorch/pytorch/blob/master/LICENSE
|
142 |
+
|
143 |
+
torchvision https://github.com/pytorch/vision/blob/master/LICENSE
|
144 |
+
|
145 |
+
tensorboard_logger https://github.com/TeamHG-Memex/tensorboard_logger/blob/master/LICENSE
|
146 |
+
|
147 |
+
argparse https://github.com/ThomasWaldmann/argparse/blob/master/LICENSE.txt
|
148 |
+
|
149 |
+
yaml https://github.com/yaml/pyyaml/blob/master/LICENSE
|
150 |
+
|
licenses/LICENSE_S-aiueo32
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
BSD 2-Clause License
|
2 |
+
|
3 |
+
Copyright (c) 2020, Sou Uchida
|
4 |
+
All rights reserved.
|
5 |
+
|
6 |
+
Redistribution and use in source and binary forms, with or without
|
7 |
+
modification, are permitted provided that the following conditions are met:
|
8 |
+
|
9 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
10 |
+
list of conditions and the following disclaimer.
|
11 |
+
|
12 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
13 |
+
this list of conditions and the following disclaimer in the documentation
|
14 |
+
and/or other materials provided with the distribution.
|
15 |
+
|
16 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
20 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
licenses/LICENSE_TreB1eN
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2018 TreB1eN
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
licenses/LICENSE_eladrich
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2020 Elad Richardson, Yuval Alaluf
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
licenses/LICENSE_lessw2020
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
licenses/LICENSE_rosinality
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2019 Kim Seonghyeon
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
models/__init__.py
ADDED
File without changes
|
models/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (154 Bytes). View file
|
|
models/__pycache__/psp.cpython-310.pyc
ADDED
Binary file (4.67 kB). View file
|
|
models/dex_vgg.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch.nn as nn
|
2 |
+
import torch.nn.functional as F
|
3 |
+
|
4 |
+
"""
|
5 |
+
VGG implementation from [InterDigitalInc](https://github.com/InterDigitalInc/HRFAE/blob/master/nets.py)
|
6 |
+
"""
|
7 |
+
|
8 |
+
class VGG(nn.Module):
|
9 |
+
def __init__(self, pool='max'):
|
10 |
+
super(VGG, self).__init__()
|
11 |
+
# vgg modules
|
12 |
+
self.conv1_1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
|
13 |
+
self.conv1_2 = nn.Conv2d(64, 64, kernel_size=3, padding=1)
|
14 |
+
self.conv2_1 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
|
15 |
+
self.conv2_2 = nn.Conv2d(128, 128, kernel_size=3, padding=1)
|
16 |
+
self.conv3_1 = nn.Conv2d(128, 256, kernel_size=3, padding=1)
|
17 |
+
self.conv3_2 = nn.Conv2d(256, 256, kernel_size=3, padding=1)
|
18 |
+
self.conv3_3 = nn.Conv2d(256, 256, kernel_size=3, padding=1)
|
19 |
+
self.conv4_1 = nn.Conv2d(256, 512, kernel_size=3, padding=1)
|
20 |
+
self.conv4_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
|
21 |
+
self.conv4_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
|
22 |
+
self.conv5_1 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
|
23 |
+
self.conv5_2 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
|
24 |
+
self.conv5_3 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
|
25 |
+
self.fc6 = nn.Linear(25088, 4096, bias=True)
|
26 |
+
self.fc7 = nn.Linear(4096, 4096, bias=True)
|
27 |
+
self.fc8_101 = nn.Linear(4096, 101, bias=True)
|
28 |
+
if pool == 'max':
|
29 |
+
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
|
30 |
+
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
|
31 |
+
self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
|
32 |
+
self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
|
33 |
+
self.pool5 = nn.MaxPool2d(kernel_size=2, stride=2)
|
34 |
+
elif pool == 'avg':
|
35 |
+
self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
|
36 |
+
self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
|
37 |
+
self.pool3 = nn.AvgPool2d(kernel_size=2, stride=2)
|
38 |
+
self.pool4 = nn.AvgPool2d(kernel_size=2, stride=2)
|
39 |
+
self.pool5 = nn.AvgPool2d(kernel_size=2, stride=2)
|
40 |
+
|
41 |
+
def forward(self, x):
|
42 |
+
out = {}
|
43 |
+
out['r11'] = F.relu(self.conv1_1(x))
|
44 |
+
out['r12'] = F.relu(self.conv1_2(out['r11']))
|
45 |
+
out['p1'] = self.pool1(out['r12'])
|
46 |
+
out['r21'] = F.relu(self.conv2_1(out['p1']))
|
47 |
+
out['r22'] = F.relu(self.conv2_2(out['r21']))
|
48 |
+
out['p2'] = self.pool2(out['r22'])
|
49 |
+
out['r31'] = F.relu(self.conv3_1(out['p2']))
|
50 |
+
out['r32'] = F.relu(self.conv3_2(out['r31']))
|
51 |
+
out['r33'] = F.relu(self.conv3_3(out['r32']))
|
52 |
+
out['p3'] = self.pool3(out['r33'])
|
53 |
+
out['r41'] = F.relu(self.conv4_1(out['p3']))
|
54 |
+
out['r42'] = F.relu(self.conv4_2(out['r41']))
|
55 |
+
out['r43'] = F.relu(self.conv4_3(out['r42']))
|
56 |
+
out['p4'] = self.pool4(out['r43'])
|
57 |
+
out['r51'] = F.relu(self.conv5_1(out['p4']))
|
58 |
+
out['r52'] = F.relu(self.conv5_2(out['r51']))
|
59 |
+
out['r53'] = F.relu(self.conv5_3(out['r52']))
|
60 |
+
out['p5'] = self.pool5(out['r53'])
|
61 |
+
out['p5'] = out['p5'].view(out['p5'].size(0), -1)
|
62 |
+
out['fc6'] = F.relu(self.fc6(out['p5']))
|
63 |
+
out['fc7'] = F.relu(self.fc7(out['fc6']))
|
64 |
+
out['fc8'] = self.fc8_101(out['fc7'])
|
65 |
+
return out
|
models/encoders/__init__.py
ADDED
File without changes
|
models/encoders/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (163 Bytes). View file
|
|
models/encoders/__pycache__/helpers.cpython-310.pyc
ADDED
Binary file (4.01 kB). View file
|
|
models/encoders/__pycache__/psp_encoders.cpython-310.pyc
ADDED
Binary file (4.07 kB). View file
|
|
models/encoders/helpers.py
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections import namedtuple
|
2 |
+
import torch
|
3 |
+
from torch.nn import Conv2d, BatchNorm2d, PReLU, ReLU, Sigmoid, MaxPool2d, AdaptiveAvgPool2d, Sequential, Module
|
4 |
+
|
5 |
+
"""
|
6 |
+
ArcFace implementation from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch)
|
7 |
+
"""
|
8 |
+
|
9 |
+
|
10 |
+
class Flatten(Module):
|
11 |
+
def forward(self, input):
|
12 |
+
return input.view(input.size(0), -1)
|
13 |
+
|
14 |
+
|
15 |
+
def l2_norm(input, axis=1):
|
16 |
+
norm = torch.norm(input, 2, axis, True)
|
17 |
+
output = torch.div(input, norm)
|
18 |
+
return output
|
19 |
+
|
20 |
+
|
21 |
+
class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])):
|
22 |
+
""" A named tuple describing a ResNet block. """
|
23 |
+
|
24 |
+
|
25 |
+
def get_block(in_channel, depth, num_units, stride=2):
|
26 |
+
return [Bottleneck(in_channel, depth, stride)] + [Bottleneck(depth, depth, 1) for i in range(num_units - 1)]
|
27 |
+
|
28 |
+
|
29 |
+
def get_blocks(num_layers):
|
30 |
+
if num_layers == 50:
|
31 |
+
blocks = [
|
32 |
+
get_block(in_channel=64, depth=64, num_units=3),
|
33 |
+
get_block(in_channel=64, depth=128, num_units=4),
|
34 |
+
get_block(in_channel=128, depth=256, num_units=14),
|
35 |
+
get_block(in_channel=256, depth=512, num_units=3)
|
36 |
+
]
|
37 |
+
elif num_layers == 100:
|
38 |
+
blocks = [
|
39 |
+
get_block(in_channel=64, depth=64, num_units=3),
|
40 |
+
get_block(in_channel=64, depth=128, num_units=13),
|
41 |
+
get_block(in_channel=128, depth=256, num_units=30),
|
42 |
+
get_block(in_channel=256, depth=512, num_units=3)
|
43 |
+
]
|
44 |
+
elif num_layers == 152:
|
45 |
+
blocks = [
|
46 |
+
get_block(in_channel=64, depth=64, num_units=3),
|
47 |
+
get_block(in_channel=64, depth=128, num_units=8),
|
48 |
+
get_block(in_channel=128, depth=256, num_units=36),
|
49 |
+
get_block(in_channel=256, depth=512, num_units=3)
|
50 |
+
]
|
51 |
+
else:
|
52 |
+
raise ValueError("Invalid number of layers: {}. Must be one of [50, 100, 152]".format(num_layers))
|
53 |
+
return blocks
|
54 |
+
|
55 |
+
|
56 |
+
class SEModule(Module):
|
57 |
+
def __init__(self, channels, reduction):
|
58 |
+
super(SEModule, self).__init__()
|
59 |
+
self.avg_pool = AdaptiveAvgPool2d(1)
|
60 |
+
self.fc1 = Conv2d(channels, channels // reduction, kernel_size=1, padding=0, bias=False)
|
61 |
+
self.relu = ReLU(inplace=True)
|
62 |
+
self.fc2 = Conv2d(channels // reduction, channels, kernel_size=1, padding=0, bias=False)
|
63 |
+
self.sigmoid = Sigmoid()
|
64 |
+
|
65 |
+
def forward(self, x):
|
66 |
+
module_input = x
|
67 |
+
x = self.avg_pool(x)
|
68 |
+
x = self.fc1(x)
|
69 |
+
x = self.relu(x)
|
70 |
+
x = self.fc2(x)
|
71 |
+
x = self.sigmoid(x)
|
72 |
+
return module_input * x
|
73 |
+
|
74 |
+
|
75 |
+
class bottleneck_IR(Module):
|
76 |
+
def __init__(self, in_channel, depth, stride):
|
77 |
+
super(bottleneck_IR, self).__init__()
|
78 |
+
if in_channel == depth:
|
79 |
+
self.shortcut_layer = MaxPool2d(1, stride)
|
80 |
+
else:
|
81 |
+
self.shortcut_layer = Sequential(
|
82 |
+
Conv2d(in_channel, depth, (1, 1), stride, bias=False),
|
83 |
+
BatchNorm2d(depth)
|
84 |
+
)
|
85 |
+
self.res_layer = Sequential(
|
86 |
+
BatchNorm2d(in_channel),
|
87 |
+
Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False), PReLU(depth),
|
88 |
+
Conv2d(depth, depth, (3, 3), stride, 1, bias=False), BatchNorm2d(depth)
|
89 |
+
)
|
90 |
+
|
91 |
+
def forward(self, x):
|
92 |
+
shortcut = self.shortcut_layer(x)
|
93 |
+
res = self.res_layer(x)
|
94 |
+
return res + shortcut
|
95 |
+
|
96 |
+
|
97 |
+
class bottleneck_IR_SE(Module):
|
98 |
+
def __init__(self, in_channel, depth, stride):
|
99 |
+
super(bottleneck_IR_SE, self).__init__()
|
100 |
+
if in_channel == depth:
|
101 |
+
self.shortcut_layer = MaxPool2d(1, stride)
|
102 |
+
else:
|
103 |
+
self.shortcut_layer = Sequential(
|
104 |
+
Conv2d(in_channel, depth, (1, 1), stride, bias=False),
|
105 |
+
BatchNorm2d(depth)
|
106 |
+
)
|
107 |
+
self.res_layer = Sequential(
|
108 |
+
BatchNorm2d(in_channel),
|
109 |
+
Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
|
110 |
+
PReLU(depth),
|
111 |
+
Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
|
112 |
+
BatchNorm2d(depth),
|
113 |
+
SEModule(depth, 16)
|
114 |
+
)
|
115 |
+
|
116 |
+
def forward(self, x):
|
117 |
+
shortcut = self.shortcut_layer(x)
|
118 |
+
res = self.res_layer(x)
|
119 |
+
return res + shortcut
|
models/encoders/model_irse.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, Dropout, Sequential, Module
|
2 |
+
from models.encoders.helpers import get_blocks, Flatten, bottleneck_IR, bottleneck_IR_SE, l2_norm
|
3 |
+
|
4 |
+
"""
|
5 |
+
Modified Backbone implementation from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch)
|
6 |
+
"""
|
7 |
+
|
8 |
+
|
9 |
+
class Backbone(Module):
|
10 |
+
def __init__(self, input_size, num_layers, mode='ir', drop_ratio=0.4, affine=True):
|
11 |
+
super(Backbone, self).__init__()
|
12 |
+
assert input_size in [112, 224], "input_size should be 112 or 224"
|
13 |
+
assert num_layers in [50, 100, 152], "num_layers should be 50, 100 or 152"
|
14 |
+
assert mode in ['ir', 'ir_se'], "mode should be ir or ir_se"
|
15 |
+
blocks = get_blocks(num_layers)
|
16 |
+
if mode == 'ir':
|
17 |
+
unit_module = bottleneck_IR
|
18 |
+
elif mode == 'ir_se':
|
19 |
+
unit_module = bottleneck_IR_SE
|
20 |
+
self.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1, bias=False),
|
21 |
+
BatchNorm2d(64),
|
22 |
+
PReLU(64))
|
23 |
+
if input_size == 112:
|
24 |
+
self.output_layer = Sequential(BatchNorm2d(512),
|
25 |
+
Dropout(drop_ratio),
|
26 |
+
Flatten(),
|
27 |
+
Linear(512 * 7 * 7, 512),
|
28 |
+
BatchNorm1d(512, affine=affine))
|
29 |
+
else:
|
30 |
+
self.output_layer = Sequential(BatchNorm2d(512),
|
31 |
+
Dropout(drop_ratio),
|
32 |
+
Flatten(),
|
33 |
+
Linear(512 * 14 * 14, 512),
|
34 |
+
BatchNorm1d(512, affine=affine))
|
35 |
+
|
36 |
+
modules = []
|
37 |
+
for block in blocks:
|
38 |
+
for bottleneck in block:
|
39 |
+
modules.append(unit_module(bottleneck.in_channel,
|
40 |
+
bottleneck.depth,
|
41 |
+
bottleneck.stride))
|
42 |
+
self.body = Sequential(*modules)
|
43 |
+
|
44 |
+
def forward(self, x):
|
45 |
+
x = self.input_layer(x)
|
46 |
+
x = self.body(x)
|
47 |
+
x = self.output_layer(x)
|
48 |
+
return l2_norm(x)
|
models/encoders/psp_encoders.py
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import torch
|
3 |
+
import torch.nn.functional as F
|
4 |
+
from torch import nn
|
5 |
+
from torch.nn import Conv2d, BatchNorm2d, PReLU, Sequential, Module
|
6 |
+
|
7 |
+
from models.encoders.helpers import get_blocks, bottleneck_IR, bottleneck_IR_SE
|
8 |
+
from models.stylegan2.model import EqualLinear
|
9 |
+
|
10 |
+
|
11 |
+
class GradualStyleBlock(Module):
|
12 |
+
def __init__(self, in_c, out_c, spatial):
|
13 |
+
super(GradualStyleBlock, self).__init__()
|
14 |
+
self.out_c = out_c
|
15 |
+
self.spatial = spatial
|
16 |
+
num_pools = int(np.log2(spatial))
|
17 |
+
modules = []
|
18 |
+
modules += [Conv2d(in_c, out_c, kernel_size=3, stride=2, padding=1), nn.LeakyReLU()]
|
19 |
+
for i in range(num_pools - 1):
|
20 |
+
modules += [
|
21 |
+
Conv2d(out_c, out_c, kernel_size=3, stride=2, padding=1), nn.LeakyReLU()
|
22 |
+
]
|
23 |
+
self.convs = nn.Sequential(*modules)
|
24 |
+
self.linear = EqualLinear(out_c, out_c, lr_mul=1)
|
25 |
+
|
26 |
+
def forward(self, x):
|
27 |
+
x = self.convs(x)
|
28 |
+
x = x.view(-1, self.out_c)
|
29 |
+
x = self.linear(x)
|
30 |
+
return x
|
31 |
+
|
32 |
+
|
33 |
+
class GradualStyleEncoder(Module):
|
34 |
+
def __init__(self, num_layers, mode='ir', n_styles=18, opts=None):
|
35 |
+
super(GradualStyleEncoder, self).__init__()
|
36 |
+
assert num_layers in [50, 100, 152], 'num_layers should be 50,100, or 152'
|
37 |
+
assert mode in ['ir', 'ir_se'], 'mode should be ir or ir_se'
|
38 |
+
blocks = get_blocks(num_layers)
|
39 |
+
if mode == 'ir':
|
40 |
+
unit_module = bottleneck_IR
|
41 |
+
elif mode == 'ir_se':
|
42 |
+
unit_module = bottleneck_IR_SE
|
43 |
+
self.input_layer = Sequential(Conv2d(opts.input_nc, 64, (3, 3), 1, 1, bias=False),
|
44 |
+
BatchNorm2d(64),
|
45 |
+
PReLU(64))
|
46 |
+
modules = []
|
47 |
+
for block in blocks:
|
48 |
+
for bottleneck in block:
|
49 |
+
modules.append(unit_module(bottleneck.in_channel,
|
50 |
+
bottleneck.depth,
|
51 |
+
bottleneck.stride))
|
52 |
+
self.body = Sequential(*modules)
|
53 |
+
|
54 |
+
self.styles = nn.ModuleList()
|
55 |
+
self.style_count = n_styles
|
56 |
+
self.coarse_ind = 3
|
57 |
+
self.middle_ind = 7
|
58 |
+
for i in range(self.style_count):
|
59 |
+
if i < self.coarse_ind:
|
60 |
+
style = GradualStyleBlock(512, 512, 16)
|
61 |
+
elif i < self.middle_ind:
|
62 |
+
style = GradualStyleBlock(512, 512, 32)
|
63 |
+
else:
|
64 |
+
style = GradualStyleBlock(512, 512, 64)
|
65 |
+
self.styles.append(style)
|
66 |
+
self.latlayer1 = nn.Conv2d(256, 512, kernel_size=1, stride=1, padding=0)
|
67 |
+
self.latlayer2 = nn.Conv2d(128, 512, kernel_size=1, stride=1, padding=0)
|
68 |
+
|
69 |
+
def _upsample_add(self, x, y):
|
70 |
+
'''Upsample and add two feature maps.
|
71 |
+
Args:
|
72 |
+
x: (Variable) top feature map to be upsampled.
|
73 |
+
y: (Variable) lateral feature map.
|
74 |
+
Returns:
|
75 |
+
(Variable) added feature map.
|
76 |
+
Note in PyTorch, when input size is odd, the upsampled feature map
|
77 |
+
with `F.upsample(..., scale_factor=2, mode='nearest')`
|
78 |
+
maybe not equal to the lateral feature map size.
|
79 |
+
e.g.
|
80 |
+
original input size: [N,_,15,15] ->
|
81 |
+
conv2d feature map size: [N,_,8,8] ->
|
82 |
+
upsampled feature map size: [N,_,16,16]
|
83 |
+
So we choose bilinear upsample which supports arbitrary output sizes.
|
84 |
+
'''
|
85 |
+
_, _, H, W = y.size()
|
86 |
+
return F.interpolate(x, size=(H, W), mode='bilinear', align_corners=True) + y
|
87 |
+
|
88 |
+
def forward(self, x):
|
89 |
+
x = self.input_layer(x)
|
90 |
+
|
91 |
+
latents = []
|
92 |
+
modulelist = list(self.body._modules.values())
|
93 |
+
for i, l in enumerate(modulelist):
|
94 |
+
x = l(x)
|
95 |
+
if i == 6:
|
96 |
+
c1 = x
|
97 |
+
elif i == 20:
|
98 |
+
c2 = x
|
99 |
+
elif i == 23:
|
100 |
+
c3 = x
|
101 |
+
|
102 |
+
for j in range(self.coarse_ind):
|
103 |
+
latents.append(self.styles[j](c3))
|
104 |
+
|
105 |
+
p2 = self._upsample_add(c3, self.latlayer1(c2))
|
106 |
+
for j in range(self.coarse_ind, self.middle_ind):
|
107 |
+
latents.append(self.styles[j](p2))
|
108 |
+
|
109 |
+
p1 = self._upsample_add(p2, self.latlayer2(c1))
|
110 |
+
for j in range(self.middle_ind, self.style_count):
|
111 |
+
latents.append(self.styles[j](p1))
|
112 |
+
|
113 |
+
out = torch.stack(latents, dim=1)
|
114 |
+
return out
|
models/psp.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
This file defines the core research contribution
|
3 |
+
"""
|
4 |
+
import copy
|
5 |
+
from argparse import Namespace
|
6 |
+
|
7 |
+
import torch
|
8 |
+
from torch import nn
|
9 |
+
import math
|
10 |
+
|
11 |
+
from configs.paths_config import model_paths
|
12 |
+
from models.encoders import psp_encoders
|
13 |
+
from models.stylegan2.model import Generator
|
14 |
+
|
15 |
+
|
16 |
+
class pSp(nn.Module):
|
17 |
+
|
18 |
+
def __init__(self, opts):
|
19 |
+
super(pSp, self).__init__()
|
20 |
+
self.set_opts(opts)
|
21 |
+
self.n_styles = int(math.log(self.opts.output_size, 2)) * 2 - 2
|
22 |
+
# Define architecture
|
23 |
+
self.encoder = self.set_encoder()
|
24 |
+
self.decoder = Generator(self.opts.output_size, 512, 8)
|
25 |
+
self.face_pool = torch.nn.AdaptiveAvgPool2d((256, 256))
|
26 |
+
# Load weights if needed
|
27 |
+
self.load_weights()
|
28 |
+
|
29 |
+
def set_encoder(self):
|
30 |
+
return psp_encoders.GradualStyleEncoder(50, 'ir_se', self.n_styles, self.opts)
|
31 |
+
|
32 |
+
def load_weights(self):
|
33 |
+
if self.opts.checkpoint_path is not None:
|
34 |
+
print(f'Loading SAM from checkpoint: {self.opts.checkpoint_path}')
|
35 |
+
ckpt = torch.load(self.opts.checkpoint_path, map_location='cpu')
|
36 |
+
self.encoder.load_state_dict(self.__get_keys(ckpt, 'encoder'), strict=False)
|
37 |
+
self.decoder.load_state_dict(self.__get_keys(ckpt, 'decoder'), strict=True)
|
38 |
+
if self.opts.start_from_encoded_w_plus:
|
39 |
+
self.pretrained_encoder = self.__get_pretrained_psp_encoder()
|
40 |
+
self.pretrained_encoder.load_state_dict(self.__get_keys(ckpt, 'pretrained_encoder'), strict=True)
|
41 |
+
self.__load_latent_avg(ckpt)
|
42 |
+
else:
|
43 |
+
print('Loading encoders weights from irse50!')
|
44 |
+
encoder_ckpt = torch.load(model_paths['ir_se50'])
|
45 |
+
# Transfer the RGB input of the irse50 network to the first 3 input channels of SAM's encoder
|
46 |
+
if self.opts.input_nc != 3:
|
47 |
+
shape = encoder_ckpt['input_layer.0.weight'].shape
|
48 |
+
altered_input_layer = torch.randn(shape[0], self.opts.input_nc, shape[2], shape[3], dtype=torch.float32)
|
49 |
+
altered_input_layer[:, :3, :, :] = encoder_ckpt['input_layer.0.weight']
|
50 |
+
encoder_ckpt['input_layer.0.weight'] = altered_input_layer
|
51 |
+
self.encoder.load_state_dict(encoder_ckpt, strict=False)
|
52 |
+
print(f'Loading decoder weights from pretrained path: {self.opts.stylegan_weights}')
|
53 |
+
ckpt = torch.load(self.opts.stylegan_weights)
|
54 |
+
self.decoder.load_state_dict(ckpt['g_ema'], strict=True)
|
55 |
+
self.__load_latent_avg(ckpt, repeat=self.n_styles)
|
56 |
+
if self.opts.start_from_encoded_w_plus:
|
57 |
+
self.pretrained_encoder = self.__load_pretrained_psp_encoder()
|
58 |
+
self.pretrained_encoder.eval()
|
59 |
+
|
60 |
+
def forward(self, x, resize=True, latent_mask=None, input_code=False, randomize_noise=True,
|
61 |
+
inject_latent=None, return_latents=False, alpha=None, input_is_full=False):
|
62 |
+
if input_code:
|
63 |
+
codes = x
|
64 |
+
else:
|
65 |
+
codes = self.encoder(x)
|
66 |
+
# normalize with respect to the center of an average face
|
67 |
+
if self.opts.start_from_latent_avg:
|
68 |
+
codes = codes + self.latent_avg
|
69 |
+
# normalize with respect to the latent of the encoded image of pretrained pSp encoder
|
70 |
+
elif self.opts.start_from_encoded_w_plus:
|
71 |
+
with torch.no_grad():
|
72 |
+
encoded_latents = self.pretrained_encoder(x[:, :-1, :, :])
|
73 |
+
encoded_latents = encoded_latents + self.latent_avg
|
74 |
+
codes = codes + encoded_latents
|
75 |
+
|
76 |
+
if latent_mask is not None:
|
77 |
+
for i in latent_mask:
|
78 |
+
if inject_latent is not None:
|
79 |
+
if alpha is not None:
|
80 |
+
codes[:, i] = alpha * inject_latent[:, i] + (1 - alpha) * codes[:, i]
|
81 |
+
else:
|
82 |
+
codes[:, i] = inject_latent[:, i]
|
83 |
+
else:
|
84 |
+
codes[:, i] = 0
|
85 |
+
|
86 |
+
input_is_latent = (not input_code) or (input_is_full)
|
87 |
+
images, result_latent = self.decoder([codes],
|
88 |
+
input_is_latent=input_is_latent,
|
89 |
+
randomize_noise=randomize_noise,
|
90 |
+
return_latents=return_latents)
|
91 |
+
|
92 |
+
if resize:
|
93 |
+
images = self.face_pool(images)
|
94 |
+
|
95 |
+
if return_latents:
|
96 |
+
return images, result_latent
|
97 |
+
else:
|
98 |
+
return images
|
99 |
+
|
100 |
+
def set_opts(self, opts):
|
101 |
+
self.opts = opts
|
102 |
+
|
103 |
+
def __load_latent_avg(self, ckpt, repeat=None):
|
104 |
+
if 'latent_avg' in ckpt:
|
105 |
+
self.latent_avg = ckpt['latent_avg'].to(self.opts.device)
|
106 |
+
if repeat is not None:
|
107 |
+
self.latent_avg = self.latent_avg.repeat(repeat, 1)
|
108 |
+
else:
|
109 |
+
self.latent_avg = None
|
110 |
+
|
111 |
+
def __get_pretrained_psp_encoder(self):
|
112 |
+
opts_encoder = vars(copy.deepcopy(self.opts))
|
113 |
+
opts_encoder['input_nc'] = 3
|
114 |
+
opts_encoder = Namespace(**opts_encoder)
|
115 |
+
encoder = psp_encoders.GradualStyleEncoder(50, 'ir_se', self.n_styles, opts_encoder)
|
116 |
+
return encoder
|
117 |
+
|
118 |
+
def __load_pretrained_psp_encoder(self):
|
119 |
+
print(f'Loading pSp encoder from checkpoint: {self.opts.pretrained_psp_path}')
|
120 |
+
ckpt = torch.load(self.opts.pretrained_psp_path, map_location='cpu')
|
121 |
+
encoder_ckpt = self.__get_keys(ckpt, name='encoder')
|
122 |
+
encoder = self.__get_pretrained_psp_encoder()
|
123 |
+
encoder.load_state_dict(encoder_ckpt, strict=False)
|
124 |
+
return encoder
|
125 |
+
|
126 |
+
@staticmethod
|
127 |
+
def __get_keys(d, name):
|
128 |
+
if 'state_dict' in d:
|
129 |
+
d = d['state_dict']
|
130 |
+
d_filt = {k[len(name) + 1:]: v for k, v in d.items() if k[:len(name)] == name}
|
131 |
+
return d_filt
|
models/stylegan2/__init__.py
ADDED
File without changes
|