hallucination / extra_materials /graph /vision_sae_wrapper.py
ToiTenBao's picture
Upload hallucination folder
a2ffd07 verified
Raw
History Blame Contribute Delete
1.63 kB
from unittest.mock import patch
from contextlib import contextmanager, ExitStack
# 1. A helper to generate the wrapper closure
# We pass 'original_func' here so it is "baked in" to the wrapper.
def create_avg_wrapper(original_func):
def wrapper(inputs, *args, **kwargs):
# Your custom logic
if len(inputs.shape) == 3:
inputs = inputs.mean(dim=1, keepdim=True)
elif len(inputs.shape) == 2:
inputs = inputs.unsqueeze(1)
else:
raise
# Call the CAPTURED original function
return original_func(inputs, *args, **kwargs)
return wrapper
@contextmanager
def vision_sae_wrapper(saes):
# Ensure we can handle a single SAE or a list of them
if not isinstance(saes, list):
saes = [saes]
# ExitStack is designed exactly for "I need N context managers"
with ExitStack() as stack:
for sae in saes:
# 1. Capture the specific original method for THIS sae
original_forward = sae.forward
# 2. Create a wrapper specific to this sae (closing over original_forward)
patched_forward = create_avg_wrapper(original_forward)
# 3. Enter the patch context and add it to the stack
stack.enter_context(patch.object(sae, 'forward', side_effect=patched_forward))
# Yield control back to your code
yield
# --- Usage Example ---
# sae_list = [sae1, sae2, sae3]
# with vision_sae_wrapper(sae_list):
# # All SAEs are now patched
# output1 = sae1(input_tensor)
# output2 = sae2(input_tensor)