Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:Pyro ppl Pyro Autoname Scoping

From Leeroopedia


Knowledge Sources
Domains Probabilistic Programming, Software Engineering, Modular Design
Last Updated 2026-02-09 09:00 GMT

Overview

Automatic naming and scoping provides a systematic mechanism for generating unique, hierarchical names for sample sites and parameters in probabilistic programs, enabling modular model composition without name conflicts.

Description

In probabilistic programming, every sample site and learnable parameter must have a unique name. These names serve as keys for:

  • Matching model sites to guide sites during variational inference.
  • Recording values in execution traces.
  • Conditioning on observed data.
  • Replaying recorded values.

When building complex models from reusable components, manual naming becomes error-prone:

  • Two components might use the same name for different parameters.
  • Recursive or repeated components need distinct names for each invocation.
  • Renaming is tedious and brittle when refactoring.

Automatic naming (autoname) solves this by:

  1. Assigning names to sample sites based on the function they appear in.
  2. Using scoping to create hierarchical namespaces (e.g., "encoder/layer1/weight").
  3. Automatically appending indices when the same function is called multiple times.

Scoping mechanisms include:

  • Function-based scoping: Each model function creates a scope; sample sites within are prefixed with the function name.
  • Plate-based scoping: Sites inside plates are indexed by the plate iteration.
  • Explicit scope markers: Users can manually create named scopes for organizational purposes.
  • Tree-structured data: When model components correspond to tree-structured data (e.g., phylogenetic trees), the naming system generates names that reflect the tree structure.

These mechanisms enable modular model composition: a user can define a reusable component (e.g., a Bayesian linear layer) and use it multiple times in a model without worrying about name conflicts, because each invocation is automatically scoped.

Usage

Use autoname scoping when:

  • Building models from reusable probabilistic components.
  • Using the same model function multiple times (e.g., mixture components, repeated layers).
  • Working with hierarchical or tree-structured models where naming must reflect structure.
  • Composing independently developed model modules into a larger model.
  • Debugging name conflicts or matching errors between model and guide.

Theoretical Basis

Naming convention:

# Flat naming (manual, error-prone):
# sample("weight", Normal(0, 1))        -- name: "weight"
# sample("weight", Normal(0, 1))        -- ERROR: duplicate name!

# Scoped naming (automatic):
# with scope("layer1"):
#     sample("weight", Normal(0, 1))    -- name: "layer1/weight"
# with scope("layer2"):
#     sample("weight", Normal(0, 1))    -- name: "layer2/weight"
# No conflict!

Autoname mechanism:

# Decorator that auto-scopes a function:
def autoname(fn):
    def wrapper(*args, **kwargs):
        with scope(fn.__name__):
            return fn(*args, **kwargs)
    return wrapper

# Usage:
@autoname
def bayesian_linear(x, in_features, out_features):
    weight = sample("weight", Normal(0, 1).expand([out_features, in_features]))
    bias = sample("bias", Normal(0, 1).expand([out_features]))
    return x @ weight.T + bias

# First call:  names are "bayesian_linear/weight", "bayesian_linear/bias"
# But second call would conflict! Solution: add counter

Counter-based disambiguation:

# When the same function is called multiple times:
# Append an index to the scope

# Call 1: scope = "bayesian_linear"
#   -> "bayesian_linear/weight", "bayesian_linear/bias"
# Call 2: scope = "bayesian_linear__1"
#   -> "bayesian_linear__1/weight", "bayesian_linear__1/bias"

# Or with explicit naming:
# model.linear1 = bayesian_linear  # scope: "linear1"
# model.linear2 = bayesian_linear  # scope: "linear2"

Tree-structured naming:

# For tree-structured models (e.g., phylogenetics):
# Each tree node gets a scope:

def tree_model(node):
    with scope(node.name):
        state = sample("state", prior)
        for child in node.children:
            transition = sample(f"transition_to_{child.name}", transition_dist)
            tree_model(child)

# Results in names like:
# "root/state"
# "root/transition_to_left"
# "root/left/state"
# "root/left/transition_to_leaf1"
# etc.

Mixture model naming example:

# Mixture of K components, each with the same structure:
def component(x):
    mu = sample("mu", Normal(0, 10))
    sigma = sample("sigma", LogNormal(0, 1))
    return Normal(mu, sigma).log_prob(x)

# With autoname:
# for k in range(K):
#     with scope(f"component_{k}"):
#         component(x)
# Names: "component_0/mu", "component_0/sigma",
#         "component_1/mu", "component_1/sigma", ...

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment