From 054f6938159762676f227fa5f0e605f05c06f36e Mon Sep 17 00:00:00 2001 From: Tran Xen <137925069+glucauze@users.noreply.github.com> Date: Tue, 15 Aug 2023 01:17:26 +0200 Subject: [PATCH] speed up install and config --- check.sh | 2 +- install.py | 7 ++- models.json | 1 + requirements-gpu.txt | 1 - scripts/configure.py | 46 +----------------- scripts/faceswaplab.py | 18 +++---- scripts/faceswaplab_globals.py | 15 ++++-- .../faceswaplab_settings.py | 4 +- scripts/faceswaplab_swapping/swapper.py | 6 +-- scripts/faceswaplab_ui/faceswaplab_tab.py | 4 +- .../face_checkpoints_utils.py | 4 +- scripts/faceswaplab_utils/install_utils.py | 18 +++++++ scripts/faceswaplab_utils/models_utils.py | 47 ++++++++++++++++--- 13 files changed, 99 insertions(+), 74 deletions(-) create mode 100644 models.json create mode 100644 scripts/faceswaplab_utils/install_utils.py diff --git a/check.sh b/check.sh index d5e3b5f..bbfd7d5 100755 --- a/check.sh +++ b/check.sh @@ -1,4 +1,4 @@ #!/bin/bash autoflake --in-place --remove-unused-variables -r --remove-all-unused-imports . -mypy --install-types +mypy --non-interactive --install-types pre-commit run --all-files diff --git a/install.py b/install.py index f903986..4cfe80d 100644 --- a/install.py +++ b/install.py @@ -36,6 +36,8 @@ def check_install() -> None: required_version = parse(package.split(">=")[1]) return installed_version >= required_version else: + if package_name == "opencv-python": + return launch.is_installed(package_name) or launch.is_installed("cv2") return launch.is_installed(package_name) print("Checking faceswaplab requirements") @@ -59,4 +61,7 @@ def check_install() -> None: raise e -check_install() +import timeit + +check_time = timeit.timeit(check_install, number=1) +print(check_time) diff --git a/models.json b/models.json new file mode 100644 index 0000000..f474cb2 --- /dev/null +++ b/models.json @@ -0,0 +1 @@ +[{"analyzerName":"intellisense-members-lstm-pylance","languageName":"python","identity":{"modelId":"E61945A9A512ED5E1A3EE3F1A2365B88F8FE","outputId":"E4E9EADA96734F01970E616FAB2FAC19","modifiedTimeUtc":"2020-08-11T14:06:50.811Z"},"filePath":"E61945A9A512ED5E1A3EE3F1A2365B88F8FE_E4E9EADA96734F01970E616FAB2FAC19","lastAccessTimeUtc":"2023-08-14T21:58:14.988Z"}] \ No newline at end of file diff --git a/requirements-gpu.txt b/requirements-gpu.txt index 645b201..a26f6c2 100644 --- a/requirements-gpu.txt +++ b/requirements-gpu.txt @@ -3,7 +3,6 @@ dill ifnude insightface==0.7.3 onnx>=1.14.0 -opencv-python pandas pydantic safetensors diff --git a/scripts/configure.py b/scripts/configure.py index 1340690..aa25e80 100644 --- a/scripts/configure.py +++ b/scripts/configure.py @@ -1,51 +1,15 @@ import os from tqdm import tqdm -import traceback import urllib.request from scripts.faceswaplab_utils.faceswaplab_logging import logger from scripts.faceswaplab_globals import * from packaging import version import pkg_resources -import hashlib +from scripts.faceswaplab_utils.models_utils import check_model ALREADY_DONE = False -def check_install() -> None: - # Very ugly hack :( due to sdnext optimization not calling install.py every time if git log has not changed - import importlib.util - import sys - import os - - current_dir = os.path.dirname(os.path.realpath(__file__)) - check_install_path = os.path.join(current_dir, "..", "install.py") - spec = importlib.util.spec_from_file_location("check_install", check_install_path) - check_install = importlib.util.module_from_spec(spec) - sys.modules["check_install"] = check_install - spec.loader.exec_module(check_install) - check_install.check_install() # type: ignore - #### End of ugly hack :( ! - - -def is_sha1_matching(file_path: str, expected_sha1: str) -> bool: - sha1_hash = hashlib.sha1(usedforsecurity=False) - try: - with open(file_path, "rb") as file: - for byte_block in iter(lambda: file.read(4096), b""): - sha1_hash.update(byte_block) - if sha1_hash.hexdigest() == expected_sha1: - return True - else: - return False - except Exception as e: - logger.error( - "Failed to check model hash, check the model is valid or has been downloaded adequately : %e", - e, - ) - traceback.print_exc() - return False - - def check_configuration() -> None: global ALREADY_DONE @@ -83,13 +47,7 @@ def check_configuration() -> None: if not os.path.exists(model_path): download(model_url, model_path) - - if not is_sha1_matching(model_path, EXPECTED_INSWAPPER_SHA1): - logger.error( - "Suspicious sha1 for model %s, check the model is valid or has been downloaded adequately. Should be %s", - model_path, - EXPECTED_INSWAPPER_SHA1, - ) + check_model() gradio_version = pkg_resources.get_distribution("gradio").version diff --git a/scripts/faceswaplab.py b/scripts/faceswaplab.py index 835be58..a116fb5 100644 --- a/scripts/faceswaplab.py +++ b/scripts/faceswaplab.py @@ -12,7 +12,7 @@ from scripts.faceswaplab_settings import faceswaplab_settings from scripts.faceswaplab_swapping import swapper from scripts.faceswaplab_ui import faceswaplab_tab, faceswaplab_unit_ui from scripts.faceswaplab_utils import faceswaplab_logging, imgutils, models_utils -from scripts.faceswaplab_utils.models_utils import get_current_model +from scripts.faceswaplab_utils.models_utils import get_current_swap_model from scripts.faceswaplab_utils.typing import * from scripts.faceswaplab_utils.ui_utils import dataclasses_from_flat_list from scripts.faceswaplab_utils.faceswaplab_logging import logger, save_img_debug @@ -99,7 +99,7 @@ class FaceSwapScript(scripts.Script): return f"faceswaplab" def show(self, is_img2img: bool) -> bool: - return scripts.AlwaysVisible + return scripts.AlwaysVisible # type: ignore def ui(self, is_img2img: bool) -> List[gr.components.Component]: with gr.Accordion(f"FaceSwapLab {VERSION_FLAG}", open=False): @@ -147,7 +147,7 @@ class FaceSwapScript(scripts.Script): (img, None) for img in p.init_images ] new_inits = swapper.process_images_units( - get_current_model(), + get_current_swap_model(), self.swap_in_source_units, images=init_images, force_blend=True, @@ -181,7 +181,7 @@ class FaceSwapScript(scripts.Script): for i, (img, info) in enumerate(zip(orig_images, orig_infotexts)): batch_index = i % p.batch_size swapped_images = swapper.process_images_units( - get_current_model(), + get_current_swap_model(), self.swap_in_generated_units, images=[(img, info)], ) @@ -213,8 +213,8 @@ class FaceSwapScript(scripts.Script): swp_img, p.outpath_samples, "", - p.all_seeds[batch_index], - p.all_prompts[batch_index], + p.all_seeds[batch_index], # type: ignore + p.all_prompts[batch_index], # type: ignore opts.samples_format, info=new_info, p=p, @@ -231,7 +231,7 @@ class FaceSwapScript(scripts.Script): text = processed.infotexts[0] infotexts.insert(0, text) if opts.enable_pnginfo: - grid.info["parameters"] = text + grid.info["parameters"] = text # type: ignore images.insert(0, grid) if opts.grid_save: @@ -239,8 +239,8 @@ class FaceSwapScript(scripts.Script): grid, p.outpath_grids, "swapped-grid", - p.all_seeds[0], - p.all_prompts[0], + p.all_seeds[0], # type: ignore + p.all_prompts[0], # type: ignore opts.grid_format, info=text, short_filename=not opts.grid_extended_filename, diff --git a/scripts/faceswaplab_globals.py b/scripts/faceswaplab_globals.py index 7fa0b08..7d50774 100644 --- a/scripts/faceswaplab_globals.py +++ b/scripts/faceswaplab_globals.py @@ -1,18 +1,27 @@ import os from modules import scripts +from modules.shared import opts +# Defining the absolute path for the 'faceswaplab' directory inside 'models' directory MODELS_DIR = os.path.abspath(os.path.join("models", "faceswaplab")) +# Defining the absolute path for the 'analysers' directory inside 'MODELS_DIR' ANALYZER_DIR = os.path.abspath(os.path.join(MODELS_DIR, "analysers")) +# Defining the absolute path for the 'parser' directory inside 'MODELS_DIR' FACE_PARSER_DIR = os.path.abspath(os.path.join(MODELS_DIR, "parser")) +# Defining the absolute path for the 'faces' directory inside 'MODELS_DIR' FACES_DIR = os.path.abspath(os.path.join(MODELS_DIR, "faces")) +# Constructing the path for 'references' directory inside the 'extensions' and 'sd-webui-faceswaplab' directories, based on the base directory of scripts REFERENCE_PATH = os.path.join( scripts.basedir(), "extensions", "sd-webui-faceswaplab", "references" ) -VERSION_FLAG: str = "v1.2.1" +# Defining the version flag for the application +VERSION_FLAG: str = "v1.2.2" +# Defining the path for 'sd-webui-faceswaplab' inside the 'extensions' directory EXTENSION_PATH = os.path.join("extensions", "sd-webui-faceswaplab") -# The NSFW score threshold. If any part of the image has a score greater than this threshold, the image will be considered NSFW. -NSFW_SCORE_THRESHOLD: float = 0.7 +# Defining the NSFW score threshold. Any image part with a score above this value will be treated as NSFW (Not Safe For Work) +NSFW_SCORE_THRESHOLD: float = opts.data.get("faceswaplab_nsfw_threshold", 0.7) # type: ignore +# Defining the expected SHA1 hash value for 'INSWAPPER' EXPECTED_INSWAPPER_SHA1 = "17a64851eaefd55ea597ee41e5c18409754244c5" diff --git a/scripts/faceswaplab_settings/faceswaplab_settings.py b/scripts/faceswaplab_settings/faceswaplab_settings.py index 289ee25..5183869 100644 --- a/scripts/faceswaplab_settings/faceswaplab_settings.py +++ b/scripts/faceswaplab_settings/faceswaplab_settings.py @@ -1,11 +1,11 @@ -from scripts.faceswaplab_utils.models_utils import get_models +from scripts.faceswaplab_utils.models_utils import get_swap_models from modules import script_callbacks, shared import gradio as gr def on_ui_settings() -> None: section = ("faceswaplab", "FaceSwapLab") - models = get_models() + models = get_swap_models() shared.opts.add_option( "faceswaplab_model", shared.OptionInfo( diff --git a/scripts/faceswaplab_swapping/swapper.py b/scripts/faceswaplab_swapping/swapper.py index 168ba7e..146cd6b 100644 --- a/scripts/faceswaplab_swapping/swapper.py +++ b/scripts/faceswaplab_swapping/swapper.py @@ -33,7 +33,7 @@ from scripts.faceswaplab_postprocessing.postprocessing import enhance_image from scripts.faceswaplab_postprocessing.postprocessing_options import ( PostProcessingOptions, ) -from scripts.faceswaplab_utils.models_utils import get_current_model +from scripts.faceswaplab_utils.models_utils import get_current_swap_model from scripts.faceswaplab_utils.typing import CV2ImgU8, PILImage, Face from scripts.faceswaplab_inpainting.i2i_pp import img2img_diffusion from modules import shared @@ -51,7 +51,7 @@ def use_gpu() -> bool: def force_install_gpu_providers() -> None: # Ugly Ugly hack due to SDNEXT : try: - from scripts.configure import check_install + from scripts.faceswaplab_utils.install_utils import check_install logger.warning("Try to reinstall gpu dependencies") check_install() @@ -180,7 +180,7 @@ def batch_process( current_images = [] swapped_images = process_images_units( - get_current_model(), images=[(src_image, None)], units=units + get_current_swap_model(), images=[(src_image, None)], units=units ) if len(swapped_images) > 0: current_images += [img for img, _ in swapped_images] diff --git a/scripts/faceswaplab_ui/faceswaplab_tab.py b/scripts/faceswaplab_ui/faceswaplab_tab.py index 8b99545..6415a36 100644 --- a/scripts/faceswaplab_ui/faceswaplab_tab.py +++ b/scripts/faceswaplab_ui/faceswaplab_tab.py @@ -17,7 +17,7 @@ from scripts.faceswaplab_ui.faceswaplab_unit_settings import FaceSwapUnitSetting from scripts.faceswaplab_ui.faceswaplab_unit_ui import faceswap_unit_ui from scripts.faceswaplab_utils import face_checkpoints_utils, imgutils from scripts.faceswaplab_utils.faceswaplab_logging import logger -from scripts.faceswaplab_utils.models_utils import get_models +from scripts.faceswaplab_utils.models_utils import get_swap_models from scripts.faceswaplab_utils.ui_utils import dataclasses_from_flat_list @@ -232,7 +232,7 @@ def batch_process( def tools_ui() -> None: - models = get_models() + models = get_swap_models() with gr.Tab("Tools"): with gr.Tab("Build"): gr.Markdown( diff --git a/scripts/faceswaplab_utils/face_checkpoints_utils.py b/scripts/faceswaplab_utils/face_checkpoints_utils.py index bf652f1..280359e 100644 --- a/scripts/faceswaplab_utils/face_checkpoints_utils.py +++ b/scripts/faceswaplab_utils/face_checkpoints_utils.py @@ -11,7 +11,7 @@ from scripts.faceswaplab_swapping.upcaled_inswapper_options import InswappperOpt from scripts.faceswaplab_utils.faceswaplab_logging import logger from scripts.faceswaplab_utils.typing import * from scripts.faceswaplab_utils import imgutils -from scripts.faceswaplab_utils.models_utils import get_models +from scripts.faceswaplab_utils.models_utils import get_swap_models import traceback import dill as pickle # will be removed in future versions @@ -90,7 +90,7 @@ def build_face_checkpoint_and_save( target_faces=[target_face], source_face=blended_face, target_img=reference_preview_img, - model=get_models()[0], + model=get_swap_models()[0], swapping_options=InswappperOptions(face_restorer_name="Codeformer"), ) preview_image = result.image diff --git a/scripts/faceswaplab_utils/install_utils.py b/scripts/faceswaplab_utils/install_utils.py new file mode 100644 index 0000000..5cd7bf0 --- /dev/null +++ b/scripts/faceswaplab_utils/install_utils.py @@ -0,0 +1,18 @@ +from types import ModuleType + + +def check_install() -> None: + # Very ugly hack :( due to sdnext optimization not calling install.py every time if git log has not changed + import importlib.util + import sys + import os + + current_dir = os.path.dirname(os.path.realpath(__file__)) + check_install_path = os.path.join(current_dir, "..", "..", "install.py") + spec = importlib.util.spec_from_file_location("check_install", check_install_path) + if spec != None: + check_install: ModuleType = importlib.util.module_from_spec(spec) + sys.modules["check_install"] = check_install + spec.loader.exec_module(check_install) # type: ignore + check_install.check_install() # type: ignore + #### End of ugly hack :( ! diff --git a/scripts/faceswaplab_utils/models_utils.py b/scripts/faceswaplab_utils/models_utils.py index 6bde15e..e235dec 100644 --- a/scripts/faceswaplab_utils/models_utils.py +++ b/scripts/faceswaplab_utils/models_utils.py @@ -3,12 +3,47 @@ import os from typing import List import modules.scripts as scripts from modules import scripts -from scripts.faceswaplab_globals import EXTENSION_PATH +from scripts.faceswaplab_globals import EXPECTED_INSWAPPER_SHA1, EXTENSION_PATH from modules.shared import opts from scripts.faceswaplab_utils.faceswaplab_logging import logger +import traceback +import hashlib -def get_models() -> List[str]: +def is_sha1_matching(file_path: str, expected_sha1: str) -> bool: + sha1_hash = hashlib.sha1(usedforsecurity=False) + try: + with open(file_path, "rb") as file: + for byte_block in iter(lambda: file.read(4096), b""): + sha1_hash.update(byte_block) + if sha1_hash.hexdigest() == expected_sha1: + return True + else: + return False + except Exception as e: + logger.error( + "Failed to check model hash, check the model is valid or has been downloaded adequately : %e", + e, + ) + traceback.print_exc() + return False + + +def check_model() -> bool: + model_path = get_current_swap_model() + if not is_sha1_matching( + file_path=model_path, expected_sha1=EXPECTED_INSWAPPER_SHA1 + ): + logger.error( + "Suspicious sha1 for model %s, check the model is valid or has been downloaded adequately. Should be %s", + model_path, + EXPECTED_INSWAPPER_SHA1, + ) + return False + return True + + +def get_swap_models() -> List[str]: """ Retrieve a list of swap model files. @@ -31,13 +66,13 @@ def get_models() -> List[str]: return models -def get_current_model() -> str: - model = opts.data.get("faceswaplab_model", None) +def get_current_swap_model() -> str: + model = opts.data.get("faceswaplab_model", None) # type: ignore if model is None: - models = get_models() + models = get_swap_models() model = models[0] if len(models) else None logger.info("Try to use model : %s", model) - if not os.path.isfile(model): + if not os.path.isfile(model): # type: ignore logger.error("The model %s cannot be found or loaded", model) raise FileNotFoundError( "No faceswap model found. Please add it to the faceswaplab directory."