-
Notifications
You must be signed in to change notification settings - Fork 3k
CLI: Show Progress / Save Progress / Generate Progress Video #694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #!/usr/bin/env python3 | ||
| # Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein) | ||
|
|
||
| import cv2 | ||
| import os | ||
| import re | ||
| import sys | ||
|
|
@@ -12,6 +13,7 @@ | |
| from ldm.dream.pngwriter import PngWriter | ||
| from ldm.dream.server import DreamServer, ThreadingDreamServer | ||
| from ldm.dream.image_util import make_grid | ||
| from ldm.util import make_video, show_progress | ||
| from omegaconf import OmegaConf | ||
|
|
||
| # Placeholder to be replaced with proper class that tracks the | ||
|
|
@@ -220,10 +222,70 @@ def main_loop(gen, opt, infile): | |
| prior_variations = opt.with_variations or [] | ||
| first_seed = opt.seed | ||
|
|
||
| if opt.save_progress is not None or opt.show_progress is not None: | ||
| step_index = 1 | ||
| step_count = 1 | ||
|
|
||
| if opt.show_progress is not None: | ||
| if len(opt.show_progress) < 2: | ||
| if len(opt.show_progress) == 0: | ||
| opt.show_progress.extend([5, 2]) | ||
| elif len(opt.show_progress) == 1: | ||
| opt.show_progress.append(2) | ||
| step_count = int(opt.show_progress[0]) | ||
|
|
||
| if opt.save_progress is not None: | ||
| if len(opt.save_progress) < 2: | ||
| if len(opt.save_progress) == 0: | ||
| opt.save_progress.extend([5, None]) | ||
| elif len(opt.save_progress) == 1: | ||
| opt.save_progress.append(None) | ||
|
|
||
| step_count, progress_video_type = opt.save_progress | ||
|
|
||
| if progress_video_type is not None: | ||
| frames_for_video = [] | ||
|
|
||
| if progress_video_type != 'vo': | ||
| step_writer = PngWriter(os.path.join(current_outdir, 'intermediates')) | ||
|
|
||
| def image_progress(sample, step): | ||
| nonlocal step_index | ||
| nonlocal step_count | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nonlocals make for more complex code, generally good to be avoided. Options:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The nonlocals were from the initial PR by kevin that added the progress code. It is similar to how its done on the server.py model too. I'm not a fan of it either but I didn't change it for the time being.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm with mh-dm on this one. Unless I'm reading this wrong, this could even be a function outside of
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue here is that image_callback and step_callback are predefined callbacks that I cannot pass down any values to. And unfortunately the functionality of this and the image writer need it to use values from outside the scope of these functions. And I cannot initialize step_index inside the callback either because then it'll get initialized for iteration which does not work. With how dream.py is currently written, I don't see a way to bypass this. Probably why even lstein used nonlocals in image_writer. Let me explore some options to see if there's a cleaner way for me to do this. |
||
|
|
||
| if step_count == 0: | ||
| step_count = 5 | ||
|
|
||
| if step % int(step_count) == 0 and step < opt.steps - 1: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There needs to be some type checking on the argument you pass to -save_progress or -show_progress. If you pass a non-numeric argument (as I just did with
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. I'm out at the moment. Can't work on this for a bit. If you wanna go ahead and add these tweaks in and make a PR here, I don't mind. If not, I'll do it when I'm back home. |
||
| image = gen.sample_to_image(sample) | ||
|
|
||
| if opt.save_progress is not None: | ||
| nonlocal progress_video_type | ||
| step_index_padded = str(step_index).rjust(len(str(opt.steps)), '0') | ||
|
|
||
| if progress_video_type != 'vo': | ||
| interim_seed = '.' | ||
| if opt.seed is not None: | ||
| interim_seed = f'.{opt.seed}.' | ||
| name = f'{prefix}{interim_seed}{step_index_padded}.png' | ||
| metadata = f'{opt.prompt} -S{interim_seed} [intermediate]' | ||
| step_writer.save_image_and_prompt_to_png(image, metadata, name) | ||
|
|
||
| if progress_video_type == 'v' or progress_video_type == 'vo': | ||
| frames_for_video.append(image) | ||
|
|
||
| if opt.show_progress is not None: | ||
| if step == 0 and int(step_count) == opt.steps: | ||
| return | ||
| show_progress(image) | ||
|
|
||
| step_index += 1 | ||
|
|
||
| def image_writer(image, seed, upscaled=False): | ||
| path = None | ||
| nonlocal first_seed | ||
| nonlocal prior_variations | ||
| nonlocal prior_variations | ||
|
|
||
| if opt.grid: | ||
| grid_images[seed] = image | ||
| else: | ||
|
|
@@ -255,8 +317,25 @@ def image_writer(image, seed, upscaled=False): | |
| results.append([path, formatted_dream_prompt]) | ||
| last_results.append([path, seed]) | ||
|
|
||
| if opt.save_progress is not None: | ||
| nonlocal progress_video_type | ||
| if progress_video_type == 'v' or progress_video_type == 'vo': | ||
| frames_for_video.append(image) | ||
| make_video(frames_for_video, os.path.join(current_outdir, f'{prefix}.{seed}.mp4')) | ||
| frames_for_video.clear() | ||
|
|
||
| if opt.show_progress is not None: | ||
| show_progress(image) | ||
| cv2.waitKey(1000) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove as you already call waitKey in show_progress?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not the same. The waitKey in show_progress is to keep the window alive. The waitKey here lasts for a second so the user gets a preview of the final output for atleast a second before it moves on -- added this because when a user is performing multiple iterations, the final preview gets taken off screen too quickly. |
||
|
|
||
| catch_ctrl_c = infile is None # if running interactively, we catch keyboard interrupts | ||
|
|
||
| step_callback = None | ||
| if opt.save_progress is not None or opt.show_progress is not None: | ||
|
blessedcoolant marked this conversation as resolved.
|
||
| step_callback = image_progress | ||
|
|
||
| gen.prompt2image( | ||
| step_callback=step_callback, | ||
| image_callback=image_writer, | ||
| catch_interrupts=catch_ctrl_c, | ||
| **vars(opt) | ||
|
|
@@ -294,6 +373,12 @@ def image_writer(image, seed, upscaled=False): | |
| print('Outputs:') | ||
| log_path = os.path.join(current_outdir, 'dream_log.txt') | ||
| write_log_message(results, log_path) | ||
| if opt.show_progress is not None: | ||
|
tildebyte marked this conversation as resolved.
|
||
| if (int(opt.show_progress[1]) == 0): | ||
| print("Press any key on the preview window to continue ...") | ||
| cv2.waitKey(int(opt.show_progress[1]) * 1000) | ||
| cv2.destroyAllWindows() | ||
| cv2.waitKey(1) # possible fix for window not closing on Macs | ||
| print() | ||
|
|
||
| print('goodbye!') | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
single-dash arguments are supposed to be used with single-letter flags
this file already has plenty of arguments so maybe you should skip the single-dash arguments entirely
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see https://serverfault.com/a/387936 for more info