1+ import functools
12import logging
23import os
34import threading
1415from .proxy_basics import is_fake_tensor
1516from .proxy_registry import get_global_registry
1617
17- # from .utils import print_debug
18+ SUBCLASS_HOOK_KEY = "_tc_setattr_hook"
19+
20+ logger = logging .getLogger (__name__ )
1821
1922
2023def in_dynamo () -> bool :
@@ -126,9 +129,9 @@ def __init__(
126129 current_time = get_timestamp_ns ()
127130
128131 self .__dict__ ["last_update_timestamp" ] = current_time
132+ logger .debug (f"[ProxyParameter] Created ProxyParameter: { self .var_name } " )
129133 self .register_object ()
130134
131- # print(f"init: {self.var_name}")
132135 if should_dump_trace and not should_disable_proxy_dumping ():
133136 if from_call :
134137 phase = "call"
@@ -141,7 +144,7 @@ def __init__(
141144 self .dump_trace (phase = phase , dump_loc = "initing" )
142145
143146 def __setattr__ (self , name , value ):
144- # print(f"paremeter: {self.var_name}, name = {name}, value = {value}")
147+
145148 super ().__setattr__ (name , value )
146149 self .update_timestamp ()
147150 self .register_object ()
@@ -175,7 +178,6 @@ def register_object(self):
175178 )
176179
177180 def dump_trace (self , phase , dump_loc ):
178- # print(f"parameter: {self.var_name}, phase = {phase}, dump_loc = {dump_loc}")
179181 # TODO
180182 var_name = self .__dict__ ["var_name" ]
181183 # assert var_name is not None # '' is allowed as a var_name (root object)
@@ -224,6 +226,9 @@ def proxy_parameter(
224226 return
225227 for name , t in list (module .named_parameters (recurse = False )):
226228 var_type = typename (t , is_runtime = True )
229+ logger .debug (
230+ f"[ProxyParameter] Proxying parameter: { parent_name } .{ name } of type { var_type } "
231+ )
227232 module ._parameters [name ] = ProxyParameter (
228233 t ,
229234 logdir ,
@@ -244,3 +249,37 @@ def proxy_parameter(
244249 from_call ,
245250 from_iter ,
246251 )
252+
253+ # we need to instrument the __setattr__ of the module to capture parameter updates
254+ def subclass_setattr_hook (self , name , value ):
255+ logger .debug (
256+ f"[ProxyParameter] Module __setattr__ called: { parent_name } .{ name } = { type (value )} "
257+ )
258+ if isinstance (value , torch .Tensor ) or isinstance (value , torch .nn .Module ):
259+ proxy_parameter (
260+ value ,
261+ logdir ,
262+ log_level ,
263+ parent_name + "." + name ,
264+ should_dump_trace ,
265+ from_call ,
266+ from_iter ,
267+ )
268+
269+ module .__dict__ [SUBCLASS_HOOK_KEY ] = subclass_setattr_hook
270+
271+
272+ # instrument torch.nn.Module's setattr
273+ orig_setattr = torch .nn .Module .__setattr__
274+
275+
276+ @functools .wraps (orig_setattr )
277+ def wrapped_setattr (self , name , value ):
278+ hook = getattr (self , SUBCLASS_HOOK_KEY , None )
279+ if hook is not None :
280+ # If hook returns True, skip the original setattr; otherwise continue.
281+ hook (self , name , value )
282+ return orig_setattr (self , name , value )
283+
284+
285+ torch .nn .Module .__setattr__ = wrapped_setattr
0 commit comments