Implementation:Pyro ppl Pyro AsymmetricLaplace
| Knowledge Sources | |
|---|---|
| Domains | Probability_Distributions, Deep_Learning |
| Last Updated | 2026-02-09 09:00 GMT |
Overview
Asymmetric and soft-asymmetric variants of the Laplace distribution, supporting reparameterized sampling with different exponential tail behaviors on each side.
Description
This module implements two related distributions that generalize the symmetric Laplace distribution:
AsymmetricLaplace is a distribution with different exponential decay rates to the left and right of its mode (loc). To the left of loc, it behaves like -Exponential(1 / (asymmetry * scale)); to the right, it behaves like Exponential(asymmetry / scale). The density is continuous at loc so the left and right densities agree.
The distribution is parameterized by three values:
- loc -- The mode of the distribution.
- scale -- The geometric mean of the left and right scales.
- asymmetry -- The square of the ratio of left to right scales. When
asymmetry = 1, this reduces to the standard symmetric Laplace.
Derived properties:
- left_scale =
scale * asymmetry - right_scale =
scale / asymmetry
Sampling is reparameterized (has_rsample = True) using the difference of two Exponential random variables: loc - left_scale * u + right_scale * v where u and v are independent standard Exponential samples.
The log_prob computes the density as: -|z| / scale_side - log(left_scale + right_scale), where scale_side is left_scale for z < 0 and right_scale for z >= 0.
SoftAsymmetricLaplace adds a Gaussian smoothing component to the AsymmetricLaplace distribution. It is equivalent to the sum of a Normal random variable and an AsymmetricLaplace random variable: z + a where z ~ Normal(loc, scale * softness) and a ~ AsymmetricLaplace(0, scale, asymmetry). The resulting distribution has an infinitely differentiable density with asymptotically exponential tails, and converges to AsymmetricLaplace as softness -> 0.
The log_prob of SoftAsymmetricLaplace uses the complementary error function (erfc) for numerically stable computation of the Gaussian-Exponential convolution.
Both distributions support reparameterized sampling, broadcasting of all parameters, and standard Pyro distribution features.
Usage
Use AsymmetricLaplace for modeling data with different tail behaviors on each side of the mode, such as financial returns with asymmetric risk profiles, or quantile regression. Use SoftAsymmetricLaplace when you need a smooth density (e.g., for gradient-based optimization) while maintaining the asymmetric tail structure.
Code Reference
Source Location
- Repository: Pyro
- File: pyro/distributions/asymmetriclaplace.py
Signature
class AsymmetricLaplace(TorchDistribution):
arg_constraints = {
"loc": constraints.real,
"scale": constraints.positive,
"asymmetry": constraints.positive,
}
support = constraints.real
has_rsample = True
def __init__(self, loc, scale, asymmetry, *, validate_args=None)
class SoftAsymmetricLaplace(TorchDistribution):
arg_constraints = {
"loc": constraints.real,
"scale": constraints.positive,
"asymmetry": constraints.positive,
"softness": constraints.positive,
}
support = constraints.real
has_rsample = True
def __init__(self, loc, scale, asymmetry=1.0, softness=1.0, *, validate_args=None)
Import
from pyro.distributions import AsymmetricLaplace
from pyro.distributions import SoftAsymmetricLaplace
I/O Contract
AsymmetricLaplace Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| loc | float or torch.Tensor | Yes | Location parameter (mode of the distribution). |
| scale | float or torch.Tensor | Yes | Scale parameter (geometric mean of left and right scales). Must be positive. |
| asymmetry | float or torch.Tensor | Yes | Asymmetry parameter (square of ratio of left to right scales). Must be positive. Value of 1.0 gives symmetric Laplace. |
| validate_args | bool or None | No | Whether to enable argument validation. |
AsymmetricLaplace Outputs
| Name | Type | Description |
|---|---|---|
| sample/rsample | torch.Tensor | Reparameterized samples of shape sample_shape + batch_shape.
|
| log_prob | torch.Tensor | Log probability density of shape sample_shape + batch_shape.
|
| mean | torch.Tensor | Distribution mean: loc + (right_scale^2 - left_scale^2) / (left_scale + right_scale).
|
| variance | torch.Tensor | Distribution variance: p * left^2 + q * right^2 + p * q * total^2 where p and q are mixing weights.
|
| left_scale | torch.Tensor | Left tail scale: scale * asymmetry.
|
| right_scale | torch.Tensor | Right tail scale: scale / asymmetry.
|
SoftAsymmetricLaplace Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| loc | float or torch.Tensor | Yes | Location parameter. |
| scale | float or torch.Tensor | Yes | Scale parameter. Must be positive. |
| asymmetry | float or torch.Tensor | No | Asymmetry parameter. Defaults to 1.0. |
| softness | float or torch.Tensor | No | Scale of the Gaussian smoother component. Defaults to 1.0. Must be positive. |
| validate_args | bool or None | No | Whether to enable argument validation. |
SoftAsymmetricLaplace Outputs
| Name | Type | Description |
|---|---|---|
| sample/rsample | torch.Tensor | Reparameterized samples: loc + soft_scale * z - left_scale * u + right_scale * v.
|
| log_prob | torch.Tensor | Log probability density computed via complementary error functions for numerical stability. |
| mean | torch.Tensor | Same as AsymmetricLaplace mean. |
| variance | torch.Tensor | AsymmetricLaplace variance plus soft_scale^2 (additional Gaussian variance).
|
Usage Examples
Basic AsymmetricLaplace
import torch
from pyro.distributions import AsymmetricLaplace
# Right-skewed distribution (heavier left tail)
dist = AsymmetricLaplace(
loc=torch.tensor(0.0),
scale=torch.tensor(1.0),
asymmetry=torch.tensor(2.0), # left_scale=2, right_scale=0.5
)
samples = dist.sample(torch.Size([10000]))
print(f"Mean: {dist.mean.item():.3f}")
print(f"Left scale: {dist.left_scale.item():.1f}")
print(f"Right scale: {dist.right_scale.item():.1f}")
SoftAsymmetricLaplace for Smooth Density
import torch
from pyro.distributions import SoftAsymmetricLaplace
# Smooth version with Gaussian kernel
dist = SoftAsymmetricLaplace(
loc=torch.tensor(0.0),
scale=torch.tensor(1.0),
asymmetry=torch.tensor(1.5),
softness=torch.tensor(0.5),
)
samples = dist.rsample(torch.Size([5000]))
log_p = dist.log_prob(samples)
Quantile Regression with Pyro
import pyro
import pyro.distributions as dist
import torch
def quantile_regression_model(x, y=None):
# Asymmetric Laplace likelihood for quantile regression
alpha = pyro.sample("alpha", dist.Normal(0.0, 10.0))
beta = pyro.sample("beta", dist.Normal(0.0, 10.0))
scale = pyro.sample("scale", dist.LogNormal(0.0, 1.0))
loc = alpha + beta * x
# asymmetry controls the quantile (asymmetry=1 gives median)
with pyro.plate("data", len(x)):
pyro.sample(
"obs",
dist.AsymmetricLaplace(loc, scale, asymmetry=torch.tensor(1.0)),
obs=y,
)
Batched Distribution
import torch
from pyro.distributions import AsymmetricLaplace
# Batch of distributions with varying asymmetry
dist = AsymmetricLaplace(
loc=torch.zeros(5),
scale=torch.ones(5),
asymmetry=torch.tensor([0.5, 0.8, 1.0, 1.5, 2.0]),
)
samples = dist.rsample(torch.Size([1000]))
print(samples.shape) # torch.Size([1000, 5])