From e5c6b74b40bc1b29493fe802406daacb70f37d09 Mon Sep 17 00:00:00 2001 From: xadupre Date: Mon, 8 Sep 2025 14:18:12 +0200 Subject: [PATCH 1/2] switch to 4.56.1 and other changes --- .github/workflows/ci.yml | 6 +- _unittests/ut_tasks/try_tasks.py | 36 +++ onnx_diagnostic/helpers/helper.py | 8 + onnx_diagnostic/helpers/torch_helper.py | 14 +- .../torch_models/hghub/hub_data.py | 2 + .../torch_models/hghub/model_inputs.py | 263 +++++++++--------- .../torch_models/hghub/model_specific.py | 49 ++++ 7 files changed, 248 insertions(+), 130 deletions(-) create mode 100644 onnx_diagnostic/torch_models/hghub/model_specific.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26aea477..19a50d73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: matrix: os: [ubuntu-latest] python: ['3.10', '3.11', '3.12', '3.13'] - transformers: ['4.48.3', '4.51.3', '4.52.4', '4.53.3', '4.55.4', '4.56.0', 'main'] + transformers: ['4.48.3', '4.51.3', '4.52.4', '4.53.3', '4.55.4', '4.56.1', 'main'] torch: ['2.8', 'main'] exclude: - python: '3.10' @@ -30,7 +30,7 @@ jobs: - python: '3.10' transformers: '4.55.4' - python: '3.10' - transformers: '4.56.0' + transformers: '4.56.1' - python: '3.11' torch: 'main' - python: '3.11' @@ -40,7 +40,7 @@ jobs: - python: '3.11' transformers: '4.55.4' - python: '3.11' - transformers: '4.56.0' + transformers: '4.56.1' - python: '3.13' torch: '2.8' - python: '3.13' diff --git a/_unittests/ut_tasks/try_tasks.py b/_unittests/ut_tasks/try_tasks.py index 91f7e3b7..f291633a 100644 --- a/_unittests/ut_tasks/try_tasks.py +++ b/_unittests/ut_tasks/try_tasks.py @@ -755,6 +755,42 @@ def test_imagetext2text_generation_zai_glm(self): ) print(output_text) + @never_test() + def test_sentence_similary_alibaba_nlp_gte(self): + """ + clear&&NEVERTEST=1 python _unittests/ut_tasks/try_tasks.py -k alibaba + """ + import torch.nn.functional as F + from transformers import AutoModel, AutoTokenizer + + input_texts = [ + "what is the capital of China?", + "how to implement quick sort in python?", + "Beijing", + "sorting algorithms", + ] + + model_path = "Alibaba-NLP/gte-large-en-v1.5" + tokenizer = AutoTokenizer.from_pretrained(model_path) + model = AutoModel.from_pretrained(model_path, trust_remote_code=True) + + # Tokenize the input texts + batch_dict = tokenizer( + input_texts, max_length=8192, padding=True, truncation=True, return_tensors="pt" + ) + + print("-- type:", type(model)) + print("-- subclasses:", type(model).__subclasses__()) + print("-- inputs:", self.string_type(batch_dict, with_shape=True)) + outputs = model(**batch_dict) + print("-- outputs:", self.string_type(outputs, with_shape=True)) + embeddings = outputs.last_hidden_state[:, 0] + + # (Optionally) normalize embeddings + embeddings = F.normalize(embeddings, p=2, dim=1) + scores = (embeddings[:1] @ embeddings[1:].T) * 100 + print(scores.tolist()) + if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/onnx_diagnostic/helpers/helper.py b/onnx_diagnostic/helpers/helper.py index ebd631a4..7879a1fd 100644 --- a/onnx_diagnostic/helpers/helper.py +++ b/onnx_diagnostic/helpers/helper.py @@ -774,6 +774,14 @@ def string_type( return f"{obj.__class__.__name__}(**{s})" if obj.__class__.__name__ in {"TorchModelContainer", "InferenceSession"}: return f"{obj.__class__.__name__}(...)" + if obj.__class__.__name__ == "Results": + import ultralytics + + assert isinstance( + obj, ultralytics.engine.results.Results + ), f"Unexpected type={type(obj)}" + return f"ultralytics.{obj.__class__.__name__}(...)" + if verbose: print(f"[string_type] END:{type(obj)}") raise AssertionError(f"Unsupported type {type(obj).__name__!r} - {type(obj)}") diff --git a/onnx_diagnostic/helpers/torch_helper.py b/onnx_diagnostic/helpers/torch_helper.py index 2b747ccc..a2416edb 100644 --- a/onnx_diagnostic/helpers/torch_helper.py +++ b/onnx_diagnostic/helpers/torch_helper.py @@ -721,9 +721,10 @@ def to_any(value: Any, to_value: Union[torch.dtype, torch.device, str]) -> Any: return {to_any(t, to_value) for t in value} if type(value) is dict: return {k: to_any(t, to_value) for k, t in value.items()} - if value.__class__.__name__ == "DynamicCache": + if value.__class__.__name__ in {"DynamicCache", "HybridCache"}: + make = dict(DynamicCache=make_dynamic_cache, HybridCache=make_hybrid_cache) cc = CacheKeyValue(value) - return make_dynamic_cache( + return make[value.__class__.__name__]( list( zip( [t.to(to_value) if t is not None else t for t in cc.key_cache], @@ -822,6 +823,15 @@ def torch_deepcopy(value: Any) -> Any: new_args = torch_deepcopy(args) return torch.utils._pytree.tree_unflatten(new_args, spec) + if value.__class__.__name__ == "Results": + import copy + import ultralytics + + assert isinstance( + value, ultralytics.engine.results.Results + ), f"Unexpected type={type(value)}" + return copy.deepcopy(value) + # We should have a code using serialization, deserialization assuming a model # cannot be exported without them. raise NotImplementedError(f"torch_deepcopy not implemented for type {type(value)}") diff --git a/onnx_diagnostic/torch_models/hghub/hub_data.py b/onnx_diagnostic/torch_models/hghub/hub_data.py index 0b752ec1..1f29d832 100644 --- a/onnx_diagnostic/torch_models/hghub/hub_data.py +++ b/onnx_diagnostic/torch_models/hghub/hub_data.py @@ -11,6 +11,7 @@ """ architecture,task ASTModel,feature-extraction + AutoencoderKL,image-to-image AlbertModel,feature-extraction BeitForImageClassification,image-classification BartForConditionalGeneration,summarization @@ -154,6 +155,7 @@ Wav2Vec2ForCTC,automatic-speech-recognition YolosForObjectDetection,object-detection YolosModel,image-feature-extraction + Alibaba-NLP/gte-large-en-v1.5,sentence-similarity emilyalsentzer/Bio_ClinicalBERT,fill-mask""" ) diff --git a/onnx_diagnostic/torch_models/hghub/model_inputs.py b/onnx_diagnostic/torch_models/hghub/model_inputs.py index 96350892..ca6b7680 100644 --- a/onnx_diagnostic/torch_models/hghub/model_inputs.py +++ b/onnx_diagnostic/torch_models/hghub/model_inputs.py @@ -8,6 +8,7 @@ from ...helpers.config_helper import update_config, build_diff_config from ...tasks import reduce_model_config, random_input_kwargs from .hub_api import task_from_arch, task_from_id, get_pretrained_config, download_code_modelid +from .model_specific import HANDLED_MODELS, load_specific_model def _code_needing_rewriting(model: Any) -> Any: @@ -73,7 +74,7 @@ def get_untrained_model_with_inputs( print("-- configuration:", pprint.pformat(data['configuration'])) """ assert not use_preinstalled or not use_only_preinstalled, ( - f"model_id={model_id!r}, pretinstalled model is only available " + f"model_id={model_id!r}, preinstalled model is only available " f"if use_only_preinstalled is False." ) if verbose: @@ -89,142 +90,153 @@ def get_untrained_model_with_inputs( **(model_kwargs or {}), ) - if hasattr(config, "architecture") and config.architecture: - archs = [config.architecture] - if type(config) is dict: - assert "_class_name" in config, f"Unable to get the architecture from config={config}" - archs = [config["_class_name"]] - else: - archs = config.architectures # type: ignore - task = None - if archs is None: - task = task_from_id(model_id) - assert task is not None or (archs is not None and len(archs) == 1), ( - f"Unable to determine the architecture for model {model_id!r}, " - f"architectures={archs!r}, conf={config}" - ) - if verbose: - print(f"[get_untrained_model_with_inputs] architectures={archs!r}") - print(f"[get_untrained_model_with_inputs] cls={config.__class__.__name__!r}") - if task is None: - task = task_from_arch(archs[0], model_id=model_id, subfolder=subfolder) - if verbose: - print(f"[get_untrained_model_with_inputs] task={task!r}") + model, task, mkwargs, diff_config = None, None, {}, None + if use_pretrained and same_as_pretrained: + if model_id in HANDLED_MODELS: + model, task, config = load_specific_model(model_id, verbose=verbose) - # model kwagrs - if dynamic_rope is not None: - assert ( - type(config) is not dict - ), f"Unable to set dynamic_rope if the configuration is a dictionary\n{config}" - assert hasattr(config, "rope_scaling"), f"Missing 'rope_scaling' in\n{config}" - config.rope_scaling = ( - {"rope_type": "dynamic", "factor": 10.0} if dynamic_rope else None + if model is None: + if hasattr(config, "architecture") and config.architecture: + archs = [config.architecture] + if type(config) is dict: + assert ( + "_class_name" in config + ), f"Unable to get the architecture from config={config}" + archs = [config["_class_name"]] + else: + archs = config.architectures # type: ignore + task = None + if archs is None: + task = task_from_id(model_id) + assert task is not None or (archs is not None and len(archs) == 1), ( + f"Unable to determine the architecture for model {model_id!r}, " + f"architectures={archs!r}, conf={config}" ) + if verbose: + print(f"[get_untrained_model_with_inputs] architectures={archs!r}") + print(f"[get_untrained_model_with_inputs] cls={config.__class__.__name__!r}") + if task is None: + task = task_from_arch(archs[0], model_id=model_id, subfolder=subfolder) + if verbose: + print(f"[get_untrained_model_with_inputs] task={task!r}") + + # model kwagrs + if dynamic_rope is not None: + assert ( + type(config) is not dict + ), f"Unable to set dynamic_rope if the configuration is a dictionary\n{config}" + assert hasattr(config, "rope_scaling"), f"Missing 'rope_scaling' in\n{config}" + config.rope_scaling = ( + {"rope_type": "dynamic", "factor": 10.0} if dynamic_rope else None + ) - # updating the configuration - config0 = copy.deepcopy(config) - mkwargs = reduce_model_config(config, task) if not same_as_pretrained else {} - if model_kwargs: - for k, v in model_kwargs.items(): - if isinstance(v, dict): - if k in mkwargs: - mkwargs[k].update(v) + # updating the configuration + config0 = copy.deepcopy(config) + mkwargs = reduce_model_config(config, task) if not same_as_pretrained else {} + if model_kwargs: + for k, v in model_kwargs.items(): + if isinstance(v, dict): + if k in mkwargs: + mkwargs[k].update(v) + else: + mkwargs[k] = v else: mkwargs[k] = v - else: - mkwargs[k] = v - if mkwargs: - update_config(config, mkwargs) - try: - diff_config = build_diff_config(config0, config) - except (ValueError, AttributeError, TypeError) as e: - diff_config = f"DIFF CONFIG ERROR {e}" - if verbose: - if diff_config: - print("[get_untrained_model_with_inputs] -- updated config") - pprint.pprint(diff_config) - print("[get_untrained_model_with_inputs] --") - - # SDPA - if model_kwargs and "attn_implementation" in model_kwargs: - if hasattr(config, "_attn_implementation_autoset"): - config._attn_implementation_autoset = False - config._attn_implementation = model_kwargs["attn_implementation"] # type: ignore[union-attr] + if mkwargs: + update_config(config, mkwargs) + try: + diff_config = build_diff_config(config0, config) + except (ValueError, AttributeError, TypeError) as e: + diff_config = f"DIFF CONFIG ERROR {e}" if verbose: + if diff_config: + print("[get_untrained_model_with_inputs] -- updated config") + pprint.pprint(diff_config) + print("[get_untrained_model_with_inputs] --") + + # SDPA + if model_kwargs and "attn_implementation" in model_kwargs: + if hasattr(config, "_attn_implementation_autoset"): + config._attn_implementation_autoset = False + config._attn_implementation = model_kwargs["attn_implementation"] # type: ignore[union-attr] + if verbose: + print( + f"[get_untrained_model_with_inputs] config._attn_implementation=" + f"{config._attn_implementation!r}" # type: ignore[union-attr] + ) + elif verbose: print( - f"[get_untrained_model_with_inputs] config._attn_implementation=" - f"{config._attn_implementation!r}" # type: ignore[union-attr] + f"[get_untrained_model_with_inputs] default config._attn_implementation=" + f"{getattr(config, '_attn_implementation', '?')!r}" # type: ignore[union-attr] ) - elif verbose: - print( - f"[get_untrained_model_with_inputs] default config._attn_implementation=" - f"{getattr(config, '_attn_implementation', '?')!r}" # type: ignore[union-attr] - ) - - if type(config) is dict and "_diffusers_version" in config: - import diffusers - package_source = diffusers - else: - package_source = transformers + if type(config) is dict and "_diffusers_version" in config: + import diffusers - if use_pretrained: - model = transformers.AutoModel.from_pretrained(model_id, **mkwargs) - else: - if archs is not None: - try: - cls_model = getattr(package_source, archs[0]) - except AttributeError as e: - # The code of the models is not in transformers but in the - # repository of the model. We need to download it. - pyfiles = download_code_modelid(model_id, verbose=verbose) - if pyfiles: - if "." in archs[0]: - cls_name = archs[0] - else: - modeling = [_ for _ in pyfiles if "/modeling_" in _] - assert len(modeling) == 1, ( - f"Unable to guess the main file implemented class {archs[0]!r} " - f"from {pyfiles}, found={modeling}." - ) - last_name = os.path.splitext(os.path.split(modeling[0])[-1])[0] - cls_name = f"{last_name}.{archs[0]}" - if verbose: - print( - f"[get_untrained_model_with_inputs] custom code for {cls_name!r}" - ) - print( - f"[get_untrained_model_with_inputs] from folder " - f"{os.path.split(pyfiles[0])[0]!r}" - ) - cls_model = ( - transformers.dynamic_module_utils.get_class_from_dynamic_module( - cls_name, - pretrained_model_name_or_path=os.path.split(pyfiles[0])[0], - ) - ) - else: - raise AttributeError( - f"Unable to find class 'tranformers.{archs[0]}'. " - f"The code needs to be downloaded, config=" - f"\n{pprint.pformat(config)}." - ) from e + package_source = diffusers else: - assert same_as_pretrained and use_pretrained, ( - f"Model {model_id!r} cannot be built, the model cannot be built. " - f"It must be downloaded. Use same_as_pretrained=True " - f"and use_pretrained=True." - ) + package_source = transformers - try: - if type(config) is dict: - model = cls_model(**config) + if use_pretrained: + model = transformers.AutoModel.from_pretrained( + model_id, trust_remote_code=True, **mkwargs + ) + else: + if archs is not None: + try: + cls_model = getattr(package_source, archs[0]) + except AttributeError as e: + # The code of the models is not in transformers but in the + # repository of the model. We need to download it. + pyfiles = download_code_modelid(model_id, verbose=verbose) + if pyfiles: + if "." in archs[0]: + cls_name = archs[0] + else: + modeling = [_ for _ in pyfiles if "/modeling_" in _] + assert len(modeling) == 1, ( + f"Unable to guess the main file implemented class " + f"{archs[0]!r} from {pyfiles}, found={modeling}." + ) + last_name = os.path.splitext(os.path.split(modeling[0])[-1])[0] + cls_name = f"{last_name}.{archs[0]}" + if verbose: + print( + f"[get_untrained_model_with_inputs] " + f"custom code for {cls_name!r}" + ) + print( + f"[get_untrained_model_with_inputs] from folder " + f"{os.path.split(pyfiles[0])[0]!r}" + ) + cls_model = ( + transformers.dynamic_module_utils.get_class_from_dynamic_module( + cls_name, + pretrained_model_name_or_path=os.path.split(pyfiles[0])[0], + ) + ) + else: + raise AttributeError( + f"Unable to find class 'tranformers.{archs[0]}'. " + f"The code needs to be downloaded, config=" + f"\n{pprint.pformat(config)}." + ) from e else: - model = cls_model(config) - except RuntimeError as e: - raise RuntimeError( - f"Unable to instantiate class {cls_model.__name__} with\n{config}" - ) from e + assert same_as_pretrained and use_pretrained, ( + f"Model {model_id!r} cannot be built, the model cannot be built. " + f"It must be downloaded. Use same_as_pretrained=True " + f"and use_pretrained=True." + ) + + try: + if type(config) is dict: + model = cls_model(**config) + else: + model = cls_model(config) + except RuntimeError as e: + raise RuntimeError( + f"Unable to instantiate class {cls_model.__name__} with\n{config}" + ) from e # input kwargs kwargs, fct = random_input_kwargs(config, task) @@ -243,7 +255,8 @@ def get_untrained_model_with_inputs( res["input_kwargs"] = kwargs res["model_kwargs"] = mkwargs - res["dump_info"] = dict(config_diff=diff_config) + if diff_config is not None: + res["dump_info"] = dict(config_diff=diff_config) sizes = compute_model_size(model) res["model"] = model diff --git a/onnx_diagnostic/torch_models/hghub/model_specific.py b/onnx_diagnostic/torch_models/hghub/model_specific.py new file mode 100644 index 00000000..8cbb9665 --- /dev/null +++ b/onnx_diagnostic/torch_models/hghub/model_specific.py @@ -0,0 +1,49 @@ +from typing import Any, Dict, Tuple + + +class SpecificConfig: + """Creates a specific configuration for the loaded model.""" + + def __init__(self, **kwargs): + self._atts = set(kwargs) + for k, v in kwargs.items(): + setattr(self, k, v) + + def to_dict(self) -> Dict[str, Any]: + return {k: getattr(self, k) for k in self._atts if k != "_atts"} + + +def load_specific_model( + model_id: str, verbose: int = 0, **kwargs +) -> Tuple[Any, str, SpecificConfig]: + """ + Some models do not have any generic to be loaded. + This functions + + :param model_id: model id + :param verbose: verbosiy + :param kwargs: additional parameters + :return: the model, the task associated to it, a configuration + """ + assert model_id in HANDLED_MODELS, ( + f"Unable to load model_id={model_id!r}, " + f"no function is mapped to this id in {sorted(HANDLED_MODELS)}" + ) + return HANDLED_MODELS[model_id](model_id, verbose=verbose, **kwargs) + + +def _load_bingsu_adetailer(model_id: str, verbose: int = 0) -> Tuple[Any, str, SpecificConfig]: + """See `Bingsu/adetailer `_.""" + from huggingface_hub import hf_hub_download + from ultralytics import YOLO + + path = hf_hub_download("Bingsu/adetailer", "face_yolov8n.pt") + model = YOLO(path) + return ( + model, + "object-detection", + SpecificConfig(architecture=type(model), image_size=224, num_channels=3), + ) + + +HANDLED_MODELS = {"Bingsu/adetailer": _load_bingsu_adetailer} From 9534f0e60a12864fc1f56b049fd8af235329f049 Mon Sep 17 00:00:00 2001 From: xadupre Date: Mon, 8 Sep 2025 15:05:15 +0200 Subject: [PATCH 2/2] fix --- onnx_diagnostic/helpers/torch_helper.py | 2 +- onnx_diagnostic/torch_models/hghub/model_inputs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/onnx_diagnostic/helpers/torch_helper.py b/onnx_diagnostic/helpers/torch_helper.py index a2416edb..ec3af9c6 100644 --- a/onnx_diagnostic/helpers/torch_helper.py +++ b/onnx_diagnostic/helpers/torch_helper.py @@ -724,7 +724,7 @@ def to_any(value: Any, to_value: Union[torch.dtype, torch.device, str]) -> Any: if value.__class__.__name__ in {"DynamicCache", "HybridCache"}: make = dict(DynamicCache=make_dynamic_cache, HybridCache=make_hybrid_cache) cc = CacheKeyValue(value) - return make[value.__class__.__name__]( + return make[value.__class__.__name__]( # type: ignore[operator] list( zip( [t.to(to_value) if t is not None else t for t in cc.key_cache], diff --git a/onnx_diagnostic/torch_models/hghub/model_inputs.py b/onnx_diagnostic/torch_models/hghub/model_inputs.py index ca6b7680..91cc052a 100644 --- a/onnx_diagnostic/torch_models/hghub/model_inputs.py +++ b/onnx_diagnostic/torch_models/hghub/model_inputs.py @@ -239,7 +239,7 @@ def get_untrained_model_with_inputs( ) from e # input kwargs - kwargs, fct = random_input_kwargs(config, task) + kwargs, fct = random_input_kwargs(config, task) # type: ignore[arg-type] if verbose: print(f"[get_untrained_model_with_inputs] use fct={fct}") if os.environ.get("PRINT_CONFIG") in (1, "1"):