Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Google deepmind Dm control Composer Variation

From Leeroopedia
Attribute Value
Implementation Composer Variation
Workflow Composer_Environment_Building
Domain Reinforcement_Learning, Sim_to_Real
Source dm_control
Last Updated 2026-02-15 00:00 GMT

Overview

Concrete tool for applying stochastic domain randomization to MJCF model attributes and compiled physics parameters in dm_control Composer environments through the MJCFVariator, PhysicsVariator, distribution classes, and the evaluate utility.

Description

The dm_control.composer.variation package provides a complete system for domain randomization:

Variator classes (in dm_control/composer/variation/__init__.py):

  • MJCFVariator -- binds variation callables to attributes of mjcf.Element objects. When apply_variations(random_state) is called, each attribute is set to the result of evaluating its variation. The variator records the initial value of each attribute on first application so that relative variations work correctly. Meant to be called in initialize_episode_mjcf (before compilation).
  • PhysicsVariator -- similar to MJCFVariator but operates on compiled physics bindings (physics.bind(element)). Meant to be called in initialize_episode (after compilation), avoiding recompilation for parameters that exist in the compiled model.

Both variators provide clear() to remove all bindings and reset_initial_values() to forget cached initial values.

Distribution classes (in dm_control/composer/variation/distributions.py):

  • Uniform(low=0.0, high=1.0) -- uniform distribution.
  • UniformInteger(low, high=None) -- uniform integer distribution.
  • UniformChoice(choices) -- uniform choice from a list.
  • UniformPointOnSphere() -- uniform unit vector on the 3D sphere.
  • Normal(loc=0.0, scale=1.0) -- Gaussian distribution.
  • LogNormal(mean=0.0, sigma=1.0) -- log-normal distribution.
  • Exponential(scale=1.0) -- exponential distribution.
  • Poisson(lam=1.0) -- Poisson distribution.
  • Bernoulli(prob=0.5) -- Bernoulli (coin flip) distribution.
  • BiasedRandomWalk(stdev=0.1, timescale=10.0) -- stateful Ornstein-Uhlenbeck process for correlated noise.

All distribution classes extend Variation (from dm_control.composer.variation.base), which is an abstract callable with the signature __call__(initial_value=None, current_value=None, random_state=None). The base Variation class supports arithmetic operators (+, -, *, /, **, [], unary -) for composing complex variation expressions.

evaluate (in dm_control/composer/variation/variation_values.py):

  • evaluate(structure, *args, **kwargs) -- recursively traverses an arbitrary nested structure (list, tuple, dict, namedtuple) and replaces each callable with the value returned by calling it with the given arguments. Constants are left unchanged. Uses tree.map_structure internally.

Usage

Create distribution objects and bind them to MJCF element attributes via a variator. Call apply_variations inside the appropriate task lifecycle callback. Use evaluate for one-off evaluation of nested variation structures.

Code Reference

Attribute Value
Source Location (variators) dm_control/composer/variation/__init__.py:L34-136
Source Location (distributions) dm_control/composer/variation/distributions.py:L25-258
Source Location (base) dm_control/composer/variation/base.py
Source Location (evaluate) dm_control/composer/variation/variation_values.py
Signature (MJCFVariator.__init__) MJCFVariator.__init__(self)
Signature (MJCFVariator.bind_attributes) MJCFVariator.bind_attributes(self, element, **kwargs)
Signature (MJCFVariator.apply_variations) MJCFVariator.apply_variations(self, random_state)
Signature (PhysicsVariator.__init__) PhysicsVariator.__init__(self)
Signature (PhysicsVariator.bind_attributes) PhysicsVariator.bind_attributes(self, element, **kwargs)
Signature (PhysicsVariator.apply_variations) PhysicsVariator.apply_variations(self, physics, random_state)
Signature (Uniform) Uniform.__init__(self, low=0.0, high=1.0, single_sample=False)
Signature (Normal) Normal.__init__(self, loc=0.0, scale=1.0, single_sample=False)
Signature (evaluate) evaluate(structure, *args, **kwargs)
Import from dm_control.composer import variation, from dm_control.composer.variation import distributions

I/O Contract

Inputs (MJCFVariator.bind_attributes)

Name Type Description
element mjcf.Element The MJCF element whose attributes will be varied
**kwargs Variation or value Keyword arguments mapping attribute names to variation callables or fixed values

Inputs (MJCFVariator.apply_variations)

Name Type Description
random_state np.random.RandomState Seeded random number generator

Inputs (PhysicsVariator.apply_variations)

Name Type Description
physics mjcf.Physics The compiled physics instance
random_state np.random.RandomState Seeded random number generator

Outputs

Name Type Description
Side effect Attribute mutation The bound MJCF attributes or physics bindings are set to new sampled values in-place
evaluate return nested structure Same structure as input with callables replaced by their return values

Usage Examples

Randomizing MJCF attributes before compilation

from dm_control.composer import variation
from dm_control.composer.variation import distributions


class RandomizedTask(task_module.Task):
    def __init__(self, robot, arena):
        self._arena = arena
        self._arena.attach(robot)
        self._robot = robot

        # Create an MJCF variator for pre-compile randomization
        self._mjcf_variator = variation.MJCFVariator()

        # Randomize the color of all geoms on the robot
        for geom in robot.mjcf_model.find_all('geom'):
            self._mjcf_variator.bind_attributes(
                geom,
                rgba=distributions.Uniform(
                    low=[0, 0, 0, 1], high=[1, 1, 1, 1]))

    @property
    def root_entity(self):
        return self._arena

    def initialize_episode_mjcf(self, random_state):
        self._mjcf_variator.apply_variations(random_state)

    def get_reward(self, physics):
        return 0.0

Randomizing physics parameters after compilation

class DynamicsRandomizedTask(task_module.Task):
    def __init__(self, robot, arena):
        self._arena = arena
        self._arena.attach(robot)
        self._robot = robot

        # Create a physics variator for post-compile randomization
        self._physics_variator = variation.PhysicsVariator()

        # Randomize friction of all geoms
        for geom in robot.mjcf_model.find_all('geom'):
            self._physics_variator.bind_attributes(
                geom,
                friction=distributions.Uniform(
                    low=[0.5, 0.001, 0.001],
                    high=[1.5, 0.01, 0.01]))

    @property
    def root_entity(self):
        return self._arena

    def initialize_episode(self, physics, random_state):
        self._physics_variator.apply_variations(physics, random_state)

    def get_reward(self, physics):
        return 0.0

Composing variations with arithmetic

from dm_control.composer.variation import distributions

# Mass = initial_mass * Uniform(0.8, 1.2)
# This is a Variation that, when called, samples from Uniform
# and multiplies the result by the initial attribute value.
mass_scale = distributions.Uniform(low=0.8, high=1.2)

# Additive noise: position = initial + Normal(0, 0.01)
position_noise = distributions.Normal(loc=0.0, scale=0.01)

# Evaluate a nested structure of variations
params = {
    'mass': mass_scale,
    'pos': [distributions.Uniform(-1, 1), distributions.Uniform(-1, 1), 0.5],
}
sampled = variation.evaluate(
    params,
    initial_value=None,
    current_value=None,
    random_state=np.random.RandomState(42))
# sampled = {'mass': 0.93..., 'pos': [0.12..., -0.45..., 0.5]}

Related Pages

Page Connections

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