Skip to content

Commit 3df40f4

Browse files
committed
add flex.2 tutorial
1 parent 81f3c51 commit 3df40f4

File tree

4 files changed

+935
-0
lines changed

4 files changed

+935
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Image generation with universal control using Flex.2 and OpenVINO
2+
3+
Flex.2 is flexible text-to-image diffusion model based on Flux model architecture with built in support inpainting and universal control - model accepts pose, line, and depth inputs.
4+
5+
More details about model can be found in [model card](https://huggingface.co/ostris/Flex.2-preview).
6+
7+
In this tutorial we consider how to convert and optimize Flex.2 model using OpenVINO.
8+
9+
>**Note**: Some demonstrated models can require at least 32GB RAM for conversion and running.
10+
11+
<img src="https://raw.githubusercontent.com/black-forest-labs/flux/main/assets/grid.jpg" width="1024">
12+
13+
### Notebook Contents
14+
15+
In this demonstration, you will learn how to perform text-to-image generation using Flex.2 and OpenVINO.
16+
17+
Example of model work:
18+
19+
**Input prompt**: *a tiny Yorkshire terrier astronaut hatching from an egg on the moon*
20+
![](https://github.com/user-attachments/assets/11733314-0b31-449c-9885-12ebf6365a58)
21+
22+
The tutorial consists of the following steps:
23+
24+
- Install prerequisites
25+
- Collect Pytorch model pipeline
26+
- Convert model to OpenVINO intermediate representation (IR) format
27+
- Compress weights using NNCF
28+
- Prepare OpenVINO Inference pipeline
29+
- Run Image generation
30+
- Launch interactive demo
31+
32+
## Installation Instructions
33+
34+
This is a self-contained example that relies solely on its own code.</br>
35+
We recommend running the notebook in a virtual environment. You only need a Jupyter server to start.
36+
For further details, please refer to [Installation Guide](../../README.md).

notebooks/flex.2-image-generation/flex.2-image-generation.ipynb

Lines changed: 650 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
import gradio as gr
2+
import numpy as np
3+
import torch
4+
import random
5+
from PIL import Image, ImageFilter
6+
7+
MAX_SEED = np.iinfo(np.int32).max
8+
MAX_IMAGE_SIZE = 2048
9+
10+
11+
def make_demo(pipe):
12+
def infer(edit_images, prompt, seed=42, randomize_seed=False, width=1024, height=1024, guidance_scale=3.5, control_strength=0.5, control_stop=0.33, num_inference_steps=50, progress=gr.Progress(track_tqdm=True)):
13+
image = edit_images["background"].convert("RGB")
14+
mask = Image.fromarray(np.array(edit_images["layers"][-1])[:, :, -1])
15+
if randomize_seed:
16+
seed = random.randint(0, MAX_SEED)
17+
out_image = pipe(
18+
prompt=prompt,
19+
inpaint_image=image,
20+
inpaint_mask=mask,
21+
height=height,
22+
width=width,
23+
guidance_scale=guidance_scale,
24+
control_strength=control_strength,
25+
control_stop=control_stop,
26+
num_inference_steps=num_inference_steps,
27+
generator=torch.Generator("cpu").manual_seed(seed)
28+
).images[0]
29+
return (image, out_image), seed
30+
31+
css = """
32+
:root {
33+
--primary-color: #7E57C2;
34+
--secondary-color: #5E35B1;
35+
--accent-color: #B39DDB;
36+
--background-color: #F5F5F7;
37+
--card-background: #FFFFFF;
38+
--text-color: #333333;
39+
--shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
40+
--radius: 12px;
41+
}
42+
body {
43+
font-family: 'Inter', system-ui, sans-serif;
44+
background-color: var(--background-color);
45+
}
46+
#col-container {
47+
margin: 0 auto;
48+
max-width: 1200px;
49+
padding: 0;
50+
}
51+
.container {
52+
background-color: var(--card-background);
53+
border-radius: var(--radius);
54+
box-shadow: var(--shadow);
55+
padding: 24px;
56+
margin-bottom: 24px;
57+
}
58+
.header-container {
59+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
60+
border-radius: var(--radius);
61+
padding: 32px;
62+
margin-bottom: 24px;
63+
color: white;
64+
text-align: center;
65+
box-shadow: var(--shadow);
66+
}
67+
.header-container h1 {
68+
font-weight: 700;
69+
font-size: 2.5rem;
70+
margin-bottom: 8px;
71+
background: linear-gradient(to right, #ffffff, #e0e0e0);
72+
-webkit-background-clip: text;
73+
background-clip: text;
74+
-webkit-text-fill-color: transparent;
75+
}
76+
.header-container p {
77+
font-size: 1.1rem;
78+
opacity: 0.92;
79+
margin-bottom: 16px;
80+
}
81+
.header-container a {
82+
color: var(--accent-color);
83+
text-decoration: underline;
84+
transition: opacity 0.2s;
85+
}
86+
.header-container a:hover {
87+
opacity: 0.8;
88+
}
89+
.btn-primary {
90+
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
91+
border: none;
92+
border-radius: 8px;
93+
color: white;
94+
font-weight: 600;
95+
padding: 12px 24px;
96+
font-size: 16px;
97+
cursor: pointer;
98+
transition: all 0.3s ease;
99+
box-shadow: 0 4px 12px rgba(126, 87, 194, 0.3);
100+
}
101+
.btn-primary:hover {
102+
transform: translateY(-2px);
103+
box-shadow: 0 6px 16px rgba(126, 87, 194, 0.4);
104+
}
105+
.image-editor-container {
106+
border-radius: var(--radius);
107+
overflow: hidden;
108+
box-shadow: var(--shadow);
109+
}
110+
.prompt-container {
111+
background-color: var(--card-background);
112+
border-radius: var(--radius);
113+
padding: 16px;
114+
box-shadow: var(--shadow);
115+
margin-top: 16px;
116+
}
117+
.result-container {
118+
border-radius: var(--radius);
119+
overflow: hidden;
120+
box-shadow: var(--shadow);
121+
}
122+
.settings-container {
123+
background-color: var(--card-background);
124+
border-radius: var(--radius);
125+
padding: 20px;
126+
box-shadow: var(--shadow);
127+
margin-top: 16px;
128+
}
129+
.accordion-header {
130+
font-weight: 600;
131+
color: var(--primary-color);
132+
}
133+
/* Custom slider styling */
134+
input[type="range"] {
135+
height: 6px;
136+
border-radius: 3px;
137+
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
138+
}
139+
input[type="range"]::-webkit-slider-thumb {
140+
background: var(--primary-color);
141+
border: 2px solid white;
142+
height: 18px;
143+
width: 18px;
144+
}
145+
.footer {
146+
text-align: center;
147+
padding: 24px;
148+
color: #777;
149+
font-size: 14px;
150+
}
151+
/* Animate the result transition */
152+
@keyframes fadeIn {
153+
from { opacity: 0; }
154+
to { opacity: 1; }
155+
}
156+
.result-animation {
157+
animation: fadeIn 0.5s ease-in-out;
158+
}
159+
"""
160+
161+
with gr.Blocks(css=css, theme=gr.themes.Monochrome()) as demo:
162+
with gr.Column(elem_id="col-container"):
163+
# Header with gradient
164+
with gr.Column(elem_classes=["header-container"]):
165+
gr.HTML("""
166+
<h1>Flex.2 Preview Inpainting OpenVINO Demo</h1>
167+
""")
168+
# Main interface container
169+
with gr.Column(elem_classes=["container"]):
170+
with gr.Row():
171+
# Left column: Input
172+
with gr.Column(scale=1):
173+
edit_image = gr.ImageEditor(
174+
label='Upload and draw mask for inpainting',
175+
type='pil',
176+
sources=["upload", "webcam"],
177+
image_mode='RGB',
178+
layers=False,
179+
brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed"),
180+
height=500
181+
)
182+
183+
with gr.Column(elem_classes=["prompt-container"]):
184+
prompt = gr.Text(
185+
label="Your creative prompt",
186+
show_label=True,
187+
max_lines=1,
188+
placeholder="Describe what you want to generate...",
189+
container=True,
190+
)
191+
192+
run_button = gr.Button("✨ Generate", elem_classes=["btn-primary"])
193+
# Right column: Output
194+
with gr.Column(scale=1, elem_classes=["result-container"]):
195+
result = gr.ImageSlider(
196+
label="Before & After",
197+
type="pil",
198+
image_mode='RGB',
199+
elem_classes=["result-animation"]
200+
)
201+
202+
# Advanced settings in a nice container
203+
with gr.Column(elem_classes=["settings-container"]):
204+
with gr.Accordion("Advanced Settings", open=False, elem_classes=["accordion-header"]):
205+
with gr.Column():
206+
with gr.Row():
207+
seed = gr.Slider(
208+
label="Seed",
209+
minimum=0,
210+
maximum=MAX_SEED,
211+
step=1,
212+
value=0,
213+
)
214+
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
215+
216+
with gr.Row():
217+
height = gr.Slider(64, 2048, value=512, step=64, label="Height")
218+
width = gr.Slider(64, 2048, value=512, step=64, label="Width")
219+
220+
with gr.Row():
221+
guidance_scale = gr.Slider(0.0, 20.0, value=3.5, step=0.1, label="Guidance Scale")
222+
control_strength = gr.Slider(0.0, 1.0, value=0.5, step=0.05, label="Control Strength")
223+
224+
with gr.Row():
225+
control_stop = gr.Slider(0.0, 1.0, value=0.33, step=0.05, label="Control Stop")
226+
num_inference_steps = gr.Slider(1, 100, value=20, step=1, label="Inference Steps")
227+
228+
# Footer
229+
gr.HTML("""
230+
<div class="footer">
231+
<p>Flex.2 Preview Inpainting OpenVINO Demo</p>
232+
</div>
233+
""")
234+
235+
run_button.click(
236+
fn=infer,
237+
inputs=[edit_image, prompt, seed, randomize_seed, width, height, guidance_scale, control_strength, control_stop, num_inference_steps],
238+
outputs=[result, seed]
239+
)
240+
241+
return demo
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from optimum.intel.openvino import OVDiffusionPipeline
2+
from pipeline import Flex2Pipeline
3+
4+
5+
class OVFlex2Pipeline(OVDiffusionPipeline, Flex2Pipeline):
6+
main_input_name = "prompt"
7+
export_feature = "text-to-image"
8+
auto_model_class = Flex2Pipeline

0 commit comments

Comments
 (0)