Inference results postprocessing

The infer function allows users to control how inference results are postprocessed via the postprocess keyword argument.

Internally, the inference engine operates on Marginal wrapper types that carry both the underlying distribution and any associated annotation data. The postprocessing step determines whether these wrappers are preserved or stripped from the final result.

Default behavior

The default postprocessing strategy depends on whether annotations are enabled:

  • Without annotations (annotations = nothing, the default): the strategy is UnpackMarginalPostprocess. Since no annotation data is attached, the Marginal wrapper is removed and the result contains the underlying distribution directly (e.g., a Normal or Beta distribution).
  • With annotations (e.g., annotations = LogScaleAnnotations()): the strategy is NoopPostprocess. The Marginal wrapper is preserved so that annotation data remains accessible via ReactiveMP.getannotations.

You can always override the default by passing postprocess = ... explicitly to infer.

Available strategies

RxInfer.inference_postprocessFunction
inference_postprocess(strategy, result)

Postprocesses the result of the inference procedure according to the given strategy. The result is typically a Marginal or a collection of Marginals.

The infer function selects a default strategy automatically based on whether annotations are enabled:

  • When annotations = nothing (the default), the strategy is UnpackMarginalPostprocess, which strips the Marginal wrapper and returns the underlying distribution directly.
  • When annotations are provided, the strategy is NoopPostprocess, which preserves the Marginal wrapper so that annotation data remains accessible via ReactiveMP.getannotations.

You can override this default by passing a custom postprocess argument to infer. See Inference results postprocessing for more details.

source
RxInfer.UnpackMarginalPostprocessType
UnpackMarginalPostprocess

A postprocessing strategy that removes the Marginal wrapper type from the inference result, returning the underlying distribution directly. This is the default strategy when no annotations are enabled, since the Marginal wrapper carries no extra information in that case.

See also: NoopPostprocess, inference_postprocess

source
RxInfer.NoopPostprocessType
NoopPostprocess

A postprocessing strategy that preserves the inference result as-is, keeping the Marginal wrapper intact. This is the default strategy when annotations are enabled, so that annotation data attached to each marginal remains accessible via ReactiveMP.getannotations.

See also: UnpackMarginalPostprocess, inference_postprocess

source

Custom postprocessing step

To implement a custom postprocessing strategy, define a new type and implement the inference_postprocess method for it:

using RxInfer

struct CustomPostprocess end

# For demonstration purposes our postprocessing step simply stringifies the result
RxInfer.inference_postprocess(::CustomPostprocess, result::Marginal) = string(ReactiveMP.getdata(result))

Now, we can use the postprocessing step in the infer function:

@model function beta_bernoulli(y)
    θ ~ Beta(1, 1)
    y ~ Bernoulli(θ)
end

result = infer(
    model = beta_bernoulli(),
    data  = (y = 1.,),
    postprocess = CustomPostprocess()
)

result.posteriors[:θ] # should be a `String`
"Beta{Float64}(α=2.0, β=1.0)"
result.posteriors[:θ] isa String
true