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.

Implementation:Pyro ppl Pyro TransformModule

From Leeroopedia


Attribute Value
Sources pyro/distributions/torch_transform.py
Domains Probabilistic Programming, Normalizing Flows, Learnable Transforms, Neural Networks
Last Updated 2026-02-09

Overview

Description

The TransformModule and ComposeTransformModule classes bridge PyTorch's distribution transforms system with its neural network module system. They enable transforms with learnable parameters (such as those used in normalizing flows) to participate in PyTorch's parameter management infrastructure.

TransformModule is a class that inherits from both torch.distributions.Transform and torch.nn.Module. By inheriting from nn.Module, any learnable parameters defined in subclasses are automatically registered and can be optimized by PyTorch optimizers, serialized/deserialized with state_dict(), and tracked by Pyro's parameter store when used inside PyroModule instances.

ComposeTransformModule similarly inherits from both torch.distributions.ComposeTransform and torch.nn.ModuleList. This allows a sequence of transform modules to be composed together while retaining proper parameter registration. Any nn.Module parts in the composition are automatically appended to the ModuleList, ensuring they appear in .parameters() and .named_modules() calls.

Both classes override __hash__ to use the default Python object identity hash (via super(torch.nn.Module, self).__hash__()), ensuring that transforms behave correctly when used as dictionary keys or in sets, which is important for caching mechanisms in PyTorch's transform system.

Usage

Any normalizing flow or learnable transform in Pyro should subclass TransformModule rather than the plain torch.distributions.Transform. When composing multiple such transforms, ComposeTransformModule should be used instead of torch.distributions.ComposeTransform to ensure all parameters are properly registered.

Code Reference

Source Location

Property Value
File pyro/distributions/torch_transform.py
Module pyro.distributions.torch_transform
Repository pyro-ppl/pyro

Signature

class TransformModule(torch.distributions.Transform, torch.nn.Module):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def __hash__(self):
        return super(torch.nn.Module, self).__hash__()


class ComposeTransformModule(torch.distributions.ComposeTransform, torch.nn.ModuleList):
    def __init__(self, parts, cache_size=0):
        ...

    def __hash__(self):
        return super(torch.nn.Module, self).__hash__()

    def with_cache(self, cache_size=1):
        ...

Import

from pyro.distributions import TransformModule, ComposeTransformModule

# Or from the module directly:
from pyro.distributions.torch_transform import TransformModule, ComposeTransformModule

I/O Contract

TransformModule

Parameter Type Description
*args varies Passed to both torch.distributions.Transform and torch.nn.Module constructors via super().__init__()
**kwargs varies Passed to both parent constructors via super().__init__()
Inherited Interface Source Description
_call(x), _inverse(y) Transform Must be implemented by subclasses to define the forward and inverse mappings
log_abs_det_jacobian(x, y) Transform Must be implemented by subclasses for log probability computation
parameters(), named_parameters() nn.Module Enumerates all learnable parameters
state_dict(), load_state_dict() nn.Module Serialization of learnable parameters
to(device), cuda(), cpu() nn.Module Device transfer of parameters

ComposeTransformModule

Parameter Type Description
parts list List of transform instances. Any that are nn.Module instances are automatically registered in the ModuleList.
cache_size int Cache size for the composed transform. Default: 0.
Method Return Type Description
with_cache(cache_size=1) ComposeTransformModule Returns a new ComposeTransformModule with the specified cache size. Returns self if cache_size is unchanged.
__hash__() int Returns object identity hash (bypasses Module's hash override)

Usage Examples

Creating a Custom Learnable Transform

import torch
import torch.nn as nn
from pyro.distributions.torch_transform import TransformModule

class LearnableAffineTransform(TransformModule):
    """A simple learnable affine transform: y = scale * x + shift."""
    domain = torch.distributions.constraints.real
    codomain = torch.distributions.constraints.real
    bijective = True

    def __init__(self, dim):
        super().__init__()
        self.scale = nn.Parameter(torch.ones(dim))
        self.shift = nn.Parameter(torch.zeros(dim))

    def _call(self, x):
        return self.scale * x + self.shift

    def _inverse(self, y):
        return (y - self.shift) / self.scale

    def log_abs_det_jacobian(self, x, y):
        return self.scale.abs().log().sum(-1)

# Parameters are automatically tracked
transform = LearnableAffineTransform(10)
print(list(transform.parameters()))  # [scale, shift]

Composing Multiple Learnable Transforms

import torch
from pyro.distributions import TransformModule, ComposeTransformModule, TransformedDistribution

# Assume we have custom TransformModule subclasses
# e.g., from pyro.distributions.transforms import Planar, Radial
from pyro.distributions.transforms import Planar

# Create a normalizing flow with multiple layers
transforms = [Planar(input_dim=5) for _ in range(3)]
flow = ComposeTransformModule(transforms)

# All parameters from all layers are accessible
total_params = sum(p.numel() for p in flow.parameters())
print(f"Total parameters: {total_params}")

# Use with a base distribution
base_dist = torch.distributions.Normal(torch.zeros(5), torch.ones(5))
flow_dist = TransformedDistribution(base_dist, [flow])

Using with PyroModule

import torch
import pyro
import pyro.distributions as dist
from pyro.nn import PyroModule

class FlowModel(PyroModule):
    def __init__(self):
        super().__init__()
        # TransformModule parameters are registered with Pyro's param store
        from pyro.distributions.transforms import Spline
        self.transform = Spline(input_dim=2, count_bins=8)

    def forward(self, data=None):
        base = dist.Normal(torch.zeros(2), torch.ones(2)).to_event(1)
        flow_dist = dist.TransformedDistribution(base, [self.transform])
        with pyro.plate("data", 100):
            return pyro.sample("x", flow_dist, obs=data)

Cache Control with ComposeTransformModule

from pyro.distributions.torch_transform import ComposeTransformModule
from pyro.distributions.transforms import Planar

# Build a composition of transforms
parts = [Planar(input_dim=3) for _ in range(5)]
composed = ComposeTransformModule(parts, cache_size=0)

# Enable caching for repeated forward/inverse calls
cached_composed = composed.with_cache(cache_size=1)
print(type(cached_composed))  # ComposeTransformModule

Related Pages

  • TransformedDistribution -- Distribution formed by applying transforms to a base distribution
  • Distributions_Init -- Central registry of all Pyro distributions including TransformModule
  • Stable -- A distribution that benefits from reparameterization via transforms
  • RelaxedStraightThrough -- Another distribution technique for differentiable discrete sampling

Page Connections

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