Fall back from Transformers to llama.cpp
Browse files- README.md +2 -1
- RUNBOOK.md +1 -1
- src/extraction/auto.py +20 -1
- src/extraction/zerogpu_transformers.py +32 -26
README.md
CHANGED
|
@@ -51,7 +51,8 @@ This is the active deployment path.
|
|
| 51 |
|
| 52 |
With `EXTRACTOR_BACKEND=auto`, the app checks CUDA availability at runtime. If CUDA is visible, it
|
| 53 |
uses the official OpenBMB MiniCPM-V 4.6 Transformers path. If CUDA is not visible, it falls back to
|
| 54 |
-
the CPU `llama.cpp` GGUF path.
|
|
|
|
| 55 |
in normal Gradio/Python code.
|
| 56 |
|
| 57 |
This workflow should not be further changed back to Docker unless the project intentionally gives up
|
|
|
|
| 51 |
|
| 52 |
With `EXTRACTOR_BACKEND=auto`, the app checks CUDA availability at runtime. If CUDA is visible, it
|
| 53 |
uses the official OpenBMB MiniCPM-V 4.6 Transformers path. If CUDA is not visible, it falls back to
|
| 54 |
+
the CPU `llama.cpp` GGUF path. If the CUDA worker fails, `auto` retries with CPU llama.cpp unless
|
| 55 |
+
`AUTO_FALLBACK_TO_LLAMACPP=0`. The deterministic knowledge-graph enrichment and UI rendering stay
|
| 56 |
in normal Gradio/Python code.
|
| 57 |
|
| 58 |
This workflow should not be further changed back to Docker unless the project intentionally gives up
|
RUNBOOK.md
CHANGED
|
@@ -24,7 +24,7 @@ Do not switch the Space back to Docker unless the project intentionally gives up
|
|
| 24 |
|
| 25 |
`EXTRACTOR_BACKEND`:
|
| 26 |
|
| 27 |
-
- `auto`: uses the Transformers backend when `torch.cuda.is_available()` is true; otherwise uses the CPU llama.cpp backend.
|
| 28 |
- `llamacpp-gpu`: force the GGUF llama.cpp backend.
|
| 29 |
- `zerogpu` / `transformers`: force the OpenBMB Transformers backend.
|
| 30 |
- `api`: hosted OpenBMB endpoint for development fallback only.
|
|
|
|
| 24 |
|
| 25 |
`EXTRACTOR_BACKEND`:
|
| 26 |
|
| 27 |
+
- `auto`: uses the Transformers backend when `torch.cuda.is_available()` is true; otherwise uses the CPU llama.cpp backend. If the Transformers worker fails, it retries with CPU llama.cpp unless `AUTO_FALLBACK_TO_LLAMACPP=0`.
|
| 28 |
- `llamacpp-gpu`: force the GGUF llama.cpp backend.
|
| 29 |
- `zerogpu` / `transformers`: force the OpenBMB Transformers backend.
|
| 30 |
- `api`: hosted OpenBMB endpoint for development fallback only.
|
src/extraction/auto.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
|
|
|
|
|
|
| 5 |
from src.extraction.base import Extractor
|
| 6 |
from src.extraction.llamacpp_gpu import LlamaCppGPUExtractor
|
| 7 |
from src.extraction.zerogpu_transformers import ZeroGPUTransformersExtractor
|
|
@@ -15,7 +17,20 @@ class AutoExtractor:
|
|
| 15 |
self._selected: Extractor | None = None
|
| 16 |
|
| 17 |
def extract(self, file_path: str, max_pages: int = 3):
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
def _backend(self) -> Extractor:
|
| 21 |
if self._selected is None:
|
|
@@ -32,6 +47,10 @@ def cuda_available() -> bool:
|
|
| 32 |
except Exception:
|
| 33 |
return False
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
try:
|
| 36 |
return bool(torch.cuda.is_available())
|
| 37 |
except Exception:
|
|
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
from src.extraction.base import Extractor
|
| 8 |
from src.extraction.llamacpp_gpu import LlamaCppGPUExtractor
|
| 9 |
from src.extraction.zerogpu_transformers import ZeroGPUTransformersExtractor
|
|
|
|
| 17 |
self._selected: Extractor | None = None
|
| 18 |
|
| 19 |
def extract(self, file_path: str, max_pages: int = 3):
|
| 20 |
+
backend = self._backend()
|
| 21 |
+
try:
|
| 22 |
+
return backend.extract(file_path, max_pages=max_pages)
|
| 23 |
+
except Exception as exc:
|
| 24 |
+
if not isinstance(backend, ZeroGPUTransformersExtractor) or not _fallback_enabled():
|
| 25 |
+
raise
|
| 26 |
+
|
| 27 |
+
print(
|
| 28 |
+
"[Blood Test Explainer] CUDA Transformers backend failed; "
|
| 29 |
+
f"falling back to CPU llama.cpp. Inner error: {type(exc).__name__}: {exc}",
|
| 30 |
+
flush=True,
|
| 31 |
+
)
|
| 32 |
+
self._selected = LlamaCppGPUExtractor()
|
| 33 |
+
return self._selected.extract(file_path, max_pages=max_pages)
|
| 34 |
|
| 35 |
def _backend(self) -> Extractor:
|
| 36 |
if self._selected is None:
|
|
|
|
| 47 |
except Exception:
|
| 48 |
return False
|
| 49 |
|
| 50 |
+
|
| 51 |
+
def _fallback_enabled() -> bool:
|
| 52 |
+
return os.getenv("AUTO_FALLBACK_TO_LLAMACPP", "1").strip().lower() not in {"0", "false", "no"}
|
| 53 |
+
|
| 54 |
try:
|
| 55 |
return bool(torch.cuda.is_available())
|
| 56 |
except Exception:
|
src/extraction/zerogpu_transformers.py
CHANGED
|
@@ -143,31 +143,37 @@ def _run_zerogpu_generation(
|
|
| 143 |
) -> str:
|
| 144 |
import torch
|
| 145 |
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
max_slice_nums=9,
|
| 155 |
-
).to(model.device)
|
| 156 |
-
|
| 157 |
-
with torch.inference_mode():
|
| 158 |
-
generated_ids = model.generate(
|
| 159 |
-
**inputs,
|
| 160 |
downsample_mode=downsample_mode,
|
| 161 |
-
|
| 162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
)
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
skip_special_tokens=True,
|
| 171 |
-
clean_up_tokenization_spaces=False,
|
| 172 |
-
)
|
| 173 |
-
return str(output_text[0]).strip() if output_text else ""
|
|
|
|
| 143 |
) -> str:
|
| 144 |
import torch
|
| 145 |
|
| 146 |
+
try:
|
| 147 |
+
processor, model = _get_model(model_id)
|
| 148 |
+
inputs = processor.apply_chat_template(
|
| 149 |
+
messages,
|
| 150 |
+
tokenize=True,
|
| 151 |
+
add_generation_prompt=True,
|
| 152 |
+
return_dict=True,
|
| 153 |
+
return_tensors="pt",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
downsample_mode=downsample_mode,
|
| 155 |
+
max_slice_nums=9,
|
| 156 |
+
).to(model.device)
|
| 157 |
+
|
| 158 |
+
with torch.inference_mode():
|
| 159 |
+
generated_ids = model.generate(
|
| 160 |
+
**inputs,
|
| 161 |
+
downsample_mode=downsample_mode,
|
| 162 |
+
max_new_tokens=max_new_tokens,
|
| 163 |
+
do_sample=False,
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
generated_ids_trimmed = [
|
| 167 |
+
out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, generated_ids, strict=False)
|
| 168 |
+
]
|
| 169 |
+
output_text = processor.batch_decode(
|
| 170 |
+
generated_ids_trimmed,
|
| 171 |
+
skip_special_tokens=True,
|
| 172 |
+
clean_up_tokenization_spaces=False,
|
| 173 |
)
|
| 174 |
+
return str(output_text[0]).strip() if output_text else ""
|
| 175 |
+
except Exception as exc:
|
| 176 |
+
raise RuntimeError(
|
| 177 |
+
"OpenBMB Transformers generation failed on the CUDA/ZeroGPU lane. "
|
| 178 |
+
f"Inner error: {type(exc).__name__}: {exc}"
|
| 179 |
+
) from exc
|
|
|
|
|
|
|
|
|
|
|
|