Repository navigation
Keep VAE tiles overlapping on the out-of-memory retry (no more seam lines), and retry the encode too #21
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
Keep VAE tiles overlapping on the out-of-memory retry (no more seam lines), and retry the encode too #21
Changes from all commits
1a03bc7
3dc5d6b
ee5829c
59c912a
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 |
|---|---|---|
|
|
@@ -2740,6 +2740,13 @@ int StableDiffusionGGML::align_video_frames(int frames) { | |
|
|
||
| sd::Tensor<float> StableDiffusionGGML::encode_to_vae_latents(const sd::Tensor<float>& x) { | ||
| auto latents = first_stage_model->encode(n_threads, x, vae_tiling_params, circular_x, circular_y); | ||
| // Same fallback as decode_first_stage, on a copy: an encode that ran out of memory is retried with | ||
| // overlapping tiles for this call only. | ||
| sd_tiling_params_t retry_tiling_params = vae_tiling_params; | ||
| while (latents.empty() && | ||
| sd::backend_fit::prepare_vae_retry_tiling(retry_tiling_params, false, true)) { | ||
| latents = first_stage_model->encode(n_threads, x, retry_tiling_params, circular_x, circular_y); | ||
|
Comment on lines
+2746
to
+2748
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.
When image VAE tiling starts disabled and an encode OOM triggers this retry under Useful? React with 👍 / 👎. |
||
| } | ||
| if (latents.empty()) { | ||
| return {}; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,37 @@ static void sd_tiling_calc_tiles(int& num_tiles_dim, | |
| } | ||
| } | ||
|
|
||
| int sd_tiling_seam_safe_tile_size(int small_dim, int tile_size, float tile_overlap_factor) { | ||
| // sd_tiling_calc_tiles lets the real overlap fall well below the target for some sizes. The worst case is a | ||
| // tile a little over half of the axis (e.g. round(dim / 2)): it falls back to two tiles overlapping by | ||
| // 2 * tile_size - small_dim, which is 0 or 1 latent, so the cross-fade has nothing to blend over and the tile | ||
| // edge shows as a line. Pick the nearest tile size (smaller first; a larger one only up to twice the request, | ||
| // so an explicitly small tile cannot balloon) whose tiles overlap by at least half the target and by 2+ latents. | ||
| const int min_tile_size = 4; | ||
| if (tile_overlap_factor <= 0.f || tile_size >= small_dim) { | ||
| return tile_size; | ||
| } | ||
| auto overlaps_enough = [&](int size) { | ||
| int num_tiles; | ||
| float overlap_factor; | ||
| sd_tiling_calc_tiles(num_tiles, overlap_factor, small_dim, size, tile_overlap_factor, false); | ||
|
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.
When Useful? React with 👍 / 👎.
Member
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. Fixed in ee5829c: |
||
| const int overlap = static_cast<int>(size * overlap_factor); | ||
| const int min_overlap = std::max(2, static_cast<int>(size * tile_overlap_factor * 0.5f)); | ||
| return num_tiles < 2 || overlap >= min_overlap; | ||
| }; | ||
| for (int size = tile_size; size >= min_tile_size; --size) { | ||
| if (overlaps_enough(size)) { | ||
| return size; | ||
| } | ||
| } | ||
| for (int size = tile_size + 1; size < small_dim && size <= 2 * tile_size; ++size) { | ||
| if (overlaps_enough(size)) { | ||
| return size; | ||
| } | ||
| } | ||
| return tile_size; | ||
| } | ||
|
|
||
| static int64_t sd_tensor_plane_size(const sd::Tensor<float>& tensor) { | ||
| GGML_ASSERT(tensor.dim() >= 2); | ||
| return tensor.shape()[0] * tensor.shape()[1]; | ||
|
|
||
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.
For ordinary image VAEs,
get_tile_sizesmultiplies relative encode tile sizes byencoding_factor = 2.0, but this shared floor stops retrying oncerel_size_*reaches 0.125. Consequently encode retries use effective axis fractions of 0.5 and 0.25 and then give up, never trying the advertised one-eighth-sized tile; an encode that still OOMs at one quarter but would fit at one eighth therefore fails unnecessarily. The encode floor must account for the encoding factor, just asfirst_rel_sizealready does.Useful? React with 👍 / 👎.