|
11 | 11 |
|
12 | 12 |
|
13 | 13 | # ── Safe FAISS import ──────────────────────────────────────────────────── |
14 | | -# faiss-cpu may fail with ModuleNotFoundError("No module named 'faiss.swigfaiss_avx2'") |
15 | | -# or "No module named 'faiss.swigfaiss_avx512'" when the AVX-optimized native |
16 | | -# module isn't available (e.g. older CPUs, some cloud VMs). |
17 | | -# Fall back to the non-AVX version gracefully. |
18 | | -try: |
19 | | - import faiss |
20 | | -except ModuleNotFoundError as _faiss_err: |
21 | | - _faiss_msg = str(_faiss_err) |
22 | | - if "swigfaiss_avx" in _faiss_msg: |
23 | | - import warnings |
24 | | - warnings.warn( |
25 | | - f"{_faiss_msg} — falling back to non-AVX faiss. " |
26 | | - "If you need AVX support, install a compatible faiss-cpu wheel.", |
27 | | - stacklevel=2, |
28 | | - ) |
29 | | - # Force faiss to use the fallback (non-AVX) implementation |
30 | | - try: |
31 | | - import faiss.loader as _faiss_loader |
32 | | - if hasattr(_faiss_loader, "toggle_swigfaiss_avx2"): |
33 | | - _faiss_loader.toggle_swigfaiss_avx2 = False |
34 | | - except Exception: |
35 | | - pass |
36 | | - # Clear cached failed import so faiss can retry |
37 | | - if "faiss" in sys.modules: |
38 | | - del sys.modules["faiss"] |
39 | | - # Set env var that tells faiss to skip AVX |
40 | | - os.environ["FAISS_NO_AVX2"] = "1" |
41 | | - import faiss |
42 | | - else: |
| 14 | +# faiss-cpu tries AVX512 → AVX2 → basic swigfaiss at import time. |
| 15 | +# When AVX native modules are missing it logs INFO messages and falls back, |
| 16 | +# but on some systems the ModuleNotFoundError propagates instead of being |
| 17 | +# caught internally. We handle both cases: |
| 18 | +# 1. Pre-disable AVX features via FAISS_DISABLE_CPU_FEATURES so faiss |
| 19 | +# never attempts the AVX path (avoids noisy INFO logs). |
| 20 | +# 2. If import still fails with a swigfaiss_avx* error, force the basic |
| 21 | +# loader and retry. |
| 22 | +def _import_faiss(): |
| 23 | + """Import faiss with safe AVX fallback.""" |
| 24 | + # If faiss is already loaded, return it |
| 25 | + if "faiss" in sys.modules: |
| 26 | + return sys.modules["faiss"] |
| 27 | + |
| 28 | + # First try: disable AVX features so faiss skips straight to basic |
| 29 | + _prev = os.environ.get("FAISS_DISABLE_CPU_FEATURES", "") |
| 30 | + os.environ["FAISS_DISABLE_CPU_FEATURES"] = "AVX512, AVX2, AVX512_SPR, SVE" |
| 31 | + try: |
| 32 | + import faiss as _faiss |
| 33 | + return _faiss |
| 34 | + except ModuleNotFoundError: |
| 35 | + pass |
| 36 | + finally: |
| 37 | + if _prev: |
| 38 | + os.environ["FAISS_DISABLE_CPU_FEATURES"] = _prev |
| 39 | + else: |
| 40 | + os.environ.pop("FAISS_DISABLE_CPU_FEATURES", None) |
| 41 | + |
| 42 | + # Second try: clear any partial import and retry with env set |
| 43 | + for _mod in list(sys.modules.keys()): |
| 44 | + if _mod.startswith("faiss"): |
| 45 | + del sys.modules[_mod] |
| 46 | + os.environ["FAISS_DISABLE_CPU_FEATURES"] = "AVX512, AVX2, AVX512_SPR, SVE" |
| 47 | + try: |
| 48 | + import faiss as _faiss |
| 49 | + return _faiss |
| 50 | + except ModuleNotFoundError as _faiss_err: |
| 51 | + _faiss_msg = str(_faiss_err) |
| 52 | + if "swigfaiss" in _faiss_msg: |
| 53 | + import warnings |
| 54 | + warnings.warn( |
| 55 | + f"{_faiss_msg} — faiss AVX modules unavailable. " |
| 56 | + "Install a compatible faiss-cpu wheel or set FAISS_OPT_LEVEL.", |
| 57 | + stacklevel=3, |
| 58 | + ) |
| 59 | + # Last resort: try to force the basic loader |
| 60 | + for _mod in list(sys.modules.keys()): |
| 61 | + if _mod.startswith("faiss"): |
| 62 | + del sys.modules[_mod] |
| 63 | + os.environ["FAISS_OPT_LEVEL"] = "" |
| 64 | + import faiss as _faiss |
| 65 | + return _faiss |
43 | 66 | raise |
44 | 67 |
|
| 68 | +faiss = _import_faiss() |
| 69 | + |
45 | 70 |
|
46 | 71 | from arvc.utils import huggingface |
47 | 72 | from arvc.utils.variables import translations, configs, config, logger, embedders_model, spin_model, whisper_model |
|
0 commit comments