hysts HF staff commited on
Commit
09ca579
1 Parent(s): 176e1d7
Files changed (13) hide show
  1. .gitignore +160 -0
  2. .gitmodules +3 -0
  3. .pre-commit-config.yaml +37 -0
  4. .style.yapf +5 -0
  5. README.md +1 -0
  6. app.py +36 -0
  7. app_generated_image.py +223 -0
  8. app_real_image.py +191 -0
  9. packages.txt +2 -0
  10. plug-and-play +1 -0
  11. requirements.txt +19 -0
  12. style.css +3 -0
  13. utils.py +5 -0
.gitignore ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ #.idea/
.gitmodules ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [submodule "plug-and-play"]
2
+ path = plug-and-play
3
+ url = https://github.com/MichalGeyer/plug-and-play
.pre-commit-config.yaml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ exclude: patch
2
+ repos:
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v4.2.0
5
+ hooks:
6
+ - id: check-executables-have-shebangs
7
+ - id: check-json
8
+ - id: check-merge-conflict
9
+ - id: check-shebang-scripts-are-executable
10
+ - id: check-toml
11
+ - id: check-yaml
12
+ - id: double-quote-string-fixer
13
+ - id: end-of-file-fixer
14
+ - id: mixed-line-ending
15
+ args: ['--fix=lf']
16
+ - id: requirements-txt-fixer
17
+ - id: trailing-whitespace
18
+ - repo: https://github.com/myint/docformatter
19
+ rev: v1.4
20
+ hooks:
21
+ - id: docformatter
22
+ args: ['--in-place']
23
+ - repo: https://github.com/pycqa/isort
24
+ rev: 5.12.0
25
+ hooks:
26
+ - id: isort
27
+ - repo: https://github.com/pre-commit/mirrors-mypy
28
+ rev: v0.991
29
+ hooks:
30
+ - id: mypy
31
+ args: ['--ignore-missing-imports']
32
+ additional_dependencies: ['types-python-slugify']
33
+ - repo: https://github.com/google/yapf
34
+ rev: v0.32.0
35
+ hooks:
36
+ - id: yapf
37
+ args: ['--parallel', '--in-place']
.style.yapf ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [style]
2
+ based_on_style = pep8
3
+ blank_line_before_nested_class_or_def = false
4
+ spaces_before_comment = 2
5
+ split_before_logical_operator = true
README.md CHANGED
@@ -5,6 +5,7 @@ colorFrom: blue
5
  colorTo: pink
6
  sdk: gradio
7
  sdk_version: 3.18.0
 
8
  app_file: app.py
9
  pinned: false
10
  ---
 
5
  colorTo: pink
6
  sdk: gradio
7
  sdk_version: 3.18.0
8
+ python_version: 3.10.9
9
  app_file: app.py
10
  pinned: false
11
  ---
app.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ import shlex
7
+ import subprocess
8
+
9
+ import gradio as gr
10
+
11
+ from app_generated_image import create_prompt_demo
12
+ from app_real_image import create_real_image_demo
13
+
14
+ DESCRIPTION = '''# Plug-and-Play diffusion features
15
+
16
+ This is an unofficial demo for [https://github.com/MichalGeyer/plug-and-play](https://github.com/MichalGeyer/plug-and-play).
17
+ '''
18
+
19
+ weight_dir = pathlib.Path('plug-and-play/models/ldm/stable-diffusion-v1')
20
+ if not weight_dir.exists():
21
+ subprocess.run(
22
+ shlex.split('mkdir -p plug-and-play/models/ldm/stable-diffusion-v1/'))
23
+ subprocess.run(
24
+ shlex.split(
25
+ 'wget https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt -O plug-and-play/models/ldm/stable-diffusion-v1/model.ckpt'
26
+ ))
27
+
28
+ with gr.Blocks(css='style.css') as demo:
29
+ gr.Markdown(DESCRIPTION)
30
+ with gr.Tabs():
31
+ with gr.TabItem('Use real image as input'):
32
+ create_real_image_demo()
33
+ with gr.TabItem('Use prompt as input'):
34
+ create_prompt_demo()
35
+
36
+ demo.queue().launch()
app_generated_image.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ import shlex
7
+ import subprocess
8
+ import tempfile
9
+
10
+ import gradio as gr
11
+ from omegaconf import OmegaConf
12
+
13
+ from utils import get_timestamp
14
+
15
+
16
+ def gen_feature_extraction_config(
17
+ exp_name: str,
18
+ prompt: str,
19
+ seed: int,
20
+ guidance_scale: float,
21
+ ddim_steps: int,
22
+ ) -> str:
23
+ config = OmegaConf.load(
24
+ 'plug-and-play/configs/pnp/feature-extraction-generated.yaml')
25
+ config.config.experiment_name = exp_name
26
+ config.config.prompt = prompt
27
+ config.config.seed = seed
28
+ config.config.scale = guidance_scale
29
+ config.config.ddim_steps = ddim_steps
30
+ temp_file = tempfile.NamedTemporaryFile(suffix='.yaml', delete=False)
31
+ with open(temp_file.name, 'w') as f:
32
+ f.write(OmegaConf.to_yaml(config))
33
+ return temp_file.name
34
+
35
+
36
+ def run_feature_extraction_command(
37
+ prompt: str,
38
+ seed: int,
39
+ guidance_scale: float,
40
+ ddim_steps: int,
41
+ ) -> tuple[str, str]:
42
+ exp_name = get_timestamp()
43
+ config_path = gen_feature_extraction_config(
44
+ exp_name,
45
+ prompt,
46
+ seed,
47
+ guidance_scale,
48
+ ddim_steps,
49
+ )
50
+ subprocess.run(shlex.split(
51
+ f'python run_features_extraction.py --config {config_path}'),
52
+ cwd='plug-and-play')
53
+ return f'plug-and-play/experiments/{exp_name}/samples/0.png', exp_name
54
+
55
+
56
+ def gen_pnp_config(
57
+ exp_name: str,
58
+ prompt: str,
59
+ guidance_scale: float,
60
+ ddim_steps: int,
61
+ feature_injection_threshold: int,
62
+ negative_prompt: str,
63
+ negative_prompt_alpha: float,
64
+ negative_prompt_schedule: str,
65
+ ) -> str:
66
+ config = OmegaConf.load('plug-and-play/configs/pnp/pnp-generated.yaml')
67
+ config.source_experiment_name = exp_name
68
+ config.prompts = [prompt]
69
+ config.scale = guidance_scale
70
+ config.num_ddim_sampling_steps = ddim_steps
71
+ config.feature_injection_threshold = feature_injection_threshold
72
+ config.negative_prompt = negative_prompt
73
+ config.negative_prompt_alpha = negative_prompt_alpha
74
+ config.negative_prompt_schedule = negative_prompt_schedule
75
+ temp_file = tempfile.NamedTemporaryFile(suffix='.yaml', delete=False)
76
+ with open(temp_file.name, 'w') as f:
77
+ f.write(OmegaConf.to_yaml(config))
78
+ return temp_file.name
79
+
80
+
81
+ def run_pnp_command(
82
+ exp_name: str,
83
+ prompt: str,
84
+ negative_prompt: str,
85
+ guidance_scale: float,
86
+ ddim_steps: int,
87
+ feature_injection_threshold: int,
88
+ negative_prompt_alpha: float,
89
+ negative_prompt_schedule: str,
90
+ ) -> str:
91
+ config_path = gen_pnp_config(
92
+ exp_name,
93
+ prompt,
94
+ guidance_scale,
95
+ ddim_steps,
96
+ feature_injection_threshold,
97
+ negative_prompt,
98
+ negative_prompt_alpha,
99
+ negative_prompt_schedule,
100
+ )
101
+ subprocess.run(shlex.split(f'python run_pnp.py --config {config_path}'),
102
+ cwd='plug-and-play')
103
+
104
+ out_dir = pathlib.Path(
105
+ f'plug-and-play/experiments/{exp_name}/translations/{guidance_scale}_{prompt.replace(" ", "_")}'
106
+ )
107
+ out_label = f'INJECTION_T_{feature_injection_threshold}_STEPS_{ddim_steps}_NP-ALPHA_{negative_prompt_alpha}_SCHEDULE_{negative_prompt_schedule}_NP_{negative_prompt.replace(" ", "_")}'
108
+ out_path = out_dir / f'{out_label}_sample_0.png'
109
+ return out_path.as_posix()
110
+
111
+
112
+ def create_prompt_demo() -> gr.Blocks:
113
+ with gr.Blocks() as demo:
114
+ with gr.Box():
115
+ gr.Markdown('Step 1')
116
+ with gr.Row():
117
+ with gr.Column():
118
+ source_prompt = gr.Text(label='Source prompt')
119
+ seed = gr.Slider(label='Seed',
120
+ minimum=0,
121
+ maximum=100000,
122
+ step=1,
123
+ value=0)
124
+ with gr.Accordion(label='Advanced settings', open=False):
125
+ source_guidance_scale = gr.Slider(
126
+ label='Guidance scale',
127
+ minimum=0,
128
+ maximum=50,
129
+ step=0.1,
130
+ value=5)
131
+ source_ddim_steps = gr.Slider(label='DDIM steps',
132
+ minimum=1,
133
+ maximum=100,
134
+ step=1,
135
+ value=50)
136
+ extract_feature_button = gr.Button(
137
+ 'Generate and extract features')
138
+ with gr.Column():
139
+ generated_image = gr.Image(label='Generated image',
140
+ type='filepath')
141
+ exp_name = gr.Variable()
142
+ with gr.Box():
143
+ gr.Markdown('Step 2')
144
+ with gr.Row():
145
+ with gr.Column():
146
+ translation_prompt = gr.Text(
147
+ label='Prompt for translation')
148
+ negative_prompt = gr.Text(label='Negative prompt')
149
+ with gr.Accordion(label='Advanced settings', open=False):
150
+ guidance_scale = gr.Slider(label='Guidance scale',
151
+ minimum=0,
152
+ maximum=50,
153
+ step=0.1,
154
+ value=7.5)
155
+ ddim_steps = gr.Slider(
156
+ label='Number of inference steps',
157
+ minimum=1,
158
+ maximum=100,
159
+ step=1,
160
+ value=50)
161
+ feature_injection_threshold = gr.Slider(
162
+ label='Feature injection threshold',
163
+ minimum=0,
164
+ maximum=100,
165
+ step=1,
166
+ value=40)
167
+ negative_prompt_alpha = gr.Slider(
168
+ label='Negative prompt alpha',
169
+ minimum=0,
170
+ maximum=1,
171
+ step=0.01,
172
+ value=0.75)
173
+ negative_prompt_schedule = gr.Dropdown(
174
+ label='Negative prompt schedule',
175
+ choices=['linear', 'constant', 'exp'],
176
+ value='linear')
177
+ generate_button = gr.Button('Generate')
178
+ with gr.Column():
179
+ result = gr.Image(label='Result', type='filepath')
180
+ with gr.Row():
181
+ gr.Examples(examples=[
182
+ ['horse in mud', 50, 'a photo of a zebra in the snow'],
183
+ ['horse in mud', 50, 'a photo of a husky in the grass'],
184
+ ],
185
+ inputs=[
186
+ source_prompt,
187
+ seed,
188
+ translation_prompt,
189
+ ])
190
+
191
+ extract_feature_button.click(
192
+ fn=run_feature_extraction_command,
193
+ inputs=[
194
+ source_prompt,
195
+ seed,
196
+ source_guidance_scale,
197
+ source_ddim_steps,
198
+ ],
199
+ outputs=[
200
+ generated_image,
201
+ exp_name,
202
+ ],
203
+ )
204
+ generate_button.click(
205
+ fn=run_pnp_command,
206
+ inputs=[
207
+ exp_name,
208
+ translation_prompt,
209
+ negative_prompt,
210
+ guidance_scale,
211
+ ddim_steps,
212
+ feature_injection_threshold,
213
+ negative_prompt_alpha,
214
+ negative_prompt_schedule,
215
+ ],
216
+ outputs=result,
217
+ )
218
+ return demo
219
+
220
+
221
+ if __name__ == '__main__':
222
+ demo = create_prompt_demo()
223
+ demo.queue().launch()
app_real_image.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ import shlex
7
+ import subprocess
8
+ import tempfile
9
+
10
+ import gradio as gr
11
+ from omegaconf import OmegaConf
12
+
13
+ from utils import get_timestamp
14
+
15
+
16
+ def gen_feature_extraction_config(exp_name: str, init_image_path: str) -> str:
17
+ config = OmegaConf.load(
18
+ 'plug-and-play/configs/pnp/feature-extraction-real.yaml')
19
+ config.config.experiment_name = exp_name
20
+ config.config.init_img = init_image_path
21
+ temp_file = tempfile.NamedTemporaryFile(suffix='.yaml', delete=False)
22
+ with open(temp_file.name, 'w') as f:
23
+ f.write(OmegaConf.to_yaml(config))
24
+ return temp_file.name
25
+
26
+
27
+ def run_feature_extraction_command(init_image_path: str) -> tuple[str, str]:
28
+ exp_name = get_timestamp()
29
+ config_path = gen_feature_extraction_config(exp_name, init_image_path)
30
+ subprocess.run(shlex.split(
31
+ f'python run_features_extraction.py --config {config_path}'),
32
+ cwd='plug-and-play')
33
+ return f'plug-and-play/experiments/{exp_name}/samples/0.png', exp_name
34
+
35
+
36
+ def gen_pnp_config(
37
+ exp_name: str,
38
+ prompt: str,
39
+ guidance_scale: float,
40
+ ddim_steps: int,
41
+ feature_injection_threshold: int,
42
+ negative_prompt: str,
43
+ negative_prompt_alpha: float,
44
+ negative_prompt_schedule: str,
45
+ ) -> str:
46
+ config = OmegaConf.load('plug-and-play/configs/pnp/pnp-real.yaml')
47
+ config.source_experiment_name = exp_name
48
+ config.prompts = [prompt]
49
+ config.scale = guidance_scale
50
+ config.num_ddim_sampling_steps = ddim_steps
51
+ config.feature_injection_threshold = feature_injection_threshold
52
+ config.negative_prompt = negative_prompt
53
+ config.negative_prompt_alpha = negative_prompt_alpha
54
+ config.negative_prompt_schedule = negative_prompt_schedule
55
+ temp_file = tempfile.NamedTemporaryFile(suffix='.yaml', delete=False)
56
+ with open(temp_file.name, 'w') as f:
57
+ f.write(OmegaConf.to_yaml(config))
58
+ return temp_file.name
59
+
60
+
61
+ def run_pnp_command(
62
+ exp_name: str,
63
+ prompt: str,
64
+ negative_prompt: str,
65
+ guidance_scale: float,
66
+ ddim_steps: int,
67
+ feature_injection_threshold: int,
68
+ negative_prompt_alpha: float,
69
+ negative_prompt_schedule: str,
70
+ ) -> str:
71
+ config_path = gen_pnp_config(
72
+ exp_name,
73
+ prompt,
74
+ guidance_scale,
75
+ ddim_steps,
76
+ feature_injection_threshold,
77
+ negative_prompt,
78
+ negative_prompt_alpha,
79
+ negative_prompt_schedule,
80
+ )
81
+ subprocess.run(shlex.split(f'python run_pnp.py --config {config_path}'),
82
+ cwd='plug-and-play')
83
+
84
+ out_dir = pathlib.Path(
85
+ f'plug-and-play/experiments/{exp_name}/translations/{guidance_scale}_{prompt.replace(" ", "_")}'
86
+ )
87
+ out_label = f'INJECTION_T_{feature_injection_threshold}_STEPS_{ddim_steps}_NP-ALPHA_{negative_prompt_alpha}_SCHEDULE_{negative_prompt_schedule}_NP_{negative_prompt.replace(" ", "_")}'
88
+ out_path = out_dir / f'{out_label}_sample_0.png'
89
+ return out_path.as_posix()
90
+
91
+
92
+ def create_real_image_demo():
93
+ with gr.Blocks() as demo:
94
+ with gr.Box():
95
+ gr.Markdown('Step 1')
96
+ with gr.Row():
97
+ with gr.Column():
98
+ image = gr.Image(label='Input image', type='filepath')
99
+ extract_feature_button = gr.Button(
100
+ 'Reconstruct and extract features')
101
+ with gr.Column():
102
+ reconstructed_image = gr.Image(label='Reconstructed image',
103
+ type='filepath')
104
+ exp_name = gr.Variable()
105
+ with gr.Box():
106
+ gr.Markdown('Step 2')
107
+ with gr.Row():
108
+ with gr.Column():
109
+ translation_prompt = gr.Text(
110
+ label='Prompt for translation')
111
+ negative_prompt = gr.Text(label='Negative prompt')
112
+ with gr.Accordion(label='Advanced settings', open=False):
113
+ guidance_scale = gr.Slider(label='Guidance scale',
114
+ minimum=0,
115
+ maximum=50,
116
+ step=0.1,
117
+ value=10)
118
+ ddim_steps = gr.Slider(
119
+ label='Number of inference steps',
120
+ minimum=1,
121
+ maximum=100,
122
+ step=1,
123
+ value=50)
124
+ feature_injection_threshold = gr.Slider(
125
+ label='Feature injection threshold',
126
+ minimum=0,
127
+ maximum=100,
128
+ step=1,
129
+ value=40)
130
+ negative_prompt_alpha = gr.Slider(
131
+ label='Negative prompt alpha',
132
+ minimum=0,
133
+ maximum=1,
134
+ step=0.01,
135
+ value=1)
136
+ negative_prompt_scheduler = gr.Dropdown(
137
+ label='Negative prompt schedule',
138
+ choices=['linear', 'constant', 'exp'],
139
+ value='linear')
140
+ generate_button = gr.Button('Generate')
141
+ with gr.Column():
142
+ result = gr.Image(label='Result', type='filepath')
143
+
144
+ with gr.Row():
145
+ gr.Examples(examples=[
146
+ [
147
+ 'plug-and-play/data/horse.png',
148
+ 'a photo of a robot horse',
149
+ 'a photo of a white horse',
150
+ ],
151
+ [
152
+ 'plug-and-play/data/horse.png',
153
+ 'a photo of a bronze horse in a museum',
154
+ 'a photo of a white horse',
155
+ ],
156
+ ],
157
+ inputs=[
158
+ image,
159
+ translation_prompt,
160
+ negative_prompt,
161
+ ])
162
+
163
+ extract_feature_button.click(
164
+ fn=run_feature_extraction_command,
165
+ inputs=image,
166
+ outputs=[
167
+ reconstructed_image,
168
+ exp_name,
169
+ ],
170
+ )
171
+ generate_button.click(
172
+ fn=run_pnp_command,
173
+ inputs=[
174
+ exp_name,
175
+ translation_prompt,
176
+ negative_prompt,
177
+ guidance_scale,
178
+ ddim_steps,
179
+ feature_injection_threshold,
180
+ negative_prompt_alpha,
181
+ negative_prompt_scheduler,
182
+ ],
183
+ outputs=result,
184
+ )
185
+
186
+ return demo
187
+
188
+
189
+ if __name__ == '__main__':
190
+ demo = create_real_image_demo()
191
+ demo.queue().launch()
packages.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ ffmpeg
2
+ wget
plug-and-play ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit ce9e4e23c24b4241cb9ecae9ea0b090c70871870
requirements.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ albumentations==1.3.0
2
+ -e git+https://github.com/openai/CLIP.git@main#egg=clip
3
+ diffusers==0.12.1
4
+ einops==0.6.0
5
+ gradio==3.18.0
6
+ huggingface-hub==0.12.0
7
+ imageio==2.25.0
8
+ imageio-ffmpeg==0.4.8
9
+ kornia==0.6.9
10
+ omegaconf==2.3.0
11
+ opencv-python-headless==4.7.0.68
12
+ Pillow==9.4.0
13
+ python-slugify==7.0.0
14
+ pytorch-lightning==1.9.0
15
+ scikit-learn==1.2.0
16
+ -e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
17
+ torch==1.13.1
18
+ torchvision==0.14.1
19
+ transformers==4.26.0
style.css ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ h1 {
2
+ text-align: center;
3
+ }
utils.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import datetime
2
+
3
+
4
+ def get_timestamp() -> str:
5
+ return datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S-%f')