Skip to content

Commit 8085766

Browse files
cleaned up PR
1 parent 5561906 commit 8085766

1 file changed

Lines changed: 38 additions & 85 deletions

File tree

src/olmo_core/nn/hf/convert.py

Lines changed: 38 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import re
32
from typing import Any, Dict, List
43

54
import 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

734687
def _hybrid_layer_types_from_config(config: PretrainedConfig) -> List[str]:

0 commit comments

Comments
 (0)