1010import json
1111
1212import torch
13+ from packaging import version
1314from diffusers .configuration_utils import FrozenDict
1415from diffusers .models import AutoencoderKL , UNet2DConditionModel
1516from diffusers .pipeline_utils import DiffusionPipeline
1617from diffusers .pipelines .stable_diffusion .safety_checker import StableDiffusionSafetyChecker
1718from 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+ )
1927from diffusers .pipelines .stable_diffusion import StableDiffusionPipelineOutput
2028
2129from 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