Skip to content

Commit 2306c69

Browse files
commit
0 parents  commit 2306c69

File tree

102 files changed

+12451
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+12451
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+

README.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# StyleGAN-Human: A Data-Centric Odyssey of Human Generation
2+
<img src="./img/demo_V5_thumbnails-min.png" width="96%" height="96%">
3+
4+
<!--
5+
**stylegan-human/StyleGAN-Human** is a ✨ _special_ ✨ repository because its `README.md` (this file) appears on your GitHub profile.
6+
7+
-->
8+
9+
>
10+
>
11+
> **Abstract:** *Unconditional human image generation is an important task in vision and graphics, which enables various applications in the creative industry. Existing studies in this field mainly focus on "network engineering" such as designing new components and objective functions. This work takes a data-centric perspective and investigates multiple critical aspects in "data engineering", which we believe would complement the current practice. To facilitate a comprehensive study, we collect and annotate a large-scale human image dataset with over 200K samples capturing diverse poses and textures. Equipped with this large dataset, we rigorously investigate three essential factors in data engineering for StyleGAN-based human generation, namely data size, data distribution, and data alignment. Extensive experiments reveal several valuable observations w.r.t. these aspects: 1) Large-scale data, more than 40K images, are needed to train a high-fidelity unconditional human generation model with vanilla StyleGAN. 2) A balanced training set helps improve the generation quality with rare face poses compared to the long-tailed counterpart, whereas simply balancing the clothing texture distribution does not effectively bring an improvement. 3) Human GAN models with body centers for alignment outperform models trained using face centers or pelvis points as alignment anchors. In addition, a model zoo and human editing applications are demonstrated to facilitate future research in the community.* <br>
12+
**Keyword:** Human Image Generation, Data-Centric, StyleGAN
13+
14+
Jianglin Fu, Shikai Li, [Yuming Jiang](https://yumingj.github.io/), [Kwan-Yee Lin](https://kwanyeelin.github.io/), [Chen Qian](https://scholar.google.com/citations?user=AerkT0YAAAAJ&hl=zh-CN), [Chen Change Loy](https://www.mmlab-ntu.com/person/ccloy/), [Wayne Wu](https://dblp.org/pid/50/8731.html), and [Ziwei Liu](https://liuziwei7.github.io/) <br>
15+
**[[Demo Video]](https://youtu.be/nIrb9hwsdcI)** | **[[Project Page]](https://stylegan-human.github.io/)** | **[[Paper]](https://arxiv.org/abs/1234.12345)**
16+
17+
## Updates
18+
19+
- [04/2022] This code and project page is created.
20+
21+
## Model Zoo
22+
23+
| Structure | 1024x512 | 512x256 |
24+
| --------- |:----------:| :-----: |
25+
| StyleGAN1 |[stylegan_human_v1_1024.pkl](https://drive.google.com/file/d/1h-R-IV-INGdPEzj4P9ml6JTEvihuNgLX/view?usp=sharing)| to be released |
26+
| StyleGAN2 |[stylegan_human_v2_1024.pkl](https://drive.google.com/file/d/1FlAb1rYa0r_--Zj_ML8e6shmaF28hQb5/view?usp=sharing)| [stylegan_human_v2_512.pkl](https://drive.google.com/file/d/1dlFEHbu-WzQWJl7nBBZYcTyo000H9hVm/view?usp=sharing) |
27+
| StyleGAN3 |to be released | [stylegan_human_v3_512.pkl]() |
28+
29+
30+
## Web Demo <a href="https://colab.research.google.com/drive/1sgxoDM55iM07FS54vz9ALg1XckiYA2On"><img src="https://colab.research.google.com/assets/colab-badge.svg" height=22.5></a>
31+
32+
We prepare a Colab demo to allow you to synthesize images with the provided models, as well as visualize the performance of style-mixing, interpolation, and attributes editing.
33+
The notebook will guide you to install the necessary environment and download pretrained models. The output images can be found in `./StyleGAN-Human/outputs/`.
34+
Hope you enjoy!
35+
36+
## Usage
37+
38+
### System requirements
39+
* The original code bases are [stylegan (tensorflow)](https://github.com/NVlabs/stylegan), [stylegan2-ada (pytorch)](https://github.com/NVlabs/stylegan2-ada-pytorch), [stylegan3 (pytorch)](https://github.com/NVlabs/stylegan3), released by NVidia
40+
41+
* We tested in Python 3.8.5 and PyTorch 1.9.1 with CUDA 11.1 as well as Pytorch 1.7.1 with CUDA 10.1. (See https://pytorch.org for PyTorch install instructions.)
42+
43+
### Installation
44+
To work with this project on your own machine, you need to install the environmnet as follows:
45+
46+
```
47+
conda env create -f environment.yml
48+
conda activate stylehuman
49+
# [Optional: tensorflow 1.x is required for StyleGAN1. ]
50+
pip install nvidia-pyindex
51+
pip install nvidia-tensorflow[horovod]
52+
pip install nvidia-tensorboard==1.15
53+
```
54+
Extra notes:
55+
1. In case having some conflicts when calling CUDA version, please try to empty the LD_LIBRARY_PATH. For example:
56+
```
57+
LD_LIBRARY_PATH=; python generate.py --outdir=out/stylegan_human_v2_1024 --trunc=1 --seeds=1,3,5,7
58+
--network=pretrained_models/stylegan_human_v2_1024.pkl --version 2
59+
```
60+
61+
62+
2. We found the following troubleshooting links might be helpful: [1.](https://github.com/NVlabs/stylegan3), [2.](https://github.com/NVlabs/stylegan3/blob/main/docs/troubleshooting.md)
63+
64+
### Pretrained models
65+
Please put the downloaded pretrained models [from above link](#Model-Zoo) under the folder 'pretrained_models'.
66+
67+
68+
### Generate full-body human images using our pretrained model
69+
```
70+
# Generate human full-body images without truncation
71+
python generate.py --outdir=outputs/generate/stylegan_human_v2_1024 --trunc=1 --seeds=1,3,5,7 --network=pretrained_models/stylegan_human_v2_1024.pkl --version 2
72+
73+
# Generate human full-body images with truncation
74+
python generate.py --outdir=outputs/generate/stylegan_human_v2_1024 --trunc=0.8 --seeds=0-10 --network=pretrained_models/stylegan_human_v2_1024.pkl --version 2
75+
76+
# Generate human full-body images using stylegan V1
77+
python generate.py --outdir=outputs/generate/stylegan_human_v1_1024 --network=pretrained_models/stylegan_human_v1_1024.pkl --version 1 --seeds=1,3,5
78+
```
79+
80+
81+
### Interpolation
82+
```
83+
python interpolation.py --network=pretrained_models/stylegan_human_v2_1024.pkl --seeds=85,100 --outdir=outputs/inter_gifs
84+
```
85+
86+
### Style-mixing **image** using stylegan2
87+
```
88+
python style_mixing.py --network=pretrained_models/stylegan_human_v2_1024.pkl --rows=85,100,75,458,1500 \\
89+
--cols=55,821,1789,293 --styles=0-3 --outdir=outputs/stylemixing
90+
```
91+
92+
### Style-mixing **video** using stylegan2
93+
```
94+
python stylemixing_video.py --network=pretrained_models/stylegan_human_v2_1024.pkl --row-seed=3859 \\
95+
--col-seeds=3098,31759,3791 --col-styles=8-12 --trunc=0.8 --outdir=outputs/stylemixing_video
96+
```
97+
98+
### Editing with InterfaceGAN, StyleSpace, and Sefa
99+
```
100+
python edit.py --network pretrained_models/stylegan_human_v2_1024.pkl --attr_name upper_length \\
101+
--seeds 61531,61570,61571,61610 --outdir outputs/edit_results
102+
```
103+
104+
Note:
105+
1. ''upper_length'' and ''bottom_length'' of ''attr_name'' are available for demo.
106+
2. Layers to control and editing strength are set in edit/edit_config.py.
107+
108+
109+
### Demo for [InsetGAN](https://arxiv.org/abs/2203.07293)
110+
We implement a quick demo using the key idea from InsetGAN: combining the face generated by FFHQ with the human-body generated by our pretrained model, optimizing both face and body latent codes to get a coherent full-body image.
111+
Before running the script, you need to download the [FFHQ face model]( https://docs.google.com/uc?export=download&confirm=t&id=125OG7SMkXI-Kf2aqiwLLHyCvSW-gZk3M), or you can use your own face model, as well as [pretrained face landmark](https://docs.google.com/uc?export=download&confirm=&id=1A82DnJBJzt8wI2J8ZrCK5fgHcQ2-tcWM) and [pretrained CNN face detection model for dlib](https://docs.google.com/uc?export=download&confirm=&id=1MduBgju5KFNrQfDLoQXJ_1_h5MnctCIG)
112+
```
113+
python insetgan.py --body_network=pretrained_models/stylegan_human_v2_1024.pkl --face_network=pretrained_models/ffhq.pkl \\
114+
--body_seed=82 --face_seed=43 --trunc=0.6 --outdir=outputs/insetgan/ --video 1
115+
```
116+
117+
## Results
118+
### Editing
119+
![](./img/editing.gif)
120+
121+
### InsetGAN re-implementation
122+
![](./img/insetgan.gif)
123+
124+
125+
### For more demo, please visit our [**web page**](https://stylegan-human.github.io/) .
126+
127+
128+
## TODO List
129+
<ul>
130+
<li><input type="checkbox"> Release 1024x512 version of StyleGAN-Human based on StyleGAN3 </li>
131+
<li><input type="checkbox" unchecked> Release 512x256 version of StyleGAN-Human based on StyleGAN1 </li>
132+
<li><input type="checkbox" unchecked> Release face model for downstream task : InsetGAN</li>
133+
<li><input type="checkbox" unchecked> Add Inversion Script into the provided editing pipeline</li>
134+
<li><input type="checkbox" unchecked> Release Dataset </li>
135+
</ul>
136+
137+
138+
## Citation
139+
If you find this work useful for your research, please consider citing our paper:
140+
141+
```bibtex
142+
@article{fu2022styleganhuman,
143+
title={StyleGAN-Human: A Data-Centric Odyssey of Human Generation},
144+
author={Fu, Jianglin and Li, Shikai and Jiang, Yuming and Lin, Kwan-Yee and Qian, Chen and Loy, Chen-Change and Wu, Wayne and Liu, Ziwei },
145+
journal = {arXiv preprint},
146+
volume = {arXiv:1234.12345},
147+
year = {2022}
148+
```
149+
150+
## Acknowlegement
151+
Part of the code is borrowed from [stylegan (tensorflow)](https://github.com/NVlabs/stylegan), [stylegan2-ada (pytorch)](https://github.com/NVlabs/stylegan2-ada-pytorch), [stylegan3 (pytorch)](https://github.com/NVlabs/stylegan3).

dnnlib/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) SenseTime Research. All rights reserved.
2+
3+
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
4+
#
5+
# NVIDIA CORPORATION and its licensors retain all intellectual property
6+
# and proprietary rights in and to this software, related documentation
7+
# and any modifications thereto. Any use, reproduction, disclosure or
8+
# distribution of this software and related documentation without an express
9+
# license agreement from NVIDIA CORPORATION is strictly prohibited.
10+
11+
from .util import EasyDict, make_cache_dir_path

dnnlib/tflib/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) SenseTime Research. All rights reserved.
2+
3+
# Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
4+
#
5+
# This work is made available under the Nvidia Source Code License-NC.
6+
# To view a copy of this license, visit
7+
# https://nvlabs.github.io/stylegan2/license.html
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

dnnlib/tflib/autosummary.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# Copyright (c) SenseTime Research. All rights reserved.
2+
3+
# Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
4+
#
5+
# This work is made available under the Nvidia Source Code License-NC.
6+
# To view a copy of this license, visit
7+
# https://nvlabs.github.io/stylegan2/license.html
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)

0 commit comments

Comments
 (0)