chore: make path resolution more flexible - #32
Conversation
|
@nihui hi there~ We have developed a convenient frontend based on this repository. https://github.com/EutropicAI/FinalDream To better support the distribution of downstream application models, we need some upstream improvements regarding path handling. This PR enables more flexible path resolution, ensuring the application works out-of-the-box in different directory structures. Could you please take a look? We hope this can be merged or implemented similarly. Thanks~ |
There was a problem hiding this comment.
Pull request overview
This pull request refactors path resolution for model files by introducing a new resolve_path helper function that searches for files by keyword rather than using hardcoded full paths. The goal is to make path resolution more flexible and support different directory structures.
Changes:
- Added
resolve_pathfunction that searches directories for files matching a keyword, with optional fallback directory support - Replaced hardcoded model file paths with dynamic path resolution using keyword matching
- Removed model variant detection logic (z-image vs z-image-turbo) from individual component loaders
Comments suppressed due to low confidence (9)
src/zimage.cpp:536
- CapEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.bin"));
cap_embedder.opt = opt;
cap_embedder.load_param(parampath.c_str());
cap_embedder.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:559
- ContextRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.bin"));
context_refiner.opt = opt;
context_refiner.load_param(parampath.c_str());
context_refiner.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:617
- AllXEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin"));
all_x_embedder.opt = opt;
all_x_embedder.load_param(parampath.c_str());
all_x_embedder.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:640
- NoiseRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin"));
noise_refiner.opt = opt;
noise_refiner.load_param(parampath.c_str());
noise_refiner.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:666
- UnifiedRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin"));
unified_refiner.opt = opt;
unified_refiner.load_param(parampath.c_str());
unified_refiner.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:956
- VAE::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("vae.ncnn.param"), PATHSTR("/../z-image-turbo"));
path_t modelpath = resolve_path(model, PATHSTR("vae.ncnn.bin"), PATHSTR("/../z-image-turbo"));
vae.opt = opt;
if (use_vae_tiled)
{
vae.register_custom_layer("GroupNorm", VAETiledGroupNorm_layer_creator);
}
vae.load_param(parampath.c_str());
vae.load_model(modelpath.c_str());
src/zimage.cpp:458
- TextEncoder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("text_encoder.ncnn.param"), PATHSTR("/../z-image-turbo"));
path_t modelpath = resolve_path(model, PATHSTR("text_encoder.ncnn.bin"), PATHSTR("/../z-image-turbo"));
text_encoder.opt = opt;
text_encoder.load_param(parampath.c_str());
text_encoder.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:692
- AllFinalLayer::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin"));
all_final_layer.opt = opt;
all_final_layer.load_param(parampath.c_str());
all_final_layer.load_model(modelpath.c_str());
return 0;
src/zimage.cpp:584
- TEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
path_t parampath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.bin"));
t_embedder.opt = opt;
t_embedder.load_param(parampath.c_str());
t_embedder.load_model(modelpath.c_str());
return 0;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| path_t parampath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.bin")); |
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_cap_embedder.ncnn.param and z_image_turbo_transformer_cap_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin")); | ||
|
|
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_noise_refiner.ncnn.param and z_image_turbo_transformer_noise_refiner.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param")); | |
| path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin")); | |
| // Select the correct noise refiner model variant (turbo vs non-turbo) | |
| // based on the model path, to avoid ambiguous substring matching in | |
| // resolve_path when multiple variants are present in the same directory. | |
| path_t param_filename; | |
| path_t model_filename; | |
| if (model.find(PATHSTR("z-image-turbo")) != path_t::npos) | |
| { | |
| param_filename = PATHSTR("z_image_turbo_transformer_noise_refiner.ncnn.param"); | |
| model_filename = PATHSTR("z_image_turbo_transformer_noise_refiner.ncnn.bin"); | |
| } | |
| else | |
| { | |
| param_filename = PATHSTR("z_image_transformer_noise_refiner.ncnn.param"); | |
| model_filename = PATHSTR("z_image_transformer_noise_refiner.ncnn.bin"); | |
| } | |
| path_t parampath = resolve_path(model, param_filename); | |
| path_t modelpath = resolve_path(model, model_filename); |
| fprintf(stderr, "resolve_path failed: %s\n", search_keyword.c_str()); | ||
| #endif | ||
|
|
||
| return path_t(); |
There was a problem hiding this comment.
Trailing whitespace detected at the end of the line. Remove the trailing space after path_t() for code cleanliness.
| return path_t(); | |
| return path_t(); |
| path_t parampath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.bin")); |
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_t_embedder.ncnn.param and z_image_turbo_transformer_t_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| fprintf(stderr, "resolve_path failed: %s\n", search_keyword.c_str()); | ||
| #endif | ||
|
|
||
| return path_t(); |
There was a problem hiding this comment.
Returning an empty path_t() on failure will cause BpeTokenizer::LoadFromFiles and ncnn load methods to fail or crash with an empty path. The function should either throw an exception, return an error code, or use a different mechanism to signal failure. Consider using std::optional<path_t> or checking for empty paths at call sites before using them.
| path_t parampath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.bin")); |
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_context_refiner.ncnn.param and z_image_turbo_transformer_context_refiner.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin")); | ||
|
|
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_unified.ncnn.param and z_image_turbo_transformer_unified.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param")); | |
| path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin")); | |
| path_t param_filename; | |
| path_t model_filename; | |
| if (model.find(PATHSTR("z-image-turbo")) != path_t::npos) | |
| { | |
| // Turbo variant unified transformer | |
| param_filename = PATHSTR("z_image_turbo_transformer_unified.ncnn.param"); | |
| model_filename = PATHSTR("z_image_turbo_transformer_unified.ncnn.bin"); | |
| } | |
| else if (model.find(PATHSTR("z-image")) != path_t::npos) | |
| { | |
| // Non-turbo z-image unified transformer | |
| param_filename = PATHSTR("z_image_transformer_unified.ncnn.param"); | |
| model_filename = PATHSTR("z_image_transformer_unified.ncnn.bin"); | |
| } | |
| else | |
| { | |
| // Fallback to generic unified transformer filenames | |
| param_filename = PATHSTR("transformer_unified.ncnn.param"); | |
| model_filename = PATHSTR("transformer_unified.ncnn.bin"); | |
| } | |
| path_t parampath = resolve_path(model, param_filename); | |
| path_t modelpath = resolve_path(model, model_filename); |
| path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin")); | ||
|
|
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_all_x_embedder.ncnn.param and z_image_turbo_transformer_all_x_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param")); | |
| path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin")); | |
| // Select the correct model variant (turbo vs non-turbo) based on the model path. | |
| const path_t turbo_marker = PATHSTR("z-image-turbo"); | |
| const bool is_turbo = model.find(turbo_marker) != path_t::npos; | |
| const path_t param_name = is_turbo | |
| ? PATHSTR("turbo_transformer_all_x_embedder.ncnn.param") | |
| : PATHSTR("transformer_all_x_embedder.ncnn.param"); | |
| const path_t model_name = is_turbo | |
| ? PATHSTR("turbo_transformer_all_x_embedder.ncnn.bin") | |
| : PATHSTR("transformer_all_x_embedder.ncnn.bin"); | |
| path_t parampath = resolve_path(model, param_name); | |
| path_t modelpath = resolve_path(model, model_name); |
| path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param")); | ||
| path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin")); | ||
|
|
There was a problem hiding this comment.
The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_all_final_layer.ncnn.param and z_image_turbo_transformer_all_final_layer.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.
| path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param")); | |
| path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin")); | |
| // Select the correct all-final-layer model variant explicitly based on the model path, | |
| // to avoid ambiguous substring matching inside resolve_path. | |
| path_t param_filename; | |
| path_t bin_filename; | |
| if (model.find(PATHSTR("z-image-turbo")) != path_t::npos) | |
| { | |
| // Turbo variant | |
| param_filename = PATHSTR("z_image_turbo_transformer_all_final_layer.ncnn.param"); | |
| bin_filename = PATHSTR("z_image_turbo_transformer_all_final_layer.ncnn.bin"); | |
| } | |
| else if (model.find(PATHSTR("z-image")) != path_t::npos) | |
| { | |
| // Non-turbo z-image variant | |
| param_filename = PATHSTR("z_image_transformer_all_final_layer.ncnn.param"); | |
| bin_filename = PATHSTR("z_image_transformer_all_final_layer.ncnn.bin"); | |
| } | |
| else | |
| { | |
| // Fallback to the generic filenames used previously | |
| param_filename = PATHSTR("transformer_all_final_layer.ncnn.param"); | |
| bin_filename = PATHSTR("transformer_all_final_layer.ncnn.bin"); | |
| } | |
| path_t parampath = resolve_path(model, param_filename); | |
| path_t modelpath = resolve_path(model, bin_filename); |
|
|
||
| if (!fallback_dir.empty()) | ||
| { | ||
| path_t parent = root + fallback_dir; |
There was a problem hiding this comment.
The filenames vector is reused for both the root directory search and the fallback directory search without being cleared. If the first list_directory succeeds but doesn't find a match, filenames will contain stale entries when searching the fallback directory. This could lead to incorrect path resolution. The vector should be cleared before the second list_directory call or a fresh vector should be used.
| path_t parent = root + fallback_dir; | |
| path_t parent = root + fallback_dir; | |
| filenames.clear(); |
No description provided.