Hydra: Advanced Concepts

This page features a collection of more advanced Maze and Hydra features that are used across the framework and power the configuration under the hood:

  • Factory, which Maze uses to turn configuration into instantiated objects, while allowing passing in already instantiated objects as well.

  • Interpolation, which allows you to reference parts of configuration from elsewhere.

  • Specializations, which allow you to load additional configuration files based on particular combinations of selected defaults.

Maze Factory

Factory wraps around Hydra’s own instantiation functionality and adds features like type hinting and checking, collections, configuration structure checks, and ability to take in already instantiated objects.

Using the factory, classes can accept ConfigType (or collections thereof, CollectionOfConfigType), which stands for either an already instantiated object, or a dictionary with configuration, which the factory will then use to build the instance.

Configuration dictionary consists of the _target_ attribute, along with any arguments that the instantiated class takes, e.g. (here denoted in YAML, as you will find it in many places across the framework):

_target_: maze.core.wrappers.maze_gym_env_wrapper.GymMazeEnv
env: CarRacing-v0

The factory then takes in the dictionary configuration (loaded from YAML using Hydra, or from anywhere else) and builds the object for you, checking that it is indeed of the expected type:

from maze.core.env.maze_env import MazeEnv
from maze.core.utils.factory import Factory

env = Factory(MazeEnv).instantiate({
    "_target_": "maze.core.wrappers.maze_gym_env_wrapper.GymMazeEnv",
    "env": "CarRacing-v0"
})

You can also pass in additional keyword arguments that the factory will then pass on to the constructor together with anything from the configuration dictionary:

from maze.core.env.maze_env import MazeEnv
from maze.core.utils.factory import Factory

env = Factory(MazeEnv).instantiate({
    "_target_": "maze.core.wrappers.maze_gym_env_wrapper.GymMazeEnv",
}, env="CarRacing-v0")

If you pass in an already instantiated object instead of a configuation dictionary, the instantiate method will only check that it is of the expected type and return it back. This allows components in Maze to be easily configurable both from YAML/dictionaries and by passing in already instantiated objects.

Interpolation

Hydra is based on OmegaConf and supports interpolation.

Interpolation allows us to reference and reuse a value defined elsewhere in the configuration, without repeating it. For example:

original:
  value: 1  # We want to reference this value elsewhere
some:
  other:
    structure: ${original.value}  # Reference

A (somewhat limited) form of interpolation is used also in specializations described below.

Specializations

Specializations are parts of config that depend on multiple components. For example, your wrapper configuration might depend on both the environment chosen (e.g., gym_pixel_env or gym_feature_env) and your model (e.g., default or rnn) – if using an RNN, you might want to include ObservationStackWrapper, but its configuration also depends on the environment used.

Then, specializations come to the rescue. In your root config file, you can include a specialization like this (for illustrative purposes):

defaults:
  - env: gym_pixel_env
  - model: default
  - env_model: ${defaults.1.env}-${defaults.2.model}
    optional: true

Then, when you run this configuration with env=gym_pixel_env and model=rnn, Hydra will look into the env_model directory for configuration named gym_pixel_env-rnn.yaml. This allows you to capture the dependencies between these two components easily without having to specify more overrides.

Specializations are well explained in Hydra docs here.

Where to Go Next

After understanding advanced Hydra configuration, you might want to: