neggles / animatediff-cli

a CLI utility/library for AnimateDiff stable diffusion generation
Apache License 2.0
263 stars 132 forks source link

Absolute paths aren't working #16

Closed Alphyn-gunner closed 1 year ago

Alphyn-gunner commented 1 year ago

In the prompt Json I have: "path": "c:/StableDiffusion/stable-diffusion-webui/models/Stable-diffusion/realisticVisionV50_v40VAE.safetensors", After running I get:

ValueError:
'c:\\StableDiffusion\\stable-diffusion-webui\\models\\Stable-diffusion\\realisticVisionV50_v40VAE.safetensors' is not in
the subpath of 'C:\\sd\\animatediff-cli' OR one path is relative and the other is absolute.

I can't for the life of me figure out how to correctly specify an absolute path to a model. It used to work in the previous versions.

Another note: It would be great if in this case forward slash could be treated like a part of the path, and not as an escape symbol. Copying paths in Windows gives you forward slashes and you have to change them to backslashes all the time.

neggles commented 1 year ago

Hm, the path value is just parsed by pathlib so it should handle using forward-slash ( / ) path just fine (and it looks like it is) - unfortunately on the backslash ( \ ) front that's just how json handles backslashes, but you should be able to use forward-slash paths in the config file and have them resolve correctly.

As for absolute path handling, yeah, I currently assume paths are relative to the data/ dir and use the name to check for the existence of a pre-converted model in data/models/huggingface (which is where the HF-converted models end up after checkpoint loading); Will look into how I can handle absolute paths better, the goal was to avoid re-converting the checkpoint to HF format on every run 🤔

Alphyn-gunner commented 1 year ago

Thanks for looking into this. The temporary workaround for me for using the checkpoints from the auto1111 and comfy dirs is just creating a lot of hardlinks.

Would using PurePath.as_posix() work for converting the paths into the proper format?

Skquark commented 1 year ago

What I might suggest is to support both absolute and relative paths. First check if the path exists as an absolute location, else use relative to the datadir.. I had to go though extra steps to make it relative on my end, especially to try to make it compatible with both Windows and Linux slashes. I personally prefer using absolutes with os.path instead of pathlib, but all good, it works..

neggles commented 1 year ago

So this is actually a really dumb bug since it's actually loading the model fine, then eating itself when it tries to print out the path to the model relative to the data directory. [edit] OK, while that was true, I'd also hardcoded it to join the model path to the data dir yeah.

Yeesh. Sorry, I could've fixed this weeks ago, my bad. Will push an update shortly...

Update has been pushed that should fix both of those issues 😄 Please reopen if this still doesn't work, but it does in my fairly-limited testing.

remixer-dec commented 1 year ago

I'm getting

HFValidationError: Repo id must be in the form 'repo_name' or 'namespace/repo_name': 'data/models/sd/v1-5-pruned-emaonly.ckpt'. Use repo_type argument if needed.

both when trying to use a symlink+relative path and an absolute path in --model-path argument full command: animatediff generate -W 512 -H 512 -L 6 -C 6 --model-path ./data/models/sd/v1-5-pruned-emaonly.ckpt

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/remixer/ML/animatediff-cli/src/animatediff/cli.py:260 in generate                         │
│                                                                                                  │
│   257 │                                                                                          │
│   258 │   # Get the base model if we don't have it already                                       │
│   259 │   logger.info(f"Using base model: {model_name_or_path}")                                 │
│ ❱ 260 │   base_model_path: Path = get_base_model(model_name_or_path, local_dir=get_dir("data/m   │
│   261 │                                                                                          │
│   262 │   # get a timestamp for the output directory                                             │
│   263 │   time_str = datetime.now().strftime("%Y-%m-%dT%H-%M-%S")                                │
│                                                                                                  │
│ /Users/remixer/ML/animatediff-cli/src/animatediff/utils/model.py:42 in get_base_model            │
│                                                                                                  │
│    39 │   │   │   logger.debug(f"Base model already downloaded to: {relative_path(model_save_d   │
│    40 │   │   else:                                                                              │
│    41 │   │   │   logger.info(f"Downloading base model from {model_name_or_path}...")            │
│ ❱  42 │   │   │   _ = get_hf_pipeline(model_name_or_path, model_save_dir, save=True, force_dow   │
│    43 │   │   model_name_or_path = model_save_dir                                                │
│    44 │                                                                                          │
│    45 │   return Path(model_name_or_path)                                                        │
│                                                                                                  │
│ /Users/remixer/ML/animatediff-cli/src/animatediff/utils/huggingface.py:108 in get_hf_pipeline    │
│                                                                                                  │
│   105 │   │   )                                                                                  │
│   106 │   else:                                                                                  │
│   107 │   │   target_dir.mkdir(exist_ok=True, parents=True)                                      │
│ ❱ 108 │   │   pipeline = StableDiffusionPipeline.from_pretrained(                                │
│   109 │   │   │   pretrained_model_name_or_path=str(repo_id).lstrip("./").replace("\\", "/"),    │
│   110 │   │   │   cache_dir=HF_HUB_CACHE,                                                        │
│   111 │   │   │   resume_download=True,                                                          │
│                                                                                                  │
│ /opt/homebrew/lib/python3.10/site-packages/diffusers/pipelines/pipeline_utils.py:932 in          │
│ from_pretrained                                                                                  │
│                                                                                                  │
│    929 │   │   # 1. Download the checkpoints and configs                                         │
│    930 │   │   # use snapshot download here to get it working from from_pretrained               │
│    931 │   │   if not os.path.isdir(pretrained_model_name_or_path):                              │
│ ❱  932 │   │   │   cached_folder = cls.download(                                                 │
│    933 │   │   │   │   pretrained_model_name_or_path,                                            │
│    934 │   │   │   │   cache_dir=cache_dir,                                                      │
│    935 │   │   │   │   resume_download=resume_download,                                          │
│                                                                                                  │
│ /opt/homebrew/lib/python3.10/site-packages/diffusers/pipelines/pipeline_utils.py:1349 in         │
│ download                                                                                         │
│                                                                                                  │
│   1346 │   │   model_info_call_error: Optional[Exception] = None                                 │
│   1347 │   │   if not local_files_only:                                                          │
│   1348 │   │   │   try:                                                                          │
│ ❱ 1349 │   │   │   │   info = model_info(                                                        │
│   1350 │   │   │   │   │   pretrained_model_name,                                                │
│   1351 │   │   │   │   │   use_auth_token=use_auth_token,                                        │
│   1352 │   │   │   │   │   revision=revision,                                                    │
│                                                                                                  │
│ /opt/homebrew/lib/python3.10/site-packages/huggingface_hub/utils/_validators.py:110 in _inner_fn │
│                                                                                                  │
│   107 │   │   │   kwargs.items(),  # Kwargs values                                               │
│   108 │   │   ):                                                                                 │
│   109 │   │   │   if arg_name in ["repo_id", "from_id", "to_id"]:                                │
│ ❱ 110 │   │   │   │   validate_repo_id(arg_value)                                                │
│   111 │   │   │                                                                                  │
│   112 │   │   │   elif arg_name == "token" and arg_value is not None:                            │
│   113 │   │   │   │   has_token = True                                                           │
│                                                                                                  │
│ /opt/homebrew/lib/python3.10/site-packages/huggingface_hub/utils/_validators.py:158 in           │
│ validate_repo_id                                                                                 │
│                                                                                                  │
│   155 │   │   raise HFValidationError(f"Repo id must be a string, not {type(repo_id)}: '{repo_   │
│   156 │                                                                                          │
│   157 │   if repo_id.count("/") > 1:                                                             │
│ ❱ 158 │   │   raise HFValidationError(                                                           │
│   159 │   │   │   "Repo id must be in the form 'repo_name' or 'namespace/repo_name':"            │
│   160 │   │   │   f" '{repo_id}'. Use `repo_type` argument if needed."                           │
│   161 │   │   )                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

Here lstrip("./") removes the / if the path starts with /, making an absolute path relative, and even after fixing it, I still get that error. Is it even possible to load custom .ckpt models in diffusers? If so, what am I doing wrong? Also, why is there a cmake dependency in this project?

neggles commented 1 year ago

I'm getting

HFValidationError: Repo id must be in the form 'repo_name' or 'namespace/repo_name': 'data/models/sd/v1-5-pruned-emaonly.ckpt'. Use repo_type argument if needed.

both when trying to use a symlink+relative path and an absolute path in --model-path argument full command: animatediff generate -W 512 -H 512 -L 6 -C 6 --model-path ./data/models/sd/v1-5-pruned-emaonly.ckpt [...] Here lstrip("./") removes the / if the path starts with /, making an absolute path relative, and even after fixing it, I still get that error. Is it even possible to load custom .ckpt models in diffusers? If so, what am I doing wrong? Also, why is there a cmake dependency in this project?

Ahh, okay, I see what's going on here - that's the base model path, which needs to be a HF repo ID or a path to a HF repo dir, or just left unset. That's pulled down by Diffusers and used as the skeleton that the motion module and the SD checkpoint file (specified in the prompt config .json, not at the command line) are loaded into; tbh it probably shouldn't be configurable and/or I should remove the need to have it entirely, just haven't gotten around to it.

in other words, you can just leave that path unset if you don't mind a copy of the model sitting in your HF_HUB_CACHE dir, otherwise it needs to point at a copy of this repo