@@ -73,6 +73,77 @@ def transformer_forward_pass(...):
7373_FORMAT_VERSION = 1
7474
7575
76+ def _is_graphdef (x : Any ) -> bool :
77+ return hasattr (x , "attributes" ) and hasattr (x , "nodes" )
78+
79+
80+ def _graphdef_desc (gd : Any ) -> str :
81+ """Extracts a process-deterministic digest of static attributes in an nnx.GraphDef."""
82+ items = []
83+ for k , v in getattr (gd , "attributes" , ()):
84+ if str (k ).startswith ("_pytree__" ):
85+ continue
86+ if hasattr (v , "value" ):
87+ try :
88+ s = json .dumps (
89+ v .value ,
90+ sort_keys = True ,
91+ default = lambda o : re .sub (r"0x[0-9a-fA-F]+" , "@" , repr (o )),
92+ )
93+ except Exception : # noqa: BLE001
94+ s = re .sub (r"0x[0-9a-fA-F]+" , "@" , repr (v .value ))
95+ items .append (f"{ k } :{ s } " )
96+ return "GraphDef(" + "," .join (items ) + ")"
97+
98+
99+ def extract_svg_meta (config : Any , pipeline : Any = None ) -> dict [str , Any ]:
100+ """Extracts all graph-affecting SVG configuration settings for AOT cache identity."""
101+ svg_keys = (
102+ "use_svg_attention" ,
103+ "svg_implementation" ,
104+ "svg_spatial_density" ,
105+ "svg_high_noise_density" ,
106+ "svg_low_noise_density" ,
107+ "svg_sample_max_row" ,
108+ "svg_profile_query_count" ,
109+ "svg_profile_seed" ,
110+ "svg_dense_layer_fraction" ,
111+ "svg_dense_timestep_fraction" ,
112+ "svg_active_start_step" ,
113+ "svg_active_end_step" ,
114+ "svg_active_start_layer" ,
115+ "svg_active_end_layer" ,
116+ "svg_num_train_timesteps" ,
117+ "svg_num_layers" ,
118+ "svg_include_first_frame" ,
119+ "svg_global_stride" ,
120+ "svg_global_offset" ,
121+ "svg_flash_block_sizes" ,
122+ )
123+ meta : dict [str , Any ] = {}
124+ if config is not None :
125+ for k in svg_keys :
126+ val = getattr (config , k , None ) if not isinstance (config , dict ) else config .get (k , None )
127+ if val is not None :
128+ meta [k ] = str (val )
129+ if pipeline is not None :
130+ for attr in ("transformer" , "high_noise_transformer" , "low_noise_transformer" ):
131+ t = getattr (pipeline , attr , None )
132+ if t is not None :
133+ t_cfg = getattr (t , "config" , None )
134+ attn_cfg = (
135+ getattr (t_cfg , "attention_config" , None )
136+ or (t_cfg .get ("attention_config" ) if isinstance (t_cfg , dict ) else None )
137+ )
138+ if isinstance (attn_cfg , dict ):
139+ meta [f"{ attr } _svg_config" ] = json .dumps (
140+ {k : v for k , v in attn_cfg .items () if "svg" in str (k )},
141+ sort_keys = True ,
142+ default = str ,
143+ )
144+ return meta
145+
146+
76147def _metadata_fingerprint (meta : dict [str , Any ]) -> str :
77148 """Returns the stable filename fingerprint for install-time metadata."""
78149 serialized = json .dumps (meta , sort_keys = True , default = str )
@@ -87,15 +158,18 @@ def _dynamic_signature(args: tuple, kwargs: dict) -> str:
87158 addresses and hash-order-dependent content that differ per process and
88159 made signatures never match across restarts (measured: every array
89160 part stable, only the treedef part unstable). Static graph metadata
90- not visible in key paths (attention kernel, dtypes, model path) is
91- covered by the install-time config fingerprint in the filename.
161+ in GraphDef leaves is extracted deterministically via ``_graphdef_desc``.
92162 Array leaves contribute shape/dtype; non-array leaves (python scalars,
93163 None flags) contribute an address-stripped repr.
94164 """
95- leaves_with_paths = jax .tree_util .tree_flatten_with_path ((args , kwargs ))[0 ]
165+ leaves_with_paths = jax .tree_util .tree_flatten_with_path (
166+ (args , kwargs ), is_leaf = _is_graphdef
167+ )[0 ]
96168 parts = []
97169 for path , leaf in leaves_with_paths :
98- if hasattr (leaf , "shape" ) and hasattr (leaf , "dtype" ):
170+ if _is_graphdef (leaf ):
171+ desc = _graphdef_desc (leaf )
172+ elif hasattr (leaf , "shape" ) and hasattr (leaf , "dtype" ):
99173 desc = f"{ tuple (leaf .shape )} :{ leaf .dtype } "
100174 else :
101175 desc = re .sub (r"0x[0-9a-fA-F]+" , "@" , repr (leaf ))
0 commit comments