SoftDotMessagePassingRules

The SoftDot node and its rules: a dot product of two unknowns, softened by Gaussian noise so that every message is in closed form. Use it for a Bayesian linear regression, y ~ N(θᵀx, γ⁻¹) with the noise precision γ learnt, or wherever a dot product joins two Gaussian unknowns, which the deterministic dot product node of StandardMessagePassingRules cannot do in closed form. This site is a single page.

SoftDotMessagePassingRules — Module
SoftDotMessagePassingRules

The SoftDot node, y ~ N(θᵀx, γ⁻¹): the dot product of θ and x softened by Gaussian noise of precision γ, with its variational rules. Where the deterministic dot product node, dot in StandardMessagePassingRules, has no closed-form messages for two Gaussian factors, SoftDot's are all in closed form. It serves Bayesian linear regression, y ~ N(θᵀx, γ⁻¹) with the regressors x known, and bilinear models with both factors unknown.

  • SoftDot, the node, and its alias softdot. It runs under DefaultAlgorithm, which a model need not name.
  • Its rules are variational, under the mean-field q(y)q(θ)q(x)q(γ) or the structured q(y, x)q(θ)q(γ), with an average energy for each. There are no belief-propagation rules.

Examples

julia> using MessagePassingRulesBase, ExponentialFamily, BayesBase

julia> q_θ = MvNormalMeanCovariance([1.0, 2.0], [1.0 0.0; 0.0 1.0]);

julia> q_x = MvNormalMeanCovariance([3.0, 1.0], [1.0 0.0; 0.0 1.0]);

julia> result = @call_message_update_rule(node = SoftDot, target = :y, q = (θ = q_θ, x = q_x, γ = GammaShapeRate(2.0, 1.0)));

julia> all(mean_precision(getresult(result)) .≈ (5.0, 2.0))
true
source
Where these rules run

ReactiveMP runs these rules on a factor graph, which RxInfer builds from a GraphPPL model. The examples here call the rules directly, as a test does.

Overview

A deterministic node y = θᵀx with both θ and x unknown has no closed-form messages. SoftDot replaces the constraint by a Gaussian likelihood of precision γ around it. The softening makes it a stochastic node, a density over its variables.

Under variational message passing, the node then sends a normal message towards each of y, θ and x and a gamma message towards γ, all in closed form. It contributes an average energy to the Bethe free energy. A large γ, or a prior on γ concentrated at large values, brings it close to the deterministic dot product.

Definition

\[p(y \mid θ, x, γ) = \mathcal{N}\left(y \mid θ^\top x, γ^{-1}\right) = \sqrt{\frac{γ}{2π}} \exp\left(-\frac{γ}{2} \left(y - θ^\top x\right)^2\right)\]

The output y is normal around the dot product θᵀx, with variance γ⁻¹. y is a scalar; θ and x are both scalars or both vectors of the same length.

Interfaces

using SoftDotMessagePassingRules, MessagePassingRulesBase, BayesBase, ExponentialFamily
MessagePassingRulesBase.nodespec(SoftDot)
NodeSpec: SoftDot
θ (theta)xγ (gamma)ySoftDotstochastic
interfacealiases
y
θtheta
x
γgamma
default algorithmMessagePassingRulesBase.DefaultAlgorithm()
static inputsnone
definedsrc/node.jl:38

The node has four interfaces, two of them with an alias that a model may write instead of the Greek name. The node itself has the alias softdot.

namealiasmeaningits rules read
ythe result of the soft dot product, a scalarq(y) a univariate normal; under q(y, x), the message on y, a univariate normal
θthetathe first factorq(θ) a normal, univariate or multivariate
xthe second factorq(x) a normal, or a point mass for known regressors; under q(y, x), the message on x, a normal
γgammathe precision of the noiseq(γ) a gamma, through its mean (and the mean of its logarithm for the energy)

Here q(θ) is the marginal of θ. The rules towards θ and x return a normal in weighted-mean–precision form, univariate or multivariate as the factor is. The rule towards y returns a univariate normal and the rule towards γ a GammaShapeRate. Under the structured factorisation the joint q(y, x) is a multivariate normal over [y; x].

Algorithm

SoftDot runs under DefaultAlgorithm, which takes no parameters; a model need not name it. The node declares no dependencies, so each rule takes the inputs of the default scheme.

Supported rules

MessagePassingRulesBase.rule_coverage(SoftDot)
Rule coverage for SoftDot
DefaultAlgorithm
→ y✓×2
→ θ✓×2
→ x✓×2
→ γ✓×2
average energy✓×2
q(y, x)✓

rule_coverage counts two rules per target, one per factorisation:

  • the mean field q(y)q(θ)q(x)q(γ), where every rule reads the marginals of the other interfaces;
  • the structured q(y, x)q(θ)q(γ), where the rules towards y and x read the other one's message and the rules towards θ and γ read the joint q(y, x).

The marginal rule q(y, x) computes that joint from the messages on y and x. There are two average energies, one per factorisation. There are no belief propagation rules.

Example

The message towards γ under mean field is Γ(3/2, ⟨(y - θᵀx)²⟩ / 2). With every marginal N(1, 1), the expected square is E[y²] - 2E[y]E[θ]E[x] + E[θ²]E[x²] = 2 - 2 + 4:

@call_message_update_rule(
    node = SoftDot, target = :γ,
    q = (y = NormalMeanVariance(1.0, 1.0), θ = NormalMeanVariance(1.0, 1.0), x = NormalMeanVariance(1.0, 1.0)),
)
RuleResult: message of SoftDot towards :γvariational
yθxγSoftDot
Result
valueExponentialFamily.GammaShapeRate{Float64}(a=1.5, b=2.0)
typeExponentialFamily.GammaShapeRate{Float64}
log scaleundefined: the message rule for SoftDot towards :γ under MessagePassingRulesBase.DefaultAlgorithm declares no `logscale`
Inputs
edgevalue
yqExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=1.0)
θqExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=1.0)
xqExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=1.0)
Rule
declared inputsq[:y]::Any, q[:θ]::Any, q[:x]::Any
algorithmDefaultAlgorithm()
log scalenone
checkscheck_y_θ_x(args.q[:y], args.q[:θ], args.q[:x])
definedsrc/rules.jl:70
body
args->begin
        (my, Vy) = mean_cov(args.q[:y])
        (mθ, Vθ) = mean_cov(args.q[:θ])
        (mx, Vx) = mean_cov(args.q[:x])
        T = promote_paramfloattype(args.q[:y], args.q[:θ], args.q[:x])
        β = add_outer(Vy, my) / 2
        β -= my * mθ' * mx
        β += (trace_product(Vx, Vθ) + (mθ' * Vx) * mθ + (mx' * Vθ) * mx + (mθ' * mx) * (mx' * mθ)) / 2
        GammaShapeRate(convert(T, 3 / 2), β)
    end
Other rules for this target (1)
src/rules.jl:86
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗q[:y, :x]::Union{ExponentialFamily.MultivariateNormalDistributionsFamily{T}, ExponentialFamily.MultivariateGaussianDistributionsFamily{T}} where T not provided
✓q[:θ]::Any got ExponentialFamily.NormalMeanVariance{Float64}
✗q[:x]::ExponentialFamily.NormalMeanVariance{Float64} provided but not consumed
✗q[:y]::ExponentialFamily.NormalMeanVariance{Float64} provided but not consumed

@call_message_update_rule runs the rule and draws the marginals it read. The result is Γ(1.5, 2.0), which getresult extracts:

julia> using MessagePassingRulesBase, SoftDotMessagePassingRules, ExponentialFamily, BayesBase

julia> q = (y = NormalMeanVariance(1.0, 1.0), θ = NormalMeanVariance(1.0, 1.0), x = NormalMeanVariance(1.0, 1.0));

julia> message = getresult(@call_message_update_rule(node = SoftDot, target = :γ, q = q));

julia> shape(message) ≈ 1.5 && rate(message) ≈ 2.0
true

Limitations

  • Variational rules only: there is no belief propagation rule, so the node needs a factorisation, mean-field or q(y, x)q(θ)q(γ). It also needs initial marginals where the schedule reads them before they are computed.
  • No rules for other factorisations, such as a joint over θ and x or over y and θ.
  • y is a scalar: a vector-valued output needs one node per component. The mean-field rules and energy check it, and that θ and x are both univariate or both multivariate, and throw a RuleInputError otherwise.
  • The rules take normal marginals and messages on y, θ and x and a gamma-like marginal on γ (anything with a mean, and a mean of the logarithm for the energy).

API

The node and its alias, the name an RxInfer model writes:

SoftDotMessagePassingRules.SoftDot — Type
SoftDot

The SoftDot node, the density

p(y | θ, x, γ) = N(y | θᵀx, γ⁻¹),

a dot product of θ and x softened by Gaussian noise of precision γ. A stochastic node with the interfaces, in order:

  1. y, the result, a scalar;
  2. θ (alias theta), the first factor, a scalar or a vector;
  3. x, the second factor, of the same dimension as θ;
  4. γ (alias gamma), the precision of the noise, a positive scalar.

It runs under DefaultAlgorithm, which a model need not name. Its rules are variational and in closed form: every message reads the marginals of the other interfaces, under the mean-field q(y)q(θ)q(x)q(γ) or the structured q(y, x)q(θ)q(γ), where the rules towards y and x read the message on the other one and the joint q(y, x) has its own rule. The marginals on y, θ and x are normals and the one on γ a gamma: the rules read their means and covariances, and the mean and the mean of the logarithm of q(γ).

There are no belief-propagation rules, and other factorisations, such as a joint over θ and x, have no rules. There is an average energy for the two factorisations above.

See also: softdot

source