11# SPDX-License-Identifier: LGPL-3.0-or-later
22from collections .abc import (
33 Callable ,
4+ Mapping ,
45)
56from importlib .util import (
67 find_spec ,
78)
89from typing import (
910 TYPE_CHECKING ,
11+ Any ,
1012 ClassVar ,
1113)
1214
2729 )
2830
2931
32+ def detect_pt_checkpoint_backend (checkpoint : Any ) -> str | None :
33+ """Detect the backend dialect of a raw PyTorch checkpoint.
34+
35+ Parameters
36+ ----------
37+ checkpoint : Any
38+ A checkpoint payload or its unwrapped model state dictionary.
39+
40+ Returns
41+ -------
42+ str or None
43+ ``"pt-expt"`` or ``"pt"`` when the parameter names identify one
44+ backend unambiguously, otherwise ``None``.
45+ """
46+ state_dict = checkpoint
47+ if isinstance (state_dict , Mapping ) and "model" in state_dict :
48+ state_dict = state_dict ["model" ]
49+ if not isinstance (state_dict , Mapping ):
50+ return None
51+
52+ keys = tuple (key for key in state_dict if isinstance (key , str ))
53+
54+ # Weight names are decisive. pt_expt DPA4 also contains ordinary
55+ # torch-native ``.bias`` parameters, so bias names cannot override a
56+ # clear ``.w`` versus ``.matrix`` distinction.
57+ has_pt_expt_weight = any (key .endswith (".w" ) for key in keys )
58+ has_pt_weight = any (key .endswith (".matrix" ) for key in keys )
59+ if has_pt_expt_weight or has_pt_weight :
60+ if has_pt_expt_weight == has_pt_weight :
61+ return None
62+ return "pt-expt" if has_pt_expt_weight else "pt"
63+
64+ # Bias-only state dictionaries retain the original dialect fallback.
65+ has_pt_expt_bias = any (key .endswith (".b" ) for key in keys )
66+ has_pt_bias = any (key .endswith (".bias" ) for key in keys )
67+ if has_pt_expt_bias == has_pt_bias :
68+ return None
69+ return "pt-expt" if has_pt_expt_bias else "pt"
70+
71+
3072@Backend .register ("pt-expt" )
3173@Backend .register ("pytorch-exportable" )
3274class PyTorchExportableBackend (Backend ):
@@ -51,11 +93,8 @@ def match_filename(cls, filename: str) -> int:
5193 Returns
5294 -------
5395 - 1 for the regular `.pte` / `.pt2` suffixes (default behaviour).
54- - 2 for `.pt` files whose state-dict uses pt_expt's dpmodel
55- parameter naming (`.w`/`.b`); this outranks the legacy pt
56- backend's default suffix score (1) so pt_expt-trained `.pt`
57- checkpoints route here, while genuine pt-trained `.pt` files
58- (which use `.matrix`/`.bias`) keep going to the pt backend.
96+ - 2 for `.pt` files whose state dictionary uses the pt_expt parameter
97+ dialect. This outranks the pt backend's default suffix score (1).
5998 - 0 otherwise.
6099 """
61100 score = super ().match_filename (filename )
@@ -69,21 +108,14 @@ def match_filename(cls, filename: str) -> int:
69108
70109 # weights_only=True avoids unpickling arbitrary code from an
71110 # untrusted .pt — sniffing only needs the dict keys.
72- sd = torch .load (filename , map_location = "cpu" , weights_only = True )
111+ checkpoint = torch .load (filename , map_location = "cpu" , weights_only = True )
73112 except Exception :
74113 # Not a valid torch archive (corrupt file, wrong format, or a
75114 # weights_only=True restriction trip). Surrender the claim so
76115 # the dispatcher falls back to the default suffix match — pt's
77116 # default score (1) will pick up the file under `dp --pt`.
78117 return 0
79- if isinstance (sd , dict ) and "model" in sd :
80- sd = sd ["model" ]
81- keys = list (sd .keys ()) if hasattr (sd , "keys" ) else []
82- has_pt_expt = any (k .endswith (".w" ) or k .endswith (".b" ) for k in keys )
83- has_pt = any (k .endswith (".matrix" ) or k .endswith (".bias" ) for k in keys )
84- if has_pt_expt and not has_pt :
85- return 2
86- return 0
118+ return 2 if detect_pt_checkpoint_backend (checkpoint ) == "pt-expt" else 0
87119
88120 def is_available (self ) -> bool :
89121 """Check if the backend is available.
0 commit comments