Skip to content

Samplers

A sampler draws the perturbations that stochastic gradient estimation evaluates around the current point. Which sampler is used determines where those points are placed; how far they are placed is set separately, by perturbation_magnitudes.

The default is SciPySampler, drawing from a standard normal distribution \(N(0, 1)\). It also offers uniform and truncated normal distributions, and the quasi-random Sobol, Halton and Latin hypercube sequences, which cover a space more evenly than independent draws.

Selecting a sampler

Samplers are listed at the top level of the configuration and referenced from variables.samplers, one entry per variable, so different variables can be perturbed by different samplers:

CONFIG = {
    "variables": {
        "variable_count": 4,
        "perturbation_magnitudes": 1e-6,
        "samplers": [0, 0, 1, 1],   # variables 0,1 use sampler 0; 2,3 use sampler 1
    },
    "samplers": [
        {"method": "scipy/default"},   # index 0
        {"method": "scipy/sobol"},     # index 1
    ],
}

Omit both fields entirely to perturb every variable with the default sampler. See Sharing optimizer components by key for the indexing pattern, which objectives and constraints use in the same way, and samplers for the fields of a sampler configuration.

Sample scaling

Samplers produce unscaled perturbations — values with a characteristic magnitude of approximately one. During gradient estimation these samples are multiplied element-wise by the perturbation_magnitudes defined in VariablesConfig.

The separation keeps the two independent: the sampler determines the distribution of the perturbed points, and perturbation_magnitudes determines their distance from the current point, whichever sampler is in use.

Shared perturbations

By default each realization receives its own independently drawn set of perturbations. Setting the shared flag to True in SamplerConfig reuses the same perturbation values across all realizations:

"samplers": [{"method": "scipy/default", "shared": True}]

This can reduce noise in the gradient estimate when the objective varies smoothly across realizations, because the realizations then differ only in the objective and not also in where it was sampled. The flag has no effect on a sampler whose values do not depend on the realization in the first place.

Writing a custom sampler

A custom sampler is a plugin implementing the Sampler base class, whose generate_samples documents the shape the samples must have and how the mask and shared settings affect them. Like the other component kinds, a sampler defined in a script or a notebook is made selectable with register_plugin.

The runnable script is examples/sampler.py, which perturbs one variable at a time. With one perturbation per variable and a unit step, the gradient estimate is a forward finite difference — which shows that perturbations need not be random at all. Its second method scales each step by a random factor instead, and the two optimizations differ in shared to show where that flag changes the samples.