Skip to content

[ONNX] Stable Diffusion exporter and pipeline#399

Merged
anton-l merged 16 commits into
mainfrom
sd-onnx-pipeline
Sep 8, 2022
Merged

[ONNX] Stable Diffusion exporter and pipeline#399
anton-l merged 16 commits into
mainfrom
sd-onnx-pipeline

Conversation

@anton-l

@anton-l anton-l commented Sep 7, 2022

Copy link
Copy Markdown
Member

Usage:

pip install onnxruntime

python scripts/convert_stable_diffusion_checkpoint_to_onnx.py --model_path="CompVis/stable-diffusion-v1-4" --output_path="./sd_onnx"

from diffusers import StableDiffusionOnnxPipeline

pipe = StableDiffusionOnnxPipeline.from_pretrained("./sd_onnx", provider="CPUExecutionProvider")

Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py Outdated
@HuggingFaceDocBuilderDev

HuggingFaceDocBuilderDev commented Sep 7, 2022

Copy link
Copy Markdown

The documentation is not available anymore as the PR was closed or merged.

Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
anton-l and others added 2 commits September 7, 2022 18:13
Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com>
Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com>
Comment thread src/diffusers/pipeline_utils.py Outdated

@patil-suraj patil-suraj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool addition! Let's also add tests for this no, maybe in future PR.
Just left some nits :)

Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py
Comment thread src/diffusers/onnx_utils.py
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_onnx.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/onnx_utils.py

@patrickvonplaten patrickvonplaten left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very nice! More or less good to go for me - I like the design. Think we could:

  • avoid one-liners a bit more
  • push_to_hub is maybe a bit too much for now
  • Mark the ONNX class as experimental
  • Maybe add a test (ok without for me as well)

Comment thread src/diffusers/onnx_utils.py Outdated
logger = logging.get_logger(__name__)


class OnnxModel:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turbo nit: ONNX and ONNX Runtime are commonly confused as being the same thing (the former being a format, the latter a runtime)

it would be technically more correct to call this ORTModel or OnnxRuntimeModel since the __call__ method is passing the ONNX model through ONNX Runtime.

(no need to follow this advice, just noting it since the discussion also came up in optimum :))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me to call it OnnxRuntimeModel -> your call though @anton-l :-)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to change the name, I prefer OnnxRuntimeModel too (rather than ORTModel, even if people use ORT all the time).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opted for OnnxRuntimeModel!

Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py
@harishanand95

harishanand95 commented Sep 7, 2022

Copy link
Copy Markdown

Hi @anton-l, I did a quick try of this PR on DMLExecutionProvider. It works if the safetychecker is commented out as it fails for clip_input error, similar to the error on CPUExecutionProvider.

There are few places where a provider is not passed, so I had to make minor changes to make this PR work.

  1. Missing provider=provider
    model = OnnxModel.load_model(os.path.join(model_id, model_file_name))
  2. Missing provider in loading_kwargs dictionary.
    loading_kwargs = {}

    I added the provider provider = kwargs.pop("provider", None) on line 168, and set the provider in loading_kwargs after the declaration statement on line 260.
    torch_dtype = kwargs.pop("torch_dtype", None)

If anyone wants to test this with DmlExecutionProvider on Windows (works on AMD/NVIDIA cards), here are the steps.

conda create --name sd39 python=3.9 -y && conda activate sd39
pip install transformers ftfy scipy onnxruntime
cd diffusers/ && git checkout sd-onnx-pipeline && pip install -e .
# Download nightly onnxruntime-directml from the link below
# https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/ort-nightly-directml/overview/1.13.0.dev20220908001
pip install ort_nightly_directml-1.13.0.dev20220830001-cp39-cp39-win_amd64.whl --force-reinstall
from diffusers import StableDiffusionOnnxPipeline
pipe = StableDiffusionOnnxPipeline.from_pretrained("./sd_onnx", provider="DmlExecutionProvider")
prompt = "a photo of an astronaut riding a horse on mars"
image = pipe(prompt).images[0] 
image.save("astronaut_rides_horse.png")

Comment thread tests/test_pipelines.py
Comment thread tests/test_pipelines.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py Outdated

@pcuenca pcuenca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! I don't have much to contribute on top of what the others said. I'll test it in CUDA and CPU later if it helps.

Comment thread scripts/convert_stable_diffusion_checkpoint_to_onnx.py Outdated
Comment thread src/diffusers/onnx_utils.py Outdated
Comment thread src/diffusers/pipelines/stable_diffusion/safety_checker.py
Comment thread src/diffusers/utils/dummy_transformers_and_onnx_objects.py Outdated
@patrickvonplaten

Copy link
Copy Markdown
Contributor

Very cool - feel free to merge when you want 🥳

@anton-l
anton-l merged commit 8d9c4a5 into main Sep 8, 2022
@anton-l
anton-l deleted the sd-onnx-pipeline branch September 8, 2022 13:20
@tdeboissiere

Copy link
Copy Markdown

@pcuenca would be keen to know what inference speed numbers you get on GPU.
On a T4, I'm actually getting slower inference with Onnx (about 40 seconds), instead of 12 with vanilla pytorch.

@patrickvonplaten

Copy link
Copy Markdown
Contributor

cc @anton-l could you verify this real quick?

@anton-l

anton-l commented Sep 8, 2022

Copy link
Copy Markdown
Member Author

@tdeboissiere to enable the GPU runtime, you'll need to install one more package on top:
pip install onnxruntime-gpu

Then CUDAExecutionProvider should run at expected speeds:

pipe = StableDiffusionOnnxPipeline.from_pretrained("./sd_onnx", provider="CUDAExecutionProvider")

@tdeboissiere

tdeboissiere commented Sep 8, 2022

Copy link
Copy Markdown

Yep, that's what I did.

I also used this quick hack to ensure SD was executing on GPU

# in import_utils.py
_onnx_available = importlib.util.find_spec("onnxruntime") is not None
try:
    _onnxruntime_version = importlib_metadata.version("onnxruntime")
    logger.debug(f"Successfully imported onnxruntime version {_onnxruntime_version}")
except importlib_metadata.PackageNotFoundError:
    _onnxruntime_version = importlib_metadata.version("onnxruntime-gpu")
    _onnx_available = True
except Exception:
    _onnx_available = False

I've also found that installing both onnxruntime at the same time onnxruntime-gpu led to an error ('CUDAExecutionProvider' is not in available provider names.Available providers: 'CPUExecutionProvider'). Installing onnxruntime first, then onnxruntime-gpu works though

@josipledic

Copy link
Copy Markdown

Is someone planning on working on an onnx img2img pipeline? That would be awesome

@deepdiffuser

Copy link
Copy Markdown

I'm also getting much slower inference speed with Onnx on a 3090.

@patrickvonplaten

Copy link
Copy Markdown
Contributor

cc @anton-l

PhaneeshB pushed a commit to nod-ai/diffusers that referenced this pull request Mar 1, 2023
yoonseokjin pushed a commit to yoonseokjin/diffusers that referenced this pull request Dec 25, 2023
* initial export and design

* update imports

* custom prover, import fixes

* Update src/diffusers/onnx_utils.py

Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com>

* Update src/diffusers/onnx_utils.py

Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com>

* remove push_to_hub

* Update src/diffusers/onnx_utils.py

Co-authored-by: Suraj Patil <surajp815@gmail.com>

* remove torch_device

* numpify the rest of the pipeline

* torchify the safety checker

* revert tensor

* Code review suggestions + quality

* fix tests

* fix provider, add an end-to-end test

* style

Co-authored-by: Patrick von Platen <patrick.v.platen@gmail.com>
Co-authored-by: Suraj Patil <surajp815@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.