From 4deb16e8305cd31fc6baf40acd137dfb66d49839 Mon Sep 17 00:00:00 2001 From: Patrick von Platen Date: Wed, 5 Oct 2022 22:20:53 +0200 Subject: [PATCH] [Docs] Advertise fp16 instead of autocast (#740) up --- README.md | 29 +++++++++++++++++++++---- docs/source/api/pipelines/overview.mdx | 12 +++------- docs/source/optimization/fp16.mdx | 9 +++++--- docs/source/training/text_inversion.mdx | 4 +--- docs/source/using-diffusers/img2img.mdx | 4 +--- docs/source/using-diffusers/inpaint.mdx | 4 +--- examples/dreambooth/README.md | 6 +---- examples/dreambooth/train_dreambooth.py | 5 +---- examples/textual_inversion/README.md | 5 +---- 9 files changed, 40 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index b5ecc35c..f2abe197 100644 --- a/README.md +++ b/README.md @@ -74,11 +74,14 @@ You need to accept the model license before downloading or using the Stable Diff ### Text-to-Image generation with Stable Diffusion +We recommend using the model in [half-precision (`fp16`)](https://pytorch.org/blog/accelerating-training-on-nvidia-gpus-with-pytorch-automatic-mixed-precision/) as it gives almost always the same results as full +precision while being roughly twice as fast and requiring half the amount of GPU RAM. + ```python # make sure you're logged in with `huggingface-cli login` from diffusers import StableDiffusionPipeline -pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4") +pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", torch_type=torch.float16, revision="fp16") pipe = pipe.to("cuda") prompt = "a photo of an astronaut riding a horse on mars" @@ -105,8 +108,8 @@ prompt = "a photo of an astronaut riding a horse on mars" image = pipe(prompt).images[0] ``` -If you are limited by GPU memory, you might want to consider using the model in `fp16` as -well as chunking the attention computation. +If you are limited by GPU memory, you might want to consider chunking the attention computation in addition +to using `fp16`. The following snippet should result in less than 4GB VRAM. ```python @@ -122,7 +125,7 @@ pipe.enable_attention_slicing() image = pipe(prompt).images[0] ``` -Finally, if you wish to use a different scheduler, you can simply instantiate +If you wish to use a different scheduler, you can simply instantiate it before the pipeline and pass it to `from_pretrained`. ```python @@ -148,6 +151,24 @@ image = pipe(prompt).images[0] image.save("astronaut_rides_horse.png") ``` +If you want to run Stable Diffusion on CPU or you want to have maximum precision on GPU, +please run the model in the default *full-precision* setting: + +```python +# make sure you're logged in with `huggingface-cli login` +from diffusers import StableDiffusionPipeline + +pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4") + +# disable the following line if you run on CPU +pipe = pipe.to("cuda") + +prompt = "a photo of an astronaut riding a horse on mars" +image = pipe(prompt).images[0] + +image.save("astronaut_rides_horse.png") +``` + ### Image-to-Image text-guided generation with Stable Diffusion The `StableDiffusionImg2ImgPipeline` lets you pass a text prompt and an initial image to condition the generation of new images. diff --git a/docs/source/api/pipelines/overview.mdx b/docs/source/api/pipelines/overview.mdx index 68b783be..7b2d89e8 100644 --- a/docs/source/api/pipelines/overview.mdx +++ b/docs/source/api/pipelines/overview.mdx @@ -98,15 +98,13 @@ logic including pre-processing, an unrolled diffusion loop, and post-processing ```python # make sure you're logged in with `huggingface-cli login` -from torch import autocast from diffusers import StableDiffusionPipeline, LMSDiscreteScheduler pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4") pipe = pipe.to("cuda") prompt = "a photo of an astronaut riding a horse on mars" -with autocast("cuda"): - image = pipe(prompt).images[0] +image = pipe(prompt).images[0] image.save("astronaut_rides_horse.png") ``` @@ -116,7 +114,6 @@ image.save("astronaut_rides_horse.png") The `StableDiffusionImg2ImgPipeline` lets you pass a text prompt and an initial image to condition the generation of new images. ```python -from torch import autocast import requests from PIL import Image from io import BytesIO @@ -138,8 +135,7 @@ init_image = init_image.resize((768, 512)) prompt = "A fantasy landscape, trending on artstation" -with autocast("cuda"): - images = pipe(prompt=prompt, init_image=init_image, strength=0.75, guidance_scale=7.5).images +images = pipe(prompt=prompt, init_image=init_image, strength=0.75, guidance_scale=7.5).images images[0].save("fantasy_landscape.png") ``` @@ -157,7 +153,6 @@ The `StableDiffusionInpaintPipeline` lets you edit specific parts of an image by ```python from io import BytesIO -from torch import autocast import requests import PIL @@ -181,8 +176,7 @@ pipe = StableDiffusionInpaintPipeline.from_pretrained( ).to(device) prompt = "a cat sitting on a bench" -with autocast("cuda"): - images = pipe(prompt=prompt, init_image=init_image, mask_image=mask_image, strength=0.75).images +images = pipe(prompt=prompt, init_image=init_image, mask_image=mask_image, strength=0.75).images images[0].save("cat_on_bench.png") ``` diff --git a/docs/source/optimization/fp16.mdx b/docs/source/optimization/fp16.mdx index f19326ec..b561aedb 100644 --- a/docs/source/optimization/fp16.mdx +++ b/docs/source/optimization/fp16.mdx @@ -68,7 +68,7 @@ Despite the precision loss, in our experience the final image results look the s ## Half precision weights -To save more GPU memory, you can load the model weights directly in half precision. This involves loading the float16 version of the weights, which was saved to a branch named `fp16`, and telling PyTorch to use the `float16` type when loading them: +To save more GPU memory and get even more speed, you can load and run the model weights directly in half precision. This involves loading the float16 version of the weights, which was saved to a branch named `fp16`, and telling PyTorch to use the `float16` type when loading them: ```Python pipe = StableDiffusionPipeline.from_pretrained( @@ -76,6 +76,10 @@ pipe = StableDiffusionPipeline.from_pretrained( revision="fp16", torch_dtype=torch.float16, ) +pipe = pipe.to("cuda") + +prompt = "a photo of an astronaut riding a horse on mars" +image = pipe(prompt).images[0] ``` ## Sliced attention for additional memory savings @@ -101,8 +105,7 @@ pipe = pipe.to("cuda") prompt = "a photo of an astronaut riding a horse on mars" pipe.enable_attention_slicing() -with torch.autocast("cuda"): - image = pipe(prompt).images[0] +image = pipe(prompt).images[0] ``` There's a small performance penalty of about 10% slower inference times, but this method allows you to use Stable Diffusion in as little as 3.2 GB of VRAM! diff --git a/docs/source/training/text_inversion.mdx b/docs/source/training/text_inversion.mdx index 82cb1290..13ea7c94 100644 --- a/docs/source/training/text_inversion.mdx +++ b/docs/source/training/text_inversion.mdx @@ -109,7 +109,6 @@ A full training run takes ~1 hour on one V100 GPU. Once you have trained a model using above command, the inference can be done simply using the `StableDiffusionPipeline`. Make sure to include the `placeholder_token` in your prompt. ```python -from torch import autocast from diffusers import StableDiffusionPipeline model_id = "path-to-your-trained-model" @@ -117,8 +116,7 @@ pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float prompt = "A backpack" -with autocast("cuda"): - image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] +image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] image.save("cat-backpack.png") ``` diff --git a/docs/source/using-diffusers/img2img.mdx b/docs/source/using-diffusers/img2img.mdx index 6becc2d5..3b57b0f5 100644 --- a/docs/source/using-diffusers/img2img.mdx +++ b/docs/source/using-diffusers/img2img.mdx @@ -15,7 +15,6 @@ specific language governing permissions and limitations under the License. The [`StableDiffusionImg2ImgPipeline`] lets you pass a text prompt and an initial image to condition the generation of new images. ```python -from torch import autocast import requests from PIL import Image from io import BytesIO @@ -37,8 +36,7 @@ init_image = init_image.resize((768, 512)) prompt = "A fantasy landscape, trending on artstation" -with autocast("cuda"): - images = pipe(prompt=prompt, init_image=init_image, strength=0.75, guidance_scale=7.5).images +images = pipe(prompt=prompt, init_image=init_image, strength=0.75, guidance_scale=7.5).images images[0].save("fantasy_landscape.png") ``` diff --git a/docs/source/using-diffusers/inpaint.mdx b/docs/source/using-diffusers/inpaint.mdx index d6269f4b..7b4687c2 100644 --- a/docs/source/using-diffusers/inpaint.mdx +++ b/docs/source/using-diffusers/inpaint.mdx @@ -17,7 +17,6 @@ The [`StableDiffusionInpaintPipeline`] lets you edit specific parts of an image ```python from io import BytesIO -from torch import autocast import requests import PIL @@ -41,8 +40,7 @@ pipe = StableDiffusionInpaintPipeline.from_pretrained( ).to(device) prompt = "a cat sitting on a bench" -with autocast("cuda"): - images = pipe(prompt=prompt, init_image=init_image, mask_image=mask_image, strength=0.75).images +images = pipe(prompt=prompt, init_image=init_image, mask_image=mask_image, strength=0.75).images images[0].save("cat_on_bench.png") ``` diff --git a/examples/dreambooth/README.md b/examples/dreambooth/README.md index 9d78c112..6770133a 100644 --- a/examples/dreambooth/README.md +++ b/examples/dreambooth/README.md @@ -125,8 +125,6 @@ accelerate launch train_dreambooth.py \ Once you have trained a model using above command, the inference can be done simply using the `StableDiffusionPipeline`. Make sure to include the `identifier`(e.g. sks in above example) in your prompt. ```python - -from torch import autocast from diffusers import StableDiffusionPipeline import torch @@ -134,9 +132,7 @@ model_id = "path-to-your-trained-model" pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda") prompt = "A photo of sks dog in a bucket" - -with autocast("cuda"): - image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] +image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] image.save("dog-bucket.png") ``` diff --git a/examples/dreambooth/train_dreambooth.py b/examples/dreambooth/train_dreambooth.py index e507fcbd..322c5506 100644 --- a/examples/dreambooth/train_dreambooth.py +++ b/examples/dreambooth/train_dreambooth.py @@ -1,7 +1,6 @@ import argparse import math import os -from contextlib import nullcontext from pathlib import Path from typing import Optional @@ -346,12 +345,10 @@ def main(): sample_dataloader = accelerator.prepare(sample_dataloader) pipeline.to(accelerator.device) - context = torch.autocast("cuda") if accelerator.device.type == "cuda" else nullcontext for example in tqdm( sample_dataloader, desc="Generating class images", disable=not accelerator.is_local_main_process ): - with context: - images = pipeline(example["prompt"]).images + images = pipeline(example["prompt"]).images for i, image in enumerate(images): image.save(class_images_dir / f"{example['index'][i] + cur_class_images}.jpg") diff --git a/examples/textual_inversion/README.md b/examples/textual_inversion/README.md index 0976e734..05d8ffb8 100644 --- a/examples/textual_inversion/README.md +++ b/examples/textual_inversion/README.md @@ -74,8 +74,6 @@ A full training run takes ~1 hour on one V100 GPU. Once you have trained a model using above command, the inference can be done simply using the `StableDiffusionPipeline`. Make sure to include the `placeholder_token` in your prompt. ```python - -from torch import autocast from diffusers import StableDiffusionPipeline model_id = "path-to-your-trained-model" @@ -83,8 +81,7 @@ pipe = StableDiffusionPipeline.from_pretrained(model_id,torch_dtype=torch.float1 prompt = "A backpack" -with autocast("cuda"): - image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] +image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] image.save("cat-backpack.png") ```