@@ -1241,6 +1241,19 @@ def _path_c_model_value_dtype(model: Any) -> str | None:
12411241 parameters = getattr (model , "parameters" , None )
12421242 if not callable (parameters ):
12431243 return None
1244+ # Value banks (parameters/activations) must carry the model's low-precision
1245+ # CARRIER dtype, not whatever parameter happens to be first in tree order. A
1246+ # mixed-precision (fp8/bf16) model keeps weights+activations in 16-bit and only
1247+ # uses fp32 for accumulation/optimizer state; a leading fp32 norm/scale wrongly
1248+ # widened every Path C value bank to float32 (2x memory + bandwidth — the fp8
1249+ # Path C regression vs Path B). Prefer the 16-bit carrier when present.
1250+ try :
1251+ names = _collect_tensor_dtype_names (parameters ())
1252+ except Exception :
1253+ names = set ()
1254+ for carrier in ("bfloat16" , "float16" ):
1255+ if carrier in names :
1256+ return carrier
12441257 try :
12451258 return _first_tensor_dtype_name (parameters ())
12461259 except Exception :
@@ -1266,6 +1279,25 @@ def _first_tensor_dtype_name(value: Any) -> str | None:
12661279 return None
12671280
12681281
1282+ def _collect_tensor_dtype_names (value : Any , out : set [str ] | None = None ) -> set [str ]:
1283+ if out is None :
1284+ out = set ()
1285+ dtype = getattr (value , "dtype" , None )
1286+ shape = getattr (value , "shape" , None )
1287+ if dtype is not None and shape is not None :
1288+ name = str (dtype ).rsplit ("." , 1 )[- 1 ]
1289+ if name :
1290+ out .add (name )
1291+ return out
1292+ if isinstance (value , Mapping ):
1293+ for item in value .values ():
1294+ _collect_tensor_dtype_names (item , out )
1295+ elif isinstance (value , (list , tuple )):
1296+ for item in value :
1297+ _collect_tensor_dtype_names (item , out )
1298+ return out
1299+
1300+
12691301def _path_c_model_shape_env_from_config (config : Any | None ) -> PathCModelShapeEnv | None :
12701302 if config is None :
12711303 return None
0 commit comments