Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit 06e19de

Browse files
committed
copy models, remove obsolete commands
1 parent 7979acf commit 06e19de

File tree

8 files changed

+64
-152
lines changed

8 files changed

+64
-152
lines changed

OnnxStack.Converter/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ convert.py --optimize --model_input '..\stable-diffusion-v1-5' --model_output '.
1515

1616
`--model_input` - Safetensor model to convert
1717

18-
`--model_output` - Output for converted ONNX model
18+
`--model_output` - Output for converted ONNX model (NOTE: This folder is deleted before each run)
1919

2020
`--controlnet` - Create a ControlNet enabled Unet model
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# OnnxStack.Converter
2+
3+
## Requirements
4+
```bash
5+
pip install onnxruntime-directml
6+
pip install olive-ai[directml]
7+
python -m pip install -r requirements.txt
8+
```
9+
10+
## Usage
11+
```bash
12+
convert.py --optimize --model_input '..\stable-cascade' --model_output '..\converted'
13+
```
14+
`--optimize` - Run the model optimization
15+
16+
`--model_input` - Safetensor model to convert
17+
18+
`--model_output` - Output for converted ONNX model (NOTE: This folder is deleted before each run)
19+
20+
`--image_encoder` - Convert the optional image encoder

OnnxStack.Converter/stable_cascade/config_decoder.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@
5555
"config": {
5656
"target_opset": 16,
5757
"save_as_external_data": true,
58-
"all_tensors_to_one_file": true,
59-
"external_data_name": "weights.pb"
58+
"all_tensors_to_one_file": true
6059
}
6160
},
6261
"optimize": {

OnnxStack.Converter/stable_cascade/config_image_encoder.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"model_script": "models.py",
88
"io_config": {
99
"input_names": [ "sample"],
10-
"output_names": [ "latent_sample" ],
10+
"output_names": [ "image_embeds", "last_hidden_state"],
1111
"dynamic_axes": { "sample": { "0": "batch", "1": "channels", "2": "height", "3": "width" } }
1212
},
1313
"dummy_inputs_func": "image_encoder_conversion_inputs"

OnnxStack.Converter/stable_cascade/config_prior.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@
5656
"config": {
5757
"target_opset": 16,
5858
"save_as_external_data": true,
59-
"all_tensors_to_one_file": true,
60-
"external_data_name": "weights.pb"
59+
"all_tensors_to_one_file": true
6160
}
6261
},
6362
"optimize": {

OnnxStack.Converter/stable_cascade/convert.py

Lines changed: 10 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def optimize(
9393
model_input: str,
9494
model_output: Path,
9595
provider: str,
96-
controlnet: bool
96+
image_encoder: bool
9797
):
9898
from google.protobuf import __version__ as protobuf_version
9999

@@ -109,7 +109,6 @@ def optimize(
109109
shutil.rmtree(script_dir / "footprints", ignore_errors=True)
110110
shutil.rmtree(model_output, ignore_errors=True)
111111

112-
113112
# Load the entire PyTorch pipeline to ensure all models and their configurations are downloaded and cached.
114113
# This avoids an issue where the non-ONNX components (tokenizer, scheduler, and feature extractor) are not
115114
# automatically cached correctly if individual models are fetched one at a time.
@@ -121,15 +120,10 @@ def optimize(
121120

122121
model_info = {}
123122

124-
submodel_names = [ "text_encoder", "decoder", "prior", "image_encoder"]
125-
126-
has_safety_checker = getattr(pipeline, "safety_checker", None) is not None
127-
128-
if has_safety_checker:
129-
submodel_names.append("safety_checker")
123+
submodel_names = [ "text_encoder", "decoder", "prior", "vqgan"]
130124

131-
if controlnet:
132-
submodel_names.append("controlnet")
125+
if image_encoder:
126+
submodel_names.append("image_encoder")
133127

134128
for submodel_name in submodel_names:
135129
print(f"\nOptimizing {submodel_name}")
@@ -138,14 +132,7 @@ def optimize(
138132
with (script_dir / f"config_{submodel_name}.json").open() as fin:
139133
olive_config = json.load(fin)
140134
olive_config = update_config_with_provider(olive_config, provider)
141-
142-
if submodel_name in ("unet", "controlnet", "text_encoder"):
143-
olive_config["input_model"]["config"]["model_path"] = model_dir
144-
else:
145-
# Only the unet & text encoder are affected by LoRA, so it's better to use the base model ID for
146-
# other models: the Olive cache is based on the JSON config, and two LoRA variants with the same
147-
# base model ID should be able to reuse previously optimized copies.
148-
olive_config["input_model"]["config"]["model_path"] = model_dir
135+
olive_config["input_model"]["config"]["model_path"] = model_dir
149136

150137
run_res = olive_run(olive_config)
151138

@@ -156,52 +143,22 @@ def optimize(
156143
from sd_utils.ort import save_onnx_pipeline
157144

158145
save_onnx_pipeline(
159-
has_safety_checker, model_info, model_output, pipeline, submodel_names
146+
model_info, model_output, pipeline, submodel_names
160147
)
161148

162149
return model_info
163150

164151

165152
def parse_common_args(raw_args):
166153
parser = argparse.ArgumentParser("Common arguments")
167-
168154
parser.add_argument("--model_input", default="stable-diffusion-v1-5", type=str)
169155
parser.add_argument("--model_output", default="stable-diffusion-v1-5", type=Path)
170-
parser.add_argument("--controlnet",action="store_true", help="Create ControlNet Unet Model")
171-
parser.add_argument(
172-
"--provider", default="dml", type=str, choices=["dml", "cuda"], help="Execution provider to use"
173-
)
156+
parser.add_argument("--image_encoder",action="store_true", help="Create image encoder model")
157+
parser.add_argument("--provider", default="dml", type=str, choices=["dml", "cuda"], help="Execution provider to use")
174158
parser.add_argument("--optimize", action="store_true", help="Runs the optimization step")
175159
parser.add_argument("--clean_cache", action="store_true", help="Deletes the Olive cache")
176160
parser.add_argument("--test_unoptimized", action="store_true", help="Use unoptimized model for inference")
177-
parser.add_argument("--batch_size", default=1, type=int, help="Number of images to generate per batch")
178-
parser.add_argument(
179-
"--prompt",
180-
default=(
181-
"castle surrounded by water and nature, village, volumetric lighting, photorealistic, "
182-
"detailed and intricate, fantasy, epic cinematic shot, mountains, 8k ultra hd"
183-
),
184-
type=str,
185-
)
186-
parser.add_argument(
187-
"--guidance_scale",
188-
default=7.5,
189-
type=float,
190-
help="Guidance scale as defined in Classifier-Free Diffusion Guidance",
191-
)
192-
parser.add_argument("--num_images", default=1, type=int, help="Number of images to generate")
193-
parser.add_argument("--num_inference_steps", default=50, type=int, help="Number of steps in diffusion process")
194161
parser.add_argument("--tempdir", default=None, type=str, help="Root directory for tempfile directories and files")
195-
parser.add_argument(
196-
"--strength",
197-
default=1.0,
198-
type=float,
199-
help="Value between 0.0 and 1.0, that controls the amount of noise that is added to the input image. "
200-
"Values that approach 1.0 enable lots of variations but will also produce images "
201-
"that are not semantically consistent with the input.",
202-
)
203-
parser.add_argument("--image_size", default=512, type=int, help="Width and height of the images to generate")
204-
205162
return parser.parse_known_args(raw_args)
206163

207164

@@ -231,8 +188,6 @@ def main(raw_args=None):
231188
if common_args.clean_cache:
232189
shutil.rmtree(script_dir / "cache", ignore_errors=True)
233190

234-
guidance_scale = common_args.guidance_scale
235-
236191
ort_args = None, None
237192
ort_args, extra_args = parse_ort_args(extra_args)
238193

@@ -246,27 +201,10 @@ def main(raw_args=None):
246201
from sd_utils.ort import validate_args
247202

248203
validate_args(ort_args, common_args.provider)
249-
optimize(common_args.model_input, common_args.model_output, common_args.provider, common_args.controlnet)
204+
optimize(common_args.model_input, common_args.model_output, common_args.provider, common_args.image_encoder)
250205

251206
if not common_args.optimize:
252-
model_dir = model_output / "F32" if common_args.test_unoptimized else model_output / "F16"
253-
with warnings.catch_warnings():
254-
warnings.simplefilter("ignore")
255-
256-
from sd_utils.ort import get_ort_pipeline
257-
258-
pipeline = get_ort_pipeline(model_dir, common_args, ort_args, guidance_scale)
259-
run_inference_loop(
260-
pipeline,
261-
common_args.prompt,
262-
common_args.num_images,
263-
common_args.batch_size,
264-
common_args.image_size,
265-
common_args.num_inference_steps,
266-
guidance_scale,
267-
common_args.strength,
268-
provider=provider,
269-
)
207+
print("TODO: Create OnnxStableCascadePipeline")
270208

271209

272210
if __name__ == "__main__":

OnnxStack.Converter/stable_cascade/models.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ def __getitem__(self, idx):
2727
# TEXT ENCODER
2828
# -----------------------------------------------------------------------------
2929

30-
3130
def text_encoder_inputs(batchsize, torch_dtype):
3231
return torch.zeros((batchsize, 77), dtype=torch_dtype)
3332

@@ -45,11 +44,12 @@ def text_encoder_data_loader(data_dir, batchsize, *args, **kwargs):
4544
return RandomDataLoader(text_encoder_inputs, batchsize, torch.int32)
4645

4746

47+
48+
4849
# -----------------------------------------------------------------------------
49-
# decoder
50+
# DECODER UNET
5051
# -----------------------------------------------------------------------------
5152

52-
5353
def decoder_inputs(batchsize, torch_dtype, is_conversion_inputs=False):
5454
# TODO(jstoecker): Rename onnx::Concat_4 to text_embeds and onnx::Shape_5 to time_ids
5555
inputs = {
@@ -81,8 +81,9 @@ def decoder_data_loader(data_dir, batchsize, *args, **kwargs):
8181

8282

8383

84+
8485
# -----------------------------------------------------------------------------
85-
# prior
86+
# PRIOR UNET
8687
# -----------------------------------------------------------------------------
8788

8889
def prior_inputs(batchsize, torch_dtype, is_conversion_inputs=False):
@@ -116,10 +117,9 @@ def prior_data_loader(data_dir, batchsize, *args, **kwargs):
116117

117118

118119

119-
120120

121121
# -----------------------------------------------------------------------------
122-
# image_encoder
122+
# IMAGE ENCODER
123123
# -----------------------------------------------------------------------------
124124

125125
def image_encoder_inputs(batchsize, torch_dtype, is_conversion_inputs=False):
@@ -142,8 +142,10 @@ def image_encoder_data_loader(data_dir, batchsize, *args, **kwargs):
142142
return RandomDataLoader(image_encoder_inputs, batchsize, torch.float16)
143143

144144

145+
146+
145147
# -----------------------------------------------------------------------------
146-
# vqgan
148+
# VQGAN
147149
# -----------------------------------------------------------------------------
148150

149151
def vqgan_inputs(batchsize, torch_dtype, is_conversion_inputs=False):

OnnxStack.Converter/stable_cascade/sd_utils/ort.py

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing import Dict
1111

1212
import onnxruntime as ort
13-
from diffusers import OnnxRuntimeModel, OnnxStableDiffusionPipeline
13+
from diffusers import OnnxRuntimeModel, StableCascadePriorPipeline
1414
from onnxruntime import __version__ as OrtVersion
1515
from packaging import version
1616

@@ -77,9 +77,11 @@ def save_optimized_onnx_submodel(submodel_name, provider, model_info):
7777
model_info[submodel_name] = {
7878
"unoptimized": {
7979
"path": Path(unoptimized_olive_model.model_path),
80+
"data": Path(unoptimized_olive_model.model_path + ".data"),
8081
},
8182
"optimized": {
8283
"path": Path(optimized_olive_model.model_path),
84+
"data": Path(optimized_olive_model.model_path + ".data"),
8385
},
8486
}
8587

@@ -88,76 +90,28 @@ def save_optimized_onnx_submodel(submodel_name, provider, model_info):
8890

8991

9092
def save_onnx_pipeline(
91-
has_safety_checker, model_info, model_output, pipeline, submodel_names
93+
model_info, model_output, pipeline, submodel_names
9294
):
9395
# Save the unoptimized models in a directory structure that the diffusers library can load and run.
9496
# This is optional, and the optimized models can be used directly in a custom pipeline if desired.
95-
print("\nCreating ONNX pipeline...")
96-
97-
optimized_model_dir = model_output / "Optimized"
98-
unoptimized_model_dir = model_output / "Default"
99-
has_controlnet = 'controlnet' in submodel_names
100-
if has_safety_checker:
101-
safety_checker = OnnxRuntimeModel.from_pretrained(model_info["safety_checker"]["unoptimized"]["path"].parent)
102-
else:
103-
safety_checker = None
104-
105-
text_encoder=OnnxRuntimeModel.from_pretrained(model_info["text_encoder"]["unoptimized"]["path"].parent)
106-
decoder=OnnxRuntimeModel.from_pretrained(model_info["text_encoder"]["unoptimized"]["path"].parent)
107-
prior=OnnxRuntimeModel.from_pretrained(model_info["text_encoder"]["unoptimized"]["path"].parent)
108-
97+
# print("\nCreating ONNX pipeline...")
10998

99+
# TODO: Create OnnxStableCascadePipeline
110100

111-
print("Saving unoptimized models...")
112-
text_encoder.save_pretrained(unoptimized_model_dir / "text_encoder")
113-
decoder.save_pretrained(unoptimized_model_dir/ "decoder")
114-
prior.save_pretrained(unoptimized_model_dir/ "prior")
115-
116101
# Create a copy of the unoptimized model directory, then overwrite with optimized models from the olive cache.
117102
print("Copying optimized models...")
118-
shutil.copytree(unoptimized_model_dir, optimized_model_dir, ignore=shutil.ignore_patterns("weights.pb"))
119-
for submodel_name in submodel_names:
120-
src_path = model_info[submodel_name]["optimized"]["path"]
121-
dst_path = optimized_model_dir / submodel_name / "model.onnx"
122-
exists = os.path.exists(dst_path)
123-
if not exists:
124-
os.mkdir(optimized_model_dir / submodel_name)
125-
shutil.copyfile(src_path, dst_path)
126-
127-
print(f"The default pipeline is located here: {unoptimized_model_dir}")
128-
print(f"The optimized pipeline is located here: {optimized_model_dir}")
129-
130-
131-
def get_ort_pipeline(model_dir, common_args, ort_args, guidance_scale):
132-
ort.set_default_logger_severity(3)
133-
134-
print("Loading models into ORT session...")
135-
sess_options = ort.SessionOptions()
136-
sess_options.enable_mem_pattern = False
137-
138-
static_dims = not ort_args.dynamic_dims
139-
batch_size = common_args.batch_size
140-
image_size = common_args.image_size
141-
provider = common_args.provider
142-
143-
if static_dims:
144-
hidden_batch_size = batch_size if (guidance_scale == 0.0) else batch_size * 2
145-
# Not necessary, but helps DML EP further optimize runtime performance.
146-
# batch_size is doubled for sample & hidden state because of classifier free guidance:
147-
# https://github.com/huggingface/diffusers/blob/46c52f9b9607e6ecb29c782c052aea313e6487b7/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py#L672
148-
sess_options.add_free_dimension_override_by_name("unet_sample_batch", hidden_batch_size)
149-
sess_options.add_free_dimension_override_by_name("unet_sample_channels", 4)
150-
sess_options.add_free_dimension_override_by_name("unet_sample_height", image_size // 8)
151-
sess_options.add_free_dimension_override_by_name("unet_sample_width", image_size // 8)
152-
sess_options.add_free_dimension_override_by_name("unet_time_batch", 1)
153-
sess_options.add_free_dimension_override_by_name("unet_hidden_batch", hidden_batch_size)
154-
sess_options.add_free_dimension_override_by_name("unet_hidden_sequence", 77)
155-
156-
provider_map = {
157-
"dml": "DmlExecutionProvider",
158-
"cuda": "CUDAExecutionProvider",
159-
}
160-
assert provider in provider_map, f"Unsupported provider: {provider}"
161-
return OnnxStableDiffusionPipeline.from_pretrained(
162-
model_dir, provider=provider_map[provider], sess_options=sess_options
163-
)
103+
for passType in ["optimized", "unoptimized"]:
104+
model_dir = model_output / passType
105+
for submodel_name in submodel_names:
106+
src_path = model_info[submodel_name][passType]["path"] # model.onnx
107+
src_data_path = model_info[submodel_name][passType]["data"]# model.onnx.data
108+
109+
dst_path = model_dir / submodel_name
110+
if not os.path.exists(dst_path):
111+
os.makedirs(dst_path, exist_ok=True)
112+
113+
shutil.copyfile(src_path, dst_path / "model.onnx")
114+
if os.path.exists(src_data_path):
115+
shutil.copyfile(src_data_path, dst_path / "model.onnx.data")
116+
117+
print(f"The converted model is located here: {model_output}")

0 commit comments

Comments
 (0)