Skip to content

Using enable_model_cpu_offload with multiple XL pipelines triggers error Expected all tensors to be on the same device #5281

Description

@alexisrolland

Hello,

I am having difficulties to use enable_model_cpu_offload in the context of my application where I am loading multiple pipelines in memory (StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline and StableDiffusionXLControlNetPipeline). I read through the documentation here: Model offloading for fast inference and memory savings and I also read through this issue which seemed similar to what I am facing: Diffusers 0.21 breaks model offloading. I couldn't find a complete code snippet that could help...

The error I am facing:

Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument mat1 in method wrapper_CUDA_addmm)

It is triggered when calling pipeline_controlnet:

import torch
from compel import Compel, ReturnedEmbeddingsType
from diffusers import ControlNetModel, StableDiffusionXLControlNetPipeline, StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained('stabilityai/stable-diffusion-xl-base-1.0', torch_dtype=torch.float16, variant='fp16', use_safetensors=True)
pipeline.enable_model_cpu_offload()

controlnet = ControlNetModel.from_pretrained('diffusers/controlnet-depth-sdxl-1.0', torch_dtype=torch.float16)
pipeline_controlnet = StableDiffusionXLControlNetPipeline(controlnet=controlnet, **pipeline.components)

compel = Compel(
    tokenizer=[pipeline.tokenizer, pipeline.tokenizer_2],
    text_encoder=[pipeline.text_encoder, pipeline.text_encoder_2],
    returned_embeddings_type=ReturnedEmbeddingsType.PENULTIMATE_HIDDEN_STATES_NON_NORMALIZED,
    requires_pooled=[False, True]
)

prompts = ["a cat playing with a (ball)++++ in the forest"]
negative_prompts = [""]
prompt_embeds, pooled_prompt_embeds = compel(prompts)
negative_prompt_embeds, negative_pooled_prompt_embeds = compel(negative_prompts)
seed = 123456
generators = torch.Generator(device='cuda').manual_seed(seed)

image = pipeline(
    prompt_embeds=prompt_embeds,
    pooled_prompt_embeds=pooled_prompt_embeds,
    negative_prompt_embeds=negative_prompt_embeds,
    negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
    num_inference_steps=30,
    num_images_per_prompt=1,
    generator=generators
).images[0]

torch.cuda.empty_cache()
torch.cuda.ipc_collect()

image = pipeline_controlnet(
    prompt_embeds=prompt_embeds,
    pooled_prompt_embeds=pooled_prompt_embeds,
    negative_prompt_embeds=negative_prompt_embeds,
    negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
    image=image,
    controlnet_conditioning_scale=0.5,
    num_inference_steps=30,
    num_images_per_prompt=1,
    generator=generators
).images[0]

torch.cuda.empty_cache()
torch.cuda.ipc_collect()

I have tried to add pipeline_controlnet.enable_model_cpu_offload() like this:

[...]
MODEL_PATH_CONTROLNET = os.getenv('MODEL_PATH_CONTROLNET_DEPTH')
controlnet = ControlNetModel.from_pretrained(MODEL_PATH_CONTROLNET, torch_dtype=torch.float16)
pipeline_controlnet = StableDiffusionXLControlNetPipeline(controlnet=controlnet, **pipeline.components)
pipeline_controlnet.enable_model_cpu_offload() 
[...]

But then calling the StableDiffusionXLPipeline pipeline triggers:

ValueError: Cannot generate a cpu tensor from a generator of type cuda.

@sayakpaul @patrickvonplaten I would really appreciate some guidance how to achieve this!

Thank you <3

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleIssues that haven't received updates

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions