11import logging
2- import re
32from typing import Any , Dict , List
43
54import torch
@@ -613,75 +612,58 @@ def convert_state_to_hf(
613612 "lm_head.w_out.weight" : "lm_head.weight" ,
614613}
615614
616- _HYBRID_BLOCK_KEY_RE = re .compile (r"^blocks\.(\d+)\.(.+)$" )
617615
618-
619- @beta_feature
620- def convert_hybrid_state_to_hf (
621- state_dict : Dict [str , Any ],
622- layer_types : List [str ],
623- ) -> Dict [str , Any ]:
616+ def _build_hybrid_mapping_templates (
617+ layer_types : List [str ], * , to_hf : bool
618+ ) -> List [StateMappingTemplate ]:
624619 """
625- Convert an OLMo-core hybrid state dict to HF ``olmo_hybrid`` format .
620+ Build concrete (placeholder-free) :class:`StateMappingTemplate`s for a hybrid model .
626621
627- Uses :data:`HYBRID_SHARED_KEY_MAP` for non-block keys, and per-layer
628- :data:`HYBRID_GDN_LAYER_KEY_MAP` / :data:`HYBRID_ATTN_LAYER_KEY_MAP`
629- based on *layer_types* .
622+ For each layer, the GDN (``"linear_attention"``) or attention (``"full_attention"``) suffix
623+ map is selected so the per-layer-type naming difference is baked into the concrete keys. The
624+ resulting templates can be fed to a standard :class:`StateConverter` .
630625
631- :param state_dict: An unsharded OLMo-core model state dict.
632626 :param layer_types: Per-layer type list (``"linear_attention"`` or ``"full_attention"``).
627+ :param to_hf: If ``True``, map OLMo-core keys to HF keys, otherwise HF keys to OLMo-core keys.
633628 """
634- hf_state : Dict [str , Any ] = {}
635-
636- for olmo_key , value in state_dict .items ():
637- # Try shared (non-block) keys first.
638- if olmo_key in HYBRID_SHARED_KEY_MAP :
639- hf_state [HYBRID_SHARED_KEY_MAP [olmo_key ]] = value
640- continue
641629
642- m = _HYBRID_BLOCK_KEY_RE . match ( olmo_key )
643- if m is None :
644- raise KeyError ( f"Unmapped key: { olmo_key } " )
630+ def template ( olmo_key : str , hf_key : str ) -> StateMappingTemplate :
631+ src , dst = ( olmo_key , hf_key ) if to_hf else ( hf_key , olmo_key )
632+ return StateMappingTemplate ( src , dst )
645633
646- layer_idx = int (m .group (1 ))
647- suffix = m .group (2 )
634+ templates = [template (olmo_key , hf_key ) for olmo_key , hf_key in HYBRID_SHARED_KEY_MAP .items ()]
648635
636+ for layer_idx , layer_type in enumerate (layer_types ):
649637 key_map = (
650638 HYBRID_GDN_LAYER_KEY_MAP
651- if layer_types [ layer_idx ] == "linear_attention"
639+ if layer_type == "linear_attention"
652640 else HYBRID_ATTN_LAYER_KEY_MAP
653641 )
654- if suffix not in key_map :
655- raise KeyError (
656- f"Unmapped block suffix for layer { layer_idx } "
657- f"(type={ layer_types [layer_idx ]!r} ): { olmo_key } "
658- )
659-
660- hf_key = f"model.layers.{ layer_idx } .{ key_map [suffix ]} "
661- hf_state [hf_key ] = value
662-
663- return hf_state
642+ templates .extend (
643+ template (f"blocks.{ layer_idx } .{ olmo_suffix } " , f"model.layers.{ layer_idx } .{ hf_suffix } " )
644+ for olmo_suffix , hf_suffix in key_map .items ()
645+ )
664646
647+ return templates
665648
666- def _invert_hybrid_key_map (key_map : Dict [str , str ]) -> Dict [str , str ]:
667- inverse : Dict [str , str ] = {}
668- for olmo_suffix , hf_suffix in key_map .items ():
669- if hf_suffix in inverse :
670- raise ValueError (f"Non-invertible hybrid key map: duplicate HF key { hf_suffix !r} " )
671- inverse [hf_suffix ] = olmo_suffix
672- return inverse
673649
650+ @beta_feature
651+ def convert_hybrid_state_to_hf (
652+ state_dict : Dict [str , Any ],
653+ layer_types : List [str ],
654+ ) -> Dict [str , Any ]:
655+ """
656+ Convert an OLMo-core hybrid state dict to HF ``olmo_hybrid`` format.
674657
675- #: Inverse of the hybrid maps, for the HF -> OLMo-core direction.
676- _HF_TO_OLMO_HYBRID_SHARED_KEY_MAP : Dict [str , str ] = _invert_hybrid_key_map (HYBRID_SHARED_KEY_MAP )
677- _HF_TO_OLMO_HYBRID_GDN_LAYER_KEY_MAP : Dict [str , str ] = _invert_hybrid_key_map (
678- HYBRID_GDN_LAYER_KEY_MAP
679- )
680- _HF_TO_OLMO_HYBRID_ATTN_LAYER_KEY_MAP : Dict [str , str ] = _invert_hybrid_key_map (
681- HYBRID_ATTN_LAYER_KEY_MAP
682- )
658+ Uses :data:`HYBRID_SHARED_KEY_MAP` for non-block keys, and per-layer
659+ :data:`HYBRID_GDN_LAYER_KEY_MAP` / :data:`HYBRID_ATTN_LAYER_KEY_MAP`
660+ based on *layer_types*.
683661
684- _HF_HYBRID_BLOCK_KEY_RE = re .compile (r"^model\.layers\.(\d+)\.(.+)$" )
662+ :param state_dict: An unsharded OLMo-core model state dict.
663+ :param layer_types: Per-layer type list (``"linear_attention"`` or ``"full_attention"``).
664+ """
665+ templates = _build_hybrid_mapping_templates (layer_types , to_hf = True )
666+ return StateConverter (templates ).convert (state_dict , placeholder_bounds = {})
685667
686668
687669@beta_feature
@@ -692,43 +674,14 @@ def convert_hybrid_state_from_hf(
692674 """
693675 Convert an HF ``olmo_hybrid`` state dict to OLMo-core format.
694676
695- Inverse of :func:`convert_hybrid_state_to_hf`: uses the inverse of
696- :data:`HYBRID_SHARED_KEY_MAP` for non-block keys, and the inverse of
697- :data:`HYBRID_GDN_LAYER_KEY_MAP` / :data:`HYBRID_ATTN_LAYER_KEY_MAP`
698- based on *layer_types*.
677+ Inverse of :func:`convert_hybrid_state_to_hf`: uses the same suffix maps in the HF ->
678+ OLMo-core direction, selecting per layer based on *layer_types*.
699679
700680 :param state_dict: An unsharded HF ``olmo_hybrid`` model state dict.
701681 :param layer_types: Per-layer type list (``"linear_attention"`` or ``"full_attention"``).
702682 """
703- olmo_state : Dict [str , Any ] = {}
704-
705- for hf_key , value in state_dict .items ():
706- # Try shared (non-block) keys first.
707- if hf_key in _HF_TO_OLMO_HYBRID_SHARED_KEY_MAP :
708- olmo_state [_HF_TO_OLMO_HYBRID_SHARED_KEY_MAP [hf_key ]] = value
709- continue
710-
711- m = _HF_HYBRID_BLOCK_KEY_RE .match (hf_key )
712- if m is None :
713- raise KeyError (f"Unmapped key: { hf_key } " )
714-
715- layer_idx = int (m .group (1 ))
716- suffix = m .group (2 )
717-
718- key_map = (
719- _HF_TO_OLMO_HYBRID_GDN_LAYER_KEY_MAP
720- if layer_types [layer_idx ] == "linear_attention"
721- else _HF_TO_OLMO_HYBRID_ATTN_LAYER_KEY_MAP
722- )
723- if suffix not in key_map :
724- raise KeyError (
725- f"Unmapped block suffix for layer { layer_idx } "
726- f"(type={ layer_types [layer_idx ]!r} ): { hf_key } "
727- )
728-
729- olmo_state [f"blocks.{ layer_idx } .{ key_map [suffix ]} " ] = value
730-
731- return olmo_state
683+ templates = _build_hybrid_mapping_templates (layer_types , to_hf = False )
684+ return StateConverter (templates ).convert (state_dict , placeholder_bounds = {})
732685
733686
734687def _hybrid_layer_types_from_config (config : PretrainedConfig ) -> List [str ]:
0 commit comments