Seeking Help: OutOfOrderError with DiffusionModel

Hi everyone,

I’m encountering a perplexing OutOfOrderError when trying to collect layer activations during model generation. My goal is to extract the outputs from specific layers while a model is running.

Here’s a simplified version of my code:

with model.generate(
    prompts,
    **generate_kwargs,
    device=device,
    seed=seed,
):
    with model.iter[0:50] as step:
        for name, layer in layers.items():
            print(step, name)
            activations.append(layer.output) # also tried with output.save()
    
    outputs.extend(model.output.images)

return activations, outputs

The error I’m getting is:

OutOfOrderError: Value was missed for model.unet.mid_block.attentions.0.transformer_blocks.0.attn1.to_q.output.i0. Did you call an Envoy out of order?

I suspect this might be happening because the order in which I’m iterating through my layers dictionary isn’t the same as the order in which the layers are executed during the forward pass. The model.iter context seems to be designed to handle this, but I’m clearly doing something wrong.

Is there a standard or recommended way to correctly collect activations from a list of specific layers without causing an OutOfOrderError? Do I need to get the layers in the correct execution order first? If so, how can I do that? Any advice or examples would be greatly appreciated!

Thanks in advance for your help! :folded_hands:

Hi @mamiglia - happy to see you using our DiffusionModel class!

Can you share more details about your tracing setup:

  • nnsight version
  • model name
  • layers you are looping over

Thanks.

Hey @AdamBelfki , here’s the details:

  • nnsight version 0.5.1
  • model=stable-diffusion-v1-5/stable-diffusion-v1-5

Here’s a reduced version of the code I use:

layers = OrderedDict()
regex = r"blocks?\.(1\.)?attentions\.0.*attn2\.to_[kqv]"

for name, module in model.unet.named_modules():
    if re.search(regex, name):
        layers[name] = module

So layers.keys() returns

'model.unet.down_blocks.1.attentions.0.transformer_blocks.0.attn2.to_q', 
'model.unet.down_blocks.1.attentions.0.transformer_blocks.0.attn2.to_k', 
'model.unet.down_blocks.1.attentions.0.transformer_blocks.0.attn2.to_v', 
'model.unet.up_blocks.1.attentions.0.transformer_blocks.0.attn2.to_q', 
'model.unet.up_blocks.1.attentions.0.transformer_blocks.0.attn2.to_k', 
'model.unet.up_blocks.1.attentions.0.transformer_blocks.0.attn2.to_v', 
'model.unet.mid_block.attentions.0.transformer_blocks.0.attn2.to_q', 
'model.unet.mid_block.attentions.0.transformer_blocks.0.attn2.to_k', 
'model.unet.mid_block.attentions.0.transformer_blocks.0.attn2.to_v'

So as you can see the problem is that mid_blocks is extracted after the up_blocks, so they are called in the wrong order. I could sort them manually, but I’d like to avoid this.

bump @AdamBelfki

would it make sense to use empty invokes here?

Also @mamiglia if you just want to collect the activation, you should use the nnsight 0.5 new cache feature: NNsight 0.5: Official Walkthrough — nnsight
that would also solve your problem

Hey @mamiglia . This is my suggested workflow for you using the cache.

import re
from collections import OrderedDict

import torch

from nnsight.modeling.diffusion import DiffusionModel

id = "CompVis/stable-diffusion-v1-4"
model = DiffusionModel(id, dispatch=True).to('cuda:0').to(torch.bfloat16)


layers = OrderedDict()
regex = r"blocks?\.(1\.)?attentions\.0.*attn2\.to_[kqv]"

for name, module in model.unet.named_modules():
    if re.search(regex, name):
        layers[name] = module
        
with model.generate("world",num_inference_steps=50, seed=40) as tracer:
    
    cache = tracer.cache(layers)
    
    output = tracer.result.save()

I’m curious why you use an OrderedDict instead of a list here, does it change anything?