echen01 commited on
Commit
2e34814
1 Parent(s): 23744e2
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. PTI/.gitignore +1 -0
  2. PTI/LICENSE +21 -0
  3. PTI/README.md +229 -0
  4. PTI/color_transfer_loss.py +60 -0
  5. PTI/configs/__init__.py +0 -0
  6. PTI/configs/evaluation_config.py +1 -0
  7. PTI/configs/global_config.py +12 -0
  8. PTI/configs/hyperparameters.py +31 -0
  9. PTI/configs/paths_config.py +41 -0
  10. PTI/criteria/__init__.py +0 -0
  11. PTI/criteria/backbones/__init__.py +25 -0
  12. PTI/criteria/backbones/iresnet.py +186 -0
  13. PTI/criteria/backbones/iresnet2060.py +176 -0
  14. PTI/criteria/backbones/mobilefacenet.py +130 -0
  15. PTI/criteria/deeplab.py +353 -0
  16. PTI/criteria/helpers.py +119 -0
  17. PTI/criteria/id_loss.py +64 -0
  18. PTI/criteria/l2_loss.py +14 -0
  19. PTI/criteria/localitly_regulizer.py +59 -0
  20. PTI/criteria/mask.py +123 -0
  21. PTI/criteria/model_irse.py +115 -0
  22. PTI/criteria/validation.py +0 -0
  23. PTI/dnnlib/__init__.py +9 -0
  24. PTI/dnnlib/util.py +477 -0
  25. PTI/models/StyleCLIP/__init__.py +0 -0
  26. PTI/models/StyleCLIP/criteria/__init__.py +0 -0
  27. PTI/models/StyleCLIP/criteria/clip_loss.py +17 -0
  28. PTI/models/StyleCLIP/criteria/id_loss.py +39 -0
  29. PTI/models/StyleCLIP/global_directions/GUI.py +103 -0
  30. PTI/models/StyleCLIP/global_directions/GenerateImg.py +50 -0
  31. PTI/models/StyleCLIP/global_directions/GetCode.py +232 -0
  32. PTI/models/StyleCLIP/global_directions/GetGUIData.py +67 -0
  33. PTI/models/StyleCLIP/global_directions/Inference.py +106 -0
  34. PTI/models/StyleCLIP/global_directions/MapTS.py +394 -0
  35. PTI/models/StyleCLIP/global_directions/PlayInteractively.py +197 -0
  36. PTI/models/StyleCLIP/global_directions/SingleChannel.py +109 -0
  37. PTI/models/StyleCLIP/global_directions/__init__.py +0 -0
  38. PTI/models/StyleCLIP/global_directions/data/ffhq/w_plus.npy +3 -0
  39. PTI/models/StyleCLIP/global_directions/dnnlib/__init__.py +9 -0
  40. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/__init__.py +20 -0
  41. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/autosummary.py +193 -0
  42. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/custom_ops.py +181 -0
  43. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/network.py +781 -0
  44. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/__init__.py +9 -0
  45. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/fused_bias_act.cu +220 -0
  46. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/fused_bias_act.py +211 -0
  47. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/upfirdn_2d.cu +359 -0
  48. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/upfirdn_2d.py +418 -0
  49. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/optimizer.py +372 -0
  50. PTI/models/StyleCLIP/global_directions/dnnlib/tflib/tfutil.py +262 -0
PTI/.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+
PTI/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Daniel Roich
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.
PTI/README.md ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PTI: Pivotal Tuning for Latent-based editing of Real Images
2
+
3
+ <!-- > Recently, a surge of advanced facial editing techniques have been proposed
4
+ that leverage the generative power of a pre-trained StyleGAN. To successfully
5
+ edit an image this way, one must first project (or invert) the image into
6
+ the pre-trained generator’s domain. As it turns out, however, StyleGAN’s
7
+ latent space induces an inherent tradeoff between distortion and editability,
8
+ i.e. between maintaining the original appearance and convincingly altering
9
+ some of its attributes. Practically, this means it is still challenging to
10
+ apply ID-preserving facial latent-space editing to faces which are out of the
11
+ generator’s domain. In this paper, we present an approach to bridge this
12
+ gap. Our technique slightly alters the generator, so that an out-of-domain
13
+ image is faithfully mapped into an in-domain latent code. The key idea is
14
+ pivotal tuning — a brief training process that preserves the editing quality
15
+ of an in-domain latent region, while changing its portrayed identity and
16
+ appearance. In Pivotal Tuning Inversion (PTI), an initial inverted latent code
17
+ serves as a pivot, around which the generator is fined-tuned. At the same
18
+ time, a regularization term keeps nearby identities intact, to locally contain
19
+ the effect. This surgical training process ends up altering appearance features
20
+ that represent mostly identity, without affecting editing capabilities.
21
+ To supplement this, we further show that pivotal tuning can also adjust the
22
+ generator to accommodate a multitude of faces, while introducing negligible
23
+ distortion on the rest of the domain. We validate our technique through
24
+ inversion and editing metrics, and show preferable scores to state-of-the-art
25
+ methods. We further qualitatively demonstrate our technique by applying
26
+ advanced edits (such as pose, age, or expression) to numerous images of
27
+ well-known and recognizable identities. Finally, we demonstrate resilience
28
+ to harder cases, including heavy make-up, elaborate hairstyles and/or headwear,
29
+ which otherwise could not have been successfully inverted and edited
30
+ by state-of-the-art methods. -->
31
+
32
+ <a href="https://arxiv.org/abs/2106.05744"><img src="https://img.shields.io/badge/arXiv-2008.00951-b31b1b.svg"></a>
33
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
34
+ Inference Notebook: <a href="https://colab.research.google.com/github/danielroich/PTI/blob/main/notebooks/inference_playground.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" height=20></a>
35
+
36
+ <p align="center">
37
+ <img src="docs/teaser.jpg"/>
38
+ <br>
39
+ Pivotal Tuning Inversion (PTI) enables employing off-the-shelf latent based
40
+ semantic editing techniques on real images using StyleGAN.
41
+ PTI excels in identity preserving edits, portrayed through recognizable figures —
42
+ Serena Williams and Robert Downey Jr. (top), and in handling faces which
43
+ are clearly out-of-domain, e.g., due to heavy makeup (bottom).
44
+ </br>
45
+ </p>
46
+
47
+ ## Description
48
+ Official Implementation of our PTI paper + code for evaluation metrics. PTI introduces an optimization mechanizem for solving the StyleGAN inversion task.
49
+ Providing near-perfect reconstruction results while maintaining the high editing abilitis of the native StyleGAN latent space W. For more details, see <a href="https://arxiv.org/abs/2106.05744"><img src="https://img.shields.io/badge/arXiv-2008.00951-b31b1b.svg"></a>
50
+
51
+ ## Recent Updates
52
+ **2021.07.01**: Fixed files download phase in the inference notebook. Which might caused the notebook not to run smoothly.
53
+
54
+ **2021.06.29**: Added support for CPU. In order to run PTI on CPU please change `device` parameter under `configs/global_config.py` to "cpu" instead of "cuda".
55
+
56
+ **2021.06.25** : Adding mohawk edit using StyleCLIP+PTI in inference notebook.
57
+ Updating documentation in inference notebook due to Google Drive rate limit reached.
58
+ Currently, Google Drive does not allow to download the pretrined models using Colab automatically. Manual intervention might be needed.
59
+
60
+ ## Getting Started
61
+ ### Prerequisites
62
+ - Linux or macOS
63
+ - NVIDIA GPU + CUDA CuDNN (Not mandatory bur recommended)
64
+ - Python 3
65
+
66
+ ### Installation
67
+ - Dependencies:
68
+ 1. lpips
69
+ 2. wandb
70
+ 3. pytorch
71
+ 4. torchvision
72
+ 5. matplotlib
73
+ 6. dlib
74
+ - All dependencies can be installed using *pip install* and the package name
75
+
76
+ ## Pretrained Models
77
+ Please download the pretrained models from the following links.
78
+
79
+ ### Auxiliary Models
80
+ We provide various auxiliary models needed for PTI inversion task.
81
+ This includes the StyleGAN generator and pre-trained models used for loss computation.
82
+ | Path | Description
83
+ | :--- | :----------
84
+ |[FFHQ StyleGAN](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/ffhq.pkl) | StyleGAN2-ada model trained on FFHQ with 1024x1024 output resolution.
85
+ |[Dlib alignment](https://drive.google.com/file/d/1HKmjg6iXsWr4aFPuU0gBXPGR83wqMzq7/view?usp=sharing) | Dlib alignment used for images preproccessing.
86
+ |[FFHQ e4e encoder](https://drive.google.com/file/d/1ALC5CLA89Ouw40TwvxcwebhzWXM5YSCm/view?usp=sharing) | Pretrained e4e encoder. Used for StyleCLIP editing.
87
+
88
+ Note: The StyleGAN model is used directly from the official [stylegan2-ada-pytorch implementation](https://github.com/NVlabs/stylegan2-ada-pytorch).
89
+ For StyleCLIP pretrained mappers, please see [StyleCLIP's official routes](https://github.com/orpatashnik/StyleCLIP/blob/main/utils.py)
90
+
91
+
92
+ By default, we assume that all auxiliary models are downloaded and saved to the directory `pretrained_models`.
93
+ However, you may use your own paths by changing the necessary values in `configs/path_configs.py`.
94
+
95
+
96
+ ## Inversion
97
+ ### Preparing your Data
98
+ In order to invert a real image and edit it you should first align and crop it to the correct size. To do so you should perform *One* of the following steps:
99
+ 1. Run `notebooks/align_data.ipynb` and change the "images_path" variable to the raw images path
100
+ 2. Run `utils/align_data.py` and change the "images_path" variable to the raw images path
101
+
102
+
103
+ ### Weights And Biases
104
+ The project supports [Weights And Biases](https://wandb.ai/home) framework for experiment tracking. For the inversion task it enables visualization of the losses progression and the generator intermediate results during the initial inversion and the *Pivotal Tuning*(PT) procedure.
105
+
106
+ The log frequency can be adjusted using the parameters defined at `configs/global_config.py` under the "Logs" subsection.
107
+
108
+ There is no no need to have an account. However, in order to use the features provided by Weights and Biases you first have to register on their site.
109
+
110
+
111
+ ### Running PTI
112
+ The main training script is `scripts/run_pti.py`. The script receives aligned and cropped images from paths configured in the "Input info" subscetion in
113
+ `configs/paths_config.py`.
114
+ Results are saved to directories found at "Dirs for output files" under `configs/paths_config.py`. This includes inversion latent codes and tuned generators.
115
+ The hyperparametrs for the inversion task can be found at `configs/hyperparameters.py`. They are intilized to the default values used in the paper.
116
+
117
+ ## Editing
118
+ By default, we assume that all auxiliary edit directions are downloaded and saved to the directory `editings`.
119
+ However, you may use your own paths by changing the necessary values in `configs/path_configs.py` under "Edit directions" subsection.
120
+
121
+ Example of editing code can be found at `scripts/latent_editor_wrapper.py`
122
+
123
+ ## Inference Notebooks
124
+ To help visualize the results of PTI we provide a Jupyter notebook found in `notebooks/inference_playground.ipynb`.
125
+ The notebook will download the pretrained models and run inference on a sample image found online or
126
+ on images of your choosing. It is recommended to run this in [Google Colab](https://colab.research.google.com/github/danielroich/PTI/blob/main/notebooks/inference_playground.ipynb).
127
+
128
+ The notebook demonstrates how to:
129
+ - Invert an image using PTI
130
+ - Visualise the inversion and use the PTI output
131
+ - Edit the image after PTI using InterfaceGAN and StyleCLIP
132
+ - Compare to other inversion methods
133
+
134
+ ## Evaluation
135
+ Currently the repository supports qualitative evaluation for reconstruction of: PTI, SG2 (*W Space*), e4e, SG2Plus (*W+ Space*).
136
+ As well as editing using InterfaceGAN and GANSpace for the same inversion methods.
137
+ To run the evaluation please see `evaluation/qualitative_edit_comparison.py`. Examples of the evaluation scripts are:
138
+
139
+ <p align="center">
140
+ <img src="docs/model_rec.jpg"/>
141
+ <br>
142
+ Reconsturction comparison between different methods. The images order is: Original image, W+ inversion, e4e inversion, W inversion, PTI inversion
143
+ </br>
144
+ </p>
145
+
146
+ <p align="center">
147
+ <img src="docs/stern_rotation.jpg"/>
148
+ <br>
149
+ InterfaceGAN pose edit comparison between different methods. The images order is: Original, W+, e4e, W, PTI
150
+ </br>
151
+ </p>
152
+
153
+ <p align="center">
154
+ <img src="docs/tyron_original.jpg" width="220" height="220"/>
155
+ <img src="docs/tyron_edit.jpg" width="220" height="220"/>
156
+ <br>
157
+ Image per edit or several edits without comparison
158
+ </br>
159
+ </p>
160
+
161
+ ### Coming Soon - Quantitative evaluation and StyleCLIP qualitative evaluation
162
+
163
+ ## Repository structure
164
+ | Path | Description <img width=200>
165
+ | :--- | :---
166
+ | &boxvr;&nbsp; configs | Folder containing configs defining Hyperparameters, paths and logging
167
+ | &boxvr;&nbsp; criteria | Folder containing various loss and regularization criterias for the optimization
168
+ | &boxvr;&nbsp; dnnlib | Folder containing internal utils for StyleGAN2-ada
169
+ | &boxvr;&nbsp; docs | Folder containing the latent space edit directions
170
+ | &boxvr;&nbsp; editings | Folder containing images displayed in the README
171
+ | &boxvr;&nbsp; environment | Folder containing Anaconda environment used in our experiments
172
+ | &boxvr;&nbsp; licenses | Folder containing licenses of the open source projects used in this repository
173
+ | &boxvr;&nbsp; models | Folder containing models used in different editing techniques and first phase inversion
174
+ | &boxvr;&nbsp; notebooks | Folder with jupyter notebooks to demonstrate the usage of PTI end-to-end
175
+ | &boxvr;&nbsp; scripts | Folder with running scripts for inversion, editing and metric computations
176
+ | &boxvr;&nbsp; torch_utils | Folder containing internal utils for StyleGAN2-ada
177
+ | &boxvr;&nbsp; training | Folder containing the core training logic of PTI
178
+ | &boxvr;&nbsp; utils | Folder with various utility functions
179
+
180
+
181
+ ## Credits
182
+ **StyleGAN2-ada model and implementation:**
183
+ https://github.com/NVlabs/stylegan2-ada-pytorch
184
+ Copyright © 2021, NVIDIA Corporation.
185
+ Nvidia Source Code License https://nvlabs.github.io/stylegan2-ada-pytorch/license.html
186
+
187
+ **LPIPS model and implementation:**
188
+ https://github.com/richzhang/PerceptualSimilarity
189
+ Copyright (c) 2020, Sou Uchida
190
+ License (BSD 2-Clause) https://github.com/richzhang/PerceptualSimilarity/blob/master/LICENSE
191
+
192
+ **e4e model and implementation:**
193
+ https://github.com/omertov/encoder4editing
194
+ Copyright (c) 2021 omertov
195
+ License (MIT) https://github.com/omertov/encoder4editing/blob/main/LICENSE
196
+
197
+ **StyleCLIP model and implementation:**
198
+ https://github.com/orpatashnik/StyleCLIP
199
+ Copyright (c) 2021 orpatashnik
200
+ License (MIT) https://github.com/orpatashnik/StyleCLIP/blob/main/LICENSE
201
+
202
+ **InterfaceGAN implementation:**
203
+ https://github.com/genforce/interfacegan
204
+ Copyright (c) 2020 genforce
205
+ License (MIT) https://github.com/genforce/interfacegan/blob/master/LICENSE
206
+
207
+ **GANSpace implementation:**
208
+ https://github.com/harskish/ganspace
209
+ Copyright (c) 2020 harkish
210
+ License (Apache License 2.0) https://github.com/harskish/ganspace/blob/master/LICENSE
211
+
212
+
213
+ ## Acknowledgments
214
+ This repository structure is based on [encoder4editing](https://github.com/omertov/encoder4editing) and [ReStyle](https://github.com/yuval-alaluf/restyle-encoder) repositories
215
+
216
+ ## Contact
217
+ For any inquiry please contact us at our email addresses: [email protected] or [email protected]
218
+
219
+
220
+ ## Citation
221
+ If you use this code for your research, please cite:
222
+ ```
223
+ @article{roich2021pivotal,
224
+ title={Pivotal Tuning for Latent-based Editing of Real Images},
225
+ author={Roich, Daniel and Mokady, Ron and Bermano, Amit H and Cohen-Or, Daniel},
226
+ journal={arXiv preprint arXiv:2106.05744},
227
+ year={2021}
228
+ }
229
+ ```
PTI/color_transfer_loss.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional
2
+
3
+ import torch
4
+ from torch import nn
5
+ from torch.nn.functional import (
6
+ smooth_l1_loss,
7
+ )
8
+
9
+
10
+ def flatten_CHW(im: torch.Tensor) -> torch.Tensor:
11
+ """
12
+ (B, C, H, W) -> (B, -1)
13
+ """
14
+ B = im.shape[0]
15
+ return im.reshape(B, -1)
16
+
17
+
18
+ def stddev(x: torch.Tensor) -> torch.Tensor:
19
+ """
20
+ x: (B, -1), assume with mean normalized
21
+ Retuens:
22
+ stddev: (B)
23
+ """
24
+ return torch.sqrt(torch.mean(x * x, dim=-1))
25
+
26
+
27
+ def gram_matrix(input_):
28
+ B, C = input_.shape[:2]
29
+ features = input_.view(B, C, -1)
30
+ N = features.shape[-1]
31
+ G = torch.bmm(features, features.transpose(1, 2)) # C x C
32
+ return G.div(C * N)
33
+
34
+
35
+ class ColorTransferLoss(nn.Module):
36
+ """Penalize the gram matrix difference between StyleGAN2's ToRGB outputs"""
37
+ def __init__(
38
+ self,
39
+ init_rgbs,
40
+ scale_rgb: bool = False
41
+ ):
42
+ super().__init__()
43
+
44
+ with torch.no_grad():
45
+ init_feats = [x.detach() for x in init_rgbs]
46
+ self.stds = [stddev(flatten_CHW(rgb)) if scale_rgb else 1 for rgb in init_feats] # (B, 1, 1, 1) or scalar
47
+ self.grams = [gram_matrix(rgb / std) for rgb, std in zip(init_feats, self.stds)]
48
+
49
+ def forward(self, rgbs: List[torch.Tensor], level: int = None):
50
+ if level is None:
51
+ level = len(self.grams)
52
+
53
+ feats = rgbs
54
+ loss = 0
55
+ for i, (rgb, std) in enumerate(zip(feats[:level], self.stds[:level])):
56
+ G = gram_matrix(rgb / std)
57
+ loss = loss + smooth_l1_loss(G, self.grams[i])
58
+
59
+ return loss
60
+
PTI/configs/__init__.py ADDED
File without changes
PTI/configs/evaluation_config.py ADDED
@@ -0,0 +1 @@
 
 
1
+ evaluated_methods = ['e4e', 'SG2', 'SG2Plus']
PTI/configs/global_config.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Device
2
+ cuda_visible_devices = "1"
3
+ device = "cuda:0"
4
+
5
+ ## Logs
6
+ training_step = 1
7
+ image_rec_result_log_snapshot = 100
8
+ pivotal_training_steps = 0
9
+ model_snapshot_interval = 400
10
+
11
+ ## Run name to be updated during PTI
12
+ run_name = ""
PTI/configs/hyperparameters.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Architechture
2
+ lpips_type = "alex"
3
+ first_inv_type = "w"
4
+ optim_type = "adam"
5
+
6
+ ## Locality regularization
7
+ latent_ball_num_of_samples = 1
8
+ locality_regularization_interval = 1
9
+ use_locality_regularization = False
10
+ regulizer_l2_lambda = 0.1
11
+ regulizer_lpips_lambda = 0.1
12
+ regulizer_alpha = 30
13
+
14
+ ## Loss
15
+ use_mask = True
16
+ pt_l2_lambda = 0.7
17
+ pt_lpips_lambda = 1
18
+ color_transfer_lambda = 0 # 1e6
19
+ id_lambda = 1
20
+
21
+ ## Steps
22
+ LPIPS_value_threshold = 0.01 # 0.06
23
+ max_pti_steps = 350
24
+ first_inv_steps = 450
25
+ max_images_to_invert = 10
26
+
27
+ ## Optimization
28
+ pti_learning_rate = 3e-4
29
+ first_inv_lr = 5e-3
30
+ train_batch_size = 1
31
+ use_last_w_pivots = True
PTI/configs/paths_config.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ year = "2010"
2
+
3
+ ## Pretrained models paths
4
+ e4e = "./pretrained_models/e4e_ffhq_encode.pt"
5
+
6
+
7
+ stylegan2_ada_ffhq = f"../pretrained_models/{year}.pkl"
8
+
9
+ style_clip_pretrained_mappers = ""
10
+ ir_se50 = "/share/phoenix/nfs04/S7/wikitime_models/model_ir_se50.pth"
11
+ dlib = "./pretrained_models/align.dat"
12
+ deeplab = "/share/phoenix/nfs04/S7/wikitime_models/deeplab_model/deeplab_model.pth"
13
+
14
+ ## Dirs for output files
15
+ checkpoints_dir = "./checkpoints"
16
+ embedding_base_dir = "./embeddings"
17
+ styleclip_output_dir = "./StyleCLIP_results"
18
+ experiments_output_dir = "./output"
19
+
20
+ ## Input info
21
+ ### Input dir, where the images reside
22
+ input_data_path = (
23
+ f"/share/phoenix/nfs04/S7/emc348/WikiFaces/datasets/new_crops/test/{year}"
24
+ )
25
+ input_data_id = f"{year}"
26
+
27
+
28
+
29
+
30
+ ## Keywords
31
+ pti_results_keyword = "PTI"
32
+ e4e_results_keyword = "e4e"
33
+ sg2_results_keyword = "SG2"
34
+ sg2_plus_results_keyword = "SG2_plus"
35
+ multi_id_model_type = "multi_id_fine"
36
+
37
+ ## Edit directions
38
+ interfacegan_age = "editings/interfacegan_directions/age.pt"
39
+ interfacegan_smile = "editings/interfacegan_directions/smile.pt"
40
+ interfacegan_rotation = "editings/interfacegan_directions/rotation.pt"
41
+ ffhq_pca = "editings/ganspace_pca/ffhq_pca.pt"
PTI/criteria/__init__.py ADDED
File without changes
PTI/criteria/backbones/__init__.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .iresnet import iresnet18, iresnet34, iresnet50, iresnet100, iresnet200
2
+ from .mobilefacenet import get_mbf
3
+
4
+
5
+ def get_model(name, **kwargs):
6
+ # resnet
7
+ if name == "r18":
8
+ return iresnet18(False, **kwargs)
9
+ elif name == "r34":
10
+ return iresnet34(False, **kwargs)
11
+ elif name == "r50":
12
+ return iresnet50(False, **kwargs)
13
+ elif name == "r100":
14
+ return iresnet100(False, **kwargs)
15
+ elif name == "r200":
16
+ return iresnet200(False, **kwargs)
17
+ elif name == "r2060":
18
+ from .iresnet2060 import iresnet2060
19
+ return iresnet2060(False, **kwargs)
20
+ elif name == "mbf":
21
+ fp16 = kwargs.get("fp16", False)
22
+ num_features = kwargs.get("num_features", 512)
23
+ return get_mbf(fp16=fp16, num_features=num_features)
24
+ else:
25
+ raise ValueError()
PTI/criteria/backbones/iresnet.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+
4
+ __all__ = ['iresnet18', 'iresnet34', 'iresnet50', 'iresnet100', 'iresnet200']
5
+
6
+
7
+ def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
8
+ """3x3 convolution with padding"""
9
+ return nn.Conv2d(in_planes,
10
+ out_planes,
11
+ kernel_size=3,
12
+ stride=stride,
13
+ padding=dilation,
14
+ groups=groups,
15
+ bias=False,
16
+ dilation=dilation)
17
+
18
+
19
+ def conv1x1(in_planes, out_planes, stride=1):
20
+ """1x1 convolution"""
21
+ return nn.Conv2d(in_planes,
22
+ out_planes,
23
+ kernel_size=1,
24
+ stride=stride,
25
+ bias=False)
26
+
27
+
28
+ class IBasicBlock(nn.Module):
29
+ expansion = 1
30
+ def __init__(self, inplanes, planes, stride=1, downsample=None,
31
+ groups=1, base_width=64, dilation=1):
32
+ super(IBasicBlock, self).__init__()
33
+ if groups != 1 or base_width != 64:
34
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
35
+ if dilation > 1:
36
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
37
+ self.bn1 = nn.BatchNorm2d(inplanes, eps=1e-05,)
38
+ self.conv1 = conv3x3(inplanes, planes)
39
+ self.bn2 = nn.BatchNorm2d(planes, eps=1e-05,)
40
+ self.prelu = nn.PReLU(planes)
41
+ self.conv2 = conv3x3(planes, planes, stride)
42
+ self.bn3 = nn.BatchNorm2d(planes, eps=1e-05,)
43
+ self.downsample = downsample
44
+ self.stride = stride
45
+
46
+ def forward(self, x):
47
+ identity = x
48
+ out = self.bn1(x)
49
+ out = self.conv1(out)
50
+ out = self.bn2(out)
51
+ out = self.prelu(out)
52
+ out = self.conv2(out)
53
+ out = self.bn3(out)
54
+ if self.downsample is not None:
55
+ identity = self.downsample(x)
56
+ out += identity
57
+ return out
58
+
59
+
60
+ class IResNet(nn.Module):
61
+ fc_scale = 7 * 7
62
+ def __init__(self,
63
+ block, layers, dropout=0, num_features=512, zero_init_residual=False,
64
+ groups=1, width_per_group=64, replace_stride_with_dilation=None, fp16=False):
65
+ super(IResNet, self).__init__()
66
+ self.fp16 = fp16
67
+ self.inplanes = 64
68
+ self.dilation = 1
69
+ if replace_stride_with_dilation is None:
70
+ replace_stride_with_dilation = [False, False, False]
71
+ if len(replace_stride_with_dilation) != 3:
72
+ raise ValueError("replace_stride_with_dilation should be None "
73
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
74
+ self.groups = groups
75
+ self.base_width = width_per_group
76
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
77
+ self.bn1 = nn.BatchNorm2d(self.inplanes, eps=1e-05)
78
+ self.prelu = nn.PReLU(self.inplanes)
79
+ self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
80
+ self.layer2 = self._make_layer(block,
81
+ 128,
82
+ layers[1],
83
+ stride=2,
84
+ dilate=replace_stride_with_dilation[0])
85
+ self.layer3 = self._make_layer(block,
86
+ 256,
87
+ layers[2],
88
+ stride=2,
89
+ dilate=replace_stride_with_dilation[1])
90
+ self.layer4 = self._make_layer(block,
91
+ 512,
92
+ layers[3],
93
+ stride=2,
94
+ dilate=replace_stride_with_dilation[2])
95
+ self.bn2 = nn.BatchNorm2d(512 * block.expansion, eps=1e-05,)
96
+ self.dropout = nn.Dropout(p=dropout, inplace=True)
97
+ self.fc = nn.Linear(512 * block.expansion * self.fc_scale, num_features)
98
+ self.features = nn.BatchNorm1d(num_features, eps=1e-05)
99
+ nn.init.constant_(self.features.weight, 1.0)
100
+ self.features.weight.requires_grad = False
101
+
102
+ for m in self.modules():
103
+ if isinstance(m, nn.Conv2d):
104
+ nn.init.normal_(m.weight, 0, 0.1)
105
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
106
+ nn.init.constant_(m.weight, 1)
107
+ nn.init.constant_(m.bias, 0)
108
+
109
+ if zero_init_residual:
110
+ for m in self.modules():
111
+ if isinstance(m, IBasicBlock):
112
+ nn.init.constant_(m.bn2.weight, 0)
113
+
114
+ def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
115
+ downsample = None
116
+ previous_dilation = self.dilation
117
+ if dilate:
118
+ self.dilation *= stride
119
+ stride = 1
120
+ if stride != 1 or self.inplanes != planes * block.expansion:
121
+ downsample = nn.Sequential(
122
+ conv1x1(self.inplanes, planes * block.expansion, stride),
123
+ nn.BatchNorm2d(planes * block.expansion, eps=1e-05, ),
124
+ )
125
+ layers = []
126
+ layers.append(
127
+ block(self.inplanes, planes, stride, downsample, self.groups,
128
+ self.base_width, previous_dilation))
129
+ self.inplanes = planes * block.expansion
130
+ for _ in range(1, blocks):
131
+ layers.append(
132
+ block(self.inplanes,
133
+ planes,
134
+ groups=self.groups,
135
+ base_width=self.base_width,
136
+ dilation=self.dilation))
137
+
138
+ return nn.Sequential(*layers)
139
+
140
+ def forward(self, x):
141
+ with torch.cuda.amp.autocast(self.fp16):
142
+ x = self.conv1(x)
143
+ x = self.bn1(x)
144
+ x = self.prelu(x)
145
+ x = self.layer1(x)
146
+ x = self.layer2(x)
147
+ x = self.layer3(x)
148
+ x = self.layer4(x)
149
+ x = self.bn2(x)
150
+ x = torch.flatten(x, 1)
151
+ x = self.dropout(x)
152
+ x = self.fc(x.float() if self.fp16 else x)
153
+ x = self.features(x)
154
+ return x
155
+
156
+
157
+ def _iresnet(arch, block, layers, pretrained, progress, **kwargs):
158
+ model = IResNet(block, layers, **kwargs)
159
+ if pretrained:
160
+ raise ValueError()
161
+ return model
162
+
163
+
164
+ def iresnet18(pretrained=False, progress=True, **kwargs):
165
+ return _iresnet('iresnet18', IBasicBlock, [2, 2, 2, 2], pretrained,
166
+ progress, **kwargs)
167
+
168
+
169
+ def iresnet34(pretrained=False, progress=True, **kwargs):
170
+ return _iresnet('iresnet34', IBasicBlock, [3, 4, 6, 3], pretrained,
171
+ progress, **kwargs)
172
+
173
+
174
+ def iresnet50(pretrained=False, progress=True, **kwargs):
175
+ return _iresnet('iresnet50', IBasicBlock, [3, 4, 14, 3], pretrained,
176
+ progress, **kwargs)
177
+
178
+
179
+ def iresnet100(pretrained=False, progress=True, **kwargs):
180
+ return _iresnet('iresnet100', IBasicBlock, [3, 13, 30, 3], pretrained,
181
+ progress, **kwargs)
182
+
183
+
184
+ def iresnet200(pretrained=False, progress=True, **kwargs):
185
+ return _iresnet('iresnet200', IBasicBlock, [6, 26, 60, 6], pretrained,
186
+ progress, **kwargs)
PTI/criteria/backbones/iresnet2060.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+
4
+ assert torch.__version__ >= "1.8.1"
5
+ from torch.utils.checkpoint import checkpoint_sequential
6
+
7
+ __all__ = ['iresnet2060']
8
+
9
+
10
+ def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
11
+ """3x3 convolution with padding"""
12
+ return nn.Conv2d(in_planes,
13
+ out_planes,
14
+ kernel_size=3,
15
+ stride=stride,
16
+ padding=dilation,
17
+ groups=groups,
18
+ bias=False,
19
+ dilation=dilation)
20
+
21
+
22
+ def conv1x1(in_planes, out_planes, stride=1):
23
+ """1x1 convolution"""
24
+ return nn.Conv2d(in_planes,
25
+ out_planes,
26
+ kernel_size=1,
27
+ stride=stride,
28
+ bias=False)
29
+
30
+
31
+ class IBasicBlock(nn.Module):
32
+ expansion = 1
33
+
34
+ def __init__(self, inplanes, planes, stride=1, downsample=None,
35
+ groups=1, base_width=64, dilation=1):
36
+ super(IBasicBlock, self).__init__()
37
+ if groups != 1 or base_width != 64:
38
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
39
+ if dilation > 1:
40
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
41
+ self.bn1 = nn.BatchNorm2d(inplanes, eps=1e-05, )
42
+ self.conv1 = conv3x3(inplanes, planes)
43
+ self.bn2 = nn.BatchNorm2d(planes, eps=1e-05, )
44
+ self.prelu = nn.PReLU(planes)
45
+ self.conv2 = conv3x3(planes, planes, stride)
46
+ self.bn3 = nn.BatchNorm2d(planes, eps=1e-05, )
47
+ self.downsample = downsample
48
+ self.stride = stride
49
+
50
+ def forward(self, x):
51
+ identity = x
52
+ out = self.bn1(x)
53
+ out = self.conv1(out)
54
+ out = self.bn2(out)
55
+ out = self.prelu(out)
56
+ out = self.conv2(out)
57
+ out = self.bn3(out)
58
+ if self.downsample is not None:
59
+ identity = self.downsample(x)
60
+ out += identity
61
+ return out
62
+
63
+
64
+ class IResNet(nn.Module):
65
+ fc_scale = 7 * 7
66
+
67
+ def __init__(self,
68
+ block, layers, dropout=0, num_features=512, zero_init_residual=False,
69
+ groups=1, width_per_group=64, replace_stride_with_dilation=None, fp16=False):
70
+ super(IResNet, self).__init__()
71
+ self.fp16 = fp16
72
+ self.inplanes = 64
73
+ self.dilation = 1
74
+ if replace_stride_with_dilation is None:
75
+ replace_stride_with_dilation = [False, False, False]
76
+ if len(replace_stride_with_dilation) != 3:
77
+ raise ValueError("replace_stride_with_dilation should be None "
78
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
79
+ self.groups = groups
80
+ self.base_width = width_per_group
81
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
82
+ self.bn1 = nn.BatchNorm2d(self.inplanes, eps=1e-05)
83
+ self.prelu = nn.PReLU(self.inplanes)
84
+ self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
85
+ self.layer2 = self._make_layer(block,
86
+ 128,
87
+ layers[1],
88
+ stride=2,
89
+ dilate=replace_stride_with_dilation[0])
90
+ self.layer3 = self._make_layer(block,
91
+ 256,
92
+ layers[2],
93
+ stride=2,
94
+ dilate=replace_stride_with_dilation[1])
95
+ self.layer4 = self._make_layer(block,
96
+ 512,
97
+ layers[3],
98
+ stride=2,
99
+ dilate=replace_stride_with_dilation[2])
100
+ self.bn2 = nn.BatchNorm2d(512 * block.expansion, eps=1e-05, )
101
+ self.dropout = nn.Dropout(p=dropout, inplace=True)
102
+ self.fc = nn.Linear(512 * block.expansion * self.fc_scale, num_features)
103
+ self.features = nn.BatchNorm1d(num_features, eps=1e-05)
104
+ nn.init.constant_(self.features.weight, 1.0)
105
+ self.features.weight.requires_grad = False
106
+
107
+ for m in self.modules():
108
+ if isinstance(m, nn.Conv2d):
109
+ nn.init.normal_(m.weight, 0, 0.1)
110
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
111
+ nn.init.constant_(m.weight, 1)
112
+ nn.init.constant_(m.bias, 0)
113
+
114
+ if zero_init_residual:
115
+ for m in self.modules():
116
+ if isinstance(m, IBasicBlock):
117
+ nn.init.constant_(m.bn2.weight, 0)
118
+
119
+ def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
120
+ downsample = None
121
+ previous_dilation = self.dilation
122
+ if dilate:
123
+ self.dilation *= stride
124
+ stride = 1
125
+ if stride != 1 or self.inplanes != planes * block.expansion:
126
+ downsample = nn.Sequential(
127
+ conv1x1(self.inplanes, planes * block.expansion, stride),
128
+ nn.BatchNorm2d(planes * block.expansion, eps=1e-05, ),
129
+ )
130
+ layers = []
131
+ layers.append(
132
+ block(self.inplanes, planes, stride, downsample, self.groups,
133
+ self.base_width, previous_dilation))
134
+ self.inplanes = planes * block.expansion
135
+ for _ in range(1, blocks):
136
+ layers.append(
137
+ block(self.inplanes,
138
+ planes,
139
+ groups=self.groups,
140
+ base_width=self.base_width,
141
+ dilation=self.dilation))
142
+
143
+ return nn.Sequential(*layers)
144
+
145
+ def checkpoint(self, func, num_seg, x):
146
+ if self.training:
147
+ return checkpoint_sequential(func, num_seg, x)
148
+ else:
149
+ return func(x)
150
+
151
+ def forward(self, x):
152
+ with torch.cuda.amp.autocast(self.fp16):
153
+ x = self.conv1(x)
154
+ x = self.bn1(x)
155
+ x = self.prelu(x)
156
+ x = self.layer1(x)
157
+ x = self.checkpoint(self.layer2, 20, x)
158
+ x = self.checkpoint(self.layer3, 100, x)
159
+ x = self.layer4(x)
160
+ x = self.bn2(x)
161
+ x = torch.flatten(x, 1)
162
+ x = self.dropout(x)
163
+ x = self.fc(x.float() if self.fp16 else x)
164
+ x = self.features(x)
165
+ return x
166
+
167
+
168
+ def _iresnet(arch, block, layers, pretrained, progress, **kwargs):
169
+ model = IResNet(block, layers, **kwargs)
170
+ if pretrained:
171
+ raise ValueError()
172
+ return model
173
+
174
+
175
+ def iresnet2060(pretrained=False, progress=True, **kwargs):
176
+ return _iresnet('iresnet2060', IBasicBlock, [3, 128, 1024 - 128, 3], pretrained, progress, **kwargs)
PTI/criteria/backbones/mobilefacenet.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Adapted from https://github.com/cavalleria/cavaface.pytorch/blob/master/backbone/mobilefacenet.py
3
+ Original author cavalleria
4
+ '''
5
+
6
+ import torch.nn as nn
7
+ from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, Sequential, Module
8
+ import torch
9
+
10
+
11
+ class Flatten(Module):
12
+ def forward(self, x):
13
+ return x.view(x.size(0), -1)
14
+
15
+
16
+ class ConvBlock(Module):
17
+ def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1):
18
+ super(ConvBlock, self).__init__()
19
+ self.layers = nn.Sequential(
20
+ Conv2d(in_c, out_c, kernel, groups=groups, stride=stride, padding=padding, bias=False),
21
+ BatchNorm2d(num_features=out_c),
22
+ PReLU(num_parameters=out_c)
23
+ )
24
+
25
+ def forward(self, x):
26
+ return self.layers(x)
27
+
28
+
29
+ class LinearBlock(Module):
30
+ def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1):
31
+ super(LinearBlock, self).__init__()
32
+ self.layers = nn.Sequential(
33
+ Conv2d(in_c, out_c, kernel, stride, padding, groups=groups, bias=False),
34
+ BatchNorm2d(num_features=out_c)
35
+ )
36
+
37
+ def forward(self, x):
38
+ return self.layers(x)
39
+
40
+
41
+ class DepthWise(Module):
42
+ def __init__(self, in_c, out_c, residual=False, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=1):
43
+ super(DepthWise, self).__init__()
44
+ self.residual = residual
45
+ self.layers = nn.Sequential(
46
+ ConvBlock(in_c, out_c=groups, kernel=(1, 1), padding=(0, 0), stride=(1, 1)),
47
+ ConvBlock(groups, groups, groups=groups, kernel=kernel, padding=padding, stride=stride),
48
+ LinearBlock(groups, out_c, kernel=(1, 1), padding=(0, 0), stride=(1, 1))
49
+ )
50
+
51
+ def forward(self, x):
52
+ short_cut = None
53
+ if self.residual:
54
+ short_cut = x
55
+ x = self.layers(x)
56
+ if self.residual:
57
+ output = short_cut + x
58
+ else:
59
+ output = x
60
+ return output
61
+
62
+
63
+ class Residual(Module):
64
+ def __init__(self, c, num_block, groups, kernel=(3, 3), stride=(1, 1), padding=(1, 1)):
65
+ super(Residual, self).__init__()
66
+ modules = []
67
+ for _ in range(num_block):
68
+ modules.append(DepthWise(c, c, True, kernel, stride, padding, groups))
69
+ self.layers = Sequential(*modules)
70
+
71
+ def forward(self, x):
72
+ return self.layers(x)
73
+
74
+
75
+ class GDC(Module):
76
+ def __init__(self, embedding_size):
77
+ super(GDC, self).__init__()
78
+ self.layers = nn.Sequential(
79
+ LinearBlock(512, 512, groups=512, kernel=(7, 7), stride=(1, 1), padding=(0, 0)),
80
+ Flatten(),
81
+ Linear(512, embedding_size, bias=False),
82
+ BatchNorm1d(embedding_size))
83
+
84
+ def forward(self, x):
85
+ return self.layers(x)
86
+
87
+
88
+ class MobileFaceNet(Module):
89
+ def __init__(self, fp16=False, num_features=512):
90
+ super(MobileFaceNet, self).__init__()
91
+ scale = 2
92
+ self.fp16 = fp16
93
+ self.layers = nn.Sequential(
94
+ ConvBlock(3, 64 * scale, kernel=(3, 3), stride=(2, 2), padding=(1, 1)),
95
+ ConvBlock(64 * scale, 64 * scale, kernel=(3, 3), stride=(1, 1), padding=(1, 1), groups=64),
96
+ DepthWise(64 * scale, 64 * scale, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=128),
97
+ Residual(64 * scale, num_block=4, groups=128, kernel=(3, 3), stride=(1, 1), padding=(1, 1)),
98
+ DepthWise(64 * scale, 128 * scale, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=256),
99
+ Residual(128 * scale, num_block=6, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)),
100
+ DepthWise(128 * scale, 128 * scale, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=512),
101
+ Residual(128 * scale, num_block=2, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)),
102
+ )
103
+ self.conv_sep = ConvBlock(128 * scale, 512, kernel=(1, 1), stride=(1, 1), padding=(0, 0))
104
+ self.features = GDC(num_features)
105
+ self._initialize_weights()
106
+
107
+ def _initialize_weights(self):
108
+ for m in self.modules():
109
+ if isinstance(m, nn.Conv2d):
110
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
111
+ if m.bias is not None:
112
+ m.bias.data.zero_()
113
+ elif isinstance(m, nn.BatchNorm2d):
114
+ m.weight.data.fill_(1)
115
+ m.bias.data.zero_()
116
+ elif isinstance(m, nn.Linear):
117
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
118
+ if m.bias is not None:
119
+ m.bias.data.zero_()
120
+
121
+ def forward(self, x):
122
+ with torch.cuda.amp.autocast(self.fp16):
123
+ x = self.layers(x)
124
+ x = self.conv_sep(x.float() if self.fp16 else x)
125
+ x = self.features(x)
126
+ return x
127
+
128
+
129
+ def get_mbf(fp16, num_features):
130
+ return MobileFaceNet(fp16, num_features)
PTI/criteria/deeplab.py ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Taken from the https://github.com/chenxi116/DeepLabv3.pytorch repository.
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import math
6
+ import torch.utils.model_zoo as model_zoo
7
+ from torch.nn import functional as F
8
+ import os
9
+
10
+
11
+ __all__ = ["ResNet", "resnet50", "resnet101", "resnet152"]
12
+
13
+
14
+ model_urls = {
15
+ "resnet50": "https://download.pytorch.org/models/resnet50-19c8e357.pth",
16
+ "resnet101": "https://download.pytorch.org/models/resnet101-5d3b4d8f.pth",
17
+ "resnet152": "https://download.pytorch.org/models/resnet152-b121ed2d.pth",
18
+ }
19
+
20
+
21
+ class Conv2d(nn.Conv2d):
22
+ def __init__(
23
+ self,
24
+ in_channels,
25
+ out_channels,
26
+ kernel_size,
27
+ stride=1,
28
+ padding=0,
29
+ dilation=1,
30
+ groups=1,
31
+ bias=True,
32
+ ):
33
+ super(Conv2d, self).__init__(
34
+ in_channels,
35
+ out_channels,
36
+ kernel_size,
37
+ stride,
38
+ padding,
39
+ dilation,
40
+ groups,
41
+ bias,
42
+ )
43
+
44
+ def forward(self, x):
45
+ # return super(Conv2d, self).forward(x)
46
+ weight = self.weight
47
+ weight_mean = (
48
+ weight.mean(dim=1, keepdim=True)
49
+ .mean(dim=2, keepdim=True)
50
+ .mean(dim=3, keepdim=True)
51
+ )
52
+ weight = weight - weight_mean
53
+ std = weight.view(weight.size(0), -1).std(dim=1).view(-1, 1, 1, 1) + 1e-5
54
+ weight = weight / std.expand_as(weight)
55
+ return F.conv2d(
56
+ x, weight, self.bias, self.stride, self.padding, self.dilation, self.groups
57
+ )
58
+
59
+
60
+ class ASPP(nn.Module):
61
+ def __init__(
62
+ self,
63
+ C,
64
+ depth,
65
+ num_classes,
66
+ conv=nn.Conv2d,
67
+ norm=nn.BatchNorm2d,
68
+ momentum=0.0003,
69
+ mult=1,
70
+ ):
71
+ super(ASPP, self).__init__()
72
+ self._C = C
73
+ self._depth = depth
74
+ self._num_classes = num_classes
75
+
76
+ self.global_pooling = nn.AdaptiveAvgPool2d(1)
77
+ self.relu = nn.ReLU(inplace=True)
78
+ self.aspp1 = conv(C, depth, kernel_size=1, stride=1, bias=False)
79
+ self.aspp2 = conv(
80
+ C,
81
+ depth,
82
+ kernel_size=3,
83
+ stride=1,
84
+ dilation=int(6 * mult),
85
+ padding=int(6 * mult),
86
+ bias=False,
87
+ )
88
+ self.aspp3 = conv(
89
+ C,
90
+ depth,
91
+ kernel_size=3,
92
+ stride=1,
93
+ dilation=int(12 * mult),
94
+ padding=int(12 * mult),
95
+ bias=False,
96
+ )
97
+ self.aspp4 = conv(
98
+ C,
99
+ depth,
100
+ kernel_size=3,
101
+ stride=1,
102
+ dilation=int(18 * mult),
103
+ padding=int(18 * mult),
104
+ bias=False,
105
+ )
106
+ self.aspp5 = conv(C, depth, kernel_size=1, stride=1, bias=False)
107
+ self.aspp1_bn = norm(depth, momentum)
108
+ self.aspp2_bn = norm(depth, momentum)
109
+ self.aspp3_bn = norm(depth, momentum)
110
+ self.aspp4_bn = norm(depth, momentum)
111
+ self.aspp5_bn = norm(depth, momentum)
112
+ self.conv2 = conv(depth * 5, depth, kernel_size=1, stride=1, bias=False)
113
+ self.bn2 = norm(depth, momentum)
114
+ self.conv3 = nn.Conv2d(depth, num_classes, kernel_size=1, stride=1)
115
+
116
+ def forward(self, x):
117
+ x1 = self.aspp1(x)
118
+ x1 = self.aspp1_bn(x1)
119
+ x1 = self.relu(x1)
120
+ x2 = self.aspp2(x)
121
+ x2 = self.aspp2_bn(x2)
122
+ x2 = self.relu(x2)
123
+ x3 = self.aspp3(x)
124
+ x3 = self.aspp3_bn(x3)
125
+ x3 = self.relu(x3)
126
+ x4 = self.aspp4(x)
127
+ x4 = self.aspp4_bn(x4)
128
+ x4 = self.relu(x4)
129
+ x5 = self.global_pooling(x)
130
+ x5 = self.aspp5(x5)
131
+ x5 = self.aspp5_bn(x5)
132
+ x5 = self.relu(x5)
133
+ x5 = nn.Upsample((x.shape[2], x.shape[3]), mode="bilinear", align_corners=True)(
134
+ x5
135
+ )
136
+ x = torch.cat((x1, x2, x3, x4, x5), 1)
137
+ x = self.conv2(x)
138
+ x = self.bn2(x)
139
+ x = self.relu(x)
140
+ x = self.conv3(x)
141
+
142
+ return x
143
+
144
+
145
+ class Bottleneck(nn.Module):
146
+ expansion = 4
147
+
148
+ def __init__(
149
+ self,
150
+ inplanes,
151
+ planes,
152
+ stride=1,
153
+ downsample=None,
154
+ dilation=1,
155
+ conv=None,
156
+ norm=None,
157
+ ):
158
+ super(Bottleneck, self).__init__()
159
+ self.conv1 = conv(inplanes, planes, kernel_size=1, bias=False)
160
+ self.bn1 = norm(planes)
161
+ self.conv2 = conv(
162
+ planes,
163
+ planes,
164
+ kernel_size=3,
165
+ stride=stride,
166
+ dilation=dilation,
167
+ padding=dilation,
168
+ bias=False,
169
+ )
170
+ self.bn2 = norm(planes)
171
+ self.conv3 = conv(planes, planes * self.expansion, kernel_size=1, bias=False)
172
+ self.bn3 = norm(planes * self.expansion)
173
+ self.relu = nn.ReLU(inplace=True)
174
+ self.downsample = downsample
175
+ self.stride = stride
176
+
177
+ def forward(self, x):
178
+ residual = x
179
+
180
+ out = self.conv1(x)
181
+ out = self.bn1(out)
182
+ out = self.relu(out)
183
+
184
+ out = self.conv2(out)
185
+ out = self.bn2(out)
186
+ out = self.relu(out)
187
+
188
+ out = self.conv3(out)
189
+ out = self.bn3(out)
190
+
191
+ if self.downsample is not None:
192
+ residual = self.downsample(x)
193
+
194
+ out += residual
195
+ out = self.relu(out)
196
+
197
+ return out
198
+
199
+
200
+ class ResNet(nn.Module):
201
+ def __init__(
202
+ self, block, layers, num_classes, num_groups=None, weight_std=False, beta=False
203
+ ):
204
+ self.inplanes = 64
205
+ self.norm = (
206
+ lambda planes, momentum=0.05: nn.BatchNorm2d(planes, momentum=momentum)
207
+ if num_groups is None
208
+ else nn.GroupNorm(num_groups, planes)
209
+ )
210
+ self.conv = Conv2d if weight_std else nn.Conv2d
211
+
212
+ super(ResNet, self).__init__()
213
+ if not beta:
214
+ self.conv1 = self.conv(
215
+ 3, 64, kernel_size=7, stride=2, padding=3, bias=False
216
+ )
217
+ else:
218
+ self.conv1 = nn.Sequential(
219
+ self.conv(3, 64, 3, stride=2, padding=1, bias=False),
220
+ self.conv(64, 64, 3, stride=1, padding=1, bias=False),
221
+ self.conv(64, 64, 3, stride=1, padding=1, bias=False),
222
+ )
223
+ self.bn1 = self.norm(64)
224
+ self.relu = nn.ReLU(inplace=True)
225
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
226
+ self.layer1 = self._make_layer(block, 64, layers[0])
227
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
228
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
229
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=2)
230
+ self.aspp = ASPP(
231
+ 512 * block.expansion, 256, num_classes, conv=self.conv, norm=self.norm
232
+ )
233
+
234
+ for m in self.modules():
235
+ if isinstance(m, self.conv):
236
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
237
+ m.weight.data.normal_(0, math.sqrt(2.0 / n))
238
+ elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.GroupNorm):
239
+ m.weight.data.fill_(1)
240
+ m.bias.data.zero_()
241
+
242
+ def _make_layer(self, block, planes, blocks, stride=1, dilation=1):
243
+ downsample = None
244
+ if stride != 1 or dilation != 1 or self.inplanes != planes * block.expansion:
245
+ downsample = nn.Sequential(
246
+ self.conv(
247
+ self.inplanes,
248
+ planes * block.expansion,
249
+ kernel_size=1,
250
+ stride=stride,
251
+ dilation=max(1, dilation / 2),
252
+ bias=False,
253
+ ),
254
+ self.norm(planes * block.expansion),
255
+ )
256
+
257
+ layers = []
258
+ layers.append(
259
+ block(
260
+ self.inplanes,
261
+ planes,
262
+ stride,
263
+ downsample,
264
+ dilation=max(1, dilation / 2),
265
+ conv=self.conv,
266
+ norm=self.norm,
267
+ )
268
+ )
269
+ self.inplanes = planes * block.expansion
270
+ for i in range(1, blocks):
271
+ layers.append(
272
+ block(
273
+ self.inplanes,
274
+ planes,
275
+ dilation=dilation,
276
+ conv=self.conv,
277
+ norm=self.norm,
278
+ )
279
+ )
280
+
281
+ return nn.Sequential(*layers)
282
+
283
+ def forward(self, x):
284
+ size = (x.shape[2], x.shape[3])
285
+ x = self.conv1(x)
286
+ x = self.bn1(x)
287
+ x = self.relu(x)
288
+ x = self.maxpool(x)
289
+
290
+ x = self.layer1(x)
291
+ x = self.layer2(x)
292
+ x = self.layer3(x)
293
+ x = self.layer4(x)
294
+
295
+ x = self.aspp(x)
296
+ x = nn.Upsample(size, mode="bilinear", align_corners=True)(x)
297
+ return x
298
+
299
+
300
+ def resnet50(pretrained=False, **kwargs):
301
+ """Constructs a ResNet-50 model.
302
+
303
+ Args:
304
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
305
+ """
306
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
307
+ if pretrained:
308
+ model.load_state_dict(model_zoo.load_url(model_urls["resnet50"]))
309
+ return model
310
+
311
+
312
+ def resnet101(path=None, pretrained=False, num_groups=None, weight_std=False, **kwargs):
313
+ """Constructs a ResNet-101 model.
314
+
315
+ Args:
316
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
317
+ """
318
+ model = ResNet(
319
+ Bottleneck,
320
+ [3, 4, 23, 3],
321
+ num_groups=num_groups,
322
+ weight_std=weight_std,
323
+ **kwargs
324
+ )
325
+ if pretrained:
326
+ model_dict = model.state_dict()
327
+ if num_groups and weight_std:
328
+ path = os.path.join(os.path.dirname(path), "R-101-GN-WS.pth.tar")
329
+ pretrained_dict = torch.load(path)
330
+ overlap_dict = {
331
+ k[7:]: v for k, v in pretrained_dict.items() if k[7:] in model_dict
332
+ }
333
+ assert len(overlap_dict) == 312
334
+ elif not num_groups and not weight_std:
335
+ pretrained_dict = model_zoo.load_url(model_urls["resnet101"])
336
+ overlap_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
337
+ else:
338
+ raise ValueError("Currently only support BN or GN+WS")
339
+ model_dict.update(overlap_dict)
340
+ model.load_state_dict(model_dict)
341
+ return model
342
+
343
+
344
+ def resnet152(pretrained=False, **kwargs):
345
+ """Constructs a ResNet-152 model.
346
+
347
+ Args:
348
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
349
+ """
350
+ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
351
+ if pretrained:
352
+ model.load_state_dict(model_zoo.load_url(model_urls["resnet152"]))
353
+ return model
PTI/criteria/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
PTI/criteria/id_loss.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ import torch.nn.functional as F
4
+ from criteria.model_irse import Backbone
5
+ from criteria.backbones import get_model
6
+
7
+
8
+ class IDLoss(nn.Module):
9
+ """
10
+ Computes a cosine similarity between people in two images.
11
+ Taken from TreB1eN's [1] implementation of InsightFace [2, 3], as used in pixel2style2pixel [4].
12
+
13
+ [1] https://github.com/TreB1eN/InsightFace_Pytorch
14
+ [2] https://github.com/deepinsight/insightface
15
+ [3] Deng, Jiankang and Guo, Jia and Niannan, Xue and Zafeiriou, Stefanos.
16
+ ArcFace: Additive Angular Margin Loss for Deep Face Recognition. In CVPR, 2019
17
+ [4] https://github.com/eladrich/pixel2style2pixel
18
+ """
19
+
20
+ def __init__(self, model_path, official=False):
21
+ """
22
+ Arguments:
23
+ model_path (str): Path to IR-SE50 model.
24
+ """
25
+ super(IDLoss, self).__init__()
26
+ print("Loading ResNet ArcFace")
27
+ self.official = official
28
+ if official:
29
+ self.facenet = get_model("r100", fp16=False)
30
+ else:
31
+ self.facenet = Backbone(
32
+ input_size=112, num_layers=50, drop_ratio=0.6, mode="ir_se"
33
+ )
34
+
35
+ self.facenet.load_state_dict(torch.load(model_path))
36
+ self.face_pool = torch.nn.AdaptiveAvgPool2d((112, 112))
37
+ self.facenet.eval()
38
+
39
+ def extract_feats(self, x):
40
+ x = x[:, :, 35:223, 32:220] # Crop interesting region
41
+ x = self.face_pool(x)
42
+ x_feats = self.facenet(x)
43
+ return x_feats
44
+
45
+ def forward(self, x, y):
46
+ """
47
+ Arguments:
48
+ x (Tensor): The batch of original images
49
+ y (Tensor): The batch of generated images
50
+
51
+ Returns:
52
+ loss (Tensor): Cosine similarity between the
53
+ features of the original and generated images.
54
+
55
+ """
56
+
57
+ x_feats = self.extract_feats(x)
58
+ y_feats = self.extract_feats(y)
59
+ if self.official:
60
+ x_feats = F.normalize(x_feats)
61
+ y_feats = F.normalize(y_feats)
62
+
63
+ loss = (1 - (x_feats * y_feats).sum(dim=1)).mean()
64
+ return loss
PTI/criteria/l2_loss.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+
4
+ l2_criterion = torch.nn.MSELoss(reduction="mean")
5
+
6
+
7
+ def l2_loss(real_images, generated_images, gray=False):
8
+ if gray:
9
+ real_images = torchvision.transforms.functional.rgb_to_grayscale(real_images)
10
+ generated_images = torchvision.transforms.functional.rgb_to_grayscale(
11
+ generated_images
12
+ )
13
+ loss = l2_criterion(real_images, generated_images)
14
+ return loss
PTI/criteria/localitly_regulizer.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ import wandb
4
+ from criteria import l2_loss
5
+ from configs import hyperparameters
6
+ from configs import global_config
7
+
8
+
9
+ class Space_Regulizer:
10
+ def __init__(self, original_G, lpips_net):
11
+ self.original_G = original_G
12
+ self.morphing_regulizer_alpha = hyperparameters.regulizer_alpha
13
+ self.lpips_loss = lpips_net
14
+
15
+ def get_morphed_w_code(self, new_w_code, fixed_w):
16
+ interpolation_direction = new_w_code - fixed_w
17
+ interpolation_direction_norm = torch.norm(interpolation_direction, p=2)
18
+ direction_to_move = hyperparameters.regulizer_alpha * interpolation_direction / interpolation_direction_norm
19
+ result_w = fixed_w + direction_to_move
20
+ self.morphing_regulizer_alpha * fixed_w + (1 - self.morphing_regulizer_alpha) * new_w_code
21
+
22
+ return result_w
23
+
24
+ def get_image_from_ws(self, w_codes, G):
25
+ return torch.cat([G.synthesis(w_code, noise_mode='none', force_fp32=True) for w_code in w_codes])
26
+
27
+ def ball_holder_loss_lazy(self, new_G, num_of_sampled_latents, w_batch, use_wandb=False):
28
+ loss = 0.0
29
+
30
+ z_samples = np.random.randn(num_of_sampled_latents, self.original_G.z_dim)
31
+ w_samples = self.original_G.mapping(torch.from_numpy(z_samples).to(global_config.device), None,
32
+ truncation_psi=0.5)
33
+ territory_indicator_ws = [self.get_morphed_w_code(w_code.unsqueeze(0), w_batch) for w_code in w_samples]
34
+
35
+ for w_code in territory_indicator_ws:
36
+ new_img = new_G.synthesis(w_code, noise_mode='none', force_fp32=True)
37
+ with torch.no_grad():
38
+ old_img = self.original_G.synthesis(w_code, noise_mode='none', force_fp32=True)
39
+
40
+ if hyperparameters.regulizer_l2_lambda > 0:
41
+ l2_loss_val = l2_loss.l2_loss(old_img, new_img)
42
+ if use_wandb:
43
+ wandb.log({f'space_regulizer_l2_loss_val': l2_loss_val.detach().cpu()},
44
+ step=global_config.training_step)
45
+ loss += l2_loss_val * hyperparameters.regulizer_l2_lambda
46
+
47
+ if hyperparameters.regulizer_lpips_lambda > 0:
48
+ loss_lpips = self.lpips_loss(old_img, new_img)
49
+ loss_lpips = torch.mean(torch.squeeze(loss_lpips))
50
+ if use_wandb:
51
+ wandb.log({f'space_regulizer_lpips_loss_val': loss_lpips.detach().cpu()},
52
+ step=global_config.training_step)
53
+ loss += loss_lpips * hyperparameters.regulizer_lpips_lambda
54
+
55
+ return loss / len(territory_indicator_ws)
56
+
57
+ def space_regulizer_loss(self, new_G, w_batch, use_wandb):
58
+ ret_val = self.ball_holder_loss_lazy(new_G, hyperparameters.latent_ball_num_of_samples, w_batch, use_wandb)
59
+ return ret_val
PTI/criteria/mask.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision.transforms as transforms
3
+ import criteria.deeplab as deeplab
4
+ import PIL.Image as Image
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ from configs import paths_config, global_config
8
+ import numpy as np
9
+
10
+
11
+ class Mask(nn.Module):
12
+ def __init__(self):
13
+ """
14
+
15
+ | Class | Number | Class | Number |
16
+ |------------|--------|-------|--------|
17
+ | background | 0 | mouth | 10 |
18
+ | skin | 1 | u_lip | 11 |
19
+ | nose | 2 | l_lip | 12 |
20
+ | eye_g | 3 | hair | 13 |
21
+ | l_eye | 4 | hat | 14 |
22
+ | r_eye | 5 | ear_r | 15 |
23
+ | l_brow | 6 | neck_l| 16 |
24
+ | r_brow | 7 | neck | 17 |
25
+ | l_ear | 8 | cloth | 18 |
26
+ | r_ear | 9 |
27
+
28
+ """
29
+ super().__init__()
30
+
31
+ self.seg_model = (
32
+ getattr(deeplab, "resnet101")(
33
+ path=paths_config.deeplab,
34
+ pretrained=True,
35
+ num_classes=19,
36
+ num_groups=32,
37
+ weight_std=True,
38
+ beta=False,
39
+ )
40
+ .eval()
41
+ .requires_grad_(False)
42
+ )
43
+
44
+ ckpt = torch.load(paths_config.deeplab, map_location=global_config.device)
45
+ state_dict = {
46
+ k[7:]: v for k, v in ckpt["state_dict"].items() if "tracked" not in k
47
+ }
48
+ self.seg_model.load_state_dict(state_dict)
49
+ self.seg_model = self.seg_model.to(global_config.device)
50
+
51
+ self.labels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17]
52
+ self.kernel = torch.ones((1, 1, 25, 25), device=global_config.device)
53
+
54
+ def get_labels(self, img):
55
+ """Returns a mask from an input image"""
56
+ data_transforms = transforms.Compose(
57
+ [
58
+ transforms.Resize((513, 513)),
59
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
60
+ ]
61
+ )
62
+ img = data_transforms(img)
63
+ with torch.no_grad():
64
+ out = self.seg_model(img)
65
+ _, label = torch.max(out, 1)
66
+ label = label.unsqueeze(0).type(torch.float32)
67
+
68
+ label = (
69
+ F.interpolate(label, size=(256, 256), mode="nearest")
70
+ .squeeze()
71
+ .type(torch.LongTensor)
72
+ )
73
+ return label
74
+
75
+ def get_mask(self, label):
76
+ mask = torch.zeros_like(label, device=global_config.device, dtype=torch.float)
77
+ for idx in self.labels:
78
+ mask[label == idx] = 1
79
+
80
+ # smooth the mask with a mean convolution
81
+ """mask = (
82
+ 1
83
+ - torch.clamp(
84
+ torch.nn.functional.conv2d(
85
+ 1 - mask[None, None, :, :], self.kernel, padding="same"
86
+ ),
87
+ 0,
88
+ 1,
89
+ ).squeeze()
90
+ )"""
91
+ """ mask = torch.clamp(
92
+ torch.nn.functional.conv2d(
93
+ mask[None, None, :, :], self.kernel, padding="same"
94
+ ),
95
+ 0,
96
+ 1,
97
+ ).squeeze()"""
98
+ mask[label == 13] = 0.1
99
+ return mask
100
+
101
+ def forward(self, real_imgs, generated_imgs):
102
+ #return real_imgs, generated_imgs
103
+ label = self.get_labels(real_imgs)
104
+ mask = self.get_mask(label)
105
+ real_imgs = real_imgs * mask
106
+ generated_imgs = generated_imgs * mask
107
+
108
+ """out = (real_imgs * mask).squeeze().detach()
109
+
110
+ out = (out.permute(1, 2, 0) * 127.5 + 127.5).clamp(0, 255).to(torch.uint8)
111
+ Image.fromarray(out.cpu().numpy()).save("real_mask.png")
112
+
113
+ out = (generated_imgs).squeeze().detach()
114
+
115
+ out = (out.permute(1, 2, 0) * 127.5 + 127.5).clamp(0, 255).to(torch.uint8)
116
+ Image.fromarray(out.cpu().numpy()).save("generated_mask.png")
117
+
118
+ mask = (mask).squeeze().detach()
119
+ mask = mask.repeat(3, 1, 1)
120
+ mask = (mask.permute(1, 2, 0) * 127.5 + 127.5).clamp(0, 255).to(torch.uint8)
121
+ Image.fromarray(mask.cpu().numpy()).save("mask.png")"""
122
+
123
+ return real_imgs, generated_imgs
PTI/criteria/model_irse.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch.nn import (
2
+ Linear,
3
+ Conv2d,
4
+ BatchNorm1d,
5
+ BatchNorm2d,
6
+ PReLU,
7
+ Dropout,
8
+ Sequential,
9
+ Module,
10
+ )
11
+ from criteria.helpers import (
12
+ get_blocks,
13
+ Flatten,
14
+ bottleneck_IR,
15
+ bottleneck_IR_SE,
16
+ l2_norm,
17
+ )
18
+
19
+ """
20
+ Modified Backbone implementation from [TreB1eN](https://github.com/TreB1eN/InsightFace_Pytorch)
21
+ """
22
+
23
+
24
+ class Backbone(Module):
25
+ def __init__(self, input_size, num_layers, mode="ir", drop_ratio=0.4, affine=True):
26
+ super(Backbone, self).__init__()
27
+ assert input_size in [112, 224], "input_size should be 112 or 224"
28
+ assert num_layers in [50, 100, 152], "num_layers should be 50, 100 or 152"
29
+ assert mode in ["ir", "ir_se"], "mode should be ir or ir_se"
30
+ blocks = get_blocks(num_layers)
31
+ if mode == "ir":
32
+ unit_module = bottleneck_IR
33
+ elif mode == "ir_se":
34
+ unit_module = bottleneck_IR_SE
35
+ self.input_layer = Sequential(
36
+ Conv2d(3, 64, (3, 3), 1, 1, bias=False), BatchNorm2d(64), PReLU(64)
37
+ )
38
+ if input_size == 112:
39
+ self.output_layer = Sequential(
40
+ BatchNorm2d(512),
41
+ Dropout(drop_ratio),
42
+ Flatten(),
43
+ Linear(512 * 7 * 7, 512),
44
+ BatchNorm1d(512, affine=affine),
45
+ )
46
+ else:
47
+ self.output_layer = Sequential(
48
+ BatchNorm2d(512),
49
+ Dropout(drop_ratio),
50
+ Flatten(),
51
+ Linear(512 * 14 * 14, 512),
52
+ BatchNorm1d(512, affine=affine),
53
+ )
54
+
55
+ modules = []
56
+ for block in blocks:
57
+ for bottleneck in block:
58
+ modules.append(
59
+ unit_module(
60
+ bottleneck.in_channel, bottleneck.depth, bottleneck.stride
61
+ )
62
+ )
63
+ self.body = Sequential(*modules)
64
+
65
+ def forward(self, x):
66
+ x = self.input_layer(x)
67
+ x = self.body(x)
68
+ x = self.output_layer(x)
69
+ return l2_norm(x)
70
+
71
+
72
+ def IR_50(input_size):
73
+ """Constructs a ir-50 model."""
74
+ model = Backbone(input_size, num_layers=50, mode="ir", drop_ratio=0.4, affine=False)
75
+ return model
76
+
77
+
78
+ def IR_101(input_size):
79
+ """Constructs a ir-101 model."""
80
+ model = Backbone(
81
+ input_size, num_layers=100, mode="ir", drop_ratio=0.4, affine=False
82
+ )
83
+ return model
84
+
85
+
86
+ def IR_152(input_size):
87
+ """Constructs a ir-152 model."""
88
+ model = Backbone(
89
+ input_size, num_layers=152, mode="ir", drop_ratio=0.4, affine=False
90
+ )
91
+ return model
92
+
93
+
94
+ def IR_SE_50(input_size):
95
+ """Constructs a ir_se-50 model."""
96
+ model = Backbone(
97
+ input_size, num_layers=50, mode="ir_se", drop_ratio=0.4, affine=False
98
+ )
99
+ return model
100
+
101
+
102
+ def IR_SE_101(input_size):
103
+ """Constructs a ir_se-101 model."""
104
+ model = Backbone(
105
+ input_size, num_layers=100, mode="ir_se", drop_ratio=0.4, affine=False
106
+ )
107
+ return model
108
+
109
+
110
+ def IR_SE_152(input_size):
111
+ """Constructs a ir_se-152 model."""
112
+ model = Backbone(
113
+ input_size, num_layers=152, mode="ir_se", drop_ratio=0.4, affine=False
114
+ )
115
+ return model
PTI/criteria/validation.py ADDED
File without changes
PTI/dnnlib/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ from .util import EasyDict, make_cache_dir_path
PTI/dnnlib/util.py ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Miscellaneous utility classes and functions."""
10
+
11
+ import ctypes
12
+ import fnmatch
13
+ import importlib
14
+ import inspect
15
+ import numpy as np
16
+ import os
17
+ import shutil
18
+ import sys
19
+ import types
20
+ import io
21
+ import pickle
22
+ import re
23
+ import requests
24
+ import html
25
+ import hashlib
26
+ import glob
27
+ import tempfile
28
+ import urllib
29
+ import urllib.request
30
+ import uuid
31
+
32
+ from distutils.util import strtobool
33
+ from typing import Any, List, Tuple, Union
34
+
35
+
36
+ # Util classes
37
+ # ------------------------------------------------------------------------------------------
38
+
39
+
40
+ class EasyDict(dict):
41
+ """Convenience class that behaves like a dict but allows access with the attribute syntax."""
42
+
43
+ def __getattr__(self, name: str) -> Any:
44
+ try:
45
+ return self[name]
46
+ except KeyError:
47
+ raise AttributeError(name)
48
+
49
+ def __setattr__(self, name: str, value: Any) -> None:
50
+ self[name] = value
51
+
52
+ def __delattr__(self, name: str) -> None:
53
+ del self[name]
54
+
55
+
56
+ class Logger(object):
57
+ """Redirect stderr to stdout, optionally print stdout to a file, and optionally force flushing on both stdout and the file."""
58
+
59
+ def __init__(self, file_name: str = None, file_mode: str = "w", should_flush: bool = True):
60
+ self.file = None
61
+
62
+ if file_name is not None:
63
+ self.file = open(file_name, file_mode)
64
+
65
+ self.should_flush = should_flush
66
+ self.stdout = sys.stdout
67
+ self.stderr = sys.stderr
68
+
69
+ sys.stdout = self
70
+ sys.stderr = self
71
+
72
+ def __enter__(self) -> "Logger":
73
+ return self
74
+
75
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
76
+ self.close()
77
+
78
+ def write(self, text: Union[str, bytes]) -> None:
79
+ """Write text to stdout (and a file) and optionally flush."""
80
+ if isinstance(text, bytes):
81
+ text = text.decode()
82
+ if len(text) == 0: # workaround for a bug in VSCode debugger: sys.stdout.write(''); sys.stdout.flush() => crash
83
+ return
84
+
85
+ if self.file is not None:
86
+ self.file.write(text)
87
+
88
+ self.stdout.write(text)
89
+
90
+ if self.should_flush:
91
+ self.flush()
92
+
93
+ def flush(self) -> None:
94
+ """Flush written text to both stdout and a file, if open."""
95
+ if self.file is not None:
96
+ self.file.flush()
97
+
98
+ self.stdout.flush()
99
+
100
+ def close(self) -> None:
101
+ """Flush, close possible files, and remove stdout/stderr mirroring."""
102
+ self.flush()
103
+
104
+ # if using multiple loggers, prevent closing in wrong order
105
+ if sys.stdout is self:
106
+ sys.stdout = self.stdout
107
+ if sys.stderr is self:
108
+ sys.stderr = self.stderr
109
+
110
+ if self.file is not None:
111
+ self.file.close()
112
+ self.file = None
113
+
114
+
115
+ # Cache directories
116
+ # ------------------------------------------------------------------------------------------
117
+
118
+ _dnnlib_cache_dir = None
119
+
120
+ def set_cache_dir(path: str) -> None:
121
+ global _dnnlib_cache_dir
122
+ _dnnlib_cache_dir = path
123
+
124
+ def make_cache_dir_path(*paths: str) -> str:
125
+ if _dnnlib_cache_dir is not None:
126
+ return os.path.join(_dnnlib_cache_dir, *paths)
127
+ if 'DNNLIB_CACHE_DIR' in os.environ:
128
+ return os.path.join(os.environ['DNNLIB_CACHE_DIR'], *paths)
129
+ if 'HOME' in os.environ:
130
+ return os.path.join(os.environ['HOME'], '.cache', 'dnnlib', *paths)
131
+ if 'USERPROFILE' in os.environ:
132
+ return os.path.join(os.environ['USERPROFILE'], '.cache', 'dnnlib', *paths)
133
+ return os.path.join(tempfile.gettempdir(), '.cache', 'dnnlib', *paths)
134
+
135
+ # Small util functions
136
+ # ------------------------------------------------------------------------------------------
137
+
138
+
139
+ def format_time(seconds: Union[int, float]) -> str:
140
+ """Convert the seconds to human readable string with days, hours, minutes and seconds."""
141
+ s = int(np.rint(seconds))
142
+
143
+ if s < 60:
144
+ return "{0}s".format(s)
145
+ elif s < 60 * 60:
146
+ return "{0}m {1:02}s".format(s // 60, s % 60)
147
+ elif s < 24 * 60 * 60:
148
+ return "{0}h {1:02}m {2:02}s".format(s // (60 * 60), (s // 60) % 60, s % 60)
149
+ else:
150
+ return "{0}d {1:02}h {2:02}m".format(s // (24 * 60 * 60), (s // (60 * 60)) % 24, (s // 60) % 60)
151
+
152
+
153
+ def ask_yes_no(question: str) -> bool:
154
+ """Ask the user the question until the user inputs a valid answer."""
155
+ while True:
156
+ try:
157
+ print("{0} [y/n]".format(question))
158
+ return strtobool(input().lower())
159
+ except ValueError:
160
+ pass
161
+
162
+
163
+ def tuple_product(t: Tuple) -> Any:
164
+ """Calculate the product of the tuple elements."""
165
+ result = 1
166
+
167
+ for v in t:
168
+ result *= v
169
+
170
+ return result
171
+
172
+
173
+ _str_to_ctype = {
174
+ "uint8": ctypes.c_ubyte,
175
+ "uint16": ctypes.c_uint16,
176
+ "uint32": ctypes.c_uint32,
177
+ "uint64": ctypes.c_uint64,
178
+ "int8": ctypes.c_byte,
179
+ "int16": ctypes.c_int16,
180
+ "int32": ctypes.c_int32,
181
+ "int64": ctypes.c_int64,
182
+ "float32": ctypes.c_float,
183
+ "float64": ctypes.c_double
184
+ }
185
+
186
+
187
+ def get_dtype_and_ctype(type_obj: Any) -> Tuple[np.dtype, Any]:
188
+ """Given a type name string (or an object having a __name__ attribute), return matching Numpy and ctypes types that have the same size in bytes."""
189
+ type_str = None
190
+
191
+ if isinstance(type_obj, str):
192
+ type_str = type_obj
193
+ elif hasattr(type_obj, "__name__"):
194
+ type_str = type_obj.__name__
195
+ elif hasattr(type_obj, "name"):
196
+ type_str = type_obj.name
197
+ else:
198
+ raise RuntimeError("Cannot infer type name from input")
199
+
200
+ assert type_str in _str_to_ctype.keys()
201
+
202
+ my_dtype = np.dtype(type_str)
203
+ my_ctype = _str_to_ctype[type_str]
204
+
205
+ assert my_dtype.itemsize == ctypes.sizeof(my_ctype)
206
+
207
+ return my_dtype, my_ctype
208
+
209
+
210
+ def is_pickleable(obj: Any) -> bool:
211
+ try:
212
+ with io.BytesIO() as stream:
213
+ pickle.dump(obj, stream)
214
+ return True
215
+ except:
216
+ return False
217
+
218
+
219
+ # Functionality to import modules/objects by name, and call functions by name
220
+ # ------------------------------------------------------------------------------------------
221
+
222
+ def get_module_from_obj_name(obj_name: str) -> Tuple[types.ModuleType, str]:
223
+ """Searches for the underlying module behind the name to some python object.
224
+ Returns the module and the object name (original name with module part removed)."""
225
+
226
+ # allow convenience shorthands, substitute them by full names
227
+ obj_name = re.sub("^np.", "numpy.", obj_name)
228
+ obj_name = re.sub("^tf.", "tensorflow.", obj_name)
229
+
230
+ # list alternatives for (module_name, local_obj_name)
231
+ parts = obj_name.split(".")
232
+ name_pairs = [(".".join(parts[:i]), ".".join(parts[i:])) for i in range(len(parts), 0, -1)]
233
+
234
+ # try each alternative in turn
235
+ for module_name, local_obj_name in name_pairs:
236
+ try:
237
+ module = importlib.import_module(module_name) # may raise ImportError
238
+ get_obj_from_module(module, local_obj_name) # may raise AttributeError
239
+ return module, local_obj_name
240
+ except:
241
+ pass
242
+
243
+ # maybe some of the modules themselves contain errors?
244
+ for module_name, _local_obj_name in name_pairs:
245
+ try:
246
+ importlib.import_module(module_name) # may raise ImportError
247
+ except ImportError:
248
+ if not str(sys.exc_info()[1]).startswith("No module named '" + module_name + "'"):
249
+ raise
250
+
251
+ # maybe the requested attribute is missing?
252
+ for module_name, local_obj_name in name_pairs:
253
+ try:
254
+ module = importlib.import_module(module_name) # may raise ImportError
255
+ get_obj_from_module(module, local_obj_name) # may raise AttributeError
256
+ except ImportError:
257
+ pass
258
+
259
+ # we are out of luck, but we have no idea why
260
+ raise ImportError(obj_name)
261
+
262
+
263
+ def get_obj_from_module(module: types.ModuleType, obj_name: str) -> Any:
264
+ """Traverses the object name and returns the last (rightmost) python object."""
265
+ if obj_name == '':
266
+ return module
267
+ obj = module
268
+ for part in obj_name.split("."):
269
+ obj = getattr(obj, part)
270
+ return obj
271
+
272
+
273
+ def get_obj_by_name(name: str) -> Any:
274
+ """Finds the python object with the given name."""
275
+ module, obj_name = get_module_from_obj_name(name)
276
+ return get_obj_from_module(module, obj_name)
277
+
278
+
279
+ def call_func_by_name(*args, func_name: str = None, **kwargs) -> Any:
280
+ """Finds the python object with the given name and calls it as a function."""
281
+ assert func_name is not None
282
+ func_obj = get_obj_by_name(func_name)
283
+ assert callable(func_obj)
284
+ return func_obj(*args, **kwargs)
285
+
286
+
287
+ def construct_class_by_name(*args, class_name: str = None, **kwargs) -> Any:
288
+ """Finds the python class with the given name and constructs it with the given arguments."""
289
+ return call_func_by_name(*args, func_name=class_name, **kwargs)
290
+
291
+
292
+ def get_module_dir_by_obj_name(obj_name: str) -> str:
293
+ """Get the directory path of the module containing the given object name."""
294
+ module, _ = get_module_from_obj_name(obj_name)
295
+ return os.path.dirname(inspect.getfile(module))
296
+
297
+
298
+ def is_top_level_function(obj: Any) -> bool:
299
+ """Determine whether the given object is a top-level function, i.e., defined at module scope using 'def'."""
300
+ return callable(obj) and obj.__name__ in sys.modules[obj.__module__].__dict__
301
+
302
+
303
+ def get_top_level_function_name(obj: Any) -> str:
304
+ """Return the fully-qualified name of a top-level function."""
305
+ assert is_top_level_function(obj)
306
+ module = obj.__module__
307
+ if module == '__main__':
308
+ module = os.path.splitext(os.path.basename(sys.modules[module].__file__))[0]
309
+ return module + "." + obj.__name__
310
+
311
+
312
+ # File system helpers
313
+ # ------------------------------------------------------------------------------------------
314
+
315
+ def list_dir_recursively_with_ignore(dir_path: str, ignores: List[str] = None, add_base_to_relative: bool = False) -> List[Tuple[str, str]]:
316
+ """List all files recursively in a given directory while ignoring given file and directory names.
317
+ Returns list of tuples containing both absolute and relative paths."""
318
+ assert os.path.isdir(dir_path)
319
+ base_name = os.path.basename(os.path.normpath(dir_path))
320
+
321
+ if ignores is None:
322
+ ignores = []
323
+
324
+ result = []
325
+
326
+ for root, dirs, files in os.walk(dir_path, topdown=True):
327
+ for ignore_ in ignores:
328
+ dirs_to_remove = [d for d in dirs if fnmatch.fnmatch(d, ignore_)]
329
+
330
+ # dirs need to be edited in-place
331
+ for d in dirs_to_remove:
332
+ dirs.remove(d)
333
+
334
+ files = [f for f in files if not fnmatch.fnmatch(f, ignore_)]
335
+
336
+ absolute_paths = [os.path.join(root, f) for f in files]
337
+ relative_paths = [os.path.relpath(p, dir_path) for p in absolute_paths]
338
+
339
+ if add_base_to_relative:
340
+ relative_paths = [os.path.join(base_name, p) for p in relative_paths]
341
+
342
+ assert len(absolute_paths) == len(relative_paths)
343
+ result += zip(absolute_paths, relative_paths)
344
+
345
+ return result
346
+
347
+
348
+ def copy_files_and_create_dirs(files: List[Tuple[str, str]]) -> None:
349
+ """Takes in a list of tuples of (src, dst) paths and copies files.
350
+ Will create all necessary directories."""
351
+ for file in files:
352
+ target_dir_name = os.path.dirname(file[1])
353
+
354
+ # will create all intermediate-level directories
355
+ if not os.path.exists(target_dir_name):
356
+ os.makedirs(target_dir_name)
357
+
358
+ shutil.copyfile(file[0], file[1])
359
+
360
+
361
+ # URL helpers
362
+ # ------------------------------------------------------------------------------------------
363
+
364
+ def is_url(obj: Any, allow_file_urls: bool = False) -> bool:
365
+ """Determine whether the given object is a valid URL string."""
366
+ if not isinstance(obj, str) or not "://" in obj:
367
+ return False
368
+ if allow_file_urls and obj.startswith('file://'):
369
+ return True
370
+ try:
371
+ res = requests.compat.urlparse(obj)
372
+ if not res.scheme or not res.netloc or not "." in res.netloc:
373
+ return False
374
+ res = requests.compat.urlparse(requests.compat.urljoin(obj, "/"))
375
+ if not res.scheme or not res.netloc or not "." in res.netloc:
376
+ return False
377
+ except:
378
+ return False
379
+ return True
380
+
381
+
382
+ def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: bool = True, return_filename: bool = False, cache: bool = True) -> Any:
383
+ """Download the given URL and return a binary-mode file object to access the data."""
384
+ assert num_attempts >= 1
385
+ assert not (return_filename and (not cache))
386
+
387
+ # Doesn't look like an URL scheme so interpret it as a local filename.
388
+ if not re.match('^[a-z]+://', url):
389
+ return url if return_filename else open(url, "rb")
390
+
391
+ # Handle file URLs. This code handles unusual file:// patterns that
392
+ # arise on Windows:
393
+ #
394
+ # file:///c:/foo.txt
395
+ #
396
+ # which would translate to a local '/c:/foo.txt' filename that's
397
+ # invalid. Drop the forward slash for such pathnames.
398
+ #
399
+ # If you touch this code path, you should test it on both Linux and
400
+ # Windows.
401
+ #
402
+ # Some internet resources suggest using urllib.request.url2pathname() but
403
+ # but that converts forward slashes to backslashes and this causes
404
+ # its own set of problems.
405
+ if url.startswith('file://'):
406
+ filename = urllib.parse.urlparse(url).path
407
+ if re.match(r'^/[a-zA-Z]:', filename):
408
+ filename = filename[1:]
409
+ return filename if return_filename else open(filename, "rb")
410
+
411
+ assert is_url(url)
412
+
413
+ # Lookup from cache.
414
+ if cache_dir is None:
415
+ cache_dir = make_cache_dir_path('downloads')
416
+
417
+ url_md5 = hashlib.md5(url.encode("utf-8")).hexdigest()
418
+ if cache:
419
+ cache_files = glob.glob(os.path.join(cache_dir, url_md5 + "_*"))
420
+ if len(cache_files) == 1:
421
+ filename = cache_files[0]
422
+ return filename if return_filename else open(filename, "rb")
423
+
424
+ # Download.
425
+ url_name = None
426
+ url_data = None
427
+ with requests.Session() as session:
428
+ if verbose:
429
+ print("Downloading %s ..." % url, end="", flush=True)
430
+ for attempts_left in reversed(range(num_attempts)):
431
+ try:
432
+ with session.get(url) as res:
433
+ res.raise_for_status()
434
+ if len(res.content) == 0:
435
+ raise IOError("No data received")
436
+
437
+ if len(res.content) < 8192:
438
+ content_str = res.content.decode("utf-8")
439
+ if "download_warning" in res.headers.get("Set-Cookie", ""):
440
+ links = [html.unescape(link) for link in content_str.split('"') if "export=download" in link]
441
+ if len(links) == 1:
442
+ url = requests.compat.urljoin(url, links[0])
443
+ raise IOError("Google Drive virus checker nag")
444
+ if "Google Drive - Quota exceeded" in content_str:
445
+ raise IOError("Google Drive download quota exceeded -- please try again later")
446
+
447
+ match = re.search(r'filename="([^"]*)"', res.headers.get("Content-Disposition", ""))
448
+ url_name = match[1] if match else url
449
+ url_data = res.content
450
+ if verbose:
451
+ print(" done")
452
+ break
453
+ except KeyboardInterrupt:
454
+ raise
455
+ except:
456
+ if not attempts_left:
457
+ if verbose:
458
+ print(" failed")
459
+ raise
460
+ if verbose:
461
+ print(".", end="", flush=True)
462
+
463
+ # Save to cache.
464
+ if cache:
465
+ safe_name = re.sub(r"[^0-9a-zA-Z-._]", "_", url_name)
466
+ cache_file = os.path.join(cache_dir, url_md5 + "_" + safe_name)
467
+ temp_file = os.path.join(cache_dir, "tmp_" + uuid.uuid4().hex + "_" + url_md5 + "_" + safe_name)
468
+ os.makedirs(cache_dir, exist_ok=True)
469
+ with open(temp_file, "wb") as f:
470
+ f.write(url_data)
471
+ os.replace(temp_file, cache_file) # atomic
472
+ if return_filename:
473
+ return cache_file
474
+
475
+ # Return data as file object.
476
+ assert not return_filename
477
+ return io.BytesIO(url_data)
PTI/models/StyleCLIP/__init__.py ADDED
File without changes
PTI/models/StyleCLIP/criteria/__init__.py ADDED
File without changes
PTI/models/StyleCLIP/criteria/clip_loss.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import clip
4
+
5
+
6
+ class CLIPLoss(torch.nn.Module):
7
+
8
+ def __init__(self, opts):
9
+ super(CLIPLoss, self).__init__()
10
+ self.model, self.preprocess = clip.load("ViT-B/32", device="cuda")
11
+ self.upsample = torch.nn.Upsample(scale_factor=7)
12
+ self.avg_pool = torch.nn.AvgPool2d(kernel_size=opts.stylegan_size // 32)
13
+
14
+ def forward(self, image, text):
15
+ image = self.avg_pool(self.upsample(image))
16
+ similarity = 1 - self.model(image, text)[0] / 100
17
+ return similarity
PTI/models/StyleCLIP/criteria/id_loss.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+
4
+ from models.facial_recognition.model_irse import Backbone
5
+
6
+
7
+ class IDLoss(nn.Module):
8
+ def __init__(self, opts):
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(opts.ir_se50_weights))
13
+ self.pool = torch.nn.AdaptiveAvgPool2d((256, 256))
14
+ self.face_pool = torch.nn.AdaptiveAvgPool2d((112, 112))
15
+ self.facenet.eval()
16
+ self.opts = opts
17
+
18
+ def extract_feats(self, x):
19
+ if x.shape[2] != 256:
20
+ x = self.pool(x)
21
+ x = x[:, :, 35:223, 32:220] # Crop interesting region
22
+ x = self.face_pool(x)
23
+ x_feats = self.facenet(x)
24
+ return x_feats
25
+
26
+ def forward(self, y_hat, y):
27
+ n_samples = y.shape[0]
28
+ y_feats = self.extract_feats(y) # Otherwise use the feature from there
29
+ y_hat_feats = self.extract_feats(y_hat)
30
+ y_feats = y_feats.detach()
31
+ loss = 0
32
+ sim_improvement = 0
33
+ count = 0
34
+ for i in range(n_samples):
35
+ diff_target = y_hat_feats[i].dot(y_feats[i])
36
+ loss += 1 - diff_target
37
+ count += 1
38
+
39
+ return loss / count, sim_improvement / count
PTI/models/StyleCLIP/global_directions/GUI.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ from tkinter import Tk,Frame ,Label,Button,messagebox,Canvas,Text,Scale
4
+ from tkinter import HORIZONTAL
5
+
6
+ class View():
7
+ def __init__(self,master):
8
+
9
+ self.width=600
10
+ self.height=600
11
+
12
+
13
+ self.root=master
14
+ self.root.geometry("600x600")
15
+
16
+ self.left_frame=Frame(self.root,width=600)
17
+ self.left_frame.pack_propagate(0)
18
+ self.left_frame.pack(fill='both', side='left', expand='True')
19
+
20
+ self.retrieval_frame=Frame(self.root,bg='snow3')
21
+ self.retrieval_frame.pack_propagate(0)
22
+ self.retrieval_frame.pack(fill='both', side='right', expand='True')
23
+
24
+ self.bg_frame=Frame(self.left_frame,bg='snow3',height=600,width=600)
25
+ self.bg_frame.pack_propagate(0)
26
+ self.bg_frame.pack(fill='both', side='top', expand='True')
27
+
28
+ self.command_frame=Frame(self.left_frame,bg='snow3')
29
+ self.command_frame.pack_propagate(0)
30
+ self.command_frame.pack(fill='both', side='bottom', expand='True')
31
+ # self.command_frame.grid(row=1, column=0,padx=0, pady=0)
32
+
33
+ self.bg=Canvas(self.bg_frame,width=self.width,height=self.height, bg='gray')
34
+ self.bg.place(relx=0.5, rely=0.5, anchor='center')
35
+
36
+ self.mani=Canvas(self.retrieval_frame,width=1024,height=1024, bg='gray')
37
+ self.mani.grid(row=0, column=0,padx=0, pady=42)
38
+
39
+ self.SetCommand()
40
+
41
+
42
+
43
+
44
+ def run(self):
45
+ self.root.mainloop()
46
+
47
+ def helloCallBack(self):
48
+ category=self.set_category.get()
49
+ messagebox.showinfo( "Hello Python",category)
50
+
51
+ def SetCommand(self):
52
+
53
+ tmp = Label(self.command_frame, text="neutral", width=10 ,bg='snow3')
54
+ tmp.grid(row=1, column=0,padx=10, pady=10)
55
+
56
+ tmp = Label(self.command_frame, text="a photo of a", width=10 ,bg='snow3')
57
+ tmp.grid(row=1, column=1,padx=10, pady=10)
58
+
59
+ self.neutral = Text ( self.command_frame, height=2, width=30)
60
+ self.neutral.grid(row=1, column=2,padx=10, pady=10)
61
+
62
+
63
+ tmp = Label(self.command_frame, text="target", width=10 ,bg='snow3')
64
+ tmp.grid(row=2, column=0,padx=10, pady=10)
65
+
66
+ tmp = Label(self.command_frame, text="a photo of a", width=10 ,bg='snow3')
67
+ tmp.grid(row=2, column=1,padx=10, pady=10)
68
+
69
+ self.target = Text ( self.command_frame, height=2, width=30)
70
+ self.target.grid(row=2, column=2,padx=10, pady=10)
71
+
72
+ tmp = Label(self.command_frame, text="strength", width=10 ,bg='snow3')
73
+ tmp.grid(row=3, column=0,padx=10, pady=10)
74
+
75
+ self.alpha = Scale(self.command_frame, from_=-15, to=25, orient=HORIZONTAL,bg='snow3', length=250,resolution=0.01)
76
+ self.alpha.grid(row=3, column=2,padx=10, pady=10)
77
+
78
+
79
+ tmp = Label(self.command_frame, text="disentangle", width=10 ,bg='snow3')
80
+ tmp.grid(row=4, column=0,padx=10, pady=10)
81
+
82
+ self.beta = Scale(self.command_frame, from_=0.08, to=0.4, orient=HORIZONTAL,bg='snow3', length=250,resolution=0.001)
83
+ self.beta.grid(row=4, column=2,padx=10, pady=10)
84
+
85
+ self.reset = Button(self.command_frame, text='Reset')
86
+ self.reset.grid(row=5, column=1,padx=10, pady=10)
87
+
88
+
89
+ self.set_init = Button(self.command_frame, text='Accept')
90
+ self.set_init.grid(row=5, column=2,padx=10, pady=10)
91
+
92
+ #%%
93
+ if __name__ == "__main__":
94
+ master=Tk()
95
+ self=View(master)
96
+ self.run()
97
+
98
+
99
+
100
+
101
+
102
+
103
+
PTI/models/StyleCLIP/global_directions/GenerateImg.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import numpy as np
4
+ import argparse
5
+ from manipulate import Manipulator
6
+
7
+ from PIL import Image
8
+ #%%
9
+
10
+ if __name__ == "__main__":
11
+ parser = argparse.ArgumentParser(description='Process some integers.')
12
+
13
+ parser.add_argument('--dataset_name',type=str,default='ffhq',
14
+ help='name of dataset, for example, ffhq')
15
+
16
+ args = parser.parse_args()
17
+ dataset_name=args.dataset_name
18
+
19
+ if not os.path.isdir('./data/'+dataset_name):
20
+ os.system('mkdir ./data/'+dataset_name)
21
+ #%%
22
+ M=Manipulator(dataset_name=dataset_name)
23
+ np.set_printoptions(suppress=True)
24
+ print(M.dataset_name)
25
+ #%%
26
+
27
+ M.img_index=0
28
+ M.num_images=50
29
+ M.alpha=[0]
30
+ M.step=1
31
+ lindex,bname=0,0
32
+
33
+ M.manipulate_layers=[lindex]
34
+ codes,out=M.EditOneC(bname)
35
+ #%%
36
+
37
+ for i in range(len(out)):
38
+ img=out[i,0]
39
+ img=Image.fromarray(img)
40
+ img.save('./data/'+dataset_name+'/'+str(i)+'.jpg')
41
+ #%%
42
+ w=np.load('./npy/'+dataset_name+'/W.npy')
43
+
44
+ tmp=w[:M.num_images]
45
+ tmp=tmp[:,None,:]
46
+ tmp=np.tile(tmp,(1,M.Gs.components.synthesis.input_shape[1],1))
47
+
48
+ np.save('./data/'+dataset_name+'/w_plus.npy',tmp)
49
+
50
+
PTI/models/StyleCLIP/global_directions/GetCode.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ import os
5
+ import pickle
6
+ import numpy as np
7
+ from dnnlib import tflib
8
+ import tensorflow as tf
9
+
10
+ import argparse
11
+
12
+ def LoadModel(dataset_name):
13
+ # Initialize TensorFlow.
14
+ tflib.init_tf()
15
+ model_path='./model/'
16
+ model_name=dataset_name+'.pkl'
17
+
18
+ tmp=os.path.join(model_path,model_name)
19
+ with open(tmp, 'rb') as f:
20
+ _, _, Gs = pickle.load(f)
21
+ return Gs
22
+
23
+ def lerp(a,b,t):
24
+ return a + (b - a) * t
25
+
26
+ #stylegan-ada
27
+ def SelectName(layer_name,suffix):
28
+ if suffix==None:
29
+ tmp1='add:0' in layer_name
30
+ tmp2='shape=(?,' in layer_name
31
+ tmp4='G_synthesis_1' in layer_name
32
+ tmp= tmp1 and tmp2 and tmp4
33
+ else:
34
+ tmp1=('/Conv0_up'+suffix) in layer_name
35
+ tmp2=('/Conv1'+suffix) in layer_name
36
+ tmp3=('4x4/Conv'+suffix) in layer_name
37
+ tmp4='G_synthesis_1' in layer_name
38
+ tmp5=('/ToRGB'+suffix) in layer_name
39
+ tmp= (tmp1 or tmp2 or tmp3 or tmp5) and tmp4
40
+ return tmp
41
+
42
+
43
+ def GetSNames(suffix):
44
+ #get style tensor name
45
+ with tf.Session() as sess:
46
+ op = sess.graph.get_operations()
47
+ layers=[m.values() for m in op]
48
+
49
+
50
+ select_layers=[]
51
+ for layer in layers:
52
+ layer_name=str(layer)
53
+ if SelectName(layer_name,suffix):
54
+ select_layers.append(layer[0])
55
+ return select_layers
56
+
57
+ def SelectName2(layer_name):
58
+ tmp1='mod_bias' in layer_name
59
+ tmp2='mod_weight' in layer_name
60
+ tmp3='ToRGB' in layer_name
61
+
62
+ tmp= (tmp1 or tmp2) and (not tmp3)
63
+ return tmp
64
+
65
+ def GetKName(Gs):
66
+
67
+ layers=[var for name, var in Gs.components.synthesis.vars.items()]
68
+
69
+ select_layers=[]
70
+ for layer in layers:
71
+ layer_name=str(layer)
72
+ if SelectName2(layer_name):
73
+ select_layers.append(layer)
74
+ return select_layers
75
+
76
+ def GetCode(Gs,random_state,num_img,num_once,dataset_name):
77
+ rnd = np.random.RandomState(random_state) #5
78
+
79
+ truncation_psi=0.7
80
+ truncation_cutoff=8
81
+
82
+ dlatent_avg=Gs.get_var('dlatent_avg')
83
+
84
+ dlatents=np.zeros((num_img,512),dtype='float32')
85
+ for i in range(int(num_img/num_once)):
86
+ src_latents = rnd.randn(num_once, Gs.input_shape[1])
87
+ src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]
88
+
89
+ # Apply truncation trick.
90
+ if truncation_psi is not None and truncation_cutoff is not None:
91
+ layer_idx = np.arange(src_dlatents.shape[1])[np.newaxis, :, np.newaxis]
92
+ ones = np.ones(layer_idx.shape, dtype=np.float32)
93
+ coefs = np.where(layer_idx < truncation_cutoff, truncation_psi * ones, ones)
94
+ src_dlatents_np=lerp(dlatent_avg, src_dlatents, coefs)
95
+ src_dlatents=src_dlatents_np[:,0,:].astype('float32')
96
+ dlatents[(i*num_once):((i+1)*num_once),:]=src_dlatents
97
+ print('get all z and w')
98
+
99
+ tmp='./npy/'+dataset_name+'/W'
100
+ np.save(tmp,dlatents)
101
+
102
+
103
+ def GetImg(Gs,num_img,num_once,dataset_name,save_name='images'):
104
+ print('Generate Image')
105
+ tmp='./npy/'+dataset_name+'/W.npy'
106
+ dlatents=np.load(tmp)
107
+ fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True)
108
+
109
+ all_images=[]
110
+ for i in range(int(num_img/num_once)):
111
+ print(i)
112
+ images=[]
113
+ for k in range(num_once):
114
+ tmp=dlatents[i*num_once+k]
115
+ tmp=tmp[None,None,:]
116
+ tmp=np.tile(tmp,(1,Gs.components.synthesis.input_shape[1],1))
117
+ image2= Gs.components.synthesis.run(tmp, randomize_noise=False, output_transform=fmt)
118
+ images.append(image2)
119
+
120
+ images=np.concatenate(images)
121
+
122
+ all_images.append(images)
123
+
124
+ all_images=np.concatenate(all_images)
125
+
126
+ tmp='./npy/'+dataset_name+'/'+save_name
127
+ np.save(tmp,all_images)
128
+
129
+ def GetS(dataset_name,num_img):
130
+ print('Generate S')
131
+ tmp='./npy/'+dataset_name+'/W.npy'
132
+ dlatents=np.load(tmp)[:num_img]
133
+
134
+ with tf.Session() as sess:
135
+ init = tf.global_variables_initializer()
136
+ sess.run(init)
137
+
138
+ Gs=LoadModel(dataset_name)
139
+ Gs.print_layers() #for ada
140
+ select_layers1=GetSNames(suffix=None) #None,'/mul_1:0','/mod_weight/read:0','/MatMul:0'
141
+ dlatents=dlatents[:,None,:]
142
+ dlatents=np.tile(dlatents,(1,Gs.components.synthesis.input_shape[1],1))
143
+
144
+ all_s = sess.run(
145
+ select_layers1,
146
+ feed_dict={'G_synthesis_1/dlatents_in:0': dlatents})
147
+
148
+ layer_names=[layer.name for layer in select_layers1]
149
+ save_tmp=[layer_names,all_s]
150
+ return save_tmp
151
+
152
+
153
+
154
+
155
+ def convert_images_to_uint8(images, drange=[-1,1], nchw_to_nhwc=False):
156
+ """Convert a minibatch of images from float32 to uint8 with configurable dynamic range.
157
+ Can be used as an output transformation for Network.run().
158
+ """
159
+ if nchw_to_nhwc:
160
+ images = np.transpose(images, [0, 2, 3, 1])
161
+
162
+ scale = 255 / (drange[1] - drange[0])
163
+ images = images * scale + (0.5 - drange[0] * scale)
164
+
165
+ np.clip(images, 0, 255, out=images)
166
+ images=images.astype('uint8')
167
+ return images
168
+
169
+
170
+ def GetCodeMS(dlatents):
171
+ m=[]
172
+ std=[]
173
+ for i in range(len(dlatents)):
174
+ tmp= dlatents[i]
175
+ tmp_mean=tmp.mean(axis=0)
176
+ tmp_std=tmp.std(axis=0)
177
+ m.append(tmp_mean)
178
+ std.append(tmp_std)
179
+ return m,std
180
+
181
+
182
+
183
+ #%%
184
+ if __name__ == "__main__":
185
+
186
+
187
+ parser = argparse.ArgumentParser(description='Process some integers.')
188
+
189
+ parser.add_argument('--dataset_name',type=str,default='ffhq',
190
+ help='name of dataset, for example, ffhq')
191
+ parser.add_argument('--code_type',choices=['w','s','s_mean_std'],default='w')
192
+
193
+ args = parser.parse_args()
194
+ random_state=5
195
+ num_img=100_000
196
+ num_once=1_000
197
+ dataset_name=args.dataset_name
198
+
199
+ if not os.path.isfile('./model/'+dataset_name+'.pkl'):
200
+ url='https://nvlabs-fi-cdn.nvidia.com/stylegan2/networks/'
201
+ name='stylegan2-'+dataset_name+'-config-f.pkl'
202
+ os.system('wget ' +url+name + ' -P ./model/')
203
+ os.system('mv ./model/'+name+' ./model/'+dataset_name+'.pkl')
204
+
205
+ if not os.path.isdir('./npy/'+dataset_name):
206
+ os.system('mkdir ./npy/'+dataset_name)
207
+
208
+ if args.code_type=='w':
209
+ Gs=LoadModel(dataset_name=dataset_name)
210
+ GetCode(Gs,random_state,num_img,num_once,dataset_name)
211
+ # GetImg(Gs,num_img=num_img,num_once=num_once,dataset_name=dataset_name,save_name='images_100K') #no need
212
+ elif args.code_type=='s':
213
+ save_name='S'
214
+ save_tmp=GetS(dataset_name,num_img=2_000)
215
+ tmp='./npy/'+dataset_name+'/'+save_name
216
+ with open(tmp, "wb") as fp:
217
+ pickle.dump(save_tmp, fp)
218
+
219
+ elif args.code_type=='s_mean_std':
220
+ save_tmp=GetS(dataset_name,num_img=num_img)
221
+ dlatents=save_tmp[1]
222
+ m,std=GetCodeMS(dlatents)
223
+ save_tmp=[m,std]
224
+ save_name='S_mean_std'
225
+ tmp='./npy/'+dataset_name+'/'+save_name
226
+ with open(tmp, "wb") as fp:
227
+ pickle.dump(save_tmp, fp)
228
+
229
+
230
+
231
+
232
+
PTI/models/StyleCLIP/global_directions/GetGUIData.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import numpy as np
4
+ import argparse
5
+ from manipulate import Manipulator
6
+ import torch
7
+ from PIL import Image
8
+ #%%
9
+
10
+ if __name__ == "__main__":
11
+ parser = argparse.ArgumentParser(description='Process some integers.')
12
+
13
+ parser.add_argument('--dataset_name',type=str,default='ffhq',
14
+ help='name of dataset, for example, ffhq')
15
+
16
+ parser.add_argument('--real', action='store_true')
17
+
18
+ args = parser.parse_args()
19
+ dataset_name=args.dataset_name
20
+
21
+ if not os.path.isdir('./data/'+dataset_name):
22
+ os.system('mkdir ./data/'+dataset_name)
23
+ #%%
24
+ M=Manipulator(dataset_name=dataset_name)
25
+ np.set_printoptions(suppress=True)
26
+ print(M.dataset_name)
27
+ #%%
28
+ #remove all .jpg
29
+ names=os.listdir('./data/'+dataset_name+'/')
30
+ for name in names:
31
+ if '.jpg' in name:
32
+ os.system('rm ./data/'+dataset_name+'/'+name)
33
+
34
+
35
+ #%%
36
+ if args.real:
37
+ latents=torch.load('./data/'+dataset_name+'/latents.pt')
38
+ w_plus=latents.cpu().detach().numpy()
39
+ else:
40
+ w=np.load('./npy/'+dataset_name+'/W.npy')
41
+ tmp=w[:50] #only use 50 images
42
+ tmp=tmp[:,None,:]
43
+ w_plus=np.tile(tmp,(1,M.Gs.components.synthesis.input_shape[1],1))
44
+ np.save('./data/'+dataset_name+'/w_plus.npy',w_plus)
45
+
46
+ #%%
47
+ tmp=M.W2S(w_plus)
48
+ M.dlatents=tmp
49
+
50
+ M.img_index=0
51
+ M.num_images=len(w_plus)
52
+ M.alpha=[0]
53
+ M.step=1
54
+ lindex,bname=0,0
55
+
56
+ M.manipulate_layers=[lindex]
57
+ codes,out=M.EditOneC(bname)
58
+ #%%
59
+
60
+ for i in range(len(out)):
61
+ img=out[i,0]
62
+ img=Image.fromarray(img)
63
+ img.save('./data/'+dataset_name+'/'+str(i)+'.jpg')
64
+ #%%
65
+
66
+
67
+
PTI/models/StyleCLIP/global_directions/Inference.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ from manipulate import Manipulator
4
+ import tensorflow as tf
5
+ import numpy as np
6
+ import torch
7
+ import clip
8
+ from MapTS import GetBoundary,GetDt
9
+
10
+ class StyleCLIP():
11
+
12
+ def __init__(self,dataset_name='ffhq'):
13
+ print('load clip')
14
+ device = "cuda" if torch.cuda.is_available() else "cpu"
15
+ self.model, preprocess = clip.load("ViT-B/32", device=device)
16
+ self.LoadData(dataset_name)
17
+
18
+ def LoadData(self, dataset_name):
19
+ tf.keras.backend.clear_session()
20
+ M=Manipulator(dataset_name=dataset_name)
21
+ np.set_printoptions(suppress=True)
22
+ fs3=np.load('./npy/'+dataset_name+'/fs3.npy')
23
+
24
+ self.M=M
25
+ self.fs3=fs3
26
+
27
+ w_plus=np.load('./data/'+dataset_name+'/w_plus.npy')
28
+ self.M.dlatents=M.W2S(w_plus)
29
+
30
+ if dataset_name=='ffhq':
31
+ self.c_threshold=20
32
+ else:
33
+ self.c_threshold=100
34
+ self.SetInitP()
35
+
36
+ def SetInitP(self):
37
+ self.M.alpha=[3]
38
+ self.M.num_images=1
39
+
40
+ self.target=''
41
+ self.neutral=''
42
+ self.GetDt2()
43
+ img_index=0
44
+ self.M.dlatent_tmp=[tmp[img_index:(img_index+1)] for tmp in self.M.dlatents]
45
+
46
+
47
+ def GetDt2(self):
48
+ classnames=[self.target,self.neutral]
49
+ dt=GetDt(classnames,self.model)
50
+
51
+ self.dt=dt
52
+ num_cs=[]
53
+ betas=np.arange(0.1,0.3,0.01)
54
+ for i in range(len(betas)):
55
+ boundary_tmp2,num_c=GetBoundary(self.fs3,self.dt,self.M,threshold=betas[i])
56
+ print(betas[i])
57
+ num_cs.append(num_c)
58
+
59
+ num_cs=np.array(num_cs)
60
+ select=num_cs>self.c_threshold
61
+
62
+ if sum(select)==0:
63
+ self.beta=0.1
64
+ else:
65
+ self.beta=betas[select][-1]
66
+
67
+
68
+ def GetCode(self):
69
+ boundary_tmp2,num_c=GetBoundary(self.fs3,self.dt,self.M,threshold=self.beta)
70
+ codes=self.M.MSCode(self.M.dlatent_tmp,boundary_tmp2)
71
+ return codes
72
+
73
+ def GetImg(self):
74
+
75
+ codes=self.GetCode()
76
+ out=self.M.GenerateImg(codes)
77
+ img=out[0,0]
78
+ return img
79
+
80
+
81
+
82
+
83
+ #%%
84
+ if __name__ == "__main__":
85
+ style_clip=StyleCLIP()
86
+ self=style_clip
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
PTI/models/StyleCLIP/global_directions/MapTS.py ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Feb 4 17:36:31 2021
5
+
6
+ @author: wuzongze
7
+ """
8
+
9
+ import os
10
+ #os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
11
+ #os.environ["CUDA_VISIBLE_DEVICES"] = "1" #(or "1" or "2")
12
+
13
+ import sys
14
+
15
+ #sys.path=['', '/usr/local/tensorflow/avx-avx2-gpu/1.14.0/python3.7/site-packages', '/usr/local/matlab/2018b/lib/python3.7/site-packages', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python37.zip', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python3.7', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python3.7/lib-dynload', '/usr/lib/python3.7', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python3.7/site-packages', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python3.7/site-packages/copkmeans-1.5-py3.7.egg', '/cs/labs/danix/wuzongze/pythonV/venv3.7/lib/python3.7/site-packages/spherecluster-0.1.7-py3.7.egg', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.7/dist-packages', '/usr/lib/python3/dist-packages/IPython/extensions']
16
+
17
+ import tensorflow as tf
18
+
19
+ import numpy as np
20
+ import torch
21
+ import clip
22
+ from PIL import Image
23
+ import pickle
24
+ import copy
25
+ import matplotlib.pyplot as plt
26
+
27
+ def GetAlign(out,dt,model,preprocess):
28
+ imgs=out
29
+ imgs1=imgs.reshape([-1]+list(imgs.shape[2:]))
30
+
31
+ tmp=[]
32
+ for i in range(len(imgs1)):
33
+
34
+ img=Image.fromarray(imgs1[i])
35
+ image = preprocess(img).unsqueeze(0).to(device)
36
+ tmp.append(image)
37
+
38
+ image=torch.cat(tmp)
39
+
40
+ with torch.no_grad():
41
+ image_features = model.encode_image(image)
42
+ image_features = image_features / image_features.norm(dim=-1, keepdim=True)
43
+
44
+ image_features1=image_features.cpu().numpy()
45
+
46
+ image_features1=image_features1.reshape(list(imgs.shape[:2])+[512])
47
+
48
+ fd=image_features1[:,1:,:]-image_features1[:,:-1,:]
49
+
50
+ fd1=fd.reshape([-1,512])
51
+ fd2=fd1/np.linalg.norm(fd1,axis=1)[:,None]
52
+
53
+ tmp=np.dot(fd2,dt)
54
+ m=tmp.mean()
55
+ acc=np.sum(tmp>0)/len(tmp)
56
+ print(m,acc)
57
+ return m,acc
58
+
59
+
60
+ def SplitS(ds_p,M,if_std):
61
+ all_ds=[]
62
+ start=0
63
+ for i in M.mindexs:
64
+ tmp=M.dlatents[i].shape[1]
65
+ end=start+tmp
66
+ tmp=ds_p[start:end]
67
+ # tmp=tmp*M.code_std[i]
68
+
69
+ all_ds.append(tmp)
70
+ start=end
71
+
72
+ all_ds2=[]
73
+ tmp_index=0
74
+ for i in range(len(M.s_names)):
75
+ if (not 'RGB' in M.s_names[i]) and (not len(all_ds[tmp_index])==0):
76
+
77
+ # tmp=np.abs(all_ds[tmp_index]/M.code_std[i])
78
+ # print(i,tmp.mean())
79
+ # tmp=np.dot(M.latent_codes[i],all_ds[tmp_index])
80
+ # print(tmp)
81
+ if if_std:
82
+ tmp=all_ds[tmp_index]*M.code_std[i]
83
+ else:
84
+ tmp=all_ds[tmp_index]
85
+
86
+ all_ds2.append(tmp)
87
+ tmp_index+=1
88
+ else:
89
+ tmp=np.zeros(len(M.dlatents[i][0]))
90
+ all_ds2.append(tmp)
91
+ return all_ds2
92
+
93
+
94
+ imagenet_templates = [
95
+ 'a bad photo of a {}.',
96
+ # 'a photo of many {}.',
97
+ 'a sculpture of a {}.',
98
+ 'a photo of the hard to see {}.',
99
+ 'a low resolution photo of the {}.',
100
+ 'a rendering of a {}.',
101
+ 'graffiti of a {}.',
102
+ 'a bad photo of the {}.',
103
+ 'a cropped photo of the {}.',
104
+ 'a tattoo of a {}.',
105
+ 'the embroidered {}.',
106
+ 'a photo of a hard to see {}.',
107
+ 'a bright photo of a {}.',
108
+ 'a photo of a clean {}.',
109
+ 'a photo of a dirty {}.',
110
+ 'a dark photo of the {}.',
111
+ 'a drawing of a {}.',
112
+ 'a photo of my {}.',
113
+ 'the plastic {}.',
114
+ 'a photo of the cool {}.',
115
+ 'a close-up photo of a {}.',
116
+ 'a black and white photo of the {}.',
117
+ 'a painting of the {}.',
118
+ 'a painting of a {}.',
119
+ 'a pixelated photo of the {}.',
120
+ 'a sculpture of the {}.',
121
+ 'a bright photo of the {}.',
122
+ 'a cropped photo of a {}.',
123
+ 'a plastic {}.',
124
+ 'a photo of the dirty {}.',
125
+ 'a jpeg corrupted photo of a {}.',
126
+ 'a blurry photo of the {}.',
127
+ 'a photo of the {}.',
128
+ 'a good photo of the {}.',
129
+ 'a rendering of the {}.',
130
+ 'a {} in a video game.',
131
+ 'a photo of one {}.',
132
+ 'a doodle of a {}.',
133
+ 'a close-up photo of the {}.',
134
+ 'a photo of a {}.',
135
+ 'the origami {}.',
136
+ 'the {} in a video game.',
137
+ 'a sketch of a {}.',
138
+ 'a doodle of the {}.',
139
+ 'a origami {}.',
140
+ 'a low resolution photo of a {}.',
141
+ 'the toy {}.',
142
+ 'a rendition of the {}.',
143
+ 'a photo of the clean {}.',
144
+ 'a photo of a large {}.',
145
+ 'a rendition of a {}.',
146
+ 'a photo of a nice {}.',
147
+ 'a photo of a weird {}.',
148
+ 'a blurry photo of a {}.',
149
+ 'a cartoon {}.',
150
+ 'art of a {}.',
151
+ 'a sketch of the {}.',
152
+ 'a embroidered {}.',
153
+ 'a pixelated photo of a {}.',
154
+ 'itap of the {}.',
155
+ 'a jpeg corrupted photo of the {}.',
156
+ 'a good photo of a {}.',
157
+ 'a plushie {}.',
158
+ 'a photo of the nice {}.',
159
+ 'a photo of the small {}.',
160
+ 'a photo of the weird {}.',
161
+ 'the cartoon {}.',
162
+ 'art of the {}.',
163
+ 'a drawing of the {}.',
164
+ 'a photo of the large {}.',
165
+ 'a black and white photo of a {}.',
166
+ 'the plushie {}.',
167
+ 'a dark photo of a {}.',
168
+ 'itap of a {}.',
169
+ 'graffiti of the {}.',
170
+ 'a toy {}.',
171
+ 'itap of my {}.',
172
+ 'a photo of a cool {}.',
173
+ 'a photo of a small {}.',
174
+ 'a tattoo of the {}.',
175
+ ]
176
+
177
+
178
+ def zeroshot_classifier(classnames, templates,model):
179
+ with torch.no_grad():
180
+ zeroshot_weights = []
181
+ for classname in classnames:
182
+ texts = [template.format(classname) for template in templates] #format with class
183
+ texts = clip.tokenize(texts).cuda() #tokenize
184
+ class_embeddings = model.encode_text(texts) #embed with text encoder
185
+ class_embeddings /= class_embeddings.norm(dim=-1, keepdim=True)
186
+ class_embedding = class_embeddings.mean(dim=0)
187
+ class_embedding /= class_embedding.norm()
188
+ zeroshot_weights.append(class_embedding)
189
+ zeroshot_weights = torch.stack(zeroshot_weights, dim=1).cuda()
190
+ return zeroshot_weights
191
+
192
+
193
+ def GetDt(classnames,model):
194
+ text_features=zeroshot_classifier(classnames, imagenet_templates,model).t()
195
+
196
+ dt=text_features[0]-text_features[1]
197
+ dt=dt.cpu().numpy()
198
+
199
+ # t_m1=t_m/np.linalg.norm(t_m)
200
+ # dt=text_features.cpu().numpy()[0]-t_m1
201
+ print(np.linalg.norm(dt))
202
+ dt=dt/np.linalg.norm(dt)
203
+ return dt
204
+
205
+
206
+ def GetBoundary(fs3,dt,M,threshold):
207
+ tmp=np.dot(fs3,dt)
208
+
209
+ ds_imp=copy.copy(tmp)
210
+ select=np.abs(tmp)<threshold
211
+ num_c=np.sum(~select)
212
+
213
+
214
+ ds_imp[select]=0
215
+ tmp=np.abs(ds_imp).max()
216
+ ds_imp/=tmp
217
+
218
+ boundary_tmp2=SplitS(ds_imp,M,if_std=True)
219
+ print('num of channels being manipulated:',num_c)
220
+ return boundary_tmp2,num_c
221
+
222
+ def GetFs(file_path):
223
+ fs=np.load(file_path+'single_channel.npy')
224
+ tmp=np.linalg.norm(fs,axis=-1)
225
+ fs1=fs/tmp[:,:,:,None]
226
+ fs2=fs1[:,:,1,:]-fs1[:,:,0,:] # 5*sigma - (-5)* sigma
227
+ fs3=fs2/np.linalg.norm(fs2,axis=-1)[:,:,None]
228
+ fs3=fs3.mean(axis=1)
229
+ fs3=fs3/np.linalg.norm(fs3,axis=-1)[:,None]
230
+ return fs3
231
+ #%%
232
+
233
+ if __name__ == "__main__":
234
+ device = "cuda" if torch.cuda.is_available() else "cpu"
235
+ model, preprocess = clip.load("ViT-B/32", device=device)
236
+ #%%
237
+ sys.path.append('/cs/labs/danix/wuzongze/Gan_Manipulation/play')
238
+ from example_try import Manipulator4
239
+
240
+ M=Manipulator4(dataset_name='ffhq',code_type='S')
241
+ np.set_printoptions(suppress=True)
242
+
243
+ #%%
244
+
245
+
246
+ file_path='/cs/labs/danix/wuzongze/Tansformer_Manipulation/CLIP/results/'+M.dataset_name+'/'
247
+ fs3=GetFs(file_path)
248
+
249
+
250
+
251
+ #%%
252
+ '''
253
+ text_features=zeroshot_classifier2(classnames, imagenet_templates) #.t()
254
+
255
+ tmp=np.linalg.norm(text_features,axis=2)
256
+ text_features/=tmp[:,:,None]
257
+ dt=text_features[0]-text_features[1]
258
+
259
+ tmp=np.linalg.norm(dt,axis=1)
260
+ dt/=tmp[:,None]
261
+ dt=dt.mean(axis=0)
262
+ '''
263
+
264
+ #%%
265
+ '''
266
+ all_tmp=[]
267
+ tmp=torch.load('/cs/labs/danix/wuzongze/downloads/harris_latent.pt')
268
+ tmp=tmp.cpu().detach().numpy() #[:,:14,:]
269
+ all_tmp.append(tmp)
270
+
271
+ tmp=torch.load('/cs/labs/danix/wuzongze/downloads/ariana_latent.pt')
272
+ tmp=tmp.cpu().detach().numpy() #[:,:14,:]
273
+ all_tmp.append(tmp)
274
+
275
+ tmp=torch.load('/cs/labs/danix/wuzongze/downloads/federer.pt')
276
+ tmp=tmp.cpu().detach().numpy() #[:,:14,:]
277
+ all_tmp.append(tmp)
278
+
279
+ all_tmp=np.array(all_tmp)[:,0]
280
+
281
+ dlatent_tmp=M.W2S(all_tmp)
282
+ '''
283
+ '''
284
+ tmp=torch.load('/cs/labs/danix/wuzongze/downloads/all_cars.pt')
285
+ tmp=tmp.cpu().detach().numpy()[:300]
286
+ dlatent_tmp=M.W2S(tmp)
287
+ '''
288
+ '''
289
+ tmp=torch.load('/cs/labs/danix/wuzongze/downloads/faces.pt')
290
+ tmp=tmp.cpu().detach().numpy()[:100]
291
+ dlatent_tmp=M.W2S(tmp)
292
+ '''
293
+ #%%
294
+ # M.viz_size=1024
295
+ M.img_index=0
296
+ M.num_images=30
297
+ dlatent_tmp=[tmp[M.img_index:(M.img_index+M.num_images)] for tmp in M.dlatents]
298
+ #%%
299
+
300
+ classnames=['face','face with glasses']
301
+
302
+ # classnames=['car','classic car']
303
+ # classnames=['dog','happy dog']
304
+ # classnames=['bedroom','modern bedroom']
305
+
306
+ # classnames=['church','church without watermark']
307
+ # classnames=['natural scene','natural scene without grass']
308
+ dt=GetDt(classnames,model)
309
+ # tmp=np.dot(fs3,dt)
310
+ #
311
+ # ds_imp=copy.copy(tmp)
312
+ # select=np.abs(tmp)<0.1
313
+ # num_c=np.sum(~select)
314
+ #
315
+ #
316
+ # ds_imp[select]=0
317
+ # tmp=np.abs(ds_imp).max()
318
+ # ds_imp/=tmp
319
+ #
320
+ # boundary_tmp2=SplitS(ds_imp,M,if_std=True)
321
+ # print('num of channels being manipulated:',num_c)
322
+
323
+ boundary_tmp2=GetBoundary(fs3,dt,M,threshold=0.13)
324
+
325
+ #%%
326
+ M.start_distance=-20
327
+ M.end_distance=20
328
+ M.step=7
329
+ # M.num_images=100
330
+ codes=M.MSCode(dlatent_tmp,boundary_tmp2)
331
+ out=M.GenerateImg(codes)
332
+ M.Vis2(str('tmp'),'filter2',out)
333
+
334
+ # full=GetAlign(out,dt,model,preprocess)
335
+
336
+
337
+ #%%
338
+ boundary_tmp3=copy.copy(boundary_tmp2) #primary
339
+ boundary_tmp4=copy.copy(boundary_tmp2) #condition
340
+ #%%
341
+ boundary_tmp2=copy.copy(boundary_tmp3)
342
+ for i in range(len(boundary_tmp3)):
343
+ select=boundary_tmp4[i]==0
344
+ boundary_tmp2[i][~select]=0
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+ #%%1
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+
377
+
378
+
379
+
380
+
381
+
382
+
383
+
384
+
385
+
386
+
387
+
388
+
389
+
390
+
391
+
392
+
393
+
394
+
PTI/models/StyleCLIP/global_directions/PlayInteractively.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ from tkinter import Tk
5
+ from PIL import Image, ImageTk
6
+ from tkinter.filedialog import askopenfilename
7
+ from GUI import View
8
+ from Inference import StyleCLIP
9
+ import argparse
10
+ #%%
11
+
12
+
13
+ class PlayInteractively(): #Controller
14
+ '''
15
+ followed Model View Controller Design Pattern
16
+
17
+ controller, model, view
18
+ '''
19
+ def __init__(self,dataset_name='ffhq'):
20
+
21
+ self.root = Tk()
22
+ self.view=View(self.root)
23
+ self.img_ratio=2
24
+ self.style_clip=StyleCLIP(dataset_name)
25
+
26
+ self.view.neutral.bind("<Return>", self.text_n)
27
+ self.view.target.bind("<Return>", self.text_t)
28
+ self.view.alpha.bind('<ButtonRelease-1>', self.ChangeAlpha)
29
+ self.view.beta.bind('<ButtonRelease-1>', self.ChangeBeta)
30
+ self.view.set_init.bind('<ButtonPress-1>', self.SetInit)
31
+ self.view.reset.bind('<ButtonPress-1>', self.Reset)
32
+ self.view.bg.bind('<Double-1>', self.open_img)
33
+
34
+
35
+ self.drawn = None
36
+
37
+ self.view.target.delete(1.0, "end")
38
+ self.view.target.insert("end", self.style_clip.target)
39
+ #
40
+ self.view.neutral.delete(1.0, "end")
41
+ self.view.neutral.insert("end", self.style_clip.neutral)
42
+
43
+
44
+ def Reset(self,event):
45
+ self.style_clip.GetDt2()
46
+ self.style_clip.M.alpha=[0]
47
+
48
+ self.view.beta.set(self.style_clip.beta)
49
+ self.view.alpha.set(0)
50
+
51
+ img=self.style_clip.GetImg()
52
+ img=Image.fromarray(img)
53
+ img = ImageTk.PhotoImage(img)
54
+ self.addImage_m(img)
55
+
56
+
57
+ def SetInit(self,event):
58
+ codes=self.style_clip.GetCode()
59
+ self.style_clip.M.dlatent_tmp=[tmp[:,0] for tmp in codes]
60
+ print('set init')
61
+
62
+ def ChangeAlpha(self,event):
63
+ tmp=self.view.alpha.get()
64
+ self.style_clip.M.alpha=[float(tmp)]
65
+
66
+ img=self.style_clip.GetImg()
67
+ print('manipulate one')
68
+ img=Image.fromarray(img)
69
+ img = ImageTk.PhotoImage(img)
70
+ self.addImage_m(img)
71
+
72
+ def ChangeBeta(self,event):
73
+ tmp=self.view.beta.get()
74
+ self.style_clip.beta=float(tmp)
75
+
76
+ img=self.style_clip.GetImg()
77
+ print('manipulate one')
78
+ img=Image.fromarray(img)
79
+ img = ImageTk.PhotoImage(img)
80
+ self.addImage_m(img)
81
+
82
+ def ChangeDataset(self,event):
83
+
84
+ dataset_name=self.view.set_category.get()
85
+
86
+ self.style_clip.LoadData(dataset_name)
87
+
88
+ self.view.target.delete(1.0, "end")
89
+ self.view.target.insert("end", self.style_clip.target)
90
+
91
+ self.view.neutral.delete(1.0, "end")
92
+ self.view.neutral.insert("end", self.style_clip.neutral)
93
+
94
+ def text_t(self,event):
95
+ tmp=self.view.target.get("1.0",'end')
96
+ tmp=tmp.replace('\n','')
97
+
98
+ self.view.target.delete(1.0, "end")
99
+ self.view.target.insert("end", tmp)
100
+
101
+ print('target',tmp,'###')
102
+ self.style_clip.target=tmp
103
+ self.style_clip.GetDt2()
104
+ self.view.beta.set(self.style_clip.beta)
105
+ self.view.alpha.set(3)
106
+ self.style_clip.M.alpha=[3]
107
+
108
+ img=self.style_clip.GetImg()
109
+ print('manipulate one')
110
+ img=Image.fromarray(img)
111
+ img = ImageTk.PhotoImage(img)
112
+ self.addImage_m(img)
113
+
114
+
115
+ def text_n(self,event):
116
+ tmp=self.view.neutral.get("1.0",'end')
117
+ tmp=tmp.replace('\n','')
118
+
119
+ self.view.neutral.delete(1.0, "end")
120
+ self.view.neutral.insert("end", tmp)
121
+
122
+ print('neutral',tmp,'###')
123
+ self.style_clip.neutral=tmp
124
+ self.view.target.delete(1.0, "end")
125
+ self.view.target.insert("end", tmp)
126
+
127
+
128
+ def run(self):
129
+ self.root.mainloop()
130
+
131
+ def addImage(self,img):
132
+ self.view.bg.create_image(self.view.width/2, self.view.height/2, image=img, anchor='center')
133
+ self.image=img #save a copy of image. if not the image will disappear
134
+
135
+ def addImage_m(self,img):
136
+ self.view.mani.create_image(512, 512, image=img, anchor='center')
137
+ self.image2=img
138
+
139
+
140
+ def openfn(self):
141
+ filename = askopenfilename(title='open',initialdir='./data/'+self.style_clip.M.dataset_name+'/',filetypes=[("all image format", ".jpg"),("all image format", ".png")])
142
+ return filename
143
+
144
+ def open_img(self,event):
145
+ x = self.openfn()
146
+ print(x)
147
+
148
+
149
+ img = Image.open(x)
150
+ img2 = img.resize(( 512,512), Image.ANTIALIAS)
151
+ img2 = ImageTk.PhotoImage(img2)
152
+ self.addImage(img2)
153
+
154
+ img = ImageTk.PhotoImage(img)
155
+ self.addImage_m(img)
156
+
157
+ img_index=x.split('/')[-1].split('.')[0]
158
+ img_index=int(img_index)
159
+ print(img_index)
160
+ self.style_clip.M.img_index=img_index
161
+ self.style_clip.M.dlatent_tmp=[tmp[img_index:(img_index+1)] for tmp in self.style_clip.M.dlatents]
162
+
163
+
164
+ self.style_clip.GetDt2()
165
+ self.view.beta.set(self.style_clip.beta)
166
+ self.view.alpha.set(3)
167
+
168
+ #%%
169
+ if __name__ == "__main__":
170
+ parser = argparse.ArgumentParser(description='Process some integers.')
171
+
172
+ parser.add_argument('--dataset_name',type=str,default='ffhq',
173
+ help='name of dataset, for example, ffhq')
174
+
175
+ args = parser.parse_args()
176
+ dataset_name=args.dataset_name
177
+
178
+ self=PlayInteractively(dataset_name)
179
+ self.run()
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
PTI/models/StyleCLIP/global_directions/SingleChannel.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ import numpy as np
5
+ import torch
6
+ import clip
7
+ from PIL import Image
8
+ import copy
9
+ from manipulate import Manipulator
10
+ import argparse
11
+
12
+ def GetImgF(out,model,preprocess):
13
+ imgs=out
14
+ imgs1=imgs.reshape([-1]+list(imgs.shape[2:]))
15
+
16
+ tmp=[]
17
+ for i in range(len(imgs1)):
18
+
19
+ img=Image.fromarray(imgs1[i])
20
+ image = preprocess(img).unsqueeze(0).to(device)
21
+ tmp.append(image)
22
+
23
+ image=torch.cat(tmp)
24
+ with torch.no_grad():
25
+ image_features = model.encode_image(image)
26
+
27
+ image_features1=image_features.cpu().numpy()
28
+ image_features1=image_features1.reshape(list(imgs.shape[:2])+[512])
29
+
30
+ return image_features1
31
+
32
+ def GetFs(fs):
33
+ tmp=np.linalg.norm(fs,axis=-1)
34
+ fs1=fs/tmp[:,:,:,None]
35
+ fs2=fs1[:,:,1,:]-fs1[:,:,0,:] # 5*sigma - (-5)* sigma
36
+ fs3=fs2/np.linalg.norm(fs2,axis=-1)[:,:,None]
37
+ fs3=fs3.mean(axis=1)
38
+ fs3=fs3/np.linalg.norm(fs3,axis=-1)[:,None]
39
+ return fs3
40
+
41
+ #%%
42
+ if __name__ == "__main__":
43
+ parser = argparse.ArgumentParser(description='Process some integers.')
44
+
45
+ parser.add_argument('--dataset_name',type=str,default='cat',
46
+ help='name of dataset, for example, ffhq')
47
+ args = parser.parse_args()
48
+ dataset_name=args.dataset_name
49
+
50
+ #%%
51
+ device = "cuda" if torch.cuda.is_available() else "cpu"
52
+ model, preprocess = clip.load("ViT-B/32", device=device)
53
+ #%%
54
+ M=Manipulator(dataset_name=dataset_name)
55
+ np.set_printoptions(suppress=True)
56
+ print(M.dataset_name)
57
+ #%%
58
+ img_sindex=0
59
+ num_images=100
60
+ dlatents_o=[]
61
+ tmp=img_sindex*num_images
62
+ for i in range(len(M.dlatents)):
63
+ tmp1=M.dlatents[i][tmp:(tmp+num_images)]
64
+ dlatents_o.append(tmp1)
65
+ #%%
66
+
67
+ all_f=[]
68
+ M.alpha=[-5,5] #ffhq 5
69
+ M.step=2
70
+ M.num_images=num_images
71
+ select=np.array(M.mindexs)<=16 #below or equal to 128 resolution
72
+ mindexs2=np.array(M.mindexs)[select]
73
+ for lindex in mindexs2: #ignore ToRGB layers
74
+ print(lindex)
75
+ num_c=M.dlatents[lindex].shape[1]
76
+ for cindex in range(num_c):
77
+
78
+ M.dlatents=copy.copy(dlatents_o)
79
+ M.dlatents[lindex][:,cindex]=M.code_mean[lindex][cindex]
80
+
81
+ M.manipulate_layers=[lindex]
82
+ codes,out=M.EditOneC(cindex)
83
+ image_features1=GetImgF(out,model,preprocess)
84
+ all_f.append(image_features1)
85
+
86
+ all_f=np.array(all_f)
87
+
88
+ fs3=GetFs(all_f)
89
+
90
+ #%%
91
+ file_path='./npy/'+M.dataset_name+'/'
92
+ np.save(file_path+'fs3',fs3)
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
PTI/models/StyleCLIP/global_directions/__init__.py ADDED
File without changes
PTI/models/StyleCLIP/global_directions/data/ffhq/w_plus.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:394f0f166305654f49cd1b0cd3d4f2b7a51e740a449a1ebfa1c69f79d01399fa
3
+ size 2506880
PTI/models/StyleCLIP/global_directions/dnnlib/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ from .util import EasyDict, make_cache_dir_path
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ from . import autosummary
10
+ from . import network
11
+ from . import optimizer
12
+ from . import tfutil
13
+ from . import custom_ops
14
+
15
+ from .tfutil import *
16
+ from .network import Network
17
+
18
+ from .optimizer import Optimizer
19
+
20
+ from .custom_ops import get_plugin
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/autosummary.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Helper for adding automatically tracked values to Tensorboard.
10
+
11
+ Autosummary creates an identity op that internally keeps track of the input
12
+ values and automatically shows up in TensorBoard. The reported value
13
+ represents an average over input components. The average is accumulated
14
+ constantly over time and flushed when save_summaries() is called.
15
+
16
+ Notes:
17
+ - The output tensor must be used as an input for something else in the
18
+ graph. Otherwise, the autosummary op will not get executed, and the average
19
+ value will not get accumulated.
20
+ - It is perfectly fine to include autosummaries with the same name in
21
+ several places throughout the graph, even if they are executed concurrently.
22
+ - It is ok to also pass in a python scalar or numpy array. In this case, it
23
+ is added to the average immediately.
24
+ """
25
+
26
+ from collections import OrderedDict
27
+ import numpy as np
28
+ import tensorflow as tf
29
+ from tensorboard import summary as summary_lib
30
+ from tensorboard.plugins.custom_scalar import layout_pb2
31
+
32
+ from . import tfutil
33
+ from .tfutil import TfExpression
34
+ from .tfutil import TfExpressionEx
35
+
36
+ # Enable "Custom scalars" tab in TensorBoard for advanced formatting.
37
+ # Disabled by default to reduce tfevents file size.
38
+ enable_custom_scalars = False
39
+
40
+ _dtype = tf.float64
41
+ _vars = OrderedDict() # name => [var, ...]
42
+ _immediate = OrderedDict() # name => update_op, update_value
43
+ _finalized = False
44
+ _merge_op = None
45
+
46
+
47
+ def _create_var(name: str, value_expr: TfExpression) -> TfExpression:
48
+ """Internal helper for creating autosummary accumulators."""
49
+ assert not _finalized
50
+ name_id = name.replace("/", "_")
51
+ v = tf.cast(value_expr, _dtype)
52
+
53
+ if v.shape.is_fully_defined():
54
+ size = np.prod(v.shape.as_list())
55
+ size_expr = tf.constant(size, dtype=_dtype)
56
+ else:
57
+ size = None
58
+ size_expr = tf.reduce_prod(tf.cast(tf.shape(v), _dtype))
59
+
60
+ if size == 1:
61
+ if v.shape.ndims != 0:
62
+ v = tf.reshape(v, [])
63
+ v = [size_expr, v, tf.square(v)]
64
+ else:
65
+ v = [size_expr, tf.reduce_sum(v), tf.reduce_sum(tf.square(v))]
66
+ v = tf.cond(tf.is_finite(v[1]), lambda: tf.stack(v), lambda: tf.zeros(3, dtype=_dtype))
67
+
68
+ with tfutil.absolute_name_scope("Autosummary/" + name_id), tf.control_dependencies(None):
69
+ var = tf.Variable(tf.zeros(3, dtype=_dtype), trainable=False) # [sum(1), sum(x), sum(x**2)]
70
+ update_op = tf.cond(tf.is_variable_initialized(var), lambda: tf.assign_add(var, v), lambda: tf.assign(var, v))
71
+
72
+ if name in _vars:
73
+ _vars[name].append(var)
74
+ else:
75
+ _vars[name] = [var]
76
+ return update_op
77
+
78
+
79
+ def autosummary(name: str, value: TfExpressionEx, passthru: TfExpressionEx = None, condition: TfExpressionEx = True) -> TfExpressionEx:
80
+ """Create a new autosummary.
81
+
82
+ Args:
83
+ name: Name to use in TensorBoard
84
+ value: TensorFlow expression or python value to track
85
+ passthru: Optionally return this TF node without modifications but tack an autosummary update side-effect to this node.
86
+
87
+ Example use of the passthru mechanism:
88
+
89
+ n = autosummary('l2loss', loss, passthru=n)
90
+
91
+ This is a shorthand for the following code:
92
+
93
+ with tf.control_dependencies([autosummary('l2loss', loss)]):
94
+ n = tf.identity(n)
95
+ """
96
+ tfutil.assert_tf_initialized()
97
+ name_id = name.replace("/", "_")
98
+
99
+ if tfutil.is_tf_expression(value):
100
+ with tf.name_scope("summary_" + name_id), tf.device(value.device):
101
+ condition = tf.convert_to_tensor(condition, name='condition')
102
+ update_op = tf.cond(condition, lambda: tf.group(_create_var(name, value)), tf.no_op)
103
+ with tf.control_dependencies([update_op]):
104
+ return tf.identity(value if passthru is None else passthru)
105
+
106
+ else: # python scalar or numpy array
107
+ assert not tfutil.is_tf_expression(passthru)
108
+ assert not tfutil.is_tf_expression(condition)
109
+ if condition:
110
+ if name not in _immediate:
111
+ with tfutil.absolute_name_scope("Autosummary/" + name_id), tf.device(None), tf.control_dependencies(None):
112
+ update_value = tf.placeholder(_dtype)
113
+ update_op = _create_var(name, update_value)
114
+ _immediate[name] = update_op, update_value
115
+ update_op, update_value = _immediate[name]
116
+ tfutil.run(update_op, {update_value: value})
117
+ return value if passthru is None else passthru
118
+
119
+
120
+ def finalize_autosummaries() -> None:
121
+ """Create the necessary ops to include autosummaries in TensorBoard report.
122
+ Note: This should be done only once per graph.
123
+ """
124
+ global _finalized
125
+ tfutil.assert_tf_initialized()
126
+
127
+ if _finalized:
128
+ return None
129
+
130
+ _finalized = True
131
+ tfutil.init_uninitialized_vars([var for vars_list in _vars.values() for var in vars_list])
132
+
133
+ # Create summary ops.
134
+ with tf.device(None), tf.control_dependencies(None):
135
+ for name, vars_list in _vars.items():
136
+ name_id = name.replace("/", "_")
137
+ with tfutil.absolute_name_scope("Autosummary/" + name_id):
138
+ moments = tf.add_n(vars_list)
139
+ moments /= moments[0]
140
+ with tf.control_dependencies([moments]): # read before resetting
141
+ reset_ops = [tf.assign(var, tf.zeros(3, dtype=_dtype)) for var in vars_list]
142
+ with tf.name_scope(None), tf.control_dependencies(reset_ops): # reset before reporting
143
+ mean = moments[1]
144
+ std = tf.sqrt(moments[2] - tf.square(moments[1]))
145
+ tf.summary.scalar(name, mean)
146
+ if enable_custom_scalars:
147
+ tf.summary.scalar("xCustomScalars/" + name + "/margin_lo", mean - std)
148
+ tf.summary.scalar("xCustomScalars/" + name + "/margin_hi", mean + std)
149
+
150
+ # Setup layout for custom scalars.
151
+ layout = None
152
+ if enable_custom_scalars:
153
+ cat_dict = OrderedDict()
154
+ for series_name in sorted(_vars.keys()):
155
+ p = series_name.split("/")
156
+ cat = p[0] if len(p) >= 2 else ""
157
+ chart = "/".join(p[1:-1]) if len(p) >= 3 else p[-1]
158
+ if cat not in cat_dict:
159
+ cat_dict[cat] = OrderedDict()
160
+ if chart not in cat_dict[cat]:
161
+ cat_dict[cat][chart] = []
162
+ cat_dict[cat][chart].append(series_name)
163
+ categories = []
164
+ for cat_name, chart_dict in cat_dict.items():
165
+ charts = []
166
+ for chart_name, series_names in chart_dict.items():
167
+ series = []
168
+ for series_name in series_names:
169
+ series.append(layout_pb2.MarginChartContent.Series(
170
+ value=series_name,
171
+ lower="xCustomScalars/" + series_name + "/margin_lo",
172
+ upper="xCustomScalars/" + series_name + "/margin_hi"))
173
+ margin = layout_pb2.MarginChartContent(series=series)
174
+ charts.append(layout_pb2.Chart(title=chart_name, margin=margin))
175
+ categories.append(layout_pb2.Category(title=cat_name, chart=charts))
176
+ layout = summary_lib.custom_scalar_pb(layout_pb2.Layout(category=categories))
177
+ return layout
178
+
179
+ def save_summaries(file_writer, global_step=None):
180
+ """Call FileWriter.add_summary() with all summaries in the default graph,
181
+ automatically finalizing and merging them on the first call.
182
+ """
183
+ global _merge_op
184
+ tfutil.assert_tf_initialized()
185
+
186
+ if _merge_op is None:
187
+ layout = finalize_autosummaries()
188
+ if layout is not None:
189
+ file_writer.add_summary(layout)
190
+ with tf.device(None), tf.control_dependencies(None):
191
+ _merge_op = tf.summary.merge_all()
192
+
193
+ file_writer.add_summary(_merge_op.eval(), global_step)
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/custom_ops.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """TensorFlow custom ops builder.
10
+ """
11
+
12
+ import glob
13
+ import os
14
+ import re
15
+ import uuid
16
+ import hashlib
17
+ import tempfile
18
+ import shutil
19
+ import tensorflow as tf
20
+ from tensorflow.python.client import device_lib # pylint: disable=no-name-in-module
21
+
22
+ from .. import util
23
+
24
+ #----------------------------------------------------------------------------
25
+ # Global configs.
26
+
27
+ cuda_cache_path = None
28
+ cuda_cache_version_tag = 'v1'
29
+ do_not_hash_included_headers = True # Speed up compilation by assuming that headers included by the CUDA code never change.
30
+ verbose = True # Print status messages to stdout.
31
+
32
+ #----------------------------------------------------------------------------
33
+ # Internal helper funcs.
34
+
35
+ def _find_compiler_bindir():
36
+ hostx64_paths = sorted(glob.glob('C:/Program Files (x86)/Microsoft Visual Studio/*/Professional/VC/Tools/MSVC/*/bin/Hostx64/x64'), reverse=True)
37
+ if hostx64_paths != []:
38
+ return hostx64_paths[0]
39
+ hostx64_paths = sorted(glob.glob('C:/Program Files (x86)/Microsoft Visual Studio/*/BuildTools/VC/Tools/MSVC/*/bin/Hostx64/x64'), reverse=True)
40
+ if hostx64_paths != []:
41
+ return hostx64_paths[0]
42
+ hostx64_paths = sorted(glob.glob('C:/Program Files (x86)/Microsoft Visual Studio/*/Community/VC/Tools/MSVC/*/bin/Hostx64/x64'), reverse=True)
43
+ if hostx64_paths != []:
44
+ return hostx64_paths[0]
45
+ vc_bin_dir = 'C:/Program Files (x86)/Microsoft Visual Studio 14.0/vc/bin'
46
+ if os.path.isdir(vc_bin_dir):
47
+ return vc_bin_dir
48
+ return None
49
+
50
+ def _get_compute_cap(device):
51
+ caps_str = device.physical_device_desc
52
+ m = re.search('compute capability: (\\d+).(\\d+)', caps_str)
53
+ major = m.group(1)
54
+ minor = m.group(2)
55
+ return (major, minor)
56
+
57
+ def _get_cuda_gpu_arch_string():
58
+ gpus = [x for x in device_lib.list_local_devices() if x.device_type == 'GPU']
59
+ if len(gpus) == 0:
60
+ raise RuntimeError('No GPU devices found')
61
+ (major, minor) = _get_compute_cap(gpus[0])
62
+ return 'sm_%s%s' % (major, minor)
63
+
64
+ def _run_cmd(cmd):
65
+ with os.popen(cmd) as pipe:
66
+ output = pipe.read()
67
+ status = pipe.close()
68
+ if status is not None:
69
+ raise RuntimeError('NVCC returned an error. See below for full command line and output log:\n\n%s\n\n%s' % (cmd, output))
70
+
71
+ def _prepare_nvcc_cli(opts):
72
+ cmd = 'nvcc ' + opts.strip()
73
+ cmd += ' --disable-warnings'
74
+ cmd += ' --include-path "%s"' % tf.sysconfig.get_include()
75
+ cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'protobuf_archive', 'src')
76
+ cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'com_google_absl')
77
+ cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'eigen_archive')
78
+
79
+ compiler_bindir = _find_compiler_bindir()
80
+ if compiler_bindir is None:
81
+ # Require that _find_compiler_bindir succeeds on Windows. Allow
82
+ # nvcc to use whatever is the default on Linux.
83
+ if os.name == 'nt':
84
+ raise RuntimeError('Could not find MSVC/GCC/CLANG installation on this computer. Check compiler_bindir_search_path list in "%s".' % __file__)
85
+ else:
86
+ cmd += ' --compiler-bindir "%s"' % compiler_bindir
87
+ cmd += ' 2>&1'
88
+ return cmd
89
+
90
+ #----------------------------------------------------------------------------
91
+ # Main entry point.
92
+
93
+ _plugin_cache = dict()
94
+
95
+ def get_plugin(cuda_file, extra_nvcc_options=[]):
96
+ cuda_file_base = os.path.basename(cuda_file)
97
+ cuda_file_name, cuda_file_ext = os.path.splitext(cuda_file_base)
98
+
99
+ # Already in cache?
100
+ if cuda_file in _plugin_cache:
101
+ return _plugin_cache[cuda_file]
102
+
103
+ # Setup plugin.
104
+ if verbose:
105
+ print('Setting up TensorFlow plugin "%s": ' % cuda_file_base, end='', flush=True)
106
+ try:
107
+ # Hash CUDA source.
108
+ md5 = hashlib.md5()
109
+ with open(cuda_file, 'rb') as f:
110
+ md5.update(f.read())
111
+ md5.update(b'\n')
112
+
113
+ # Hash headers included by the CUDA code by running it through the preprocessor.
114
+ if not do_not_hash_included_headers:
115
+ if verbose:
116
+ print('Preprocessing... ', end='', flush=True)
117
+ with tempfile.TemporaryDirectory() as tmp_dir:
118
+ tmp_file = os.path.join(tmp_dir, cuda_file_name + '_tmp' + cuda_file_ext)
119
+ _run_cmd(_prepare_nvcc_cli('"%s" --preprocess -o "%s" --keep --keep-dir "%s"' % (cuda_file, tmp_file, tmp_dir)))
120
+ with open(tmp_file, 'rb') as f:
121
+ bad_file_str = ('"' + cuda_file.replace('\\', '/') + '"').encode('utf-8') # __FILE__ in error check macros
122
+ good_file_str = ('"' + cuda_file_base + '"').encode('utf-8')
123
+ for ln in f:
124
+ if not ln.startswith(b'# ') and not ln.startswith(b'#line '): # ignore line number pragmas
125
+ ln = ln.replace(bad_file_str, good_file_str)
126
+ md5.update(ln)
127
+ md5.update(b'\n')
128
+
129
+ # Select compiler configs.
130
+ compile_opts = ''
131
+ if os.name == 'nt':
132
+ compile_opts += '"%s"' % os.path.join(tf.sysconfig.get_lib(), 'python', '_pywrap_tensorflow_internal.lib')
133
+ elif os.name == 'posix':
134
+ compile_opts += f' --compiler-options \'-fPIC\''
135
+ compile_opts += f' --compiler-options \'{" ".join(tf.sysconfig.get_compile_flags())}\''
136
+ compile_opts += f' --linker-options \'{" ".join(tf.sysconfig.get_link_flags())}\''
137
+ else:
138
+ assert False # not Windows or Linux, w00t?
139
+ compile_opts += f' --gpu-architecture={_get_cuda_gpu_arch_string()}'
140
+ compile_opts += ' --use_fast_math'
141
+ for opt in extra_nvcc_options:
142
+ compile_opts += ' ' + opt
143
+ nvcc_cmd = _prepare_nvcc_cli(compile_opts)
144
+
145
+ # Hash build configuration.
146
+ md5.update(('nvcc_cmd: ' + nvcc_cmd).encode('utf-8') + b'\n')
147
+ md5.update(('tf.VERSION: ' + tf.VERSION).encode('utf-8') + b'\n')
148
+ md5.update(('cuda_cache_version_tag: ' + cuda_cache_version_tag).encode('utf-8') + b'\n')
149
+
150
+ # Compile if not already compiled.
151
+ cache_dir = util.make_cache_dir_path('tflib-cudacache') if cuda_cache_path is None else cuda_cache_path
152
+ bin_file_ext = '.dll' if os.name == 'nt' else '.so'
153
+ bin_file = os.path.join(cache_dir, cuda_file_name + '_' + md5.hexdigest() + bin_file_ext)
154
+ if not os.path.isfile(bin_file):
155
+ if verbose:
156
+ print('Compiling... ', end='', flush=True)
157
+ with tempfile.TemporaryDirectory() as tmp_dir:
158
+ tmp_file = os.path.join(tmp_dir, cuda_file_name + '_tmp' + bin_file_ext)
159
+ _run_cmd(nvcc_cmd + ' "%s" --shared -o "%s" --keep --keep-dir "%s"' % (cuda_file, tmp_file, tmp_dir))
160
+ os.makedirs(cache_dir, exist_ok=True)
161
+ intermediate_file = os.path.join(cache_dir, cuda_file_name + '_' + uuid.uuid4().hex + '_tmp' + bin_file_ext)
162
+ shutil.copyfile(tmp_file, intermediate_file)
163
+ os.rename(intermediate_file, bin_file) # atomic
164
+
165
+ # Load.
166
+ if verbose:
167
+ print('Loading... ', end='', flush=True)
168
+ plugin = tf.load_op_library(bin_file)
169
+
170
+ # Add to cache.
171
+ _plugin_cache[cuda_file] = plugin
172
+ if verbose:
173
+ print('Done.', flush=True)
174
+ return plugin
175
+
176
+ except:
177
+ if verbose:
178
+ print('Failed!', flush=True)
179
+ raise
180
+
181
+ #----------------------------------------------------------------------------
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/network.py ADDED
@@ -0,0 +1,781 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Helper for managing networks."""
10
+
11
+ import types
12
+ import inspect
13
+ import re
14
+ import uuid
15
+ import sys
16
+ import copy
17
+ import numpy as np
18
+ import tensorflow as tf
19
+
20
+ from collections import OrderedDict
21
+ from typing import Any, List, Tuple, Union, Callable
22
+
23
+ from . import tfutil
24
+ from .. import util
25
+
26
+ from .tfutil import TfExpression, TfExpressionEx
27
+
28
+ # pylint: disable=protected-access
29
+ # pylint: disable=attribute-defined-outside-init
30
+ # pylint: disable=too-many-public-methods
31
+
32
+ _import_handlers = [] # Custom import handlers for dealing with legacy data in pickle import.
33
+ _import_module_src = dict() # Source code for temporary modules created during pickle import.
34
+
35
+
36
+ def import_handler(handler_func):
37
+ """Function decorator for declaring custom import handlers."""
38
+ _import_handlers.append(handler_func)
39
+ return handler_func
40
+
41
+
42
+ class Network:
43
+ """Generic network abstraction.
44
+
45
+ Acts as a convenience wrapper for a parameterized network construction
46
+ function, providing several utility methods and convenient access to
47
+ the inputs/outputs/weights.
48
+
49
+ Network objects can be safely pickled and unpickled for long-term
50
+ archival purposes. The pickling works reliably as long as the underlying
51
+ network construction function is defined in a standalone Python module
52
+ that has no side effects or application-specific imports.
53
+
54
+ Args:
55
+ name: Network name. Used to select TensorFlow name and variable scopes. Defaults to build func name if None.
56
+ func_name: Fully qualified name of the underlying network construction function, or a top-level function object.
57
+ static_kwargs: Keyword arguments to be passed in to the network construction function.
58
+ """
59
+
60
+ def __init__(self, name: str = None, func_name: Any = None, **static_kwargs):
61
+ # Locate the user-specified build function.
62
+ assert isinstance(func_name, str) or util.is_top_level_function(func_name)
63
+ if util.is_top_level_function(func_name):
64
+ func_name = util.get_top_level_function_name(func_name)
65
+ module, func_name = util.get_module_from_obj_name(func_name)
66
+ func = util.get_obj_from_module(module, func_name)
67
+
68
+ # Dig up source code for the module containing the build function.
69
+ module_src = _import_module_src.get(module, None)
70
+ if module_src is None:
71
+ module_src = inspect.getsource(module)
72
+
73
+ # Initialize fields.
74
+ self._init_fields(name=(name or func_name), static_kwargs=static_kwargs, build_func=func, build_func_name=func_name, build_module_src=module_src)
75
+
76
+ def _init_fields(self, name: str, static_kwargs: dict, build_func: Callable, build_func_name: str, build_module_src: str) -> None:
77
+ tfutil.assert_tf_initialized()
78
+ assert isinstance(name, str)
79
+ assert len(name) >= 1
80
+ assert re.fullmatch(r"[A-Za-z0-9_.\\-]*", name)
81
+ assert isinstance(static_kwargs, dict)
82
+ assert util.is_pickleable(static_kwargs)
83
+ assert callable(build_func)
84
+ assert isinstance(build_func_name, str)
85
+ assert isinstance(build_module_src, str)
86
+
87
+ # Choose TensorFlow name scope.
88
+ with tf.name_scope(None):
89
+ scope = tf.get_default_graph().unique_name(name, mark_as_used=True)
90
+
91
+ # Query current TensorFlow device.
92
+ with tfutil.absolute_name_scope(scope), tf.control_dependencies(None):
93
+ device = tf.no_op(name="_QueryDevice").device
94
+
95
+ # Immutable state.
96
+ self._name = name
97
+ self._scope = scope
98
+ self._device = device
99
+ self._static_kwargs = util.EasyDict(copy.deepcopy(static_kwargs))
100
+ self._build_func = build_func
101
+ self._build_func_name = build_func_name
102
+ self._build_module_src = build_module_src
103
+
104
+ # State before _init_graph().
105
+ self._var_inits = dict() # var_name => initial_value, set to None by _init_graph()
106
+ self._all_inits_known = False # Do we know for sure that _var_inits covers all the variables?
107
+ self._components = None # subnet_name => Network, None if the components are not known yet
108
+
109
+ # Initialized by _init_graph().
110
+ self._input_templates = None
111
+ self._output_templates = None
112
+ self._own_vars = None
113
+
114
+ # Cached values initialized the respective methods.
115
+ self._input_shapes = None
116
+ self._output_shapes = None
117
+ self._input_names = None
118
+ self._output_names = None
119
+ self._vars = None
120
+ self._trainables = None
121
+ self._var_global_to_local = None
122
+ self._run_cache = dict()
123
+
124
+ def _init_graph(self) -> None:
125
+ assert self._var_inits is not None
126
+ assert self._input_templates is None
127
+ assert self._output_templates is None
128
+ assert self._own_vars is None
129
+
130
+ # Initialize components.
131
+ if self._components is None:
132
+ self._components = util.EasyDict()
133
+
134
+ # Choose build func kwargs.
135
+ build_kwargs = dict(self.static_kwargs)
136
+ build_kwargs["is_template_graph"] = True
137
+ build_kwargs["components"] = self._components
138
+
139
+ # Override scope and device, and ignore surrounding control dependencies.
140
+ with tfutil.absolute_variable_scope(self.scope, reuse=False), tfutil.absolute_name_scope(self.scope), tf.device(self.device), tf.control_dependencies(None):
141
+ assert tf.get_variable_scope().name == self.scope
142
+ assert tf.get_default_graph().get_name_scope() == self.scope
143
+
144
+ # Create input templates.
145
+ self._input_templates = []
146
+ for param in inspect.signature(self._build_func).parameters.values():
147
+ if param.kind == param.POSITIONAL_OR_KEYWORD and param.default is param.empty:
148
+ self._input_templates.append(tf.placeholder(tf.float32, name=param.name))
149
+
150
+ # Call build func.
151
+ out_expr = self._build_func(*self._input_templates, **build_kwargs)
152
+
153
+ # Collect output templates and variables.
154
+ assert tfutil.is_tf_expression(out_expr) or isinstance(out_expr, tuple)
155
+ self._output_templates = [out_expr] if tfutil.is_tf_expression(out_expr) else list(out_expr)
156
+ self._own_vars = OrderedDict((var.name[len(self.scope) + 1:].split(":")[0], var) for var in tf.global_variables(self.scope + "/"))
157
+
158
+ # Check for errors.
159
+ if len(self._input_templates) == 0:
160
+ raise ValueError("Network build func did not list any inputs.")
161
+ if len(self._output_templates) == 0:
162
+ raise ValueError("Network build func did not return any outputs.")
163
+ if any(not tfutil.is_tf_expression(t) for t in self._output_templates):
164
+ raise ValueError("Network outputs must be TensorFlow expressions.")
165
+ if any(t.shape.ndims is None for t in self._input_templates):
166
+ raise ValueError("Network input shapes not defined. Please call x.set_shape() for each input.")
167
+ if any(t.shape.ndims is None for t in self._output_templates):
168
+ raise ValueError("Network output shapes not defined. Please call x.set_shape() where applicable.")
169
+ if any(not isinstance(comp, Network) for comp in self._components.values()):
170
+ raise ValueError("Components of a Network must be Networks themselves.")
171
+ if len(self._components) != len(set(comp.name for comp in self._components.values())):
172
+ raise ValueError("Components of a Network must have unique names.")
173
+
174
+ # Initialize variables.
175
+ if len(self._var_inits):
176
+ tfutil.set_vars({self._get_vars()[name]: value for name, value in self._var_inits.items() if name in self._get_vars()})
177
+ remaining_inits = [var.initializer for name, var in self._own_vars.items() if name not in self._var_inits]
178
+ if self._all_inits_known:
179
+ assert len(remaining_inits) == 0
180
+ else:
181
+ tfutil.run(remaining_inits)
182
+ self._var_inits = None
183
+
184
+ @property
185
+ def name(self):
186
+ """User-specified name string."""
187
+ return self._name
188
+
189
+ @property
190
+ def scope(self):
191
+ """Unique TensorFlow scope containing template graph and variables, derived from the user-specified name."""
192
+ return self._scope
193
+
194
+ @property
195
+ def device(self):
196
+ """Name of the TensorFlow device that the weights of this network reside on. Determined by the current device at construction time."""
197
+ return self._device
198
+
199
+ @property
200
+ def static_kwargs(self):
201
+ """EasyDict of arguments passed to the user-supplied build func."""
202
+ return copy.deepcopy(self._static_kwargs)
203
+
204
+ @property
205
+ def components(self):
206
+ """EasyDict of sub-networks created by the build func."""
207
+ return copy.copy(self._get_components())
208
+
209
+ def _get_components(self):
210
+ if self._components is None:
211
+ self._init_graph()
212
+ assert self._components is not None
213
+ return self._components
214
+
215
+ @property
216
+ def input_shapes(self):
217
+ """List of input tensor shapes, including minibatch dimension."""
218
+ if self._input_shapes is None:
219
+ self._input_shapes = [t.shape.as_list() for t in self.input_templates]
220
+ return copy.deepcopy(self._input_shapes)
221
+
222
+ @property
223
+ def output_shapes(self):
224
+ """List of output tensor shapes, including minibatch dimension."""
225
+ if self._output_shapes is None:
226
+ self._output_shapes = [t.shape.as_list() for t in self.output_templates]
227
+ return copy.deepcopy(self._output_shapes)
228
+
229
+ @property
230
+ def input_shape(self):
231
+ """Short-hand for input_shapes[0]."""
232
+ return self.input_shapes[0]
233
+
234
+ @property
235
+ def output_shape(self):
236
+ """Short-hand for output_shapes[0]."""
237
+ return self.output_shapes[0]
238
+
239
+ @property
240
+ def num_inputs(self):
241
+ """Number of input tensors."""
242
+ return len(self.input_shapes)
243
+
244
+ @property
245
+ def num_outputs(self):
246
+ """Number of output tensors."""
247
+ return len(self.output_shapes)
248
+
249
+ @property
250
+ def input_names(self):
251
+ """Name string for each input."""
252
+ if self._input_names is None:
253
+ self._input_names = [t.name.split("/")[-1].split(":")[0] for t in self.input_templates]
254
+ return copy.copy(self._input_names)
255
+
256
+ @property
257
+ def output_names(self):
258
+ """Name string for each output."""
259
+ if self._output_names is None:
260
+ self._output_names = [t.name.split("/")[-1].split(":")[0] for t in self.output_templates]
261
+ return copy.copy(self._output_names)
262
+
263
+ @property
264
+ def input_templates(self):
265
+ """Input placeholders in the template graph."""
266
+ if self._input_templates is None:
267
+ self._init_graph()
268
+ assert self._input_templates is not None
269
+ return copy.copy(self._input_templates)
270
+
271
+ @property
272
+ def output_templates(self):
273
+ """Output tensors in the template graph."""
274
+ if self._output_templates is None:
275
+ self._init_graph()
276
+ assert self._output_templates is not None
277
+ return copy.copy(self._output_templates)
278
+
279
+ @property
280
+ def own_vars(self):
281
+ """Variables defined by this network (local_name => var), excluding sub-networks."""
282
+ return copy.copy(self._get_own_vars())
283
+
284
+ def _get_own_vars(self):
285
+ if self._own_vars is None:
286
+ self._init_graph()
287
+ assert self._own_vars is not None
288
+ return self._own_vars
289
+
290
+ @property
291
+ def vars(self):
292
+ """All variables (local_name => var)."""
293
+ return copy.copy(self._get_vars())
294
+
295
+ def _get_vars(self):
296
+ if self._vars is None:
297
+ self._vars = OrderedDict(self._get_own_vars())
298
+ for comp in self._get_components().values():
299
+ self._vars.update((comp.name + "/" + name, var) for name, var in comp._get_vars().items())
300
+ return self._vars
301
+
302
+ @property
303
+ def trainables(self):
304
+ """All trainable variables (local_name => var)."""
305
+ return copy.copy(self._get_trainables())
306
+
307
+ def _get_trainables(self):
308
+ if self._trainables is None:
309
+ self._trainables = OrderedDict((name, var) for name, var in self.vars.items() if var.trainable)
310
+ return self._trainables
311
+
312
+ @property
313
+ def var_global_to_local(self):
314
+ """Mapping from variable global names to local names."""
315
+ return copy.copy(self._get_var_global_to_local())
316
+
317
+ def _get_var_global_to_local(self):
318
+ if self._var_global_to_local is None:
319
+ self._var_global_to_local = OrderedDict((var.name.split(":")[0], name) for name, var in self.vars.items())
320
+ return self._var_global_to_local
321
+
322
+ def reset_own_vars(self) -> None:
323
+ """Re-initialize all variables of this network, excluding sub-networks."""
324
+ if self._var_inits is None or self._components is None:
325
+ tfutil.run([var.initializer for var in self._get_own_vars().values()])
326
+ else:
327
+ self._var_inits.clear()
328
+ self._all_inits_known = False
329
+
330
+ def reset_vars(self) -> None:
331
+ """Re-initialize all variables of this network, including sub-networks."""
332
+ if self._var_inits is None:
333
+ tfutil.run([var.initializer for var in self._get_vars().values()])
334
+ else:
335
+ self._var_inits.clear()
336
+ self._all_inits_known = False
337
+ if self._components is not None:
338
+ for comp in self._components.values():
339
+ comp.reset_vars()
340
+
341
+ def reset_trainables(self) -> None:
342
+ """Re-initialize all trainable variables of this network, including sub-networks."""
343
+ tfutil.run([var.initializer for var in self._get_trainables().values()])
344
+
345
+ def get_output_for(self, *in_expr: TfExpression, return_as_list: bool = False, **dynamic_kwargs) -> Union[TfExpression, List[TfExpression]]:
346
+ """Construct TensorFlow expression(s) for the output(s) of this network, given the input expression(s).
347
+ The graph is placed on the current TensorFlow device."""
348
+ assert len(in_expr) == self.num_inputs
349
+ assert not all(expr is None for expr in in_expr)
350
+ self._get_vars() # ensure that all variables have been created
351
+
352
+ # Choose build func kwargs.
353
+ build_kwargs = dict(self.static_kwargs)
354
+ build_kwargs.update(dynamic_kwargs)
355
+ build_kwargs["is_template_graph"] = False
356
+ build_kwargs["components"] = self._components
357
+
358
+ # Build TensorFlow graph to evaluate the network.
359
+ with tfutil.absolute_variable_scope(self.scope, reuse=True), tf.name_scope(self.name):
360
+ assert tf.get_variable_scope().name == self.scope
361
+ valid_inputs = [expr for expr in in_expr if expr is not None]
362
+ final_inputs = []
363
+ for expr, name, shape in zip(in_expr, self.input_names, self.input_shapes):
364
+ if expr is not None:
365
+ expr = tf.identity(expr, name=name)
366
+ else:
367
+ expr = tf.zeros([tf.shape(valid_inputs[0])[0]] + shape[1:], name=name)
368
+ final_inputs.append(expr)
369
+ out_expr = self._build_func(*final_inputs, **build_kwargs)
370
+
371
+ # Propagate input shapes back to the user-specified expressions.
372
+ for expr, final in zip(in_expr, final_inputs):
373
+ if isinstance(expr, tf.Tensor):
374
+ expr.set_shape(final.shape)
375
+
376
+ # Express outputs in the desired format.
377
+ assert tfutil.is_tf_expression(out_expr) or isinstance(out_expr, tuple)
378
+ if return_as_list:
379
+ out_expr = [out_expr] if tfutil.is_tf_expression(out_expr) else list(out_expr)
380
+ return out_expr
381
+
382
+ def get_var_local_name(self, var_or_global_name: Union[TfExpression, str]) -> str:
383
+ """Get the local name of a given variable, without any surrounding name scopes."""
384
+ assert tfutil.is_tf_expression(var_or_global_name) or isinstance(var_or_global_name, str)
385
+ global_name = var_or_global_name if isinstance(var_or_global_name, str) else var_or_global_name.name
386
+ return self._get_var_global_to_local()[global_name]
387
+
388
+ def find_var(self, var_or_local_name: Union[TfExpression, str]) -> TfExpression:
389
+ """Find variable by local or global name."""
390
+ assert tfutil.is_tf_expression(var_or_local_name) or isinstance(var_or_local_name, str)
391
+ return self._get_vars()[var_or_local_name] if isinstance(var_or_local_name, str) else var_or_local_name
392
+
393
+ def get_var(self, var_or_local_name: Union[TfExpression, str]) -> np.ndarray:
394
+ """Get the value of a given variable as NumPy array.
395
+ Note: This method is very inefficient -- prefer to use tflib.run(list_of_vars) whenever possible."""
396
+ return self.find_var(var_or_local_name).eval()
397
+
398
+ def set_var(self, var_or_local_name: Union[TfExpression, str], new_value: Union[int, float, np.ndarray]) -> None:
399
+ """Set the value of a given variable based on the given NumPy array.
400
+ Note: This method is very inefficient -- prefer to use tflib.set_vars() whenever possible."""
401
+ tfutil.set_vars({self.find_var(var_or_local_name): new_value})
402
+
403
+ def __getstate__(self) -> dict:
404
+ """Pickle export."""
405
+ state = dict()
406
+ state["version"] = 5
407
+ state["name"] = self.name
408
+ state["static_kwargs"] = dict(self.static_kwargs)
409
+ state["components"] = dict(self.components)
410
+ state["build_module_src"] = self._build_module_src
411
+ state["build_func_name"] = self._build_func_name
412
+ state["variables"] = list(zip(self._get_own_vars().keys(), tfutil.run(list(self._get_own_vars().values()))))
413
+ state["input_shapes"] = self.input_shapes
414
+ state["output_shapes"] = self.output_shapes
415
+ state["input_names"] = self.input_names
416
+ state["output_names"] = self.output_names
417
+ return state
418
+
419
+ def __setstate__(self, state: dict) -> None:
420
+ """Pickle import."""
421
+
422
+ # Execute custom import handlers.
423
+ for handler in _import_handlers:
424
+ state = handler(state)
425
+
426
+ # Get basic fields.
427
+ assert state["version"] in [2, 3, 4, 5]
428
+ name = state["name"]
429
+ static_kwargs = state["static_kwargs"]
430
+ build_module_src = state["build_module_src"]
431
+ build_func_name = state["build_func_name"]
432
+
433
+ # Create temporary module from the imported source code.
434
+ module_name = "_tflib_network_import_" + uuid.uuid4().hex
435
+ module = types.ModuleType(module_name)
436
+ sys.modules[module_name] = module
437
+ _import_module_src[module] = build_module_src
438
+ exec(build_module_src, module.__dict__) # pylint: disable=exec-used
439
+ build_func = util.get_obj_from_module(module, build_func_name)
440
+
441
+ # Initialize fields.
442
+ self._init_fields(name=name, static_kwargs=static_kwargs, build_func=build_func, build_func_name=build_func_name, build_module_src=build_module_src)
443
+ self._var_inits.update(copy.deepcopy(state["variables"]))
444
+ self._all_inits_known = True
445
+ self._components = util.EasyDict(state.get("components", {}))
446
+ self._input_shapes = copy.deepcopy(state.get("input_shapes", None))
447
+ self._output_shapes = copy.deepcopy(state.get("output_shapes", None))
448
+ self._input_names = copy.deepcopy(state.get("input_names", None))
449
+ self._output_names = copy.deepcopy(state.get("output_names", None))
450
+
451
+ def clone(self, name: str = None, **new_static_kwargs) -> "Network":
452
+ """Create a clone of this network with its own copy of the variables."""
453
+ static_kwargs = dict(self.static_kwargs)
454
+ static_kwargs.update(new_static_kwargs)
455
+ net = object.__new__(Network)
456
+ net._init_fields(name=(name or self.name), static_kwargs=static_kwargs, build_func=self._build_func, build_func_name=self._build_func_name, build_module_src=self._build_module_src)
457
+ net.copy_vars_from(self)
458
+ return net
459
+
460
+ def copy_own_vars_from(self, src_net: "Network") -> None:
461
+ """Copy the values of all variables from the given network, excluding sub-networks."""
462
+
463
+ # Source has unknown variables or unknown components => init now.
464
+ if (src_net._var_inits is not None and not src_net._all_inits_known) or src_net._components is None:
465
+ src_net._get_vars()
466
+
467
+ # Both networks are inited => copy directly.
468
+ if src_net._var_inits is None and self._var_inits is None:
469
+ names = [name for name in self._get_own_vars().keys() if name in src_net._get_own_vars()]
470
+ tfutil.set_vars(tfutil.run({self._get_vars()[name]: src_net._get_vars()[name] for name in names}))
471
+ return
472
+
473
+ # Read from source.
474
+ if src_net._var_inits is None:
475
+ value_dict = tfutil.run(src_net._get_own_vars())
476
+ else:
477
+ value_dict = src_net._var_inits
478
+
479
+ # Write to destination.
480
+ if self._var_inits is None:
481
+ tfutil.set_vars({self._get_vars()[name]: value for name, value in value_dict.items() if name in self._get_vars()})
482
+ else:
483
+ self._var_inits.update(value_dict)
484
+
485
+ def copy_vars_from(self, src_net: "Network") -> None:
486
+ """Copy the values of all variables from the given network, including sub-networks."""
487
+
488
+ # Source has unknown variables or unknown components => init now.
489
+ if (src_net._var_inits is not None and not src_net._all_inits_known) or src_net._components is None:
490
+ src_net._get_vars()
491
+
492
+ # Source is inited, but destination components have not been created yet => set as initial values.
493
+ if src_net._var_inits is None and self._components is None:
494
+ self._var_inits.update(tfutil.run(src_net._get_vars()))
495
+ return
496
+
497
+ # Destination has unknown components => init now.
498
+ if self._components is None:
499
+ self._get_vars()
500
+
501
+ # Both networks are inited => copy directly.
502
+ if src_net._var_inits is None and self._var_inits is None:
503
+ names = [name for name in self._get_vars().keys() if name in src_net._get_vars()]
504
+ tfutil.set_vars(tfutil.run({self._get_vars()[name]: src_net._get_vars()[name] for name in names}))
505
+ return
506
+
507
+ # Copy recursively, component by component.
508
+ self.copy_own_vars_from(src_net)
509
+ for name, src_comp in src_net._components.items():
510
+ if name in self._components:
511
+ self._components[name].copy_vars_from(src_comp)
512
+
513
+ def copy_trainables_from(self, src_net: "Network") -> None:
514
+ """Copy the values of all trainable variables from the given network, including sub-networks."""
515
+ names = [name for name in self._get_trainables().keys() if name in src_net._get_trainables()]
516
+ tfutil.set_vars(tfutil.run({self._get_vars()[name]: src_net._get_vars()[name] for name in names}))
517
+
518
+ def convert(self, new_func_name: str, new_name: str = None, **new_static_kwargs) -> "Network":
519
+ """Create new network with the given parameters, and copy all variables from this network."""
520
+ if new_name is None:
521
+ new_name = self.name
522
+ static_kwargs = dict(self.static_kwargs)
523
+ static_kwargs.update(new_static_kwargs)
524
+ net = Network(name=new_name, func_name=new_func_name, **static_kwargs)
525
+ net.copy_vars_from(self)
526
+ return net
527
+
528
+ def setup_as_moving_average_of(self, src_net: "Network", beta: TfExpressionEx = 0.99, beta_nontrainable: TfExpressionEx = 0.0) -> tf.Operation:
529
+ """Construct a TensorFlow op that updates the variables of this network
530
+ to be slightly closer to those of the given network."""
531
+ with tfutil.absolute_name_scope(self.scope + "/_MovingAvg"):
532
+ ops = []
533
+ for name, var in self._get_vars().items():
534
+ if name in src_net._get_vars():
535
+ cur_beta = beta if var.trainable else beta_nontrainable
536
+ new_value = tfutil.lerp(src_net._get_vars()[name], var, cur_beta)
537
+ ops.append(var.assign(new_value))
538
+ return tf.group(*ops)
539
+
540
+ def run(self,
541
+ *in_arrays: Tuple[Union[np.ndarray, None], ...],
542
+ input_transform: dict = None,
543
+ output_transform: dict = None,
544
+ return_as_list: bool = False,
545
+ print_progress: bool = False,
546
+ minibatch_size: int = None,
547
+ num_gpus: int = 1,
548
+ assume_frozen: bool = False,
549
+ **dynamic_kwargs) -> Union[np.ndarray, Tuple[np.ndarray, ...], List[np.ndarray]]:
550
+ """Run this network for the given NumPy array(s), and return the output(s) as NumPy array(s).
551
+
552
+ Args:
553
+ input_transform: A dict specifying a custom transformation to be applied to the input tensor(s) before evaluating the network.
554
+ The dict must contain a 'func' field that points to a top-level function. The function is called with the input
555
+ TensorFlow expression(s) as positional arguments. Any remaining fields of the dict will be passed in as kwargs.
556
+ output_transform: A dict specifying a custom transformation to be applied to the output tensor(s) after evaluating the network.
557
+ The dict must contain a 'func' field that points to a top-level function. The function is called with the output
558
+ TensorFlow expression(s) as positional arguments. Any remaining fields of the dict will be passed in as kwargs.
559
+ return_as_list: True = return a list of NumPy arrays, False = return a single NumPy array, or a tuple if there are multiple outputs.
560
+ print_progress: Print progress to the console? Useful for very large input arrays.
561
+ minibatch_size: Maximum minibatch size to use, None = disable batching.
562
+ num_gpus: Number of GPUs to use.
563
+ assume_frozen: Improve multi-GPU performance by assuming that the trainable parameters will remain changed between calls.
564
+ dynamic_kwargs: Additional keyword arguments to be passed into the network build function.
565
+ """
566
+ assert len(in_arrays) == self.num_inputs
567
+ assert not all(arr is None for arr in in_arrays)
568
+ assert input_transform is None or util.is_top_level_function(input_transform["func"])
569
+ assert output_transform is None or util.is_top_level_function(output_transform["func"])
570
+ output_transform, dynamic_kwargs = _handle_legacy_output_transforms(output_transform, dynamic_kwargs)
571
+ num_items = in_arrays[0].shape[0]
572
+ if minibatch_size is None:
573
+ minibatch_size = num_items
574
+
575
+ # Construct unique hash key from all arguments that affect the TensorFlow graph.
576
+ key = dict(input_transform=input_transform, output_transform=output_transform, num_gpus=num_gpus, assume_frozen=assume_frozen, dynamic_kwargs=dynamic_kwargs)
577
+ def unwind_key(obj):
578
+ if isinstance(obj, dict):
579
+ return [(key, unwind_key(value)) for key, value in sorted(obj.items())]
580
+ if callable(obj):
581
+ return util.get_top_level_function_name(obj)
582
+ return obj
583
+ key = repr(unwind_key(key))
584
+
585
+ # Build graph.
586
+ if key not in self._run_cache:
587
+ with tfutil.absolute_name_scope(self.scope + "/_Run"), tf.control_dependencies(None):
588
+ with tf.device("/cpu:0"):
589
+ in_expr = [tf.placeholder(tf.float32, name=name) for name in self.input_names]
590
+ in_split = list(zip(*[tf.split(x, num_gpus) for x in in_expr]))
591
+
592
+ out_split = []
593
+ for gpu in range(num_gpus):
594
+ with tf.device(self.device if num_gpus == 1 else "/gpu:%d" % gpu):
595
+ net_gpu = self.clone() if assume_frozen else self
596
+ in_gpu = in_split[gpu]
597
+
598
+ if input_transform is not None:
599
+ in_kwargs = dict(input_transform)
600
+ in_gpu = in_kwargs.pop("func")(*in_gpu, **in_kwargs)
601
+ in_gpu = [in_gpu] if tfutil.is_tf_expression(in_gpu) else list(in_gpu)
602
+
603
+ assert len(in_gpu) == self.num_inputs
604
+ out_gpu = net_gpu.get_output_for(*in_gpu, return_as_list=True, **dynamic_kwargs)
605
+
606
+ if output_transform is not None:
607
+ out_kwargs = dict(output_transform)
608
+ out_gpu = out_kwargs.pop("func")(*out_gpu, **out_kwargs)
609
+ out_gpu = [out_gpu] if tfutil.is_tf_expression(out_gpu) else list(out_gpu)
610
+
611
+ assert len(out_gpu) == self.num_outputs
612
+ out_split.append(out_gpu)
613
+
614
+ with tf.device("/cpu:0"):
615
+ out_expr = [tf.concat(outputs, axis=0) for outputs in zip(*out_split)]
616
+ self._run_cache[key] = in_expr, out_expr
617
+
618
+ # Run minibatches.
619
+ in_expr, out_expr = self._run_cache[key]
620
+ out_arrays = [np.empty([num_items] + expr.shape.as_list()[1:], expr.dtype.name) for expr in out_expr]
621
+
622
+ for mb_begin in range(0, num_items, minibatch_size):
623
+ if print_progress:
624
+ print("\r%d / %d" % (mb_begin, num_items), end="")
625
+
626
+ mb_end = min(mb_begin + minibatch_size, num_items)
627
+ mb_num = mb_end - mb_begin
628
+ mb_in = [src[mb_begin : mb_end] if src is not None else np.zeros([mb_num] + shape[1:]) for src, shape in zip(in_arrays, self.input_shapes)]
629
+ mb_out = tf.get_default_session().run(out_expr, dict(zip(in_expr, mb_in)))
630
+
631
+ for dst, src in zip(out_arrays, mb_out):
632
+ dst[mb_begin: mb_end] = src
633
+
634
+ # Done.
635
+ if print_progress:
636
+ print("\r%d / %d" % (num_items, num_items))
637
+
638
+ if not return_as_list:
639
+ out_arrays = out_arrays[0] if len(out_arrays) == 1 else tuple(out_arrays)
640
+ return out_arrays
641
+
642
+ def list_ops(self) -> List[TfExpression]:
643
+ _ = self.output_templates # ensure that the template graph has been created
644
+ include_prefix = self.scope + "/"
645
+ exclude_prefix = include_prefix + "_"
646
+ ops = tf.get_default_graph().get_operations()
647
+ ops = [op for op in ops if op.name.startswith(include_prefix)]
648
+ ops = [op for op in ops if not op.name.startswith(exclude_prefix)]
649
+ return ops
650
+
651
+ def list_layers(self) -> List[Tuple[str, TfExpression, List[TfExpression]]]:
652
+ """Returns a list of (layer_name, output_expr, trainable_vars) tuples corresponding to
653
+ individual layers of the network. Mainly intended to be used for reporting."""
654
+ layers = []
655
+
656
+ def recurse(scope, parent_ops, parent_vars, level):
657
+ if len(parent_ops) == 0 and len(parent_vars) == 0:
658
+ return
659
+
660
+ # Ignore specific patterns.
661
+ if any(p in scope for p in ["/Shape", "/strided_slice", "/Cast", "/concat", "/Assign"]):
662
+ return
663
+
664
+ # Filter ops and vars by scope.
665
+ global_prefix = scope + "/"
666
+ local_prefix = global_prefix[len(self.scope) + 1:]
667
+ cur_ops = [op for op in parent_ops if op.name.startswith(global_prefix) or op.name == global_prefix[:-1]]
668
+ cur_vars = [(name, var) for name, var in parent_vars if name.startswith(local_prefix) or name == local_prefix[:-1]]
669
+ if not cur_ops and not cur_vars:
670
+ return
671
+
672
+ # Filter out all ops related to variables.
673
+ for var in [op for op in cur_ops if op.type.startswith("Variable")]:
674
+ var_prefix = var.name + "/"
675
+ cur_ops = [op for op in cur_ops if not op.name.startswith(var_prefix)]
676
+
677
+ # Scope does not contain ops as immediate children => recurse deeper.
678
+ contains_direct_ops = any("/" not in op.name[len(global_prefix):] and op.type not in ["Identity", "Cast", "Transpose"] for op in cur_ops)
679
+ if (level == 0 or not contains_direct_ops) and (len(cur_ops) != 0 or len(cur_vars) != 0):
680
+ visited = set()
681
+ for rel_name in [op.name[len(global_prefix):] for op in cur_ops] + [name[len(local_prefix):] for name, _var in cur_vars]:
682
+ token = rel_name.split("/")[0]
683
+ if token not in visited:
684
+ recurse(global_prefix + token, cur_ops, cur_vars, level + 1)
685
+ visited.add(token)
686
+ return
687
+
688
+ # Report layer.
689
+ layer_name = scope[len(self.scope) + 1:]
690
+ layer_output = cur_ops[-1].outputs[0] if cur_ops else cur_vars[-1][1]
691
+ layer_trainables = [var for _name, var in cur_vars if var.trainable]
692
+ layers.append((layer_name, layer_output, layer_trainables))
693
+
694
+ recurse(self.scope, self.list_ops(), list(self._get_vars().items()), 0)
695
+ return layers
696
+
697
+ def print_layers(self, title: str = None, hide_layers_with_no_params: bool = False) -> None:
698
+ """Print a summary table of the network structure."""
699
+ rows = [[title if title is not None else self.name, "Params", "OutputShape", "WeightShape"]]
700
+ rows += [["---"] * 4]
701
+ total_params = 0
702
+
703
+ for layer_name, layer_output, layer_trainables in self.list_layers():
704
+ num_params = sum(int(np.prod(var.shape.as_list())) for var in layer_trainables)
705
+ weights = [var for var in layer_trainables if var.name.endswith("/weight:0")]
706
+ weights.sort(key=lambda x: len(x.name))
707
+ if len(weights) == 0 and len(layer_trainables) == 1:
708
+ weights = layer_trainables
709
+ total_params += num_params
710
+
711
+ if not hide_layers_with_no_params or num_params != 0:
712
+ num_params_str = str(num_params) if num_params > 0 else "-"
713
+ output_shape_str = str(layer_output.shape)
714
+ weight_shape_str = str(weights[0].shape) if len(weights) >= 1 else "-"
715
+ rows += [[layer_name, num_params_str, output_shape_str, weight_shape_str]]
716
+
717
+ rows += [["---"] * 4]
718
+ rows += [["Total", str(total_params), "", ""]]
719
+
720
+ widths = [max(len(cell) for cell in column) for column in zip(*rows)]
721
+ print()
722
+ for row in rows:
723
+ print(" ".join(cell + " " * (width - len(cell)) for cell, width in zip(row, widths)))
724
+ print()
725
+
726
+ def setup_weight_histograms(self, title: str = None) -> None:
727
+ """Construct summary ops to include histograms of all trainable parameters in TensorBoard."""
728
+ if title is None:
729
+ title = self.name
730
+
731
+ with tf.name_scope(None), tf.device(None), tf.control_dependencies(None):
732
+ for local_name, var in self._get_trainables().items():
733
+ if "/" in local_name:
734
+ p = local_name.split("/")
735
+ name = title + "_" + p[-1] + "/" + "_".join(p[:-1])
736
+ else:
737
+ name = title + "_toplevel/" + local_name
738
+
739
+ tf.summary.histogram(name, var)
740
+
741
+ #----------------------------------------------------------------------------
742
+ # Backwards-compatible emulation of legacy output transformation in Network.run().
743
+
744
+ _print_legacy_warning = True
745
+
746
+ def _handle_legacy_output_transforms(output_transform, dynamic_kwargs):
747
+ global _print_legacy_warning
748
+ legacy_kwargs = ["out_mul", "out_add", "out_shrink", "out_dtype"]
749
+ if not any(kwarg in dynamic_kwargs for kwarg in legacy_kwargs):
750
+ return output_transform, dynamic_kwargs
751
+
752
+ if _print_legacy_warning:
753
+ _print_legacy_warning = False
754
+ print()
755
+ print("WARNING: Old-style output transformations in Network.run() are deprecated.")
756
+ print("Consider using 'output_transform=dict(func=tflib.convert_images_to_uint8)'")
757
+ print("instead of 'out_mul=127.5, out_add=127.5, out_dtype=np.uint8'.")
758
+ print()
759
+ assert output_transform is None
760
+
761
+ new_kwargs = dict(dynamic_kwargs)
762
+ new_transform = {kwarg: new_kwargs.pop(kwarg) for kwarg in legacy_kwargs if kwarg in dynamic_kwargs}
763
+ new_transform["func"] = _legacy_output_transform_func
764
+ return new_transform, new_kwargs
765
+
766
+ def _legacy_output_transform_func(*expr, out_mul=1.0, out_add=0.0, out_shrink=1, out_dtype=None):
767
+ if out_mul != 1.0:
768
+ expr = [x * out_mul for x in expr]
769
+
770
+ if out_add != 0.0:
771
+ expr = [x + out_add for x in expr]
772
+
773
+ if out_shrink > 1:
774
+ ksize = [1, 1, out_shrink, out_shrink]
775
+ expr = [tf.nn.avg_pool(x, ksize=ksize, strides=ksize, padding="VALID", data_format="NCHW") for x in expr]
776
+
777
+ if out_dtype is not None:
778
+ if tf.as_dtype(out_dtype).is_integer:
779
+ expr = [tf.round(x) for x in expr]
780
+ expr = [tf.saturate_cast(x, out_dtype) for x in expr]
781
+ return expr
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ # empty
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/fused_bias_act.cu ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ //
3
+ // NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ // and proprietary rights in and to this software, related documentation
5
+ // and any modifications thereto. Any use, reproduction, disclosure or
6
+ // distribution of this software and related documentation without an express
7
+ // license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ #define EIGEN_USE_GPU
10
+ #define __CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__
11
+ #include "tensorflow/core/framework/op.h"
12
+ #include "tensorflow/core/framework/op_kernel.h"
13
+ #include "tensorflow/core/framework/shape_inference.h"
14
+ #include <stdio.h>
15
+
16
+ using namespace tensorflow;
17
+ using namespace tensorflow::shape_inference;
18
+
19
+ #define OP_CHECK_CUDA_ERROR(CTX, CUDA_CALL) do { cudaError_t err = CUDA_CALL; OP_REQUIRES(CTX, err == cudaSuccess, errors::Internal(cudaGetErrorName(err))); } while (false)
20
+
21
+ //------------------------------------------------------------------------
22
+ // CUDA kernel.
23
+
24
+ template <class T>
25
+ struct FusedBiasActKernelParams
26
+ {
27
+ const T* x; // [sizeX]
28
+ const T* b; // [sizeB] or NULL
29
+ const T* xref; // [sizeX] or NULL
30
+ const T* yref; // [sizeX] or NULL
31
+ T* y; // [sizeX]
32
+
33
+ int grad;
34
+ int axis;
35
+ int act;
36
+ float alpha;
37
+ float gain;
38
+ float clamp;
39
+
40
+ int sizeX;
41
+ int sizeB;
42
+ int stepB;
43
+ int loopX;
44
+ };
45
+
46
+ template <class T>
47
+ static __global__ void FusedBiasActKernel(const FusedBiasActKernelParams<T> p)
48
+ {
49
+ const float expRange = 80.0f;
50
+ const float halfExpRange = 40.0f;
51
+ const float seluScale = 1.0507009873554804934193349852946f;
52
+ const float seluAlpha = 1.6732632423543772848170429916717f;
53
+
54
+ // Loop over elements.
55
+ int xi = blockIdx.x * p.loopX * blockDim.x + threadIdx.x;
56
+ for (int loopIdx = 0; loopIdx < p.loopX && xi < p.sizeX; loopIdx++, xi += blockDim.x)
57
+ {
58
+ // Load and apply bias.
59
+ float x = (float)p.x[xi];
60
+ if (p.b)
61
+ x += (float)p.b[(xi / p.stepB) % p.sizeB];
62
+ float xref = (p.xref) ? (float)p.xref[xi] : 0.0f;
63
+ float yref = (p.yref) ? (float)p.yref[xi] : 0.0f;
64
+ float yy = (p.gain != 0.0f) ? yref / p.gain : 0.0f;
65
+
66
+ // Evaluate activation func.
67
+ float y;
68
+ switch (p.act * 10 + p.grad)
69
+ {
70
+ // linear
71
+ default:
72
+ case 10: y = x; break;
73
+ case 11: y = x; break;
74
+ case 12: y = 0.0f; break;
75
+
76
+ // relu
77
+ case 20: y = (x > 0.0f) ? x : 0.0f; break;
78
+ case 21: y = (yy > 0.0f) ? x : 0.0f; break;
79
+ case 22: y = 0.0f; break;
80
+
81
+ // lrelu
82
+ case 30: y = (x > 0.0f) ? x : x * p.alpha; break;
83
+ case 31: y = (yy > 0.0f) ? x : x * p.alpha; break;
84
+ case 32: y = 0.0f; break;
85
+
86
+ // tanh
87
+ case 40: { float c = expf(x); float d = 1.0f / c; y = (x < -expRange) ? -1.0f : (x > expRange) ? 1.0f : (c - d) / (c + d); } break;
88
+ case 41: y = x * (1.0f - yy * yy); break;
89
+ case 42: y = x * (1.0f - yy * yy) * (-2.0f * yy); break;
90
+
91
+ // sigmoid
92
+ case 50: y = (x < -expRange) ? 0.0f : 1.0f / (expf(-x) + 1.0f); break;
93
+ case 51: y = x * yy * (1.0f - yy); break;
94
+ case 52: y = x * yy * (1.0f - yy) * (1.0f - 2.0f * yy); break;
95
+
96
+ // elu
97
+ case 60: y = (x >= 0.0f) ? x : expf(x) - 1.0f; break;
98
+ case 61: y = (yy >= 0.0f) ? x : x * (yy + 1.0f); break;
99
+ case 62: y = (yy >= 0.0f) ? 0.0f : x * (yy + 1.0f); break;
100
+
101
+ // selu
102
+ case 70: y = (x >= 0.0f) ? seluScale * x : (seluScale * seluAlpha) * (expf(x) - 1.0f); break;
103
+ case 71: y = (yy >= 0.0f) ? x * seluScale : x * (yy + seluScale * seluAlpha); break;
104
+ case 72: y = (yy >= 0.0f) ? 0.0f : x * (yy + seluScale * seluAlpha); break;
105
+
106
+ // softplus
107
+ case 80: y = (x > expRange) ? x : logf(expf(x) + 1.0f); break;
108
+ case 81: y = x * (1.0f - expf(-yy)); break;
109
+ case 82: { float c = expf(-yy); y = x * c * (1.0f - c); } break;
110
+
111
+ // swish
112
+ case 90: y = (x < -expRange) ? 0.0f : x / (expf(-x) + 1.0f); break;
113
+ case 91:
114
+ case 92:
115
+ {
116
+ float c = expf(xref);
117
+ float d = c + 1.0f;
118
+ if (p.grad == 1)
119
+ y = (xref > halfExpRange) ? x : x * c * (xref + d) / (d * d);
120
+ else
121
+ y = (xref > halfExpRange) ? 0.0f : x * c * (xref * (2.0f - d) + 2.0f * d) / (d * d * d);
122
+ yref = (xref < -expRange) ? 0.0f : xref / (expf(-xref) + 1.0f) * p.gain;
123
+ }
124
+ break;
125
+ }
126
+
127
+ // Apply gain.
128
+ y *= p.gain;
129
+
130
+ // Clamp.
131
+ if (p.clamp >= 0.0f)
132
+ {
133
+ if (p.grad == 0)
134
+ y = (fabsf(y) < p.clamp) ? y : (y >= 0.0f) ? p.clamp : -p.clamp;
135
+ else
136
+ y = (fabsf(yref) < p.clamp) ? y : 0.0f;
137
+ }
138
+
139
+ // Store.
140
+ p.y[xi] = (T)y;
141
+ }
142
+ }
143
+
144
+ //------------------------------------------------------------------------
145
+ // TensorFlow op.
146
+
147
+ template <class T>
148
+ struct FusedBiasActOp : public OpKernel
149
+ {
150
+ FusedBiasActKernelParams<T> m_attribs;
151
+
152
+ FusedBiasActOp(OpKernelConstruction* ctx) : OpKernel(ctx)
153
+ {
154
+ memset(&m_attribs, 0, sizeof(m_attribs));
155
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("grad", &m_attribs.grad));
156
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("axis", &m_attribs.axis));
157
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("act", &m_attribs.act));
158
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("alpha", &m_attribs.alpha));
159
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("gain", &m_attribs.gain));
160
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("clamp", &m_attribs.clamp));
161
+ OP_REQUIRES(ctx, m_attribs.grad >= 0, errors::InvalidArgument("grad must be non-negative"));
162
+ OP_REQUIRES(ctx, m_attribs.axis >= 0, errors::InvalidArgument("axis must be non-negative"));
163
+ OP_REQUIRES(ctx, m_attribs.act >= 0, errors::InvalidArgument("act must be non-negative"));
164
+ }
165
+
166
+ void Compute(OpKernelContext* ctx)
167
+ {
168
+ FusedBiasActKernelParams<T> p = m_attribs;
169
+ cudaStream_t stream = ctx->eigen_device<Eigen::GpuDevice>().stream();
170
+
171
+ const Tensor& x = ctx->input(0); // [...]
172
+ const Tensor& b = ctx->input(1); // [sizeB] or [0]
173
+ const Tensor& xref = ctx->input(2); // x.shape or [0]
174
+ const Tensor& yref = ctx->input(3); // x.shape or [0]
175
+ p.x = x.flat<T>().data();
176
+ p.b = (b.NumElements()) ? b.flat<T>().data() : NULL;
177
+ p.xref = (xref.NumElements()) ? xref.flat<T>().data() : NULL;
178
+ p.yref = (yref.NumElements()) ? yref.flat<T>().data() : NULL;
179
+ OP_REQUIRES(ctx, b.NumElements() == 0 || m_attribs.axis < x.dims(), errors::InvalidArgument("axis out of bounds"));
180
+ OP_REQUIRES(ctx, b.dims() == 1, errors::InvalidArgument("b must have rank 1"));
181
+ OP_REQUIRES(ctx, b.NumElements() == 0 || b.NumElements() == x.dim_size(m_attribs.axis), errors::InvalidArgument("b has wrong number of elements"));
182
+ OP_REQUIRES(ctx, xref.NumElements() == 0 || xref.NumElements() == x.NumElements(), errors::InvalidArgument("xref has wrong number of elements"));
183
+ OP_REQUIRES(ctx, yref.NumElements() == 0 || yref.NumElements() == x.NumElements(), errors::InvalidArgument("yref has wrong number of elements"));
184
+ OP_REQUIRES(ctx, x.NumElements() <= kint32max, errors::InvalidArgument("x is too large"));
185
+
186
+ p.sizeX = (int)x.NumElements();
187
+ p.sizeB = (int)b.NumElements();
188
+ p.stepB = 1;
189
+ for (int i = m_attribs.axis + 1; i < x.dims(); i++)
190
+ p.stepB *= (int)x.dim_size(i);
191
+
192
+ Tensor* y = NULL; // x.shape
193
+ OP_REQUIRES_OK(ctx, ctx->allocate_output(0, x.shape(), &y));
194
+ p.y = y->flat<T>().data();
195
+
196
+ p.loopX = 4;
197
+ int blockSize = 4 * 32;
198
+ int gridSize = (p.sizeX - 1) / (p.loopX * blockSize) + 1;
199
+ void* args[] = {&p};
200
+ OP_CHECK_CUDA_ERROR(ctx, cudaLaunchKernel((void*)FusedBiasActKernel<T>, gridSize, blockSize, args, 0, stream));
201
+ }
202
+ };
203
+
204
+ REGISTER_OP("FusedBiasAct")
205
+ .Input ("x: T")
206
+ .Input ("b: T")
207
+ .Input ("xref: T")
208
+ .Input ("yref: T")
209
+ .Output ("y: T")
210
+ .Attr ("T: {float, half}")
211
+ .Attr ("grad: int = 0")
212
+ .Attr ("axis: int = 1")
213
+ .Attr ("act: int = 0")
214
+ .Attr ("alpha: float = 0.0")
215
+ .Attr ("gain: float = 1.0")
216
+ .Attr ("clamp: float = -1.0");
217
+ REGISTER_KERNEL_BUILDER(Name("FusedBiasAct").Device(DEVICE_GPU).TypeConstraint<float>("T"), FusedBiasActOp<float>);
218
+ REGISTER_KERNEL_BUILDER(Name("FusedBiasAct").Device(DEVICE_GPU).TypeConstraint<Eigen::half>("T"), FusedBiasActOp<Eigen::half>);
219
+
220
+ //------------------------------------------------------------------------
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/fused_bias_act.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Custom TensorFlow ops for efficient bias and activation."""
10
+
11
+ import os
12
+ import numpy as np
13
+ import tensorflow as tf
14
+ from .. import custom_ops
15
+ from ...util import EasyDict
16
+
17
+ def _get_plugin():
18
+ return custom_ops.get_plugin(os.path.splitext(__file__)[0] + '.cu')
19
+
20
+ #----------------------------------------------------------------------------
21
+
22
+ activation_funcs = {
23
+ 'linear': EasyDict(func=lambda x, **_: x, def_alpha=None, def_gain=1.0, cuda_idx=1, ref='y', zero_2nd_grad=True),
24
+ 'relu': EasyDict(func=lambda x, **_: tf.nn.relu(x), def_alpha=None, def_gain=np.sqrt(2), cuda_idx=2, ref='y', zero_2nd_grad=True),
25
+ 'lrelu': EasyDict(func=lambda x, alpha, **_: tf.nn.leaky_relu(x, alpha), def_alpha=0.2, def_gain=np.sqrt(2), cuda_idx=3, ref='y', zero_2nd_grad=True),
26
+ 'tanh': EasyDict(func=lambda x, **_: tf.nn.tanh(x), def_alpha=None, def_gain=1.0, cuda_idx=4, ref='y', zero_2nd_grad=False),
27
+ 'sigmoid': EasyDict(func=lambda x, **_: tf.nn.sigmoid(x), def_alpha=None, def_gain=1.0, cuda_idx=5, ref='y', zero_2nd_grad=False),
28
+ 'elu': EasyDict(func=lambda x, **_: tf.nn.elu(x), def_alpha=None, def_gain=1.0, cuda_idx=6, ref='y', zero_2nd_grad=False),
29
+ 'selu': EasyDict(func=lambda x, **_: tf.nn.selu(x), def_alpha=None, def_gain=1.0, cuda_idx=7, ref='y', zero_2nd_grad=False),
30
+ 'softplus': EasyDict(func=lambda x, **_: tf.nn.softplus(x), def_alpha=None, def_gain=1.0, cuda_idx=8, ref='y', zero_2nd_grad=False),
31
+ 'swish': EasyDict(func=lambda x, **_: tf.nn.sigmoid(x) * x, def_alpha=None, def_gain=np.sqrt(2), cuda_idx=9, ref='x', zero_2nd_grad=False),
32
+ }
33
+
34
+ #----------------------------------------------------------------------------
35
+
36
+ def fused_bias_act(x, b=None, axis=1, act='linear', alpha=None, gain=None, clamp=None, impl='cuda'):
37
+ r"""Fused bias and activation function.
38
+
39
+ Adds bias `b` to activation tensor `x`, evaluates activation function `act`,
40
+ and scales the result by `gain`. Each of the steps is optional. In most cases,
41
+ the fused op is considerably more efficient than performing the same calculation
42
+ using standard TensorFlow ops. It supports first and second order gradients,
43
+ but not third order gradients.
44
+
45
+ Args:
46
+ x: Input activation tensor. Can have any shape, but if `b` is defined, the
47
+ dimension corresponding to `axis`, as well as the rank, must be known.
48
+ b: Bias vector, or `None` to disable. Must be a 1D tensor of the same type
49
+ as `x`. The shape must be known, and it must match the dimension of `x`
50
+ corresponding to `axis`.
51
+ axis: The dimension in `x` corresponding to the elements of `b`.
52
+ The value of `axis` is ignored if `b` is not specified.
53
+ act: Name of the activation function to evaluate, or `"linear"` to disable.
54
+ Can be e.g. `"relu"`, `"lrelu"`, `"tanh"`, `"sigmoid"`, `"swish"`, etc.
55
+ See `activation_funcs` for a full list. `None` is not allowed.
56
+ alpha: Shape parameter for the activation function, or `None` to use the default.
57
+ gain: Scaling factor for the output tensor, or `None` to use default.
58
+ See `activation_funcs` for the default scaling of each activation function.
59
+ If unsure, consider specifying `1.0`.
60
+ clamp: Clamp the output values to `[-clamp, +clamp]`, or `None` to disable
61
+ the clamping (default).
62
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
63
+
64
+ Returns:
65
+ Tensor of the same shape and datatype as `x`.
66
+ """
67
+
68
+ impl_dict = {
69
+ 'ref': _fused_bias_act_ref,
70
+ 'cuda': _fused_bias_act_cuda,
71
+ }
72
+ return impl_dict[impl](x=x, b=b, axis=axis, act=act, alpha=alpha, gain=gain, clamp=clamp)
73
+
74
+ #----------------------------------------------------------------------------
75
+
76
+ def _fused_bias_act_ref(x, b, axis, act, alpha, gain, clamp):
77
+ """Slow reference implementation of `fused_bias_act()` using standard TensorFlow ops."""
78
+
79
+ # Validate arguments.
80
+ x = tf.convert_to_tensor(x)
81
+ b = tf.convert_to_tensor(b) if b is not None else tf.constant([], dtype=x.dtype)
82
+ act_spec = activation_funcs[act]
83
+ assert b.shape.rank == 1 and (b.shape[0] == 0 or b.shape[0] == x.shape[axis])
84
+ assert b.shape[0] == 0 or 0 <= axis < x.shape.rank
85
+ if alpha is None:
86
+ alpha = act_spec.def_alpha
87
+ if gain is None:
88
+ gain = act_spec.def_gain
89
+
90
+ # Add bias.
91
+ if b.shape[0] != 0:
92
+ x += tf.reshape(b, [-1 if i == axis else 1 for i in range(x.shape.rank)])
93
+
94
+ # Evaluate activation function.
95
+ x = act_spec.func(x, alpha=alpha)
96
+
97
+ # Scale by gain.
98
+ if gain != 1:
99
+ x *= gain
100
+
101
+ # Clamp.
102
+ if clamp is not None:
103
+ clamp = np.asarray(clamp, dtype=x.dtype.name)
104
+ assert clamp.shape == () and clamp >= 0
105
+ x = tf.clip_by_value(x, -clamp, clamp)
106
+ return x
107
+
108
+ #----------------------------------------------------------------------------
109
+
110
+ def _fused_bias_act_cuda(x, b, axis, act, alpha, gain, clamp):
111
+ """Fast CUDA implementation of `fused_bias_act()` using custom ops."""
112
+
113
+ # Validate arguments.
114
+ x = tf.convert_to_tensor(x)
115
+ empty_tensor = tf.constant([], dtype=x.dtype)
116
+ b = tf.convert_to_tensor(b) if b is not None else empty_tensor
117
+ act_spec = activation_funcs[act]
118
+ assert b.shape.rank == 1 and (b.shape[0] == 0 or b.shape[0] == x.shape[axis])
119
+ assert b.shape[0] == 0 or 0 <= axis < x.shape.rank
120
+ if alpha is None:
121
+ alpha = act_spec.def_alpha
122
+ if gain is None:
123
+ gain = act_spec.def_gain
124
+
125
+ # Special cases.
126
+ if act == 'linear' and b is None and gain == 1.0:
127
+ return x
128
+ if act_spec.cuda_idx is None:
129
+ return _fused_bias_act_ref(x=x, b=b, axis=axis, act=act, alpha=alpha, gain=gain, clamp=clamp)
130
+
131
+ # CUDA op.
132
+ cuda_op = _get_plugin().fused_bias_act
133
+ cuda_kwargs = dict(axis=int(axis), act=int(act_spec.cuda_idx), gain=float(gain))
134
+ if alpha is not None:
135
+ cuda_kwargs['alpha'] = float(alpha)
136
+ if clamp is not None:
137
+ clamp = np.asarray(clamp, dtype=x.dtype.name)
138
+ assert clamp.shape == () and clamp >= 0
139
+ cuda_kwargs['clamp'] = float(clamp.astype(np.float32))
140
+ def ref(tensor, name):
141
+ return tensor if act_spec.ref == name else empty_tensor
142
+
143
+ # Forward pass: y = func(x, b).
144
+ def func_y(x, b):
145
+ y = cuda_op(x=x, b=b, xref=empty_tensor, yref=empty_tensor, grad=0, **cuda_kwargs)
146
+ y.set_shape(x.shape)
147
+ return y
148
+
149
+ # Backward pass: dx, db = grad(dy, x, y)
150
+ def grad_dx(dy, x, y):
151
+ dx = cuda_op(x=dy, b=empty_tensor, xref=ref(x,'x'), yref=ref(y,'y'), grad=1, **cuda_kwargs)
152
+ dx.set_shape(x.shape)
153
+ return dx
154
+ def grad_db(dx):
155
+ if b.shape[0] == 0:
156
+ return empty_tensor
157
+ db = dx
158
+ if axis < x.shape.rank - 1:
159
+ db = tf.reduce_sum(db, list(range(axis + 1, x.shape.rank)))
160
+ if axis > 0:
161
+ db = tf.reduce_sum(db, list(range(axis)))
162
+ db.set_shape(b.shape)
163
+ return db
164
+
165
+ # Second order gradients: d_dy, d_x = grad2(d_dx, d_db, x, y)
166
+ def grad2_d_dy(d_dx, d_db, x, y):
167
+ d_dy = cuda_op(x=d_dx, b=d_db, xref=ref(x,'x'), yref=ref(y,'y'), grad=1, **cuda_kwargs)
168
+ d_dy.set_shape(x.shape)
169
+ return d_dy
170
+ def grad2_d_x(d_dx, d_db, x, y):
171
+ d_x = cuda_op(x=d_dx, b=d_db, xref=ref(x,'x'), yref=ref(y,'y'), grad=2, **cuda_kwargs)
172
+ d_x.set_shape(x.shape)
173
+ return d_x
174
+
175
+ # Fast version for piecewise-linear activation funcs.
176
+ @tf.custom_gradient
177
+ def func_zero_2nd_grad(x, b):
178
+ y = func_y(x, b)
179
+ @tf.custom_gradient
180
+ def grad(dy):
181
+ dx = grad_dx(dy, x, y)
182
+ db = grad_db(dx)
183
+ def grad2(d_dx, d_db):
184
+ d_dy = grad2_d_dy(d_dx, d_db, x, y)
185
+ return d_dy
186
+ return (dx, db), grad2
187
+ return y, grad
188
+
189
+ # Slow version for general activation funcs.
190
+ @tf.custom_gradient
191
+ def func_nonzero_2nd_grad(x, b):
192
+ y = func_y(x, b)
193
+ def grad_wrap(dy):
194
+ @tf.custom_gradient
195
+ def grad_impl(dy, x):
196
+ dx = grad_dx(dy, x, y)
197
+ db = grad_db(dx)
198
+ def grad2(d_dx, d_db):
199
+ d_dy = grad2_d_dy(d_dx, d_db, x, y)
200
+ d_x = grad2_d_x(d_dx, d_db, x, y)
201
+ return d_dy, d_x
202
+ return (dx, db), grad2
203
+ return grad_impl(dy, x)
204
+ return y, grad_wrap
205
+
206
+ # Which version to use?
207
+ if act_spec.zero_2nd_grad:
208
+ return func_zero_2nd_grad(x, b)
209
+ return func_nonzero_2nd_grad(x, b)
210
+
211
+ #----------------------------------------------------------------------------
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/upfirdn_2d.cu ADDED
@@ -0,0 +1,359 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ //
3
+ // NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ // and proprietary rights in and to this software, related documentation
5
+ // and any modifications thereto. Any use, reproduction, disclosure or
6
+ // distribution of this software and related documentation without an express
7
+ // license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ #define EIGEN_USE_GPU
10
+ #define __CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__
11
+ #include "tensorflow/core/framework/op.h"
12
+ #include "tensorflow/core/framework/op_kernel.h"
13
+ #include "tensorflow/core/framework/shape_inference.h"
14
+ #include <stdio.h>
15
+
16
+ using namespace tensorflow;
17
+ using namespace tensorflow::shape_inference;
18
+
19
+ //------------------------------------------------------------------------
20
+ // Helpers.
21
+
22
+ #define OP_CHECK_CUDA_ERROR(CTX, CUDA_CALL) do { cudaError_t err = CUDA_CALL; OP_REQUIRES(CTX, err == cudaSuccess, errors::Internal(cudaGetErrorName(err))); } while (false)
23
+
24
+ static __host__ __device__ __forceinline__ int floorDiv(int a, int b)
25
+ {
26
+ int t = 1 - a / b;
27
+ return (a + t * b) / b - t;
28
+ }
29
+
30
+ //------------------------------------------------------------------------
31
+ // CUDA kernel params.
32
+
33
+ template <class T>
34
+ struct UpFirDn2DKernelParams
35
+ {
36
+ const T* x; // [majorDim, inH, inW, minorDim]
37
+ const T* k; // [kernelH, kernelW]
38
+ T* y; // [majorDim, outH, outW, minorDim]
39
+
40
+ int upx;
41
+ int upy;
42
+ int downx;
43
+ int downy;
44
+ int padx0;
45
+ int padx1;
46
+ int pady0;
47
+ int pady1;
48
+
49
+ int majorDim;
50
+ int inH;
51
+ int inW;
52
+ int minorDim;
53
+ int kernelH;
54
+ int kernelW;
55
+ int outH;
56
+ int outW;
57
+ int loopMajor;
58
+ int loopX;
59
+ };
60
+
61
+ //------------------------------------------------------------------------
62
+ // General CUDA implementation for large filter kernels.
63
+
64
+ template <class T>
65
+ static __global__ void UpFirDn2DKernel_large(const UpFirDn2DKernelParams<T> p)
66
+ {
67
+ // Calculate thread index.
68
+ int minorIdx = blockIdx.x * blockDim.x + threadIdx.x;
69
+ int outY = minorIdx / p.minorDim;
70
+ minorIdx -= outY * p.minorDim;
71
+ int outXBase = blockIdx.y * p.loopX * blockDim.y + threadIdx.y;
72
+ int majorIdxBase = blockIdx.z * p.loopMajor;
73
+ if (outXBase >= p.outW || outY >= p.outH || majorIdxBase >= p.majorDim)
74
+ return;
75
+
76
+ // Setup Y receptive field.
77
+ int midY = outY * p.downy + p.upy - 1 - p.pady0;
78
+ int inY = min(max(floorDiv(midY, p.upy), 0), p.inH);
79
+ int h = min(max(floorDiv(midY + p.kernelH, p.upy), 0), p.inH) - inY;
80
+ int kernelY = midY + p.kernelH - (inY + 1) * p.upy;
81
+
82
+ // Loop over majorDim and outX.
83
+ for (int loopMajor = 0, majorIdx = majorIdxBase; loopMajor < p.loopMajor && majorIdx < p.majorDim; loopMajor++, majorIdx++)
84
+ for (int loopX = 0, outX = outXBase; loopX < p.loopX && outX < p.outW; loopX++, outX += blockDim.y)
85
+ {
86
+ // Setup X receptive field.
87
+ int midX = outX * p.downx + p.upx - 1 - p.padx0;
88
+ int inX = min(max(floorDiv(midX, p.upx), 0), p.inW);
89
+ int w = min(max(floorDiv(midX + p.kernelW, p.upx), 0), p.inW) - inX;
90
+ int kernelX = midX + p.kernelW - (inX + 1) * p.upx;
91
+
92
+ // Initialize pointers.
93
+ const T* xp = &p.x[((majorIdx * p.inH + inY) * p.inW + inX) * p.minorDim + minorIdx];
94
+ const T* kp = &p.k[kernelY * p.kernelW + kernelX];
95
+ int xpx = p.minorDim;
96
+ int kpx = -p.upx;
97
+ int xpy = p.inW * p.minorDim;
98
+ int kpy = -p.upy * p.kernelW;
99
+
100
+ // Inner loop.
101
+ float v = 0.0f;
102
+ for (int y = 0; y < h; y++)
103
+ {
104
+ for (int x = 0; x < w; x++)
105
+ {
106
+ v += (float)(*xp) * (float)(*kp);
107
+ xp += xpx;
108
+ kp += kpx;
109
+ }
110
+ xp += xpy - w * xpx;
111
+ kp += kpy - w * kpx;
112
+ }
113
+
114
+ // Store result.
115
+ p.y[((majorIdx * p.outH + outY) * p.outW + outX) * p.minorDim + minorIdx] = (T)v;
116
+ }
117
+ }
118
+
119
+ //------------------------------------------------------------------------
120
+ // Specialized CUDA implementation for small filter kernels.
121
+
122
+ template <class T, int upx, int upy, int downx, int downy, int kernelW, int kernelH, int tileOutW, int tileOutH>
123
+ static __global__ void UpFirDn2DKernel_small(const UpFirDn2DKernelParams<T> p)
124
+ {
125
+ //assert(kernelW % upx == 0);
126
+ //assert(kernelH % upy == 0);
127
+ const int tileInW = ((tileOutW - 1) * downx + kernelW - 1) / upx + 1;
128
+ const int tileInH = ((tileOutH - 1) * downy + kernelH - 1) / upy + 1;
129
+ __shared__ volatile float sk[kernelH][kernelW];
130
+ __shared__ volatile float sx[tileInH][tileInW];
131
+
132
+ // Calculate tile index.
133
+ int minorIdx = blockIdx.x;
134
+ int tileOutY = minorIdx / p.minorDim;
135
+ minorIdx -= tileOutY * p.minorDim;
136
+ tileOutY *= tileOutH;
137
+ int tileOutXBase = blockIdx.y * p.loopX * tileOutW;
138
+ int majorIdxBase = blockIdx.z * p.loopMajor;
139
+ if (tileOutXBase >= p.outW | tileOutY >= p.outH | majorIdxBase >= p.majorDim)
140
+ return;
141
+
142
+ // Load filter kernel (flipped).
143
+ for (int tapIdx = threadIdx.x; tapIdx < kernelH * kernelW; tapIdx += blockDim.x)
144
+ {
145
+ int ky = tapIdx / kernelW;
146
+ int kx = tapIdx - ky * kernelW;
147
+ float v = 0.0f;
148
+ if (kx < p.kernelW & ky < p.kernelH)
149
+ v = (float)p.k[(p.kernelH - 1 - ky) * p.kernelW + (p.kernelW - 1 - kx)];
150
+ sk[ky][kx] = v;
151
+ }
152
+
153
+ // Loop over majorDim and outX.
154
+ for (int loopMajor = 0, majorIdx = majorIdxBase; loopMajor < p.loopMajor & majorIdx < p.majorDim; loopMajor++, majorIdx++)
155
+ for (int loopX = 0, tileOutX = tileOutXBase; loopX < p.loopX & tileOutX < p.outW; loopX++, tileOutX += tileOutW)
156
+ {
157
+ // Load input pixels.
158
+ int tileMidX = tileOutX * downx + upx - 1 - p.padx0;
159
+ int tileMidY = tileOutY * downy + upy - 1 - p.pady0;
160
+ int tileInX = floorDiv(tileMidX, upx);
161
+ int tileInY = floorDiv(tileMidY, upy);
162
+ __syncthreads();
163
+ for (int inIdx = threadIdx.x; inIdx < tileInH * tileInW; inIdx += blockDim.x)
164
+ {
165
+ int relInY = inIdx / tileInW;
166
+ int relInX = inIdx - relInY * tileInW;
167
+ int inX = relInX + tileInX;
168
+ int inY = relInY + tileInY;
169
+ float v = 0.0f;
170
+ if (inX >= 0 & inY >= 0 & inX < p.inW & inY < p.inH)
171
+ v = (float)p.x[((majorIdx * p.inH + inY) * p.inW + inX) * p.minorDim + minorIdx];
172
+ sx[relInY][relInX] = v;
173
+ }
174
+
175
+ // Loop over output pixels.
176
+ __syncthreads();
177
+ for (int outIdx = threadIdx.x; outIdx < tileOutH * tileOutW; outIdx += blockDim.x)
178
+ {
179
+ int relOutY = outIdx / tileOutW;
180
+ int relOutX = outIdx - relOutY * tileOutW;
181
+ int outX = relOutX + tileOutX;
182
+ int outY = relOutY + tileOutY;
183
+
184
+ // Setup receptive field.
185
+ int midX = tileMidX + relOutX * downx;
186
+ int midY = tileMidY + relOutY * downy;
187
+ int inX = floorDiv(midX, upx);
188
+ int inY = floorDiv(midY, upy);
189
+ int relInX = inX - tileInX;
190
+ int relInY = inY - tileInY;
191
+ int kernelX = (inX + 1) * upx - midX - 1; // flipped
192
+ int kernelY = (inY + 1) * upy - midY - 1; // flipped
193
+
194
+ // Inner loop.
195
+ float v = 0.0f;
196
+ #pragma unroll
197
+ for (int y = 0; y < kernelH / upy; y++)
198
+ #pragma unroll
199
+ for (int x = 0; x < kernelW / upx; x++)
200
+ v += sx[relInY + y][relInX + x] * sk[kernelY + y * upy][kernelX + x * upx];
201
+
202
+ // Store result.
203
+ if (outX < p.outW & outY < p.outH)
204
+ p.y[((majorIdx * p.outH + outY) * p.outW + outX) * p.minorDim + minorIdx] = (T)v;
205
+ }
206
+ }
207
+ }
208
+
209
+ //------------------------------------------------------------------------
210
+ // TensorFlow op.
211
+
212
+ template <class T>
213
+ struct UpFirDn2DOp : public OpKernel
214
+ {
215
+ UpFirDn2DKernelParams<T> m_attribs;
216
+
217
+ UpFirDn2DOp(OpKernelConstruction* ctx) : OpKernel(ctx)
218
+ {
219
+ memset(&m_attribs, 0, sizeof(m_attribs));
220
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("upx", &m_attribs.upx));
221
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("upy", &m_attribs.upy));
222
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("downx", &m_attribs.downx));
223
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("downy", &m_attribs.downy));
224
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("padx0", &m_attribs.padx0));
225
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("padx1", &m_attribs.padx1));
226
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("pady0", &m_attribs.pady0));
227
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("pady1", &m_attribs.pady1));
228
+ OP_REQUIRES(ctx, m_attribs.upx >= 1 && m_attribs.upy >= 1, errors::InvalidArgument("upx and upy must be at least 1x1"));
229
+ OP_REQUIRES(ctx, m_attribs.downx >= 1 && m_attribs.downy >= 1, errors::InvalidArgument("downx and downy must be at least 1x1"));
230
+ }
231
+
232
+ void Compute(OpKernelContext* ctx)
233
+ {
234
+ UpFirDn2DKernelParams<T> p = m_attribs;
235
+ cudaStream_t stream = ctx->eigen_device<Eigen::GpuDevice>().stream();
236
+
237
+ const Tensor& x = ctx->input(0); // [majorDim, inH, inW, minorDim]
238
+ const Tensor& k = ctx->input(1); // [kernelH, kernelW]
239
+ p.x = x.flat<T>().data();
240
+ p.k = k.flat<T>().data();
241
+ OP_REQUIRES(ctx, x.dims() == 4, errors::InvalidArgument("input must have rank 4"));
242
+ OP_REQUIRES(ctx, k.dims() == 2, errors::InvalidArgument("kernel must have rank 2"));
243
+ OP_REQUIRES(ctx, x.NumElements() <= kint32max, errors::InvalidArgument("input too large"));
244
+ OP_REQUIRES(ctx, k.NumElements() <= kint32max, errors::InvalidArgument("kernel too large"));
245
+
246
+ p.majorDim = (int)x.dim_size(0);
247
+ p.inH = (int)x.dim_size(1);
248
+ p.inW = (int)x.dim_size(2);
249
+ p.minorDim = (int)x.dim_size(3);
250
+ p.kernelH = (int)k.dim_size(0);
251
+ p.kernelW = (int)k.dim_size(1);
252
+ OP_REQUIRES(ctx, p.kernelW >= 1 && p.kernelH >= 1, errors::InvalidArgument("kernel must be at least 1x1"));
253
+
254
+ p.outW = (p.inW * p.upx + p.padx0 + p.padx1 - p.kernelW + p.downx) / p.downx;
255
+ p.outH = (p.inH * p.upy + p.pady0 + p.pady1 - p.kernelH + p.downy) / p.downy;
256
+ OP_REQUIRES(ctx, p.outW >= 1 && p.outH >= 1, errors::InvalidArgument("output must be at least 1x1"));
257
+
258
+ Tensor* y = NULL; // [majorDim, outH, outW, minorDim]
259
+ TensorShape ys;
260
+ ys.AddDim(p.majorDim);
261
+ ys.AddDim(p.outH);
262
+ ys.AddDim(p.outW);
263
+ ys.AddDim(p.minorDim);
264
+ OP_REQUIRES_OK(ctx, ctx->allocate_output(0, ys, &y));
265
+ p.y = y->flat<T>().data();
266
+ OP_REQUIRES(ctx, y->NumElements() <= kint32max, errors::InvalidArgument("output too large"));
267
+
268
+ // Choose CUDA kernel to use.
269
+ void* cudaKernel = (void*)UpFirDn2DKernel_large<T>;
270
+ int tileOutW = -1;
271
+ int tileOutH = -1;
272
+
273
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 7 && p.kernelH <= 7 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 7,7, 64,16>; tileOutW = 64; tileOutH = 16; }
274
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 6 && p.kernelH <= 6 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 6,6, 64,16>; tileOutW = 64; tileOutH = 16; }
275
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 5 && p.kernelH <= 5 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 5,5, 64,16>; tileOutW = 64; tileOutH = 16; }
276
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 4 && p.kernelH <= 4 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 4,4, 64,16>; tileOutW = 64; tileOutH = 16; }
277
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 3 && p.kernelH <= 3 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 3,3, 64,16>; tileOutW = 64; tileOutH = 16; }
278
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 24 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 24,1, 128,8>; tileOutW = 128; tileOutH = 8; }
279
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 20 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 20,1, 128,8>; tileOutW = 128; tileOutH = 8; }
280
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 16 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 16,1, 128,8>; tileOutW = 128; tileOutH = 8; }
281
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 12 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 12,1, 128,8>; tileOutW = 128; tileOutH = 8; }
282
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 8 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 8,1, 128,8>; tileOutW = 128; tileOutH = 8; }
283
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 24) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 1,24, 32,32>; tileOutW = 32; tileOutH = 32; }
284
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 20) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 1,20, 32,32>; tileOutW = 32; tileOutH = 32; }
285
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 16) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 1,16, 32,32>; tileOutW = 32; tileOutH = 32; }
286
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 12) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 1,12, 32,32>; tileOutW = 32; tileOutH = 32; }
287
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 8 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,1, 1,8, 32,32>; tileOutW = 32; tileOutH = 32; }
288
+
289
+ if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 8 && p.kernelH <= 8 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,2, 1,1, 8,8, 64,16>; tileOutW = 64; tileOutH = 16; }
290
+ if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 6 && p.kernelH <= 6 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,2, 1,1, 6,6, 64,16>; tileOutW = 64; tileOutH = 16; }
291
+ if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 4 && p.kernelH <= 4 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,2, 1,1, 4,4, 64,16>; tileOutW = 64; tileOutH = 16; }
292
+ if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 2 && p.kernelH <= 2 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,2, 1,1, 2,2, 64,16>; tileOutW = 64; tileOutH = 16; }
293
+ if (p.upx == 2 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 24 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,1, 1,1, 24,1, 128,8>; tileOutW = 128; tileOutH = 8; }
294
+ if (p.upx == 2 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 20 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,1, 1,1, 20,1, 128,8>; tileOutW = 128; tileOutH = 8; }
295
+ if (p.upx == 2 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 16 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,1, 1,1, 16,1, 128,8>; tileOutW = 128; tileOutH = 8; }
296
+ if (p.upx == 2 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 12 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,1, 1,1, 12,1, 128,8>; tileOutW = 128; tileOutH = 8; }
297
+ if (p.upx == 2 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 8 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 2,1, 1,1, 8,1, 128,8>; tileOutW = 128; tileOutH = 8; }
298
+ if (p.upx == 1 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 24) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,2, 1,1, 1,24, 32,32>; tileOutW = 32; tileOutH = 32; }
299
+ if (p.upx == 1 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 20) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,2, 1,1, 1,20, 32,32>; tileOutW = 32; tileOutH = 32; }
300
+ if (p.upx == 1 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 16) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,2, 1,1, 1,16, 32,32>; tileOutW = 32; tileOutH = 32; }
301
+ if (p.upx == 1 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 12) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,2, 1,1, 1,12, 32,32>; tileOutW = 32; tileOutH = 32; }
302
+ if (p.upx == 1 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 1 && p.kernelH <= 8 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,2, 1,1, 1,8, 32,32>; tileOutW = 32; tileOutH = 32; }
303
+
304
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 8 && p.kernelH <= 8 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,2, 8,8, 32,8 >; tileOutW = 32; tileOutH = 8; }
305
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 6 && p.kernelH <= 6 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,2, 6,6, 32,8 >; tileOutW = 32; tileOutH = 8; }
306
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 4 && p.kernelH <= 4 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,2, 4,4, 32,8 >; tileOutW = 32; tileOutH = 8; }
307
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 2 && p.kernelH <= 2 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,2, 2,2, 32,8 >; tileOutW = 32; tileOutH = 8; }
308
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 1 && p.kernelW <= 24 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,1, 24,1, 64,8 >; tileOutW = 64; tileOutH = 8; }
309
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 1 && p.kernelW <= 20 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,1, 20,1, 64,8 >; tileOutW = 64; tileOutH = 8; }
310
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 1 && p.kernelW <= 16 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,1, 16,1, 64,8 >; tileOutW = 64; tileOutH = 8; }
311
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 1 && p.kernelW <= 12 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,1, 12,1, 64,8 >; tileOutW = 64; tileOutH = 8; }
312
+ if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 1 && p.kernelW <= 8 && p.kernelH <= 1 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 2,1, 8,1, 64,8 >; tileOutW = 64; tileOutH = 8; }
313
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 2 && p.kernelW <= 1 && p.kernelH <= 24) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,2, 1,24, 32,16>; tileOutW = 32; tileOutH = 16; }
314
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 2 && p.kernelW <= 1 && p.kernelH <= 20) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,2, 1,20, 32,16>; tileOutW = 32; tileOutH = 16; }
315
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 2 && p.kernelW <= 1 && p.kernelH <= 16) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,2, 1,16, 32,16>; tileOutW = 32; tileOutH = 16; }
316
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 2 && p.kernelW <= 1 && p.kernelH <= 12) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,2, 1,12, 32,16>; tileOutW = 32; tileOutH = 16; }
317
+ if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 2 && p.kernelW <= 1 && p.kernelH <= 8 ) { cudaKernel = (void*)UpFirDn2DKernel_small<T, 1,1, 1,2, 1,8, 32,16>; tileOutW = 32; tileOutH = 16; }
318
+
319
+ // Choose launch params.
320
+ dim3 blockSize;
321
+ dim3 gridSize;
322
+ if (tileOutW > 0 && tileOutH > 0) // small
323
+ {
324
+ p.loopMajor = (p.majorDim - 1) / 16384 + 1;
325
+ p.loopX = 1;
326
+ blockSize = dim3(32 * 8, 1, 1);
327
+ gridSize = dim3(((p.outH - 1) / tileOutH + 1) * p.minorDim, (p.outW - 1) / (p.loopX * tileOutW) + 1, (p.majorDim - 1) / p.loopMajor + 1);
328
+ }
329
+ else // large
330
+ {
331
+ p.loopMajor = (p.majorDim - 1) / 16384 + 1;
332
+ p.loopX = 4;
333
+ blockSize = dim3(4, 32, 1);
334
+ gridSize = dim3((p.outH * p.minorDim - 1) / blockSize.x + 1, (p.outW - 1) / (p.loopX * blockSize.y) + 1, (p.majorDim - 1) / p.loopMajor + 1);
335
+ }
336
+
337
+ // Launch CUDA kernel.
338
+ void* args[] = {&p};
339
+ OP_CHECK_CUDA_ERROR(ctx, cudaLaunchKernel(cudaKernel, gridSize, blockSize, args, 0, stream));
340
+ }
341
+ };
342
+
343
+ REGISTER_OP("UpFirDn2D")
344
+ .Input ("x: T")
345
+ .Input ("k: T")
346
+ .Output ("y: T")
347
+ .Attr ("T: {float, half}")
348
+ .Attr ("upx: int = 1")
349
+ .Attr ("upy: int = 1")
350
+ .Attr ("downx: int = 1")
351
+ .Attr ("downy: int = 1")
352
+ .Attr ("padx0: int = 0")
353
+ .Attr ("padx1: int = 0")
354
+ .Attr ("pady0: int = 0")
355
+ .Attr ("pady1: int = 0");
356
+ REGISTER_KERNEL_BUILDER(Name("UpFirDn2D").Device(DEVICE_GPU).TypeConstraint<float>("T"), UpFirDn2DOp<float>);
357
+ REGISTER_KERNEL_BUILDER(Name("UpFirDn2D").Device(DEVICE_GPU).TypeConstraint<Eigen::half>("T"), UpFirDn2DOp<Eigen::half>);
358
+
359
+ //------------------------------------------------------------------------
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/ops/upfirdn_2d.py ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Custom TensorFlow ops for efficient resampling of 2D images."""
10
+
11
+ import os
12
+ import numpy as np
13
+ import tensorflow as tf
14
+ from .. import custom_ops
15
+
16
+ def _get_plugin():
17
+ return custom_ops.get_plugin(os.path.splitext(__file__)[0] + '.cu')
18
+
19
+ #----------------------------------------------------------------------------
20
+
21
+ def upfirdn_2d(x, k, upx=1, upy=1, downx=1, downy=1, padx0=0, padx1=0, pady0=0, pady1=0, impl='cuda'):
22
+ r"""Pad, upsample, FIR filter, and downsample a batch of 2D images.
23
+
24
+ Accepts a batch of 2D images of the shape `[majorDim, inH, inW, minorDim]`
25
+ and performs the following operations for each image, batched across
26
+ `majorDim` and `minorDim`:
27
+
28
+ 1. Upsample the image by inserting the zeros after each pixel (`upx`, `upy`).
29
+
30
+ 2. Pad the image with zeros by the specified number of pixels on each side
31
+ (`padx0`, `padx1`, `pady0`, `pady1`). Specifying a negative value
32
+ corresponds to cropping the image.
33
+
34
+ 3. Convolve the image with the specified 2D FIR filter (`k`), shrinking the
35
+ image so that the footprint of all output pixels lies within the input image.
36
+
37
+ 4. Downsample the image by throwing away pixels (`downx`, `downy`).
38
+
39
+ This sequence of operations bears close resemblance to scipy.signal.upfirdn().
40
+ The fused op is considerably more efficient than performing the same calculation
41
+ using standard TensorFlow ops. It supports gradients of arbitrary order.
42
+
43
+ Args:
44
+ x: Input tensor of the shape `[majorDim, inH, inW, minorDim]`.
45
+ k: 2D FIR filter of the shape `[firH, firW]`.
46
+ upx: Integer upsampling factor along the X-axis (default: 1).
47
+ upy: Integer upsampling factor along the Y-axis (default: 1).
48
+ downx: Integer downsampling factor along the X-axis (default: 1).
49
+ downy: Integer downsampling factor along the Y-axis (default: 1).
50
+ padx0: Number of pixels to pad on the left side (default: 0).
51
+ padx1: Number of pixels to pad on the right side (default: 0).
52
+ pady0: Number of pixels to pad on the top side (default: 0).
53
+ pady1: Number of pixels to pad on the bottom side (default: 0).
54
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
55
+
56
+ Returns:
57
+ Tensor of the shape `[majorDim, outH, outW, minorDim]`, and same datatype as `x`.
58
+ """
59
+
60
+ impl_dict = {
61
+ 'ref': _upfirdn_2d_ref,
62
+ 'cuda': _upfirdn_2d_cuda,
63
+ }
64
+ return impl_dict[impl](x=x, k=k, upx=upx, upy=upy, downx=downx, downy=downy, padx0=padx0, padx1=padx1, pady0=pady0, pady1=pady1)
65
+
66
+ #----------------------------------------------------------------------------
67
+
68
+ def _upfirdn_2d_ref(x, k, upx, upy, downx, downy, padx0, padx1, pady0, pady1):
69
+ """Slow reference implementation of `upfirdn_2d()` using standard TensorFlow ops."""
70
+
71
+ x = tf.convert_to_tensor(x)
72
+ k = np.asarray(k, dtype=np.float32)
73
+ assert x.shape.rank == 4
74
+ inH = x.shape[1].value
75
+ inW = x.shape[2].value
76
+ minorDim = _shape(x, 3)
77
+ kernelH, kernelW = k.shape
78
+ assert inW >= 1 and inH >= 1
79
+ assert kernelW >= 1 and kernelH >= 1
80
+ assert isinstance(upx, int) and isinstance(upy, int)
81
+ assert isinstance(downx, int) and isinstance(downy, int)
82
+ assert isinstance(padx0, int) and isinstance(padx1, int)
83
+ assert isinstance(pady0, int) and isinstance(pady1, int)
84
+
85
+ # Upsample (insert zeros).
86
+ x = tf.reshape(x, [-1, inH, 1, inW, 1, minorDim])
87
+ x = tf.pad(x, [[0, 0], [0, 0], [0, upy - 1], [0, 0], [0, upx - 1], [0, 0]])
88
+ x = tf.reshape(x, [-1, inH * upy, inW * upx, minorDim])
89
+
90
+ # Pad (crop if negative).
91
+ x = tf.pad(x, [[0, 0], [max(pady0, 0), max(pady1, 0)], [max(padx0, 0), max(padx1, 0)], [0, 0]])
92
+ x = x[:, max(-pady0, 0) : x.shape[1].value - max(-pady1, 0), max(-padx0, 0) : x.shape[2].value - max(-padx1, 0), :]
93
+
94
+ # Convolve with filter.
95
+ x = tf.transpose(x, [0, 3, 1, 2])
96
+ x = tf.reshape(x, [-1, 1, inH * upy + pady0 + pady1, inW * upx + padx0 + padx1])
97
+ w = tf.constant(k[::-1, ::-1, np.newaxis, np.newaxis], dtype=x.dtype)
98
+ x = tf.nn.conv2d(x, w, strides=[1,1,1,1], padding='VALID', data_format='NCHW')
99
+ x = tf.reshape(x, [-1, minorDim, inH * upy + pady0 + pady1 - kernelH + 1, inW * upx + padx0 + padx1 - kernelW + 1])
100
+ x = tf.transpose(x, [0, 2, 3, 1])
101
+
102
+ # Downsample (throw away pixels).
103
+ return x[:, ::downy, ::downx, :]
104
+
105
+ #----------------------------------------------------------------------------
106
+
107
+ def _upfirdn_2d_cuda(x, k, upx, upy, downx, downy, padx0, padx1, pady0, pady1):
108
+ """Fast CUDA implementation of `upfirdn_2d()` using custom ops."""
109
+
110
+ x = tf.convert_to_tensor(x)
111
+ k = np.asarray(k, dtype=np.float32)
112
+ majorDim, inH, inW, minorDim = x.shape.as_list()
113
+ kernelH, kernelW = k.shape
114
+ assert inW >= 1 and inH >= 1
115
+ assert kernelW >= 1 and kernelH >= 1
116
+ assert isinstance(upx, int) and isinstance(upy, int)
117
+ assert isinstance(downx, int) and isinstance(downy, int)
118
+ assert isinstance(padx0, int) and isinstance(padx1, int)
119
+ assert isinstance(pady0, int) and isinstance(pady1, int)
120
+
121
+ outW = (inW * upx + padx0 + padx1 - kernelW) // downx + 1
122
+ outH = (inH * upy + pady0 + pady1 - kernelH) // downy + 1
123
+ assert outW >= 1 and outH >= 1
124
+
125
+ cuda_op = _get_plugin().up_fir_dn2d
126
+ kc = tf.constant(k, dtype=x.dtype)
127
+ gkc = tf.constant(k[::-1, ::-1], dtype=x.dtype)
128
+ gpadx0 = kernelW - padx0 - 1
129
+ gpady0 = kernelH - pady0 - 1
130
+ gpadx1 = inW * upx - outW * downx + padx0 - upx + 1
131
+ gpady1 = inH * upy - outH * downy + pady0 - upy + 1
132
+
133
+ @tf.custom_gradient
134
+ def func(x):
135
+ y = cuda_op(x=x, k=kc, upx=int(upx), upy=int(upy), downx=int(downx), downy=int(downy), padx0=int(padx0), padx1=int(padx1), pady0=int(pady0), pady1=int(pady1))
136
+ y.set_shape([majorDim, outH, outW, minorDim])
137
+ @tf.custom_gradient
138
+ def grad(dy):
139
+ dx = cuda_op(x=dy, k=gkc, upx=int(downx), upy=int(downy), downx=int(upx), downy=int(upy), padx0=int(gpadx0), padx1=int(gpadx1), pady0=int(gpady0), pady1=int(gpady1))
140
+ dx.set_shape([majorDim, inH, inW, minorDim])
141
+ return dx, func
142
+ return y, grad
143
+ return func(x)
144
+
145
+ #----------------------------------------------------------------------------
146
+
147
+ def filter_2d(x, k, gain=1, padding=0, data_format='NCHW', impl='cuda'):
148
+ r"""Filter a batch of 2D images with the given FIR filter.
149
+
150
+ Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]`
151
+ and filters each image with the given filter. The filter is normalized so that
152
+ if the input pixels are constant, they will be scaled by the specified `gain`.
153
+ Pixels outside the image are assumed to be zero.
154
+
155
+ Args:
156
+ x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`.
157
+ k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable).
158
+ gain: Scaling factor for signal magnitude (default: 1.0).
159
+ padding: Number of pixels to pad or crop the output on each side (default: 0).
160
+ data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`).
161
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
162
+
163
+ Returns:
164
+ Tensor of the same shape and datatype as `x`.
165
+ """
166
+
167
+ assert isinstance(padding, int)
168
+ k = _FilterKernel(k=k, gain=gain)
169
+ assert k.w == k.h
170
+ pad0 = k.w // 2 + padding
171
+ pad1 = (k.w - 1) // 2 + padding
172
+ return _simple_upfirdn_2d(x, k, pad0=pad0, pad1=pad1, data_format=data_format, impl=impl)
173
+
174
+ #----------------------------------------------------------------------------
175
+
176
+ def upsample_2d(x, k=None, factor=2, gain=1, padding=0, data_format='NCHW', impl='cuda'):
177
+ r"""Upsample a batch of 2D images with the given filter.
178
+
179
+ Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]`
180
+ and upsamples each image with the given filter. The filter is normalized so that
181
+ if the input pixels are constant, they will be scaled by the specified `gain`.
182
+ Pixels outside the image are assumed to be zero, and the filter is padded with
183
+ zeros so that its shape is a multiple of the upsampling factor.
184
+
185
+ Args:
186
+ x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`.
187
+ k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable).
188
+ The default is `[1] * factor`, which corresponds to nearest-neighbor
189
+ upsampling.
190
+ factor: Integer upsampling factor (default: 2).
191
+ gain: Scaling factor for signal magnitude (default: 1.0).
192
+ padding: Number of pixels to pad or crop the output on each side (default: 0).
193
+ data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`).
194
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
195
+
196
+ Returns:
197
+ Tensor of the shape `[N, C, H * factor, W * factor]` or
198
+ `[N, H * factor, W * factor, C]`, and same datatype as `x`.
199
+ """
200
+
201
+ assert isinstance(factor, int) and factor >= 1
202
+ assert isinstance(padding, int)
203
+ k = _FilterKernel(k if k is not None else [1] * factor, gain * (factor ** 2))
204
+ assert k.w == k.h
205
+ pad0 = (k.w + factor - 1) // 2 + padding
206
+ pad1 = (k.w - factor) // 2 + padding
207
+ return _simple_upfirdn_2d(x, k, up=factor, pad0=pad0, pad1=pad1, data_format=data_format, impl=impl)
208
+
209
+ #----------------------------------------------------------------------------
210
+
211
+ def downsample_2d(x, k=None, factor=2, gain=1, padding=0, data_format='NCHW', impl='cuda'):
212
+ r"""Downsample a batch of 2D images with the given filter.
213
+
214
+ Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]`
215
+ and downsamples each image with the given filter. The filter is normalized so that
216
+ if the input pixels are constant, they will be scaled by the specified `gain`.
217
+ Pixels outside the image are assumed to be zero, and the filter is padded with
218
+ zeros so that its shape is a multiple of the downsampling factor.
219
+
220
+ Args:
221
+ x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`.
222
+ k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable).
223
+ The default is `[1] * factor`, which corresponds to average pooling.
224
+ factor: Integer downsampling factor (default: 2).
225
+ gain: Scaling factor for signal magnitude (default: 1.0).
226
+ padding: Number of pixels to pad or crop the output on each side (default: 0).
227
+ data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`).
228
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
229
+
230
+ Returns:
231
+ Tensor of the shape `[N, C, H // factor, W // factor]` or
232
+ `[N, H // factor, W // factor, C]`, and same datatype as `x`.
233
+ """
234
+
235
+ assert isinstance(factor, int) and factor >= 1
236
+ assert isinstance(padding, int)
237
+ k = _FilterKernel(k if k is not None else [1] * factor, gain)
238
+ assert k.w == k.h
239
+ pad0 = (k.w - factor + 1) // 2 + padding * factor
240
+ pad1 = (k.w - factor) // 2 + padding * factor
241
+ return _simple_upfirdn_2d(x, k, down=factor, pad0=pad0, pad1=pad1, data_format=data_format, impl=impl)
242
+
243
+ #----------------------------------------------------------------------------
244
+
245
+ def upsample_conv_2d(x, w, k=None, factor=2, gain=1, padding=0, data_format='NCHW', impl='cuda'):
246
+ r"""Fused `upsample_2d()` followed by `tf.nn.conv2d()`.
247
+
248
+ Padding is performed only once at the beginning, not between the operations.
249
+ The fused op is considerably more efficient than performing the same calculation
250
+ using standard TensorFlow ops. It supports gradients of arbitrary order.
251
+
252
+ Args:
253
+ x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`.
254
+ w: Weight tensor of the shape `[filterH, filterW, inChannels, outChannels]`.
255
+ Grouped convolution can be performed by `inChannels = x.shape[0] // numGroups`.
256
+ k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable).
257
+ The default is `[1] * factor`, which corresponds to nearest-neighbor
258
+ upsampling.
259
+ factor: Integer upsampling factor (default: 2).
260
+ gain: Scaling factor for signal magnitude (default: 1.0).
261
+ padding: Number of pixels to pad or crop the output on each side (default: 0).
262
+ data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`).
263
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
264
+
265
+ Returns:
266
+ Tensor of the shape `[N, C, H * factor, W * factor]` or
267
+ `[N, H * factor, W * factor, C]`, and same datatype as `x`.
268
+ """
269
+
270
+ assert isinstance(factor, int) and factor >= 1
271
+ assert isinstance(padding, int)
272
+
273
+ # Check weight shape.
274
+ w = tf.convert_to_tensor(w)
275
+ ch, cw, _inC, _outC = w.shape.as_list()
276
+ inC = _shape(w, 2)
277
+ outC = _shape(w, 3)
278
+ assert cw == ch
279
+
280
+ # Fast path for 1x1 convolution.
281
+ if cw == 1 and ch == 1:
282
+ x = tf.nn.conv2d(x, w, data_format=data_format, strides=[1,1,1,1], padding='VALID')
283
+ x = upsample_2d(x, k, factor=factor, gain=gain, padding=padding, data_format=data_format, impl=impl)
284
+ return x
285
+
286
+ # Setup filter kernel.
287
+ k = _FilterKernel(k if k is not None else [1] * factor, gain * (factor ** 2))
288
+ assert k.w == k.h
289
+
290
+ # Determine data dimensions.
291
+ if data_format == 'NCHW':
292
+ stride = [1, 1, factor, factor]
293
+ output_shape = [_shape(x, 0), outC, (_shape(x, 2) - 1) * factor + ch, (_shape(x, 3) - 1) * factor + cw]
294
+ num_groups = _shape(x, 1) // inC
295
+ else:
296
+ stride = [1, factor, factor, 1]
297
+ output_shape = [_shape(x, 0), (_shape(x, 1) - 1) * factor + ch, (_shape(x, 2) - 1) * factor + cw, outC]
298
+ num_groups = _shape(x, 3) // inC
299
+
300
+ # Transpose weights.
301
+ w = tf.reshape(w, [ch, cw, inC, num_groups, -1])
302
+ w = tf.transpose(w[::-1, ::-1], [0, 1, 4, 3, 2])
303
+ w = tf.reshape(w, [ch, cw, -1, num_groups * inC])
304
+
305
+ # Execute.
306
+ x = tf.nn.conv2d_transpose(x, w, output_shape=output_shape, strides=stride, padding='VALID', data_format=data_format)
307
+ pad0 = (k.w + factor - cw) // 2 + padding
308
+ pad1 = (k.w - factor - cw + 3) // 2 + padding
309
+ return _simple_upfirdn_2d(x, k, pad0=pad0, pad1=pad1, data_format=data_format, impl=impl)
310
+
311
+ #----------------------------------------------------------------------------
312
+
313
+ def conv_downsample_2d(x, w, k=None, factor=2, gain=1, padding=0, data_format='NCHW', impl='cuda'):
314
+ r"""Fused `tf.nn.conv2d()` followed by `downsample_2d()`.
315
+
316
+ Padding is performed only once at the beginning, not between the operations.
317
+ The fused op is considerably more efficient than performing the same calculation
318
+ using standard TensorFlow ops. It supports gradients of arbitrary order.
319
+
320
+ Args:
321
+ x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`.
322
+ w: Weight tensor of the shape `[filterH, filterW, inChannels, outChannels]`.
323
+ Grouped convolution can be performed by `inChannels = x.shape[0] // numGroups`.
324
+ k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable).
325
+ The default is `[1] * factor`, which corresponds to average pooling.
326
+ factor: Integer downsampling factor (default: 2).
327
+ gain: Scaling factor for signal magnitude (default: 1.0).
328
+ padding: Number of pixels to pad or crop the output on each side (default: 0).
329
+ data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`).
330
+ impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default).
331
+
332
+ Returns:
333
+ Tensor of the shape `[N, C, H // factor, W // factor]` or
334
+ `[N, H // factor, W // factor, C]`, and same datatype as `x`.
335
+ """
336
+
337
+ assert isinstance(factor, int) and factor >= 1
338
+ assert isinstance(padding, int)
339
+
340
+ # Check weight shape.
341
+ w = tf.convert_to_tensor(w)
342
+ ch, cw, _inC, _outC = w.shape.as_list()
343
+ assert cw == ch
344
+
345
+ # Fast path for 1x1 convolution.
346
+ if cw == 1 and ch == 1:
347
+ x = downsample_2d(x, k, factor=factor, gain=gain, padding=padding, data_format=data_format, impl=impl)
348
+ x = tf.nn.conv2d(x, w, data_format=data_format, strides=[1,1,1,1], padding='VALID')
349
+ return x
350
+
351
+ # Setup filter kernel.
352
+ k = _FilterKernel(k if k is not None else [1] * factor, gain)
353
+ assert k.w == k.h
354
+
355
+ # Determine stride.
356
+ if data_format == 'NCHW':
357
+ s = [1, 1, factor, factor]
358
+ else:
359
+ s = [1, factor, factor, 1]
360
+
361
+ # Execute.
362
+ pad0 = (k.w - factor + cw) // 2 + padding * factor
363
+ pad1 = (k.w - factor + cw - 1) // 2 + padding * factor
364
+ x = _simple_upfirdn_2d(x, k, pad0=pad0, pad1=pad1, data_format=data_format, impl=impl)
365
+ return tf.nn.conv2d(x, w, strides=s, padding='VALID', data_format=data_format)
366
+
367
+ #----------------------------------------------------------------------------
368
+ # Internal helpers.
369
+
370
+ class _FilterKernel:
371
+ def __init__(self, k, gain=1):
372
+ k = np.asarray(k, dtype=np.float32)
373
+ k /= np.sum(k)
374
+
375
+ # Separable.
376
+ if k.ndim == 1 and k.size >= 8:
377
+ self.w = k.size
378
+ self.h = k.size
379
+ self.kx = k[np.newaxis, :]
380
+ self.ky = k[:, np.newaxis] * gain
381
+ self.kxy = None
382
+
383
+ # Non-separable.
384
+ else:
385
+ if k.ndim == 1:
386
+ k = np.outer(k, k)
387
+ assert k.ndim == 2
388
+ self.w = k.shape[1]
389
+ self.h = k.shape[0]
390
+ self.kx = None
391
+ self.ky = None
392
+ self.kxy = k * gain
393
+
394
+ def _simple_upfirdn_2d(x, k, up=1, down=1, pad0=0, pad1=0, data_format='NCHW', impl='cuda'):
395
+ assert isinstance(k, _FilterKernel)
396
+ assert data_format in ['NCHW', 'NHWC']
397
+ assert x.shape.rank == 4
398
+ y = x
399
+ if data_format == 'NCHW':
400
+ y = tf.reshape(y, [-1, _shape(y, 2), _shape(y, 3), 1])
401
+ if k.kx is not None:
402
+ y = upfirdn_2d(y, k.kx, upx=up, downx=down, padx0=pad0, padx1=pad1, impl=impl)
403
+ if k.ky is not None:
404
+ y = upfirdn_2d(y, k.ky, upy=up, downy=down, pady0=pad0, pady1=pad1, impl=impl)
405
+ if k.kxy is not None:
406
+ y = upfirdn_2d(y, k.kxy, upx=up, upy=up, downx=down, downy=down, padx0=pad0, padx1=pad1, pady0=pad0, pady1=pad1, impl=impl)
407
+ if data_format == 'NCHW':
408
+ y = tf.reshape(y, [-1, _shape(x, 1), _shape(y, 1), _shape(y, 2)])
409
+ return y
410
+
411
+ def _shape(tf_expr, dim_idx):
412
+ if tf_expr.shape.rank is not None:
413
+ dim = tf_expr.shape[dim_idx].value
414
+ if dim is not None:
415
+ return dim
416
+ return tf.shape(tf_expr)[dim_idx]
417
+
418
+ #----------------------------------------------------------------------------
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/optimizer.py ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Helper wrapper for a Tensorflow optimizer."""
10
+
11
+ import platform
12
+ import numpy as np
13
+ import tensorflow as tf
14
+
15
+ from collections import OrderedDict
16
+ from typing import List, Union
17
+
18
+ from . import autosummary
19
+ from . import tfutil
20
+ from .. import util
21
+
22
+ from .tfutil import TfExpression, TfExpressionEx
23
+
24
+ _collective_ops_warning_printed = False
25
+ _collective_ops_group_key = 831766147
26
+ _collective_ops_instance_key = 436340067
27
+
28
+ class Optimizer:
29
+ """A Wrapper for tf.train.Optimizer.
30
+
31
+ Automatically takes care of:
32
+ - Gradient averaging for multi-GPU training.
33
+ - Gradient accumulation for arbitrarily large minibatches.
34
+ - Dynamic loss scaling and typecasts for FP16 training.
35
+ - Ignoring corrupted gradients that contain NaNs/Infs.
36
+ - Reporting statistics.
37
+ - Well-chosen default settings.
38
+ """
39
+
40
+ def __init__(self,
41
+ name: str = "Train", # Name string that will appear in TensorFlow graph.
42
+ tf_optimizer: str = "tf.train.AdamOptimizer", # Underlying optimizer class.
43
+ learning_rate: TfExpressionEx = 0.001, # Learning rate. Can vary over time.
44
+ minibatch_multiplier: TfExpressionEx = None, # Treat N consecutive minibatches as one by accumulating gradients.
45
+ share: "Optimizer" = None, # Share internal state with a previously created optimizer?
46
+ use_loss_scaling: bool = False, # Enable dynamic loss scaling for robust mixed-precision training?
47
+ loss_scaling_init: float = 64.0, # Log2 of initial loss scaling factor.
48
+ loss_scaling_inc: float = 0.0005, # Log2 of per-minibatch loss scaling increment when there is no overflow.
49
+ loss_scaling_dec: float = 1.0, # Log2 of per-minibatch loss scaling decrement when there is an overflow.
50
+ report_mem_usage: bool = False, # Report fine-grained memory usage statistics in TensorBoard?
51
+ **kwargs):
52
+
53
+ # Public fields.
54
+ self.name = name
55
+ self.learning_rate = learning_rate
56
+ self.minibatch_multiplier = minibatch_multiplier
57
+ self.id = self.name.replace("/", ".")
58
+ self.scope = tf.get_default_graph().unique_name(self.id)
59
+ self.optimizer_class = util.get_obj_by_name(tf_optimizer)
60
+ self.optimizer_kwargs = dict(kwargs)
61
+ self.use_loss_scaling = use_loss_scaling
62
+ self.loss_scaling_init = loss_scaling_init
63
+ self.loss_scaling_inc = loss_scaling_inc
64
+ self.loss_scaling_dec = loss_scaling_dec
65
+
66
+ # Private fields.
67
+ self._updates_applied = False
68
+ self._devices = OrderedDict() # device_name => EasyDict()
69
+ self._shared_optimizers = OrderedDict() # device_name => optimizer_class
70
+ self._gradient_shapes = None # [shape, ...]
71
+ self._report_mem_usage = report_mem_usage
72
+
73
+ # Validate arguments.
74
+ assert callable(self.optimizer_class)
75
+
76
+ # Share internal state if requested.
77
+ if share is not None:
78
+ assert isinstance(share, Optimizer)
79
+ assert self.optimizer_class is share.optimizer_class
80
+ assert self.learning_rate is share.learning_rate
81
+ assert self.optimizer_kwargs == share.optimizer_kwargs
82
+ self._shared_optimizers = share._shared_optimizers # pylint: disable=protected-access
83
+
84
+ def _get_device(self, device_name: str):
85
+ """Get internal state for the given TensorFlow device."""
86
+ tfutil.assert_tf_initialized()
87
+ if device_name in self._devices:
88
+ return self._devices[device_name]
89
+
90
+ # Initialize fields.
91
+ device = util.EasyDict()
92
+ device.name = device_name
93
+ device.optimizer = None # Underlying optimizer: optimizer_class
94
+ device.loss_scaling_var = None # Log2 of loss scaling: tf.Variable
95
+ device.grad_raw = OrderedDict() # Raw gradients: var => [grad, ...]
96
+ device.grad_clean = OrderedDict() # Clean gradients: var => grad
97
+ device.grad_acc_vars = OrderedDict() # Accumulation sums: var => tf.Variable
98
+ device.grad_acc_count = None # Accumulation counter: tf.Variable
99
+ device.grad_acc = OrderedDict() # Accumulated gradients: var => grad
100
+
101
+ # Setup TensorFlow objects.
102
+ with tfutil.absolute_name_scope(self.scope + "/Devices"), tf.device(device_name), tf.control_dependencies(None):
103
+ if device_name not in self._shared_optimizers:
104
+ optimizer_name = self.scope.replace("/", "_") + "_opt%d" % len(self._shared_optimizers)
105
+ self._shared_optimizers[device_name] = self.optimizer_class(name=optimizer_name, learning_rate=self.learning_rate, **self.optimizer_kwargs)
106
+ device.optimizer = self._shared_optimizers[device_name]
107
+ if self.use_loss_scaling:
108
+ device.loss_scaling_var = tf.Variable(np.float32(self.loss_scaling_init), trainable=False, name="loss_scaling_var")
109
+
110
+ # Register device.
111
+ self._devices[device_name] = device
112
+ return device
113
+
114
+ def register_gradients(self, loss: TfExpression, trainable_vars: Union[List, dict]) -> None:
115
+ """Register the gradients of the given loss function with respect to the given variables.
116
+ Intended to be called once per GPU."""
117
+ tfutil.assert_tf_initialized()
118
+ assert not self._updates_applied
119
+ device = self._get_device(loss.device)
120
+
121
+ # Validate trainables.
122
+ if isinstance(trainable_vars, dict):
123
+ trainable_vars = list(trainable_vars.values()) # allow passing in Network.trainables as vars
124
+ assert isinstance(trainable_vars, list) and len(trainable_vars) >= 1
125
+ assert all(tfutil.is_tf_expression(expr) for expr in trainable_vars + [loss])
126
+ assert all(var.device == device.name for var in trainable_vars)
127
+
128
+ # Validate shapes.
129
+ if self._gradient_shapes is None:
130
+ self._gradient_shapes = [var.shape.as_list() for var in trainable_vars]
131
+ assert len(trainable_vars) == len(self._gradient_shapes)
132
+ assert all(var.shape.as_list() == var_shape for var, var_shape in zip(trainable_vars, self._gradient_shapes))
133
+
134
+ # Report memory usage if requested.
135
+ deps = [loss]
136
+ if self._report_mem_usage:
137
+ self._report_mem_usage = False
138
+ try:
139
+ with tf.name_scope(self.id + '_mem'), tf.device(device.name), tf.control_dependencies([loss]):
140
+ deps.append(autosummary.autosummary(self.id + "/mem_usage_gb", tf.contrib.memory_stats.BytesInUse() / 2**30))
141
+ except tf.errors.NotFoundError:
142
+ pass
143
+
144
+ # Compute gradients.
145
+ with tf.name_scope(self.id + "_grad"), tf.device(device.name), tf.control_dependencies(deps):
146
+ loss = self.apply_loss_scaling(tf.cast(loss, tf.float32))
147
+ gate = tf.train.Optimizer.GATE_NONE # disable gating to reduce memory usage
148
+ grad_list = device.optimizer.compute_gradients(loss=loss, var_list=trainable_vars, gate_gradients=gate)
149
+
150
+ # Register gradients.
151
+ for grad, var in grad_list:
152
+ if var not in device.grad_raw:
153
+ device.grad_raw[var] = []
154
+ device.grad_raw[var].append(grad)
155
+
156
+ def apply_updates(self, allow_no_op: bool = False) -> tf.Operation:
157
+ """Construct training op to update the registered variables based on their gradients."""
158
+ tfutil.assert_tf_initialized()
159
+ assert not self._updates_applied
160
+ self._updates_applied = True
161
+ all_ops = []
162
+
163
+ # Check for no-op.
164
+ if allow_no_op and len(self._devices) == 0:
165
+ with tfutil.absolute_name_scope(self.scope):
166
+ return tf.no_op(name='TrainingOp')
167
+
168
+ # Clean up gradients.
169
+ for device_idx, device in enumerate(self._devices.values()):
170
+ with tfutil.absolute_name_scope(self.scope + "/Clean%d" % device_idx), tf.device(device.name):
171
+ for var, grad in device.grad_raw.items():
172
+
173
+ # Filter out disconnected gradients and convert to float32.
174
+ grad = [g for g in grad if g is not None]
175
+ grad = [tf.cast(g, tf.float32) for g in grad]
176
+
177
+ # Sum within the device.
178
+ if len(grad) == 0:
179
+ grad = tf.zeros(var.shape) # No gradients => zero.
180
+ elif len(grad) == 1:
181
+ grad = grad[0] # Single gradient => use as is.
182
+ else:
183
+ grad = tf.add_n(grad) # Multiple gradients => sum.
184
+
185
+ # Scale as needed.
186
+ scale = 1.0 / len(device.grad_raw[var]) / len(self._devices)
187
+ scale = tf.constant(scale, dtype=tf.float32, name="scale")
188
+ if self.minibatch_multiplier is not None:
189
+ scale /= tf.cast(self.minibatch_multiplier, tf.float32)
190
+ scale = self.undo_loss_scaling(scale)
191
+ device.grad_clean[var] = grad * scale
192
+
193
+ # Sum gradients across devices.
194
+ if len(self._devices) > 1:
195
+ with tfutil.absolute_name_scope(self.scope + "/Broadcast"), tf.device(None):
196
+ if platform.system() == "Windows": # Windows => NCCL ops are not available.
197
+ self._broadcast_fallback()
198
+ elif tf.VERSION.startswith("1.15."): # TF 1.15 => NCCL ops are broken: https://github.com/tensorflow/tensorflow/issues/41539
199
+ self._broadcast_fallback()
200
+ else: # Otherwise => NCCL ops are safe to use.
201
+ self._broadcast_nccl()
202
+
203
+ # Apply updates separately on each device.
204
+ for device_idx, device in enumerate(self._devices.values()):
205
+ with tfutil.absolute_name_scope(self.scope + "/Apply%d" % device_idx), tf.device(device.name):
206
+ # pylint: disable=cell-var-from-loop
207
+
208
+ # Accumulate gradients over time.
209
+ if self.minibatch_multiplier is None:
210
+ acc_ok = tf.constant(True, name='acc_ok')
211
+ device.grad_acc = OrderedDict(device.grad_clean)
212
+ else:
213
+ # Create variables.
214
+ with tf.control_dependencies(None):
215
+ for var in device.grad_clean.keys():
216
+ device.grad_acc_vars[var] = tf.Variable(tf.zeros(var.shape), trainable=False, name="grad_acc_var")
217
+ device.grad_acc_count = tf.Variable(tf.zeros([]), trainable=False, name="grad_acc_count")
218
+
219
+ # Track counter.
220
+ count_cur = device.grad_acc_count + 1.0
221
+ count_inc_op = lambda: tf.assign(device.grad_acc_count, count_cur)
222
+ count_reset_op = lambda: tf.assign(device.grad_acc_count, tf.zeros([]))
223
+ acc_ok = (count_cur >= tf.cast(self.minibatch_multiplier, tf.float32))
224
+ all_ops.append(tf.cond(acc_ok, count_reset_op, count_inc_op))
225
+
226
+ # Track gradients.
227
+ for var, grad in device.grad_clean.items():
228
+ acc_var = device.grad_acc_vars[var]
229
+ acc_cur = acc_var + grad
230
+ device.grad_acc[var] = acc_cur
231
+ with tf.control_dependencies([acc_cur]):
232
+ acc_inc_op = lambda: tf.assign(acc_var, acc_cur)
233
+ acc_reset_op = lambda: tf.assign(acc_var, tf.zeros(var.shape))
234
+ all_ops.append(tf.cond(acc_ok, acc_reset_op, acc_inc_op))
235
+
236
+ # No overflow => apply gradients.
237
+ all_ok = tf.reduce_all(tf.stack([acc_ok] + [tf.reduce_all(tf.is_finite(g)) for g in device.grad_acc.values()]))
238
+ apply_op = lambda: device.optimizer.apply_gradients([(tf.cast(grad, var.dtype), var) for var, grad in device.grad_acc.items()])
239
+ all_ops.append(tf.cond(all_ok, apply_op, tf.no_op))
240
+
241
+ # Adjust loss scaling.
242
+ if self.use_loss_scaling:
243
+ ls_inc_op = lambda: tf.assign_add(device.loss_scaling_var, self.loss_scaling_inc)
244
+ ls_dec_op = lambda: tf.assign_sub(device.loss_scaling_var, self.loss_scaling_dec)
245
+ ls_update_op = lambda: tf.group(tf.cond(all_ok, ls_inc_op, ls_dec_op))
246
+ all_ops.append(tf.cond(acc_ok, ls_update_op, tf.no_op))
247
+
248
+ # Last device => report statistics.
249
+ if device_idx == len(self._devices) - 1:
250
+ all_ops.append(autosummary.autosummary(self.id + "/learning_rate", tf.convert_to_tensor(self.learning_rate)))
251
+ all_ops.append(autosummary.autosummary(self.id + "/overflow_frequency", tf.where(all_ok, 0, 1), condition=acc_ok))
252
+ if self.use_loss_scaling:
253
+ all_ops.append(autosummary.autosummary(self.id + "/loss_scaling_log2", device.loss_scaling_var))
254
+
255
+ # Initialize variables.
256
+ self.reset_optimizer_state()
257
+ if self.use_loss_scaling:
258
+ tfutil.init_uninitialized_vars([device.loss_scaling_var for device in self._devices.values()])
259
+ if self.minibatch_multiplier is not None:
260
+ tfutil.run([var.initializer for device in self._devices.values() for var in list(device.grad_acc_vars.values()) + [device.grad_acc_count]])
261
+
262
+ # Group everything into a single op.
263
+ with tfutil.absolute_name_scope(self.scope):
264
+ return tf.group(*all_ops, name="TrainingOp")
265
+
266
+ def reset_optimizer_state(self) -> None:
267
+ """Reset internal state of the underlying optimizer."""
268
+ tfutil.assert_tf_initialized()
269
+ tfutil.run([var.initializer for device in self._devices.values() for var in device.optimizer.variables()])
270
+
271
+ def get_loss_scaling_var(self, device: str) -> Union[tf.Variable, None]:
272
+ """Get or create variable representing log2 of the current dynamic loss scaling factor."""
273
+ return self._get_device(device).loss_scaling_var
274
+
275
+ def apply_loss_scaling(self, value: TfExpression) -> TfExpression:
276
+ """Apply dynamic loss scaling for the given expression."""
277
+ assert tfutil.is_tf_expression(value)
278
+ if not self.use_loss_scaling:
279
+ return value
280
+ return value * tfutil.exp2(self.get_loss_scaling_var(value.device))
281
+
282
+ def undo_loss_scaling(self, value: TfExpression) -> TfExpression:
283
+ """Undo the effect of dynamic loss scaling for the given expression."""
284
+ assert tfutil.is_tf_expression(value)
285
+ if not self.use_loss_scaling:
286
+ return value
287
+ return value * tfutil.exp2(-self.get_loss_scaling_var(value.device)) # pylint: disable=invalid-unary-operand-type
288
+
289
+ def _broadcast_nccl(self):
290
+ """Sum gradients across devices using NCCL ops (fast path)."""
291
+ from tensorflow.python.ops import nccl_ops # pylint: disable=no-name-in-module
292
+ for all_vars in zip(*[device.grad_clean.keys() for device in self._devices.values()]):
293
+ if any(x.shape.num_elements() > 0 for x in all_vars):
294
+ all_grads = [device.grad_clean[var] for device, var in zip(self._devices.values(), all_vars)]
295
+ all_grads = nccl_ops.all_sum(all_grads)
296
+ for device, var, grad in zip(self._devices.values(), all_vars, all_grads):
297
+ device.grad_clean[var] = grad
298
+
299
+ def _broadcast_fallback(self):
300
+ """Sum gradients across devices using TensorFlow collective ops (slow fallback path)."""
301
+ from tensorflow.python.ops import collective_ops # pylint: disable=no-name-in-module
302
+ global _collective_ops_warning_printed, _collective_ops_group_key, _collective_ops_instance_key
303
+ if all(x.shape.num_elements() == 0 for device in self._devices.values() for x in device.grad_clean.values()):
304
+ return
305
+ if not _collective_ops_warning_printed:
306
+ print("------------------------------------------------------------------------")
307
+ print("WARNING: Using slow fallback implementation for inter-GPU communication.")
308
+ print("Please use TensorFlow 1.14 on Linux for optimal training performance.")
309
+ print("------------------------------------------------------------------------")
310
+ _collective_ops_warning_printed = True
311
+ for device in self._devices.values():
312
+ with tf.device(device.name):
313
+ combo = [tf.reshape(x, [x.shape.num_elements()]) for x in device.grad_clean.values()]
314
+ combo = tf.concat(combo, axis=0)
315
+ combo = collective_ops.all_reduce(combo, merge_op='Add', final_op='Id',
316
+ group_size=len(self._devices), group_key=_collective_ops_group_key,
317
+ instance_key=_collective_ops_instance_key)
318
+ cur_ofs = 0
319
+ for var, grad_old in device.grad_clean.items():
320
+ grad_new = tf.reshape(combo[cur_ofs : cur_ofs + grad_old.shape.num_elements()], grad_old.shape)
321
+ cur_ofs += grad_old.shape.num_elements()
322
+ device.grad_clean[var] = grad_new
323
+ _collective_ops_instance_key += 1
324
+
325
+
326
+ class SimpleAdam:
327
+ """Simplified version of tf.train.AdamOptimizer that behaves identically when used with dnnlib.tflib.Optimizer."""
328
+
329
+ def __init__(self, name="Adam", learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
330
+ self.name = name
331
+ self.learning_rate = learning_rate
332
+ self.beta1 = beta1
333
+ self.beta2 = beta2
334
+ self.epsilon = epsilon
335
+ self.all_state_vars = []
336
+
337
+ def variables(self):
338
+ return self.all_state_vars
339
+
340
+ def compute_gradients(self, loss, var_list, gate_gradients=tf.train.Optimizer.GATE_NONE):
341
+ assert gate_gradients == tf.train.Optimizer.GATE_NONE
342
+ return list(zip(tf.gradients(loss, var_list), var_list))
343
+
344
+ def apply_gradients(self, grads_and_vars):
345
+ with tf.name_scope(self.name):
346
+ state_vars = []
347
+ update_ops = []
348
+
349
+ # Adjust learning rate to deal with startup bias.
350
+ with tf.control_dependencies(None):
351
+ b1pow_var = tf.Variable(dtype=tf.float32, initial_value=1, trainable=False)
352
+ b2pow_var = tf.Variable(dtype=tf.float32, initial_value=1, trainable=False)
353
+ state_vars += [b1pow_var, b2pow_var]
354
+ b1pow_new = b1pow_var * self.beta1
355
+ b2pow_new = b2pow_var * self.beta2
356
+ update_ops += [tf.assign(b1pow_var, b1pow_new), tf.assign(b2pow_var, b2pow_new)]
357
+ lr_new = self.learning_rate * tf.sqrt(1 - b2pow_new) / (1 - b1pow_new)
358
+
359
+ # Construct ops to update each variable.
360
+ for grad, var in grads_and_vars:
361
+ with tf.control_dependencies(None):
362
+ m_var = tf.Variable(dtype=tf.float32, initial_value=tf.zeros_like(var), trainable=False)
363
+ v_var = tf.Variable(dtype=tf.float32, initial_value=tf.zeros_like(var), trainable=False)
364
+ state_vars += [m_var, v_var]
365
+ m_new = self.beta1 * m_var + (1 - self.beta1) * grad
366
+ v_new = self.beta2 * v_var + (1 - self.beta2) * tf.square(grad)
367
+ var_delta = lr_new * m_new / (tf.sqrt(v_new) + self.epsilon)
368
+ update_ops += [tf.assign(m_var, m_new), tf.assign(v_var, v_new), tf.assign_sub(var, var_delta)]
369
+
370
+ # Group everything together.
371
+ self.all_state_vars += state_vars
372
+ return tf.group(*update_ops)
PTI/models/StyleCLIP/global_directions/dnnlib/tflib/tfutil.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ """Miscellaneous helper utils for Tensorflow."""
10
+
11
+ import os
12
+ import numpy as np
13
+ import tensorflow as tf
14
+
15
+ # Silence deprecation warnings from TensorFlow 1.13 onwards
16
+ import logging
17
+ logging.getLogger('tensorflow').setLevel(logging.ERROR)
18
+ import tensorflow.contrib # requires TensorFlow 1.x!
19
+ tf.contrib = tensorflow.contrib
20
+
21
+ from typing import Any, Iterable, List, Union
22
+
23
+ TfExpression = Union[tf.Tensor, tf.Variable, tf.Operation]
24
+ """A type that represents a valid Tensorflow expression."""
25
+
26
+ TfExpressionEx = Union[TfExpression, int, float, np.ndarray]
27
+ """A type that can be converted to a valid Tensorflow expression."""
28
+
29
+
30
+ def run(*args, **kwargs) -> Any:
31
+ """Run the specified ops in the default session."""
32
+ assert_tf_initialized()
33
+ return tf.get_default_session().run(*args, **kwargs)
34
+
35
+
36
+ def is_tf_expression(x: Any) -> bool:
37
+ """Check whether the input is a valid Tensorflow expression, i.e., Tensorflow Tensor, Variable, or Operation."""
38
+ return isinstance(x, (tf.Tensor, tf.Variable, tf.Operation))
39
+
40
+
41
+ def shape_to_list(shape: Iterable[tf.Dimension]) -> List[Union[int, None]]:
42
+ """Convert a Tensorflow shape to a list of ints. Retained for backwards compatibility -- use TensorShape.as_list() in new code."""
43
+ return [dim.value for dim in shape]
44
+
45
+
46
+ def flatten(x: TfExpressionEx) -> TfExpression:
47
+ """Shortcut function for flattening a tensor."""
48
+ with tf.name_scope("Flatten"):
49
+ return tf.reshape(x, [-1])
50
+
51
+
52
+ def log2(x: TfExpressionEx) -> TfExpression:
53
+ """Logarithm in base 2."""
54
+ with tf.name_scope("Log2"):
55
+ return tf.log(x) * np.float32(1.0 / np.log(2.0))
56
+
57
+
58
+ def exp2(x: TfExpressionEx) -> TfExpression:
59
+ """Exponent in base 2."""
60
+ with tf.name_scope("Exp2"):
61
+ return tf.exp(x * np.float32(np.log(2.0)))
62
+
63
+
64
+ def erfinv(y: TfExpressionEx) -> TfExpression:
65
+ """Inverse of the error function."""
66
+ # pylint: disable=no-name-in-module
67
+ from tensorflow.python.ops.distributions import special_math
68
+ return special_math.erfinv(y)
69
+
70
+
71
+ def lerp(a: TfExpressionEx, b: TfExpressionEx, t: TfExpressionEx) -> TfExpressionEx:
72
+ """Linear interpolation."""
73
+ with tf.name_scope("Lerp"):
74
+ return a + (b - a) * t
75
+
76
+
77
+ def lerp_clip(a: TfExpressionEx, b: TfExpressionEx, t: TfExpressionEx) -> TfExpression:
78
+ """Linear interpolation with clip."""
79
+ with tf.name_scope("LerpClip"):
80
+ return a + (b - a) * tf.clip_by_value(t, 0.0, 1.0)
81
+
82
+
83
+ def absolute_name_scope(scope: str) -> tf.name_scope:
84
+ """Forcefully enter the specified name scope, ignoring any surrounding scopes."""
85
+ return tf.name_scope(scope + "/")
86
+
87
+
88
+ def absolute_variable_scope(scope: str, **kwargs) -> tf.variable_scope:
89
+ """Forcefully enter the specified variable scope, ignoring any surrounding scopes."""
90
+ return tf.variable_scope(tf.VariableScope(name=scope, **kwargs), auxiliary_name_scope=False)
91
+
92
+
93
+ def _sanitize_tf_config(config_dict: dict = None) -> dict:
94
+ # Defaults.
95
+ cfg = dict()
96
+ cfg["rnd.np_random_seed"] = None # Random seed for NumPy. None = keep as is.
97
+ cfg["rnd.tf_random_seed"] = "auto" # Random seed for TensorFlow. 'auto' = derive from NumPy random state. None = keep as is.
98
+ cfg["env.TF_CPP_MIN_LOG_LEVEL"] = "1" # 0 = Print all available debug info from TensorFlow. 1 = Print warnings and errors, but disable debug info.
99
+ cfg["env.HDF5_USE_FILE_LOCKING"] = "FALSE" # Disable HDF5 file locking to avoid concurrency issues with network shares.
100
+ cfg["graph_options.place_pruned_graph"] = True # False = Check that all ops are available on the designated device. True = Skip the check for ops that are not used.
101
+ cfg["gpu_options.allow_growth"] = True # False = Allocate all GPU memory at the beginning. True = Allocate only as much GPU memory as needed.
102
+
103
+ # Remove defaults for environment variables that are already set.
104
+ for key in list(cfg):
105
+ fields = key.split(".")
106
+ if fields[0] == "env":
107
+ assert len(fields) == 2
108
+ if fields[1] in os.environ:
109
+ del cfg[key]
110
+
111
+ # User overrides.
112
+ if config_dict is not None:
113
+ cfg.update(config_dict)
114
+ return cfg
115
+
116
+
117
+ def init_tf(config_dict: dict = None) -> None:
118
+ """Initialize TensorFlow session using good default settings."""
119
+ # Skip if already initialized.
120
+ if tf.get_default_session() is not None:
121
+ return
122
+
123
+ # Setup config dict and random seeds.
124
+ cfg = _sanitize_tf_config(config_dict)
125
+ np_random_seed = cfg["rnd.np_random_seed"]
126
+ if np_random_seed is not None:
127
+ np.random.seed(np_random_seed)
128
+ tf_random_seed = cfg["rnd.tf_random_seed"]
129
+ if tf_random_seed == "auto":
130
+ tf_random_seed = np.random.randint(1 << 31)
131
+ if tf_random_seed is not None:
132
+ tf.set_random_seed(tf_random_seed)
133
+
134
+ # Setup environment variables.
135
+ for key, value in cfg.items():
136
+ fields = key.split(".")
137
+ if fields[0] == "env":
138
+ assert len(fields) == 2
139
+ os.environ[fields[1]] = str(value)
140
+
141
+ # Create default TensorFlow session.
142
+ create_session(cfg, force_as_default=True)
143
+
144
+
145
+ def assert_tf_initialized():
146
+ """Check that TensorFlow session has been initialized."""
147
+ if tf.get_default_session() is None:
148
+ raise RuntimeError("No default TensorFlow session found. Please call dnnlib.tflib.init_tf().")
149
+
150
+
151
+ def create_session(config_dict: dict = None, force_as_default: bool = False) -> tf.Session:
152
+ """Create tf.Session based on config dict."""
153
+ # Setup TensorFlow config proto.
154
+ cfg = _sanitize_tf_config(config_dict)
155
+ config_proto = tf.ConfigProto()
156
+ for key, value in cfg.items():
157
+ fields = key.split(".")
158
+ if fields[0] not in ["rnd", "env"]:
159
+ obj = config_proto
160
+ for field in fields[:-1]:
161
+ obj = getattr(obj, field)
162
+ setattr(obj, fields[-1], value)
163
+
164
+ # Create session.
165
+ session = tf.Session(config=config_proto)
166
+ if force_as_default:
167
+ # pylint: disable=protected-access
168
+ session._default_session = session.as_default()
169
+ session._default_session.enforce_nesting = False
170
+ session._default_session.__enter__()
171
+ return session
172
+
173
+
174
+ def init_uninitialized_vars(target_vars: List[tf.Variable] = None) -> None:
175
+ """Initialize all tf.Variables that have not already been initialized.
176
+
177
+ Equivalent to the following, but more efficient and does not bloat the tf graph:
178
+ tf.variables_initializer(tf.report_uninitialized_variables()).run()
179
+ """
180
+ assert_tf_initialized()
181
+ if target_vars is None:
182
+ target_vars = tf.global_variables()
183
+
184
+ test_vars = []
185
+ test_ops = []
186
+
187
+ with tf.control_dependencies(None): # ignore surrounding control_dependencies
188
+ for var in target_vars:
189
+ assert is_tf_expression(var)
190
+
191
+ try:
192
+ tf.get_default_graph().get_tensor_by_name(var.name.replace(":0", "/IsVariableInitialized:0"))
193
+ except KeyError:
194
+ # Op does not exist => variable may be uninitialized.
195
+ test_vars.append(var)
196
+
197
+ with absolute_name_scope(var.name.split(":")[0]):
198
+ test_ops.append(tf.is_variable_initialized(var))
199
+
200
+ init_vars = [var for var, inited in zip(test_vars, run(test_ops)) if not inited]
201
+ run([var.initializer for var in init_vars])
202
+
203
+
204
+ def set_vars(var_to_value_dict: dict) -> None:
205
+ """Set the values of given tf.Variables.
206
+
207
+ Equivalent to the following, but more efficient and does not bloat the tf graph:
208
+ tflib.run([tf.assign(var, value) for var, value in var_to_value_dict.items()]
209
+ """
210
+ assert_tf_initialized()
211
+ ops = []
212
+ feed_dict = {}
213
+
214
+ for var, value in var_to_value_dict.items():
215
+ assert is_tf_expression(var)
216
+
217
+ try:
218
+ setter = tf.get_default_graph().get_tensor_by_name(var.name.replace(":0", "/setter:0")) # look for existing op
219
+ except KeyError:
220
+ with absolute_name_scope(var.name.split(":")[0]):
221
+ with tf.control_dependencies(None): # ignore surrounding control_dependencies
222
+ setter = tf.assign(var, tf.placeholder(var.dtype, var.shape, "new_value"), name="setter") # create new setter
223
+
224
+ ops.append(setter)
225
+ feed_dict[setter.op.inputs[1]] = value
226
+
227
+ run(ops, feed_dict)
228
+
229
+
230
+ def create_var_with_large_initial_value(initial_value: np.ndarray, *args, **kwargs):
231
+ """Create tf.Variable with large initial value without bloating the tf graph."""
232
+ assert_tf_initialized()
233
+ assert isinstance(initial_value, np.ndarray)
234
+ zeros = tf.zeros(initial_value.shape, initial_value.dtype)
235
+ var = tf.Variable(zeros, *args, **kwargs)
236
+ set_vars({var: initial_value})
237
+ return var
238
+
239
+
240
+ def convert_images_from_uint8(images, drange=[-1,1], nhwc_to_nchw=False):
241
+ """Convert a minibatch of images from uint8 to float32 with configurable dynamic range.
242
+ Can be used as an input transformation for Network.run().
243
+ """
244
+ images = tf.cast(images, tf.float32)
245
+ if nhwc_to_nchw:
246
+ images = tf.transpose(images, [0, 3, 1, 2])
247
+ return images * ((drange[1] - drange[0]) / 255) + drange[0]
248
+
249
+
250
+ def convert_images_to_uint8(images, drange=[-1,1], nchw_to_nhwc=False, shrink=1):
251
+ """Convert a minibatch of images from float32 to uint8 with configurable dynamic range.
252
+ Can be used as an output transformation for Network.run().
253
+ """
254
+ images = tf.cast(images, tf.float32)
255
+ if shrink > 1:
256
+ ksize = [1, 1, shrink, shrink]
257
+ images = tf.nn.avg_pool(images, ksize=ksize, strides=ksize, padding="VALID", data_format="NCHW")
258
+ if nchw_to_nhwc:
259
+ images = tf.transpose(images, [0, 2, 3, 1])
260
+ scale = 255 / (drange[1] - drange[0])
261
+ images = images * scale + (0.5 - drange[0] * scale)
262
+ return tf.saturate_cast(images, tf.uint8)