Skip to content

Commit 2ccbafd

Browse files
bvdmitrialbertpod
andauthored
Add Performance Tips and FAQ (#502)
* add perf tips and faq * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * links * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * Apply suggestion from @albertpod Co-authored-by: Albert <[email protected]> * fix link * missing cross references --------- Co-authored-by: Albert <[email protected]>
1 parent 85ce9ca commit 2ccbafd

File tree

8 files changed

+180
-4
lines changed

8 files changed

+180
-4
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ dev_doc_init:
4646
docs: doc_init ## Generate documentation
4747
julia --startup-file=no --project=docs/ docs/make.jl
4848

49+
docs-serve: doc_init ## Serve documentation locally for preview in browser, requires `LiveServer.jl` installed globally
50+
julia --project=docs/ -e 'ENV["DOCS_DRAFT"]="true"; using LiveServer; LiveServer.servedocs(launch_browser=true, port=5678)'
51+
4952
devdocs: dev_doc_init ## Same as `make docs` but uses `dev-ed` versions of core packages
5053
julia --startup-file=no --project=docs/ docs/make.jl
5154

docs/make.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ draft = get(ENV, "DOCS_DRAFT", "false") == "true"
1313

1414
makedocs(;
1515
draft = draft,
16-
warnonly = false,
16+
warnonly = draft,
1717
modules = [RxInfer],
1818
authors = "Bagaev Dmitry <[email protected]> and contributors",
1919
sitename = "RxInfer.jl",
@@ -49,6 +49,8 @@ makedocs(;
4949
],
5050
"Inference customization" =>
5151
["Defining a custom node and rules" => "manuals/customization/custom-node.md", "Inference results postprocessing" => "manuals/customization/postprocess.md"],
52+
"Performance Tips" => "manuals/performance-tips.md",
53+
"FAQ" => "manuals/faq.md",
5254
"Debugging" => "manuals/debugging.md",
5355
"Session summary" => "manuals/session_summary.md",
5456
"Sharing sessions & telemetry" => "manuals/telemetry.md",

docs/src/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Pages = [
7474
"manuals/meta-specification.md",
7575
"manuals/inference-execution.md",
7676
"manuals/custom-node.md",
77+
"manuals/performance-tips.md",
78+
"manuals/faq.md",
7779
"manuals/debugging.md",
7880
"manuals/delta-node.md",
7981
"manuals/how-to-use-rxinfer-from-python.md",

docs/src/manuals/faq.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# [Frequently Asked Questions (FAQ)](@id user-guide-faq)
2+
3+
This section addresses common questions and issues that users encounter when working with RxInfer. The FAQ is a living document that grows based on community feedback and common usage patterns.
4+
5+
## General Questions
6+
7+
### What is RxInfer?
8+
9+
RxInfer is a Julia package for automated Bayesian inference on factor graphs using reactive message passing. It provides an efficient, scalable framework for probabilistic programming with a focus on streaming data.
10+
11+
### How does RxInfer compare to other probabilistic programming packages?
12+
13+
See our detailed [comparison guide](@ref comparison) for a comprehensive analysis of RxInfer vs. other tools like Turing.jl, Stan, and PyMC.
14+
15+
### Is RxInfer suitable for beginners?
16+
17+
Yes! RxInfer provides a user-friendly syntax through GraphPPL and comprehensive documentation. Start with the [Getting Started](@ref user-guide-getting-started) guide and work through examples.
18+
19+
## Installation and Setup
20+
21+
See [Installation](@ref user-guide-getting-started-installation) for details.
22+
23+
### I'm getting dependency conflicts. What should I do?
24+
25+
Try `Pkg.resolve()` to resolve conflicts. See [Pkg.jl](https://pkgdocs.julialang.org/v1/getting-started/) for more details.
26+
27+
### Can I use RxInfer from Python?
28+
29+
Yes! See our guide on [Using RxInfer from Python](@ref python-usage).
30+
31+
## Model Specification
32+
33+
### What's the difference between `=` and `:=` in model specification?
34+
35+
- `=` is a regular Julia assignment operator, use it only for regular Julia variables
36+
- `:=` creates a random variable node, use it to create latent variables in your model
37+
38+
See [Sharp Bits: Using `=` instead of `:=`](@ref usage-colon-equality) for details.
39+
40+
### How do I handle missing/incomplete data?
41+
42+
RxInfer supports missing data through the `missing` value in Julia. The inference engine will automatically handle missing observations. See [Missing Data](@ref manual-static-inference-missing-data) for details.
43+
44+
### How do I create custom nodes and message update rules?
45+
46+
See [Custom Node and Rules](@ref create-node) for detailed guidance on extending RxInfer.
47+
48+
## Inference Issues
49+
50+
### I'm getting "Rule not found" errors. What does this mean?
51+
52+
This error occurs when RxInfer can't find appropriate message update rules for your model. See [Rule Not Found Error](@ref rule-not-found) for solutions.
53+
54+
### "Stack overflow in inference"
55+
56+
See [Stack Overflow during inference](@ref stack-overflow-inference) for more details.
57+
58+
### My inference is running very slowly. How can I improve performance?
59+
60+
Check our [Performance Tips](@ref user-guide-performance-tips) section for optimization strategies.
61+
62+
### How do I debug inference problems?
63+
64+
Check out the [Debugging](@ref user-guide-debugging) guide.
65+
66+
## Performance and Scaling
67+
68+
### How large can my models be?
69+
70+
RxInfer can handle models with millions of latent variables. Performance depends on:
71+
- Model complexity (e.g. simple models with conjugate pairs of distributions are the fastest)
72+
- Available memory (large models require more memory)
73+
- Computational resources (more cores, more memory, faster CPU, etc.)
74+
- Optimization techniques used (see [Performance Tips](@ref user-guide-performance-tips))
75+
76+
### Can I use RxInfer for real-time applications?
77+
78+
Yes! RxInfer is designed for real-time inference with reactive message passing. See our [streaming inference](@ref manual-online-inference) documentation.
79+
80+
## Community and Support
81+
82+
### Where can I get help?
83+
84+
1. **Documentation**: Start with the relevant sections in the [User Guide](@ref user-guide-getting-started)
85+
2. **GitHub Discussions**: [Ask](https://github.com/ReactiveBayes/RxInfer.jl/discussions) questions and share experiences
86+
3. **Issues**: [Report](https://github.com/ReactiveBayes/RxInfer.jl/issues) bugs and request features
87+
4. **Community Meetings**: Join regular public discussions, more info [here](https://dynalist.io/d/F4aA-Z2c8X-M1iWTn9hY_ndN)
88+
89+
### How can I contribute?
90+
91+
See our [Contributing Guide](@ref contributing-guidelines) for ways to help. Any help is welcome!
92+
93+
## Contributing to the FAQ
94+
95+
This FAQ grows through community contributions! If you have questions that aren't covered here:
96+
97+
1. **Check existing discussions** on GitHub
98+
2. **Ask your question** in GitHub Discussions
99+
3. **Consider contributing** the answer back to this FAQ
100+
4. **Open an issue** if you find a documentation gap
101+
102+
### How to add questions to the FAQ
103+
104+
1. Open a discussion or issue with your question
105+
2. If it's a common question, consider adding it here
106+
3. Follow the [Contributing to Documentation](@ref guide-docs-contributing) guide
107+
4. Use clear, concise language and include code examples when helpful
108+
109+
---
110+
111+
**Note**: This FAQ is maintained by the community. For the most up-to-date information, check GitHub discussions and issues. If you find outdated information, please help us keep it current!

docs/src/manuals/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ It supports both exact and variational inference algorithms and forms an ecosyst
88

99
This page provides the necessary information you need to get started with `Rxinfer`. We will show the general approach to solving inference problems with `RxInfer` by means of a running example: inferring the bias of a coin using a simple Beta-Bernoulli model.
1010

11-
## Installation
11+
## [Installation](@id user-guide-getting-started-installation)
1212

1313
`RxInfer` is an officially registered Julia package. Install `RxInfer` through the Julia package manager by using the following command from the package manager mode:
1414

docs/src/manuals/how-to-use-rxinfer-from-python.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Using RxInfer from Python
1+
# [Using RxInfer from Python](@id python-usage)
22

33
RxInfer can be used from Python through the [`RxInferServer.jl`](https://github.com/lazydynamics/RxInferServer) RESTful API and the [`RxInferClient.py`](https://github.com/lazydynamics/RxInferClient.py) Python SDK.
44

docs/src/manuals/inference/static.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ p = plot!(p, rθ, (x) -> pdf(results.posteriors[:θ], x), title="Posterior", fil
9595
p = vline!(p, [ hidden_θ ], label = "Real (hidden) θ")
9696
```
9797

98-
### Missing data points and predictions
98+
### [Missing data points and predictions](@id manual-static-inference-missing-data)
9999

100100
```@example manual-static-inference
101101
result = infer(
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# [Performance Tips](@id user-guide-performance-tips)
2+
3+
This section provides practical advice and best practices for optimizing the performance of your RxInfer models. Following these guidelines can significantly improve inference speed and memory efficiency.
4+
5+
!!! note
6+
Before diving into RxInfer-specific optimizations, we strongly recommend reading Julia's official [Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/) guide. Many performance improvements come from following Julia's general best practices, such as avoiding global variables, using type stability, and minimizing allocations. The tips in this section build upon those fundamental principles.
7+
8+
## Julia Compilation Latency
9+
10+
Julia uses **Just-In-Time (JIT)** compilation. The **first time** you run a model and inference procedure, Julia compiles the specialized machine code. This can cause noticeable delays **only once**. Afterward, execution becomes much faster. This might be especially problematic for models and factor nodes that accept a dynamic number of arguments. Such nodes include mixture nodes (where the number of components is only known at compilation time) as well as deterministic nodes representing non-linear transformations (since those transformations can be arbitrary, their signature is only known at compilation time).
11+
12+
**Tips:**
13+
- Don't worry about long first-run times during development — focus on steady-state performance.
14+
- Use the `@time` macro from Julia to investigate the time spent on compilation and execution.
15+
16+
## Model Structure Optimization
17+
18+
RxInfer is designed for fast inference on factor graphs and leverages the model structure to optimize the inference procedure. However, it is always possible to create a huge model with complex dependencies between variables and make inference slow with RxInfer.
19+
20+
**General guidelines for model structure optimization:**
21+
22+
### Choose Appropriate Parametrization for Your Nodes
23+
24+
While confusing at first glance, the choice of parametrization for your nodes can have a significant impact on the performance of the inference procedure. For this reason, RxInfer allows you to choose, for example, between `NormalMeanPrecision` and `NormalMeanVariance` parametrizations for `Normal` nodes. Or, you can choose between `MvNormalMeanPrecision` and `MvNormalMeanScalePrecision` parametrizations for `MvNormal` nodes. The difference between these parametrizations is that the former needs to store the entire precision matrix, while the latter uses a single number to store the scale of the diagonal of the precision matrix.
25+
26+
### Use Conjugate Pairs
27+
28+
[Conjugate pairs](https://en.wikipedia.org/wiki/Conjugate_prior) enable analytical message updates. For example, a `Gamma` prior is appropriate for a `NormalMeanPrecision` node, but an `InverseGamma` is not. Conversely, an `InverseGamma` prior is appropriate for a `NormalMeanVariance` node, but a `Gamma` is not. Another example is that a `Beta` prior is appropriate for a `Bernoulli` node, but a `Binomial` is not. A `Wishart` prior is appropriate for an `MvNormalMeanPrecision` node, and an `InverseWishart` is appropriate for an `MvNormalMeanCovariance` node. Note that the conjugacy also depends on the local factorization of your model. If you place priors on both the mean and the precision in `MvNormalMeanPrecision`, you must enforce independence (e.g., `q(μ,Λ)=q(μ)q(Λ)`) to make the model conditionally conjugate.
29+
### Be Aware of the Computational Overhead of Deterministic Nodes
30+
31+
Each deterministic node adds computational overhead and requires approximation method specification. Read more about approximation methods in the [Deterministic nodes](@ref delta-node-manual) section. In some situations, however, it is possible to use specialized factor nodes instead of deterministic nodes. For example, the `SoftDot` node is a specialized factor node for computing the dot product of two vectors where the result is passed to a `Normal` node. Using `SoftDot` directly instead of `Normal(mean = dot(...), ...)` can significantly improve both the performance and accuracy of the inference procedure. Similar applies to `ContinuousTransition` node.
32+
33+
If a specialized node is not available, you can either [create one yourself](@ref create-node) or choose an appropriate approximation method for the deterministic node. For example, if all inputs to the non-linear transformation are known to be Gaussian, the fastest approximation method is probably `Linearization`. However, it requires the function to be differentiable and "nice" enough. More computationally expensive methods, such as `Unscented` or `CVIProjection`, are more robust and can be used in more general cases. We also suggest you to check [Fusing deterministic transformations with stochastic nodes](@ref inference-undefinedrules-fusedelta) example that provides additional tricks.
34+
35+
### Smoothing vs. Filtering
36+
37+
It might be appropriate to convert your model from operating on the whole dataset (smoothing) to operating on one observation at a time (filtering). Read more about smoothing in the [Static Inference](@ref manual-static-inference) section and about filtering in the [Online Inference](@ref manual-online-inference) section. It is also possible to combine both approaches and process data in batches.
38+
39+
## Inference Procedure Optimization
40+
41+
The [`infer`](@ref) function is the main entry point for inference in RxInfer.jl. It is a wrapper around the inference procedure and allows you to specify the inference algorithm, the number of iterations, the initial values for the parameters, and more. The default parameters are chosen to be a good compromise between speed and accuracy. However, in some situations, it is possible to improve the performance of the inference procedure by tuning the parameters.
42+
43+
### Use `free_energy = Float64` Instead of `free_energy = true`
44+
45+
By default, when computing free energy values, they are stored as an abstract type `Real` and are converted to `Float64` only when they are returned. This can be a significant overhead (read Julia's [Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-unnecessary-type-conversions)), especially for large models. The reason for this choice is that in this case, the inference procedure can be auto-differentiated where free energy values serve as the objective function. If you do not plan to auto-differentiate the inference procedure, you can set `free_energy = Float64` to avoid the overhead of type conversions.
46+
47+
### Be Aware of the Computational Overhead of the `limit_stack_depth` Option
48+
49+
RxInfer provides a `limit_stack_depth` option to limit the depth of the stack of the inference procedure, which is explained in the [Stack Overflow during inference](@ref stack-overflow-inference) section. This can be useful to avoid stack overflows, but it can also significantly degrade the performance of the inference procedure. The larger the value, the less the performance is degraded. You can tune the value based on the size of your model as well as your computer. The optimal value differs for different models and computers.
50+
51+
## Getting Help
52+
53+
If you encounter performance issues:
54+
55+
1. **Check the documentation**: Review relevant sections for optimization tips
56+
2. **Use the community**: Open discussions on GitHub for specific issues
57+
3. **Profile your code**: Use Julia's profiling tools to identify bottlenecks
58+
4. **Start simple**: Build complexity gradually to identify performance issues

0 commit comments

Comments
 (0)