Show HN: SymForce – Fast symbolic computation, code generation, and optimization (github.com)
SymForce is a library that makes it easy to code a problem once in Python with an augmented SymPy API (backed by C++), experiment with it symbolically, generate optimized code in C++ or any backend language, and then run highly efficient nonlinear optimization problems based on the original problem definition. This workflow elegantly solves a wide variety of tasks in robotics and related domains, and can speed up common tasks by an order of magnitude while requiring less handwritten code and reducing the surface area for bugs. See our paper at https://arxiv.org/abs/2204.07889 for experiments (accepted to RSS 2022).
We developed it at Skydio for real-time robotics algorithms like SLAM, calibration, bundle adjustment, MPC, and system identification on our drones. It’s a key pillar of our autonomy stack that has accelerated our iteration cycle from prototypes to production systems. We are releasing it to benefit the open-source community, and think its components are useful to anyone writing algorithmic code, like students, research teams, and tech companies.
You can pip install it, play around with a formulation in a notebook, and deploy production code in a couple of hours. Try it at https://github.com/symforce-org/symforce
18 comments
[ 3.2 ms ] story [ 47.8 ms ] threadHaving a toolbox based on modern open source and widely adopted tools like Sympy to do this automatically is super powerful.
In the paper it is briefly mentioned that TensorFlow/JAX are slower due to more overhead? I doubt this is true. Also, TensorFlow could be compiled to TF-lite or XLA and then C++ or whatever you like. Same for JAX.
It is also mentioned that TensorFlow/JAX perform poorly on second-order optimization. But this is not true.
Further, it is said that TensorFlow/JAX have poor performance for sparse matrices. While the performance is not great, I am not sure that other frameworks would perform faster.
Some fair benchmarks would be nice.
But then, despite just benchmarks, also a more direct comparison on a conceptual level would be nice. Because from the description, I don't directly understand how it is much different.
Similarly, SymForce examines sparsity of individual matrices and jacobians at code generation time, so that operations with sparse matrices are similarly one instruction per op - at runtime there's no looping or indirection through sparse data structures or allocations of sparse matrices in the optimization loop. There's definitely a cross-over point where dimensions become large enough that TF / JAX / etc will be the tool to use - we'd love to provide some more benchmarks and comparisons here. For the first two experiments in the paper (see Tables II and III), we do compare to JAX and amortizing across a batch size of 1000, SymForce is still way ahead. We tried to be careful, but the code is available so please come beat up our numbers.
This put the problem outside of L2 and thus is not a fair comparison, especially if your problem is small enough to fit in L1.
In addition, XLA does a poor job in optimizing for CPU cache reuse, so I'm not surprised that directly transcoded C++ code would be much faster than XLA.
However, TensorFlow code can directly run on GPU. SymForce cannot.
SymForce is not trying to compute on large data-parallelism, but it could generate an inner kernel for that. In that way it complements TensorFlow nicely.
I think this is just a matter of tweaking the code generator, and not a hard limitation of Symforce.
I am somewhat familiar with Ceres and GTSAM. Can you explain how it differs from these? What are the key features of SymForce that make it stand out?
The main comparison is that in SymForce one writes symbolic expressions in Python, and generates runtime code. In GTSAM and Ceres you write C++ code. This is really nice for exploration and code maintainability. SymForce also has a powerful system of automatically competing tangent space Jacobians that is more elegant and powerful than what the alternatives offer. Finally, SymForce has the benefit of a fresh implementation using the other libraries as a reference, and I think we were able to get better performance by greatly improving memory access patterns and designing functional APIs with solid abstractions (in the C++ optimization library). You can see this with the benchmarks described in detail in the paper.