1616
1717from __future__ import annotations
1818
19- from typing import TYPE_CHECKING , Literal
19+ import logging
20+ from collections .abc import Mapping
21+ from typing import TYPE_CHECKING , Literal , MutableMapping
22+ from uuid import uuid4
23+
24+ from fairchem .core .common import distutils
2025
2126if TYPE_CHECKING :
2227 from fairchem .core .units .mlip_unit .api .inference import MLIPInferenceCheckpoint
3742_UMA_BACKBONE_FQN_SUFFIX = "uma.escn_moe.eSCNMDMoeBackbone"
3843
3944
40- def get_uma_version (model_config : dict | None ) -> UmaVersion :
45+ def is_uma_moe_backbone_config (backbone_config : Mapping | None ) -> bool :
46+ """
47+ Return whether a backbone config describes an UMA MoE model.
48+
49+ The UMA MoE backbone is also shared by models such as eSEN with
50+ ``num_experts == 0``. Those models do not have model-ID-gated behavior and
51+ therefore do not require a ``model_id``.
52+
53+ Args:
54+ backbone_config: Backbone configuration to classify.
55+
56+ Returns:
57+ Whether the configuration describes an UMA backbone with experts.
58+ """
59+ if not isinstance (backbone_config , Mapping ):
60+ return False
61+
62+ model = backbone_config .get ("model" )
63+ if not isinstance (model , str ) or not (
64+ model == _UMA_BACKBONE_SHORT_NAME or model .endswith (_UMA_BACKBONE_FQN_SUFFIX )
65+ ):
66+ return False
67+
68+ num_experts = backbone_config .get ("num_experts" )
69+ return isinstance (num_experts , int ) and num_experts > 0
70+
71+
72+ def ensure_uma_model_id (model_config : MutableMapping ) -> str | None :
73+ """
74+ Add a generated ID to an untagged UMA MoE model config.
75+
76+ Existing IDs are preserved, and non-UMA model configs are unchanged.
77+
78+ Args:
79+ model_config: Model configuration to update in place.
80+
81+ Returns:
82+ The existing or generated UMA model ID, or ``None`` for non-UMA models.
83+ """
84+ if not is_uma_moe_backbone_config (model_config .get ("backbone" )):
85+ return None
86+
87+ model_id = model_config .get ("model_id" )
88+ if isinstance (model_id , str ) and model_id .strip ():
89+ return model_id
90+
91+ model_id = f"UMA-{ uuid4 ().hex [:12 ]} " if distutils .is_master () else None
92+ model_id_list = [model_id ]
93+ distutils .broadcast_object_list (model_id_list , src = 0 )
94+ model_id = model_id_list [0 ]
95+ if not isinstance (model_id , str ):
96+ raise RuntimeError ("Failed to broadcast the generated UMA model_id" )
97+ model_config ["model_id" ] = model_id
98+ if distutils .is_master ():
99+ logging .warning (
100+ "No model_id was provided for an UMA MoE model. Generated model_id=%r." ,
101+ model_id ,
102+ )
103+ return model_id
104+
105+
106+ def get_uma_version (model_config : Mapping | None ) -> UmaVersion :
41107 """Classify what fix-up a checkpoint needs (see :func:`apply_uma_compat_fixups`).
42108
43109 * ``"not_uma"`` — not a UMA MoE backbone. This includes non-UMA models and
@@ -50,20 +116,10 @@ def get_uma_version(model_config: dict | None) -> UmaVersion:
50116 * ``"tagged"`` — already has a ``model_id`` (UMA 1.2+ or custom) → no-op. The
51117 1.2 ``include_self`` rule lives in the backbone, keyed on ``model_id``.
52118 """
53- if not isinstance (model_config , dict ):
119+ if not isinstance (model_config , Mapping ):
54120 return "not_uma"
55121 backbone = model_config .get ("backbone" , {})
56- if not isinstance (backbone , dict ):
57- return "not_uma"
58- model = backbone .get ("model" )
59- if not isinstance (model , str ) or not (
60- model == _UMA_BACKBONE_SHORT_NAME or model .endswith (_UMA_BACKBONE_FQN_SUFFIX )
61- ):
62- return "not_uma"
63-
64- # UMA uses num_experts > 0; eSCNMDMoeBackbone with num_experts == 0
65- # (e.g. eSEN) is not UMA.
66- if not isinstance (backbone .get ("num_experts" ), int ) or backbone ["num_experts" ] == 0 :
122+ if not is_uma_moe_backbone_config (backbone ):
67123 return "not_uma"
68124
69125 model_id = model_config .get ("model_id" )
0 commit comments