Skip to content

Conversation

as-suvorov
Copy link
Collaborator

@as-suvorov as-suvorov commented Sep 9, 2025

Implements void export_model(const std::filesystem::path& blob_path) and ov::Property<std::filesystem::path> blob_path{"blob_path"} for Text2ImagePipeline.
Ticket: 171706

@as-suvorov as-suvorov changed the title Image2Image Unet model export/import Text2Image Unet model export/import Sep 9, 2025
@github-actions github-actions bot added category: image generation Image generation pipelines category: cmake / build Cmake scripts category: CPP API Changes in GenAI C++ public headers no-match-files category: Image generation samples GenAI Image generation samples labels Sep 9, 2025
@as-suvorov
Copy link
Collaborator Author

@Wovchena
Copy link
Collaborator

LGTM. Why did NPU use a property instead of export_model()?

@TianmengChen
Copy link
Contributor

LGTM

@as-suvorov
Copy link
Collaborator Author

as-suvorov commented Sep 10, 2025

@dmatveev We want to enable export/import blobs for Image2Image pipeline and potentially for other pipelines as well.
There is existing functionality for some NPU pipelines. NPU implementation uses EXPORT_BLOB property: https://github.com/openvinotoolkit/openvino.genai/blob/master/src/cpp/src/utils.cpp#L525
My current proposal is to use export_model, it correlates with the core.export_model approach, allows to delay export after pipeline ctor. Sample: c7cb70e#diff-7c43ee3f358ffafcb7b99c16da468002ff143722294947b8bcb22bd153894a10R71
What's your thoughts on EXPORT_BLOB property vs export_model API?

}

void test_npu_request_size(const std::filesystem::path& models_path) {
ov::AnyMap properties{{"NPU_USE_NPUW", "YES"}, {"NPUW_DEVICES", "CPU"}, {"NPUW_ONLINE_PIPELINE", "NONE"}};
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry for bothering. Just a question here, should we use NPUW for image generation pipeline? I think NPU should be able to handle image generation pipeline without enable NPUW.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It should work without NPUW.

@github-actions github-actions bot removed category: cmake / build Cmake scripts category: Image generation samples GenAI Image generation samples labels Sep 15, 2025
@github-actions github-actions bot added the category: Image generation samples GenAI Image generation samples label Sep 18, 2025
@as-suvorov as-suvorov marked this pull request as ready for review September 18, 2025 14:50
@Copilot Copilot AI review requested due to automatic review settings September 18, 2025 14:50
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds export/import functionality for Text2Image UNet model components, enabling users to export compiled models to blob files and later import them for faster loading. The implementation supports exporting individual model components (UNet, CLIP text encoders, VAE) and provides Python bindings for the export functionality.

  • Adds export/import methods to core image generation model classes (UNet2DConditionModel, CLIPTextModel, AutoencoderKL)
  • Implements blob path property handling to enable model import during construction
  • Provides Python bindings and documentation for the new export/import API

Reviewed Changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/python/py_utils.cpp Adds support for PosixPath objects in Python property conversion
src/python/py_image_generation_pipelines.cpp Exposes export_model method for Text2ImagePipeline in Python
src/python/py_image_generation_models.cpp Adds Python bindings for export_model methods on individual model classes
src/python/openvino_genai/py_openvino_genai.pyi Type stub definitions for the new export_model methods
src/cpp/src/utils.hpp Declares utility functions for blob export/import operations
src/cpp/src/utils.cpp Implements blob export/import utility functions
src/cpp/src/image_generation/text2image_pipeline.cpp Adds export_model method to Text2ImagePipeline
src/cpp/src/image_generation/stable_diffusion_xl_pipeline.hpp Implements export/import logic for SDXL pipeline components
src/cpp/src/image_generation/models/ Adds export/import methods to UNet inference classes
src/cpp/src/image_generation/models/unet2d_condition_model.cpp Implements export/import for UNet2DConditionModel
src/cpp/src/image_generation/models/clip_text_model.cpp Implements export/import for CLIPTextModel
src/cpp/src/image_generation/models/autoencoder_kl.cpp Implements export/import for AutoencoderKL
src/cpp/src/image_generation/diffusion_pipeline.hpp Adds virtual export_model method to base DiffusionPipeline
src/cpp/include/openvino/genai/ Header updates with export_model method declarations
src/cpp/include/openvino/genai/common_types.hpp Defines blob_path property for specifying import directory
samples/ Documentation and examples for using the export/import functionality

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@as-suvorov as-suvorov changed the title Text2Image Unet model export/import Text2Image pipeline export/import Sep 18, 2025
@as-suvorov
Copy link
Collaborator Author

Export import doesn't work on NPU, potential fix: openvinotoolkit/openvino#32054

OV PR merged. export/import on NPU device with fallback {"NPUW_DEVICES", "CPU"} works fine.

@as-suvorov as-suvorov requested a review from dmatveev September 19, 2025 09:23
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add tests. I think the test should check that a new pipeline can be constructed form the blob. Save the blob to a temp dir instead of cache to reduce share usage

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are no image generation python tests for the moment. I propose to implement it in a separate PR, I'll create a ticket for that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I know.

Adding a file shouldn't be a big deal. Anna wouldn't be able to implement it easily because she isn't familiar with GenAI's tests because of the reason you named, so adding export test here should be a good start

@as-suvorov
Copy link
Collaborator Author

@TianmengChen could you please test this export/import API on NPU device?

@TianmengChen
Copy link
Contributor

TianmengChen commented Sep 24, 2025

@TianmengChen could you please test this export/import API on NPU device?

Hi @as-suvorov , can you give me example codes, when I use ov::CacheMode::OPTIMIZE_SPEED it return
Exception from src\inference\src\cpp\core.cpp:112:
Exception from src\inference\src\dev\plugin.cpp:53:
Exception from src\plugins\intel_npu\src\common\src\filtered_config.cpp:37:
[ NOT_FOUND ] Option 'CACHE_MODE' is not supported for current configuration

here are my test codes:

    std::string device = "NPU";
    ov::AnyMap import_blob_properties{{ov::cache_mode.name(),ov::CacheMode::OPTIMIZE_SPEED}};
    ov::genai::Text2ImagePipeline pipeline(models_path, device, import_blob_properties);
    pipeline.export_model(models_path / "blobs");

and can you give me some example codes like heterogeneous_stable_diffusion.cpp example, that text_encoder on CPU
UNet on NPU and vae_decoder on GPU and their blob can be exported according to their device.

@as-suvorov
Copy link
Collaborator Author

as-suvorov commented Sep 24, 2025

@TianmengChen could you please test this export/import API on NPU device?

Hi @as-suvorov , can you give me example codes, when I use ov::CacheMode::OPTIMIZE_SPEED it return Exception from src\inference\src\cpp\core.cpp:112: Exception from src\inference\src\dev\plugin.cpp:53: Exception from src\plugins\intel_npu\src\common\src\filtered_config.cpp:37: [ NOT_FOUND ] Option 'CACHE_MODE' is not supported for current configuration

here are my test codes:

    std::string device = "NPU";
    ov::AnyMap import_blob_properties{{ov::cache_mode.name(),ov::CacheMode::OPTIMIZE_SPEED}};
    ov::genai::Text2ImagePipeline pipeline(models_path, device, import_blob_properties);
    pipeline.export_model(models_path / "blobs");

and can you give me some example codes like heterogeneous_stable_diffusion.cpp example, that text_encoder on CPU UNet on NPU and vae_decoder on GPU and their blob can be exported according to their device.

This is NPU plugin issue, we need help from NPU team.
Could you please try to use GPU device:

std::string device = "GPU";
ov::genai::Text2ImagePipeline pipeline(models_path, device, ov::cache_mode(ov::CacheMode::OPTIMIZE_SPEED));
pipeline.export_model(models_path / "blobs");

ov::genai::Text2ImagePipeline imported_pipeline(models_path, device, ov::genai::blob_path(models_path / "blobs"));

Let's also try to remove cache mode for NPU:

std::string device = "NPU";
ov::genai::Text2ImagePipeline pipeline(models_path, device);
pipeline.export_model(models_path / "blobs");

@as-suvorov
Copy link
Collaborator Author

@TianmengChen please check heterogeneous_stable_diffusion with export/import sample: https://gist.github.com/as-suvorov/7cd131b6f42a4326cfb75c1bab8dae6d

@TianmengChen
Copy link
Contributor

TianmengChen commented Sep 25, 2025

@TianmengChen please check heterogeneous_stable_diffusion with export/import sample: https://gist.github.com/as-suvorov/7cd131b6f42a4326cfb75c1bab8dae6d

Thanks @as-suvorov , I first tried with this code on NPU and remove xml and bin file under unet, vae, text_encoder, and it works.

    std::string device = "NPU";
    // ov::genai::Text2ImagePipeline pipeline(models_path, device);
    // pipeline.export_model(models_path / "blobs");
    ov::genai::Text2ImagePipeline imported_pipeline(models_path, device, ov::genai::blob_path(models_path / "blobs"));

But for heterogeneous_stable_diffusion example, it return this:

text_encoder_device: CPU
unet_device: NPU
vae_decoder_device: GPU
Generating image 0
Check 'encoder_hidden_states_bs == m_native_batch_size' failed at C:\chen\openvino.genai\src\cpp\src\image_generation/models/unet_inference_static_bs1.hpp:80:
UNetInferenceStaticBS1::set_hidden_states: native batch size is 1, but encoder_hidden_states has batch size of 2

But this model can run with original heterogeneous_stable_diffusion example.

FYI @JohnLeFeng

@as-suvorov
Copy link
Collaborator Author

Thanks @as-suvorov , I first tried with this code on NPU and remove xml and bin file under unet, vae, text_encoder, and it works.

    std::string device = "NPU";
    // ov::genai::Text2ImagePipeline pipeline(models_path, device);
    // pipeline.export_model(models_path / "blobs");
    ov::genai::Text2ImagePipeline imported_pipeline(models_path, device, ov::genai::blob_path(models_path / "blobs"));

But for heterogeneous_stable_diffusion example, it return this:

text_encoder_device: CPU unet_device: NPU vae_decoder_device: GPU Generating image 0 Check 'encoder_hidden_states_bs == m_native_batch_size' failed at C:\chen\openvino.genai\src\cpp\src\image_generation/models/unet_inference_static_bs1.hpp:80: UNetInferenceStaticBS1::set_hidden_states: native batch size is 1, but encoder_hidden_states has batch size of 2

But this model can run with original heterogeneous_stable_diffusion example.

FYI @JohnLeFeng

There is a limitation of NPU export/import unet model implementation. The batch size is not preserved and model always imported with batch size 1: https://github.com/openvinotoolkit/openvino.genai/pull/2716/files#r2355059791
But expected batch size is calculated with guidance scale and equal to 2 for the default config.
https://github.com/openvinotoolkit/openvino.genai/blob/master/src/cpp/src/image_generation/stable_diffusion_xl_pipeline.hpp#L176
https://github.com/openvinotoolkit/openvino.genai/blob/master/src/cpp/include/openvino/genai/image_generation/unet2d_condition_model.hpp#L96
The workaround I can suggest is to use guidance_scale=1 to set unet model batch size to 1. I updated gist to use guidance_scale=1: https://gist.github.com/as-suvorov/7cd131b6f42a4326cfb75c1bab8dae6d
@likholat Maybe you have other suggestions?

@likholat
Copy link
Contributor

Thanks @as-suvorov , I first tried with this code on NPU and remove xml and bin file under unet, vae, text_encoder, and it works.

    std::string device = "NPU";
    // ov::genai::Text2ImagePipeline pipeline(models_path, device);
    // pipeline.export_model(models_path / "blobs");
    ov::genai::Text2ImagePipeline imported_pipeline(models_path, device, ov::genai::blob_path(models_path / "blobs"));

But for heterogeneous_stable_diffusion example, it return this:
text_encoder_device: CPU unet_device: NPU vae_decoder_device: GPU Generating image 0 Check 'encoder_hidden_states_bs == m_native_batch_size' failed at C:\chen\openvino.genai\src\cpp\src\image_generation/models/unet_inference_static_bs1.hpp:80: UNetInferenceStaticBS1::set_hidden_states: native batch size is 1, but encoder_hidden_states has batch size of 2
But this model can run with original heterogeneous_stable_diffusion example.
FYI @JohnLeFeng

There is a limitation of NPU export/import unet model implementation. The batch size is not preserved and model always imported with batch size 1: https://github.com/openvinotoolkit/openvino.genai/pull/2716/files#r2355059791 But expected batch size is calculated with guidance scale and equal to 2 for the default config. https://github.com/openvinotoolkit/openvino.genai/blob/master/src/cpp/src/image_generation/stable_diffusion_xl_pipeline.hpp#L176 https://github.com/openvinotoolkit/openvino.genai/blob/master/src/cpp/include/openvino/genai/image_generation/unet2d_condition_model.hpp#L96 The workaround I can suggest is to use guidance_scale=1 to set unet model batch size to 1. I updated gist to use guidance_scale=1: https://gist.github.com/as-suvorov/7cd131b6f42a4326cfb75c1bab8dae6d @likholat Maybe you have other suggestions?

This is the only workaround I see at the moment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: CPP API Changes in GenAI C++ public headers category: Image generation samples GenAI Image generation samples category: image generation Image generation pipelines category: Python API Python API for GenAI no-match-files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants