-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpredict.py
More file actions
213 lines (179 loc) · 7.14 KB
/
Copy pathpredict.py
File metadata and controls
213 lines (179 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
"""Z-Image Predictor for Replicate with detailed logging and error handling."""
import sys
import time
import traceback
from pathlib import Path as FilePath
from typing import Union
import torch
from cog import BasePredictor, Input, Path
from diffusers import DiffusionPipeline
from huggingface_hub import snapshot_download
# Force stdout/stderr to be unbuffered for real-time logs
sys.stdout.reconfigure(line_buffering=True)
sys.stderr.reconfigure(line_buffering=True)
MODEL_NAME = "Tongyi-MAI/Z-Image-Turbo"
MODEL_CACHE = "./model-cache"
def log(message: str):
"""Print timestamped log message."""
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}", flush=True)
def download_model():
"""Download model weights if not exists."""
if not FilePath(MODEL_CACHE).exists():
log(f"Downloading model {MODEL_NAME}...")
snapshot_download(
MODEL_NAME,
local_dir=MODEL_CACHE,
local_dir_use_symlinks=False,
resume_download=True,
)
log("Model download completed!")
else:
log(f"Model already exists at {MODEL_CACHE}")
class Predictor(BasePredictor):
def setup(self) -> None:
"""Load the Z-Image model into memory."""
try:
log("=" * 60)
log("Starting Z-Image-Turbo setup...")
log("=" * 60)
# Check CUDA availability
log(f"PyTorch version: {torch.__version__}")
log(f"CUDA available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
log(f"CUDA version: {torch.version.cuda}")
log(f"GPU: {torch.cuda.get_device_name(0)}")
log(f"GPU memory: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.2f} GB")
# Download model if needed
log("Checking model weights...")
download_model()
log(f"Model cache found at: {MODEL_CACHE}")
# Load pipeline
log("Loading Z-Image-Turbo pipeline...")
start_time = time.time()
self.pipe = DiffusionPipeline.from_pretrained(
MODEL_CACHE,
torch_dtype=torch.bfloat16,
use_safetensors=True,
)
log(f"Pipeline loaded in {time.time() - start_time:.2f}s")
# Move to GPU
log("Moving model to CUDA...")
start_time = time.time()
self.pipe.to("cuda")
log(f"Model moved to CUDA in {time.time() - start_time:.2f}s")
# Enable optimizations
log("Enabling optimizations...")
# Try to enable Flash Attention
try:
if hasattr(self.pipe, 'transformer'):
self.pipe.transformer.set_attention_backend("flash")
log("✓ Flash Attention enabled")
except Exception as e:
log(f"⚠ Flash Attention not available: {e}")
# Enable memory efficient attention
try:
self.pipe.enable_attention_slicing()
log("✓ Attention slicing enabled")
except Exception as e:
log(f"⚠ Attention slicing failed: {e}")
# Warmup run
log("Running warmup inference...")
start_time = time.time()
_ = self.pipe(
prompt="test",
height=512,
width=512,
num_inference_steps=1,
guidance_scale=0.0,
)
log(f"Warmup completed in {time.time() - start_time:.2f}s")
# Clear CUDA cache
if torch.cuda.is_available():
torch.cuda.empty_cache()
log(f"GPU memory allocated: {torch.cuda.memory_allocated(0) / 1024**3:.2f} GB")
log(f"GPU memory reserved: {torch.cuda.memory_reserved(0) / 1024**3:.2f} GB")
log("=" * 60)
log("✓ Setup completed successfully!")
log("=" * 60)
except Exception as e:
log("=" * 60)
log(f"✗ SETUP FAILED: {str(e)}")
log("=" * 60)
log("Full traceback:")
traceback.print_exc()
raise
def predict(
self,
prompt: str = Input(
description="Text prompt for image generation. Supports English and Chinese.",
default="A beautiful landscape with mountains and a lake at sunset"
),
width: int = Input(
description="Width of the output image",
default=1024,
ge=512,
le=2048
),
height: int = Input(
description="Height of the output image",
default=1024,
ge=512,
le=2048
),
num_inference_steps: int = Input(
description="Number of denoising steps (Z-Image-Turbo uses 8 steps)",
default=8,
ge=1,
le=50
),
seed: int = Input(
description="Random seed for reproducibility. Use 0 for random.",
default=0
),
) -> Path:
"""Generate an image from a text prompt using Z-Image-Turbo."""
try:
log("=" * 60)
log("Starting prediction...")
log(f"Prompt: {prompt}")
log(f"Size: {width}x{height}")
log(f"Steps: {num_inference_steps}")
log(f"Seed: {seed}")
log("=" * 60)
# Set random seed if provided (0 means random)
generator = None
if seed != 0:
generator = torch.Generator("cuda").manual_seed(seed)
log(f"Using seed: {seed}")
# Generate image
log("Generating image...")
start_time = time.time()
image = self.pipe(
prompt=prompt,
height=height,
width=width,
num_inference_steps=num_inference_steps,
guidance_scale=0.0, # Z-Image-Turbo uses guidance_scale=0
generator=generator,
).images[0]
generation_time = time.time() - start_time
log(f"✓ Image generated in {generation_time:.2f}s")
# Save output
output_path = "/tmp/output.png"
log(f"Saving image to {output_path}...")
image.save(output_path, format="PNG", optimize=True)
# Log GPU memory usage
if torch.cuda.is_available():
log(f"GPU memory allocated: {torch.cuda.memory_allocated(0) / 1024**3:.2f} GB")
log("=" * 60)
log("✓ Prediction completed successfully!")
log("=" * 60)
return Path(output_path)
except Exception as e:
log("=" * 60)
log(f"✗ PREDICTION FAILED: {str(e)}")
log("=" * 60)
log("Full traceback:")
traceback.print_exc()
raise