diff --git a/facefusion/execution.py b/facefusion/execution.py index 6a1d2283..061866e9 100644 --- a/facefusion/execution.py +++ b/facefusion/execution.py @@ -3,7 +3,7 @@ import shutil import subprocess import xml.etree.ElementTree as ElementTree from functools import lru_cache -from typing import List, Optional +from typing import List, Optional, Tuple import onnxruntime @@ -18,6 +18,16 @@ def has_execution_provider(execution_provider : ExecutionProvider) -> bool: return execution_provider in get_available_execution_providers() +@lru_cache() +def get_onnxruntime_version() -> Tuple[int, int, int]: + version_split = onnxruntime.__version__.split('.') + major_version = int(version_split[0]) + minor_version = int(version_split[1]) + patch_version = int(version_split[2].split('+')[0]) + + return major_version, minor_version, patch_version + + def get_available_execution_providers() -> List[ExecutionProvider]: inference_session_providers = onnxruntime.get_available_providers() available_execution_providers : List[ExecutionProvider] = [] diff --git a/facefusion/inference_manager.py b/facefusion/inference_manager.py index aed662f3..ff5bbb03 100644 --- a/facefusion/inference_manager.py +++ b/facefusion/inference_manager.py @@ -9,7 +9,7 @@ from onnxruntime import InferenceSession from facefusion import logger, process_manager, state_manager, translator from facefusion.app_context import detect_app_context from facefusion.common_helper import is_windows -from facefusion.execution import create_inference_providers, has_execution_provider +from facefusion.execution import create_inference_providers, get_onnxruntime_version, has_execution_provider from facefusion.exit_helper import fatal_exit from facefusion.filesystem import get_file_name, is_file from facefusion.time_helper import calculate_end_time @@ -25,17 +25,21 @@ INFERENCE_POOL_SET : InferencePoolSet =\ def get_inference_pool(module_name : str, model_names : List[str], model_source_set : DownloadSet) -> InferencePool: while process_manager.is_checking(): sleep(0.5) + execution_device_ids = state_manager.get_item('execution_device_ids') execution_providers = state_manager.get_item('execution_providers') + has_arena_leak = has_execution_provider('cuda') and get_onnxruntime_version() > (1, 24, 4) app_context = detect_app_context() for execution_device_id in execution_device_ids: inference_context = get_inference_context(module_name, model_names, execution_device_id, execution_providers) - if app_context == 'cli' and INFERENCE_POOL_SET.get('ui').get(inference_context): - INFERENCE_POOL_SET['cli'][inference_context] = INFERENCE_POOL_SET.get('ui').get(inference_context) - if app_context == 'ui' and INFERENCE_POOL_SET.get('cli').get(inference_context): - INFERENCE_POOL_SET['ui'][inference_context] = INFERENCE_POOL_SET.get('cli').get(inference_context) + if not has_arena_leak: + if app_context == 'cli' and INFERENCE_POOL_SET.get('ui').get(inference_context): + INFERENCE_POOL_SET['cli'][inference_context] = INFERENCE_POOL_SET.get('ui').get(inference_context) + if app_context == 'ui' and INFERENCE_POOL_SET.get('cli').get(inference_context): + INFERENCE_POOL_SET['ui'][inference_context] = INFERENCE_POOL_SET.get('cli').get(inference_context) + if not INFERENCE_POOL_SET.get(app_context).get(inference_context): inference_providers = resolve_static_inference_providers(module_name, execution_device_id) INFERENCE_POOL_SET[app_context][inference_context] = create_inference_pool(model_source_set, inference_providers) @@ -49,6 +53,7 @@ def create_inference_pool(model_source_set : DownloadSet, inference_providers : for model_name in model_source_set.keys(): model_path = model_source_set.get(model_name).get('path') + if is_file(model_path): inference_pool[model_name] = create_inference_session(model_path, inference_providers) @@ -65,6 +70,7 @@ def clear_inference_pool(module_name : str, model_names : List[str]) -> None: for execution_device_id in execution_device_ids: inference_context = get_inference_context(module_name, model_names, execution_device_id, execution_providers) + if INFERENCE_POOL_SET.get(app_context).get(inference_context): del INFERENCE_POOL_SET[app_context][inference_context] diff --git a/facefusion/installer.py b/facefusion/installer.py index 10045254..36f39fb5 100644 --- a/facefusion/installer.py +++ b/facefusion/installer.py @@ -19,16 +19,17 @@ LOCALES =\ } ONNXRUNTIME_SET =\ { - 'default': ('onnxruntime', '1.26.0') + 'default': ('onnxruntime', '1.28.0') } if is_windows() or is_linux(): - ONNXRUNTIME_SET['cuda'] = ('onnxruntime-gpu', '1.26.0') + ONNXRUNTIME_SET['cuda@12'] = ('onnxruntime-gpu', '1.24.4') + ONNXRUNTIME_SET['cuda@13'] = ('onnxruntime-gpu', '1.28.0') ONNXRUNTIME_SET['openvino'] = ('onnxruntime-openvino', '1.24.1') if is_windows(): ONNXRUNTIME_SET['directml'] = ('onnxruntime-directml', '1.24.4') - ONNXRUNTIME_SET['qnn'] = ('onnxruntime-qnn', '1.24.4') + ONNXRUNTIME_SET['qnn'] = ('onnxruntime-qnn', '2.4.0') if is_linux(): - ONNXRUNTIME_SET['migraphx'] = ('onnxruntime-migraphx', '1.26.0') + ONNXRUNTIME_SET['migraphx'] = ('onnxruntime-migraphx', '1.27.1') ONNXRUNTIME_SET['rocm'] = ('onnxruntime-rocm', '1.22.2.post3') @@ -54,6 +55,9 @@ def run(program : ArgumentParser) -> None: sys.stdout.write(LOCALES.get('conda_not_activated') + os.linesep) sys.exit(1) + for onnxruntime_package, _ in ONNXRUNTIME_SET.values(): + subprocess.call([ shutil.which('pip'), 'uninstall', onnxruntime_package, '-y', '-q' ], stderr = subprocess.DEVNULL) + commands = [ shutil.which('pip'), 'install' ] if args.force_reinstall: @@ -63,12 +67,10 @@ def run(program : ArgumentParser) -> None: for line in file.readlines(): __line__ = line.strip() + if not __line__.startswith('onnxruntime'): commands.append(__line__) onnxruntime_name, onnxruntime_version = ONNXRUNTIME_SET.get(args.onnxruntime) commands.append(onnxruntime_name + '==' + onnxruntime_version) - - subprocess.call([ shutil.which('pip'), 'uninstall', 'onnxruntime', onnxruntime_name, '-y', '-q' ]) - subprocess.call(commands) diff --git a/facefusion/metadata.py b/facefusion/metadata.py index fd9083dc..24a1db62 100644 --- a/facefusion/metadata.py +++ b/facefusion/metadata.py @@ -4,7 +4,7 @@ METADATA =\ { 'name': 'FaceFusion', 'description': 'Industry leading face manipulation platform', - 'version': '3.8.0', + 'version': '3.8.1', 'license': 'OpenRAIL-AS', 'author': 'Henry Ruhs', 'url': 'https://facefusion.io' diff --git a/facefusion/processors/modules/face_swapper/core.py b/facefusion/processors/modules/face_swapper/core.py index 8f4954fd..da1736b2 100755 --- a/facefusion/processors/modules/face_swapper/core.py +++ b/facefusion/processors/modules/face_swapper/core.py @@ -504,17 +504,17 @@ def clear_inference_pool() -> None: def adjust_inference_providers() -> List[InferenceProvider]: model_precision = get_model_options().get('precision') - model_type = get_model_options().get('type') + workflow_mode = state_manager.get_item('workflow_mode') - if is_macos() and has_execution_provider('coreml'): - if model_type in [ 'ghost', 'uniface' ] or model_precision == 'fp16': - return\ - [ - (facefusion.choices.execution_provider_set.get('coreml'), - { - 'ModelFormat': 'MLProgram' - }) - ] + if is_macos() and has_execution_provider('coreml') and model_precision == 'fp16' and workflow_mode == 'image-to-video': + return\ + [ + (facefusion.choices.execution_provider_set.get('coreml'), + { + 'ModelFormat': 'MLProgram', + 'MLComputeUnits': 'CPUAndGPU' + }) + ] return [] diff --git a/requirements.txt b/requirements.txt index 860cc2e0..e8bc2da7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ gradio-rangeslider==0.0.8 gradio==5.50.0 numpy==2.4.6 onnx==1.22.0 -onnxruntime==1.26.0 +onnxruntime==1.28.0 opencv-python-headless==5.0.0.93 tqdm==4.70.0 scipy==1.18.0 diff --git a/tests/test_cli_job_manager.py b/tests/test_cli_job_manager.py index 6030b898..4383f210 100644 --- a/tests/test_cli_job_manager.py +++ b/tests/test_cli_job_manager.py @@ -36,9 +36,21 @@ def before_each() -> None: init_jobs(get_test_jobs_directory()) -@pytest.mark.skip() def test_job_list() -> None: - pass + commands = [ sys.executable, 'facefusion.py', 'job-list', 'drafted', '--jobs-path', get_test_jobs_directory() ] + + assert subprocess.run(commands).returncode == 1 + + commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-list', '--jobs-path', get_test_jobs_directory() ] + subprocess.run(commands) + + commands = [ sys.executable, 'facefusion.py', 'job-list', 'drafted', '--jobs-path', get_test_jobs_directory() ] + + assert subprocess.run(commands).returncode == 0 + + commands = [ sys.executable, 'facefusion.py', 'job-list', 'queued', '--jobs-path', get_test_jobs_directory() ] + + assert subprocess.run(commands).returncode == 1 def test_job_create() -> None: diff --git a/tests/test_inference_manager.py b/tests/test_inference_manager.py index 047093cf..611bc625 100644 --- a/tests/test_inference_manager.py +++ b/tests/test_inference_manager.py @@ -6,7 +6,7 @@ from onnxruntime import InferenceSession from facefusion import content_analyser, state_manager from facefusion.execution import resolve_cache_path -from facefusion.inference_manager import INFERENCE_POOL_SET, get_inference_pool, resolve_static_inference_providers +from facefusion.inference_manager import get_inference_pool, resolve_static_inference_providers @pytest.fixture(scope = 'module', autouse = True) @@ -20,17 +20,29 @@ def test_get_inference_pool() -> None: model_names = [ 'nsfw_1', 'nsfw_2', 'nsfw_3' ] _, model_source_set = content_analyser.collect_model_downloads() - with patch('facefusion.inference_manager.detect_app_context', return_value = 'cli'): - get_inference_pool('facefusion.content_analyser', model_names, model_source_set) + with patch('facefusion.inference_manager.has_execution_provider', return_value = True): + with patch('facefusion.inference_manager.get_onnxruntime_version', return_value = (1, 26, 0)): - assert isinstance(INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.nsfw_1.nsfw_2.nsfw_3.0.cpu').get('nsfw_1'), InferenceSession) + with patch('facefusion.inference_manager.detect_app_context', return_value = 'cli'): + cli_inference_pool = get_inference_pool('facefusion.content_analyser', model_names, model_source_set) - with patch('facefusion.inference_manager.detect_app_context', return_value = 'ui'): - get_inference_pool('facefusion.content_analyser', model_names, model_source_set) + assert isinstance(cli_inference_pool.get('nsfw_1'), InferenceSession) - assert isinstance(INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.nsfw_1.nsfw_2.nsfw_3.0.cpu').get('nsfw_1'), InferenceSession) + with patch('facefusion.inference_manager.detect_app_context', return_value = 'ui'): + ui_inference_pool = get_inference_pool('facefusion.content_analyser', model_names, model_source_set) - assert INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.nsfw_1.nsfw_2.nsfw_3.0.cpu').get('nsfw_1') == INFERENCE_POOL_SET.get('ui').get('facefusion.content_analyser.nsfw_1.nsfw_2.nsfw_3.0.cpu').get('nsfw_1') + assert isinstance(ui_inference_pool.get('nsfw_1'), InferenceSession) + + assert not (cli_inference_pool.get('nsfw_1') is ui_inference_pool.get('nsfw_1')) + + with patch('facefusion.inference_manager.get_onnxruntime_version', return_value = (1, 24, 4)): + + with patch('facefusion.inference_manager.detect_app_context', return_value = 'ui'): + ui_inference_pool = get_inference_pool('facefusion.content_analyser', model_names, model_source_set) + + assert isinstance(ui_inference_pool.get('nsfw_1'), InferenceSession) + + assert cli_inference_pool.get('nsfw_1') is ui_inference_pool.get('nsfw_1') @pytest.fixture @@ -48,9 +60,15 @@ def test_resolve_static_inference_providers(override_module : SimpleNamespace, a resolve_static_inference_providers.cache_clear() with patch('facefusion.inference_manager.importlib', Mock(import_module = Mock(return_value = override_module))): - assert resolve_static_inference_providers('override_module', 0) == [ ('CoreMLExecutionProvider', { 'ModelFormat': 'MLProgram' }) ] + inference_providers = resolve_static_inference_providers('override_module', 0) + + assert inference_providers == [ ('CoreMLExecutionProvider', { 'ModelFormat': 'MLProgram' }) ] with patch('facefusion.inference_manager.importlib', Mock(import_module = Mock(return_value = adjust_module))): - assert resolve_static_inference_providers('adjust_module', 0) == [ ('CoreMLExecutionProvider', { 'SpecializationStrategy': 'FastPrediction', 'ModelCacheDirectory': resolve_cache_path(), 'ModelFormat': 'MLProgram' }) ] + inference_providers = resolve_static_inference_providers('adjust_module', 0) - assert resolve_static_inference_providers('test', 0) == [ ('CoreMLExecutionProvider', { 'SpecializationStrategy': 'FastPrediction', 'ModelCacheDirectory': resolve_cache_path() }) ] + assert inference_providers == [ ('CoreMLExecutionProvider', { 'SpecializationStrategy': 'FastPrediction', 'ModelCacheDirectory': resolve_cache_path(), 'ModelFormat': 'MLProgram' }) ] + + inference_providers = resolve_static_inference_providers('test', 0) + + assert inference_providers == [ ('CoreMLExecutionProvider', { 'SpecializationStrategy': 'FastPrediction', 'ModelCacheDirectory': resolve_cache_path() }) ]