Spaces:
Running
on
Zero
Running
on
Zero
Cleanup
Browse files- app.py +13 -10
- optimization.py +5 -3
- optimization_utils.py +18 -18
app.py
CHANGED
@@ -54,24 +54,27 @@ default_prompt_i2v = "make this image come alive, cinematic motion, smooth anima
|
|
54 |
default_negative_prompt = "Bright tones, overexposed, static, blurred details, subtitles, style, works, paintings, images, static, overall gray, worst quality, low quality, JPEG compression residue, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn faces, deformed, disfigured, misshapen limbs, fused fingers, still picture, messy background, three legs, many people in the background, walking backwards, watermark, text, signature"
|
55 |
|
56 |
|
57 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
target_aspect = LANDSCAPE_WIDTH / LANDSCAPE_HEIGHT
|
59 |
width, height = image.size
|
60 |
in_aspect = width / height
|
61 |
if in_aspect > target_aspect:
|
62 |
-
new_width =
|
63 |
left = (width - new_width) // 2
|
64 |
image = image.crop((left, 0, left + new_width, height))
|
65 |
else:
|
66 |
-
new_height =
|
67 |
top = (height - new_height) // 2
|
68 |
image = image.crop((0, top, width, top + new_height))
|
69 |
-
|
70 |
-
(LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT)
|
71 |
-
if in_aspect > target_aspect else
|
72 |
-
(LANDSCAPE_HEIGHT, LANDSCAPE_WIDTH)
|
73 |
-
)
|
74 |
-
return image.resize((target_width, target_height), Image.LANCZOS)
|
75 |
|
76 |
def get_duration(
|
77 |
input_image,
|
@@ -147,7 +150,7 @@ def generate_video(
|
|
147 |
|
148 |
num_frames = np.clip(int(round(duration_seconds * FIXED_FPS)), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
|
149 |
current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
|
150 |
-
resized_image =
|
151 |
|
152 |
output_frames_list = pipe(
|
153 |
image=resized_image,
|
|
|
54 |
default_negative_prompt = "Bright tones, overexposed, static, blurred details, subtitles, style, works, paintings, images, static, overall gray, worst quality, low quality, JPEG compression residue, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn faces, deformed, disfigured, misshapen limbs, fused fingers, still picture, messy background, three legs, many people in the background, walking backwards, watermark, text, signature"
|
55 |
|
56 |
|
57 |
+
def resize_image(image: Image.Image) -> Image.Image:
|
58 |
+
if image.height > image.width:
|
59 |
+
transposed = image.transpose(Image.Transpose.ROTATE_90)
|
60 |
+
resized = resize_image_landscape(transposed)
|
61 |
+
return resized.transpose(Image.Transpose.ROTATE_270)
|
62 |
+
return resize_image_landscape(image)
|
63 |
+
|
64 |
+
|
65 |
+
def resize_image_landscape(image: Image.Image) -> Image.Image:
|
66 |
target_aspect = LANDSCAPE_WIDTH / LANDSCAPE_HEIGHT
|
67 |
width, height = image.size
|
68 |
in_aspect = width / height
|
69 |
if in_aspect > target_aspect:
|
70 |
+
new_width = round(height * target_aspect)
|
71 |
left = (width - new_width) // 2
|
72 |
image = image.crop((left, 0, left + new_width, height))
|
73 |
else:
|
74 |
+
new_height = round(width / target_aspect)
|
75 |
top = (height - new_height) // 2
|
76 |
image = image.crop((0, top, width, top + new_height))
|
77 |
+
return image.resize((LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT), Image.LANCZOS)
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
def get_duration(
|
80 |
input_image,
|
|
|
150 |
|
151 |
num_frames = np.clip(int(round(duration_seconds * FIXED_FPS)), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
|
152 |
current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
|
153 |
+
resized_image = resize_image(input_image)
|
154 |
|
155 |
output_frames_list = pipe(
|
156 |
image=resized_image,
|
optimization.py
CHANGED
@@ -89,10 +89,12 @@ def optimize_pipeline_(pipeline: Callable[P, Any], *args: P.args, **kwargs: P.kw
|
|
89 |
compiled_landscape = aoti_compile(exported_landscape, INDUCTOR_CONFIGS)
|
90 |
print('compiled_landscape', -(t0 - (t0 := datetime.now())))
|
91 |
|
92 |
-
compiled_portrait = aoti_compile(exported_portrait, INDUCTOR_CONFIGS)
|
93 |
-
compiled_portrait.weights.clear()
|
94 |
print('compiled_portrait', -(t0 - (t0 := datetime.now())))
|
95 |
-
|
|
|
|
|
|
|
96 |
return compiled_landscape, compiled_portrait
|
97 |
|
98 |
compiled_landscape, compiled_portrait = compile_transformer()
|
|
|
89 |
compiled_landscape = aoti_compile(exported_landscape, INDUCTOR_CONFIGS)
|
90 |
print('compiled_landscape', -(t0 - (t0 := datetime.now())))
|
91 |
|
92 |
+
compiled_portrait = aoti_compile(exported_portrait, INDUCTOR_CONFIGS)
|
|
|
93 |
print('compiled_portrait', -(t0 - (t0 := datetime.now())))
|
94 |
+
|
95 |
+
# Avoid weights duplication when serializing back to main process
|
96 |
+
compiled_portrait.weights = compiled_landscape.weights
|
97 |
+
|
98 |
return compiled_landscape, compiled_portrait
|
99 |
|
100 |
compiled_landscape, compiled_portrait = compile_transformer()
|
optimization_utils.py
CHANGED
@@ -10,7 +10,6 @@ from unittest.mock import patch
|
|
10 |
import torch
|
11 |
from torch._inductor.package.package import package_aoti
|
12 |
from torch.export.pt2_archive._package import AOTICompiledModel
|
13 |
-
from torch.export.pt2_archive._package_weights import TensorProperties
|
14 |
from torch.export.pt2_archive._package_weights import Weights
|
15 |
|
16 |
|
@@ -21,31 +20,31 @@ INDUCTOR_CONFIGS_OVERRIDES = {
|
|
21 |
}
|
22 |
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
class ZeroGPUCompiledModel:
|
25 |
-
def __init__(self, archive_file: torch.types.FileLike, weights:
|
26 |
self.archive_file = archive_file
|
27 |
self.weights = weights
|
28 |
-
if cuda:
|
29 |
-
self.weights_to_cuda_()
|
30 |
self.compiled_model: ContextVar[AOTICompiledModel | None] = ContextVar('compiled_model', default=None)
|
31 |
-
def weights_to_cuda_(self):
|
32 |
-
for name in self.weights:
|
33 |
-
tensor, properties = self.weights.get_weight(name)
|
34 |
-
self.weights[name] = (tensor.to('cuda'), properties)
|
35 |
def __call__(self, *args, **kwargs):
|
36 |
if (compiled_model := self.compiled_model.get()) is None:
|
37 |
-
constants_map = {name: value[0] for name, value in self.weights.items()}
|
38 |
compiled_model = cast(AOTICompiledModel, torch._inductor.aoti_load_package(self.archive_file))
|
39 |
-
compiled_model.load_constants(constants_map, check_full_update=True, user_managed=True)
|
40 |
self.compiled_model.set(compiled_model)
|
41 |
return compiled_model(*args, **kwargs)
|
42 |
-
def __reduce__(self):
|
43 |
-
weight_dict: dict[str, tuple[torch.Tensor, TensorProperties]] = {}
|
44 |
-
for name in self.weights:
|
45 |
-
tensor, properties = self.weights.get_weight(name)
|
46 |
-
tensor_ = torch.empty_like(tensor, device='cpu').pin_memory()
|
47 |
-
weight_dict[name] = (tensor_.copy_(tensor).detach().share_memory_(), properties)
|
48 |
-
return ZeroGPUCompiledModel, (self.archive_file, Weights(weight_dict), True)
|
49 |
|
50 |
|
51 |
def aoti_compile(
|
@@ -61,7 +60,8 @@ def aoti_compile(
|
|
61 |
files: list[str | Weights] = [file for file in artifacts if isinstance(file, str)]
|
62 |
package_aoti(archive_file, files)
|
63 |
weights, = (artifact for artifact in artifacts if isinstance(artifact, Weights))
|
64 |
-
|
|
|
65 |
|
66 |
|
67 |
@contextlib.contextmanager
|
|
|
10 |
import torch
|
11 |
from torch._inductor.package.package import package_aoti
|
12 |
from torch.export.pt2_archive._package import AOTICompiledModel
|
|
|
13 |
from torch.export.pt2_archive._package_weights import Weights
|
14 |
|
15 |
|
|
|
20 |
}
|
21 |
|
22 |
|
23 |
+
class ZeroGPUWeights:
|
24 |
+
def __init__(self, constants_map: dict[str, torch.Tensor], to_cuda: bool = False):
|
25 |
+
if to_cuda:
|
26 |
+
self.constants_map = {name: tensor.to('cuda') for name, tensor in constants_map.items()}
|
27 |
+
else:
|
28 |
+
self.constants_map = constants_map
|
29 |
+
def __reduce__(self):
|
30 |
+
constants_map: dict[str, torch.Tensor] = {}
|
31 |
+
for name, tensor in self.constants_map.items():
|
32 |
+
tensor_ = torch.empty_like(tensor, device='cpu').pin_memory()
|
33 |
+
constants_map[name] = tensor_.copy_(tensor).detach().share_memory_()
|
34 |
+
return ZeroGPUWeights, (constants_map, True)
|
35 |
+
|
36 |
+
|
37 |
class ZeroGPUCompiledModel:
|
38 |
+
def __init__(self, archive_file: torch.types.FileLike, weights: ZeroGPUWeights):
|
39 |
self.archive_file = archive_file
|
40 |
self.weights = weights
|
|
|
|
|
41 |
self.compiled_model: ContextVar[AOTICompiledModel | None] = ContextVar('compiled_model', default=None)
|
|
|
|
|
|
|
|
|
42 |
def __call__(self, *args, **kwargs):
|
43 |
if (compiled_model := self.compiled_model.get()) is None:
|
|
|
44 |
compiled_model = cast(AOTICompiledModel, torch._inductor.aoti_load_package(self.archive_file))
|
45 |
+
compiled_model.load_constants(self.weights.constants_map, check_full_update=True, user_managed=True)
|
46 |
self.compiled_model.set(compiled_model)
|
47 |
return compiled_model(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
|
50 |
def aoti_compile(
|
|
|
60 |
files: list[str | Weights] = [file for file in artifacts if isinstance(file, str)]
|
61 |
package_aoti(archive_file, files)
|
62 |
weights, = (artifact for artifact in artifacts if isinstance(artifact, Weights))
|
63 |
+
zerogpu_weights = ZeroGPUWeights({name: weights.get_weight(name)[0] for name in weights})
|
64 |
+
return ZeroGPUCompiledModel(archive_file, zerogpu_weights)
|
65 |
|
66 |
|
67 |
@contextlib.contextmanager
|