Skip to content

Commit c1871c1

Browse files
authored
Merge pull request #121 from nateraw/diffusers-0.9.0
Diffusers 0.9.0
2 parents ffbea6d + c11d154 commit c1871c1

6 files changed

Lines changed: 90 additions & 24 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,5 @@ dmypy.json
132132
dreams
133133
images
134134
run.py
135-
test_outputs
135+
test_outputs
136+
examples/music

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,9 @@ Enjoy 🤗
137137

138138
You can also 4x upsample your images with [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN)!
139139

140-
First, you'll need to install it...
140+
It's included when you pip install the latest version of `stable-diffusion-videos`!
141141

142-
```bash
143-
pip install realesrgan
144-
```
145-
146-
Then, you'll be able to use `upsample=True` in the `walk` function, like this:
142+
You'll be able to use `upsample=True` in the `walk` function, like this:
147143

148144
```python
149145
pipeline.walk(['a cat', 'a dog'], [234, 345], upsample=True)

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
transformers
2-
diffusers==0.6.0
1+
transformers>=4.21.0
2+
diffusers==0.9.0
33
scipy
44
fire
55
gradio
66
librosa
77
av<10.0.0
8+
realesrgan==0.2.5.0

setup.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ def get_version() -> str:
1414
with open("requirements.txt", "r") as f:
1515
requirements = f.read().splitlines()
1616

17-
extras = {}
18-
extras['realesrgan'] = ['realesrgan==0.2.5.0']
19-
2017
setup(
2118
name="stable_diffusion_videos",
2219
version=get_version(),
@@ -29,6 +26,5 @@ def get_version() -> str:
2926
long_description_content_type="text/markdown",
3027
license="Apache",
3128
install_requires=requirements,
32-
extras_require=extras,
3329
packages=find_packages(),
3430
)

stable_diffusion_videos/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,4 @@ def __dir__():
114114
},
115115
)
116116

117-
__version__ = "0.6.2"
117+
__version__ = "0.7.0"

stable_diffusion_videos/stable_diffusion_pipeline.py

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@
1010
import json
1111

1212
import torch
13+
from packaging import version
1314
from diffusers.configuration_utils import FrozenDict
1415
from diffusers.models import AutoencoderKL, UNet2DConditionModel
1516
from diffusers.pipeline_utils import DiffusionPipeline
1617
from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker
1718
from diffusers.utils import deprecate, logging
18-
from diffusers.schedulers import DDIMScheduler, LMSDiscreteScheduler, PNDMScheduler
19+
from diffusers.schedulers import (
20+
DDIMScheduler,
21+
DPMSolverMultistepScheduler,
22+
EulerAncestralDiscreteScheduler,
23+
EulerDiscreteScheduler,
24+
LMSDiscreteScheduler,
25+
PNDMScheduler,
26+
)
1927
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
2028

2129
from transformers import CLIPFeatureExtractor, CLIPTextModel, CLIPTokenizer
@@ -166,9 +174,17 @@ def __init__(
166174
text_encoder: CLIPTextModel,
167175
tokenizer: CLIPTokenizer,
168176
unet: UNet2DConditionModel,
169-
scheduler: Union[DDIMScheduler, PNDMScheduler, LMSDiscreteScheduler],
177+
scheduler: Union[
178+
DDIMScheduler,
179+
PNDMScheduler,
180+
LMSDiscreteScheduler,
181+
EulerDiscreteScheduler,
182+
EulerAncestralDiscreteScheduler,
183+
DPMSolverMultistepScheduler,
184+
],
170185
safety_checker: StableDiffusionSafetyChecker,
171186
feature_extractor: CLIPFeatureExtractor,
187+
requires_safety_checker: bool = True,
172188
):
173189
super().__init__()
174190

@@ -186,8 +202,21 @@ def __init__(
186202
new_config["steps_offset"] = 1
187203
scheduler._internal_dict = FrozenDict(new_config)
188204

189-
if safety_checker is None:
190-
logger.warn(
205+
if hasattr(scheduler.config, "clip_sample") and scheduler.config.clip_sample is True:
206+
deprecation_message = (
207+
f"The configuration file of this scheduler: {scheduler} has not set the configuration `clip_sample`."
208+
" `clip_sample` should be set to False in the configuration file. Please make sure to update the"
209+
" config accordingly as not setting `clip_sample` in the config might lead to incorrect results in"
210+
" future versions. If you have downloaded this checkpoint from the Hugging Face Hub, it would be very"
211+
" nice if you could open a Pull request for the `scheduler/scheduler_config.json` file"
212+
)
213+
deprecate("clip_sample not set", "1.0.0", deprecation_message, standard_warn=False)
214+
new_config = dict(scheduler.config)
215+
new_config["clip_sample"] = False
216+
scheduler._internal_dict = FrozenDict(new_config)
217+
218+
if safety_checker is None and requires_safety_checker:
219+
logger.warning(
191220
f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"
192221
" that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"
193222
" results in services or applications open to the public. Both the diffusers team and Hugging Face"
@@ -196,6 +225,33 @@ def __init__(
196225
" information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."
197226
)
198227

228+
if safety_checker is not None and feature_extractor is None:
229+
raise ValueError(
230+
"Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"
231+
" checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."
232+
)
233+
234+
is_unet_version_less_0_9_0 = hasattr(unet.config, "_diffusers_version") and version.parse(
235+
version.parse(unet.config._diffusers_version).base_version
236+
) < version.parse("0.9.0.dev0")
237+
is_unet_sample_size_less_64 = hasattr(unet.config, "sample_size") and unet.config.sample_size < 64
238+
if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:
239+
deprecation_message = (
240+
"The configuration file of the unet has set the default `sample_size` to smaller than"
241+
" 64 which seems highly unlikely .If you're checkpoint is a fine-tuned version of any of the"
242+
" following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"
243+
" CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"
244+
" \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"
245+
" configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"
246+
" in the config might lead to incorrect results in future versions. If you have downloaded this"
247+
" checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"
248+
" the `unet/config.json` file"
249+
)
250+
deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False)
251+
new_config = dict(unet.config)
252+
new_config["sample_size"] = 64
253+
unet._internal_dict = FrozenDict(new_config)
254+
199255
self.register_modules(
200256
vae=vae,
201257
text_encoder=text_encoder,
@@ -205,6 +261,9 @@ def __init__(
205261
safety_checker=safety_checker,
206262
feature_extractor=feature_extractor,
207263
)
264+
self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)
265+
self.register_to_config(requires_safety_checker=requires_safety_checker)
266+
208267

209268
def enable_attention_slicing(self, slice_size: Optional[Union[str, int]] = "auto"):
210269
r"""
@@ -218,9 +277,14 @@ def enable_attention_slicing(self, slice_size: Optional[Union[str, int]] = "auto
218277
`attention_head_dim` must be a multiple of `slice_size`.
219278
"""
220279
if slice_size == "auto":
221-
# half the attention head size is usually a good trade-off between
222-
# speed and memory
223-
slice_size = self.unet.config.attention_head_dim // 2
280+
if isinstance(self.unet.config.attention_head_dim, int):
281+
# half the attention head size is usually a good trade-off between
282+
# speed and memory
283+
slice_size = self.unet.config.attention_head_dim // 2
284+
else:
285+
# if `attention_head_dim` is a list, take the smallest head size
286+
slice_size = min(self.unet.config.attention_head_dim)
287+
224288
self.unet.set_attention_slice(slice_size)
225289

226290
def disable_attention_slicing(self):
@@ -361,7 +425,7 @@ def __call__(
361425
uncond_tokens: List[str]
362426
if negative_prompt is None:
363427
uncond_tokens = [""]
364-
elif type(prompt) is not type(negative_prompt):
428+
elif text_embeddings is None and type(prompt) is not type(negative_prompt):
365429
raise TypeError(
366430
f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="
367431
f" {type(prompt)}."
@@ -524,6 +588,7 @@ def make_clip_frames(
524588
image_file_ext: str = ".png",
525589
T: np.ndarray = None,
526590
skip: int = 0,
591+
negative_prompt: str = None,
527592
):
528593
save_path = Path(save_path)
529594
save_path.mkdir(parents=True, exist_ok=True)
@@ -559,6 +624,7 @@ def make_clip_frames(
559624
eta=eta,
560625
num_inference_steps=num_inference_steps,
561626
output_type="pil" if not upsample else "numpy",
627+
negative_prompt=negative_prompt,
562628
)["images"]
563629

564630
for image in outputs:
@@ -588,6 +654,7 @@ def walk(
588654
audio_start_sec: Optional[Union[int, float]] = None,
589655
margin: Optional[float] = 1.0,
590656
smooth: Optional[float] = 0.0,
657+
negative_prompt: Optional[str] = None,
591658
):
592659
"""Generate a video from a sequence of prompts and seeds. Optionally, add audio to the
593660
video to interpolate to the intensity of the audio.
@@ -638,6 +705,8 @@ def walk(
638705
Margin from librosa hpss to use for audio interpolation.
639706
smooth (Optional[float], *optional*, defaults to 0.0):
640707
Smoothness of the audio interpolation. 1.0 means linear interpolation.
708+
negative_prompt (Optional[str], *optional*, defaults to None):
709+
Optional negative prompt to use. Same across all prompts.
641710
642711
This function will create sub directories for each prompt and seed pair.
643712
@@ -710,6 +779,7 @@ def walk(
710779
width=width,
711780
audio_filepath=audio_filepath,
712781
audio_start_sec=audio_start_sec,
782+
negative_prompt=negative_prompt,
713783
),
714784
indent=2,
715785
sort_keys=False,
@@ -729,6 +799,7 @@ def walk(
729799
width = data["width"]
730800
audio_filepath = data["audio_filepath"]
731801
audio_start_sec = data["audio_start_sec"]
802+
negative_prompt = data.get("negative_prompt", None)
732803

733804
for i, (prompt_a, prompt_b, seed_a, seed_b, num_step) in enumerate(
734805
zip(prompts, prompts[1:], seeds, seeds[1:], num_interpolation_steps)
@@ -771,7 +842,6 @@ def walk(
771842
width=width,
772843
upsample=upsample,
773844
batch_size=batch_size,
774-
skip=skip,
775845
T=get_timesteps_arr(
776846
audio_filepath,
777847
offset=audio_offset,
@@ -782,6 +852,8 @@ def walk(
782852
)
783853
if audio_filepath
784854
else None,
855+
skip=skip,
856+
negative_prompt=negative_prompt,
785857
)
786858
make_video_pyav(
787859
save_path,
@@ -805,7 +877,7 @@ def walk(
805877
sr=44100,
806878
)
807879

808-
def embed_text(self, text):
880+
def embed_text(self, text, negative_prompt=None):
809881
"""Helper to embed some text"""
810882
with torch.autocast("cuda"):
811883
text_input = self.tokenizer(

0 commit comments

Comments
 (0)